Exemple #1
0
    def set_voice_client(self, voice_client: discord.VoiceClient):
        """Set new voice client to the state.

        If the same client is provided, does nothing.
        If other voice client is present, it will be removed and all playing
        audio sources will be immediately finished first.

        TODO: Hey, we can change voice client, that is owned by guild/channel
        with a voice client key != our voice client key. Do something!

        Args:
            voice_client: Voice client to set.

        Raises:
            ValueError: If not a :class:`discord.VoiceClient` provided, or voice
                client is not connected.
        """
        if not isinstance(voice_client, discord.VoiceClient):
            raise ValueError("Not a voice client")
        if voice_client == self._voice_client:
            return
        if not voice_client.is_connected():
            raise ValueError("Voice client is not connected")
        if self._voice_client is not None:
            self.remove_voice_client()

        self._loop = voice_client.loop
        self._voice_client = voice_client
        self._voice_client_disconnect_source = voice_client.disconnect
        voice_client.disconnect = self._on_disconnect

        log.debug(f"Voice client has set (Voice client key ID #{self._key_id})")
Exemple #2
0
async def play_forever(vc: discord.VoiceClient):
    event = asyncio.Event()
    while vc.is_connected():
        audio = discord.FFmpegPCMAudio('resources/shame.mp3')
        vc.play(audio, after=lambda _: event.set())
        await event.wait()
        event.clear()
Exemple #3
0
    def play_song(self, client: VoiceClient, url):
        if not client.is_connected():
            return
        song_there = os.path.isfile("song.mp3")
        try:
            if song_there:
                os.remove("song.mp3")
        except PermissionError:
            print('error')
            return
        print("Someone wants to play music let me get that ready for them...")
        ydl_opts = {
            'format': 'bestaudio/best',
            'postprocessors': [{
                'key': 'FFmpegExtractAudio',
                'preferredcodec': 'mp3',
                'preferredquality': '192',
            }],
        }
        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
            ydl.download([url])
        for file in os.listdir("./"):
            if file.endswith(".mp3"):
                os.rename(file, 'song.mp3')

        def after_playing(err):
            song = self.get_next_song()
            print(song, self.playlist)
            self.play_song(client, song)

        client.play(discord.FFmpegPCMAudio("song.mp3"), after=after_playing)
        client.volume = 100
Exemple #4
0
 def callback(self, client: discord.VoiceClient,
              queue: collections.deque) -> None:
     """Handle callbacks after the voice client finishes playing."""
     if not client.is_connected():
         queue.clear()
     elif queue:
         now = queue.popleft()
         client.play(now, after=lambda e: self.callback(client, queue))
Exemple #5
0
    async def next_track(self, voice_client: VoiceClient):
        """Play next track"""

        if voice_client is None:
            self.cleanup()
            return

        if not voice_client.is_connected():
            self.cleanup()
            return

        if voice_client.is_connected() and self.queue:
            source = self.queue.pop(0)
            await source.load_source()
            voice_client.play(source,
                              after=lambda error: self.on_track_end(
                                  source, error, voice_client))
            self.on_track_start(audio_source=source)
Exemple #6
0
 async def play(self, voice_channel:discord.VoiceClient, channel:discord.VoiceChannel):
     while len(self.playlist[channel.id]) != 0:
         file = self.playlist[channel.id][0]
         if not voice_channel.is_connected():
             await voice_channel.connect(reconnect=True)
         self.playing[channel.id] = voice_channel
         voice_channel.play(discord.FFmpegPCMAudio(executable=self.ffmpeg, source=file),
                             after=None)
         while voice_channel.is_playing():
             if self.playing[channel.id] == None:
                 voice_channel.stop()
                 await voice_channel.disconnect()
                 self.playlist[channel.id].clear()
                 return
             await asyncio.sleep(0.05)
         if file[:3] == 'tmp':
             fileManager.delete_file(file)
         self.playlist[channel.id].pop(0)
     self.playing[channel.id] = None
Exemple #7
0
 async def _play_loop(self, voice: discord.VoiceClient) -> None:
     try:
         while voice.is_connected():
             self._queue_update_flag.clear()
             async with self._queue_lock:
                 if self._voice is None and len(self._queue) > 0:
                     self._now_playing = self._queue.popleft()
                     log.info(f"[{self._now_playing.user.name}:{self._now_playing.user.id}] "
                              f"Now playing {self._now_playing.title}")
                     # Launch ffmpeg process
                     self._stream = FfmpegStream(
                         self._now_playing,
                         discord.opus.Encoder()
                     )
                     self._voice = voice
                     # Waits until ffmpeg has buffered audio before playing
                     await self._stream.wait_ready(loop=self.loop)
                     # Wait an extra second for livestreams so player clock runs behind input
                     if self._now_playing.live is True:
                         await asyncio.sleep(1, loop=self.loop)
                     # Sync play start time to player start
                     self._play_start_time = time.perf_counter()
                     self._voice.play(
                         # About the same as a max volume YouTube video, I think
                         discord.PCMVolumeTransformer(self._stream, volume=0.3),
                         after=lambda err: asyncio.run_coroutine_threadsafe(
                             self._after_song(),
                             loop=self.loop
                         )
                     )
                     self._change_status(Status.PLAYING)
             await self._queue_update_flag.wait()
     except asyncio.CancelledError:
         pass
     except Exception as e:
         log.error(f"Unhandled exception: {e}")
Exemple #8
0
    async def queue_task(self, ctx: commands.Context,
                         voice_client: discord.VoiceClient):
        # 왜인지는 모르겠는데 매우 불안정하네요.
        while voice_client.is_connected():
            if ctx.guild.id not in self.queues.keys():
                if voice_client.is_playing():
                    voice_client.stop()
                break
            try:
                is_loop = bool(self.queues[ctx.guild.id]["playing"]["loop"])
                is_shuffle = bool(
                    self.queues[ctx.guild.id]["playing"]["random"])
            except KeyError:
                is_loop = False
                is_shuffle = False
            if not voice_client.is_playing() and not voice_client.is_paused(
            ) and (not is_loop and len(self.queues[ctx.guild.id]) <= 1):
                break
            if voice_client.is_playing() or voice_client.is_paused():
                await asyncio.sleep(1)
                continue
            print(self.queues)
            song_id_list = [
                x for x in self.queues[ctx.guild.id].keys() if x != "playing"
            ]
            next_song_id = (
                sorted(song_id_list)[0] if not is_shuffle else
                random.choice(song_id_list)) if not is_loop else "playing"
            print(next_song_id)
            next_song = self.queues[ctx.guild.id][next_song_id].copy()
            embed = discord.Embed(
                title="유튜브 음악 재생 - 재생 시작",
                description=
                f"업로더: [`{next_song['vid_author']}`]({next_song['vid_channel_url']})\n"
                f"제목: [`{next_song['vid_title']}`]({next_song['vid_url']})",
                color=discord.Color.red(),
                timestamp=datetime.datetime.now(
                    tz=datetime.timezone(datetime.timedelta(hours=9))))
            embed.set_footer(text=str(next_song['req_by']),
                             icon_url=next_song['req_by'].avatar_url)
            embed.set_image(url=next_song['thumb'])
            voice_client.play(
                discord.FFmpegPCMAudio(next_song["tgt_url"],
                                       before_options=get_youtube.before_args))
            voice_client.source = discord.PCMVolumeTransformer(
                voice_client.source)
            voice_client.source.volume = self.queues[
                ctx.guild.id]["playing"]["vol"]

            await ctx.send(embed=embed)

            if not is_loop:
                for k, v in next_song.items():
                    self.queues[ctx.guild.id]["playing"][k] = v
                del self.queues[ctx.guild.id][next_song_id]

            await asyncio.sleep(1)

        if ctx.guild.id in self.queues.keys():
            del self.queues[ctx.guild.id]
        if voice_client.is_connected():
            await voice_client.disconnect()
        await ctx.send(
            f"대기열이 비어있고 모든 노래를 재생했어요. `{voice_client.channel}`에서 나갈께요.")
Exemple #9
0
 async def play_next_queued(self, voice_client: discord.VoiceClient):
     if voice_client is None or not voice_client.is_connected():
         return
     await asyncio.sleep(0.5)
     guild_document = await self.guild_document_from_guild(
         voice_client.guild)
     guild_queued = guild_document.get("queue", [])
     if len(guild_queued) == 0:
         # await voice_client.disconnect()
         return
     if guild_document.get("loop", False):
         next_song_url = guild_queued[0]
     else:
         next_song_url = guild_queued.pop(0)
     await self.music_db.songs.update_one({"_id": voice_client.guild.id},
                                          {'$set': {
                                              "queue": guild_queued
                                          }},
                                          upsert=True)
     local_ffmpeg_options = ffmpeg_options.copy()
     resume_from = 0
     if type(next_song_url) == tuple or type(next_song_url) == list:
         next_song_url, resume_from = next_song_url
         local_ffmpeg_options['options'] = "-vn -ss {}".format(resume_from)
     volume_document = await self.bot.mongo.find_by_id(
         self.music_db.volumes, voice_client.guild.id)
     volume = volume_document.get("volume", 0.5)
     if next_song_url is None:
         self.bot.loop.create_task(self.play_next_queued(voice_client))
         return
     next_song_url = await self.transform_single_song(next_song_url)
     if next_song_url is None:
         self.bot.loop.create_task(self.play_next_queued(voice_client))
         return
     data = await YTDLSource.get_video_data(next_song_url, self.bot.loop)
     source = YTDLSource(discord.FFmpegPCMAudio(data["url"],
                                                **local_ffmpeg_options),
                         data=data,
                         volume=volume,
                         resume_from=resume_from)
     if voice_client.guild.id in self.tts_cog.guild_queues:
         while len(self.tts_cog.guild_queues[voice_client.guild.id]) > 0:
             await asyncio.sleep(0.1)
     while voice_client.is_playing():
         await asyncio.sleep(0.1)
     voice_client.play(source,
                       after=lambda e: self.bot.loop.create_task(
                           self.play_next_queued(voice_client)))
     title = await self.title_from_url(next_song_url)
     embed = self.bot.create_completed_embed(
         "Playing next song!",
         "Playing **[{}]({})**".format(title, next_song_url))
     thumbnail_url = await self.thumbnail_from_url(next_song_url)
     if thumbnail_url is not None:
         embed.set_thumbnail(url=thumbnail_url)
     text_channel_id = guild_document.get("text_channel_id", None)
     if text_channel_id is None:
         print("text channel id is none")
         return
     # noinspection PyTypeChecker
     called_channel = self.bot.get_channel(text_channel_id)
     history = await called_channel.history(limit=1).flatten()
     print("sending message")
     if len(history) > 0 and history[0].author.id == self.bot.user.id:
         old_message = history[0]
         if len(old_message.embeds) > 0:
             if old_message.embeds[0].title == "Playing next song!":
                 await old_message.edit(embed=embed)
                 return
     await called_channel.send(embed=embed)