From: Skullheadx Date: Sun, 13 Oct 2024 23:19:18 +0000 (-0400) Subject: everything X-Git-Url: http://git.skullheadx.com/tech/openbsd_html_css/static/gitweb.css?a=commitdiff_plain;h=d0d5b91b2e41da8141a3e882f8765314a788c14c;p=youtube-downloader.git everything --- diff --git a/README.md b/README.md index 76e3731..7964b8d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,12 @@ -# youtube-downloader +# Youtube Downloader - ytdl + +## usage +```shell +ytdl "https://music.youtube.com/watch?v=lYBUbBu4W08&si=z03FVSmqqyxKZFmZ" +``` +downloads the audio and video and stitches it together in the current directory. Automatically detects playlists. + +- `-a` - audio only +- `-v` - video only +- `-av` - audio + video separate -HOW TO USE -- Enter links into the links_file.txt file each on a new line. - - You can even put links to playlists too! -- Run the main.py file using python -- Enjoy your newly downloaded videos in the "downloaded" folder. (audio and video streams are available in the respective folders in downloaded) diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..7895f27 --- /dev/null +++ b/install.sh @@ -0,0 +1 @@ +pip install -e . \ No newline at end of file diff --git a/links.txt b/links.txt index b00161d..5acca21 100644 --- a/links.txt +++ b/links.txt @@ -1,26 +1 @@ -https://www.youtube.com/watch?app=desktop&v=lW4KseyDqcY -https://www.youtube.com/watch?v=nJ7ZCN0m14A -https://www.youtube.com/watch?app=desktop&v=VvWX3vRRLME -https://www.youtube.com/watch?v=iCx2nBfu54I -https://www.youtube.com/watch?app=desktop&v=V2hrTDS4Ml4 -https://www.youtube.com/watch?app=desktop&v=_Sd11FWbvZ8 -https://www.youtube.com/watch?v=HDOIQZZoABg -https://www.youtube.com/watch?v=j-ttaqEzXKM -https://www.youtube.com/watch?app=desktop&v=UMiW3G1USHg#dialog -https://www.youtube.com/watch?v=uPG77Gtn0Ws -https://www.youtube.com/watch?app=desktop&v=7cKGmeTY9eg -https://www.youtube.com/watch?app=desktop&v=Pfs9yAsRbaU -https://www.youtube.com/watch?v=WxKbU98GLRY -https://www.youtube.com/watch?v=9MzCxt1QpWg -https://www.youtube.com/watch?v=jCaug9SkKEI -https://www.youtube.com/watch?v=V19v3oNPixQ -https://www.youtube.com/watch?v=NscXXbmAggI -https://www.youtube.com/watch?v=iCx2nBfu54I -https://www.youtube.com/watch?v=9pq-G57iSEQ -https://www.youtube.com/watch?v=XVRno3Y1TX8 -https://www.youtube.com/watch?v=codyY_-AiXc -https://www.youtube.com/watch?v=qZ2yWvholHw -https://www.youtube.com/watch?v=wodcSTIxZtw -https://www.youtube.com/watch?v=btKTE4eMPf4 -https://www.youtube.com/watch?v=kW-WE5zrJsg -https://www.youtube.com/watch?v=i5M-WHDhQ4c +https://music.youtube.com/watch?v=lYBUbBu4W08&si=z03FVSmqqyxKZFmZ diff --git a/main.py b/main.py deleted file mode 100644 index 5f5b3a1..0000000 --- a/main.py +++ /dev/null @@ -1,87 +0,0 @@ -from pytubefix import YouTube, Playlist -from pytubefix.exceptions import VideoUnavailable -import ffmpeg - - -RES = ["1440p", "1080p", "720p", "480p", "360p", "240p", "144p"] -ABR = ["160kbps", "128kbps", "70kbps", "50kbps", "48kbps"] -target_res = 0 -target_abr=0 - -failed_download = set() - -if __name__ == "__main__": - - # get list of links from file - links = [] - with open('links.txt', 'r') as f: - links = f.read().split('\n') - if links[-1] == "": - links = links[:-1] - - for link in links: - if "playlist" in link: - p = Playlist(link) - for url in p.video_urls: - links.append(url) - links.remove(link) - - - # download links one by one - for link in links: - target_res = 0 - target_abr = 0 - video_success = True - audio_success = True - - try: - yt = YouTube(link) - yt.streams - - except VideoUnavailable: - print(f'Video {link} is unavaialable, skipping.') - failed_download.add(((yt.title, link))) - else: - video_streams = [] - while len(video_streams) == 0: - video_streams = yt.streams.filter(file_extension='mp4', res=RES[target_res]) # find available streams - if target_res + 1 < len(RES): - target_res = target_res + 1 - else: - video_success = False - break - if not video_success: - print(f"Unable to find video stream for {yt.title}") - failed_download.add(((yt.title, link))) - - break - vstream = video_streams[0] - - # audio - audio_streams = [] - while len(audio_streams) == 0: - audio_streams = yt.streams.filter(only_audio=True, abr=ABR[target_abr]) # find available streams - - if target_abr + 1 < len(RES): - target_abr = target_abr + 1 - else: - audio_success = False - break - if not audio_success: - print(f"Unable to find audio stream for {yt.title}") - failed_download.add(((yt.title, link))) - - break - astream = audio_streams[0] - - vstream.download(output_path="downloaded/video_only") - astream.download(output_path="downloaded/audio_only") - - input_video = ffmpeg.input(f"downloaded/video_only/{vstream.default_filename}") - input_audio = ffmpeg.input(f"downloaded/audio_only/{astream.default_filename}") - - ffmpeg.concat(input_video, input_audio, v=1, a=1).output(f'downloaded/{yt.title}.mp4').run() - -print("Failed Downloading:") -print(failed_download) - diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b8c2199 --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +from setuptools import setup +setup( + name = 'ytdl', + version = '0.1.0', + packages = ['ytdl'], + entry_points = { + 'console_scripts': [ + 'ytdl = ytdl.__main__:main' + ] + }) \ No newline at end of file diff --git a/ytdl.egg-info/PKG-INFO b/ytdl.egg-info/PKG-INFO new file mode 100644 index 0000000..d54d315 --- /dev/null +++ b/ytdl.egg-info/PKG-INFO @@ -0,0 +1,4 @@ +Metadata-Version: 2.1 +Name: ytdl +Version: 0.1.0 +License-File: LICENSE diff --git a/ytdl.egg-info/SOURCES.txt b/ytdl.egg-info/SOURCES.txt new file mode 100644 index 0000000..11a7a88 --- /dev/null +++ b/ytdl.egg-info/SOURCES.txt @@ -0,0 +1,13 @@ +LICENSE +README.md +setup.py +ytdl/__init__.py +ytdl/__main__.py +ytdl/classmodule.py +ytdl/funcmodule.py +ytdl/main.py +ytdl.egg-info/PKG-INFO +ytdl.egg-info/SOURCES.txt +ytdl.egg-info/dependency_links.txt +ytdl.egg-info/entry_points.txt +ytdl.egg-info/top_level.txt \ No newline at end of file diff --git a/ytdl.egg-info/dependency_links.txt b/ytdl.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ytdl.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/ytdl.egg-info/entry_points.txt b/ytdl.egg-info/entry_points.txt new file mode 100644 index 0000000..ab2a57f --- /dev/null +++ b/ytdl.egg-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +ytdl = ytdl.__main__:main diff --git a/ytdl.egg-info/top_level.txt b/ytdl.egg-info/top_level.txt new file mode 100644 index 0000000..763acad --- /dev/null +++ b/ytdl.egg-info/top_level.txt @@ -0,0 +1 @@ +ytdl diff --git a/ytdl/__init__.py b/ytdl/__init__.py new file mode 100644 index 0000000..ea9ae9e --- /dev/null +++ b/ytdl/__init__.py @@ -0,0 +1,4 @@ +modes = ["-d", "-a", "-v", "-av"] + +ABR = ["160kbps", "128kbps", "70kbps", "50kbps", "48kbps"] + diff --git a/ytdl/__main__.py b/ytdl/__main__.py new file mode 100644 index 0000000..85b0add --- /dev/null +++ b/ytdl/__main__.py @@ -0,0 +1,45 @@ +from .__init__ import * +import sys +from .classmodule import MyClass +from .funcmodule import check_playlist, links_work, download_audio + +def main(): + args = sys.argv[1:] + + links = [] + mode = "-d" + for arg in args: + print('passed argument :: {}'.format(arg)) + if arg in modes: + mode = arg + + if "youtube.com" in arg: + links.extend(arg.split(" ")) + + + assert len(links) > 0, "Should pass at least one link as arg" + assert mode in modes, f"Mode should be one of {modes}" + + # remove empty strings + links = list(filter(None, links)) + assert len(links) > 0, "Should not remove all links" + + links = check_playlist(links) + assert len(links) > 0, "Should be at least one song in playlist" + + #assert links_work(links), "Links don't work :(" + + if arg == "-d": + pass + elif arg == "-a": + download_audio(links) + elif arg == "-v": + pass + elif arg == "-av": + pass + + +if __name__ == '__main__': + main() + + diff --git a/ytdl/__pycache__/__init__.cpython-312.pyc b/ytdl/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..fdc5d88 Binary files /dev/null and b/ytdl/__pycache__/__init__.cpython-312.pyc differ diff --git a/ytdl/__pycache__/__main__.cpython-312.pyc b/ytdl/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..d52e7da Binary files /dev/null and b/ytdl/__pycache__/__main__.cpython-312.pyc differ diff --git a/ytdl/__pycache__/classmodule.cpython-312.pyc b/ytdl/__pycache__/classmodule.cpython-312.pyc new file mode 100644 index 0000000..626cbfd Binary files /dev/null and b/ytdl/__pycache__/classmodule.cpython-312.pyc differ diff --git a/ytdl/__pycache__/funcmodule.cpython-312.pyc b/ytdl/__pycache__/funcmodule.cpython-312.pyc new file mode 100644 index 0000000..ad1302f Binary files /dev/null and b/ytdl/__pycache__/funcmodule.cpython-312.pyc differ diff --git a/ytdl/classmodule.py b/ytdl/classmodule.py new file mode 100644 index 0000000..31fea4f --- /dev/null +++ b/ytdl/classmodule.py @@ -0,0 +1,6 @@ +class MyClass(): + def __init__(self, name): + self.name = name + + def say_name(self): + print('name is {}'.format(self.name)) diff --git a/ytdl/funcmodule.py b/ytdl/funcmodule.py new file mode 100644 index 0000000..35b4cc3 --- /dev/null +++ b/ytdl/funcmodule.py @@ -0,0 +1,112 @@ +from .__init__ import * +from pytube import YouTube, Playlist +from pytube.exceptions import VideoUnavailable +import ffmpeg + + + +def check_playlist(links): + for link in links: + if "playlist" in link: + p = Playlist(link) + for url in p.video_urls: + links.append(url) + links.remove(link) + return links + +def links_work(links): + for link in links: + YouTube(link).check_availability() + return True + + +def download_audio(links, target_abr="160kbps"): + print(links, ABR) + print('a') + for link in links: + yt = YouTube(link) + # assert yt.includes_audio_track() + print(yt.streams.filter(only_audio=True)) + print(yt.streams) + + + + + + + + + + +# RES = ["1440p", "1080p", "720p", "480p", "360p", "240p", "144p"] +# ABR = ["160kbps", "128kbps", "70kbps", "50kbps", "48kbps"] +# target_res = 0 +# target_abr=0 + +# get list of links from file +# links = [] +# with open('links.txt', 'r') as f: +# links = f.read().split('\n') +# if links[-1] == "": +# links = links[:-1] +# print(links) + + + +# # download links one by one +# for link in links: +# target_res = 0 +# target_abr = 0 +# video_success = True +# audio_success = True + +# try: +# yt = YouTube(link) +# yt.streams + +# except VideoUnavailable: +# print(f'Video {link} is unavaialable, skipping.') +# failed_download.add(((yt.title, link))) +# else: +# video_streams = [] +# while len(video_streams) == 0: +# video_streams = yt.streams.filter(file_extension='mp4', res=RES[target_res]) # find available streams +# if target_res + 1 < len(RES): +# target_res = target_res + 1 +# else: +# video_success = False +# break +# if not video_success: +# print(f"Unable to find video stream for {yt.title}") +# failed_download.add(((yt.title, link))) + +# break +# vstream = video_streams[0] + +# # audio +# audio_streams = [] +# while len(audio_streams) == 0: +# audio_streams = yt.streams.filter(only_audio=True, abr=ABR[target_abr]) # find available streams + +# if target_abr + 1 < len(RES): +# target_abr = target_abr + 1 +# else: +# audio_success = False +# break +# if not audio_success: +# print(f"Unable to find audio stream for {yt.title}") +# failed_download.add(((yt.title, link))) + +# break +# astream = audio_streams[0] + +# vstream.download(output_path="downloaded/video_only") +# astream.download(output_path="downloaded/audio_only") + +# input_video = ffmpeg.input(f"downloaded/video_only/{vstream.default_filename}") +# input_audio = ffmpeg.input(f"downloaded/audio_only/{astream.default_filename}") + +# ffmpeg.concat(input_video, input_audio, v=1, a=1).output(f'downloaded/{yt.title}.mp4').run() + +# print("Failed Downloading:") +# print(failed_download) diff --git a/ytdl/main.py b/ytdl/main.py new file mode 100644 index 0000000..e69de29