Пример #1
0
 def test_image(self):
     self.assertEqual(Song(image_url="image").image, "image")
     self.assertEqual(
         Song(image_url="image", thumbnail="thumb").image, "image"
     )
     self.assertEqual(Song(thumbnail="thumb").image, "thumb")
     self.assertEqual(Song().image, None)
Пример #2
0
    async def youtube_playlist(self, url: str) -> List[Song]:
        """
        Extract information from YouTube by Playlist url
        @param url:
        @return:
        """
        url = VariableStore.youtube_url_to_id(url)
        node: Node = self.node_controller.get_best_node()

        response = await node.client.request("youtube_playlist",
                                             url,
                                             response=True,
                                             timeout=10)

        if not response.successful:
            raise PlaylistExtractionException()

        songs = []
        for track in json.loads(response.text):
            song = Song()
            song.title = track["title"]
            song.link = track["link"]
            songs.append(song)

        return songs
Пример #3
0
 def test_song_copy(self):
     """
     Test Song Copy
     @return:
     """
     a = Song(title="Test1", image_url="fest1", duration=1)
     b = Song(image_url="kalb53")
     c = Song.copy_song(a, b)
     self.assertEqual(c.title, "Test1")
     self.assertEqual(c.image_url, "kalb53")
     self.assertEqual(c.duration, 1)
Пример #4
0
    async def youtube_url(self, url, guild_id: int) -> Song:
        """
        Extract information from YouTube by url
        @param url:
        @param guild_id:
        @return:
        """
        url = VariableStore.youtube_url_to_id(url)
        node: Node = self.node_controller.get_best_node(guild_id)

        response = await node.client.request("youtube_video",
                                             url,
                                             response=True,
                                             timeout=10)

        if not response.successful:
            LOG.warning(f"[YT-URL] {url} {response.text}")
            raise SongExtractionException()

        song_dict: dict = json.loads(response.text)

        if song_dict == {}:
            raise NoResultsFound(Errors.no_results_found)
        song: Song = Song.from_dict(song_dict)
        return song
Пример #5
0
 async def spotify_album(self, album_url) -> List[Song]:
     """
     Retrieves an album from Spotify.
     @param album_url:
     @return:
     """
     token = await self._request_token()
     album = SpotifyType(album_url)
     if not album.valid:
         raise PlaylistExtractionException()
     url = "https://api.spotify.com/v1/albums/" + album.id + "?limit=50"
     header = {"Authorization": "Bearer " + token}
     result = await self._request_get(url, header)
     json_result = json.loads(result)
     if "error" in json_result:
         raise PlaylistExtractionException()
     track_list = []
     for item in json_result["tracks"]["items"]:
         track_list.append(
             Song(
                 title=f"{item['artists'][0]['name']} - {item['name']}",
                 artist=item["artists"][0]["name"],
                 image_url=json_result["images"][0]["url"],
                 song_name=item["name"],
             ))
     if not track_list:
         raise PlaylistExtractionException()
     return track_list
Пример #6
0
 async def spotify_artist(self, artist_url: str) -> List[Song]:
     """
     Retrieves a Spotify Artist
     @param artist_url:
     @return:
     """
     token = await self._request_token()
     artist = SpotifyType(artist_url)
     if not artist.valid:
         raise PlaylistExtractionException()
     url = ("https://api.spotify.com/v1/artists/" + artist.id +
            "/top-tracks?country=DE")
     header = {"Authorization": "Bearer " + token}
     result = await self._request_get(url, header)
     json_result = json.loads(result)
     if "error" in json_result:
         raise PlaylistExtractionException()
     track_list = []
     for item in json_result["tracks"]:
         track_list.append(
             Song(
                 title=f"{item['artists'][0]['name']} - {item['name']}",
                 artist=item["artists"][0]["name"],
                 image_url=item["album"]["images"][0]["url"],
                 song_name=item["name"],
             ))
     if not track_list:
         raise PlaylistExtractionException
     return track_list
Пример #7
0
 async def soundcloud_playlist(self, url: str) -> List[Song]:
     """
     Retrieve a playlist from SoundCloud
     @param url:
     @return:
     """
     try:
         node: Node = self.node_controller.get_best_node()
         response: karp.response.Response = await node.client.request(
             "soundcloud_playlist", url, timeout=10, response=True)
         if not response.successful:
             self.log.warning(f"[SC-SET] {url} {response.text}")
             raise PlaylistExtractionException()
         parsed_response = json.loads(response.text)
         songs = []
         for _song in parsed_response:
             song: Song = Song()
             song.link = _song.get("link", None)
             song.title = _song.get("title", "")
             if song.link:
                 songs.append(song)
         return songs
     except (TimeoutError, AttributeError):
         self.log.error(traceback.format_exc())
         raise PlaylistExtractionException(Errors.default)
Пример #8
0
    async def soundcloud_search(self, song: Song) -> Song:
        """
        Search SoundCloud
        :param song:
        :return:
        """
        term = getattr(song, "title", getattr(song, "term", None))
        if not term:
            raise NoResultsFound(Errors.no_results_found)
        node: Node = self.node_controller.get_best_node(guild_id=song.guild_id)

        response = await node.client.request("soundcloud_search",
                                             term,
                                             response=True,
                                             timeout=10)

        if not response.successful:
            self.log.warning(f"[SC-TERM] {term} {response.text}")
            raise SongExtractionException()

        song_dict: dict = json.loads(response.text)
        song_dict["term"] = term

        song: Song = Song.from_dict(song_dict)
        return song
Пример #9
0
    async def youtube_term(self, song: (Song, str)):
        if isinstance(song, Song):
            if song.term:
                term = song.term
            elif song.title:
                term = song.title
            else:
                return Error(True, Errors.no_results_found)
        else:
            term = song

        node = self.node_controller.get_best_node(guild_id=song.guild_id)
        url = await self.http_post(
            self.term_url.format(node.ip, node.port), term
        )

        if isinstance(url, Error):
            return url

        url = VariableStore.youtube_url_to_id(url)
        sd = await self.http_post(
            url=self.url_url.format(node.ip, node.port), data=url
        )
        if isinstance(sd, Error):
            return sd
        song_dict: dict = json.loads(sd)
        song_dict["term"] = term

        song: Song = Song.from_dict(song_dict)
        return song
Пример #10
0
 async def extract_first_infos_youtube(self, url, ctx):
     youtube_type = Url.determine_youtube_type(url=url)
     if youtube_type == Url.youtube_url:
         __song = Song()
         __song.user = ctx.message.author
         __song.link = url
         return [__song]
     if youtube_type == Url.youtube_playlist:
         __songs = []
         __song_list = await self.parent.youtube.youtube_playlist(url)
         if len(__song_list) == 0:
             await self.parent.send_error_message(ctx, Errors.spotify_pull)
             return []
         for track in __song_list:
             track.user = ctx.message.author
             __songs.append(track)
         return __songs
Пример #11
0
    async def preload_song(self, ctx: commands.Context) -> None:
        """
        Preload of the next song.
        :param ctx:
        :return:
        """
        try:
            if self.guilds[ctx.guild.id].song_queue.qsize() == 0:
                return
            i = 0
            for item in self.guilds[ctx.guild.id].song_queue.queue:
                item: Song
                if item.stream:
                    continue
                backup_title: str = str(item.title)
                if item.link is not None:
                    try:
                        type_of_source = Url.determine_source(item.link)
                        if type_of_source == Url.youtube_url:
                            youtube_dict = await self.parent.youtube.youtube_url(
                                item.link, ctx.guild.id)
                        elif type_of_source == Url.soundcloud_track:
                            youtube_dict = await self.parent.soundcloud.soundcloud_track(
                                item.link)
                        else:
                            continue
                    except BasicError:
                        self.parent.log(
                            logging_manager.debug_info(traceback.format_exc()))
                        continue
                    youtube_dict.user = item.user
                else:
                    if item.title:
                        continue
                    try:
                        youtube_dict = await self._search_song(ctx, item)
                    except BasicError:
                        continue
                    youtube_dict.user = item.user
                j: int = 0

                for _song in self.guilds[ctx.guild.id].song_queue.queue:
                    _song: Song
                    if _song.title != backup_title:
                        j += 1
                        continue
                    self.guilds[
                        ctx.guild.id].song_queue.queue[j] = Song.copy_song(
                            youtube_dict,
                            self.guilds[ctx.guild.id].song_queue.queue[j],
                        )
                    break
                break
            i += 1
        except IndexError:
            pass
        except AttributeError:
            traceback.print_exc()
Пример #12
0
    async def youtube_playlist(self, url):
        url = VariableStore.youtube_url_to_id(url)
        node = self.node_controller.get_best_node()
        sd = await self.http_post(
            url=self.playlist_url.format(node.ip, node.port), data=url
        )

        if isinstance(sd, Error):
            return []

        songs = []
        for t in json.loads(sd):
            s = Song()
            s.title = t["title"]
            s.link = t["link"]
            songs.append(s)

        return songs
Пример #13
0
 async def _extract_first_infos_spotify(
         self, url: str, ctx: commands.Context) -> List[Song]:
     spotify_type = Url.determine_spotify_type(url=url)
     __songs = []
     __song = Song()
     __song.user = ctx.message.author
     if spotify_type == Url.spotify_playlist:
         song_list = await self.parent.spotify.spotify_playlist(url)
         return song_list
     if spotify_type == Url.spotify_track:
         track = await self.parent.spotify.spotify_track(url)
         if track:
             return [track]
         return []
     if spotify_type == Url.spotify_artist:
         song_list = await self.parent.spotify.spotify_artist(url)
         return song_list
     if spotify_type == Url.spotify_album:
         song_list = await self.parent.spotify.spotify_album(url)
         return song_list
Пример #14
0
 async def player(self, ctx: commands.Context, small_dict: Song) -> None:
     """
     Plays a Song.
     @param ctx:
     @param small_dict:
     @return:
     """
     try:
         self.guilds[ctx.guild.id].unlock_queue()
         if self.guilds[ctx.guild.id].voice_client is None:
             return
         try:
             small_dict.guild_id = ctx.guild.id
             await self.guilds[ctx.guild.id].voice_client.play(small_dict)
             self.guilds[ctx.guild.id].voice_client.set_after(
                 self.song_conclusion, ctx)
         except discord.ClientException:
             if ctx.guild.voice_client is None:
                 if self.guilds[ctx.guild.id].voice_channel is not None:
                     self.guilds[
                         ctx.guild.id].voice_client = await self.guilds[
                             ctx.guild.id
                         ].voice_channel.connect(timeout=10, reconnect=True)
                     small_dict.guild_id = ctx.guild.id
                     await self.guilds[ctx.guild.id
                                       ].voice_client.play(small_dict, )
                     self.guilds[ctx.guild.id].voice_client.set_after(
                         self.song_conclusion, ctx)
         self.guilds[ctx.guild.id].now_playing = small_dict
         if self.guilds[ctx.guild.id].announce:
             if not self.guilds[ctx.guild.id].now_playing_message:
                 self.guilds[
                     ctx.guild.id].now_playing_message = NowPlayingMessage(
                         self.parent)
             await self.guilds[ctx.guild.id
                               ].now_playing_message.new_song(ctx=ctx)
     except (Exception, discord.ClientException) as discord_exception:
         self.parent.log.debug(
             logging_manager.debug_info(
                 traceback.format_exc(discord_exception)))
Пример #15
0
 async def tts(self, ctx: commands.Context, *, text: str):
     quoted = quote(text)
     if await self.parent.player.join_check(ctx):
         if await self.parent.player.join_channel(ctx):
             song: Song = Song.from_dict(
                 {
                     "guild_id": ctx.guild.id,
                     "stream": f"{self.tts_base_url}{quoted}",
                 }
             )
             self.tts_queue.put_nowait(song)
             if not self.guilds[ctx.guild.id].voice_client.is_playing():
                 await self.next_tts(ctx)
Пример #16
0
    async def youtube_url(self, url, guild_id: int):
        url = VariableStore.youtube_url_to_id(url)
        node = self.node_controller.get_best_node(guild_id)
        sd = await self.http_post(
            url=self.url_url.format(node.ip, node.port), data=url
        )

        if isinstance(sd, Error):
            return sd

        song_dict: dict = json.loads(sd)

        if song_dict == {}:
            return Error(Errors.default)
        song: Song = Song.from_dict(song_dict)
        return song
Пример #17
0
    async def preload_song(self, ctx):
        """
        Preload of the next song.
        :param ctx:
        :return:
        """
        try:
            if self.parent.guilds[ctx.guild.id].song_queue.qsize() > 0:
                i = 0
                for item in self.parent.guilds[ctx.guild.id].song_queue.queue:
                    item: Song
                    if item.stream is None:
                        backup_title: str = str(item.title)
                        if item.link is not None:
                            youtube_dict = await self.parent.youtube.youtube_url(
                                item.link, ctx.guild.id)
                            youtube_dict.user = item.user
                        else:
                            if item.title is not None:
                                youtube_dict = await self.parent.youtube.youtube_term(
                                    item)
                            else:
                                youtube_dict = await self.parent.youtube.youtube_term(
                                    item)
                            youtube_dict.user = item.user
                        j: int = 0

                        for _song in self.parent.guilds[
                                ctx.guild.id].song_queue.queue:
                            _song: Song
                            if _song.title == backup_title:
                                self.parent.guilds[
                                    ctx.guild.
                                    id].song_queue.queue[j] = Song.copy_song(
                                        youtube_dict,
                                        self.parent.guilds[
                                            ctx.guild.id].song_queue.queue[j],
                                    )
                                break
                            j -= -1
                        break
                    i += 1
        except IndexError:
            pass
        except AttributeError as e:
            traceback.print_exc()
Пример #18
0
 async def extract_first_infos_other(self, url, ctx):
     if url == "charts":
         __songs = []
         __song = Song()
         __song.user = ctx.message.author
         song_list = await self.extract_first_infos_spotify(
             "https://open.spotify.com/playlist/37i9dQZEVXbMDoHDwVN2tF?si=vgYiEOfYTL-ejBdn0A_E2g",
             ctx,
         )
         for track in song_list:
             track.user = ctx.message.author
             __songs.append(track)
         return __songs
     __song = Song()
     __song.title = url
     __song.user = ctx.message.author
     return [__song]
Пример #19
0
    async def youtube_term(self, song: (Song, str), service: str) -> Song:
        """
        Extract information from YouTube by Term
        @param song:
        @param service: 
        @return:
        """
        term = getattr(song, "title", getattr(song, "term", None))
        if not term:
            raise NoResultsFound(Errors.no_results_found)

        node: Node = self.node_controller.get_best_node(guild_id=song.guild_id)

        response = await node.client.request(
            "youtube_search",
            json.dumps({
                "service": service,
                "term": term
            }),
            response=True,
            timeout=10,
        )

        if not response.successful:
            raise NoResultsFound(response.text)
        url = response.text

        url = VariableStore.youtube_url_to_id(url)

        response = await node.client.request("youtube_video",
                                             url,
                                             response=True,
                                             timeout=10)

        if not response.successful:
            LOG.warning(f"[YT-TERM] {url} {response.text}")
            raise SongExtractionException()

        song_dict: dict = json.loads(response.text)
        song_dict["term"] = term

        song: Song = Song.from_dict(song_dict)
        return song
Пример #20
0
 async def soundcloud_playlist(self, url: str):
     try:
         async with async_timeout.timeout(timeout=10):
             async with aiohttp.request(
                     "POST",
                     "http://parent:8008/research/soundcloud_playlist",
                     data=url,
             ) as r:
                 response = await r.text()
                 if r.status != 200:
                     return Error(True, response)
                 parsed_response = json.loads(response)
                 songs = []
                 for s in parsed_response:
                     song: Song = Song()
                     song.link = s.get("link", None)
                     if song.link:
                         songs.append(song)
                 return songs
     except (TimeoutError, AttributeError) as e:
         self.log.error(e)
         return Error(True)
Пример #21
0
 async def soundcloud_track(self, url: str) -> Song:
     """
     Retrieve Track information from SoundCloud
     @param url:
     @return:
     """
     try:
         node: Node = self.node_controller.get_best_node()
         response: karp.response.Response = await node.client.request(
             "soundcloud_track", url, response=True, timeout=10)
         if not response.successful:
             self.log.warning(f"[SC-TRK] {url} {response.text}")
             raise SongExtractionException()
         response: dict = json.loads(response.text)
         song: Song = Song(
             title=response.get("title", None),
             term=response.get("term", ""),
             link=response.get("link", ""),
             stream=response.get("stream", None),
             duration=response.get("duration", 0),
             loadtime=response.get("loadtime", 0),
             thumbnail=response.get("thumbnail", ""),
             abr=response.get("abr", None),
             codec=response.get("codec", ""),
         )
         if song.duration == 0:
             # try to determine the songs length by content length
             if song.abr:
                 abr = song.abr * 1000 / 8
                 async with aiohttp.request("HEAD", song.stream) as _r:
                     content_length = _r.headers.get("Content-Length", "")
                 try:
                     song.duration = int(content_length) / abr
                 except ValueError:
                     pass
         return song
     except (TimeoutError, AttributeError) as thrown_exception:
         self.log.error(traceback.format_exc(thrown_exception))
         raise SongExtractionException()
Пример #22
0
 async def spotify_track(self, track_url) -> Song:
     """
     Extract Information from a Spotify Track url.
     @param track_url: Spotify Track Url
     @return: Spotify Song
     @rtype: Song
     """
     token = await self._request_token()
     track = SpotifyType(track_url)
     if not track.valid:
         raise SongExtractionException()
     url = "https://api.spotify.com/v1/tracks/" + track.id
     header = {"Authorization": "Bearer " + token}
     result = await self._request_get(url, header)
     result = json.loads(result)
     if "error" in result:
         raise SongExtractionException()
     return Song(
         title=result["artists"][0]["name"] + " - " + result["name"],
         image_url=result["album"]["images"][0]["url"],
         song_name=result["name"],
         artist=result["artists"][0]["name"],
     )
Пример #23
0
 async def soundcloud_track(self, url: str):
     node = self.node_controller.get_best_node()
     try:
         async with async_timeout.timeout(timeout=10):
             async with self.client.post(
                     f"http://{node.ip}:{node.port}/research/soundcloud_track",
                     data=url,
             ) as r:
                 if r.status != 200:
                     return Error(True)
                 response: dict = json.loads(await r.text())
                 song: Song = Song(
                     title=response.get("title", None),
                     term=response.get("term", ""),
                     link=response.get("link", ""),
                     stream=response.get("stream", None),
                     duration=response.get("duration", 0),
                     loadtime=response.get("loadtime", 0),
                     thumbnail=response.get("thumbnail", ""),
                     abr=response.get("abr", None),
                     codec=response.get("codec", ""),
                 )
                 if song.duration == 0:
                     # try to determine the songs length by content length
                     if song.abr:
                         abr = song.abr * 1000 / 8
                         async with aiohttp.request("HEAD",
                                                    song.stream) as _r:
                             cl = _r.headers.get("Content-Length", "")
                         try:
                             song.duration = int(cl) / abr
                         except ValueError:
                             pass
                 return song
     except (TimeoutError, AttributeError) as e:
         self.log.error(e)
         return Error(True)
Пример #24
0
    async def pre_player(self, ctx, bypass=None):
        if (self.parent.guilds[ctx.guild.id].song_queue.qsize() > 0
                or bypass is not None):
            if bypass is None:
                small_dict = await self.parent.guilds[ctx.guild.id
                                                      ].song_queue.get()
            else:
                small_dict = bypass
            self.parent.guilds[
                ctx.guild.id].now_playing_message = NowPlayingMessage(
                    message=await
                    self.parent.send_embed_message(ctx=ctx,
                                                   message=" Loading ... ",
                                                   delete_after=None),
                    ctx=ctx,
                )
            if small_dict.stream is None:
                if small_dict.link is not None:
                    # url
                    _type = Url.determine_source(small_dict.link)
                    if _type == Url.youtube:
                        youtube_dict = Song.copy_song(
                            await self.parent.youtube.youtube_url(
                                small_dict.link, ctx.guild.id),
                            small_dict,
                        )
                    elif _type == Url.soundcloud:
                        youtube_dict = Song.copy_song(
                            await self.parent.soundcloud.soundcloud_track(
                                small_dict.link),
                            small_dict,
                        )
                    else:
                        self.parent.log.warning("Incompatible Song Type: " +
                                                _type)
                        return
                else:
                    if small_dict.title is None:
                        self.parent.log.warning(small_dict)
                    # term
                    youtube_dict = Song.copy_song(
                        await self.parent.youtube.youtube_term(small_dict),
                        small_dict,
                    )
                if isinstance(youtube_dict, Error):
                    if youtube_dict.reason != Errors.error_please_retry:
                        await self.parent.send_error_message(
                            ctx, youtube_dict.reason)
                        await self.parent.guilds[
                            ctx.guild.id].now_playing_message.message.delete()
                        await self.pre_player(ctx)
                        return
                    await self.parent.guilds[
                        ctx.guild.id].now_playing_message.message.delete()
                    await self.pre_player(ctx, bypass=small_dict)
                    return
                youtube_dict.user = small_dict.user
                youtube_dict.image_url = small_dict.image_url
                await self.player(ctx, youtube_dict)
                if hasattr(youtube_dict, "title"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_most_played(
                            youtube_dict.title))
                if hasattr(youtube_dict, "loadtime"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_response_time(
                            youtube_dict.loadtime))
            else:
                await self.player(ctx, small_dict)
                if hasattr(small_dict, "title"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_most_played(small_dict.title))
                if hasattr(small_dict, "loadtime"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_response_time(
                            small_dict.loadtime))

            asyncio.ensure_future(self.preload_song(ctx=ctx))
Пример #25
0
 def test_song_from_dict(self):
     self.assertEqual(
         str(Song.from_dict({"title": "hello", "duration": 10})),
         str(Song(title="hello", duration=10)),
     )
Пример #26
0
 def test_song_copy_b(self):
     a = Song(title="2", duration=10, artist="jeff")
     self.assertEqual(str(Song(a)), str(a))
Пример #27
0
 async def extract_first_infos_spotify(self, url, ctx):
     spotify_type = Url.determine_spotify_type(url=url)
     __songs = []
     __song = Song()
     __song.user = ctx.message.author
     if spotify_type == Url.spotify_playlist:
         __song_list = await self.parent.spotify.spotify_playlist(url)
         if len(__song_list) == 0:
             await self.parent.send_error_message(
                 ctx=ctx, message=Errors.spotify_pull)
             return []
         for track in __song_list:
             track: SpotifySong
             __song = Song(song=__song)
             __song.title = track.title
             __song.image_url = track.image_url
             __song.artist = track.artist
             __song.song_name = track.song_name
             __songs.append(__song)
         return __songs
     if spotify_type == Url.spotify_track:
         track = await self.parent.spotify.spotify_track(url)
         if track is not None:
             __song.title = track.title
             __song.image_url = track.image_url
             __song.artist = track.artist
             __song.song_name = track.song_name
             return [__song]
         return []
     if spotify_type == Url.spotify_artist:
         song_list = await self.parent.spotify.spotify_artist(url)
         for track in song_list:
             __song = Song(song=__song)
             __song.title = track
             __songs.append(__song)
         return __songs
     if spotify_type == Url.spotify_album:
         song_list = await self.parent.spotify.spotify_album(url)
         for track in song_list:
             __song = Song(song=__song)
             __song.title = track
             __songs.append(__song)
         return __songs
Пример #28
0
    async def player(self, ctx, small_dict):
        if isinstance(small_dict, Error):
            error_message = small_dict.reason
            await self.parent.send_error_message(ctx, error_message)
            if error_message in (Errors.no_results_found, Errors.default):
                await self.parent.guilds[
                    ctx.guild.id].now_playing_message.message.delete()
                return

            small_dict = Song.copy_song(
                await self.parent.youtube.youtube_url(small_dict.link,
                                                      ctx.guild.id),
                small_dict,
            )

            if isinstance(small_dict, Error):
                self.parent.log.error(small_dict.reason)
                await self.parent.send_error_message(ctx, small_dict.reason)
                return

        try:
            self.parent.guilds[ctx.guild.id].now_playing = small_dict
            if self.parent.guilds[ctx.guild.id].voice_client is None:
                return
            volume = getattr(
                self.parent.guilds[ctx.guild.id],
                "volume",
                await self.parent.mongo.get_volume(ctx.guild.id),
            )
            if small_dict.codec == "opus":
                self.parent.log.debug("Using OPUS Audio.")
                # source = await FFmpegOpusAudioB.from_probe(
                #    small_dict.stream,
                #    volume=volume,
                # before_options="-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
                # commented, because of spamming messages of failed reconnects.
                # )
            else:
                # only used for backup soundcloud atm
                self.parent.log.debug("Using PCM Audio.")
                # source = PCMVolumeTransformerB(
                #   FFmpegPCMAudioB(
                #      small_dict.stream,
                #     before_options="-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
                # ),
                # volume=volume,
                # )
            try:
                small_dict.guild_id = ctx.guild.id
                self.parent.guilds[ctx.guild.id].voice_client.play(
                    small_dict
                    # source,
                    # after=lambda error: self.song_conclusion(ctx, error=error),
                )
                self.parent.guilds[ctx.guild.id].voice_client.set_after(
                    self.song_conclusion, ctx, error=None)
            except discord.ClientException:
                if ctx.guild.voice_client is None:
                    if (self.parent.guilds[ctx.guild.id].voice_channel
                            is not None):
                        self.parent.guilds[
                            ctx.guild.
                            id].voice_client = await self.parent.guilds[
                                ctx.guild.id
                            ].voice_channel.connect(timeout=10, reconnect=True)
                        small_dict.guild_id = ctx.guild.id
                        self.parent.guilds[ctx.guild.id].voice_client.play(
                            small_dict,
                            # after=lambda error: self.song_conclusion(
                            #    ctx, error=error
                            # ),
                        )
                        self.parent.guilds[
                            ctx.guild.id].voice_client.set_after(
                                self.song_conclusion, ctx, error=None)
            full, empty = await self.parent.mongo.get_chars(ctx.guild.id)
            self.parent.guilds[
                ctx.guild.id].now_playing_message = NowPlayingMessage(
                    ctx=ctx,
                    message=self.parent.guilds[
                        ctx.guild.id].now_playing_message.message,
                    song=self.parent.guilds[ctx.guild.id].now_playing,
                    full=full,
                    empty=empty,
                    discord_music=self.parent,
                    voice_client=self.parent.guilds[ctx.guild.id].voice_client,
                )
            await self.parent.guilds[ctx.guild.id].now_playing_message.send()

        except (Exception, discord.ClientException) as e:
            self.parent.log.debug(
                logging_manager.debug_info(traceback.format_exc(e)))
Пример #29
0
    async def pre_player(self, ctx: commands.Context, bypass=None) -> None:
        """
        Routine called before a song gets played.
        @param ctx:
        @param bypass:
        @return:
        """
        guild_id = ctx.guild.id
        if self.guilds[guild_id].song_queue.qsize() > 0 or bypass is not None:
            if bypass is None:
                small_dict = await self.guilds[ctx.guild.id].song_queue.get()
            else:
                small_dict = bypass
            if small_dict.stream is None:
                try:
                    if small_dict.link is not None:
                        # url
                        _type = Url.determine_source(small_dict.link)
                        if _type == Url.youtube:
                            youtube_dict = Song.copy_song(
                                await self.parent.youtube.youtube_url(
                                    small_dict.link, ctx.guild.id),
                                small_dict,
                            )
                        elif _type == Url.soundcloud:
                            youtube_dict = Song.copy_song(
                                await self.parent.soundcloud.soundcloud_track(
                                    small_dict.link),
                                small_dict,
                            )
                        else:
                            self.parent.log.warning(
                                f"Incompatible Song Type: {_type}")
                            return
                    else:
                        if small_dict.title is None:
                            self.parent.log.warning(small_dict)
                        # term
                        youtube_dict = Song.copy_song(
                            await self._search_song(ctx, small_dict),
                            small_dict)
                except NoResultsFound:
                    await self.parent.send_error_message(
                        ctx, Errors.no_results_found)
                    self.guilds[guild_id].unlock_queue()
                    await self.pre_player(ctx)
                    return
                except SongExtractionException:
                    await self.parent.send_error_message(
                        ctx, Errors.youtube_video_not_available)
                    self.guilds[guild_id].unlock_queue()
                    await self.pre_player(ctx)
                    return
                except (BasicError, asyncio.TimeoutError) as basic_error:
                    if str(basic_error) != Errors.error_please_retry:
                        await self.parent.send_error_message(
                            ctx, str(basic_error))
                        self.guilds[guild_id].unlock_queue()
                        await self.pre_player(ctx)
                        return
                    return await self.pre_player(ctx, bypass=small_dict)
                youtube_dict.user = small_dict.user
                youtube_dict.image_url = small_dict.image_url
                await self.player(ctx, youtube_dict)

                # add stats to website
                if hasattr(youtube_dict, "title"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_most_played(
                            youtube_dict.title))
                if hasattr(youtube_dict, "loadtime"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_response_time(
                            youtube_dict.loadtime))
            else:
                await self.player(ctx, small_dict)
                if hasattr(small_dict, "title"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_most_played(small_dict.title))
                if hasattr(small_dict, "loadtime"):
                    asyncio.ensure_future(
                        self.parent.mongo.append_response_time(
                            small_dict.loadtime))

            asyncio.ensure_future(self.preload_song(ctx=ctx))
Пример #30
0
    async def spotify_playlist(self, playlist_url) -> List[Song]:
        """
        Extracts all songs from a spotify playlist.
        @param playlist_url: Spotify Playlist Url
        @return: List of Songs
        @rtype: List[Song]
        """
        token = await self._request_token()
        playlist = SpotifyType(playlist_url)
        if not playlist.valid:
            raise PlaylistExtractionException()
        url = ("https://api.spotify.com/v1/playlists/" + playlist.id +
               "/tracks?limit=100&offset=0")
        header = {"Authorization": "Bearer " + token}
        result = await self._request_get(url, header)
        json_result = json.loads(result)
        if "error" in json_result:
            raise PlaylistExtractionException()
        t_list = []
        more = True
        while more is True:
            try:
                for track in json_result["items"]:
                    if track["is_local"]:
                        try:
                            t_list.append(
                                Song(
                                    title=track["track"]["artists"][0]["name"]
                                    + " - " + track["track"]["name"],
                                    image_url=None,
                                    song_name=track["track"]["name"],
                                    artist=track["track"]["artists"][0]
                                    ["name"],
                                ))

                        except (
                                IndexError,
                                KeyError,
                                TypeError,
                        ):  # pragma: no cover
                            # Probably invalid local file
                            continue
                    else:
                        try:
                            t_list.append(
                                Song(
                                    title=track["track"]["album"]["artists"][0]
                                    ["name"] + " - " + track["track"]["name"],
                                    image_url=track["track"]["album"]["images"]
                                    [0]["url"],
                                    song_name=track["track"]["name"],
                                    artist=track["track"]["artists"][0]
                                    ["name"],
                                ))
                        except (
                                IndexError,
                                KeyError,
                                TypeError,
                        ):  # catch preemtively to prevent
                            # no-response
                            pass

                if json_result["next"] is None:
                    more = False
                else:
                    url = json_result["next"]
                    result = await self._request_get(url, header)
                    json_result = json.loads(result)
            except KeyError as key_error:
                self.log.warning(
                    logging_manager.debug_info(
                        str(key_error) + " " + str(json_result)))
                if "error" in json_result:
                    self.token = ""
                more = False

            if not t_list:
                raise PlaylistExtractionException()
        return t_list