mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-11-04 00:25:15 +00:00 
			
		
		
		
	[extractor/slideslive] Fix slides and chapters/duration (#6024)
* Fix slides/thumbnails extraction * Extract duration to fix issues w/ `--embed-chapters`, `--split-chapters` * Add `InfoExtractor._extract_mpd_vod_duration` method * Expand applicability of `InfoExtractor._parse_m3u8_vod_duration` method Authored by: bashonly
This commit is contained in:
		@@ -2180,13 +2180,23 @@ class InfoExtractor:
 | 
				
			|||||||
        return self._parse_m3u8_vod_duration(m3u8_vod or '', video_id)
 | 
					        return self._parse_m3u8_vod_duration(m3u8_vod or '', video_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _parse_m3u8_vod_duration(self, m3u8_vod, video_id):
 | 
					    def _parse_m3u8_vod_duration(self, m3u8_vod, video_id):
 | 
				
			||||||
        if '#EXT-X-PLAYLIST-TYPE:VOD' not in m3u8_vod:
 | 
					        if '#EXT-X-ENDLIST' not in m3u8_vod:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return int(sum(
 | 
					        return int(sum(
 | 
				
			||||||
            float(line[len('#EXTINF:'):].split(',')[0])
 | 
					            float(line[len('#EXTINF:'):].split(',')[0])
 | 
				
			||||||
            for line in m3u8_vod.splitlines() if line.startswith('#EXTINF:'))) or None
 | 
					            for line in m3u8_vod.splitlines() if line.startswith('#EXTINF:'))) or None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _extract_mpd_vod_duration(
 | 
				
			||||||
 | 
					            self, mpd_url, video_id, note=None, errnote=None, data=None, headers={}, query={}):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mpd_doc = self._download_xml(
 | 
				
			||||||
 | 
					            mpd_url, video_id,
 | 
				
			||||||
 | 
					            note='Downloading MPD VOD manifest' if note is None else note,
 | 
				
			||||||
 | 
					            errnote='Failed to download VOD manifest' if errnote is None else errnote,
 | 
				
			||||||
 | 
					            fatal=False, data=data, headers=headers, query=query) or {}
 | 
				
			||||||
 | 
					        return int_or_none(parse_duration(mpd_doc.get('mediaPresentationDuration')))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def _xpath_ns(path, namespace=None):
 | 
					    def _xpath_ns(path, namespace=None):
 | 
				
			||||||
        if not namespace:
 | 
					        if not namespace:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'thumbnail': r're:^https?://.*\.jpg',
 | 
					            'thumbnail': r're:^https?://.*\.jpg',
 | 
				
			||||||
            'thumbnails': 'count:42',
 | 
					            'thumbnails': 'count:42',
 | 
				
			||||||
            'chapters': 'count:41',
 | 
					            'chapters': 'count:41',
 | 
				
			||||||
 | 
					            'duration': 1638,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -45,6 +46,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'thumbnail': r're:^https?://.*\.(?:jpg|png)',
 | 
					            'thumbnail': r're:^https?://.*\.(?:jpg|png)',
 | 
				
			||||||
            'thumbnails': 'count:640',
 | 
					            'thumbnails': 'count:640',
 | 
				
			||||||
            'chapters': 'count:639',
 | 
					            'chapters': 'count:639',
 | 
				
			||||||
 | 
					            'duration': 9832,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -61,6 +63,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'timestamp': 1643728135,
 | 
					            'timestamp': 1643728135,
 | 
				
			||||||
            'thumbnails': 'count:3',
 | 
					            'thumbnails': 'count:3',
 | 
				
			||||||
            'chapters': 'count:2',
 | 
					            'chapters': 'count:2',
 | 
				
			||||||
 | 
					            'duration': 5889,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -110,6 +113,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'timestamp': 1629671508,
 | 
					            'timestamp': 1629671508,
 | 
				
			||||||
            'upload_date': '20210822',
 | 
					            'upload_date': '20210822',
 | 
				
			||||||
            'chapters': 'count:7',
 | 
					            'chapters': 'count:7',
 | 
				
			||||||
 | 
					            'duration': 326,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -126,6 +130,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'timestamp': 1654714970,
 | 
					            'timestamp': 1654714970,
 | 
				
			||||||
            'upload_date': '20220608',
 | 
					            'upload_date': '20220608',
 | 
				
			||||||
            'chapters': 'count:6',
 | 
					            'chapters': 'count:6',
 | 
				
			||||||
 | 
					            'duration': 171,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -142,6 +147,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'timestamp': 1622806321,
 | 
					            'timestamp': 1622806321,
 | 
				
			||||||
            'upload_date': '20210604',
 | 
					            'upload_date': '20210604',
 | 
				
			||||||
            'chapters': 'count:15',
 | 
					            'chapters': 'count:15',
 | 
				
			||||||
 | 
					            'duration': 306,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -158,6 +164,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'timestamp': 1654714896,
 | 
					            'timestamp': 1654714896,
 | 
				
			||||||
            'upload_date': '20220608',
 | 
					            'upload_date': '20220608',
 | 
				
			||||||
            'chapters': 'count:8',
 | 
					            'chapters': 'count:8',
 | 
				
			||||||
 | 
					            'duration': 295,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -174,6 +181,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'thumbnails': 'count:22',
 | 
					            'thumbnails': 'count:22',
 | 
				
			||||||
            'upload_date': '20220608',
 | 
					            'upload_date': '20220608',
 | 
				
			||||||
            'chapters': 'count:21',
 | 
					            'chapters': 'count:21',
 | 
				
			||||||
 | 
					            'duration': 294,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -196,6 +204,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
                'thumbnails': 'count:30',
 | 
					                'thumbnails': 'count:30',
 | 
				
			||||||
                'upload_date': '20220608',
 | 
					                'upload_date': '20220608',
 | 
				
			||||||
                'chapters': 'count:31',
 | 
					                'chapters': 'count:31',
 | 
				
			||||||
 | 
					                'duration': 272,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }, {
 | 
					        }, {
 | 
				
			||||||
            'info_dict': {
 | 
					            'info_dict': {
 | 
				
			||||||
@@ -237,6 +246,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
                'thumbnails': 'count:43',
 | 
					                'thumbnails': 'count:43',
 | 
				
			||||||
                'upload_date': '20220608',
 | 
					                'upload_date': '20220608',
 | 
				
			||||||
                'chapters': 'count:43',
 | 
					                'chapters': 'count:43',
 | 
				
			||||||
 | 
					                'duration': 315,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }, {
 | 
					        }, {
 | 
				
			||||||
            'info_dict': {
 | 
					            'info_dict': {
 | 
				
			||||||
@@ -285,6 +295,23 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					    }, {
 | 
				
			||||||
 | 
					        # /v3/ slides, .png only, service_name = yoda
 | 
				
			||||||
 | 
					        'url': 'https://slideslive.com/38983994',
 | 
				
			||||||
 | 
					        'info_dict': {
 | 
				
			||||||
 | 
					            'id': '38983994',
 | 
				
			||||||
 | 
					            'ext': 'mp4',
 | 
				
			||||||
 | 
					            'title': 'Zero-Shot AutoML with Pretrained Models',
 | 
				
			||||||
 | 
					            'timestamp': 1662384834,
 | 
				
			||||||
 | 
					            'upload_date': '20220905',
 | 
				
			||||||
 | 
					            'thumbnail': r're:^https?://.*\.(?:jpg|png)',
 | 
				
			||||||
 | 
					            'thumbnails': 'count:23',
 | 
				
			||||||
 | 
					            'chapters': 'count:22',
 | 
				
			||||||
 | 
					            'duration': 295,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        'params': {
 | 
				
			||||||
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    }, {
 | 
					    }, {
 | 
				
			||||||
        # service_name = yoda
 | 
					        # service_name = yoda
 | 
				
			||||||
        'url': 'https://slideslive.com/38903721/magic-a-scientific-resurrection-of-an-esoteric-legend',
 | 
					        'url': 'https://slideslive.com/38903721/magic-a-scientific-resurrection-of-an-esoteric-legend',
 | 
				
			||||||
@@ -311,6 +338,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
            'timestamp': 1629671508,
 | 
					            'timestamp': 1629671508,
 | 
				
			||||||
            'upload_date': '20210822',
 | 
					            'upload_date': '20210822',
 | 
				
			||||||
            'chapters': 'count:7',
 | 
					            'chapters': 'count:7',
 | 
				
			||||||
 | 
					            'duration': 326,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'params': {
 | 
					        'params': {
 | 
				
			||||||
            'skip_download': 'm3u8',
 | 
					            'skip_download': 'm3u8',
 | 
				
			||||||
@@ -369,15 +397,28 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return m3u8_dict
 | 
					        return m3u8_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _extract_formats(self, cdn_hostname, path, video_id):
 | 
					    def _extract_formats_and_duration(self, cdn_hostname, path, video_id, skip_duration=False):
 | 
				
			||||||
        formats = []
 | 
					        formats, duration = [], None
 | 
				
			||||||
        formats.extend(self._extract_m3u8_formats(
 | 
					
 | 
				
			||||||
 | 
					        hls_formats = self._extract_m3u8_formats(
 | 
				
			||||||
            f'https://{cdn_hostname}/{path}/master.m3u8',
 | 
					            f'https://{cdn_hostname}/{path}/master.m3u8',
 | 
				
			||||||
            video_id, 'mp4', m3u8_id='hls', fatal=False, live=True))
 | 
					            video_id, 'mp4', m3u8_id='hls', fatal=False, live=True)
 | 
				
			||||||
        formats.extend(self._extract_mpd_formats(
 | 
					        if hls_formats:
 | 
				
			||||||
            f'https://{cdn_hostname}/{path}/master.mpd',
 | 
					            if not skip_duration:
 | 
				
			||||||
            video_id, mpd_id='dash', fatal=False))
 | 
					                duration = self._extract_m3u8_vod_duration(
 | 
				
			||||||
        return formats
 | 
					                    hls_formats[0]['url'], video_id, note='Extracting duration from HLS manifest')
 | 
				
			||||||
 | 
					            formats.extend(hls_formats)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dash_formats = self._extract_mpd_formats(
 | 
				
			||||||
 | 
					            f'https://{cdn_hostname}/{path}/master.mpd', video_id, mpd_id='dash', fatal=False)
 | 
				
			||||||
 | 
					        if dash_formats:
 | 
				
			||||||
 | 
					            if not duration and not skip_duration:
 | 
				
			||||||
 | 
					                duration = self._extract_mpd_vod_duration(
 | 
				
			||||||
 | 
					                    f'https://{cdn_hostname}/{path}/master.mpd', video_id,
 | 
				
			||||||
 | 
					                    note='Extracting duration from DASH manifest')
 | 
				
			||||||
 | 
					            formats.extend(dash_formats)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return formats, duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _real_extract(self, url):
 | 
					    def _real_extract(self, url):
 | 
				
			||||||
        video_id = self._match_id(url)
 | 
					        video_id = self._match_id(url)
 | 
				
			||||||
@@ -406,44 +447,42 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
        assert service_name in ('url', 'yoda', 'vimeo', 'youtube')
 | 
					        assert service_name in ('url', 'yoda', 'vimeo', 'youtube')
 | 
				
			||||||
        service_id = player_info['service_id']
 | 
					        service_id = player_info['service_id']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slides_info_url = None
 | 
					        slide_url_template = 'https://slides.slideslive.com/%s/slides/original/%s%s'
 | 
				
			||||||
        slides, slides_info = [], []
 | 
					        slides, slides_info = {}, []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if player_info.get('slides_json_url'):
 | 
					        if player_info.get('slides_json_url'):
 | 
				
			||||||
            slides_info_url = player_info['slides_json_url']
 | 
					            slides = self._download_json(
 | 
				
			||||||
            slides = traverse_obj(self._download_json(
 | 
					                player_info['slides_json_url'], video_id, fatal=False,
 | 
				
			||||||
                slides_info_url, video_id, fatal=False,
 | 
					                note='Downloading slides JSON', errnote=False) or {}
 | 
				
			||||||
                note='Downloading slides JSON', errnote=False), 'slides', expected_type=list) or []
 | 
					            slide_ext_default = '.png'
 | 
				
			||||||
            for slide_id, slide in enumerate(slides, start=1):
 | 
					            slide_quality = traverse_obj(slides, ('slide_qualities', 0))
 | 
				
			||||||
 | 
					            if slide_quality:
 | 
				
			||||||
 | 
					                slide_ext_default = '.jpg'
 | 
				
			||||||
 | 
					                slide_url_template = f'https://cdn.slideslive.com/data/presentations/%s/slides/{slide_quality}/%s%s'
 | 
				
			||||||
 | 
					            for slide_id, slide in enumerate(traverse_obj(slides, ('slides', ...), expected_type=dict), 1):
 | 
				
			||||||
                slides_info.append((
 | 
					                slides_info.append((
 | 
				
			||||||
                    slide_id, traverse_obj(slide, ('image', 'name')),
 | 
					                    slide_id, traverse_obj(slide, ('image', 'name')),
 | 
				
			||||||
 | 
					                    traverse_obj(slide, ('image', 'extname'), default=slide_ext_default),
 | 
				
			||||||
                    int_or_none(slide.get('time'), scale=1000)))
 | 
					                    int_or_none(slide.get('time'), scale=1000)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not slides and player_info.get('slides_xml_url'):
 | 
					        if not slides and player_info.get('slides_xml_url'):
 | 
				
			||||||
            slides_info_url = player_info['slides_xml_url']
 | 
					 | 
				
			||||||
            slides = self._download_xml(
 | 
					            slides = self._download_xml(
 | 
				
			||||||
                slides_info_url, video_id, fatal=False,
 | 
					                player_info['slides_xml_url'], video_id, fatal=False,
 | 
				
			||||||
                note='Downloading slides XML', errnote='Failed to download slides info')
 | 
					                note='Downloading slides XML', errnote='Failed to download slides info')
 | 
				
			||||||
            for slide_id, slide in enumerate(slides.findall('./slide'), start=1):
 | 
					            slide_url_template = 'https://cdn.slideslive.com/data/presentations/%s/slides/big/%s%s'
 | 
				
			||||||
 | 
					            for slide_id, slide in enumerate(slides.findall('./slide') if slides else [], 1):
 | 
				
			||||||
                slides_info.append((
 | 
					                slides_info.append((
 | 
				
			||||||
                    slide_id, xpath_text(slide, './slideName', 'name'),
 | 
					                    slide_id, xpath_text(slide, './slideName', 'name'), '.jpg',
 | 
				
			||||||
                    int_or_none(xpath_text(slide, './timeSec', 'time'))))
 | 
					                    int_or_none(xpath_text(slide, './timeSec', 'time'))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        slides_version = int(self._search_regex(
 | 
					 | 
				
			||||||
            r'https?://slides\.slideslive\.com/\d+/v(\d+)/\w+\.(?:json|xml)',
 | 
					 | 
				
			||||||
            slides_info_url, 'slides version', default=0))
 | 
					 | 
				
			||||||
        if slides_version < 4:
 | 
					 | 
				
			||||||
            slide_url_template = 'https://cdn.slideslive.com/data/presentations/%s/slides/big/%s.jpg'
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            slide_url_template = 'https://slides.slideslive.com/%s/slides/original/%s.png'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        chapters, thumbnails = [], []
 | 
					        chapters, thumbnails = [], []
 | 
				
			||||||
        if url_or_none(player_info.get('thumbnail')):
 | 
					        if url_or_none(player_info.get('thumbnail')):
 | 
				
			||||||
            thumbnails.append({'id': 'cover', 'url': player_info['thumbnail']})
 | 
					            thumbnails.append({'id': 'cover', 'url': player_info['thumbnail']})
 | 
				
			||||||
        for slide_id, slide_path, start_time in slides_info:
 | 
					        for slide_id, slide_path, slide_ext, start_time in slides_info:
 | 
				
			||||||
            if slide_path:
 | 
					            if slide_path:
 | 
				
			||||||
                thumbnails.append({
 | 
					                thumbnails.append({
 | 
				
			||||||
                    'id': f'{slide_id:03d}',
 | 
					                    'id': f'{slide_id:03d}',
 | 
				
			||||||
                    'url': slide_url_template % (video_id, slide_path),
 | 
					                    'url': slide_url_template % (video_id, slide_path, slide_ext),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            chapters.append({
 | 
					            chapters.append({
 | 
				
			||||||
                'title': f'Slide {slide_id:03d}',
 | 
					                'title': f'Slide {slide_id:03d}',
 | 
				
			||||||
@@ -473,7 +512,12 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
        if service_name == 'url':
 | 
					        if service_name == 'url':
 | 
				
			||||||
            info['url'] = service_id
 | 
					            info['url'] = service_id
 | 
				
			||||||
        elif service_name == 'yoda':
 | 
					        elif service_name == 'yoda':
 | 
				
			||||||
            info['formats'] = self._extract_formats(player_info['video_servers'][0], service_id, video_id)
 | 
					            formats, duration = self._extract_formats_and_duration(
 | 
				
			||||||
 | 
					                player_info['video_servers'][0], service_id, video_id)
 | 
				
			||||||
 | 
					            info.update({
 | 
				
			||||||
 | 
					                'duration': duration,
 | 
				
			||||||
 | 
					                'formats': formats,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            info.update({
 | 
					            info.update({
 | 
				
			||||||
                '_type': 'url_transparent',
 | 
					                '_type': 'url_transparent',
 | 
				
			||||||
@@ -486,7 +530,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
                    f'https://player.vimeo.com/video/{service_id}',
 | 
					                    f'https://player.vimeo.com/video/{service_id}',
 | 
				
			||||||
                    {'http_headers': {'Referer': url}})
 | 
					                    {'http_headers': {'Referer': url}})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        video_slides = traverse_obj(slides, (..., 'video', 'id'))
 | 
					        video_slides = traverse_obj(slides, ('slides', ..., 'video', 'id'))
 | 
				
			||||||
        if not video_slides:
 | 
					        if not video_slides:
 | 
				
			||||||
            return info
 | 
					            return info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -500,7 +544,7 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
                    'videos': ','.join(video_slides),
 | 
					                    'videos': ','.join(video_slides),
 | 
				
			||||||
                }, note='Downloading video slides info', errnote='Failed to download video slides info') or {}
 | 
					                }, note='Downloading video slides info', errnote='Failed to download video slides info') or {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for slide_id, slide in enumerate(slides, 1):
 | 
					            for slide_id, slide in enumerate(traverse_obj(slides, ('slides', ...)), 1):
 | 
				
			||||||
                if not traverse_obj(slide, ('video', 'service')) == 'yoda':
 | 
					                if not traverse_obj(slide, ('video', 'service')) == 'yoda':
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                video_path = traverse_obj(slide, ('video', 'id'))
 | 
					                video_path = traverse_obj(slide, ('video', 'id'))
 | 
				
			||||||
@@ -508,7 +552,8 @@ class SlidesLiveIE(InfoExtractor):
 | 
				
			|||||||
                    video_path, 'video_servers', ...), get_all=False)
 | 
					                    video_path, 'video_servers', ...), get_all=False)
 | 
				
			||||||
                if not cdn_hostname or not video_path:
 | 
					                if not cdn_hostname or not video_path:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                formats = self._extract_formats(cdn_hostname, video_path, video_id)
 | 
					                formats, _ = self._extract_formats_and_duration(
 | 
				
			||||||
 | 
					                    cdn_hostname, video_path, video_id, skip_duration=True)
 | 
				
			||||||
                if not formats:
 | 
					                if not formats:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                yield {
 | 
					                yield {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user