diff --git a/downloader.kv b/downloader.kv index 99f1e16..684b328 100644 --- a/downloader.kv +++ b/downloader.kv @@ -49,6 +49,7 @@ text_size: self.width, None size_hint: 1, None height: self.texture_size[1] + on_ref_press: root.on_ref_press(args[1]) markup: True Button: text: 'Close' @@ -82,12 +83,9 @@ BoxLayout: orientation: 'vertical' ScrollView: - Label: - id: info_label - size: self.texture_size - text_size: self.width, None - size_hint: 1, None - height: self.texture_size[1] + BoxLayout: + id: view + orientation: 'vertical' Button: size_hint_y: .1 text: 'Close' @@ -164,7 +162,7 @@ text_size: self.width, None height: self.texture_size[1] Label: - text: str(root.percent) + '%' + ' ' + root.speed + ' ' + root.file_size + ' ' + root.ETA + text: '{:5.2f}% {} {} {}'.format(root.percent, root.file_size, root.speed, root.ETA) text_size: self.width, None height: self.texture_size[1] ProgressBar: diff --git a/downloaderThread.py b/downloaderThread.py index 330c28a..3604fb7 100644 --- a/downloaderThread.py +++ b/downloaderThread.py @@ -5,26 +5,27 @@ from status import STATUS_IN_PROGRESS, STATUS_DONE, STATUS_ERROR + class DownloaderThread(threading.Thread): - def __init__(self, url, ydl_opts, datum): - threading.Thread.__init__(self) - self.url = url - self.ydl_opts = ydl_opts - self.logger = ydl_opts['logger'] - self.datum = datum + def __init__(self, url, ydl_opts, datum): + threading.Thread.__init__(self) + self.url = url + self.ydl_opts = ydl_opts + self.logger = ydl_opts['logger'] + self.datum = datum - def run(self): - try: - with youtube_dl.YoutubeDL(self.ydl_opts) as ydl: - retcode = ydl.download([self.url]) - self.logger.debug(f'Finished with retcode {retcode}') - self.datum['status'] = STATUS_DONE if retcode == 0 else STATUS_ERROR - except SystemExit: - self.logger.debug('System Exit') - self.datum['status'] = STATUS_ERROR - pass - except Exception as inst: - self.logger.error(inst) - self.logger.error(traceback.format_exc()) - self.datum['status'] = STATUS_ERROR - pass + def run(self): + try: + with youtube_dl.YoutubeDL(self.ydl_opts) as ydl: + retcode = ydl.download([self.url]) + self.logger.debug(f'Finished with retcode {retcode}') + self.datum['status'] = STATUS_DONE if retcode == 0 else STATUS_ERROR + except SystemExit: + self.logger.debug('System Exit') + self.datum['status'] = STATUS_ERROR + pass + except Exception as inst: + self.logger.error(inst) + self.logger.error(traceback.format_exc()) + self.datum['status'] = STATUS_ERROR + pass diff --git a/logger.py b/logger.py index 2ea4088..974dc12 100644 --- a/logger.py +++ b/logger.py @@ -1,29 +1,34 @@ import re + class YdlLogger(object): - rv = None - - def __init__(self, rv, index): - self.rv = rv - self.index = index - - def debug(self, msg): - m = re.search(r'\[download\][ ]+(\d+\.\d+)% of (~?\d+\.\d+).* at[ ]+(.*) ETA (\d+\:\d+)', msg) - - if m is not None: - self.rv.data[self.index]['percent'] = float(m.group(1)) - self.rv.data[self.index]['file_size'] = m.group(2) - self.rv.data[self.index]['speed'] = m.group(3) - self.rv.data[self.index]['ETA'] = m.group(4) - self.rv.refresh_from_data() - else: - self.rv.data[self.index]['log'] += f"{msg}\n" - self.rv.refresh_from_data() - - def warning(self, msg): - self.rv.data[self.index]['log'] += f"[color=ffff00]{msg}[/color]\n" - self.rv.refresh_from_data() - - def error(self, msg): - self.rv.data[self.index]['log'] += f"[color=ff0000]{msg}[/color]\n" - self.rv.refresh_from_data() \ No newline at end of file + rv = None + + def __init__(self, rv, index): + self.rv = rv + self.index = index + + def debug(self, msg): + m = re.search( + r'\[download\][ ]+(\d+\.\d+)% of (~?\d+\.\d+.*) at[ ]+(.*) ETA (\d+\:\d+)', msg) + + if m is not None: + self.rv.data[self.index]['percent'] = float(m.group(1)) + self.rv.data[self.index]['file_size'] = m.group(2) + self.rv.data[self.index]['speed'] = m.group(3) + self.rv.data[self.index]['ETA'] = m.group(4) + else: + self.rv.data[self.index]['log'] += f"{msg}\n" + if msg.endswith('has already been downloaded'): + self.rv.data[self.index]['percent'] = 100 + self.rv.data[self.index]['ETA'] = 'This video has alderly been downloaded' + + self.rv.refresh_from_data() + + def warning(self, msg): + self.rv.data[self.index]['log'] += f"[color=ffff00]{msg}[/color]\n" + self.rv.refresh_from_data() + + def error(self, msg): + self.rv.data[self.index]['log'] += f"[color=ff0000]{msg}[/color]\n" + self.rv.refresh_from_data() diff --git a/main.py b/main.py index cbd68ce..36a92ea 100644 --- a/main.py +++ b/main.py @@ -21,6 +21,7 @@ from kivy.uix.scrollview import ScrollView from kivy.utils import platform from kivy.uix.checkbox import CheckBox +from kivy.uix.image import AsyncImage if platform == 'android': from android.storage import primary_external_storage_path @@ -37,9 +38,11 @@ class RV(RecycleView): pass + class ActionBarMain(ActionBar): pass + class LogPopup(Popup): log = StringProperty() index = NumericProperty() @@ -49,13 +52,14 @@ def __init__(self, log, index, **kwargs): self.log = log self.index = index + class FormatSelectPopup(Popup): meta = {} selected_format_id = [] def __init__(self, meta, **kwargs): super(FormatSelectPopup, self).__init__(**kwargs) - formats_sorted = sorted(meta['formats'], key=lambda k:k['format']) + formats_sorted = sorted(meta['formats'], key=lambda k: k['format']) for format in formats_sorted: grid = self.ids.layout grid.add_widget(Label(text=format['format'] + ' ' + format['ext'])) @@ -70,13 +74,27 @@ def on_checkbox_active(self, format_id, instance, value): else: self.selected_format_id.remove(format_id) + class InfoDisplayPopup(Popup): meta = {} def __init__(self, meta, **kwargs): super(InfoDisplayPopup, self).__init__(**kwargs) self.meta = meta - self.ids.info_label.text = meta['description'] + + self.add_to_view(Label(text='[b]'+meta['title']+'[/b]', markup=True)) + + if meta['description']: + self.add_to_view(Label(text=meta['description'])) + + if meta['thumbnails']: + url = meta['thumbnails'][0]['url'] + thumbnail = AsyncImage(source=url) + self.add_to_view(thumbnail) + + def add_to_view(self, widget): + self.ids.view.add_widget(widget) + class DownloadStatusBar(BoxLayout): url = StringProperty('') @@ -107,6 +125,7 @@ def on_log(self, instance, value): if(self.popup is not None and instance.index == self.popup.index): self.popup.log = value + class DownloaderLayout(BoxLayout): popup = None # info display popup @@ -115,8 +134,8 @@ def on_press_button_info(self): try: if not bool(app.meta): with youtube_dl.YoutubeDL(app.ydl_opts) as ydl: - app.meta = ydl.extract_info(app.url, download = False) - + app.meta = ydl.extract_info(app.url, download=False) + self.popup = InfoDisplayPopup(app.meta) self.popup.open() except Exception as inst: @@ -124,28 +143,27 @@ def on_press_button_info(self): def on_format_select_popup_dismiss(self, url, ydl_opts, meta, instance): if instance.selected_format_id: - self.start_download(url, {**ydl_opts, **{'format': ','.join(instance.selected_format_id)}}, meta) + self.start_download( + url, {**ydl_opts, **{'format': ','.join(instance.selected_format_id)}}, meta) def on_press_button_download(self): app = App.get_running_app() - if not bool(app.meta): - with youtube_dl.YoutubeDL(app.ydl_opts) as ydl: - app.meta = ydl.extract_info(app.url, download = False) + try: + if not bool(app.meta): + with youtube_dl.YoutubeDL(app.ydl_opts) as ydl: + app.meta = ydl.extract_info(app.url, download=False) + except Exception as e: + print('Error while trying to extract info: ' + str(e)) + return - # if the format method is set to 'Ask', get the metadata which contains the available formats for this url format_method = app.config.get('general', 'method') if format_method == 'Ask': - try: - if not bool(app.meta): - with youtube_dl.YoutubeDL(app.ydl_opts) as ydl: - app.meta = ydl.extract_info(app.url, download = False) - - self.popup = FormatSelectPopup(app.meta) - callback = partial(self.on_format_select_popup_dismiss, app.url, app.ydl_opts, app.meta) - self.popup.bind(on_dismiss=callback) - self.popup.open() - except Exception as inst: - print('Exception: ' + str(inst)) + self.popup = FormatSelectPopup(app.meta) + callback = partial(self.on_format_select_popup_dismiss, + app.url, app.ydl_opts, app.meta) + self.popup.bind(on_dismiss=callback) + self.popup.open() + else: self.start_download(app.url, app.ydl_opts, app.meta) @@ -170,14 +188,16 @@ def start_download(self, url, ydl_opts, meta): class RootLayout(Label): pass + class StatusIcon(Label): status = NumericProperty(1) + class DownloaderApp(App): meta = DictProperty() ydl_opts = DictProperty() url = StringProperty() - filetmpl = '%(title)s.%(ext)s' + filetmpl = '%(title)s_%(format)s.%(ext)s' def get_output_dir(self): if platform == 'android':