Skip to content

Commit 6344af0

Browse files
Merge pull request avinashkranjan#487 from XZANATOL/Youtube_Video/Playlist_Downloader
Added (DownTube) Youtube Video/Playlist Downloader
2 parents cf95f4f + c45016d commit 6344af0

File tree

4 files changed

+237
-0
lines changed

4 files changed

+237
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#DownTube is a Youtube Video/Audio downloader script written by XZANATOL
2+
#https://www.github.com/XZANATOL
3+
#source code can be found on https://github.com/avinashkranjan/Amazing-Python-Scripts
4+
from pytube.cli import on_progress
5+
from pytube import YouTube, Playlist
6+
from optparse import OptionParser
7+
import sys
8+
import os
9+
import re
10+
11+
#Help menu
12+
usage = """
13+
<Script> [Options]
14+
15+
[Options]:
16+
-h, --help show this help message and exit.
17+
-a, --audio-only Flag to download only the audio source (True/Flase).
18+
-p, --playlist Playlist flag if the provided link is a playlist not a single video.
19+
-u, --url Parameter used to add Youtube link.
20+
-f, --file Parameter used to add file that contains some Youtube links.
21+
22+
Notes:
23+
1) You can't pass both -f and -u at the same time.
24+
2) If a file that exists has the same name of a file to be downloaded, the current file WILL NOT be overwritten.
25+
"""
26+
27+
#load args
28+
parser = OptionParser()
29+
parser.add_option("-a", "--audio-only", action="store_true", dest="only_audio", help="Flag to download only the audio source (True/Flase).")
30+
parser.add_option("-p", "--playlist", action="store_true", dest="playlist", help="Playlist flag is the provided link is a playlist not a single video.")
31+
parser.add_option("-u", "--url", dest="url", help="Parameter used to add Youtube link.")
32+
parser.add_option("-f", "--file", dest="file", help="Parameter used to add file that contains some Youtube links.")
33+
34+
pattern = r'res="([0-9]+)p"' #used for checking available resolutions
35+
36+
37+
def choice_single_link(links):
38+
"""Walkthorugh algorithm if -p/--playlist flag is False"""
39+
try:
40+
links = YouTube(links, on_progress_callback=on_progress)
41+
except:
42+
raise "Can't verify link, check internet connectivity/provided link."
43+
44+
if only_audio: #if -a/--audio-only flag is True
45+
count = audio_download([links]) #function accepts a list of urls
46+
else:
47+
count = is_vid([links]) #function accepts a list of urls
48+
49+
return count
50+
51+
52+
def choice_playlist(links):
53+
"""Walkthorugh algorithm if -p/--playlist flag is True"""
54+
try:
55+
links = Playlist(links)
56+
except:
57+
raise "Can't verify playlist, check internet connectivity/provided link."
58+
59+
if only_audio: #if -a/--audio-only flag is True
60+
count = audio_download(links.videos)
61+
else:
62+
count = is_vid(links.videos)
63+
64+
return count
65+
66+
67+
def file_handler(path):
68+
"""Reads file that contains Youtube links and downloads them"""
69+
try:
70+
with open(path, "r") as file:
71+
i=0 #counter for items
72+
for line in file.readlines():
73+
if not "youtube" in line or not line.rstrip("\n"):
74+
continue
75+
choice_single_link(line.rstrip("\n"))
76+
i+=1
77+
return i
78+
except:
79+
raise "Can't open file, check provided path/read permissions."
80+
81+
82+
def is_vid(lst):
83+
"""Filtering function for video downloading"""
84+
#Instead of filtring the video on each approach (playlist or single_vid or file scraping),
85+
#This function takes care of the video filtering for all approaches,
86+
#Just feed her a list of streams and watch the magic. :D
87+
88+
#this loop to check the available resolutions for 1 vid (one will apply for all)
89+
resolutions_mp4 = []
90+
resolutions_webm = []
91+
for i in lst:
92+
mp4_res = i.streams.filter(progressive=True, file_extension="mp4")
93+
for res in mp4_res:
94+
resolutions_mp4.append(re.search(pattern, str(res))[1])
95+
96+
webm_res = i.streams.filter(progressive=True, file_extension="webm")
97+
for res in webm_res:
98+
resolutions_webm.append(re.search(pattern, str(res))[1])
99+
break
100+
101+
print("Select one of the available resolutions:")
102+
print("mp4:", resolutions_mp4)
103+
print("webm:", resolutions_webm)
104+
ext, res = input("[extension] [resolution] > ").split(" ")
105+
106+
#check input
107+
if not res in resolutions_mp4+resolutions_webm or not ext in ["mp4", "webm"]:
108+
raise "Invalid Input..."
109+
110+
return video_download(lst, ext, res)
111+
112+
113+
def audio_download(objct): #objct is a list of urls
114+
"""Function that downloads provided streams as audios"""
115+
i=0 #counter for items
116+
for aud in objct:
117+
print("Downloading: " + aud.title)
118+
aud.register_on_progress_callback(on_progress) #show progress bar
119+
try:
120+
aud.streams.filter(type="audio").order_by("abr").desc().first().download()
121+
i+=1
122+
except:
123+
pass
124+
print() #add a blank line to seperate intersecting progress bars
125+
126+
return i
127+
128+
129+
def video_download(objct, ext, res): #objct is a list of urls
130+
"""Function that downloads provided streams as videos"""
131+
i=0 #counter for items
132+
for vid in objct:
133+
print("Downloading: " + vid.title)
134+
vid.register_on_progress_callback(on_progress) #show progress bar
135+
try:
136+
stream = vid.streams.filter(progressive=True, type="video", resolution=res+"p", file_extension=ext).order_by("abr").desc()
137+
138+
if len(stream)==0: #That if condition is for in case any videos in the playlist doesn't offer the same stream resolution (common in Mix playlists)
139+
print("Couldn't find available resolution for the video, Downloading with the best available one")
140+
stream = vid.streams.filter(progressive=True, type="video", file_extension=ext).order_by("resolution").desc().order_by("abr").desc()
141+
142+
stream.first().download()
143+
i+=1
144+
except:
145+
pass
146+
print() #add a blank line to seperate intersecting progress bars
147+
148+
return i
149+
150+
151+
def check_Download_folder():
152+
"""Checks if Donwloads folder exists.. If not, then it will create one."""
153+
if os.path.exists("Downloads/"):
154+
os.chdir("Downloads/")
155+
else:
156+
try:
157+
os.mkdir("Downloads")
158+
except:
159+
raise "Couldn't create 'Downloads' folder, Check write permissions"
160+
os.chdir("Downloads/")
161+
162+
163+
#Start checkpoint
164+
if __name__ == "__main__":
165+
(options, args) = parser.parse_args()
166+
167+
#flags
168+
only_audio = options.only_audio
169+
playlist = options.playlist
170+
link = options.url
171+
file = options.file
172+
173+
#validate arguments
174+
if not bool(link) ^ bool(file): #xor gate
175+
print(usage)
176+
sys.exit()
177+
178+
#prepare Downloads directory
179+
check_Download_folder()
180+
181+
if link:
182+
if playlist:
183+
count = choice_playlist(link)
184+
else:
185+
count = choice_single_link(link)
186+
else:
187+
count = file_handler(file)
188+
189+
#print a small report
190+
print("\n[+]Downloaded {} items".format(count))
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
REM Edit this batch file to run the .exe script if you don't have Python installed on your machine.
2+
3+
DownTube.py -f "E:\gmv.txt" -a
4+
5+
pause

DownTube-Youtube-Downloader/Readme.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# DownTube.
2+
3+
DownTube is an on-to-go downloader for any bundle of Youtube links you want to download. Make it be a single video, an entire playlist, or even a file that contains a couple of youtube links.
4+
5+
# Setup Instructions
6+
7+
The script depends on Pytube and Regex libraries to do Its work.
8+
9+
> pip3 install regex pytube
10+
11+
Download the script from Github, or you can clone the whole repository.
12+
13+
> git clone https://github.com/avinashkranjan/Amazing-Python-Scripts
14+
15+
# Usage
16+
17+
1) For downloading a single video, use "-u \<link>" or "--url \<link>" argument.
18+
> python3 DownTube.py -u https://www.youtube.com/watch?v=D6VnOIgnLr8
19+
2) For downloading a complete playlist, add the "-p" or "--playlist" flag.
20+
> python3 DownTube.py -u https://www.youtube.com/playlist?list=PLsRxtLB5dnMaX54r-INR_HQlDtNomT_xa -p
21+
3) For downloading urls from a text file, use the "-f \<path>" or "--file \<path>" argument.
22+
> python3 DownTube.py -f C:\file.txt
23+
4) For downloading only the audio source add the "-a" or "--audio-only" flag.
24+
> python3 DownTube.py -f C:\file.txt -a
25+
26+
# Output
27+
28+
Download Videos and Audio from Youtube, so that a user can enjoy it offline.
29+
30+
# Authors
31+
32+
Written by <a href="https://github.com/XZANATOL" target="_blank">XZANATOL</a>
33+
34+
Mentored by <a href="https://github.com/avinashkranjan" target="_blank">Avinash Kr. Ranjan</a>
35+
36+
This project was built under the mentorship of <a href="https://gssoc.girlscript.tech/" target="_blank">GSSOC21</a>
37+
38+
# Notes
39+
40+
1) You can't pass -f and -u arguments at the same time. only use one at a time.
41+
2) If a file that exists has the same name of a file to be downloaded, the current file WILL NOT be overwritten.
42+
3) Use double quotes on links and file_paths when using Windows CMD.

0 commit comments

Comments
 (0)