Просмотр исходного кода

[downloader/fragment] HLS download can continue without first fragment

Closes #5274
pukkandan 2 лет назад
Родитель
Сommit
814bba3933

+ 1 - 1
yt_dlp/downloader/dash.py

@@ -51,7 +51,7 @@ class DashSegmentsFD(FragmentFD):
 
             args.append([ctx, fragments_to_download, fmt])
 
-        return self.download_and_append_fragments_multiple(*args)
+        return self.download_and_append_fragments_multiple(*args, is_fatal=lambda idx: idx == 0)
 
     def _resolve_fragments(self, fragments, ctx):
         fragments = fragments(ctx) if callable(fragments) else fragments

+ 1 - 3
yt_dlp/downloader/f4m.py

@@ -424,6 +424,4 @@ class F4mFD(FragmentFD):
                     msg = 'Missed %d fragments' % (fragments_list[0][1] - (frag_i + 1))
                     self.report_warning(msg)
 
-        self._finish_frag_download(ctx, info_dict)
-
-        return True
+        return self._finish_frag_download(ctx, info_dict)

+ 25 - 24
yt_dlp/downloader/fragment.py

@@ -295,16 +295,23 @@ class FragmentFD(FileDownloader):
                 self.try_remove(ytdl_filename)
         elapsed = time.time() - ctx['started']
 
-        if ctx['tmpfilename'] == '-':
-            downloaded_bytes = ctx['complete_frags_downloaded_bytes']
+        to_file = ctx['tmpfilename'] != '-'
+        if to_file:
+            downloaded_bytes = os.path.getsize(encodeFilename(ctx['tmpfilename']))
         else:
+            downloaded_bytes = ctx['complete_frags_downloaded_bytes']
+
+        if not downloaded_bytes:
+            if to_file:
+                self.try_remove(ctx['tmpfilename'])
+            self.report_error('The downloaded file is empty')
+            return False
+        elif to_file:
             self.try_rename(ctx['tmpfilename'], ctx['filename'])
-            if self.params.get('updatetime', True):
-                filetime = ctx.get('fragment_filetime')
-                if filetime:
-                    with contextlib.suppress(Exception):
-                        os.utime(ctx['filename'], (time.time(), filetime))
-            downloaded_bytes = os.path.getsize(encodeFilename(ctx['filename']))
+            filetime = ctx.get('fragment_filetime')
+            if self.params.get('updatetime', True) and filetime:
+                with contextlib.suppress(Exception):
+                    os.utime(ctx['filename'], (time.time(), filetime))
 
         self._hook_progress({
             'downloaded_bytes': downloaded_bytes,
@@ -316,6 +323,7 @@ class FragmentFD(FileDownloader):
             'max_progress': ctx.get('max_progress'),
             'progress_idx': ctx.get('progress_idx'),
         }, info_dict)
+        return True
 
     def _prepare_external_frag_download(self, ctx):
         if 'live' not in ctx:
@@ -362,7 +370,7 @@ class FragmentFD(FileDownloader):
 
         return decrypt_fragment
 
-    def download_and_append_fragments_multiple(self, *args, pack_func=None, finish_func=None):
+    def download_and_append_fragments_multiple(self, *args, **kwargs):
         '''
         @params (ctx1, fragments1, info_dict1), (ctx2, fragments2, info_dict2), ...
                 all args must be either tuple or list
@@ -370,7 +378,7 @@ class FragmentFD(FileDownloader):
         interrupt_trigger = [True]
         max_progress = len(args)
         if max_progress == 1:
-            return self.download_and_append_fragments(*args[0], pack_func=pack_func, finish_func=finish_func)
+            return self.download_and_append_fragments(*args[0], **kwargs)
         max_workers = self.params.get('concurrent_fragment_downloads', 1)
         if max_progress > 1:
             self._prepare_multiline_status(max_progress)
@@ -380,8 +388,7 @@ class FragmentFD(FileDownloader):
             ctx['max_progress'] = max_progress
             ctx['progress_idx'] = idx
             return self.download_and_append_fragments(
-                ctx, fragments, info_dict, pack_func=pack_func, finish_func=finish_func,
-                tpe=tpe, interrupt_trigger=interrupt_trigger)
+                ctx, fragments, info_dict, **kwargs, tpe=tpe, interrupt_trigger=interrupt_trigger)
 
         class FTPE(concurrent.futures.ThreadPoolExecutor):
             # has to stop this or it's going to wait on the worker thread itself
@@ -428,17 +435,12 @@ class FragmentFD(FileDownloader):
         return result
 
     def download_and_append_fragments(
-            self, ctx, fragments, info_dict, *, pack_func=None, finish_func=None,
-            tpe=None, interrupt_trigger=None):
-        if not interrupt_trigger:
-            interrupt_trigger = (True, )
-
-        is_fatal = (
-            ((lambda _: False) if info_dict.get('is_live') else (lambda idx: idx == 0))
-            if self.params.get('skip_unavailable_fragments', True) else (lambda _: True))
+            self, ctx, fragments, info_dict, *, is_fatal=(lambda idx: False),
+            pack_func=(lambda content, idx: content), finish_func=None,
+            tpe=None, interrupt_trigger=(True, )):
 
-        if not pack_func:
-            pack_func = lambda frag_content, _: frag_content
+        if not self.params.get('skip_unavailable_fragments', True):
+            is_fatal = lambda _: True
 
         def download_fragment(fragment, ctx):
             if not interrupt_trigger[0]:
@@ -527,5 +529,4 @@ class FragmentFD(FileDownloader):
         if finish_func is not None:
             ctx['dest_stream'].write(finish_func())
             ctx['dest_stream'].flush()
-        self._finish_frag_download(ctx, info_dict)
-        return True
+        return self._finish_frag_download(ctx, info_dict)

+ 1 - 2
yt_dlp/downloader/ism.py

@@ -280,5 +280,4 @@ class IsmFD(FragmentFD):
                     return False
                 self.report_skip_fragment(frag_index)
 
-        self._finish_frag_download(ctx, info_dict)
-        return True
+        return self._finish_frag_download(ctx, info_dict)

+ 1 - 2
yt_dlp/downloader/mhtml.py

@@ -186,5 +186,4 @@ body > figure > img {
 
         ctx['dest_stream'].write(
             b'--%b--\r\n\r\n' % frag_boundary.encode('us-ascii'))
-        self._finish_frag_download(ctx, info_dict)
-        return True
+        return self._finish_frag_download(ctx, info_dict)

+ 1 - 2
yt_dlp/downloader/youtube_live_chat.py

@@ -191,8 +191,7 @@ class YoutubeLiveChatFD(FragmentFD):
             if test:
                 break
 
-        self._finish_frag_download(ctx, info_dict)
-        return True
+        return self._finish_frag_download(ctx, info_dict)
 
     @staticmethod
     def parse_live_timestamp(action):