]> jfr.im git - yt-dlp.git/blame - yt_dlp/downloader/__init__.py
[dash,youtube] Download live from start to end (#888)
[yt-dlp.git] / yt_dlp / downloader / __init__.py
CommitLineData
db1f3888
PH
1from __future__ import unicode_literals
2
52a8a1e1 3from ..compat import compat_str
5219cb3e 4from ..utils import (
5 determine_protocol,
dbf5416a 6 NO_DEFAULT
5219cb3e 7)
8
9
96fccc10 10def get_suitable_downloader(info_dict, params={}, default=NO_DEFAULT, protocol=None, to_stdout=False):
dbf5416a 11 info_dict['protocol'] = determine_protocol(info_dict)
5219cb3e 12 info_copy = info_dict.copy()
96fccc10 13 info_copy['to_stdout'] = to_stdout
c111cefa 14
adbc4ec4
THD
15 protocols = (protocol or info_copy['protocol']).split('+')
16 downloaders = [_get_suitable_downloader(info_copy, proto, params, default) for proto in protocols]
17
c111cefa 18 if set(downloaders) == {FFmpegFD} and FFmpegFD.can_merge_formats(info_copy, params):
19 return FFmpegFD
adbc4ec4
THD
20 elif (set(downloaders) == {DashSegmentsFD}
21 and not (to_stdout and len(protocols) > 1)
22 and set(protocols) == {'http_dash_segments_generator'}):
23 return DashSegmentsFD
c111cefa 24 elif len(downloaders) == 1:
25 return downloaders[0]
26 return None
5219cb3e 27
28
dbf5416a 29# Some of these require get_suitable_downloader
3bc2ddcc 30from .common import FileDownloader
5219cb3e 31from .dash import DashSegmentsFD
222516d9 32from .f4m import F4mFD
3bc2ddcc
JMF
33from .hls import HlsFD
34from .http import HttpFD
3bc2ddcc 35from .rtmp import RtmpFD
be24916a 36from .rtsp import RtspFD
b2758123 37from .ism import IsmFD
cdb19aa4 38from .mhtml import MhtmlFD
fb198a8a 39from .niconico import NiconicoDmcFD
e36d50c5 40from .websocket import WebSocketFragmentFD
c60ee3a2 41from .youtube_live_chat import YoutubeLiveChatFD
12b84ac8 42from .external import (
43 get_external_downloader,
44 FFmpegFD,
45)
3bc2ddcc 46
a055469f
PH
47PROTOCOL_MAP = {
48 'rtmp': RtmpFD,
f304da8a 49 'rtmpe': RtmpFD,
0fa9a1e2 50 'rtmp_ffmpeg': FFmpegFD,
12b84ac8 51 'm3u8_native': HlsFD,
52 'm3u8': FFmpegFD,
be24916a 53 'mms': RtspFD,
54 'rtsp': RtspFD,
a055469f 55 'f4m': F4mFD,
423d2be5 56 'http_dash_segments': DashSegmentsFD,
adbc4ec4 57 'http_dash_segments_generator': DashSegmentsFD,
b2758123 58 'ism': IsmFD,
cdb19aa4 59 'mhtml': MhtmlFD,
fb198a8a 60 'niconico_dmc': NiconicoDmcFD,
e36d50c5 61 'websocket_frag': WebSocketFragmentFD,
c60ee3a2 62 'youtube_live_chat': YoutubeLiveChatFD,
63 'youtube_live_chat_replay': YoutubeLiveChatFD,
a055469f 64}
f89197d7 65
a055469f 66
52a8a1e1 67def shorten_protocol_name(proto, simplify=False):
68 short_protocol_names = {
69 'm3u8_native': 'm3u8_n',
0fa9a1e2 70 'rtmp_ffmpeg': 'rtmp_f',
52a8a1e1 71 'http_dash_segments': 'dash',
adbc4ec4 72 'http_dash_segments_generator': 'dash_g',
52a8a1e1 73 'niconico_dmc': 'dmc',
e36d50c5 74 'websocket_frag': 'WSfrag',
52a8a1e1 75 }
76 if simplify:
77 short_protocol_names.update({
78 'https': 'http',
79 'ftps': 'ftp',
80 'm3u8_native': 'm3u8',
adbc4ec4 81 'http_dash_segments_generator': 'dash',
0fa9a1e2 82 'rtmp_ffmpeg': 'rtmp',
52a8a1e1 83 'm3u8_frag_urls': 'm3u8',
84 'dash_frag_urls': 'dash',
85 })
86 return short_protocol_names.get(proto, proto)
87
88
c111cefa 89def _get_suitable_downloader(info_dict, protocol, params, default):
3bc2ddcc 90 """Get the downloader class that can handle the info dict."""
dbf5416a 91 if default is NO_DEFAULT:
92 default = HttpFD
a055469f 93
6ae27bed 94 # if (info_dict.get('start_time') or info_dict.get('end_time')) and not info_dict.get('requested_formats') and FFmpegFD.can_download(info_dict):
da1973a0 95 # return FFmpegFD
12b84ac8 96
c111cefa 97 info_dict['protocol'] = protocol
52a8a1e1 98 downloaders = params.get('external_downloader')
99 external_downloader = (
68379de5 100 downloaders if isinstance(downloaders, compat_str) or downloaders is None
52a8a1e1 101 else downloaders.get(shorten_protocol_name(protocol, True), downloaders.get('default')))
52a8a1e1 102
96fccc10 103 if external_downloader is None:
104 if info_dict['to_stdout'] and FFmpegFD.can_merge_formats(info_dict, params):
105 return FFmpegFD
106 elif external_downloader.lower() != 'native':
222516d9 107 ed = get_external_downloader(external_downloader)
7f7de7f9 108 if ed.can_download(info_dict, external_downloader):
222516d9
PH
109 return ed
110
6251555f 111 if protocol == 'http_dash_segments':
45842107 112 if info_dict.get('is_live') and (external_downloader or '').lower() != 'native':
6251555f 113 return FFmpegFD
114
72e1fe96 115 if protocol in ('m3u8', 'm3u8_native'):
5219cb3e 116 if info_dict.get('is_live'):
117 return FFmpegFD
96fccc10 118 elif (external_downloader or '').lower() == 'native':
52a8a1e1 119 return HlsFD
96fccc10 120 elif get_suitable_downloader(
121 info_dict, params, None, protocol='m3u8_frag_urls', to_stdout=info_dict['to_stdout']):
5219cb3e 122 return HlsFD
123 elif params.get('hls_prefer_native') is True:
124 return HlsFD
125 elif params.get('hls_prefer_native') is False:
126 return FFmpegFD
bf09af3a 127
5219cb3e 128 return PROTOCOL_MAP.get(protocol, default)
a055469f 129
14d4e90e
PH
130
131__all__ = [
14d4e90e 132 'FileDownloader',
52a8a1e1 133 'get_suitable_downloader',
134 'shorten_protocol_name',
14d4e90e 135]