]> jfr.im git - yt-dlp.git/blob - yt_dlp/downloader/__init__.py
a7dc6c9d0ece40d4683bc8686e94bce0f9a3845d
[yt-dlp.git] / yt_dlp / downloader / __init__.py
1 from ..utils import NO_DEFAULT, determine_protocol
2
3
4 def get_suitable_downloader(info_dict, params={}, default=NO_DEFAULT, protocol=None, to_stdout=False):
5 info_dict['protocol'] = determine_protocol(info_dict)
6 info_copy = info_dict.copy()
7 info_copy['to_stdout'] = to_stdout
8
9 protocols = (protocol or info_copy['protocol']).split('+')
10 downloaders = [_get_suitable_downloader(info_copy, proto, params, default) for proto in protocols]
11
12 if set(downloaders) == {FFmpegFD} and FFmpegFD.can_merge_formats(info_copy, params):
13 return FFmpegFD
14 elif (set(downloaders) == {DashSegmentsFD}
15 and not (to_stdout and len(protocols) > 1)
16 and set(protocols) == {'http_dash_segments_generator'}):
17 return DashSegmentsFD
18 elif len(downloaders) == 1:
19 return downloaders[0]
20 return None
21
22
23 # Some of these require get_suitable_downloader
24 from .common import FileDownloader
25 from .dash import DashSegmentsFD
26 from .external import FFmpegFD, get_external_downloader
27 from .f4m import F4mFD
28 from .fc2 import FC2LiveFD
29 from .hls import HlsFD
30 from .http import HttpFD
31 from .ism import IsmFD
32 from .mhtml import MhtmlFD
33 from .niconico import NiconicoDmcFD
34 from .rtmp import RtmpFD
35 from .rtsp import RtspFD
36 from .websocket import WebSocketFragmentFD
37 from .youtube_live_chat import YoutubeLiveChatFD
38
39 PROTOCOL_MAP = {
40 'rtmp': RtmpFD,
41 'rtmpe': RtmpFD,
42 'rtmp_ffmpeg': FFmpegFD,
43 'm3u8_native': HlsFD,
44 'm3u8': FFmpegFD,
45 'mms': RtspFD,
46 'rtsp': RtspFD,
47 'f4m': F4mFD,
48 'http_dash_segments': DashSegmentsFD,
49 'http_dash_segments_generator': DashSegmentsFD,
50 'ism': IsmFD,
51 'mhtml': MhtmlFD,
52 'niconico_dmc': NiconicoDmcFD,
53 'fc2_live': FC2LiveFD,
54 'websocket_frag': WebSocketFragmentFD,
55 'youtube_live_chat': YoutubeLiveChatFD,
56 'youtube_live_chat_replay': YoutubeLiveChatFD,
57 }
58
59
60 def shorten_protocol_name(proto, simplify=False):
61 short_protocol_names = {
62 'm3u8_native': 'm3u8_n',
63 'rtmp_ffmpeg': 'rtmp_f',
64 'http_dash_segments': 'dash',
65 'http_dash_segments_generator': 'dash_g',
66 'niconico_dmc': 'dmc',
67 'websocket_frag': 'WSfrag',
68 }
69 if simplify:
70 short_protocol_names.update({
71 'https': 'http',
72 'ftps': 'ftp',
73 'm3u8_native': 'm3u8',
74 'http_dash_segments_generator': 'dash',
75 'rtmp_ffmpeg': 'rtmp',
76 'm3u8_frag_urls': 'm3u8',
77 'dash_frag_urls': 'dash',
78 })
79 return short_protocol_names.get(proto, proto)
80
81
82 def _get_suitable_downloader(info_dict, protocol, params, default):
83 """Get the downloader class that can handle the info dict."""
84 if default is NO_DEFAULT:
85 default = HttpFD
86
87 if (info_dict.get('section_start') or info_dict.get('section_end')) and FFmpegFD.can_download(info_dict):
88 return FFmpegFD
89
90 info_dict['protocol'] = protocol
91 downloaders = params.get('external_downloader')
92 external_downloader = (
93 downloaders if isinstance(downloaders, str) or downloaders is None
94 else downloaders.get(shorten_protocol_name(protocol, True), downloaders.get('default')))
95
96 if external_downloader is None:
97 if info_dict['to_stdout'] and FFmpegFD.can_merge_formats(info_dict, params):
98 return FFmpegFD
99 elif external_downloader.lower() != 'native':
100 ed = get_external_downloader(external_downloader)
101 if ed.can_download(info_dict, external_downloader):
102 return ed
103
104 if protocol == 'http_dash_segments':
105 if info_dict.get('is_live') and (external_downloader or '').lower() != 'native':
106 return FFmpegFD
107
108 if protocol in ('m3u8', 'm3u8_native'):
109 if info_dict.get('is_live'):
110 return FFmpegFD
111 elif (external_downloader or '').lower() == 'native':
112 return HlsFD
113 elif protocol == 'm3u8_native' and get_suitable_downloader(
114 info_dict, params, None, protocol='m3u8_frag_urls', to_stdout=info_dict['to_stdout']):
115 return HlsFD
116 elif params.get('hls_prefer_native') is True:
117 return HlsFD
118 elif params.get('hls_prefer_native') is False:
119 return FFmpegFD
120
121 return PROTOCOL_MAP.get(protocol, default)
122
123
124 __all__ = [
125 'FileDownloader',
126 'get_suitable_downloader',
127 'shorten_protocol_name',
128 ]