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

Code before:
    def _mark_watched(self, video_id, player_responses):
        mark_watched_urls = {
            "playback": get_first(
                player_responses, ('playbackTracking', 'videostatsPlaybackUrl', 'baseUrl'),
                expected_type=url_or_none),
            "watchtime": get_first(
                player_responses, ('playbackTracking', 'videostatsWatchtimeUrl', 'baseUrl'),
                expected_type=url_or_none)
        }

        if not all(mark_watched_urls.values()):
            self.report_warning('Unable to mark watched')
            return
        for url_type, url in mark_watched_urls.items():
            parsed_url = compat_urlparse.urlparse(url)
            qs = compat_urlparse.parse_qs(parsed_url.query)

            # cpn generation algorithm is reverse engineered from base.js.
            # In fact it works even with dummy cpn.
            CPN_ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_'
            cpn = ''.join(CPN_ALPHABET[random.randint(0, 256) & 63] for _ in range(0, 16))

            video_length = qs.get('len') or ['1.5']
            # more consistent results setting it to right before the end
            video_length_float = float(video_length[0]) - 1
            video_length = [str(video_length_float)]

            qs.update({
                'ver': ['2'],
                'cpn': [cpn],
                'cmt': video_length,
                'el': 'detailpage',  # otherwise defaults to "shorts"
            })

            if url_type == "watchtime":
                # these seem to mark watchtime "history" in the real world
                # they're required, so send in a single value
                qs.update({
                    'st': video_length,
                    'et': video_length,
                })

            url = compat_urlparse.urlunparse(
                parsed_url._replace(query=compat_urllib_parse_urlencode(qs, True)))

            self._download_webpage(
                url, video_id, f'Marking watched ({url_type})',
                'Unable to mark watched', fatal=False)

    @staticmethod
    def _extract_urls(webpage):

Review comment (suggestion):
```suggestion
            # more consistent results setting it to right before the end
            video_length = [str(float(qs.get('len', ['1.5'])[0]) - 1)]
```

Code after:
    def _mark_watched(self, video_id, player_responses):
        for is_full, key in enumerate(('videostatsPlaybackUrl', 'videostatsWatchtimeUrl')):
            label = 'fully ' if is_full else ''
            url = get_first(player_responses, ('playbackTracking', key, 'baseUrl'),
                            expected_type=url_or_none)
            if not url:
                self.report_warning(f'Unable to mark {label}watched')
                return
            parsed_url = compat_urlparse.urlparse(url)
            qs = compat_urlparse.parse_qs(parsed_url.query)

            # cpn generation algorithm is reverse engineered from base.js.
            # In fact it works even with dummy cpn.
            CPN_ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_'
            cpn = ''.join(CPN_ALPHABET[random.randint(0, 256) & 63] for _ in range(0, 16))

            # # more consistent results setting it to right before the end
            video_length = [str(float((qs.get('len') or ['1.5'])[0]) - 1)]

            qs.update({
                'ver': ['2'],
                'cpn': [cpn],
                'cmt': video_length,
                'el': 'detailpage',  # otherwise defaults to "shorts"
            })

            if is_full:
                # these seem to mark watchtime "history" in the real world
                # they're required, so send in a single value
                qs.update({
                    'st': video_length,
                    'et': video_length,
                })

            url = compat_urlparse.urlunparse(
                parsed_url._replace(query=compat_urllib_parse_urlencode(qs, True)))

            self._download_webpage(
                url, video_id, f'Marking {label}watched',
                'Unable to mark watched', fatal=False)

    @staticmethod
    def _extract_urls(webpage):
        # Embedded YouTube player
        entries = [
            unescapeHTML(mobj.group('url'))
            for mobj in re.finditer(r'''(?x)
            (?:
                <iframe[^>]+?src=|
                data-video-url=|
                <embed[^>]+?src=|