async def call(self, **kwargs): if not (hasattr(self.msg.guild, "voice_client") and self.msg.guild.voice_client): await self.respond( "I'm currently not in a voice channel on this server.", True) return targetChannel = self.msg.guild.voice_client.channel if not self.msg.author.voice.channel == targetChannel: await self.respond( "You have to be in my voice channel to play your voiceline!", True) return dir = os.listdir(SOUND_DIR + "voicelines") for i in dir: if os.path.isdir(SOUND_DIR + "voicelines/" + i) and i == str( self.msg.author.id): #we have a voiceline for this member files = os.listdir(SOUND_DIR + "voicelines/" + i) sound = FFMPEGSound(SOUND_DIR + "voicelines/" + i + "/" + random.choice(files)) self.playSound( sound, targetChannel, False ) #Don't sync member voicelines; this may be a bad idea... return await self.respond( "You don't have a voiceline associated with your user ID!", True) return
async def call(self, **kwargs): if not (hasattr(self.msg.guild, "voice_client") and self.msg.guild.voice_client): await self.respond("I'm currently not in a voice channel on this server.",True) return dir = os.listdir(SOUND_DIR+"lucio") line = random.choice(dir) sound = FFMPEGSound(SOUND_DIR+"lucio/"+line) self.playSound(sound, self.msg.guild.voice_client.channel, False)
async def on_voice_state_update(self, what, before, after): before_channel = before.channel after_channel = after.channel #Voice line handling if (after_channel and after_channel != before_channel): #if the user is connected and has changed his voice channel (this may mean he just joined) if what.guild.voice_client and (after_channel == what.guild.voice_client.channel): #we are in the same channel as our target #Use new dynamic voiceline handling (voicelines are compared by User ID / Filename instead of a dictionary lookup #This isn't necessarily any faster but it is more convenient and doesn't require a restart to assign voicelines dir = os.listdir(self.SOUND_DIR / "voicelines") for i in dir: if os.path.isdir(self.SOUND_DIR / "voicelines" / i) and i == str(what.id): #we have a voiceline folder for this member files = os.listdir(self.SOUND_DIR / "voicelines" / i) if not files: #no voicelines found, return return filepath = self.SOUND_DIR / "voicelines" / i / random.choice(files) sound = FFMPEGSound(filepath.as_posix()) self.audio.playSound(sound, after_channel, sync=False) return
async def call(self, target, options=""): try: ch = self.msg.server.voice_client.channel except AttributeError: await self.respond("unable to play FFMPEG sound: Not connected to a voice channel on this server.", True) return try: snd = FFMPEGSound(target, shlex.split(options)) except AudioError as e: await self.respond("unable to create FFMPEG sound instance: %s" % str(e), True) return try: self.playSound(snd, ch) except AudioError as e: await self.respond("unable to play FFMPEG sound on channel %s: %s" % (ch.name, str(e)), True) return await self.respond("Queued **%s**." % target)
def playSound(self, sound, message): """ Tries to play a sound in the server the message was sent from. If no sound backend is available, this method is a noop. """ if not self.audioManager: return try: vc = message.guild.voice_client channel = vc.channel except AttributeError: return #This is easier than LBYL if not (vc and channel): return sound = FFMPEGSound(sound) self.audioManager.playSound(sound, channel, True) return True
async def call(self, query, **kwargs): loop = asyncio.get_event_loop() if not (hasattr(self.msg.guild, "voice_client") and self.msg.guild.voice_client): await self.respond( "I'm currently not in a voice channel on this server.", True) return targetChannel = self.msg.guild.voice_client.channel #LOCAL MUSIC FILES localquery = query.lower() #make query string match all cases dir = os.listdir("tracks") for i in dir: if i.lower().rsplit(".")[0] == localquery: sound = FFMPEGSound("tracks/" + i) self.playSound(sound, targetChannel) await self.respond("Queued %s." % chatutils.mdItalic(i)) return #YOUTUBE_DL if HAS_YTDL: #TODO: Currently, users could exploit the way the search engines work to add arbitrary query arguments to the HTTP call. #Fix this by escaping the query string if YTDL is to be used. if localquery.startswith("search "): q = query[7:] searchEngine = YouTubeSearch( self.config.getElementText("google.api.token")) query = await self.search(q, searchEngine, 0xFF0000) if not query: return elif localquery.startswith("youtube "): q = query[8:] searchEngine = YouTubeSearch( self.config.getElementText("google.api.token")) query = await self.search(q, searchEngine, 0xFF0000) if not query: return elif localquery.startswith("soundcloud "): q = query[11:] #Since SoundCloud doesn't allow new client applications right now, #we try to use the youtube_dl client ID (which may end up blocked or rate limited very fast) searchEngine = SoundCloudSearch( self.config.getElementText("soundcloud.clientID", SoundcloudIE._CLIENT_ID)) query = await self.search(q, searchEngine, 0xFF5500) if not query: return #New playlist handling code #We need to do youtube_dl handling manually await self.respond("Looking for requested resource online...") yt = youtube_dl.YoutubeDL(YOUTUBE_DL_OPTIONS) try: self.logger.debug( "Trying to extract youtube stream information...") func = functools.partial(yt.extract_info, query, **YOUTUBE_DL_EXTRACT_OPTIONS) info = await asyncio.get_event_loop().run_in_executor( None, func) except: self.logger.exception("YTDL failed: ") await self.respond("Couldn't find a file matching your query.", True) return #consolidate single videos to pseudo playlists if "_type" in info and info["_type"] == "playlist": await self.respond( "Playlist detected at source location, launching experimental playlist handling code.\nExamining source manifest..." ) entries = info["entries"] else: entries = [info] listLength = len(entries) await self.respond("%i source %s found, downloading..." % (listLength, ("entries" if listLength > 1 else "entry"))) i = 0 for track in entries: i += 1 self.logger.debug("Queuing entry %i of %i total: %s" % (i, listLength, track["webpage_url"])) url = track["url"] author = track["uploader"] if "uploader" in track else "Unknown" title = track["title"] if "title" in track else "Untitled" #this is necessary because the WebResourceSound downloads the target resource on instance creation. #Since this can take quite some time, the websocket can timeout before the sound is ready since the #program blocks because we can't await inside of a constructor. sound = await loop.run_in_executor( None, lambda: WebResourceSound( track["url"], author=author, title=title)) self.playSound(sound, targetChannel) await self.respond("Queued %i track(s)." % i) return await self.respond("Couldn't find a file matching your query.", True) return
async def call(self, channel, path, **kwargs): sound = FFMPEGSound(BASE_PATH + path) self.playSound(sound, channel, False)