Last active
May 16, 2016 18:18
-
-
Save samhutchins/6aa3d442a8826d744867aad07805ea3b to your computer and use it in GitHub Desktop.
YouTube Downloader.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from urllib.parse import urlparse, parse_qs | |
from os import getcwd, path | |
import requests, appex, ui | |
class YouTube_video: | |
def __init__(self, url): | |
self.id = self.get_id(url) | |
self.title = None | |
self.stream_map = None | |
self.get_video_info() | |
self.format_dict = { | |
'22': '720p HD', | |
'18': '360p SD', | |
'17': '144p SD' | |
} | |
def get_id(self, url): # can only parse youtu.be links | |
parsed_url = urlparse(url) | |
_, id = parsed_url.path.split('/') | |
return id | |
def get_video_info(self): #gets title and stream_map | |
info_page = requests.get( | |
'http://youtube.com/get_video_info?video_id=' + self.id) | |
info_page = parse_qs(info_page.text) | |
self.title = info_page['title'][0] | |
self.stream_map = str(info_page['url_encoded_fmt_stream_map'][0]).split(',') | |
def get_download_url(self, itag): | |
for stream in self.stream_map: | |
url = parse_qs(stream) | |
if url['itag'][0] == str(itag): | |
return url['url'][0] | |
def get_formats(self): | |
formats = [] | |
for stream in self.stream_map: | |
page = parse_qs(stream) | |
itag = page['itag'][0] | |
if itag in self.format_dict: | |
formats.append((self.format_dict[itag], itag)) | |
return formats | |
def debug_stream_map(self): | |
page = parse_qs(self.stream_map[0]) | |
for key in page: | |
print(key) | |
def debug_formats(self): | |
for stream in self.stream_map: | |
page = parse_qs(stream) | |
print(page['quality'][0]) | |
print(page['type'][0]) | |
print(page['itag'][0]) | |
print('---') | |
class Formats: # the data provider for the tableview | |
def __init__(self, data, callback): | |
self.data = data | |
self.callback = callback | |
def tableview_number_of_sections(self, tableview): | |
return 1 | |
def tableview_number_of_rows(self, tableview, section): | |
return len(self.data) | |
def tableview_cell_for_row(self, tableview, section, row): | |
cell = ui.TableViewCell() | |
cell.text_label.text, _ = self.data[row] | |
return cell | |
def tableview_did_select(self, tableview, section, row): | |
_, itag = self.data[row] | |
self.callback(itag) | |
class Downloader: #Responsible for downloading a given url. | |
def __init__(self, callback): | |
self.callback = callback | |
def download(self, title, url): | |
self.callback.start() | |
file_path = path.join( | |
getcwd(), | |
title + '.mp4') | |
with open(file_path, 'wb') as f: | |
r = requests.get(url, stream=True) | |
total_size = float(r.headers.get('content-length')) | |
dl = 0 | |
for chunk in r.iter_content(32768): | |
dl += len(chunk) | |
f.write(chunk) | |
self.callback.update_progress(dl/total_size) | |
self.callback.stop() | |
class DownloaderCallback(object): # Acts as an interface between the Downloader and the front end | |
def __init__(self, start, stop, progress): | |
self.start = start | |
self.stop = stop | |
self.progress = progress | |
def start(self): | |
self.start() | |
def stop(self): | |
self.stop() | |
def update_progress(self, progress): | |
self.progress(progress) | |
class DownloaderUI(ui.View): | |
def __init__(self, video_url): | |
self.name = 'Downloader' | |
self.video = YouTube_video(video_url) | |
self.frame = (0, 0, 540, 540) | |
self.background_color = 'white' | |
self.data_source = Formats(self.video.get_formats(), self.action_event) | |
self.tv = ui.TableView( | |
frame = (0, 50, 540, 490), | |
flex = 'WH') | |
self.tv.data_source = self.data_source | |
self.tv.delegate = self.data_source | |
self.progress_bar = ui.Label( | |
frame = (0, 0, 0, 50), | |
flex = '', | |
background_color = (0.00, 0.50, 1.00, 0.5)) | |
self.activity_indicator = ui.ActivityIndicator( | |
frame = (270,25,0,0), | |
flex = 'W', | |
alignment = ui.ALIGN_CENTER) | |
self.add_subview(self.tv) | |
self.add_subview(self.progress_bar) | |
self.add_subview(self.activity_indicator) | |
self.callback = DownloaderCallback( | |
self.activity_indicator.start, | |
self.activity_indicator.stop, | |
self.set_progress) | |
@ui.in_background | |
def action_event(self, itag): | |
downloader = Downloader(self.callback) | |
downloader.download( | |
self.video.title, | |
self.video.get_download_url(itag)) | |
def set_progress(self, progress): | |
self.progress_bar.width = self.width*progress | |
if self.progress_bar.width == self.width: | |
self.progress_bar.background_color = (0.00, 1.00, 0.10, 0.7) | |
self.activity_indicator.stop() | |
if __name__ == '__main__': | |
view = DownloaderUI(appex.get_url()) | |
view.present('sheet') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment