From d0d5b91b2e41da8141a3e882f8765314a788c14c Mon Sep 17 00:00:00 2001 From: Skullheadx Date: Sun, 13 Oct 2024 19:19:18 -0400 Subject: [PATCH] everything --- README.md | 17 ++- install.sh | 1 + links.txt | 27 +---- main.py | 87 -------------- setup.py | 10 ++ ytdl.egg-info/PKG-INFO | 4 + ytdl.egg-info/SOURCES.txt | 13 +++ ytdl.egg-info/dependency_links.txt | 1 + ytdl.egg-info/entry_points.txt | 2 + ytdl.egg-info/top_level.txt | 1 + ytdl/__init__.py | 4 + ytdl/__main__.py | 45 ++++++++ ytdl/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 261 bytes ytdl/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1593 bytes ytdl/__pycache__/classmodule.cpython-312.pyc | Bin 0 -> 719 bytes ytdl/__pycache__/funcmodule.cpython-312.pyc | Bin 0 -> 1448 bytes ytdl/classmodule.py | 6 + ytdl/funcmodule.py | 112 +++++++++++++++++++ ytdl/main.py | 0 19 files changed, 211 insertions(+), 119 deletions(-) create mode 100644 install.sh delete mode 100644 main.py create mode 100644 setup.py create mode 100644 ytdl.egg-info/PKG-INFO create mode 100644 ytdl.egg-info/SOURCES.txt create mode 100644 ytdl.egg-info/dependency_links.txt create mode 100644 ytdl.egg-info/entry_points.txt create mode 100644 ytdl.egg-info/top_level.txt create mode 100644 ytdl/__init__.py create mode 100644 ytdl/__main__.py create mode 100644 ytdl/__pycache__/__init__.cpython-312.pyc create mode 100644 ytdl/__pycache__/__main__.cpython-312.pyc create mode 100644 ytdl/__pycache__/classmodule.cpython-312.pyc create mode 100644 ytdl/__pycache__/funcmodule.cpython-312.pyc create mode 100644 ytdl/classmodule.py create mode 100644 ytdl/funcmodule.py create mode 100644 ytdl/main.py 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 0000000000000000000000000000000000000000..fdc5d88fac50b97f84f9a63268a53b4213e23a95 GIT binary patch literal 261 zcmX@j%ge>Uz`$VZ!;>D*z`*br#DQTZDC4sT0|Uc!hIED$hDD4~AewOzV-#a0lP0q! zOBIuDN)?lCVil8aSrxNxVwooEEp|gQgY2Y&;#=&7MiyWOn>j>)%@j(TfW`eZnQpP> z=BK0<-(q%j3R=nV8D!-zC;iak)S_bj#JrTE)biZ?ypr_%+|;5G9%oczR;)FS=Ll9U|%`1s7c%#!$cy@JYL95%W6DWy57c11i43=E763=GBm a3=9k(m>C%vZ*eF#us&k5YGf_~`5pj!EJ&aL literal 0 HcmV?d00001 diff --git a/ytdl/__pycache__/__main__.cpython-312.pyc b/ytdl/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d52e7dab005d1ef6f3392acb9a87a73ac6fd6339 GIT binary patch literal 1593 zcmX@j%ge>Uz`&pz#FPGqnStRkhy%k+P{!vl1_p-d3@HpLj5!QznHU*Tm{OQ?7^4_d z7*berm~xq;m>EH`tT`;XtWm7FY*B2v>{0BD3@L0a3{f1ZoGI+t8Vn3Y983(U9IK&* zGBQ*$S2AmIykulxV9;c|#i;cXB;%*ac#GY)(m5xwxLA|<7GH8kYI1gbK~7?2PG)h* zEv}r*yzJum^8BLgTYM?`<#{>zi7D}kr74;D$sp}8%*MdLz|6qF@R^ATm3_ZRq z3?=+96*Y`7nH08c7Y2r6b}xn$c32QMG1f34yQP@Viy?&rAu^j`E)zm+i6G3>5@8rC zg`tLVH8jLvHq|l`u%8pjOi`Fg2$vGn&xO!m&z!;pPCAU03^mLt++a3Oi8!XIj0|8E zJYW?N)x0ovC4(lPUlGU~RZO}mRiXun#l@*93W-JOrManjB??wn3e~k$+?DyIC8bHJ zddc~@zZeyYSQr=>s#JnA@=J446hK-O5=#_vQWJ|y6!P;@6+j75A+Z=_N|l&zeoCrB zF+^!nDp)>0O`%E}syi>gM4>1(H@_@ZAu%ThthKmG9V(fWifV9ieqOplW}X5p%~vt$ zCRQ=&mQ^w9CYEXP++r@SEWX8(Sd?CNi?yIAGq20IQ~SrL4h&+rO|(G70CDXN_|H-yDHTpn;s z%y7QMEq{YYu-~WCXNK^6$(fQ1jAzST<BlWVN%4Hta2G={>d(2ba4>@m$V<#kjgMc+P$bR3z)&Q~z`*c}!v> z73(oDFnnNUWMsUn?-BeFmqC3{Ia|6d8FxcrY@s@N`sNVwSwg!qMvXfti6t H3Tz$#m$!in literal 0 HcmV?d00001 diff --git a/ytdl/__pycache__/classmodule.cpython-312.pyc b/ytdl/__pycache__/classmodule.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..626cbfd346bb562e58e163376cb5e15027b043fd GIT binary patch literal 719 zcmX@j%ge>Uz`$VS%9GyDz`*br#DQTJDC4sP0|Uc!1||k~h7^Vth7`utOc0qUhDs() z=41#5LNY=q2B@A?hA74qhA5^K#ukPs<`kwDhA5UwW=)n`?7o%GIf=!^$xx%f+CXe( z1_p-DLSPGP7;6~f!4e>%l0lQvPm}Q$OI~7bswUGdmg3Z$v?5jp28LpgJ_UteuKJV%Tnb|rNF1aF3D+=W!NM6ybTw2LjAmr0WYA>ttKtHAULmtsp}JO+ z`4($IQD$DrEw;4$qTIw1a9C(E7O{bX1f*Y~h@F9f;TA`6Vr4u?AHqK{5s+JpCBgo= z!@=8;bDdA|BA?;{mF1cXH81n&T;1tAK3mPkf*@}$W6sO3=9k{44;@7StUQSF|z7G6oSUz`$@fh$npy4+Fzv5C?{tpp4IM3=9m@8B!Qh7;_lbGBGlwFr_f(Fy=Bv zG37ExF@yOmIV`!XQLJD#YYtl!TMAnXLlk=odkaGpM+#>OM+;*VXCao85kIt85kHo&jLHGhQWm))|G*wmNA8~hOvyHn6ZbW1g^e@aW#}(%T&XZ1@jij z94K~Sh!tjFsAaBU$O4%R6@^hX%rO0o3_YSO3^fc{>@Yb5jj)B0p~oGhDwsi&$?q0N z0nAq{MQjWV47a$-KwgV4Ey^jr#g)X%H@_@ZljRm`PG(+q@huh*b&Ij! z7Bfg43j+g#f`Wp=FBkpL;?$yI{lvVKqSW%-{JfI%{M^){N`3dt5|7d({mT5(lG3D9 z-IVd;mzfY&n43Vomav!)^S>-?QFz^UA_fTa1YznvA!&^7C>k;}c6$GV?WAZ?P5>W#*OKVs>;2f43`PfRKT$HgtC%93JGVgMy?NR05o5--H`A_WEp260fd1%hMc z4hv_8>J;HCETSNma*G!@xw5cIb+Fvw6`2sy9oxb5goC#usXwbT>pGwOMLzizCKveR zFY_5(;V`@dlex+v`H_=_RSF!1nvA#D4b2R)lM0G8xo&a9$7kkcmc+;3Vk@WwWhbzg zAemPXBBGaCk(^pkl9``ZTm&i$Zn34MGi9f6&_k^yWy*k8XmY#=$%u1KAM ufdNz^6@$F?ftit!@eYIdeFl}g40^X2ct3HlGYWnZVrCTh!o$u8aUcNKVl