diff --git a/README.md b/README.md index 6761e8c6c5..a9c074c2c4 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,6 @@ The following provide support for impersonating browser requests. This may be re ### Deprecated * [**rtmpdump**](http://rtmpdump.mplayerhq.hu) - For downloading `rtmp` streams. ffmpeg can be used instead with `--downloader ffmpeg`. Licensed under [GPLv2+](http://rtmpdump.mplayerhq.hu) -* [**mplayer**](http://mplayerhq.hu/design7/info.html) or [**mpv**](https://mpv.io) - For downloading `rstp`/`mms` streams. ffmpeg can be used instead with `--downloader ffmpeg`. Licensed under [GPLv2+](https://github.com/mpv-player/mpv/blob/master/Copyright) To use or redistribute the dependencies, you must agree to their respective licensing terms. @@ -625,16 +624,16 @@ Tip: Use `CTRL`+`F` (or `Command`+`F`) to search by keywords "*10:15-inf" --download-sections "intro" --downloader [PROTO:]NAME Name or path of the external downloader to use (optionally) prefixed by the protocols - (http, ftp, m3u8, dash, rstp, rtmp, mms) to - use it for. Currently supports native, - aria2c, axel, curl, ffmpeg, httpie, wget. - You can use this option multiple times to - set different downloaders for different - protocols. E.g. --downloader aria2c - --downloader "dash,m3u8:native" will use - aria2c for http/ftp downloads, and the - native downloader for dash/m3u8 downloads - (Alias: --external-downloader) + (http, ftp, m3u8, dash, rtmp) to use it for. + Currently supports native, aria2c, axel, + curl, ffmpeg, httpie, wget. You can use this + option multiple times to set different + downloaders for different protocols. E.g. + --downloader aria2c --downloader + "dash,m3u8:native" will use aria2c for + http/ftp downloads, and the native + downloader for dash/m3u8 downloads (Alias: + --external-downloader) --downloader-args NAME:ARGS Give these arguments to the external downloader. Specify the downloader name and the arguments separated by a colon ":". For @@ -1587,7 +1586,7 @@ Also filtering work for comparisons `=` (equals), `^=` (starts with), `$=` (ends - `acodec`: Name of the audio codec in use - `vcodec`: Name of the video codec in use - `container`: Name of the container format - - `protocol`: The protocol that will be used for the actual download, lower-case (`http`, `https`, `rtsp`, `rtmp`, `rtmpe`, `mms`, `f4m`, `ism`, `http_dash_segments`, `m3u8`, or `m3u8_native`) + - `protocol`: The protocol that will be used for the actual download, lower-case (`http`, `https`, `rtmp`, `rtmpe`, `f4m`, `ism`, `http_dash_segments`, `m3u8`, or `m3u8_native`) - `language`: Language code - `dynamic_range`: The dynamic range of the video - `format_id`: A short description of the format @@ -1615,7 +1614,7 @@ The available fields are: - `lang`: The language preference as determined by the extractor (e.g. original language preferred over audio description) - `quality`: The quality of the format - `source`: The preference of the source - - `proto`: Protocol used for download (`https`/`ftps` > `http`/`ftp` > `m3u8_native`/`m3u8` > `http_dash_segments`> `websocket_frag` > `mms`/`rtsp` > `f4f`/`f4m`) + - `proto`: Protocol used for download (`https`/`ftps` > `http`/`ftp` > `m3u8_native`/`m3u8` > `http_dash_segments`> `websocket_frag` > `f4f`/`f4m`) - `vcodec`: Video Codec (`av01` > `vp9.2` > `vp9` > `h265` > `h264` > `vp8` > `h263` > `theora` > other) - `acodec`: Audio Codec (`flac`/`alac` > `wav`/`aiff` > `opus` > `vorbis` > `aac` > `mp4a` > `mp3` > `ac4` > `eac3` > `ac3` > `dts` > other) - `codec`: Equivalent to `vcodec,acodec` diff --git a/test/test_utils.py b/test/test_utils.py index 14dcdd9cb6..429145ba6c 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -689,8 +689,6 @@ class TestUtil(unittest.TestCase): self.assertEqual(url_or_none('//foo.de'), '//foo.de') self.assertEqual(url_or_none('s3://foo.de'), None) self.assertEqual(url_or_none('rtmpte://foo.de'), 'rtmpte://foo.de') - self.assertEqual(url_or_none('mms://foo.de'), 'mms://foo.de') - self.assertEqual(url_or_none('rtspu://foo.de'), 'rtspu://foo.de') self.assertEqual(url_or_none('ftps://foo.de'), 'ftps://foo.de') self.assertEqual(url_or_none('ws://foo.de'), 'ws://foo.de') self.assertEqual(url_or_none('wss://foo.de'), 'wss://foo.de') diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 5040fc0e17..70c14be8b3 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -480,7 +480,7 @@ class YoutubeDL: geo_bypass_country external_downloader: A dictionary of protocol keys and the executable of the external downloader to use for it. The allowed protocols - are default|http|ftp|m3u8|dash|rtsp|rtmp|mms. + are default|http|ftp|m3u8|dash|rtmp. Set the value to 'native' to use the native downloader compat_opts: Compatibility options. See "Differences in default behavior". The following options do not work when used through the API: diff --git a/yt_dlp/downloader/__init__.py b/yt_dlp/downloader/__init__.py index ff805738d6..6771e20f3c 100644 --- a/yt_dlp/downloader/__init__.py +++ b/yt_dlp/downloader/__init__.py @@ -32,7 +32,6 @@ from .ism import IsmFD from .mhtml import MhtmlFD from .niconico import NiconicoLiveFD from .rtmp import RtmpFD -from .rtsp import RtspFD from .websocket import WebSocketFragmentFD from .youtube_live_chat import YoutubeLiveChatFD from .bunnycdn import BunnyCdnFD @@ -44,8 +43,6 @@ PROTOCOL_MAP = { 'rtmp_ffmpeg': FFmpegFD, 'm3u8_native': HlsFD, 'm3u8': FFmpegFD, - 'mms': RtspFD, - 'rtsp': RtspFD, 'f4m': F4mFD, 'http_dash_segments': DashSegmentsFD, 'http_dash_segments_generator': DashSegmentsFD, diff --git a/yt_dlp/downloader/external.py b/yt_dlp/downloader/external.py index 663728abc3..b2aaef5d4c 100644 --- a/yt_dlp/downloader/external.py +++ b/yt_dlp/downloader/external.py @@ -375,7 +375,7 @@ class HttpieFD(ExternalFD): class FFmpegFD(ExternalFD): - SUPPORTED_PROTOCOLS = ('http', 'https', 'ftp', 'ftps', 'm3u8', 'm3u8_native', 'rtsp', 'rtmp', 'rtmp_ffmpeg', 'mms', 'http_dash_segments') + SUPPORTED_PROTOCOLS = ('http', 'https', 'ftp', 'ftps', 'm3u8', 'm3u8_native', 'rtmp', 'rtmp_ffmpeg', 'http_dash_segments') SUPPORTED_FEATURES = (Features.TO_STDOUT, Features.MULTIPLE_FORMATS) @classmethod diff --git a/yt_dlp/downloader/rtsp.py b/yt_dlp/downloader/rtsp.py deleted file mode 100644 index b4b0be7e6e..0000000000 --- a/yt_dlp/downloader/rtsp.py +++ /dev/null @@ -1,42 +0,0 @@ -import os -import subprocess - -from .common import FileDownloader -from ..utils import check_executable - - -class RtspFD(FileDownloader): - def real_download(self, filename, info_dict): - url = info_dict['url'] - self.report_destination(filename) - tmpfilename = self.temp_name(filename) - - if check_executable('mplayer', ['-h']): - args = [ - 'mplayer', '-really-quiet', '-vo', 'null', '-vc', 'dummy', - '-dumpstream', '-dumpfile', tmpfilename, url] - elif check_executable('mpv', ['-h']): - args = [ - 'mpv', '-really-quiet', '--vo=null', '--stream-dump=' + tmpfilename, url] - else: - self.report_error('MMS or RTSP download detected but neither "mplayer" nor "mpv" could be run. Please install one') - return False - - self._debug_cmd(args) - - retval = subprocess.call(args) - if retval == 0: - fsize = os.path.getsize(tmpfilename) - self.to_screen(f'\r[{args[0]}] {fsize} bytes') - self.try_rename(tmpfilename, filename) - self._hook_progress({ - 'downloaded_bytes': fsize, - 'total_bytes': fsize, - 'filename': filename, - 'status': 'finished', - }, info_dict) - return True - else: - self.to_stderr('\n') - self.report_error('%s exited with code %d' % (args[0], retval)) - return False diff --git a/yt_dlp/extractor/_extractors.py b/yt_dlp/extractor/_extractors.py index 94c4e5fabc..1a89be2236 100644 --- a/yt_dlp/extractor/_extractors.py +++ b/yt_dlp/extractor/_extractors.py @@ -359,7 +359,6 @@ from .commonmistakes import ( UnicodeBOMIE, ) from .commonprotocols import ( - MmsIE, RtmpIE, ViewSourceIE, ) diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index 51c63dc546..732f8b140e 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -3542,7 +3542,7 @@ class InfoExtractor: query = urllib.parse.urlparse(url).query url = re.sub(r'/(?:manifest|playlist|jwplayer)\.(?:m3u8|f4m|mpd|smil)', '', url) mobj = re.search( - r'(?:(?:http|rtmp|rtsp)(?Ps)?:)?(?P//[^?]+)', url) + r'(?:(?:http|rtmp)(?Ps)?:)?(?P//[^?]+)', url) url_base = mobj.group('url') http_base_url = '{}{}:{}'.format('http', mobj.group('s') or '', url_base) formats = [] @@ -3567,28 +3567,16 @@ class InfoExtractor: video_id, mpd_id='dash', fatal=False)) if re.search(r'(?:/smil:|\.smil)', url_base): if 'smil' not in skip_protocols: - rtmp_formats = self._extract_smil_formats( + formats.extend(self._extract_smil_formats( manifest_url('jwplayer.smil'), - video_id, fatal=False) - for rtmp_format in rtmp_formats: - rtsp_format = rtmp_format.copy() - rtsp_format['url'] = '{}/{}'.format(rtmp_format['url'], rtmp_format['play_path']) - del rtsp_format['play_path'] - del rtsp_format['ext'] - rtsp_format.update({ - 'url': rtsp_format['url'].replace('rtmp://', 'rtsp://'), - 'format_id': rtmp_format['format_id'].replace('rtmp', 'rtsp'), - 'protocol': 'rtsp', - }) - formats.extend([rtmp_format, rtsp_format]) + video_id, fatal=False)) else: - for protocol in ('rtmp', 'rtsp'): - if protocol not in skip_protocols: - formats.append({ - 'url': f'{protocol}:{url_base}', - 'format_id': protocol, - 'protocol': protocol, - }) + if 'rtmp' not in skip_protocols: + formats.append({ + 'url': f'rtmp:{url_base}', + 'format_id': 'rtmp', + 'protocol': 'rtmp', + }) return formats def _find_jwplayer_data(self, webpage, video_id=None, transform_source=js_to_json): diff --git a/yt_dlp/extractor/commonprotocols.py b/yt_dlp/extractor/commonprotocols.py index 6d9ba0d81c..cbd72b0946 100644 --- a/yt_dlp/extractor/commonprotocols.py +++ b/yt_dlp/extractor/commonprotocols.py @@ -29,34 +29,6 @@ class RtmpIE(InfoExtractor): } -class MmsIE(InfoExtractor): - IE_DESC = False # Do not list - _VALID_URL = r'(?i)mms://.+' - - _TEST = { - # Direct MMS link - 'url': 'mms://kentro.kaist.ac.kr/200907/MilesReid(0709).wmv', - 'info_dict': { - 'id': 'MilesReid(0709)', - 'ext': 'wmv', - 'title': 'MilesReid(0709)', - }, - 'params': { - 'skip_download': True, # rtsp downloads, requiring mplayer or mpv - }, - } - - def _real_extract(self, url): - video_id = self._generic_id(url) - title = self._generic_title(url) - - return { - 'id': video_id, - 'title': title, - 'url': url, - } - - class ViewSourceIE(InfoExtractor): IE_DESC = False _VALID_URL = r'view-source:(?P.+)' diff --git a/yt_dlp/extractor/filmon.py b/yt_dlp/extractor/filmon.py index af1de7ac83..bbce7b3c44 100644 --- a/yt_dlp/extractor/filmon.py +++ b/yt_dlp/extractor/filmon.py @@ -138,7 +138,7 @@ class FilmOnChannelIE(InfoExtractor): continue if not is_live: formats.extend(self._extract_wowza_formats( - stream_url, channel_id, skip_protocols=['dash', 'rtmp', 'rtsp'])) + stream_url, channel_id, skip_protocols=['dash', 'rtmp'])) continue quality = stream.get('quality') formats.append({ diff --git a/yt_dlp/extractor/mangomolo.py b/yt_dlp/extractor/mangomolo.py index 2231f71e8f..de62bef80e 100644 --- a/yt_dlp/extractor/mangomolo.py +++ b/yt_dlp/extractor/mangomolo.py @@ -37,10 +37,7 @@ class MangomoloBaseIE(InfoExtractor): m3u8_entry_protocol = 'm3u8' if self._IS_LIVE else 'm3u8_native' format_url = self._html_search_regex( - [ - r'(?:file|src)\s*:\s*"(https?://[^"]+?/playlist\.m3u8)', - r']+href="(rtsp://[^"]+)"', - ], webpage, 'format url') + r'(?:file|src)\s*:\s*"(https?://[^"]+?/playlist\.m3u8)', webpage, 'format url') formats = self._extract_wowza_formats( format_url, page_id, m3u8_entry_protocol, ['smil']) diff --git a/yt_dlp/options.py b/yt_dlp/options.py index cd5d5b613f..b46dba20f2 100644 --- a/yt_dlp/options.py +++ b/yt_dlp/options.py @@ -1139,12 +1139,12 @@ def create_parser(): dest='external_downloader', metavar='[PROTO:]NAME', default={}, type='str', action='callback', callback=_dict_from_options_callback, callback_kwargs={ - 'allowed_keys': 'http|ftp|m3u8|dash|rtsp|rtmp|mms', + 'allowed_keys': 'http|ftp|m3u8|dash|rtmp', 'default_key': 'default', 'process': str.strip, }, help=( 'Name or path of the external downloader to use (optionally) prefixed by ' - 'the protocols (http, ftp, m3u8, dash, rstp, rtmp, mms) to use it for. ' + 'the protocols (http, ftp, m3u8, dash, rtmp) to use it for. ' f'Currently supports native, {", ".join(sorted(list_external_downloaders()))}. ' 'You can use this option multiple times to set different downloaders for different protocols. ' 'E.g. --downloader aria2c --downloader "dash,m3u8:native" will use ' diff --git a/yt_dlp/utils/_utils.py b/yt_dlp/utils/_utils.py index ede0bc93a8..856a565053 100644 --- a/yt_dlp/utils/_utils.py +++ b/yt_dlp/utils/_utils.py @@ -2076,7 +2076,7 @@ def url_or_none(url): if not url or not isinstance(url, str): return None url = url.strip() - return url if re.match(r'(?:(?:https?|rt(?:m(?:pt?[es]?|fp)|sp[su]?)|mms|ftps?|wss?):)?//', url) else None + return url if re.match(r'(?:(?:https?|rtm(?:pt?[es]?|fp)|ftps?|wss?):)?//', url) else None def strftime_or_none(timestamp, date_format='%Y%m%d', default=None): @@ -3195,10 +3195,6 @@ def determine_protocol(info_dict): url = sanitize_url(info_dict['url']) if url.startswith('rtmp'): return 'rtmp' - elif url.startswith('mms'): - return 'mms' - elif url.startswith('rtsp'): - return 'rtsp' ext = determine_ext(url) if ext == 'm3u8': @@ -5373,7 +5369,7 @@ class FormatSorter: 'hdr': {'type': 'ordered', 'regex': True, 'field': 'dynamic_range', 'order': ['dv', '(hdr)?12', r'(hdr)?10\+', '(hdr)?10', 'hlg', '', 'sdr', None]}, 'proto': {'type': 'ordered', 'regex': True, 'field': 'protocol', - 'order': ['(ht|f)tps', '(ht|f)tp$', 'm3u8.*', '.*dash', 'websocket_frag', 'rtmpe?', '', 'mms|rtsp', 'ws|websocket', 'f4']}, + 'order': ['(ht|f)tps', '(ht|f)tp$', 'm3u8.*', '.*dash', 'websocket_frag', 'rtmpe?', '', 'ws|websocket', 'f4']}, 'vext': {'type': 'ordered', 'field': 'video_ext', 'order': ('mp4', 'mov', 'webm', 'flv', '', 'none'), 'order_free': ('webm', 'mp4', 'mov', 'flv', '', 'none')},