Amazing-Python-Scripts
198 строк · 6.7 Кб
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
4from pytube.cli import on_progress5from pytube import YouTube, Playlist6from optparse import OptionParser7import sys8import os9import re10
11# Help menu
12usage = """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
22Notes:
231) You can't pass both -f and -u at the same time.
242) 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
28parser = OptionParser()29parser.add_option("-a", "--audio-only", action="store_true", dest="only_audio",30help="Flag to download only the audio source (True/Flase).")31parser.add_option("-p", "--playlist", action="store_true", dest="playlist",32help="Playlist flag is the provided link is a playlist not a single video.")33parser.add_option("-u", "--url", dest="url",34help="Parameter used to add Youtube link.")35parser.add_option("-f", "--file", dest="file",36help="Parameter used to add file that contains some Youtube links.")37
38pattern = r'res="([0-9]+)p"' # used for checking available resolutions39
40
41def choice_single_link(links):42"""Walkthorugh algorithm if -p/--playlist flag is False"""43try:44links = YouTube(links, on_progress_callback=on_progress)45except:46raise "Can't verify link, check internet connectivity/provided link."47
48if only_audio: # if -a/--audio-only flag is True49count = audio_download([links]) # function accepts a list of urls50else:51count = is_vid([links]) # function accepts a list of urls52
53return count54
55
56def choice_playlist(links):57"""Walkthorugh algorithm if -p/--playlist flag is True"""58try:59links = Playlist(links)60except:61raise "Can't verify playlist, check internet connectivity/provided link."62
63if only_audio: # if -a/--audio-only flag is True64count = audio_download(links.videos)65else:66count = is_vid(links.videos)67
68return count69
70
71def file_handler(path):72"""Reads file that contains Youtube links and downloads them"""73try:74with open(path, "r") as file:75i = 0 # counter for items76for line in file.readlines():77if not "youtube" in line or not line.rstrip("\n"):78continue79choice_single_link(line.rstrip("\n"))80i += 181return i82except:83raise "Can't open file, check provided path/read permissions."84
85
86def is_vid(lst):87"""Filtering function for video downloading"""88# Instead of filtring the video on each approach (playlist or single_vid or file scraping),89# This function takes care of the video filtering for all approaches,90# Just feed her a list of streams and watch the magic. :D91
92# this loop to check the available resolutions for 1 vid (one will apply for all)93resolutions_mp4 = []94resolutions_webm = []95for i in lst:96mp4_res = i.streams.filter(progressive=True, file_extension="mp4")97for res in mp4_res:98resolutions_mp4.append(re.search(pattern, str(res))[1])99
100webm_res = i.streams.filter(progressive=True, file_extension="webm")101for res in webm_res:102resolutions_webm.append(re.search(pattern, str(res))[1])103break104
105print("Select one of the available resolutions:")106print("mp4:", resolutions_mp4)107print("webm:", resolutions_webm)108ext, res = input("[extension] [resolution] > ").split(" ")109
110# check input111if not res in resolutions_mp4+resolutions_webm or not ext in ["mp4", "webm"]:112raise "Invalid Input..."113
114return video_download(lst, ext, res)115
116
117def audio_download(objct): # objct is a list of urls118"""Function that downloads provided streams as audios"""119i = 0 # counter for items120for aud in objct:121print("Downloading: " + aud.title)122aud.register_on_progress_callback(on_progress) # show progress bar123try:124aud.streams.filter(type="audio").order_by(125"abr").desc().first().download()126i += 1127except:128pass129print() # add a blank line to seperate intersecting progress bars130
131return i132
133
134def video_download(objct, ext, res): # objct is a list of urls135"""Function that downloads provided streams as videos"""136i = 0 # counter for items137for vid in objct:138print("Downloading: " + vid.title)139vid.register_on_progress_callback(on_progress) # show progress bar140try:141stream = vid.streams.filter(142progressive=True, type="video", resolution=res+"p", file_extension=ext).order_by("abr").desc()143
144if 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)145print(146"Couldn't find available resolution for the video, Downloading with the best available one")147stream = vid.streams.filter(progressive=True, type="video", file_extension=ext).order_by(148"resolution").desc().order_by("abr").desc()149
150stream.first().download()151i += 1152except:153pass154print() # add a blank line to seperate intersecting progress bars155
156return i157
158
159def check_Download_folder():160"""Checks if Donwloads folder exists.. If not, then it will create one."""161if os.path.exists("Downloads/"):162os.chdir("Downloads/")163else:164try:165os.mkdir("Downloads")166except:167raise "Couldn't create 'Downloads' folder, Check write permissions"168os.chdir("Downloads/")169
170
171# Start checkpoint
172if __name__ == "__main__":173(options, args) = parser.parse_args()174
175# flags176only_audio = options.only_audio177playlist = options.playlist178link = options.url179file = options.file180
181# validate arguments182if not bool(link) ^ bool(file): # xor gate183print(usage)184sys.exit()185
186# prepare Downloads directory187check_Download_folder()188
189if link:190if playlist:191count = choice_playlist(link)192else:193count = choice_single_link(link)194else:195count = file_handler(file)196
197# print a small report198print("\n[+]Downloaded {} items".format(count))199