diff --git a/config/config.py b/config/config.py index 98c3197..ddf7fb8 100644 --- a/config/config.py +++ b/config/config.py @@ -23,6 +23,7 @@ CHANNEL_NOT_FOUND_MESSAGE = "Error: Could not find channel" INFO_HISTORY_TITLE = "Songs Played:" MAX_HISTORY_LENGTH = 10 +MAX_PLAYLIST_LENGTH = 50 MAX_TRACKNAME_HISTORY_LENGTH = 15 SONGINFO_UPLOADER = "Uploader: " diff --git a/vulkanbot/music/Downloader.py b/vulkanbot/music/Downloader.py index fd620d8..16dadcb 100644 --- a/vulkanbot/music/Downloader.py +++ b/vulkanbot/music/Downloader.py @@ -1,13 +1,102 @@ +import re +from config import config +from yt_dlp import YoutubeDL +from yt_dlp.utils import ExtractorError, DownloadError + + class Downloader(): - """Download music source from Youtube with a music name""" + """Download music source from Youtube with a music name or Youtube URL""" def __init__(self) -> None: - pass + self.__YDL_OPTIONS = {'format': 'bestaudio/best', + 'default_search': 'auto', + 'playliststart': 0, + 'extract_flat': True, + 'playlistend': config.MAX_PLAYLIST_LENGTH, + 'cookiefile': config.COOKIE_PATH + } - def download(self, track_name: str) -> str: - if type(track_name) != str: + def download_one(self, music: str) -> list: + """Download one music link from Youtube + + Arg: Music url or music name to search + Return: List with the Youtube URL of the music + """ + if type(music) != str: return - def download_many(self, track_list: list) -> list: - if type(track_list) != list: + if self.__is_url(music): # If Url + info = self.__download_url(music, flat=True) + else: # If Title + info = self.__download_title(music) + + return info + + def download_many(self, music_list: list) -> list: + """Download many music links from Youtube + + Arg: List with names or music url to search + Return: List with the youtube URL of each music + """ + if type(music_list) != list: return + + musics_info = [] + for music in music_list: + info = self.download_one(music) + musics_info.extend(info) + + return musics_info + + def download_full(self, link) -> dict: + """Download the full music info with the video URL""" + info = self.__download_url(url=link, flat=False) + return info[0] + + def __download_title(self, music_name: str) -> list: + """Download and return a list with the music link in dict""" + with YoutubeDL(self.__YDL_OPTIONS) as ydl: + try: + result = ydl.extract_info( + f"ytsearch:{music_name}", download=False) + id = result['entries'][0]['id'] + + link = f"https://www.youtube.com/watch?v={id}" + return [link] + except Exception as e: + raise e + + def __download_url(self, url: str, flat=True) -> list: + """Download musics from Playlist URL or Music URL + + Arg: URL from Youtube + Return: List of youtube links + """ + options = self.__YDL_OPTIONS + options['extract_flat'] = flat + with YoutubeDL(options) as ydl: + try: + result = ydl.extract_info(url, download=False) + + musics_link = [] + + if result.get('entries'): # If got a dict of musics + for entry in result['entries']: + link = f"https://www.youtube.com/watch?v={entry['id']}" + musics_link.append(link) + else: # Or a single music + musics_link.append(result['original_url']) + + return musics_link + except ExtractorError or DownloadError: + pass + + def __is_url(self, string) -> bool: + """Verify if a string is a url""" + regex = re.compile( + "http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+") + + if re.search(regex, string): + return True + else: + return False diff --git a/vulkanbot/music/Searcher.py b/vulkanbot/music/Searcher.py index 3bde535..c1f9a32 100644 --- a/vulkanbot/music/Searcher.py +++ b/vulkanbot/music/Searcher.py @@ -1,18 +1,20 @@ +import re from vulkanbot.music.Types import Provider from vulkanbot.music.Spotify import SpotifySearch -from vulkanbot.music.Youtube import YoutubeSearch class Searcher(): """Turn the user input into list of musics names, support youtube and spotify""" def __init__(self) -> None: - self.__Youtube = YoutubeSearch() self.__Spotify = SpotifySearch() print(f'Spotify Connected: {self.__Spotify.connect()}') def search(self, music: str) -> list: - """Return a list with the track name of a music or playlist""" + """Return a list with the track name of a music or playlist + + Return -> A list of musics names + """ url_type = self.__identify_source(music) if url_type == Provider.Name: @@ -26,8 +28,9 @@ class Searcher(): musics = self.__Spotify.search(music) return musics - def __identify_source(self, music): - if 'http' not in music: + def __identify_source(self, music) -> Provider: + """Identify the provider of a music""" + if not self.__is_url(music): return Provider.Name if "https://www.youtu" in music or "https://youtu.be" in music: @@ -38,3 +41,13 @@ class Searcher(): # If no match return Provider.Unknown + + def __is_url(self, string) -> bool: + """Verify if a string is a url""" + regex = re.compile( + "http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+") + + if re.search(regex, string): + return True + else: + return False diff --git a/vulkanbot/music/Youtube.py b/vulkanbot/music/Youtube.py deleted file mode 100644 index 753b6d4..0000000 --- a/vulkanbot/music/Youtube.py +++ /dev/null @@ -1,8 +0,0 @@ -class YoutubeSearch(): - """Search for tracks in youtube""" - - def __init__(self) -> None: - pass - - def search(self, track): - pass