]> jfr.im git - yt-dlp.git/blob - yt_dlp/downloader/__init__.py
[cleanup] Misc cleanup
[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',
63 'm3u8': 'm3u8F',
64 'rtmp_ffmpeg': 'rtmpF',
65 'http_dash_segments': 'dash',
66 'http_dash_segments_generator': 'dashG',
67 'niconico_dmc': 'dmc',
68 'websocket_frag': 'WSfrag',
69 }
70 if simplify:
71 short_protocol_names.update({
72 'https': 'http',
73 'ftps': 'ftp',
74 'm3u8': 'm3u8', # Reverse above m3u8 mapping
75 'm3u8_native': 'm3u8',
76 'http_dash_segments_generator': 'dash',
77 'rtmp_ffmpeg': 'rtmp',
78 'm3u8_frag_urls': 'm3u8',
79 'dash_frag_urls': 'dash',
80 })
81 return short_protocol_names.get(proto, proto)
82
83
84 def _get_suitable_downloader(info_dict, protocol, params, default):
85 """Get the downloader class that can handle the info dict."""
86 if default is NO_DEFAULT:
87 default = HttpFD
88
89 if (info_dict.get('section_start') or info_dict.get('section_end')) and FFmpegFD.can_download(info_dict):
90 return FFmpegFD
91
92 info_dict['protocol'] = protocol
93 downloaders = params.get('external_downloader')
94 external_downloader = (
95 downloaders if isinstance(downloaders, str) or downloaders is None
96 else downloaders.get(shorten_protocol_name(protocol, True), downloaders.get('default')))
97
98 if external_downloader is None:
99 if info_dict['to_stdout'] and FFmpegFD.can_merge_formats(info_dict, params):
100 return FFmpegFD
101 elif external_downloader.lower() != 'native':
102 ed = get_external_downloader(external_downloader)
103 if ed.can_download(info_dict, external_downloader):
104 return ed
105
106 if protocol == 'http_dash_segments':
107 if info_dict.get('is_live') and (external_downloader or '').lower() != 'native':
108 return FFmpegFD
109
110 if protocol in ('m3u8', 'm3u8_native'):
111 if info_dict.get('is_live'):
112 return FFmpegFD
113 elif (external_downloader or '').lower() == 'native':
114 return HlsFD
115 elif protocol == 'm3u8_native' and get_suitable_downloader(
116 info_dict, params, None, protocol='m3u8_frag_urls', to_stdout=info_dict['to_stdout']):
117 return HlsFD
118 elif params.get('hls_prefer_native') is True:
119 return HlsFD
120 elif params.get('hls_prefer_native') is False:
121 return FFmpegFD
122
123 return PROTOCOL_MAP.get(protocol, default)
124
125
126 __all__ = [
127 'FileDownloader',
128 'get_suitable_downloader',
129 'shorten_protocol_name',
130 ]