-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathyoutube_dl_download_helper.py
160 lines (141 loc) · 5.47 KB
/
youtube_dl_download_helper.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from .download_helper import DownloadHelper
import time
from youtube_dl import YoutubeDL, DownloadError
from bot import download_dict_lock, download_dict
from ..status_utils.youtube_dl_download_status import YoutubeDLDownloadStatus
import logging
import re
import threading
LOGGER = logging.getLogger(__name__)
class MyLogger:
def __init__(self, obj):
self.obj = obj
def debug(self, msg):
LOGGER.debug(msg)
# Hack to fix changing changing extension
match = re.search(r'.ffmpeg..Merging formats into..(.*?).$', msg)
if match and not self.obj.is_playlist:
self.obj.name = match.group(1)
@staticmethod
def warning(msg):
LOGGER.warning(msg)
@staticmethod
def error(msg):
LOGGER.error(msg)
class YoutubeDLHelper(DownloadHelper):
def __init__(self, listener):
super().__init__()
self.__name = ""
self.__start_time = time.time()
self.__listener = listener
self.__gid = ""
self.opts = {
'progress_hooks': [self.__onDownloadProgress],
'logger': MyLogger(self),
'usenetrc': True
}
self.__download_speed = 0
self.download_speed_readable = ''
self.downloaded_bytes = 0
self.size = 0
self.is_playlist = False
self.last_downloaded = 0
self.is_cancelled = False
self.vid_id = ''
self.__resource_lock = threading.RLock()
@property
def download_speed(self):
with self.__resource_lock:
return self.__download_speed
@property
def gid(self):
with self.__resource_lock:
return self.__gid
def __onDownloadProgress(self, d):
if self.is_cancelled:
raise ValueError("Cancelling Download..")
if d['status'] == "finished":
if self.is_playlist:
self.last_downloaded = 0
elif d['status'] == "downloading":
with self.__resource_lock:
self.__download_speed = d['speed']
if self.is_playlist:
progress = d['downloaded_bytes'] / d['total_bytes']
chunk_size = d['downloaded_bytes'] - self.last_downloaded
self.last_downloaded = d['total_bytes'] * progress
self.downloaded_bytes += chunk_size
try:
self.progress = (self.downloaded_bytes / self.size) * 100
except ZeroDivisionError:
pass
else:
self.download_speed_readable = d['_speed_str']
self.downloaded_bytes = d['downloaded_bytes']
def __onDownloadStart(self):
with download_dict_lock:
download_dict[self.__listener.uid] = YoutubeDLDownloadStatus(self, self.__listener)
def __onDownloadComplete(self):
self.__listener.onDownloadComplete()
def onDownloadError(self, error):
self.__listener.onDownloadError(error)
def extractMetaData(self, link, qual):
if 'hotstar' in link:
self.opts['geo_bypass_country'] = 'IN'
with YoutubeDL(self.opts) as ydl:
try:
result = ydl.extract_info(link, download=False)
name = ydl.prepare_filename(result)
# noobway hack for changing extension after converting to mp3
if qual == "audio":
name = name.replace(".mp4", ".mp3").replace(".webm", ".mp3")
except DownloadError as e:
self.onDownloadError(str(e))
return
if result.get('direct'):
return None
if 'entries' in result:
video = result['entries'][0]
for v in result['entries']:
if v.get('filesize'):
self.size += float(v['filesize'])
# For playlists, ydl.prepare-filename returns the following format: <Playlist Name>-<Id of playlist>.NA
self.name = name.split(f"-{result['id']}")[0]
self.vid_id = video.get('id')
self.is_playlist = True
else:
video = result
if video.get('filesize'):
self.size = float(video.get('filesize'))
self.name = name
self.vid_id = video.get('id')
return video
def __download(self, link):
try:
with YoutubeDL(self.opts) as ydl:
try:
ydl.download([link])
except DownloadError as e:
self.onDownloadError(str(e))
return
self.__onDownloadComplete()
except ValueError:
LOGGER.info("Download Cancelled by User!")
self.onDownloadError("Download Cancelled by User!")
def add_download(self, link, path, qual):
self.__onDownloadStart()
self.extractMetaData(link, qual)
LOGGER.info(f"Downloading with YT-DL: {link}")
self.__gid = f"{self.vid_id}{self.__listener.uid}"
if qual == "audio":
self.opts['format'] = 'bestaudio/best'
self.opts['postprocessors'] = [{'key': 'FFmpegExtractAudio','preferredcodec': 'mp3','preferredquality': '192',}]
else:
self.opts['format'] = qual
if not self.is_playlist:
self.opts['outtmpl'] = f"{path}/{self.name}"
else:
self.opts['outtmpl'] = f"{path}/{self.name}/%(title)s.%(ext)s"
self.__download(link)
def cancel_download(self):
self.is_cancelled = True