__init__.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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, NiconicoLiveFD
  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. 'niconico_live': NiconicoLiveFD,
  47. 'fc2_live': FC2LiveFD,
  48. 'websocket_frag': WebSocketFragmentFD,
  49. 'youtube_live_chat': YoutubeLiveChatFD,
  50. 'youtube_live_chat_replay': YoutubeLiveChatFD,
  51. }
  52. def shorten_protocol_name(proto, simplify=False):
  53. short_protocol_names = {
  54. 'm3u8_native': 'm3u8',
  55. 'm3u8': 'm3u8F',
  56. 'rtmp_ffmpeg': 'rtmpF',
  57. 'http_dash_segments': 'dash',
  58. 'http_dash_segments_generator': 'dashG',
  59. 'niconico_dmc': 'dmc',
  60. 'websocket_frag': 'WSfrag',
  61. }
  62. if simplify:
  63. short_protocol_names.update({
  64. 'https': 'http',
  65. 'ftps': 'ftp',
  66. 'm3u8': 'm3u8', # Reverse above m3u8 mapping
  67. 'm3u8_native': 'm3u8',
  68. 'http_dash_segments_generator': 'dash',
  69. 'rtmp_ffmpeg': 'rtmp',
  70. 'm3u8_frag_urls': 'm3u8',
  71. 'dash_frag_urls': 'dash',
  72. })
  73. return short_protocol_names.get(proto, proto)
  74. def _get_suitable_downloader(info_dict, protocol, params, default):
  75. """Get the downloader class that can handle the info dict."""
  76. if default is NO_DEFAULT:
  77. default = HttpFD
  78. if (info_dict.get('section_start') or info_dict.get('section_end')) and FFmpegFD.can_download(info_dict):
  79. return FFmpegFD
  80. info_dict['protocol'] = protocol
  81. downloaders = params.get('external_downloader')
  82. external_downloader = (
  83. downloaders if isinstance(downloaders, str) or downloaders is None
  84. else downloaders.get(shorten_protocol_name(protocol, True), downloaders.get('default')))
  85. if external_downloader is None:
  86. if info_dict['to_stdout'] and FFmpegFD.can_merge_formats(info_dict, params):
  87. return FFmpegFD
  88. elif external_downloader.lower() != 'native':
  89. ed = get_external_downloader(external_downloader)
  90. if ed.can_download(info_dict, external_downloader):
  91. return ed
  92. if protocol == 'http_dash_segments':
  93. if info_dict.get('is_live') and (external_downloader or '').lower() != 'native':
  94. return FFmpegFD
  95. if protocol in ('m3u8', 'm3u8_native'):
  96. if info_dict.get('is_live'):
  97. return FFmpegFD
  98. elif (external_downloader or '').lower() == 'native':
  99. return HlsFD
  100. elif protocol == 'm3u8_native' and get_suitable_downloader(
  101. info_dict, params, None, protocol='m3u8_frag_urls', to_stdout=info_dict['to_stdout']):
  102. return HlsFD
  103. elif params.get('hls_prefer_native') is True:
  104. return HlsFD
  105. elif params.get('hls_prefer_native') is False:
  106. return FFmpegFD
  107. return PROTOCOL_MAP.get(protocol, default)
  108. __all__ = [
  109. 'FileDownloader',
  110. 'get_suitable_downloader',
  111. 'shorten_protocol_name',
  112. ]