Exemple #1
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 #2
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 #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 play_with(self, voice_client: discord.VoiceClient):
        fname = self.get_filename()
        source = await discord.FFmpegOpusAudio.from_probe(fname)
        voice_client.play(source)

        print(f"Played {self.sound_name} ({fname}) in "
              f"{voice_client.channel.name} ({voice_client.guild.name})")

        return fname
Exemple #6
0
async def _stream_media(voice_client: discord.VoiceClient, loop: asyncio.BaseEventLoop, source: YTDLSource):
    """Method which starts the streaming and playback of the provided URL.

    Args:
        voice_client (discord.VoiceClient): The voice client used by the bot.
        source (YTDLSource): Audio source which contains the audio stream.
    """

    future = loop.create_future() if loop else asyncio.get_event_loop().create_future()
    voice_client.play(source, after=lambda e: future.set_result(e))

    try:
        await asyncio.wait_for(future, timeout=None)
        error = future.result()
        if error:
            log.error("Player error: %s", error)
    except asyncio.TimeoutError:
        log.error("Player error: Timeout for song playback has been reached.")
Exemple #7
0
    async def on_voice_leave(self, self_voice_client: VoiceClient,
                             member: Member, voice_state_before: VoiceState):

        # If self client voice is empty.
        if not self.there_is_user_in_voice(voice_state_before.channel):
            guild_state = self.music_manager.get_guild_state(member.guild.id)

            self_voice_client.pause()

            guild_state.waiter = asyncio.ensure_future(
                self.wait_for_user(self_voice_client, member.guild))
            guild_state.waiting = True

            # print("Pause and wait for user")
            return

        return await super().on_voice_leave(self_voice_client, member,
                                            voice_state_before)
Exemple #8
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 #9
0
        async def get_stream_player(voice_client: discord.VoiceClient):
            ydl.download([arguments], )
            file = re.sub("[a-z]+?$", "opus", filename)

            def after():
                asyncio.ensure_future(stream_player.notify())

            return voice_client.create_ffmpeg_player(file,
                                                     use_avconv=True,
                                                     after=after)
Exemple #10
0
def playcheck(vc: discord.VoiceClient, dummy):
    global isPlay
    global nc
    global mQueue

    if isPlay:
        print("start")

    while isPlay:
        if vc.is_paused() == False:
            time.sleep(0.5)
            if vc.is_playing() == False:
                if mQueue.popQueue() != mQueue.notPlaying:
                    src = nc.getVideo(mQueue.nowPlaying["url"])
                    while os.path.getsize(src) < 128:
                        pass

                    vc.play(discord.FFmpegPCMAudio(src))
                    vc.source = discord.PCMVolumeTransformer(vc.source)
                    vc.source.volume = 0.1
                    isPlay = True
Exemple #11
0
 def disconnector(voice_client: discord.VoiceClient, bot: commands.Bot):
     """
     This function is passed as the after parameter of FFmpegPCMAudio() as it does not take coroutines.
     Args:
         voice_client: The voice client that will be disconnected (discord.VoiceClient)
         bot: The bot that will terminate the voice client, which will be this very bot
     """
     coro = voice_client.disconnect()
     fut = asyncio.run_coroutine_threadsafe(coro, bot.loop)
     try:
         fut.result()
     except asyncio.CancelledError:
         pass
Exemple #12
0
    def play_song(self,
                  voice_client: discord.VoiceClient,
                  channel: discord.VoiceChannel = None) -> None:
        """
        Plays the first song in the playlist queue.

        :param voice_client: The discord VoiceClient that the bot should play into.
        :param channel: A channel to connect to if the bot is currently not in one.
        :return: None
        """
        try:
            print(self.playlist)
            source = discord.FFmpegOpusAudio(
                self.playlist[0],
                options={'use_wallclock_as_timestamps': True})
            voice_client.play(source, after=self.play_after)
            self.playlist.pop(0)
            self.current_song_playing = self.playlist_data.pop(0)
            self.song_started_at = datetime.datetime.now()
        except discord.errors.ClientException as e:
            if 'Not connected to voice' in str(e):
                channel.connect()
Exemple #13
0
    def _send_audio_packet(self, voice_client: discord.VoiceClient,
                           opus_packet: bytes,
                           timestamp_frames: int) -> typing.Callable[[], None]:
        sock = voice_client.socket
        endpoint_ip = voice_client.endpoint_ip
        endpoint_port: int = voice_client.voice_port  # type: ignore
        sequence = voice_client.sequence

        voice_client.timestamp = timestamp_frames
        udp_packet = getattr(voice_client, '_get_voice_packet')(opus_packet)
        voice_client.sequence = (voice_client.sequence + 1) & 0xffff

        def send() -> None:
            if sock is None:
                return
            try:
                sock.sendto(udp_packet, (endpoint_ip, endpoint_port))
            except BlockingIOError:
                self.logger.warning(
                    'Network too slow, a packet is dropped. (seq={}, ts={})'.
                    format(sequence, timestamp_frames))

        return send
Exemple #14
0
 async def _alert(self, bot: commands.Bot, channel: discord.Channel, vc: discord.VoiceClient):
     ## voice alert
     len_pattern = len(self.pattern)
     to_speak = self.pattern[self.__used % len_pattern]
     to_speak_name = to_speak['name']
     to_speak_speech = to_speak['say']
     voice_file = './cache/' + self.lang + '_' + to_speak_name
     if not os.path.isfile(voice_file):
         tts = gTTS(text=to_speak_speech, lang=self.lang)
         tts.save(voice_file)
         print('Created voice')
     player = vc.create_ffmpeg_player(voice_file)
     player.start()
     await asyncio.sleep(5)
     player.stop()
Exemple #15
0
    def enqueue(self, url: str, voice: discord.VoiceClient):
        song_info = self.get_dl(url)
        full_song = {
            "url": url,
            "voice": voice,
            "title": song_info['title'],
            "duration": song_info.get('duration')
        }
        if self.playing:
            print('Song is currently playing. Adding to queue...')
            self.playlist.put_nowait(full_song)
        else:
            print('Queue is empty. Starting song...')
            self.current_song = full_song
            self.player = voice.create_ffmpeg_player(song_info['url'],
                                                     after=self.when_finished)
            self.playing = True
            self.player.start()

        return full_song
Exemple #16
0
def player_play(vc: discord.VoiceClient, m: str):

    global nc
    global mQueue
    global isPlay

    ret = ""

    if m == "#play" or m == "#p":

        # 再開
        if vc.is_paused():
            vc.resume()
            ret = "Resuming!"

    # キュー追加
    elif m.find("https://www.nicovideo.jp/watch/") >= 0:

        ret = "add `{0}`".format(mQueue.addQueue(m.split(" ")[1]))

        # 新規再生
        if not vc.is_playing():

            if mQueue.popQueue() == mQueue.notPlaying:
                return
            src = nc.getVideo(mQueue.nowPlaying["url"])

            while os.path.getsize(src) < 256:
                pass

            vc.play(discord.FFmpegPCMAudio(src))
            vc.source = discord.PCMVolumeTransformer(vc.source)
            vc.source.volume = 0.1

            if not isPlay:
                isPlay = True
                t1 = threading.Thread(target=playcheck, args=(vc, 0))
                t1.start()

            ret = "Play {0}".format(mQueue.now())

    return ret
Exemple #17
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 #18
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 #19
0
 def leaveVoice(self, _voice: discord.VoiceClient):
     coro = _voice.disconnect()
     fut = discord.compat.run_coroutine_threadsafe(coro, self.client.loop)
     fut.result()
Exemple #20
0
async def queue_task(bot: CustomClient, ctx: commands.Context,
                     voice: discord.VoiceClient):
    while True:
        exists = os.path.isfile(f"music/{ctx.guild.id}.json")
        if not exists:
            await ctx.send(f"`{voice.channel}`에서 나갈께요.")
            await voice.disconnect(force=True)
            break
        queue = await get_queue(ctx.guild.id)
        if voice.is_playing() or voice.is_paused():
            await asyncio.sleep(1)
            continue
        elif not voice.is_playing() and len(
                queue.keys()) == 1 and queue["playing"]["loop"] is not True:
            await ctx.send(f"음악이 끝났어요. `{voice.channel}`에서 나갈께요.")
            await voice.disconnect(force=True)
            os.remove(f"music/{ctx.guild.id}.json")
            break
        vol = queue["playing"]["vol"]
        if queue["playing"]["loop"] is True:
            tgt_url = queue["playing"]["tgt_url"]
            voice.play(
                discord.FFmpegPCMAudio(tgt_url,
                                       before_options=get_youtube.before_args))
            voice.source = discord.PCMVolumeTransformer(voice.source)
            voice.source.volume = vol
            await asyncio.sleep(3)
            continue
        if queue["playing"]["random"]:
            queue_keys = [str(x) for x in queue.keys() if not x == "playing"]
            tgt_name = str(random.choice(queue_keys))
            tgt_queue = queue[tgt_name]
        else:
            tgt_name = list(queue.keys())[1]
            tgt_queue = queue[tgt_name]
        vid_url = tgt_queue["vid_url"]
        vid_title = tgt_queue["vid_title"]
        vid_author = tgt_queue["vid_author"]
        vid_channel_url = tgt_queue["vid_channel_url"]
        tgt_url = tgt_queue["tgt_url"]
        thumb = tgt_queue["thumb"]
        req_by = bot.get_user(int(tgt_queue["req_by"]))
        voice.play(
            discord.FFmpegPCMAudio(tgt_url,
                                   before_options=get_youtube.before_args))
        voice.source = discord.PCMVolumeTransformer(voice.source)
        voice.source.volume = vol
        embed = discord.Embed(title="유튜브 음악 재생",
                              color=discord.Colour.from_rgb(255, 0, 0))
        embed.add_field(
            name="재생 시작",
            value=
            f"업로더: [`{vid_author}`]({vid_channel_url})\n제목: [`{vid_title}`]({vid_url})",
            inline=False)
        embed.add_field(name="요청자",
                        value=f"{req_by.mention} (`{req_by}`)",
                        inline=False)
        embed.set_image(url=str(thumb))
        queue["playing"]["vid_url"] = vid_url
        queue["playing"]["vid_title"] = vid_title
        queue["playing"]["vid_author"] = vid_author
        queue["playing"]["vid_channel_url"] = vid_channel_url
        queue["playing"]["thumb"] = thumb
        queue["playing"]["tgt_url"] = tgt_url
        queue["playing"]["req_by"] = tgt_queue["req_by"]
        await ctx.send(embed=embed)
        del queue[tgt_name]
        await update_queue(ctx.guild.id, queue)
        await asyncio.sleep(3)
Exemple #21
0
 async def _play_stream(self, audio_source: AudioSource,
                        voice_client: VoiceClient):
     voice_client.play(audio_source)
 async def create_player(self, voice_client: discord.VoiceClient):
     await self.download()
     if self.location:
         audio_source = discord.FFmpegPCMAudio(self.location)
         if not voice_client.is_playing():
             voice_client.play(audio_source)
 async def _stop(self, context: Union[commands.Context, SlashContext], voice_client: discord.VoiceClient):
     voice_client.stop()
     await context.send('Okay, I\'ll be quiet.')
Exemple #24
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 #25
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)
Exemple #26
0
def player_skip(vc: discord.VoiceClient):
    global nc

    vc.stop()
    nc.isDownload = False
    return "skip"
Exemple #27
0
def player_stop(vc: discord.VoiceClient):
    vc.pause()
    return "pause"