This shows you the differences between two versions of the page.
ii:labs:04:tasks:03 [2021/12/06 18:02] radu.mantu |
ii:labs:04:tasks:03 [2024/11/20 16:03] (current) florin.stancu created |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ==== 03. [??p] Adding & changing features ==== | + | ==== 03. [40p] Adding features ==== |
- | When you want to add a new feature to your project, you should first develop it in a [[https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches|branch]]. A branch is a named copy of the deltas that comprise your codebase up to a certain point. By adding commits to this copy, you won't interfere with other people trying to do their own thing. Note that a branch can be created from any other branch, including //master//. | + | Up until now, everything was pretty tutorial-ish. From here on out, it's time for you to get your hands dirty and add some new features to the bot! This means looking stuff on the Internet. For yourselves. Scary stuff... I know! \\ |
+ | **Hint:** a good starting point would be the [[https://docs.pycord.dev/en/stable/api/index.html|API Reference page]]. | ||
- | {{ :ii:labs:04:tasks:branches.png?700 |}} | + | === [20p] Task A - Playing music === |
- | Eventually, you will want to merge your commits with the original branch. This can be done in two ways: ''git merge'' or ''git rebase''. Here is a [[https://www.atlassian.com/git/tutorials/merging-vs-rebasing|discussion]] on which is better. You should probably read it at some point. In this lab we will be focusing on ''git rebase'' since it is more interactive and provides many functionalities that you will need when trying to get your changes accepted by the maintainer / reviewer. | + | Let's begin by adding the most important feature of a music bot: a ''play'' command that takes a song name (e.g.: [[https://www.youtube.com/watch?v=yK0P1Bk8Cx4|danger_zone.mp3]]) as argument. Invoking this command while present in a voice channel should cause the bot to connect to that channel and play the song. The song should be loaded from a local file (hint: use any music file that you have on hand, or a [[https://x2convert.com/en129/download-youtube-to-mp3-music|YouTube downloader]]). |
- | === [??p] Task A - Add token flag === | + | In order to do that, please note how the commands are defined: |
- | The feature that you'll want to add to your project is a command line argument parser that will accept an optional ''%%-t, --token [TOKEN]%%''. We suggest that you use [[https://docs.python.org/3/howto/argparse.html|argparse]]. In absence of this token, you will fall back to fetching it from the environment variable. | + | <code python> |
+ | @bot.command(brief='Generate random number between 1 and <arg>') | ||
+ | async def roll(ctx, max_val: int): | ||
+ | # implementation goes here ... | ||
+ | </code> | ||
- | <code bash> | + | To create new discord bot commands, simply define your function with the name of the command and decorate them with [[https://docs.pycord.dev/en/stable/api/application_commands.html#discord.commands.application_command|@bot.command]] as above. Oh, and whats with that '': int'' declaration? I thought Python doesn't require us to give types to our variables... that's right! But [[https://docs.python.org/3/library/typing.html|we're now able to]], if we want ;) |
- | # first, create a new branch from HEAD | + | |
- | $ git branch feature | + | |
- | # next, switch to the feature branch | + | But, as expected, the hardest part will be implementing it. There are several questions: how can you load an ''.mp3'' file from disk? how can you send it streaming over the Discord server? etc. |
- | $ git checkout branch | + | |
- | # check that the branch you are is actually feature and not master | + | You will need to read some more API references to find the appropiate calls: |
- | $ git branch | + | |
- | * feature | + | |
- | master | + | |
- | + | ||
- | # edit and test your script | + | |
- | # argparse should add a default '--help' option | + | |
- | # commit changes and push them to the remote feature branch | + | * Start from [[https://docs.pycord.dev/en/stable/api/voice.html#discord.VoiceClient|VoiceClient]]. You can read that it provides a ''play()'' function, though note that you cannot instantiate this directly... so we'll move on through the links! |
- | # first push means that the branch needs to be created (follow the command's hints) | + | * Next is the ''VoiceChannel.connect()'' routine that gives us a voice channel, but how to we get a voice channel object? |
- | $ git add ${BOT_SCRIPT} | + | * Here's the idea: find the voice channel the user issuing the play command is connected to! |
- | $ git commit -s | + | * So we start from our ''ctx'' variable, which we can find that is of type [[https://docs.pycord.dev/en/stable/api/application_commands.html#discord.ApplicationContext|ApplicationContext]] (ofc!); we follow up with the ''author'', which has a ''voice'' property (of type ''VoiceState''), which finally brings us to our desired channel! |
- | $ git push | + | * Once we got ahold of our ''VoiceChannel'', we connect to it and we finally get a ''VoiceClient'', phew! Now we can simply use ''play()''... |
- | </code> | + | * What's that? ''play()'' requires an [[https://docs.pycord.dev/en/stable/api/voice.html#discord.AudioSource|AudioSource]]-type argument? We just need something that reads ''mp3'' files... oh, we see a [[https://www.ffmpeg.org/|ffmpeg]] naming in there, which is a very popular open source library which can read almost every audio/video format in existence (check the right side menu!), so problem solved! |
+ | * Now get to writing the code! :P | ||
- | At this point, you have created a separate //feature// branch, added a (hopefully) working CLI argument parser, and pushed the newly created branch to your //remote//. When working with other people, now would be a good time to create a [[https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request|Pull Request]] (PR). This is a request to the maintainer of the project to pull your //feature// branch, check that everything is working, and give feedback if changes need be made. If changes are indeed requested, all you have to do is address them in a new commit which you'll push into your //feature// branch. The PR will be updated automatically. Once the reviewer gives his ok, your changes will be applied to the //master// branch. | + | <note> |
+ | **Hint:** check this out for an example: https://brucecodes.gitbook.io/pycord/guide/voice-commands | ||
+ | </note> | ||
- | Since this is your repository and you have to deal with integrating the changes, let's use ''git rebase'' to do just that. | + | === [10p] Task B - Enumerating the songs === |
- | <code bash> | + | This one is easier: build a **list** command that lists all available songs in the discord chat. |
- | # switch back to the master branch | + | |
- | $ git checkout master | + | |
- | # apply the extra commits from feature onto master | + | Use the basic Python [[https://docs.python.org/3/library/os.html|OS functions]] for easily reading directory contents and filtering by ''mp3'' extension. |
- | $ git rebase feature | + | |
- | Successfully rebased and updated refs/heads/master. | + | |
- | # remember to push the newly integrated changes to remote | ||
- | $ git push | ||
- | </code> | ||
- | //"Wait. That's it?"// Well... yeah. Luckily, you did not have any conflicts with //master//. If you did, ''git rebase'' would have told you exactly where those conflicts were located. Moreover, it would have modified your files to look something like this: | + | === [10p] Task C - Misc commands === |
- | <code> | + | |
- | <<<<<<< HEAD | + | |
- | Changes made to master since branch. | + | |
- | ======= | + | |
- | Changes made to feature since branch. | + | |
- | >>>>>>> feature | + | |
- | </code> | + | |
- | In order to resolve the conflicts, you would have to remove the lines with //%%"<<<"%%//, //%%"==="%%//, //%%">>>"%%// and rewrite the conflicting code so that it incorporates both your changes, and those already pushed to //master//. Finally, mark the conflicts as resolved by re-adding the files, and continue your rebase. | + | Let's assume someone enters your channel and [[https://www.youtube.com/watch?v=nZ-hHx9yh0s|plays this]]. We'll need a quick solution... |
- | <code bash> | + | So: create a **scram** command that tells the bot to disconnect from the current voice channel immediately (which will stop the play!). |
- | # re-add files with solved conflicts | + | |
- | $ git add ${CONFLICTING_FILES} | + | |
- | # continue the rebase process | + | Finally, make an event handler for ''on_voice_state_update'' that checks if the bot was left alone in the channel after a user left. If the bot is indeed alone, it should also disconnect. |
- | $ git rebase --continue | + | |
- | # alternatively, you can just give up and go back to how things were (no harm done) | + | That's it! |
- | $ git rebase --abort | + | |
- | </code> | + | |
- | This part is now optional, but it would be nice to clean up and delete the //feature// branch both locally and remotely. All changes that //feature// held are not part of //master//, so what's it good for? | ||
- | <code bash> | ||
- | # delete feature branch on remote (origin) | ||
- | $ git push -d origin feature | ||
- | |||
- | # delete feature branch locally | ||
- | $ git branch -d feature | ||
- | </code> |