{"id":116,"date":"2021-09-18T06:54:10","date_gmt":"2021-09-18T06:54:10","guid":{"rendered":"http:\/\/ouyangminwei.com\/?p=116"},"modified":"2021-10-04T15:03:07","modified_gmt":"2021-10-04T15:03:07","slug":"build-a-discrod-music-bot","status":"publish","type":"post","link":"https:\/\/ouyangminwei.com\/index.php\/2021\/09\/18\/build-a-discrod-music-bot\/","title":{"rendered":"Build a discrod music Bot"},"content":{"rendered":"\n<p><a href=\"https:\/\/www.theverge.com\/2021\/8\/24\/22640024\/youtube-discord-groovy-music-bot-closure\">https:\/\/www.theverge.com\/2021\/8\/24\/22640024\/youtube-discord-groovy-music-bot-closure<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/cdn.vox-cdn.com\/thumbor\/yrTFgtppj3i_2uQ95c3f7IKWYN8=\/0x0:649x1036\/1200x0\/filters:focal(0x0:649x1036):no_upscale()\/cdn.vox-cdn.com\/uploads\/chorus_asset\/file\/22803360\/99nShh7.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba 99nShh7.png\" width=\"487\" height=\"777\"\/><\/figure>\n\n\n\n<p><a href=\"https:\/\/www.theverge.com\/2021\/9\/12\/22669502\/youtube-discord-rythm-music-bot-closure\">https:\/\/www.theverge.com\/2021\/9\/12\/22669502\/youtube-discord-rythm-music-bot-closure<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-20.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-20.png\"\/><\/figure>\n\n\n\n<p>Recently, youtube kill&#8217;s some of the most used music robots on discord, and other public ones may also be asked to be shut down, so today let us make our discord bot!!!<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 1 : Create your bot<\/h2>\n\n\n\n<p>Goto this website <a href=\"https:\/\/discord.com\/developers\/applications\">https:\/\/discord.com\/developers\/applications<\/a>, I have already created one,  click the &#8220;New Application&#8221; button.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-22-1024x480.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-22-1024x480.png\"\/><\/figure>\n\n\n\n<p>And name your bot.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-23.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-23.png\" width=\"425\" height=\"362\"\/><\/figure>\n\n\n\n<p>If you create the bot successfully, you should see it appear on your main page, just click it.<\/p>\n\n\n\n<p>Go and copy your APPLICATION ID, and fill in this link:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:\/\/discordapp.com\/oauth2\/authorize?&amp;client_id=xxxxxxxxxxxxx&amp;scope=bot&amp;permissions=8 # replace xxxxx with you Id<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-25-1024x570.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-25-1024x570.png\"\/><\/figure>\n\n\n\n<p>with this link, you can invite it to your channel.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-27-1024x568.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-27-1024x568.png\"\/><\/figure>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 2 : authorization token<\/h2>\n\n\n\n<p>Go to the &#8220;bot&#8221; and click &#8220;copy&#8221;, this will give you your Token<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-24-1024x615.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-24-1024x615.png\"\/><\/figure>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 3 : Start coding<\/h2>\n\n\n\n<p>Here, I&#8217;m will build the bot with python in windows, so you will need python on your computer<\/p>\n\n\n\n<p>open cmd and download discord&#8217;s API<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install discord.py<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-28-1024x436.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-28-1024x436.png\"\/><\/figure>\n\n\n\n<p>Open sublime and paste the following code to start a simple bot<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/07207e4867b9a2aa90c6b338304c52dd.js\"><\/script>\n\n\n\n<p>save and open with cmd.<\/p>\n\n\n\n<p>we know this is not enough&#8230;, we need a music bot, not a ping-pong idiot&#8230;, next, I will speed up and point out the difficulties and solutions I encountered.<\/p>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 4 :  A music bot<\/h2>\n\n\n\n<p>A normal music bot should be able to play youtube music and have the following functions.<\/p>\n\n\n\n<ul class=\"has-medium-font-size wp-block-list\"><li>play    : Add a song or a  playlist to the Queqe and invite the bot to the voice channel <\/li><li>pause : pause<\/li><li>skip    : skip current song<\/li><li>list      : show the playlist<\/li><li>clear  : clear the playlist<\/li><li>loop   : loop the playlist<\/li><li>leave : leave the voice channel<\/li><\/ul>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/f682cc66223486fc26295d72463a0dc0.js\"><\/script>\n\n\n\n<p>we define severals function that we want our music bot have.<\/p>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 5 :  Play a music<\/h2>\n\n\n\n<p>Let&#8217;s see how others play music<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/50001b1f80ce6865572dcea69021f085.js\"><\/script>\n\n\n\n<p>with this code we can understand how everything works, first, we need FFmpeg.<\/p>\n\n\n\n<p><a href=\"https:\/\/www.ffmpeg.org\/download.html\">https:\/\/www.ffmpeg.org\/download.html<\/a><\/p>\n\n\n\n<p>when a user types a play command, the code will get its message channel (<strong>ctx<\/strong>), and get the Author&#8217;s voice channel (<strong>channel<\/strong>),  then with &#8220;channel.connect()&#8221; to connect the bot to the voice channel.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>channel = ctx.message.author.voice.channel #this line will get the user's voice channel\nvoice =  await channel.connect()   # connect to the user's voice channel\n\nvoice.play(discord.FFmpegPCMAudio(song_path), after = lambda e: somefuciton())\n# play the music ,  'after' will run when the song is finish.<\/code><\/pre>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 6 :   Create a class<\/h2>\n\n\n\n<p>you may ask: why do we need a class?<\/p>\n\n\n\n<p> If our robot is to serve different servers, it means that there will be different ctx, channel, and voice, we also need to queue the songs of each channel, so the best choice is to create a class, each class serves a server.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class MusicBot:\n    def __init__(self,channel, voice , ctx):\n        self.music_msg = None       # The message for current music\n        self.loop      = False      # Enable loop or not\n        self.live      = True       # Kill this Musicbot if self.live = False\n        self.channel   = channel    # Voice channel\n        self.channelid = channel.id # This Music serves channel Id\n        self.floder    = \"music\"    # Folder to store music\n        self.ctx       = ctx        # ctx\n        self.voice     = voice      # voice client\n        self.queqed    = &#91;]         # music queqed for play\n        self.passed    = &#91;]         # Played music\n        self.state     = 0          # 0:not playing , 1:playing , 2:pause\n        self.rejoin_c  = 0          # rejoin every 20 songs\n        self.dont_stop = 0          # will play untill dont_stop = 3 to check again<\/code><\/pre>\n\n\n\n<p>so I define a class that needs channel, voice, and ctx as input.<\/p>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 7 :   Download youtube music<\/h2>\n\n\n\n<p>we know we can use youtube_dl to download the music.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install youtube-dl<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>self.ytl  = {\n                'format': '249\/250\/251',\n                \"outtmpl\" : f\"{self.floder}\/{this_song_name}\",\n                'noplaylist': False\n} \nwith youtube_dl.YoutubeDL(self.ytl) as ydl:\n    ydl.download(&#91;this_song_url])<\/code><\/pre>\n\n\n\n<p>But I think it is difficult to manage which songs the user has queued and youtube_dl will download the entire playlist before I play the music, of course, I can use a thread, But it is too complex.<\/p>\n\n\n\n<p>So, I will use a youtube data API to grab the playlist&#8217;s songs and download one at a time and play it. the following is the youtube API code, however, I will not explain this code since our main character is a <strong>discord music bot<\/strong>.<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/a40b5b2a8532d363e2f93cd13797a296.js\"><\/script>\n\n\n\n<p>with this API, I can write a function to add music to the queue<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def add_thread(self,url):\n        print(\"&#91;*] Adding rest in this thread ... \")\n        output = grab_playlist(url,50)\n        for each in output&#91;10:50]:\n            self.queqed.append(each)\n        print(\"&#91;*] Adding Thread done.\")\n        print(f\"&#91;*] Qeuqed {len(self.queqed)} songs -&gt;\",self.channelid)\n\nasync def add(self,url):\n        print(\"&#91;*]\", url)\n        if (\"list\" in url):\n            print(\"&#91;*] Adding a play list in\", self.channelid)\n            output = grab_playlist(url,10)\n            for each in output&#91;0:10]:\n                self.queqed.append(each)\n            threading.Thread(target = self.add_thread, args=(url,)).start()\n\n        else:\n            print(\"&#91;*] Adding a single video in\", self.channelid)\n            self.queqed.append((get_title(url),url))\n\n        print(\"\\n&#91;*]\",self.channelid,\"-&gt; Enqueued :\",len(self.queqed), \"the remaining songs will continue add in the background\")\n\n        if (self.state ==0):\n            self._next()  #  the play music function<\/code><\/pre>\n\n\n\n<p><strong>add <\/strong>function can handle a video or a playlist, if it is a video, just add it directly, but if it is a playlist, I will first grab the first 10 videos, the rest will throw in a thread to continue, this is to speed up the time to start the song, otherwise, the user will feel impatient.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Play command<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Users_class  = {}\n\n@client.command(brief=\"Play music (My wonderful singing )\")\nasync def play(ctx, url : str):\n    if not ctx.message.author.voice:\n        await ctx.send('you are not connected to a voice channel')\n        return\n    else:\n        channel = ctx.message.author.voice.channel\n\n    if (channel.id in Users_class):\n        if ctx.guild.voice_client not in client.voice_clients:\n            await Users_class&#91;channel.id].kill() # kill the music player\n            del Users_class&#91;channel.id]\n            print(\"&#91;*] rejoin the voice channel\")\n            voice =  await channel.connect()\n            MB = MusicBot(channel, voice , ctx)\n            Users_class&#91;channel.id] = MB\n        await Users_class&#91;channel.id].add(url)\n    else:\n        voice =  await channel.connect()\n        MB = MusicBot(channel, voice , ctx)\n        print(f\"&#91;*] creating Class id : {id(MB)} for serving channel\",channel.id)\n        Users_class&#91;channel.id] = MB\n        await MB.add(url)<\/code><\/pre>\n\n\n\n<p>In play command, I will create the music bot class and save the class to a dictionary by using channel id as the key.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># play next music\nasync def _next(self):\n\n    if (len(self.queqed) == 0):\n\n        if (self.loop): # refill the music queqed for play with Played music\n            self.queqed = self.passed\n            self.passed = &#91;]\n        else:\n            self.state = 0\n            return    \n\n    self.state = 1    # State = 1 -&gt; start playing                 \n    self.this_song  = self.queqed.pop(0) # get the song \n    self.passed.append(self.this_song)   # Store in history music\n\n    print(\"&#91;*] playing  :\", self.this_song&#91;0],\"in\", self.channelid)\n    this_song_url   = self.this_song&#91;1]\n    this_song_name  = self.this_song&#91;0]\n\n\n    #  This for is beacuse the youtube_dl will change the filename\n    #  when handling special char\n    for each_char in &#91;'\"', \"'\", \":\", \"|\"]:\n        if (each_char in this_song_name):\n            this_song_name = this_song_name.replace(each_char,\"#\")\n\n    # youtube_dl will create a floder for \\ and \/\n    for each_char in &#91;\"\\\\\", \"\/\"]:\n        if (each_char in this_song_name):\n            this_song_name = this_song_name.replace(each_char,\"\")\n\n    song_path  = os.path.join(self.floder , this_song_name)\n\n    # download youtube music\n    if ( not os.path.isfile(song_path)):\n        self.ytl  = {\n            'format': '249\/250\/251',\n            \"outtmpl\" : f\"{self.floder}\/{this_song_name}\",\n            'noplaylist': False,\n        } \n        self.dowloading = await self.ctx.send(f'... Downloading {this_song_name}')\n        print(\"&#91;*] downloading -&gt;\", this_song_name,\"\\n\")\n        with youtube_dl.YoutubeDL(self.ytl) as ydl:\n            ydl.download(&#91;this_song_url])\n        print(\"\\n&#91;*] ------------ download successful ------------\")\n\n    # Check if bot is in the voice channel\n    if self.ctx.guild.voice_client not in client.voice_clients:\n        print(\"&#91;*] get kicked from\",self.channelid)\n        return\n\n    # send currently playing music\n    self.music_msg = await self.ctx.send(f':musical_note:  Now playing ({len(self.passed)}\/{len(self.queqed)+len(self.passed)}) : {this_song_name} :musical_note:')\n\n    \n\n    ######################   I will explian this later\n    FFMPEG_OPTS = {\n        'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', \n        'options': '-vn'\n        }\n           self.rejoin_c += 1\n   if (self.rejoin_c == 10):\n         self.voice.play(\n                discord.FFmpegPCMAudio(song_path, **FFMPEG_OPTS), \n                after=lambda e: print(\"&#91;*] reconnecting the ffmpeg , error : \",e)\n                )\n        self.rejoin_c = 0\n\n        await asyncio.sleep(5)\n   ######################\n\n    # play the music, call _endsong when the song finish\n    self.voice.play(\n            discord.FFmpegPCMAudio(song_path), \n            after = lambda e: asyncio.run_coroutine_threadsafe(self._endsong(e), client.loop)\n            )\n\n    \n    # check every three song \n    self.dont_stop +=1\n    if (self.dont_stop &gt; 3):\n        client.loop.create_task(self.check())\n\n\n<\/code><\/pre>\n\n\n\n<p>This is a quite long function, but most of them are actually pretty easy to understand, except the  <strong>FFMPEG_OPTS  <\/strong>part, this part is to solve a known problem.<\/p>\n\n\n\n<p><a href=\"https:\/\/support.discord.com\/hc\/fr\/articles\/360035010351--Known-Issue-Music-Bots-Not-Playing-Music-From-Certain-Sources\">https:\/\/support.discord.com\/hc\/fr\/articles\/360035010351&#8211;Known-Issue-Music-Bots-Not-Playing-Music-From-Certain-Sources<\/a><\/p>\n\n\n\n<p>The robot will suddenly have no sound while playing a song, I often encounter this problem when I am testing,<\/p>\n\n\n\n<p>To solve this problem, you have to use that  <strong>FFMPEG_OPTS<\/strong>  variable. It will reconnect the bot to the source.<\/p>\n\n\n\n<p><span style=\"color:#ee3362\" class=\"has-inline-color\">But there is a bug, I&#8217;m not sure if it is my problem or how, my FFmpeg will show &#8220;reconnect&#8221; Option not found, I still trying to fix it.<\/span><\/p>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 8 :   Complete every thing<\/h2>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/d00bb1a5fb6a6435da2bbf086b5d3522.js\"><\/script>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/d1ecded02c84288fc51d90859ef7a6da.js\"><\/script>\n\n\n\n<p>This is my MusicBot with all the functions we want.<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/OuYangMinOa\/63412426f84ffd6ff557ca61dec8ac90.js\"><\/script>\n\n\n\n<p>Then try to run the bot and see if everything works well.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-29.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-29.png\"\/><\/figure>\n\n\n\n<h2 class=\"has-text-color wp-block-heading\" style=\"color:#3979a8\">Step 9 :   Develop on server<\/h2>\n\n\n\n<p>Now try to put this robot on a server, you can use Heroku or something else, for me , I will put it on the Raspberry Pi <\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/dwzZ6giNPkhGbmumGqcT1PEHXUM6vGh4-KH6_DN6_W43eWgqiB8m7VIbTTmKkWdaTemgixIxJypIOTqtoiBrsGcG7nSMipYBg5k67A-0w4ft3BqpL_HRGePRdXz01S3euElu2lizy2EdfJV1iNwZ5fAT34kkylwHbI3wvwEoJZTZB8bKwSYWvw1YKUJ_qflXvbUVhjiBiQ6MBd95jHfg45hgcuPJSYYmw9UaGIPFTeUGzem7IT7AttdDi15Y3EeRxWd-ljVAurT4kifjwQ73j807SordCQY8M4Znj-xWB-22sS0CsqHsD3-t8QtbDNM8q95K0Y-vAM_X1ZaYIMs1lphaauKtIzhYAYtBsa_uSLwxEWVpFwUz6e5bPm2_mJnIylvd2h3W_qbUH9iltC3B9NVDO1_UBmOTqeS3l7q6l0lUjbGoe7ogyNwILFaFku_Cb9Je9lmhwqkkjvNfk7vqRjgzwJdU9kCWqsR8PBtPXIpCfuap6rxJ0OLem-89UQBtSetp5tZSvwbtvhXEMlRLHzOWBnKJ5QB7gZbng7n_MN84NyudLsFQZF4bRIJ3zLG-zTZFjzCmg3AtlZsdc_yGH8itL_B7C_693uM31TZvk-F47ZM5oD37Q5bP1hMBwe6_ntYX1vnKpKfwHa-5Ro0JXL1Nr_I7FY16IpCu2FGJ9JVQav8-XMGOpQhrbyMyeAihJSVTiy8GRk8lYFU3eAzCJrQ=w678-h903-no?authuser=1\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba dwzZ6giNPkhGbmumGqcT1PEHXUM6vGh4-KH6_DN6_W43eWgqiB8m7VIbTTmKkWdaTemgixIxJypIOTqtoiBrsGcG7nSMipYBg5k67A-0w4ft3BqpL_HRGePRdXz01S3euElu2lizy2EdfJV1iNwZ5fAT34kkylwHbI3wvwEoJZTZB8bKwSYWvw1YKUJ_qflXvbUVhjiBiQ6MBd95jHfg45hgcuPJSYYmw9UaGIPFTeUGzem7IT7AttdDi15Y3EeRxWd-ljVAurT4kifjwQ73j807SordCQY8M4Znj-xWB-22sS0CsqHsD3-t8QtbDNM8q95K0Y-vAM_X1ZaYIMs1lphaauKtIzhYAYtBsa_uSLwxEWVpFwUz6e5bPm2_mJnIylvd2h3W_qbUH9iltC3B9NVDO1_UBmOTqeS3l7q6l0lUjbGoe7ogyNwILFaFku_Cb9Je9lmhwqkkjvNfk7vqRjgzwJdU9kCWqsR8PBtPXIpCfuap6rxJ0OLem-89UQBtSetp5tZSvwbtvhXEMlRLHzOWBnKJ5QB7gZbng7n_MN84NyudLsFQZF4bRIJ3zLG-zTZFjzCmg3AtlZsdc_yGH8itL_B7C_693uM31TZvk-F47ZM5oD37Q5bP1hMBwe6_ntYX1vnKpKfwHa-5Ro0JXL1Nr_I7FY16IpCu2FGJ9JVQav8-XMGOpQhrbyMyeAihJSVTiy8GRk8lYFU3eAzCJrQ=w678-h903-no\"\/><\/figure>\n\n\n\n<p>So, first I will use python to open a simple webserver on windows to send my bot&#8217;s code to  Raspberry Pi .<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python -m http.server<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-30.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-30.png\"\/><\/figure>\n\n\n\n<p>Cause I&#8217;m connect to the same route, so I can use the local internet to send my bot, use Ip config to get you computer&#8217;s local IP<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ipconfig<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-35.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-35.png\"\/><\/figure>\n\n\n\n<p>Just wget the  ip: port\/file and you can grab the file<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-31-1024x535.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-31-1024x535.png\"\/><\/figure>\n\n\n\n<p>Set up your environment and run the server<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install google-api-python-client\npip install discord.py\npip install youtube_dl\nsudo apt install ffmpeg<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"http:\/\/ouyangminwei.com\/wp-content\/uploads\/2021\/09\/image-32-1024x268.png\" alt=\"\u9019\u5f35\u5716\u7247\u7684 alt \u5c6c\u6027\u503c\u70ba\u7a7a\uff0c\u5b83\u7684\u6a94\u6848\u540d\u7a31\u70ba image-32-1024x268.png\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span style=\"color:#ec5a00\" class=\"has-inline-color\">Congratulations, you successfully made your own robot !!!<\/span><\/h2>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/www.theverge.com\/2021\/8\/24\/22640 &hellip; <a href=\"https:\/\/ouyangminwei.com\/index.php\/2021\/09\/18\/build-a-discrod-music-bot\/\">\u95b1\u8b80\u5168\u6587 <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[7,3],"post_format":[],"class_list":["post-116","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-en","tag-python"],"_edit_lock":"1633359787:1","_edit_last":"1","_aioseo_title":"#post_title #separator_sa #site_title","_aioseo_description":"#post_excerpt","_aioseo_keywords":"","_aioseo_og_title":"","_aioseo_og_description":"","_aioseo_og_article_section":"","_aioseo_og_article_tags":"","_aioseo_twitter_title":"","_aioseo_twitter_description":"","_oembed_2544c1d0cb3503ab4c4d558c3b3c8873":"","_oembed_time_2544c1d0cb3503ab4c4d558c3b3c8873":"","_oembed_99481806ecbe6ce4ee46f8588d320993":"","_oembed_db663acf973e82e6d9d80df71945dfb8":"{{unknown}}","_oembed_16cdfab488f57db73586f4286af2704f":"{{unknown}}","_wp_old_slug":"","_links":{"self":[{"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/posts\/116","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/comments?post=116"}],"version-history":[{"count":12,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/posts\/116\/revisions"}],"predecessor-version":[{"id":148,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/posts\/116\/revisions\/148"}],"wp:attachment":[{"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/media?parent=116"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/categories?post=116"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/tags?post=116"},{"taxonomy":"post_format","embeddable":true,"href":"https:\/\/ouyangminwei.com\/index.php\/wp-json\/wp\/v2\/post_format?post=116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}