From aa4afc325507ae4f44881869037714d836fd8216 Mon Sep 17 00:00:00 2001 From: Irdumb Date: Wed, 6 Apr 2016 00:53:38 +1000 Subject: [PATCH 1/8] added sound effects support !sfx - plays the specified sound file from the data/audio/sfx directory !audioset sfx - toggles sfx for server !list sfx - lists sound effects Gives responsibility of `!stop`ping a stuck player to the user, like the other audio commands do --- cogs/audio.py | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/cogs/audio.py b/cogs/audio.py index 35d1a933b..6d869e4b0 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -49,6 +49,7 @@ class Audio: def __init__(self, bot): self.bot = bot self.music_player = EmptyPlayer() + self.sfx_player = EmptyPlayer() self.settings = fileIO("data/audio/settings.json", "load") self.queue_mode = False self.queue = [] @@ -209,6 +210,70 @@ class Audio: else: await self.bot.say("There are no valid playlists in the localtracks folder.\nIf you're the owner, see {}".format(help_link)) + @commands.command(pass_context=True, no_pm=True) + async def sfx(self, ctx, name : str): + """Plays a local sound file + + For bot's owner: + audio files must be placed in the data/audio/sfx folder. + Supported files are mp3, flac, wav""" + #sound effects default enabled + server = ctx.message.server + if self.settings["SERVER_SFX_ON"].get(server.id,None) is None: + self.settings["SERVER_SFX_ON"][server.id] = True + if not self.settings["SERVER_SFX_ON"][server.id]: + await self.bot.say("Sound effects are not enabled on this server") + return + + msg = ctx.message + localsfx = self.get_local_sfx() + if localsfx and ("data/audio/sfx/" not in name and "\\" not in name): + if name in localsfx.keys(): + file = "data/audio/sfx/{}{}".format(name,localsfx[name]) + + if await self.check_voice(msg.author, ctx.message): + try: + if self.music_player.is_playing(): + self.music_player.paused = True + self.music_player.pause() + + if self.sfx_player.is_playing(): + self.sfx_player.stop() + + self.sfx_player = self.bot.voice.create_ffmpeg_player(file, options='''-filter:a "volume={}"'''.format(self.settings["VOLUME"])) + self.sfx_player.start() + while self.sfx_player.is_playing(): + await asyncio.sleep(.5) + + if not self.music_player.is_playing(): + self.music_player.paused = False + self.music_player.resume() + except AttributeError: + #music_player not used yet. Still an EmptyPlayer. + #better to ask for forgiveness? + pass + except Exception as e: + print(e) + + else: + await self.bot.say("There is no sound effect with that name.") + else: + await self.bot.say("There are no valid sound effects in the data/audio/sfx folder.") + + def get_local_sfx(self): + filenames = {} + files = os.listdir("data/audio/sfx/") + #only reason why these are the only supported ext is cause I haven't tried any others + supported = [".mp3",".flac",".wav"] + for f in files: + item = os.path.splitext(f) + if item[1] in supported: + filenames[item[0]] = item[1] + if filenames != {}: + return filenames + else: + return False + @commands.command(pass_context=True, no_pm=True) async def loop(self, ctx): """Loops single song @@ -273,6 +338,7 @@ class Audio: self.playlist = [] self.current = -1 if self.music_player.is_playing(): self.music_player.stop() + if self.sfx_player.is_playing(): self.sfx_player.stop() await asyncio.sleep(1) if self.bot.voice: await self.bot.voice.disconnect() @@ -397,6 +463,21 @@ class Audio: else: await self.bot.say("There are no local playlists.") + @_list.command(name="sfx", pass_context=True) + async def list_sfx(self, ctx): + msg = "Available local sound effects: \n\n```" + files = self.get_local_sfx() + if files: + for i, d in enumerate(files.keys()): + if i % 4 == 0 and i != 0: + msg = msg + d + "\n" + else: + msg = msg + d + "\t" + msg += "```" + await self.bot.send_message(ctx.message.author, msg) + else: + await self.bot.say("There are no local sound effects.") + @_list.command(name="queue", pass_context=True) async def list_queue(self, ctx): queue_list = await self.queue_titles() @@ -471,6 +552,22 @@ class Audio: else: await self.bot.say("Volume must be between 0 and 1. Example: 0.40") + @audioset.command(name="sfx", pass_context=True) + async def _sfx(self, ctx): + """Enables/Disables sound effects usage in the server""" + #default on. + server = ctx.message.server + if self.settings["SERVER_SFX_ON"].get(server.id,None) is None: + self.settings["SERVER_SFX_ON"][server.id] = True + else: + self.settings["SERVER_SFX_ON"][server.id] = not self.settings["SERVER_SFX_ON"][server.id] + #for a toggle, settings should save here in case bot fails to send message + fileIO("data/audio/settings.json", "save", self.settings) + if self.settings["SERVER_SFX_ON"][server.id]: + await self.bot.say("Sound effects are now enabled on this server.") + else: + await self.bot.say("Sound effects are now disabled on this server.") + @audioset.command() @checks.is_owner() async def maxcache(self, size : int): @@ -538,6 +635,11 @@ class Audio: if self.downloader["ID"]: try: if self.music_player.is_playing(): self.music_player.stop() + # sfx_player should only ever get stuck as much as music_player does + # when it happens to music_player, the reponsibility is put on the user to !stop + # so we'll do the same with sfx_player. a timeout could be placed here though. + while self.sfx_player.is_playing(): + await asyncio.sleep(.5) self.music_player = self.bot.voice.create_ffmpeg_player(path + self.downloader["ID"], options='''-filter:a "volume={}"'''.format(self.settings["VOLUME"])) self.music_player.paused = False self.music_player.start() @@ -822,7 +924,7 @@ class MaximumLength(Exception): return self.message def check_folders(): - folders = ("data/audio", "data/audio/cache", "data/audio/playlists", "data/audio/localtracks") + folders = ("data/audio", "data/audio/cache", "data/audio/playlists", "data/audio/localtracks", "data/audio/sfx") for folder in folders: if not os.path.exists(folder): print("Creating " + folder + " folder...") @@ -830,7 +932,7 @@ def check_folders(): def check_files(): - default = {"VOLUME" : 0.5, "MAX_LENGTH" : 3700, "QUEUE_MODE" : True, "MAX_CACHE" : 0, "SOUNDCLOUD_CLIENT_ID": None, "TITLE_STATUS" : True} + default = {"VOLUME" : 0.5, "MAX_LENGTH" : 3700, "QUEUE_MODE" : True, "MAX_CACHE" : 0, "SOUNDCLOUD_CLIENT_ID": None, "TITLE_STATUS" : True, "SERVER_SFX_ON" : {}} settings_path = "data/audio/settings.json" if not os.path.isfile(settings_path): From 7259ae0fcc159e0733db43953020b15de4a0e504 Mon Sep 17 00:00:00 2001 From: Irdumb Date: Wed, 6 Apr 2016 22:37:07 +1000 Subject: [PATCH 2/8] correctly stops sfx and minor formatting --- cogs/audio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cogs/audio.py b/cogs/audio.py index 6d869e4b0..aca19cc9d 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -258,7 +258,7 @@ class Audio: else: await self.bot.say("There is no sound effect with that name.") else: - await self.bot.say("There are no valid sound effects in the data/audio/sfx folder.") + await self.bot.say("There are no valid sound effects in the `data/audio/sfx` folder.") def get_local_sfx(self): filenames = {} @@ -325,7 +325,7 @@ class Audio: """Stops audio activity """ msg = ctx.message - if self.music_player.is_playing(): + if self.music_player.is_playing() or self.sfx_player.is_playing(): if await self.is_alone_or_admin(msg): await self.close_audio() else: From 3cb7ea02ad01ce15ccf0740015752b3e7a5a5a17 Mon Sep 17 00:00:00 2001 From: Irdumb Date: Wed, 6 Apr 2016 23:19:18 +1000 Subject: [PATCH 3/8] no_pm for sfx toggle --- cogs/audio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cogs/audio.py b/cogs/audio.py index aca19cc9d..2f13609ea 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -552,7 +552,7 @@ class Audio: else: await self.bot.say("Volume must be between 0 and 1. Example: 0.40") - @audioset.command(name="sfx", pass_context=True) + @audioset.command(name="sfx", pass_context=True, no_pm=True) async def _sfx(self, ctx): """Enables/Disables sound effects usage in the server""" #default on. From 607cde76f49fa3d34acefabf30a5f22aac22396f Mon Sep 17 00:00:00 2001 From: Irdumb Date: Fri, 8 Apr 2016 16:45:47 +1000 Subject: [PATCH 4/8] support for sfx list >2k characters didn't add paging to the other list commands as per request be Twentysix?? I may have misunderstood. Doesn't account for sfx with emoji in their names. I'm not sure if that's even possible. --- cogs/audio.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/cogs/audio.py b/cogs/audio.py index 2f13609ea..deabe7172 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -465,16 +465,25 @@ class Audio: @_list.command(name="sfx", pass_context=True) async def list_sfx(self, ctx): - msg = "Available local sound effects: \n\n```" + msgs = ["Available local sound effects: \n\n```\n"] files = self.get_local_sfx() + m = 0 + maxm = 1980 if files: for i, d in enumerate(files.keys()): - if i % 4 == 0 and i != 0: - msg = msg + d + "\n" - else: - msg = msg + d + "\t" - msg += "```" - await self.bot.send_message(ctx.message.author, msg) + if len(d) < maxm: #how did you get a filename this large? + if len(msgs[m]) + len(d) > maxm: + msgs[m] += "```" + m += 1 + msgs.append("```\n") + if i % 4 == 0 and i != 0: + msgs[m] += d + "\n" + else: + msgs[m] += d + "\t" + msgs[m] += "```" + for msg in msgs: + await self.bot.send_message(ctx.message.author, msg) + await asyncio.sleep(1) else: await self.bot.say("There are no local sound effects.") From 54dc976f3a0cd579bdaf1db02145437fdda6a9a6 Mon Sep 17 00:00:00 2001 From: Irdumb Date: Sun, 10 Apr 2016 08:32:14 +1000 Subject: [PATCH 5/8] some behaviors & multiword sfx added some of the music control behaviors quotes now not needed for multiword sfx --- cogs/audio.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cogs/audio.py b/cogs/audio.py index deabe7172..a2bf1223c 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -148,6 +148,8 @@ class Audio: self.music_player.stop() else: await self.vote_skip(msg) + elif self.sfx_player.is_playing(): + self.sfx_player.stop() async def vote_skip(self, msg): v_channel = msg.server.me.voice_channel @@ -211,7 +213,7 @@ class Audio: await self.bot.say("There are no valid playlists in the localtracks folder.\nIf you're the owner, see {}".format(help_link)) @commands.command(pass_context=True, no_pm=True) - async def sfx(self, ctx, name : str): + async def sfx(self, ctx, *, name : str): """Plays a local sound file For bot's owner: @@ -337,8 +339,8 @@ class Audio: self.queue = [] self.playlist = [] self.current = -1 - if self.music_player.is_playing(): self.music_player.stop() - if self.sfx_player.is_playing(): self.sfx_player.stop() + if not self.music_player.is_done(): self.music_player.stop() + if not self.sfx_player.is_done(): self.sfx_player.stop() await asyncio.sleep(1) if self.bot.voice: await self.bot.voice.disconnect() @@ -421,7 +423,9 @@ class Audio: @commands.command() async def resume(self): """Resumes paused song.""" - if not self.music_player.is_playing(): + if self.sfx_player.is_playing(): + self.sfx_player.stop() + elif not self.music_player.is_playing(): self.music_player.paused = False self.music_player.resume() await self.bot.say("Resuming song.") From 162916db18e7fb02480c49c6fd1f51ace65f3edb Mon Sep 17 00:00:00 2001 From: Irdumb Date: Sun, 10 Apr 2016 10:50:55 +1000 Subject: [PATCH 6/8] behavior + is_done + bug fix !play behavior put is_done in EmptyPlayer so bot stops complaining fixed !queue > !sfx > !mix bug --- cogs/audio.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cogs/audio.py b/cogs/audio.py index a2bf1223c..8b078826f 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -87,7 +87,8 @@ class Audio: self.playlist = [] self.queue.append(link) self.music_player.paused = False - if self.music_player.is_playing(): self.music_player.stop() + if not self.sfx_player.is_done(): self.sfx_player.stop() + if not self.music_player.is_done(): self.music_player.stop() await self.bot.say("Playing requested link...") else: self.playlist = [] @@ -647,12 +648,12 @@ class Audio: await asyncio.sleep(1) if self.downloader["ID"]: try: - if self.music_player.is_playing(): self.music_player.stop() # sfx_player should only ever get stuck as much as music_player does # when it happens to music_player, the reponsibility is put on the user to !stop # so we'll do the same with sfx_player. a timeout could be placed here though. while self.sfx_player.is_playing(): await asyncio.sleep(.5) + if not self.music_player.is_done(): self.music_player.stop() self.music_player = self.bot.voice.create_ffmpeg_player(path + self.downloader["ID"], options='''-filter:a "volume={}"'''.format(self.settings["VOLUME"])) self.music_player.paused = False self.music_player.start() @@ -930,6 +931,9 @@ class EmptyPlayer(): #dummy player def is_playing(self): return False + def is_done(self): + return True + class MaximumLength(Exception): def __init__(self, m): self.message = m From d39c1baf920107fd63930bd20017ccc167432007 Mon Sep 17 00:00:00 2001 From: Irdumb Date: Sun, 10 Apr 2016 20:12:45 +1000 Subject: [PATCH 7/8] display only server-specific settings if available assumes server-specific settings are stored uhhhhh shoot, lemme just give an example. { "MAX_CACHE": 50, "SERVER_SFX_ON": { "server1_id_here":True, "server2_id_here":False } } --- cogs/audio.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cogs/audio.py b/cogs/audio.py index 8b078826f..d163e9f1e 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -522,10 +522,14 @@ class Audio: async def audioset(self, ctx): """Changes audio module settings""" if ctx.invoked_subcommand is None: + server = ctx.message.server await send_cmd_help(ctx) msg = "```" for k, v in self.settings.items(): - msg += str(k) + ": " + str(v) + "\n" + if type(v) is dict and server.id in v: + msg += str(k) + ": " + str(v[server.id]) + "\n" + else: + msg += str(k) + ": " + str(v) + "\n" msg += "```" await self.bot.say(msg) From ce6dd852c47fb89595b5c69acc9804cc2e482507 Mon Sep 17 00:00:00 2001 From: Irdumb Date: Mon, 11 Apr 2016 13:21:31 +1000 Subject: [PATCH 8/8] you call it refactoring right? --- cogs/audio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cogs/audio.py b/cogs/audio.py index d163e9f1e..8c4f87cda 100644 --- a/cogs/audio.py +++ b/cogs/audio.py @@ -222,7 +222,7 @@ class Audio: Supported files are mp3, flac, wav""" #sound effects default enabled server = ctx.message.server - if self.settings["SERVER_SFX_ON"].get(server.id,None) is None: + if server.id not in self.settings["SERVER_SFX_ON"]: self.settings["SERVER_SFX_ON"][server.id] = True if not self.settings["SERVER_SFX_ON"][server.id]: await self.bot.say("Sound effects are not enabled on this server") @@ -575,7 +575,7 @@ class Audio: """Enables/Disables sound effects usage in the server""" #default on. server = ctx.message.server - if self.settings["SERVER_SFX_ON"].get(server.id,None) is None: + if server.id not in self.settings["SERVER_SFX_ON"]: self.settings["SERVER_SFX_ON"][server.id] = True else: self.settings["SERVER_SFX_ON"][server.id] = not self.settings["SERVER_SFX_ON"][server.id]