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

Code before:
    def _extract_notification(self, notification):
        # notificationRenderer
        video_id = traverse_obj(
            notification, ('navigationEndpoint', 'watchEndpoint', 'videoId'), expected_type=str)
        if not video_id:
            return None
        thumbnails = traverse_obj(notification, ('videoThumbnail', 'thumbnails'), expected_type=list)
        status_text = traverse_obj(notification, ('shortMessage', 'simpleText'), expected_type=str)
        uploader = traverse_obj(
            notification, ('contextualMenu', 'menuRenderer', 'items', 1, 'menuServiceItemRenderer', 'text', 'runs', 1, 'text'), expected_type=str)
        status_text = status_text.removeprefix(uploader + ' ')
        split_text = status_text.split(': ', 2)
        title = None
        if len(split_text) == 2:
            title = split_text[1]
        extra_info = {
            'thumbnails': thumbnails,
            'uploader': uploader,
        }
        return self.url_result(
            f'https://www.youtube.com/watch?v={video_id}', ie=YoutubeIE.ie_key(),
            video_id=video_id, video_title=title, **extra_info)

    @classmethod
    def _extract_next_notification_continuation_data(cls, renderer):
        # continuationItemRenderer
        ctoken = traverse_obj(
            renderer, ('continuationEndpoint', 'getNotificationMenuEndpoint', 'ctoken'), expected_type=str)
        if not ctoken:
            return
        return cls._build_notification_continuation_query(ctoken)

    @staticmethod
    def _build_notification_continuation_query(ctoken):
        query = {
            'ctoken': ctoken
        }
        return query

    def _notification_menu_entries(self, headers, max_requests):
        continuation_list = [None]
        request_count = 0
        entries = []
        while request_count < max_requests:
            query = {}
            if continuation_list[0]:
                query = self._extract_next_notification_continuation_data(continuation_list[0])
            request_count += 1
            response = self._extract_response(
                note=f'Downloading API JSON (page {request_count})',
                ep='notification/get_notification_menu', headers=headers,

Review comment (refactor):
```suggestion
    @classmethod
    def _extract_next_notification_continuation_data(cls, renderer):
```

Code after:
    }]

    def _extract_notification_menu(self, response, continuation_list):
        notification_list = traverse_obj(
            response,
            ('actions', 0, 'openPopupAction', 'popup', 'multiPageMenuRenderer', 'sections', 0, 'multiPageMenuNotificationSectionRenderer', 'items'),
            ('actions', 0, 'appendContinuationItemsAction', 'continuationItems'),
            expected_type=list) or []
        continuation_list[0] = None
        for item in notification_list:
            entry = self._extract_notification_renderer(item.get('notificationRenderer'))
            if entry:
                yield entry
            continuation = item.get('continuationItemRenderer')
            if continuation:
                continuation_list[0] = continuation

    def _extract_notification_renderer(self, notification):
        video_id = traverse_obj(
            notification, ('navigationEndpoint', 'watchEndpoint', 'videoId'), expected_type=str)
        url = f'https://www.youtube.com/watch?v={video_id}'
        channel_id = None
        if not video_id:
            browse_ep = traverse_obj(
                notification, ('navigationEndpoint', 'browseEndpoint'), expected_type=dict)
            channel_id = traverse_obj(browse_ep, 'browseId', expected_type=str)
            post_id = self._search_regex(
                r'/post/(.+)', traverse_obj(browse_ep, 'canonicalBaseUrl', expected_type=str),
                'post id', default=None)
            if not channel_id or not post_id:
                return
            # The direct /post url redirects to this in the browser
            url = f'https://www.youtube.com/channel/{channel_id}/community?lb={post_id}'

        channel = traverse_obj(
            notification, ('contextualMenu', 'menuRenderer', 'items', 1, 'menuServiceItemRenderer', 'text', 'runs', 1, 'text'),
            expected_type=str)
        title = self._search_regex(
            rf'{re.escape(channel)} [^:]+: (.+)', self._get_text(notification, 'shortMessage'),
            'video title', default=None)
        if title:
            title = title.replace('\xad', '')  # remove soft hyphens
        upload_date = (strftime_or_none(self._extract_time_text(notification, 'sentTimeText')[0], '%Y%m%d')
                       if self._configuration_arg('approximate_date', ie_key=YoutubeTabIE.ie_key())
                       else None)
        return {
            '_type': 'url',
            'url': url,
            'ie_key': (YoutubeIE if video_id else YoutubeTabIE).ie_key(),
            'video_id': video_id,
            'title': title,