diff --git a/README.md b/README.md index 45d3e02..9641519 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![mmdl](https://raw.githubusercontent.com/techboy-coder/mmdl/main/mmdl%20image.png) +![mmdl](mmdl_image.png) # mmdl - Mega Music Downloader @@ -6,7 +6,9 @@ ## What is mmdl ❓ -MMDL is a cli app which allows you to quickly and efficiently download one or multiple songs from YouTube. +**TLDR**: MMDL is a cli app which allows you to quickly and efficiently download one or multiple songs from YouTube. + +I wanted a tool to quickly and efficiently download songs/audios from YouTube based on the name of the song. I also wanted the songs to be tagged with metadata. This is why I created this simple to use tool. ### Why @@ -68,15 +70,15 @@ Please [open a issue](https://github.com/techboy-coder/mmdl/issues/new) with som ### Questions ❓ -Please [start/check a discussion](https://github.com/techboy-coder/mmdl/discussions/new). +Please [start/search for a discussion](https://github.com/techboy-coder/mmdl/discussions/new). ## Contributing 🤜 -We welcome contributions very much. They are appreciated. +We welcome contributions very much (Even small ones). They are appreciated. ### Steps -1. Check for bugs/issues you would like to solve. +1. Check for bugs/issues you would like to solve or think of new features you would like to implement. 2. Fork the repo and make your changes. 3. Send a pull request. @@ -89,7 +91,11 @@ We welcome contributions very much. They are appreciated. - https://github.com/willmcgugan/rich - Rich by Will McGugan - https://github.com/ytdl-org/youtube-dl - YoutubeDl -## License ⚖️ +## Legality ⚖️ + +**I assume no liability or responsibility for how this app is used.** Please stay legal and respect the laws in your country. This tool is intended for archiving music for which you have a license. + +## License 📜 The MIT License (MIT) diff --git a/build/lib/mmdl/ask.py b/build/lib/mmdl/ask.py index 62b0307..64c50de 100644 --- a/build/lib/mmdl/ask.py +++ b/build/lib/mmdl/ask.py @@ -23,17 +23,17 @@ def asker(): ).ask() if single_songs == "One song": - return [questionary.text("What is the song name").ask()] + return [questionary.text("What is the song name?").ask()] else: input_method = questionary.select( - "Which songs do you want to download?", + "How do you want to download?", choices=[ - "Songs, comma seperated", + "Write song titles, comma seperated", 'List in textfile (1 Song per line)', 'From YTMusic (beta)', ]).ask() # returns value of selection - if input_method == "From YTMusic": + if input_method == "From YTMusic (beta)": console.print("""[bold red]YT-Music[/bold red]. - Go to your YTMusic liked songs playlist (https://music.youtube.com/playlist?list=LM) - Make sure you are logged in @@ -57,8 +57,8 @@ def asker(): text_file = open(file ,encoding='utf-8') songs_list = text_file.read().splitlines() return songs_list - elif input_method=="Songs, comma seperated": - songs_list = questionary.text("Write all songs (comma seperated)").ask().split(",") + elif input_method=="Write song titles, comma seperated": + songs_list = questionary.text("Write all songs (comma seperated):").ask().split(",") return songs_list except Exception as e: ## eventually change :/ diff --git a/build/lib/mmdl/cli.py b/build/lib/mmdl/cli.py index 22ce7e9..4648b92 100644 --- a/build/lib/mmdl/cli.py +++ b/build/lib/mmdl/cli.py @@ -17,6 +17,7 @@ from mmdl import MusicDownloader from .ask import asker from rich.console import Console +from .utils import * import questionary console = Console() from click_help_colors import HelpColorsGroup, HelpColorsCommand @@ -50,23 +51,15 @@ def go(verbose, debug): # Go Command > Easy way to download songs. Uses inputs/inquirer. (Simply run 'mmdl go') """ + print_logo() if debug: console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) + song_names=asker() - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(song_names))) + num_of_songs_printer(len(song_names)) # List, verbose, debug MusicDownloader(song_names, verbose, debug).download_songs() @@ -114,19 +107,11 @@ def file(file, seperator, verbose, debug): console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(songs))) - if not questionary.confirm("Do you want to continue").ask(): - quit() + print_logo() + + num_of_songs_printer(len(songs)) + + wanna_continue() # file, verbose, debug MusicDownloader(songs, verbose, debug).download_songs() return @@ -153,14 +138,14 @@ def list(songs, verbose, debug, ask): """ if ask: console.print("[cyan][>][/] We'll be manually asking you for songs.") - songs_list = questionary.text("Write all songs search terms (comma seperated)").ask() + songs_list = questionary.text("Write all songs search terms (comma seperated): ").ask() if not songs_list: quit() songs_list = songs_list.split(",") else: if len(songs) < 1: # console.print("[cyan][-][/] You didn't specify any songs. So we'll be manually asking them to you.") - songs_list = questionary.text("Write all songs search terms (comma seperated)").ask() + songs_list = questionary.text("Write all songs search terms (comma seperated):").ask() if not songs_list: quit() songs_list = songs_list.split(",") @@ -174,17 +159,8 @@ def list(songs, verbose, debug, ask): console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(songs_list))) + print_logo() + num_of_songs_printer(len(songs_list)) # file, verbose, debug MusicDownloader(songs_list, verbose, debug).download_songs() return @@ -209,9 +185,8 @@ def ytmusic(file, verbose, debug, ask): """ if not ask and not file: ask = True - if ask: - console.print("[cyan][>][/] We'll be manually asking you for the file location.") - console.print(""" + + guide = """ [bold red]YT-Music[/bold red]. - Go to your YTMusic liked songs playlist (https://music.youtube.com/playlist?list=LM) - Make sure you are logged in @@ -219,56 +194,39 @@ def ytmusic(file, verbose, debug, ask): - Keep scrolling down until you reach the end of your playlist (Songs will stop loading) - Copy the all the html markup - Create a text file and paste the html into it. - """) - if not questionary.confirm("Only continue if you have done the task.").ask(): - quit() + """ + + if ask: + console.print("[cyan][>][/] We'll be manually asking you for the file location.") + console.print(guide) + wanna_continue("Only continue if you have done the task.") + file = questionary.path("Where is that file located?").ask() with open(file, "r", encoding="utf-8") as f: data = f.read() - h = fromstring(data) - sel = CSSSelector("yt-formatted-string.title.style-scope.ytmusic-responsive-list-item-renderer.complex-string > a.yt-simple-endpoint.style-scope.yt-formatted-string") - songs_list=[e.text for e in sel(h)] - if not songs_list[0]: - console.log("[red][-] Hmm. No songs could be parsed from html. Did you select the correct HTML? If you see a error please make a bug report. Thanks!") - quit() + if not ask: if not file: console.log("[red][-] You need to enter the file location or add the -a flag.") quit() data = file.read() - h = fromstring(data) - sel = CSSSelector("yt-formatted-string.title.style-scope.ytmusic-responsive-list-item-renderer.complex-string > a.yt-simple-endpoint.style-scope.yt-formatted-string") - songs_list=[e.text for e in sel(h)] - if not songs_list[0]: - console.log("[red][-] Hmm. No songs could be parsed from html. Did you select the correct HTML? If you see a error please make a bug report. Thanks!") - console.print(""" -[bold red]YT-Music[/bold red]. -- Go to your YTMusic liked songs playlist (https://music.youtube.com/playlist?list=LM) -- Make sure you are logged in -- Press Ctrl/Cmd + Shift + i and open the dev tools -- Keep scrolling down until you reach the end of your playlist (Songs will stop loading) -- Copy the all the html markup -- Create a text file and paste the html into it. - """) + + + h = fromstring(data) + sel = CSSSelector("yt-formatted-string.title.style-scope.ytmusic-responsive-list-item-renderer.complex-string > a.yt-simple-endpoint.style-scope.yt-formatted-string") + songs_list=[e.text for e in sel(h)] + if not songs_list[0]: + console.log("[red][-] Hmm. No songs could be parsed from html. Did you select the correct HTML? If you see a error please make a bug report. Thanks!") + console.print(guide) if debug: console.log("Songs: ", str(songs_list)) console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(songs_list))) - if not questionary.confirm("Do you want to continue").ask(): - quit() + print_logo() + num_of_songs_printer(len(songs_list)) + wanna_continue() # file, verbose, debug MusicDownloader(songs_list, verbose, debug).download_songs() return @@ -300,16 +258,7 @@ def single(song, verbose, debug): console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) + print_logo() songs = [song] console.print("\n[cyan]> [/] Song: %s. \n" % (song)) # file, verbose, debug diff --git a/build/lib/mmdl/mdl.py b/build/lib/mmdl/mdl.py index 3586800..531abbf 100644 --- a/build/lib/mmdl/mdl.py +++ b/build/lib/mmdl/mdl.py @@ -36,81 +36,6 @@ ##Dev Dep import shutil -class DisplayablePath(object): - display_filename_prefix_middle = '├──' - display_filename_prefix_last = '└──' - display_parent_prefix_middle = ' ' - display_parent_prefix_last = '│ ' - - def __init__(self, path, parent_path, is_last): - self.path = Path(str(path)) - self.parent = parent_path - self.is_last = is_last - if self.parent: - self.depth = self.parent.depth + 1 - else: - self.depth = 0 - - @property - def displayname(self): - if self.path.is_dir(): - return self.path.name + '/' - return self.path.name - - @classmethod - def make_tree(cls, root, parent=None, is_last=False, criteria=None): - root = Path(str(root)) - criteria = criteria or cls._default_criteria - - displayable_root = cls(root, parent, is_last) - yield displayable_root - - children = sorted(list(path - for path in root.iterdir() - if criteria(path)), - key=lambda s: str(s).lower()) - count = 1 - for path in children: - is_last = count == len(children) - if path.is_dir(): - yield from cls.make_tree(path, - parent=displayable_root, - is_last=is_last, - criteria=criteria) - else: - yield cls(path, displayable_root, is_last) - count += 1 - - @classmethod - def _default_criteria(cls, path): - return True - - @property - def displayname(self): - if self.path.is_dir(): - return self.path.name + '/' - return self.path.name - - def displayable(self): - if self.parent is None: - return self.displayname - - _filename_prefix = (self.display_filename_prefix_last - if self.is_last - else self.display_filename_prefix_middle) - - parts = ['{!s} {!s}'.format(_filename_prefix, - self.displayname)] - - parent = self.parent - while parent and parent.parent is not None: - parts.append(self.display_parent_prefix_middle - if parent.is_last - else self.display_parent_prefix_last) - parent = parent.parent - - return ''.join(reversed(parts)) - class MusicDownloader(): def __init__(self, song_names: list[str], verbose: int, debug: bool): """Music Downloader Class. This is the main class :/ @@ -171,6 +96,7 @@ def download_songs(self): # sourcery no-metrics ] temp = [] cwd = Utils.get_cwd() + for f in filenames: # print(f["filename"]) does_exist = executor.submit(Utils.check_file_exists, f["filename"], f) diff --git a/build/lib/mmdl/utils.py b/build/lib/mmdl/utils.py index 5b29b05..fdf5d18 100644 --- a/build/lib/mmdl/utils.py +++ b/build/lib/mmdl/utils.py @@ -2,6 +2,9 @@ from pathlib import Path from rich.logging import RichHandler import concurrent.futures +from rich.console import Console +import questionary +console = Console() # log=logging @@ -58,4 +61,36 @@ def check_file_exists(filepath: str, rest): # print("lkj") # print(path, filepath) # print(Path(path+"/"+filepath).is_file()) - return [Path(filepath).is_file(), rest] \ No newline at end of file + # if any(File.endswith(".mp3") or File.endswith(".mp3") for File in os.listdir(".")): + # return True + # return False + exists=Path(os.path.splitext(filepath)[0]+".mp3").is_file() or Path(os.path.splitext(filepath)[0]+".m4a").is_file() or Path(os.path.splitext(filepath)[0]+".opus").is_file() + return [exists, rest] + + +def print_logo(): + console.print("""\b[red] + _ _ + | | | + _ __ ___ _ __ ___ __| | | + | '_ ` _ \| '_ ` _ \ / _` | | + | | | | | | | | | | | (_| | | [/]by techboy-coder[red] + |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder + + [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] + """) + +def num_of_songs_printer(num): + console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (num)) + +def wanna_continue(msg="Do you want to continue? "): + if not questionary.confirm(msg).ask(): + quit() + +def check_file(filename): + possible_extensions = ('', '.txt', '.dat') + for e in possible_extensions: + if os.path.isfile(filename + e): + return filename + e + else: + return None \ No newline at end of file diff --git a/build/lib/mmdl/yt_utils.py b/build/lib/mmdl/yt_utils.py index 6662d60..ac63da0 100644 --- a/build/lib/mmdl/yt_utils.py +++ b/build/lib/mmdl/yt_utils.py @@ -23,7 +23,7 @@ def __init__(self, mmdl: bool): { 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', - 'preferredquality': '192', + # 'preferredquality': '192', } ], 'outtmpl': str(self.output_dir)+'/%(title)s.%(ext)s', @@ -40,15 +40,11 @@ def download(self, url: str, do_download: bool, rest: None): with youtube_dl.YoutubeDL(self.ytdl_opts) as ydl: info = ydl.extract_info(url, download=True) filename = ydl.prepare_filename(info) - filename = filename.replace("webm","mp3") - filename = filename.replace("m4a", "mp3") return {"filename": filename, "url": url, "rest":rest} else: with youtube_dl.YoutubeDL(self.ytdl_opts) as ydl: info = ydl.extract_info(url, download=False) filename = ydl.prepare_filename(info) - filename = filename.replace("webm","mp3") - filename = filename.replace("m4a", "mp3") return {"filename": filename, "url": url, "rest":rest} def logger(self): diff --git a/dist/mmdl-0.1.5-py3-none-any.whl b/dist/mmdl-0.1.5-py3-none-any.whl deleted file mode 100644 index dfc33d2..0000000 Binary files a/dist/mmdl-0.1.5-py3-none-any.whl and /dev/null differ diff --git a/dist/mmdl-0.1.5.tar.gz b/dist/mmdl-0.1.5.tar.gz deleted file mode 100644 index 28f64f1..0000000 Binary files a/dist/mmdl-0.1.5.tar.gz and /dev/null differ diff --git a/dist/mmdl-0.1.6-py3-none-any.whl b/dist/mmdl-0.1.6-py3-none-any.whl new file mode 100644 index 0000000..0bd8ddf Binary files /dev/null and b/dist/mmdl-0.1.6-py3-none-any.whl differ diff --git a/dist/mmdl-0.1.6.tar.gz b/dist/mmdl-0.1.6.tar.gz new file mode 100644 index 0000000..6bdfbf3 Binary files /dev/null and b/dist/mmdl-0.1.6.tar.gz differ diff --git a/images/mmdl_go.png b/images/mmdl_go.png new file mode 100644 index 0000000..f9258a4 Binary files /dev/null and b/images/mmdl_go.png differ diff --git a/images/mmdl_help.png b/images/mmdl_help.png new file mode 100644 index 0000000..98ebabf Binary files /dev/null and b/images/mmdl_help.png differ diff --git a/mmdl image.png b/mmdl image.png deleted file mode 100644 index 04144a7..0000000 Binary files a/mmdl image.png and /dev/null differ diff --git a/mmdl.egg-info/PKG-INFO b/mmdl.egg-info/PKG-INFO index aa5f0a8..b528342 100644 --- a/mmdl.egg-info/PKG-INFO +++ b/mmdl.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: mmdl -Version: 0.1.5 +Version: 0.1.6 Summary: MMDL [Mega Music Downloader] - A tool to easily download music. Home-page: https://github.com/techboy-coder/mmdl Author: techboy-coder @@ -16,7 +16,7 @@ Description-Content-Type: text/markdown License-File: LICENSE -![mmdl](https://raw.githubusercontent.com/techboy-coder/mmdl/main/mmdl%20image.png) +![mmdl](mmdl_image.png) # mmdl - Mega Music Downloader @@ -24,7 +24,9 @@ License-File: LICENSE ## What is mmdl ❓ -MMDL is a cli app which allows you to quickly and efficiently download one or multiple songs from YouTube. +**TLDR**: MMDL is a cli app which allows you to quickly and efficiently download one or multiple songs from YouTube. + +I wanted a tool to quickly and efficiently download songs/audios from YouTube based on the name of the song. I also wanted the songs to be tagged with metadata. This is why I created this simple to use tool. ### Why @@ -86,15 +88,15 @@ Please [open a issue](https://github.com/techboy-coder/mmdl/issues/new) with som ### Questions ❓ -Please [start/check a discussion](https://github.com/techboy-coder/mmdl/discussions/new). +Please [start/search for a discussion](https://github.com/techboy-coder/mmdl/discussions/new). ## Contributing 🤜 -We welcome contributions very much. They are appreciated. +We welcome contributions very much (Even small ones). They are appreciated. ### Steps -1. Check for bugs/issues you would like to solve. +1. Check for bugs/issues you would like to solve or think of new features you would like to implement. 2. Fork the repo and make your changes. 3. Send a pull request. @@ -107,7 +109,11 @@ We welcome contributions very much. They are appreciated. - https://github.com/willmcgugan/rich - Rich by Will McGugan - https://github.com/ytdl-org/youtube-dl - YoutubeDl -## License ⚖️ +## Legality ⚖️ + +**I assume no liability or responsibility for how this app is used.** Please stay legal and respect the laws in your country. This tool is intended for archiving music for which you have a license. + +## License 📜 The MIT License (MIT) diff --git a/mmdl/ask.py b/mmdl/ask.py index 62b0307..64c50de 100644 --- a/mmdl/ask.py +++ b/mmdl/ask.py @@ -23,17 +23,17 @@ def asker(): ).ask() if single_songs == "One song": - return [questionary.text("What is the song name").ask()] + return [questionary.text("What is the song name?").ask()] else: input_method = questionary.select( - "Which songs do you want to download?", + "How do you want to download?", choices=[ - "Songs, comma seperated", + "Write song titles, comma seperated", 'List in textfile (1 Song per line)', 'From YTMusic (beta)', ]).ask() # returns value of selection - if input_method == "From YTMusic": + if input_method == "From YTMusic (beta)": console.print("""[bold red]YT-Music[/bold red]. - Go to your YTMusic liked songs playlist (https://music.youtube.com/playlist?list=LM) - Make sure you are logged in @@ -57,8 +57,8 @@ def asker(): text_file = open(file ,encoding='utf-8') songs_list = text_file.read().splitlines() return songs_list - elif input_method=="Songs, comma seperated": - songs_list = questionary.text("Write all songs (comma seperated)").ask().split(",") + elif input_method=="Write song titles, comma seperated": + songs_list = questionary.text("Write all songs (comma seperated):").ask().split(",") return songs_list except Exception as e: ## eventually change :/ diff --git a/mmdl/cli.py b/mmdl/cli.py index 22ce7e9..4648b92 100644 --- a/mmdl/cli.py +++ b/mmdl/cli.py @@ -17,6 +17,7 @@ from mmdl import MusicDownloader from .ask import asker from rich.console import Console +from .utils import * import questionary console = Console() from click_help_colors import HelpColorsGroup, HelpColorsCommand @@ -50,23 +51,15 @@ def go(verbose, debug): # Go Command > Easy way to download songs. Uses inputs/inquirer. (Simply run 'mmdl go') """ + print_logo() if debug: console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) + song_names=asker() - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(song_names))) + num_of_songs_printer(len(song_names)) # List, verbose, debug MusicDownloader(song_names, verbose, debug).download_songs() @@ -114,19 +107,11 @@ def file(file, seperator, verbose, debug): console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(songs))) - if not questionary.confirm("Do you want to continue").ask(): - quit() + print_logo() + + num_of_songs_printer(len(songs)) + + wanna_continue() # file, verbose, debug MusicDownloader(songs, verbose, debug).download_songs() return @@ -153,14 +138,14 @@ def list(songs, verbose, debug, ask): """ if ask: console.print("[cyan][>][/] We'll be manually asking you for songs.") - songs_list = questionary.text("Write all songs search terms (comma seperated)").ask() + songs_list = questionary.text("Write all songs search terms (comma seperated): ").ask() if not songs_list: quit() songs_list = songs_list.split(",") else: if len(songs) < 1: # console.print("[cyan][-][/] You didn't specify any songs. So we'll be manually asking them to you.") - songs_list = questionary.text("Write all songs search terms (comma seperated)").ask() + songs_list = questionary.text("Write all songs search terms (comma seperated):").ask() if not songs_list: quit() songs_list = songs_list.split(",") @@ -174,17 +159,8 @@ def list(songs, verbose, debug, ask): console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(songs_list))) + print_logo() + num_of_songs_printer(len(songs_list)) # file, verbose, debug MusicDownloader(songs_list, verbose, debug).download_songs() return @@ -209,9 +185,8 @@ def ytmusic(file, verbose, debug, ask): """ if not ask and not file: ask = True - if ask: - console.print("[cyan][>][/] We'll be manually asking you for the file location.") - console.print(""" + + guide = """ [bold red]YT-Music[/bold red]. - Go to your YTMusic liked songs playlist (https://music.youtube.com/playlist?list=LM) - Make sure you are logged in @@ -219,56 +194,39 @@ def ytmusic(file, verbose, debug, ask): - Keep scrolling down until you reach the end of your playlist (Songs will stop loading) - Copy the all the html markup - Create a text file and paste the html into it. - """) - if not questionary.confirm("Only continue if you have done the task.").ask(): - quit() + """ + + if ask: + console.print("[cyan][>][/] We'll be manually asking you for the file location.") + console.print(guide) + wanna_continue("Only continue if you have done the task.") + file = questionary.path("Where is that file located?").ask() with open(file, "r", encoding="utf-8") as f: data = f.read() - h = fromstring(data) - sel = CSSSelector("yt-formatted-string.title.style-scope.ytmusic-responsive-list-item-renderer.complex-string > a.yt-simple-endpoint.style-scope.yt-formatted-string") - songs_list=[e.text for e in sel(h)] - if not songs_list[0]: - console.log("[red][-] Hmm. No songs could be parsed from html. Did you select the correct HTML? If you see a error please make a bug report. Thanks!") - quit() + if not ask: if not file: console.log("[red][-] You need to enter the file location or add the -a flag.") quit() data = file.read() - h = fromstring(data) - sel = CSSSelector("yt-formatted-string.title.style-scope.ytmusic-responsive-list-item-renderer.complex-string > a.yt-simple-endpoint.style-scope.yt-formatted-string") - songs_list=[e.text for e in sel(h)] - if not songs_list[0]: - console.log("[red][-] Hmm. No songs could be parsed from html. Did you select the correct HTML? If you see a error please make a bug report. Thanks!") - console.print(""" -[bold red]YT-Music[/bold red]. -- Go to your YTMusic liked songs playlist (https://music.youtube.com/playlist?list=LM) -- Make sure you are logged in -- Press Ctrl/Cmd + Shift + i and open the dev tools -- Keep scrolling down until you reach the end of your playlist (Songs will stop loading) -- Copy the all the html markup -- Create a text file and paste the html into it. - """) + + + h = fromstring(data) + sel = CSSSelector("yt-formatted-string.title.style-scope.ytmusic-responsive-list-item-renderer.complex-string > a.yt-simple-endpoint.style-scope.yt-formatted-string") + songs_list=[e.text for e in sel(h)] + if not songs_list[0]: + console.log("[red][-] Hmm. No songs could be parsed from html. Did you select the correct HTML? If you see a error please make a bug report. Thanks!") + console.print(guide) if debug: console.log("Songs: ", str(songs_list)) console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) - console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (len(songs_list))) - if not questionary.confirm("Do you want to continue").ask(): - quit() + print_logo() + num_of_songs_printer(len(songs_list)) + wanna_continue() # file, verbose, debug MusicDownloader(songs_list, verbose, debug).download_songs() return @@ -300,16 +258,7 @@ def single(song, verbose, debug): console.log("Verbose: ", verbose) console.log("Debug: ", debug) - console.print("""\b[red] - _ _ - | | | - _ __ ___ _ __ ___ __| | | - | '_ ` _ \| '_ ` _ \ / _` | | - | | | | | | | | | | | (_| | | [/]by techboy-coder[red] - |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder - - [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] - """) + print_logo() songs = [song] console.print("\n[cyan]> [/] Song: %s. \n" % (song)) # file, verbose, debug diff --git a/mmdl/mdl.py b/mmdl/mdl.py index 3586800..531abbf 100644 --- a/mmdl/mdl.py +++ b/mmdl/mdl.py @@ -36,81 +36,6 @@ ##Dev Dep import shutil -class DisplayablePath(object): - display_filename_prefix_middle = '├──' - display_filename_prefix_last = '└──' - display_parent_prefix_middle = ' ' - display_parent_prefix_last = '│ ' - - def __init__(self, path, parent_path, is_last): - self.path = Path(str(path)) - self.parent = parent_path - self.is_last = is_last - if self.parent: - self.depth = self.parent.depth + 1 - else: - self.depth = 0 - - @property - def displayname(self): - if self.path.is_dir(): - return self.path.name + '/' - return self.path.name - - @classmethod - def make_tree(cls, root, parent=None, is_last=False, criteria=None): - root = Path(str(root)) - criteria = criteria or cls._default_criteria - - displayable_root = cls(root, parent, is_last) - yield displayable_root - - children = sorted(list(path - for path in root.iterdir() - if criteria(path)), - key=lambda s: str(s).lower()) - count = 1 - for path in children: - is_last = count == len(children) - if path.is_dir(): - yield from cls.make_tree(path, - parent=displayable_root, - is_last=is_last, - criteria=criteria) - else: - yield cls(path, displayable_root, is_last) - count += 1 - - @classmethod - def _default_criteria(cls, path): - return True - - @property - def displayname(self): - if self.path.is_dir(): - return self.path.name + '/' - return self.path.name - - def displayable(self): - if self.parent is None: - return self.displayname - - _filename_prefix = (self.display_filename_prefix_last - if self.is_last - else self.display_filename_prefix_middle) - - parts = ['{!s} {!s}'.format(_filename_prefix, - self.displayname)] - - parent = self.parent - while parent and parent.parent is not None: - parts.append(self.display_parent_prefix_middle - if parent.is_last - else self.display_parent_prefix_last) - parent = parent.parent - - return ''.join(reversed(parts)) - class MusicDownloader(): def __init__(self, song_names: list[str], verbose: int, debug: bool): """Music Downloader Class. This is the main class :/ @@ -171,6 +96,7 @@ def download_songs(self): # sourcery no-metrics ] temp = [] cwd = Utils.get_cwd() + for f in filenames: # print(f["filename"]) does_exist = executor.submit(Utils.check_file_exists, f["filename"], f) diff --git a/mmdl/utils.py b/mmdl/utils.py index 5b29b05..fdf5d18 100644 --- a/mmdl/utils.py +++ b/mmdl/utils.py @@ -2,6 +2,9 @@ from pathlib import Path from rich.logging import RichHandler import concurrent.futures +from rich.console import Console +import questionary +console = Console() # log=logging @@ -58,4 +61,36 @@ def check_file_exists(filepath: str, rest): # print("lkj") # print(path, filepath) # print(Path(path+"/"+filepath).is_file()) - return [Path(filepath).is_file(), rest] \ No newline at end of file + # if any(File.endswith(".mp3") or File.endswith(".mp3") for File in os.listdir(".")): + # return True + # return False + exists=Path(os.path.splitext(filepath)[0]+".mp3").is_file() or Path(os.path.splitext(filepath)[0]+".m4a").is_file() or Path(os.path.splitext(filepath)[0]+".opus").is_file() + return [exists, rest] + + +def print_logo(): + console.print("""\b[red] + _ _ + | | | + _ __ ___ _ __ ___ __| | | + | '_ ` _ \| '_ ` _ \ / _` | | + | | | | | | | | | | | (_| | | [/]by techboy-coder[red] + |_| |_| |_|_| |_| |_|\__,_|_| [/]find me on https://github.com/techboy-coder + + [green]mmdl [Mega Music Downloader] - A tool to easily download music.[/green] + """) + +def num_of_songs_printer(num): + console.print("\n[cyan]> [/] Total number of songs: %s. \n" % (num)) + +def wanna_continue(msg="Do you want to continue? "): + if not questionary.confirm(msg).ask(): + quit() + +def check_file(filename): + possible_extensions = ('', '.txt', '.dat') + for e in possible_extensions: + if os.path.isfile(filename + e): + return filename + e + else: + return None \ No newline at end of file diff --git a/mmdl/yt_utils.py b/mmdl/yt_utils.py index 6662d60..ac63da0 100644 --- a/mmdl/yt_utils.py +++ b/mmdl/yt_utils.py @@ -23,7 +23,7 @@ def __init__(self, mmdl: bool): { 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', - 'preferredquality': '192', + # 'preferredquality': '192', } ], 'outtmpl': str(self.output_dir)+'/%(title)s.%(ext)s', @@ -40,15 +40,11 @@ def download(self, url: str, do_download: bool, rest: None): with youtube_dl.YoutubeDL(self.ytdl_opts) as ydl: info = ydl.extract_info(url, download=True) filename = ydl.prepare_filename(info) - filename = filename.replace("webm","mp3") - filename = filename.replace("m4a", "mp3") return {"filename": filename, "url": url, "rest":rest} else: with youtube_dl.YoutubeDL(self.ytdl_opts) as ydl: info = ydl.extract_info(url, download=False) filename = ydl.prepare_filename(info) - filename = filename.replace("webm","mp3") - filename = filename.replace("m4a", "mp3") return {"filename": filename, "url": url, "rest":rest} def logger(self): diff --git a/mmdl_image.png b/mmdl_image.png new file mode 100644 index 0000000..1105182 Binary files /dev/null and b/mmdl_image.png differ diff --git a/setup.py b/setup.py index 5ba02ff..d4636e8 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: long_description = "\n" + fh.read() -VERSION = '0.1.5' +VERSION = '0.1.6' DESCRIPTION = 'MMDL [Mega Music Downloader] - A tool to easily download music.' LONG_DESCRIPTION = 'Music Downloading Cli Tool. Downloads audio and metadata from YouTube.'