ronantakizawa/codereview-bench huggingface dataset:
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/syvdk.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import try_get


class SYVDKIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?24syv\.dk/episode/(?P<id>[a-zA-Z0-9-]+)'

    _TESTS = [{
        'url': 'https://24syv.dk/episode/isabella-arendt-stiller-op-for-de-konservative-2',
        'md5': '429ce5a423dd4b1e1d0bf3a569558089',
        'info_dict': {
            'id': '12215',
            'display_id': 'isabella-arendt-stiller-op-for-de-konservative-2',
            'ext': 'mp3',
            'title': 'Isabella Arendt stiller op for De Konservative',
            'description': 'md5:f5fa6a431813bf37284f3412ad7c6c06'
        }
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        info_data = self._search_nextjs_data(webpage, video_id)["props"]["pageProps"]["episodeDetails"][0]

        return {
            'id': str(info_data['id']),
            'display_id': video_id,

Review comment (suggestion):
```suggestion
from ..utils import traverse_obj
```

Code after:
from .common import InfoExtractor
from ..utils import traverse_obj


class SYVDKIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?24syv\.dk/episode/(?P<id>[\w-]+)'

    _TESTS = [{
        'url': 'https://24syv.dk/episode/isabella-arendt-stiller-op-for-de-konservative-2',
        'md5': '429ce5a423dd4b1e1d0bf3a569558089',
        'info_dict': {
            'id': '12215',
            'display_id': 'isabella-arendt-stiller-op-for-de-konservative-2',
            'ext': 'mp3',
            'title': 'Isabella Arendt stiller op for De Konservative',
            'description': 'md5:f5fa6a431813bf37284f3412ad7c6c06'
        }
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        info_data = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['episodeDetails'][0]

        return {
            'id': str(info_data['id']),
            'vcodec': 'none',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/detik.py (Python)

Code before:
            'id': '220603135',
            'ext': 'mp4',
            'description': 'md5:4771fe101aa303edb829c59c26f9e7c6',
            'timestamp': 1654304305,
            'title': 'Merasakan Bus Imut Tanpa Pengemudi, Muter-muter di Kawasan BSD City',
            'tags': ['viral', 'autonomous vehicle', 'electric', 'shuttle bus'],
            'thumbnail': 'https://cdnv.detik.com/videoservice/AdminTV/2022/06/03/VIRAL_BUS_NO_SUPIR-20220604004707-custom.jpg?w=650&q=80',
            'duration': 593,
            'upload_date': '20220604',
        }
    }]

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)
        json_ld_data = self._search_json_ld(webpage, display_id)

        video_url = self._html_search_regex(
            r'videoUrl\s*:\s*"(?P<video_url>[^"]+)', webpage, 'videoUrl')
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(video_url, display_id, ext='mp4')

        return merge_dicts(json_ld_data, {
            'id': self._html_search_meta('video_id', webpage),
            'formats': formats,
            'subtitles': subtitles,
            'tags': str_or_none(json_ld_data.get('keywords') or self._html_search_meta(['keywords', 'keyword', 'dtk:keywords'], webpage), '').split(','),
        })


Review comment (refactor):
```suggestion
            'tags': self._html_search_meta(['keywords', 'keyword', 'dtk:keywords'], webpage), '').split(','),
```
did u forget to remove this?

Code after:
            'id': '220603135',
            'ext': 'mp4',
            'description': 'md5:4771fe101aa303edb829c59c26f9e7c6',
            'timestamp': 1654304305,
            'title': 'Merasakan Bus Imut Tanpa Pengemudi, Muter-muter di Kawasan BSD City',
            'tags': ['viral', 'autonomous vehicle', 'electric', 'shuttle bus'],
            'thumbnail': 'https://cdnv.detik.com/videoservice/AdminTV/2022/06/03/VIRAL_BUS_NO_SUPIR-20220604004707-custom.jpg?w=650&q=80',
            'duration': 593,
            'upload_date': '20220604',
        }
    }]

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)
        json_ld_data = self._search_json_ld(webpage, display_id)

        video_url = self._html_search_regex(
            r'videoUrl\s*:\s*"(?P<video_url>[^"]+)', webpage, 'videoUrl')
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(video_url, display_id, ext='mp4')

        return merge_dicts(json_ld_data, {
            'id': self._html_search_meta('video_id', webpage),
            'formats': formats,
            'subtitles': subtitles,
            'tags': str_or_none(self._html_search_meta(['keywords', 'keyword', 'dtk:keywords'], webpage), '').split(','),
        })
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/audiodraft.py (Python)

Code before:
            'average_rating': 5,
            'like_count': int,
        },
    }, {
        'url': 'http://timferriss.audiodraft.com/entry/765',
        'info_dict': {
            'id': '19710',
            'ext': 'mp3',
            'title': 'ferris03',
            'uploader': 'malex',
            'uploader_id': '17335',
            'average_rating': 5,
            'like_count': int,
        },
    }]

    def _real_extract(self, url):
        id = self._match_id(url)
        webpage = self._download_webpage(url, id)
        player_entry_id = self._search_regex(r'playAudio\(\'(player_entry_\d+)\'\);', webpage, id, 'play entry id')
        return self._audiodraft_extract_from_id(player_entry_id)


class AudiodraftGenericIE(AudiodraftIE):
    IE_NAME = 'Audiodraft:generic'
    _VALID_URL = r'https?://www\.audiodraft\.com/contests/[^/#]+\#entries&eid=(?P<id>\d+)'

    _TESTS = [{
        'url': 'https://www.audiodraft.com/contests/570-Score-A-Video-Surprise-Us#entries&eid=30138',
        'info_dict': {
            'id': '30138',
            'ext': 'mp3',
            'title': 'DROP in sound_V2',
            'uploader': 'TiagoSilva',
            'uploader_id': '19452',
            'average_rating': 4,
            'like_count': int,
        },
    }]

    def _real_extract(self, url):
        id = self._match_id(url)
        return self._audiodraft_extract_from_id(f'player_entry_{id}')


Review comment (suggestion):
```suggestion
    _VALID_URL = r'https?://www\.audiodraft\.com/contests/[^/#]+#entries&eid=(?P<id>\d+)'
```

Code after:
            'average_rating': 5,
            'like_count': int,
        },
    }, {
        'url': 'http://timferriss.audiodraft.com/entry/765',
        'info_dict': {
            'id': '19710',
            'ext': 'mp3',
            'title': 'ferris03',
            'uploader': 'malex',
            'uploader_id': '17335',
            'average_rating': 5,
            'like_count': int,
        },
    }]

    def _real_extract(self, url):
        id = self._match_id(url)
        webpage = self._download_webpage(url, id)
        player_entry_id = self._search_regex(r'playAudio\(\'(player_entry_\d+)\'\);', webpage, id, 'play entry id')
        return self._audiodraft_extract_from_id(player_entry_id)


class AudiodraftGenericIE(AudiodraftBaseIE):
    IE_NAME = 'Audiodraft:generic'
    _VALID_URL = r'https?://www\.audiodraft\.com/contests/[^/#]+#entries&eid=(?P<id>\d+)'

    _TESTS = [{
        'url': 'https://www.audiodraft.com/contests/570-Score-A-Video-Surprise-Us#entries&eid=30138',
        'info_dict': {
            'id': '30138',
            'ext': 'mp3',
            'title': 'DROP in sound_V2',
            'uploader': 'TiagoSilva',
            'uploader_id': '19452',
            'average_rating': 4,
            'like_count': int,
        },
    }]

    def _real_extract(self, url):
        id = self._match_id(url)
        return self._audiodraft_extract_from_id(f'player_entry_{id}')
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/audiodraft.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import int_or_none


class AudiodraftIE(InfoExtractor):
    def _audiodraft_extract_from_id(self, player_entry_id):
        data_json = self._download_json(
            'https://www.audiodraft.com/scripts/general/player/getPlayerInfoNew.php', player_entry_id,
            headers={
                'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
                'X-Requested-With': 'XMLHttpRequest',
            }, data=f'id={player_entry_id}'.encode('utf-8'))

        return {
            'id': str(data_json['entry_id']),
            'title': data_json.get('entry_title'),
            'url': data_json['path'],
            'vcodec': 'none',
            'ext': 'mp3',
            'uploader': data_json.get('designer_name'),
            'uploader_id': data_json.get('designer_id'),
            'webpage_url': data_json.get('entry_url'),
            'like_count': int_or_none(data_json.get('entry_likes')),
            'average_rating': int_or_none(data_json.get('entry_rating')),
        }


class AudiodraftCustomIE(AudiodraftIE):
    IE_NAME = 'Audiodraft:custom'
    _VALID_URL = r'https?://(?:[A-Za-z0-9\-]+)\.audiodraft\.com/entry/(?P<id>\d+)'

Review comment (refactor):
The convention is for the same to end in `BaseIE`
```suggestion
class AudiodraftBaseIE(InfoExtractor):
```

Code after:
from .common import InfoExtractor
from ..utils import int_or_none


class AudiodraftBaseIE(InfoExtractor):
    def _audiodraft_extract_from_id(self, player_entry_id):
        data_json = self._download_json(
            'https://www.audiodraft.com/scripts/general/player/getPlayerInfoNew.php', player_entry_id,
            headers={
                'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
                'X-Requested-With': 'XMLHttpRequest',
            }, data=f'id={player_entry_id}'.encode('utf-8'))

        return {
            'id': str(data_json['entry_id']),
            'title': data_json.get('entry_title'),
            'url': data_json['path'],
            'vcodec': 'none',
            'ext': 'mp3',
            'uploader': data_json.get('designer_name'),
            'uploader_id': data_json.get('designer_id'),
            'webpage_url': data_json.get('entry_url'),
            'like_count': int_or_none(data_json.get('entry_likes')),
            'average_rating': int_or_none(data_json.get('entry_rating')),
        }


class AudiodraftCustomIE(AudiodraftBaseIE):
    IE_NAME = 'Audiodraft:custom'
    _VALID_URL = r'https?://(?:[-\w]+)\.audiodraft\.com/entry/(?P<id>\d+)'
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/theholetv.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import extract_attributes, remove_end


class TheHoleTvExtractorIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?the-hole\.tv/episodes/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://the-hole.tv/episodes/gromkii-vopros-sergey-orlov',
        'md5': 'fea6682f47786f3ae5a6cbd635ec4bf9',
        'info_dict': {
            'id': 'gromkii-vopros-sergey-orlov',
            'ext': 'mp4',
            'title': 'Сергей Орлов — Громкий вопрос',
            'thumbnail': 'https://assets-cdn.the-hole.tv/images/t8gan4n6zn627e7wni11b2uemqts',
            'description': 'md5:45741a9202331f995d9fb76996759379'
        }
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        player_attrs = extract_attributes(self._search_regex(
            r'(<div[^>]*\bdata-controller="player"[^>]*>)', webpage, 'video player'))
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
            player_attrs['data-player-source-value'], video_id, 'mp4')
        self._sort_formats(formats)

        return {
            'id': video_id,

Review comment (refactor):
```suggestion
class TheHoleTvIE(InfoExtractor):
```

Code after:
from .common import InfoExtractor
from ..utils import extract_attributes, remove_end


class TheHoleTvIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?the-hole\.tv/episodes/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://the-hole.tv/episodes/gromkii-vopros-sergey-orlov',
        'md5': 'fea6682f47786f3ae5a6cbd635ec4bf9',
        'info_dict': {
            'id': 'gromkii-vopros-sergey-orlov',
            'ext': 'mp4',
            'title': 'Сергей Орлов — Громкий вопрос',
            'thumbnail': 'https://assets-cdn.the-hole.tv/images/t8gan4n6zn627e7wni11b2uemqts',
            'description': 'md5:45741a9202331f995d9fb76996759379'
        }
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        player_attrs = extract_attributes(self._search_regex(
            r'(<div[^>]*\bdata-controller="player"[^>]*>)', webpage, 'video player'))
        formats, subtitles = self._extract_m3u8_formats_and_subtitles(
            player_attrs['data-player-source-value'], video_id, 'mp4')
        self._sort_formats(formats)

        return {
            'id': video_id,
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/_extractors.py (Python)

Code before:
    TedSeriesIE,
    TedTalkIE,
)
from .tele5 import Tele5IE
from .tele13 import Tele13IE
from .telebruxelles import TeleBruxellesIE
from .telecinco import TelecincoIE
from .telegraaf import TelegraafIE
from .telegram import TelegramEmbedIE
from .telemb import TeleMBIE
from .telemundo import TelemundoIE
from .telequebec import (
    TeleQuebecIE,
    TeleQuebecSquatIE,
    TeleQuebecEmissionIE,
    TeleQuebecLiveIE,
    TeleQuebecVideoIE,
)
from .teletask import TeleTaskIE
from .telewebion import TelewebionIE
from .tennistv import TennisTVIE
from .tenplay import TenPlayIE
from .testurl import TestURLIE
from .tf1 import TF1IE
from .tfo import TFOIE
from .theholetv import TheHoleTvExtractorIE
from .theintercept import TheInterceptIE
from .theplatform import (
    ThePlatformIE,
    ThePlatformFeedIE,
)
from .thestar import TheStarIE
from .thesun import TheSunIE
from .theta import (
    ThetaVideoIE,
    ThetaStreamIE,
)
from .theweatherchannel import TheWeatherChannelIE
from .thisamericanlife import ThisAmericanLifeIE
from .thisav import ThisAVIE
from .thisoldhouse import ThisOldHouseIE
from .threespeak import (
    ThreeSpeakIE,
    ThreeSpeakUserIE,
)
from .threeqsdn import ThreeQSDNIE
from .tiktok import (
    TikTokIE,
    TikTokUserIE,
    TikTokSoundIE,
    TikTokEffectIE,

Review comment (suggestion):
```suggestion
from .theholetv import TheHoleTvIE
```

Code after:
    TedSeriesIE,
    TedTalkIE,
)
from .tele5 import Tele5IE
from .tele13 import Tele13IE
from .telebruxelles import TeleBruxellesIE
from .telecinco import TelecincoIE
from .telegraaf import TelegraafIE
from .telegram import TelegramEmbedIE
from .telemb import TeleMBIE
from .telemundo import TelemundoIE
from .telequebec import (
    TeleQuebecIE,
    TeleQuebecSquatIE,
    TeleQuebecEmissionIE,
    TeleQuebecLiveIE,
    TeleQuebecVideoIE,
)
from .teletask import TeleTaskIE
from .telewebion import TelewebionIE
from .tennistv import TennisTVIE
from .tenplay import TenPlayIE
from .testurl import TestURLIE
from .tf1 import TF1IE
from .tfo import TFOIE
from .theholetv import TheHoleTvIE
from .theintercept import TheInterceptIE
from .theplatform import (
    ThePlatformIE,
    ThePlatformFeedIE,
)
from .thestar import TheStarIE
from .thesun import TheSunIE
from .theta import (
    ThetaVideoIE,
    ThetaStreamIE,
)
from .theweatherchannel import TheWeatherChannelIE
from .thisamericanlife import ThisAmericanLifeIE
from .thisav import ThisAVIE
from .thisoldhouse import ThisOldHouseIE
from .threespeak import (
    ThreeSpeakIE,
    ThreeSpeakUserIE,
)
from .threeqsdn import ThreeQSDNIE
from .tiktok import (
    TikTokIE,
    TikTokUserIE,
    TikTokSoundIE,
    TikTokEffectIE,
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/hytale.py (Python)

Code before:
from re import findall

from .common import InfoExtractor
from ..utils import traverse_obj


class HytaleIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?hytale\.com/news/20\d\d/(?:0?[1-9]|1[0-2])/(?P<id>[a-z0-9-]+)'
    _TESTS = [{
        'url': 'https://hytale.com/news/2021/07/summer-2021-development-update',
        'info_dict': {
            'id': 'summer-2021-development-update',
            'title': 'Summer 2021 Development Update',
        },
        'playlist_count': 4,
    }, {
        'url': 'https://www.hytale.com/news/2019/11/hytale-graphics-update',
        'info_dict': {
            'id': 'hytale-graphics-update',
            'title': 'Hytale graphics update',
        },
        'playlist_count': 2,
    }]

    _MD5_REGEX = r'<stream\s+class\s*=\s*"ql-video\s+cf-stream"\s+src\s*=\s*"([a-f0-9]{32})"'
    _VIDEO_BASE_URL = 'https://cloudflarestream.com/{}/manifest/video.mpd?parentOrigin=https%3A%2F%2Fhytale.com'

    _MEDIA_PAGE_URL = 'https://hytale.com/media'
    _MEDIA_START_PATTERN = r'window\.__INITIAL_COMPONENTS_STATE__\s*=\s*\['

    def _real_extract(self, url):
        playlist_id = self._match_id(url)


Review comment (suggestion):
```suggestion
    _VALID_URL = r'https?://(?:www\.)?hytale\.com/news/\d+/\d+/(?P<id>[a-z0-9-]+)'
```
There is no need for it to be so strict

Code after:
import re

from .common import InfoExtractor
from ..utils import traverse_obj


class HytaleIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?hytale\.com/news/\d+/\d+/(?P<id>[a-z0-9-]+)'
    _TESTS = [{
        'url': 'https://hytale.com/news/2021/07/summer-2021-development-update',
        'info_dict': {
            'id': 'summer-2021-development-update',
            'title': 'Summer 2021 Development Update',
        },
        'playlist_count': 4,
        'playlist': [{
            'md5': '0854ebe347d233ee19b86ab7b2ead610',
            'info_dict': {
                'id': 'ed51a2609d21bad6e14145c37c334999',
                'ext': 'mp4',
                'title': 'Avatar Personalization',
                'thumbnail': r're:https://videodelivery\.net/\w+/thumbnails/thumbnail\.jpg',
            }
        }]
    }, {
        'url': 'https://www.hytale.com/news/2019/11/hytale-graphics-update',
        'info_dict': {
            'id': 'hytale-graphics-update',
            'title': 'Hytale graphics update',
        },
        'playlist_count': 2,
    }]
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/wetv.py (Python)

Code before:
import re
import time
import urllib.parse

from yt_dlp import InfoExtractor
from yt_dlp.aes import aes_cbc_encrypt
from yt_dlp.compat import compat_ord, compat_str
from yt_dlp.utils import bytes_to_intlist, random_user_agent


class WeTvBaseIE(InfoExtractor):
    _VALID_URL_BASE = r'https?://(?:www\.)?wetv\.vip/(?:[^?#]+/)?play'

    def _get_ckey(self, video_id, url, app_version, platform):
        def get_payload_checksum(payload):
            checksum = 0
            for char in payload:
                checksum += compat_ord(char)
            return compat_str(checksum)

        payload_components = [
            '',
            video_id,
            str(int(time.time())),
            'mg3c3b04ba',
            app_version,
            '0000000000000000',  # guid
            platform,
            url[:48],
            random_user_agent().lower()[:48],  # user_agent
            ''[:48],  # referer
            'Mozilla',  # nav_code_name
            'Netscape',  # nav_name

Review comment (refactor):
```suggestion
from .common import InfoExtractor
from ..aes import aes_cbc_encrypt
from ..compat import compat_ord
from ..utils import bytes_to_intlist, random_user_agent
```
1. Use relative imports
2. Don't use `compat_str` but `str`

Code after:
import re
import time

from .common import InfoExtractor
from ..aes import aes_cbc_encrypt
from ..utils import bytes_to_intlist, determine_ext, intlist_to_bytes, int_or_none, traverse_obj


class WeTvBaseIE(InfoExtractor):
    _VALID_URL_BASE = r'https?://(?:www\.)?wetv\.vip/(?:[^?#]+/)?play'

    def _get_ckey(self, video_id, url, app_version, platform):
        ua = self.get_param('http_headers')['User-Agent']

        payload = (f'{video_id}|{int(time.time())}|mg3c3b04ba|{app_version}|0000000000000000|'
                   f'{platform}|{url[:48]}|{ua.lower()[:48]}||Mozilla|Netscape|Win32|00|')

        ciphertext_int_bytes = aes_cbc_encrypt(
            bytes_to_intlist(bytes(f'|{sum(map(ord, payload))}|{payload}', 'utf-8')),
            bytes_to_intlist(b'Ok\xda\xa3\x9e/\x8c\xb0\x7f^r-\x9e\xde\xf3\x14'),
            bytes_to_intlist(b'\x01PJ\xf3V\xe6\x19\xcf.B\xbb\xa6\x8c?p\xf9'),
            'whitespace')

        return intlist_to_bytes(ciphertext_int_bytes).hex()

    def _get_video_api_response(self, video_url, video_id, series_id, subtitle_format, video_format, video_quality):
        app_version = '3.5.57'
        platform = '4830201'

        ckey = self._get_ckey(video_id, video_url, app_version, platform)
        query = {
            'vid': video_id,
            'cid': series_id,
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/wetv.py (Python)

Code before:

    _TESTS = [{
        'url': 'https://wetv.vip/play/air11ooo2rdsdi3-Cute-Programmer',
        'info_dict': {
            'id': 'air11ooo2rdsdi3',
            'title': 'Cute Programmer',
            'description': 'md5:e87beab3bf9f392d6b9e541a63286343',
        },
        'playlist_count': 30,
    }, {
        'url': 'https://wetv.vip/en/play/u37kgfnfzs73kiu-You-Are-My-Glory',
        'info_dict': {
            'id': 'u37kgfnfzs73kiu',
            'title': 'You Are My Glory',
            'description': 'md5:831363a4c3b4d7615e1f3854be3a123b',
        },
        'playlist_count': 32,
    }]

    def _real_extract(self, url):
        series_id = self._match_id(url)
        webpage = self._download_webpage(url, series_id)
        webpage_metadata = self._get_webpage_metadata(webpage, series_id)

        episode_paths = (re.findall(r'<a[^>]+class="play-video__link"[^>]+href="(?P<path>[^"]+)', webpage)
                         or [f"/{series_id}/{episode['vid']}" for episode in webpage_metadata.get('videoList')])

        return self.playlist_from_matches(
            episode_paths, series_id, traverse_obj(webpage_metadata, ('coverInfo', 'title')) or self._og_search_title(webpage),
            description=traverse_obj(webpage_metadata, ('coverInfo', 'description')) or self._og_search_description(webpage),
            ie=WeTvEpisodeIE)


Review comment (suggestion):
```suggestion
                         or [f'/{series_id}/{episode["vid"]}' for episode in webpage_metadata.get('videoList')])
```

Code after:
        'url': 'https://wetv.vip/play/air11ooo2rdsdi3-Cute-Programmer',
        'info_dict': {
            'id': 'air11ooo2rdsdi3',
            'title': 'Cute Programmer',
            'description': 'md5:e87beab3bf9f392d6b9e541a63286343',
        },
        'playlist_count': 30,
    }, {
        'url': 'https://wetv.vip/en/play/u37kgfnfzs73kiu-You-Are-My-Glory',
        'info_dict': {
            'id': 'u37kgfnfzs73kiu',
            'title': 'You Are My Glory',
            'description': 'md5:831363a4c3b4d7615e1f3854be3a123b',
        },
        'playlist_count': 32,
    }]

    def _real_extract(self, url):
        series_id = self._match_id(url)
        webpage = self._download_webpage(url, series_id)
        webpage_metadata = self._get_webpage_metadata(webpage, series_id)

        episode_paths = (re.findall(r'<a[^>]+class="play-video__link"[^>]+href="(?P<path>[^"]+)', webpage)
                         or [f'/{series_id}/{episode["vid"]}' for episode in webpage_metadata.get('videoList')])

        return self.playlist_from_matches(
            episode_paths, series_id, ie=WeTvEpisodeIE,
            title=traverse_obj(webpage_metadata, ('coverInfo', 'title')) or self._og_search_title(webpage),
            description=traverse_obj(webpage_metadata, ('coverInfo', 'description')) or self._og_search_description(webpage))