Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/tumblr.py (Python)

Code before:
        # It's possible that timestamp is ultimately None if:
        # - An API key is not set
        # - The post is does not require login (otherwise the extraction would fail altogether)
        # - The desired video is earlier in the reblog chain
        #
        # As possible future work, another HTTP request could be used to retrieve more metadata
        # about the earlier reblog, or maybe that information is available elsewhere on the page
        # and I just missed it
        timestamp = (
            traverse_obj(post_json,

                         # Timestamp of earliest post in the reblog chain (not counting the post itself)
                         # Absent if not using tumblr API or if this isn't a reblog
                         ('trail', 0, 'post', 'timestamp'),

                         # Timestamp of the post itself
                         # None if not using the tumblr API
                         'timestamp',

                         expected_type=int)

            # Timestamp as claimed by JSON-LD, only seems to be present if the the video is the most
            # recent in the reblog chain
            # None if this is a dashboard-only (i.e. login required) post OR the video in question
            # is earlier in the reblog chain.  A little unreliable, but works as a fallback
            or self._search_json_ld(webpage, None, fatal=False, expected_type=int).get('timestamp'))

        info_dict = {
            'id': video_id,
            'title': post_json.get('summary') or (blog if api_only else self._html_search_regex(
                r'(?s)<title>(?P<title>.*?)(?: \| Tumblr)?</title>', webpage, 'title', default=blog)),
            'description': description,
            'timestamp': timestamp,
            'uploader_id': uploader_id,
            'uploader_url': f'https://{uploader_id}.tumblr.com/' if uploader_id else None,
            **traverse_obj(post_json, {
                'like_count': ('like_count', {int_or_none}),
                'repost_count': ('reblog_count', {int_or_none}),
                'tags': ('tags', ..., {str}),
            }),
            'age_limit': {True: 18, False: 0}.get(post_json.get('is_nsfw')),
        }

        # for tumblr's own video hosting
        fallback_format = None
        formats = []
        video_url = self._og_search_video_url(webpage, default=None)
        # for external video hosts
        entries = []
        ignored_providers = set()
        unknown_providers = set()

Review comment (refactor):
This fallback doesn't even work, though?

The `_search_json_ld` method's `expected_type` kwarg is used to expect JSON-LD object `@type`s, not Python types.

I'm assuming none of the extractor tests use this fallback? It would be nice to add a test case that actually covers this code path. Or else add comments if some of the tests do need this.

Code after:
                r'(?s)<title>(?P<title>.*?)(?: \| Tumblr)?</title>', webpage, 'title', default=blog)),
            'description': description,
            'uploader_id': uploader_id,
            'uploader_url': f'https://{uploader_id}.tumblr.com/' if uploader_id else None,
            **traverse_obj(post_json, {
                # Try oldest post in reblog chain, fall back to timestamp of the post itself
                'timestamp': ((('trail', 0, 'post'), None), 'timestamp', {int_or_none}, any),
                'like_count': ('like_count', {int_or_none}),
                'repost_count': ('reblog_count', {int_or_none}),
                'tags': ('tags', ..., {str}),
            }),
            'age_limit': {True: 18, False: 0}.get(post_json.get('is_nsfw')),
        }

        # for tumblr's own video hosting
        fallback_format = None
        formats = []
        video_url = self._og_search_video_url(webpage, default=None)
        # for external video hosts
        entries = []
        ignored_providers = set()
        unknown_providers = set()

        for video_json in traverse_obj(content_json, lambda _, v: v['type'] in ('video', 'audio')):
            media_json = video_json.get('media') or {}
            if api_only and not media_json.get('url') and not video_json.get('url'):
                raise ExtractorError('Failed to find video data for dashboard-only post')
            provider = video_json.get('provider')

            if provider in ('tumblr', None):
                fallback_format = {
                    'url': media_json.get('url') or video_url,
                    'width': int_or_none(
                        media_json.get('width') or self._og_search_property('video:width', webpage, default=None)),
                    'height': int_or_none(
                        media_json.get('height') or self._og_search_property('video:height', webpage, default=None)),
                }
                continue
            elif provider in self._unsupported_providers:
                ignored_providers.add(provider)
                continue
            elif provider and provider not in self._providers:
                unknown_providers.add(provider)
            if video_json.get('url'):
                # external video host
                entries.append(self.url_result(
                    video_json['url'], self._providers.get(provider)))

        duration = None

        # iframes can supply duration and sometimes additional formats, so check for one