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

Code before:
        secuid = self._search_regex(r'\"secUid\":\"(?P<secUid>[^\"]+)', webpage, username)
        verifyfp_cookie = self._get_cookies('https://www.tiktok.com').get('s_v_web_id')
        if not verifyfp_cookie:
            raise ExtractorError('Improper cookies (missing s_v_web_id).', expected=True)
        api_url = f'https://m.tiktok.com/api/post/item_list/?aid=1988&cookie_enabled=true&count=30&verifyFp={verifyfp_cookie.value}&secUid={secuid}&cursor='
        cursor = '0'
        for page in itertools.count():
            data_json = self._download_json(api_url + cursor, username, note='Downloading Page %d' % page)
            for video in data_json.get('itemList', []):
                video_id = video['id']
                video_url = f'https://www.tiktok.com/@{user_id}/video/{video_id}'
                yield self._url_result(video_url, 'TikTok', video_id, str_or_none(video.get('desc')))
            if not data_json.get('hasMore'):
                break
            cursor = data_json['cursor']
    '''

    def _video_entries_api(self, webpage, user_id, username):
        query = {
            'user_id': user_id,
            'count': 21,
            'max_cursor': 0,
            'min_cursor': 0,
            'retry_type': 'no_retry',
            'device_id': ''.join(random.choices(string.digits, k=19)),
            # Some endpoints don't like randomized device_id, so it isn't directly set in _call_api.
        }

        for page in itertools.count(1):
            for retry in self.RetryManager():
                try:
                    post_list = self._call_api(
                        'aweme/post', query, username, note=f'Downloading user video list page {page}',
                        errnote='Unable to download user video list')
                except ExtractorError as e:
                    if isinstance(e.cause, json.JSONDecodeError) and e.cause.pos == 0:
                        retry.error = e
                        continue
                    raise
            yield from post_list.get('aweme_list', [])
            if not post_list.get('has_more'):
                break
            query['max_cursor'] = post_list['max_cursor']

    def _entries_api(self, user_id, videos):
        for video in videos:
            yield {
                **self._parse_aweme_video_app(video),
                'extractor_key': TikTokIE.ie_key(),
                'extractor': 'TikTok',
                'webpage_url': f'https://tiktok.com/@{user_id}/video/{video["aweme_id"]}',

Review comment (suggestion):
revert unnecessary/unrelated formatting change
```suggestion
            'device_id': ''.join(random.choices(string.digits, k=19)), # Some endpoints don't like randomized device_id, so it isn't directly set in _call_api.
```

Code after:
            'count': 21,
            'max_cursor': 0,
            'min_cursor': 0,
            'retry_type': 'no_retry',
            'device_id': ''.join(random.choices(string.digits, k=19)),  # Some endpoints don't like randomized device_id, so it isn't directly set in _call_api.
        }

        for page in itertools.count(1):
            for retry in self.RetryManager():
                try:
                    post_list = self._call_api(
                        'aweme/post', query, username, note=f'Downloading user video list page {page}',
                        errnote='Unable to download user video list')
                except ExtractorError as e:
                    if isinstance(e.cause, json.JSONDecodeError) and e.cause.pos == 0:
                        retry.error = e
                        continue
                    raise
            yield from post_list.get('aweme_list', [])
            if not post_list.get('has_more'):
                break
            query['max_cursor'] = post_list['max_cursor']

    def _entries_api(self, user_id, videos):
        for video in videos:
            yield {
                **self._parse_aweme_video_app(video),
                'extractor_key': TikTokIE.ie_key(),
                'extractor': 'TikTok',
                'webpage_url': f'https://tiktok.com/@{user_id}/video/{video["aweme_id"]}',
            }

    def _real_extract(self, url):
        user_name = self._match_id(url)
        webpage = self._download_webpage(url, user_name, headers={
            'User-Agent': 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)'
        })
        user_id = self._html_search_regex(r'snssdk\d*://user/profile/(\d+)', webpage, 'user ID', default=None) or user_name

        videos = LazyList(self._video_entries_api(webpage, user_id, user_name))
        thumbnail = traverse_obj(videos, (0, 'author', 'avatar_larger', 'url_list', 0))

        return self.playlist_result(self._entries_api(user_id, videos), user_id, user_name, thumbnail=thumbnail)


class TikTokBaseListIE(TikTokBaseIE):  # XXX: Conventionally, base classes should end with BaseIE/InfoExtractor
    def _entries(self, list_id, display_id):
        query = {
            self._QUERY_NAME: list_id,
            'cursor': 0,
            'count': 20,