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

Code before:
    _TESTS = [{
        'url': ':ythistory',
        'only_matching': True,
    }]


class YoutubeStoriesIE(InfoExtractor):
    IE_DESC = 'YouTube channel stories; "ytstories:" prefix'
    IE_NAME = 'youtube:stories'
    _VALID_URL = r'ytstories:UC(?P<id>[A-Za-z0-9_-]{21}[AQgw])$'
    _TESTS = [{
        'url': 'ytstories:UCwFCb4jeqaKWnciAYM-ZVHg',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        playlist_id = f'RLTD{self._match_id(url)}'
        return self.url_result(
            smuggle_url(f'https://www.youtube.com/playlist?list={playlist_id}&playnext=1', {'is_story': True}),
            ie=YoutubeTabIE, video_id=playlist_id)


class YoutubeShortsAudioPivotIE(InfoExtractor):
    IE_DESC = 'YouTube Shorts audio pivot; "ytshortsap:" prefix'
    IE_NAME = 'youtube:shorts:audiopivot'
    _VALID_URL = f'(?x)^ytshortsap:{YoutubeIE._VALID_URL[5:]}'  # TODO: might be better to just restrict this to id and /shorts/
    _TESTS = [{
        'url': 'ytshortsap:https://www.youtube.com/shorts/Lyj-MZSAA9o?feature=share',
        'only_matching': True,
    }, {
        'url': 'ytshortsap:Lyj-MZSAA9o',
        'only_matching': True,
    }]

    @staticmethod
    def _generate_audio_pivot_params(video_id):
        """
        Generates sfv_audio_pivot browse parameter for this video id
        """
        token = b'\xf2\x05+\n)\x12\'\n\x0b%b\x12\x0b%b\x1a\x0b%b' % ((video_id.encode(),) * 3)
        return base64.b64encode(token).decode()

    def _real_extract(self, url):
        video_id = self._match_id(url)
        return self.url_result(
            f'https://www.youtube.com/feed/sfv_audio_pivot?bp={self._generate_audio_pivot_params(video_id)}',
            ie=YoutubeTabIE.ie_key())


class YoutubeTruncatedURLIE(InfoExtractor):
    IE_NAME = 'youtube:truncated_url'

Review comment (suggestion):
```suggestion
    _VALID_URL = f'(?x)ytshortsap:{YoutubeIE._VALID_URL[5:]}'
```

Code after:
    _TESTS = [{
        'url': ':ythistory',
        'only_matching': True,
    }]


class YoutubeStoriesIE(InfoExtractor):
    IE_DESC = 'YouTube channel stories; "ytstories:" prefix'
    IE_NAME = 'youtube:stories'
    _VALID_URL = r'ytstories:UC(?P<id>[A-Za-z0-9_-]{21}[AQgw])$'
    _TESTS = [{
        'url': 'ytstories:UCwFCb4jeqaKWnciAYM-ZVHg',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        playlist_id = f'RLTD{self._match_id(url)}'
        return self.url_result(
            smuggle_url(f'https://www.youtube.com/playlist?list={playlist_id}&playnext=1', {'is_story': True}),
            ie=YoutubeTabIE, video_id=playlist_id)


class YoutubeShortsAudioPivotIE(InfoExtractor):
    IE_DESC = 'YouTube Shorts audio pivot (Shorts using audio of a given video); "ytshortsap:" prefix'
    IE_NAME = 'youtube:shorts:pivot:audio'
    _VALID_URL = f'(?x)^ytshortsap:{YoutubeIE._VALID_URL[5:]}'
    _TESTS = [{
        'url': 'ytshortsap:https://www.youtube.com/shorts/Lyj-MZSAA9o?feature=share',
        'only_matching': True,
    }, {
        'url': 'ytshortsap:Lyj-MZSAA9o',
        'only_matching': True,
    }]

    @staticmethod
    def _generate_audio_pivot_params(video_id):
        """
        Generates sfv_audio_pivot browse params for this video id
        """
        pb_params = b'\xf2\x05+\n)\x12\'\n\x0b%b\x12\x0b%b\x1a\x0b%b' % ((video_id.encode(),) * 3)
        return urllib.parse.quote(base64.b64encode(pb_params).decode())

    def _real_extract(self, url):
        video_id = self._match_id(url)
        return self.url_result(
            f'https://www.youtube.com/feed/sfv_audio_pivot?bp={self._generate_audio_pivot_params(video_id)}',
            ie=YoutubeTabIE)


class YoutubeTruncatedURLIE(InfoExtractor):
    IE_NAME = 'youtube:truncated_url'