__init__.py 4.3 KB

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