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

Code before:
                'id': '2664592',
                'title': 'VideoDowcipy - wszystkie odcinki',
            },
            'playlist_count': 71,
        },
        {
            'url': 'https://www.cda.pl/DeliciousBeauty/folder/19129979/vfilm',
            'info_dict': {
                'id': '19129979',
                'title': 'TESTY KOSMETYKÓW',
            },
            'playlist_count': 139,
        }]

    def _real_extract(self, url):
        folder_id = self._match_id(url)
        channel_name = self._search_regex(
            r'cda\.pl/([^/]+)', url, 'channel name')

        webpage = self._download_webpage(url, folder_id)

        title = self._og_search_title(webpage)

        def extract_page_entries(channel_name, folder_id, page):
            url = f'https://www.cda.pl/{channel_name}/folder/{folder_id}/vfilm/{page+1}'
            webpage = self._download_webpage(url, folder_id, f'Extracting videos list from {url}')
            items = re.findall(r'<a[^>]+href="/video/([0-9a-z]+)" class=', webpage)
            for video_id in items:
                yield self.url_result(f'https://www.cda.pl/video/{video_id}', CDAIE.ie_key(), video_id)

        entries = OnDemandPagedList(
            functools.partial(extract_page_entries, channel_name, folder_id),
            self._MAX_PAGE_SIZE)

        return self.playlist_result(entries, folder_id, playlist_title=title)


Review comment (suggestion):
Need to catch 404s, in case the last page contains 36 videos.
```suggestion
            webpage = self._download_webpage(
                f'https://www.cda.pl/{channel_name}/folder/{folder_id}/vfilm/{page + 1}', folder_id,
                f'Downloading page {page + 1}', expected_status=404)
```

Code after:
            },
            'playlist_mincount': 71,
        },
        {
            'url': 'https://www.cda.pl/DeliciousBeauty/folder/19129979/vfilm',
            'info_dict': {
                'id': '19129979',
                'title': 'TESTY KOSMETYKÓW',
            },
            'playlist_mincount': 139,
        }]

    def _real_extract(self, url):
        folder_id, channel = self._match_valid_url(url).group('id', 'channel')

        webpage = self._download_webpage(url, folder_id)

        def extract_page_entries(page):
            webpage = self._download_webpage(
                f'https://www.cda.pl/{channel}/folder/{folder_id}/vfilm/{page + 1}', folder_id,
                f'Downloading page {page + 1}', expected_status=404)
            items = re.findall(r'<a[^>]+href="/video/([0-9a-z]+)"', webpage)
            for video_id in items:
                yield self.url_result(f'https://www.cda.pl/video/{video_id}', CDAIE, video_id)

        return self.playlist_result(
            OnDemandPagedList(extract_page_entries, self._MAX_PAGE_SIZE),
            folder_id, self._og_search_title(webpage))
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/rtp.py (Python)

Code before:
import base64
import json
import re
import urllib.parse

from .common import InfoExtractor
from ..utils import js_to_json


class RTPIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play(/zigzag)?/p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)/?'
    _TESTS = [{
        'url': 'http://www.rtp.pt/play/p405/e174042/paixoes-cruzadas',
        'md5': 'e736ce0c665e459ddb818546220b4ef8',
        'info_dict': {
            'id': 'e174042',
            'ext': 'mp3',
            'title': 'Paixões Cruzadas',
            'description': 'As paixões musicais de António Cartaxo e António Macedo',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'https://www.rtp.pt/play/zigzag/p13166/e757904/25-curiosidades-25-de-abril',
        'md5': '9a81ed53f2b2197cfa7ed455b12f8ade',
        'info_dict': {
            'id': 'e757904',
            'ext': 'mp4',
            'title': '25 Curiosidades, 25 de Abril',
            'description': 'Estudar ou não estudar - Em cada um dos episódios descobrimos uma curiosidade acerca de como era viver em Portugal antes da revolução do 25 de abr',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'http://www.rtp.pt/play/p831/a-quimica-das-coisas',
        'only_matching': True,
    }]


Review comment (suggestion):
```suggestion
    _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play/(?:zigzag/)?p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)/?'
```

Code after:
import base64
import json
import re
import urllib.parse

from .common import InfoExtractor
from ..utils import js_to_json


class RTPIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play/(?:(?:estudoemcasa|palco|zigzag)/)?p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)'
    _TESTS = [{
        'url': 'http://www.rtp.pt/play/p405/e174042/paixoes-cruzadas',
        'md5': 'e736ce0c665e459ddb818546220b4ef8',
        'info_dict': {
            'id': 'e174042',
            'ext': 'mp3',
            'title': 'Paixões Cruzadas',
            'description': 'As paixões musicais de António Cartaxo e António Macedo',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'https://www.rtp.pt/play/zigzag/p13166/e757904/25-curiosidades-25-de-abril',
        'md5': '9a81ed53f2b2197cfa7ed455b12f8ade',
        'info_dict': {
            'id': 'e757904',
            'ext': 'mp4',
            'title': '25 Curiosidades, 25 de Abril',
            'description': 'Estudar ou não estudar - Em cada um dos episódios descobrimos uma curiosidade acerca de como era viver em Portugal antes da revolução do 25 de abr',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'http://www.rtp.pt/play/p831/a-quimica-das-coisas',
        'only_matching': True,
    }, {
        'url': 'https://www.rtp.pt/play/estudoemcasa/p7776/portugues-1-ano',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/rtp.py (Python)

Code before:
import base64
import json
import re
import urllib.parse

from .common import InfoExtractor
from ..utils import js_to_json


class RTPIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play/(?:zigzag/)?p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)/?'
    _TESTS = [{
        'url': 'http://www.rtp.pt/play/p405/e174042/paixoes-cruzadas',
        'md5': 'e736ce0c665e459ddb818546220b4ef8',
        'info_dict': {
            'id': 'e174042',
            'ext': 'mp3',
            'title': 'Paixões Cruzadas',
            'description': 'As paixões musicais de António Cartaxo e António Macedo',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'https://www.rtp.pt/play/zigzag/p13166/e757904/25-curiosidades-25-de-abril',
        'md5': '9a81ed53f2b2197cfa7ed455b12f8ade',
        'info_dict': {
            'id': 'e757904',
            'ext': 'mp4',
            'title': '25 Curiosidades, 25 de Abril',
            'description': 'Estudar ou não estudar - Em cada um dos episódios descobrimos uma curiosidade acerca de como era viver em Portugal antes da revolução do 25 de abr',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'http://www.rtp.pt/play/p831/a-quimica-das-coisas',
        'only_matching': True,
    }]


Review comment (suggestion):
Can you add `estudoemcasa` and `palco` as well?
```suggestion
    _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play/(?:(?:estudoemcasa|palco|zigzag)/)?p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)'
```
Please also add appropriate tests. match_only is fine.
 - https://www.rtp.pt/play/estudoemcasa/p7776/portugues-1-ano
 - https://www.rtp.pt/play/palco/p13785/l7nnon

Code after:
import base64
import json
import re
import urllib.parse

from .common import InfoExtractor
from ..utils import js_to_json


class RTPIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?rtp\.pt/play/(?:(?:estudoemcasa|palco|zigzag)/)?p(?P<program_id>[0-9]+)/(?P<id>[^/?#]+)'
    _TESTS = [{
        'url': 'http://www.rtp.pt/play/p405/e174042/paixoes-cruzadas',
        'md5': 'e736ce0c665e459ddb818546220b4ef8',
        'info_dict': {
            'id': 'e174042',
            'ext': 'mp3',
            'title': 'Paixões Cruzadas',
            'description': 'As paixões musicais de António Cartaxo e António Macedo',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'https://www.rtp.pt/play/zigzag/p13166/e757904/25-curiosidades-25-de-abril',
        'md5': '9a81ed53f2b2197cfa7ed455b12f8ade',
        'info_dict': {
            'id': 'e757904',
            'ext': 'mp4',
            'title': '25 Curiosidades, 25 de Abril',
            'description': 'Estudar ou não estudar - Em cada um dos episódios descobrimos uma curiosidade acerca de como era viver em Portugal antes da revolução do 25 de abr',
            'thumbnail': r're:^https?://.*\.jpg',
        },
    }, {
        'url': 'http://www.rtp.pt/play/p831/a-quimica-das-coisas',
        'only_matching': True,
    }, {
        'url': 'https://www.rtp.pt/play/estudoemcasa/p7776/portugues-1-ano',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/pialive.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import extract_attributes, multipart_encode, traverse_obj, url_or_none


class PiaLiveIE(InfoExtractor):
    PLAYER_ROOT_URL = 'https://player.pia-live.jp/'
    PIA_LIVE_API_URL = 'https://api.pia-live.jp'
    _VALID_URL = r'https?://player\.pia-live\.jp/stream/(?P<id>[\w-]+)'

    _TESTS = [
        {
            'url': 'https://player.pia-live.jp/stream/4JagFBEIM14s_hK9aXHKf3k3F3bY5eoHFQxu68TC6krUDqGOwN4d61dCWQYOd6CTxl4hjya9dsfEZGsM4uGOUdax60lEI4twsXGXf7crmz8Gk__GhupTrWxA7RFRVt76',
            'info_dict': {
                'id': '88f3109a-f503-4d0f-a9f7-9f39ac745d84',
                'display_id': '2431867_001',
                'title': 'こながめでたい日２０２４の視聴ページ | PIA LIVE STREAM(ぴあライブストリーム)',
                'live_status': 'was_live',
                'comment_count': int,
            },
            'params': {
                'getcomments': True,
                'skip_download': True,
                'ignore_no_formats_error': True,
            },
        },
        {
            'url': 'https://player.pia-live.jp/stream/4JagFBEIM14s_hK9aXHKf3k3F3bY5eoHFQxu68TC6krJdu0GVBVbVy01IwpJ6J3qBEm3d9TCTt1d0eWpsZGj7DrOjVOmS7GAWGwyscMgiThopJvzgWC4H5b-7XQjAfRZ',

Review comment (refactor):
```suggestion
from ..utils import extract_attributes, multipart_encode, url_or_none
from ..utils.traversal import traverse_obj
```

Code after:
from .common import InfoExtractor
from ..utils import (
    ExtractorError,
    clean_html,
    extract_attributes,
    get_element_by_class,
    get_element_html_by_class,
    multipart_encode,
    str_or_none,
    unified_timestamp,
    url_or_none,
)
from ..utils.traversal import traverse_obj


class PiaLiveIE(InfoExtractor):
    _VALID_URL = r'https?://player\.pia-live\.jp/stream/(?P<id>[\w-]+)'
    _PLAYER_ROOT_URL = 'https://player.pia-live.jp/'
    _PIA_LIVE_API_URL = 'https://api.pia-live.jp'
    _API_KEY = 'kfds)FKFps-dms9e'
    _TESTS = [{
        'url': 'https://player.pia-live.jp/stream/4JagFBEIM14s_hK9aXHKf3k3F3bY5eoHFQxu68TC6krUDqGOwN4d61dCWQYOd6CTxl4hjya9dsfEZGsM4uGOUdax60lEI4twsXGXf7crmz8Gk__GhupTrWxA7RFRVt76',
        'info_dict': {
            'id': '88f3109a-f503-4d0f-a9f7-9f39ac745d84',
            'display_id': '2431867_001',
            'title': 'こながめでたい日２０２４の視聴ページ | PIA LIVE STREAM(ぴあライブストリーム)',
            'live_status': 'was_live',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/_extractors.py (Python)

Code before:
from .pearvideo import PearVideoIE
from .peekvids import (
    PeekVidsIE,
    PlayVidsIE,
)
from .peertube import (
    PeerTubeIE,
    PeerTubePlaylistIE,
)
from .peertv import PeerTVIE
from .peloton import (
    PelotonIE,
    PelotonLiveIE,
)
from .performgroup import PerformGroupIE
from .periscope import (
    PeriscopeIE,
    PeriscopeUserIE,
)
from .pgatour import PGATourIE
from .philharmoniedeparis import PhilharmonieDeParisIE
from .phoenix import PhoenixIE
from .photobucket import PhotobucketIE
from .pialive import PiaLiveIE
from .piapro import PiaproIE
from .piaulizaportal import PIAULIZAPortalAPIIE, PIAULIZAPortalIE
from .picarto import (
    PicartoIE,
    PicartoVodIE,
)
from .piksel import PikselIE
from .pinkbike import PinkbikeIE
from .pinterest import (
    PinterestCollectionIE,
    PinterestIE,
)
from .pixivsketch import (
    PixivSketchIE,
    PixivSketchUserIE,
)
from .pladform import PladformIE
from .planetmarathi import PlanetMarathiIE
from .platzi import (
    PlatziCourseIE,
    PlatziIE,
)
from .playplustv import PlayPlusTVIE
from .playsuisse import PlaySuisseIE
from .playtvak import PlaytvakIE
from .playwire import PlaywireIE
from .pluralsight import (

Review comment (suggestion):
```suggestion
from .piaulizaportal import (
    PIAULIZAPortalAPIIE,
    PIAULIZAPortalIE,
)
```

Code after:
from .parler import ParlerIE
from .parlview import ParlviewIE
from .patreon import (
    PatreonCampaignIE,
    PatreonIE,
)
from .pbs import (
    PBSIE,
    PBSKidsIE,
)
from .pearvideo import PearVideoIE
from .peekvids import (
    PeekVidsIE,
    PlayVidsIE,
)
from .peertube import (
    PeerTubeIE,
    PeerTubePlaylistIE,
)
from .peertv import PeerTVIE
from .peloton import (
    PelotonIE,
    PelotonLiveIE,
)
from .performgroup import PerformGroupIE
from .periscope import (
    PeriscopeIE,
    PeriscopeUserIE,
)
from .pgatour import PGATourIE
from .philharmoniedeparis import PhilharmonieDeParisIE
from .phoenix import PhoenixIE
from .photobucket import PhotobucketIE
from .pialive import PiaLiveIE
from .piapro import PiaproIE
from .picarto import (
    PicartoIE,
    PicartoVodIE,
)
from .piksel import PikselIE
from .pinkbike import PinkbikeIE
from .pinterest import (
    PinterestCollectionIE,
    PinterestIE,
)
from .pixivsketch import (
    PixivSketchIE,
    PixivSketchUserIE,
)
from .pladform import PladformIE
from .planetmarathi import PlanetMarathiIE
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/dailymotion.py (Python)

Code before:
import functools
import json
import re
import urllib.parse

from .common import InfoExtractor
from ..networking.exceptions import HTTPError
from ..utils import (
    ExtractorError,
    OnDemandPagedList,
    age_restricted,
    clean_html,
    extract_attributes,
    int_or_none,
    traverse_obj,
    try_get,
    unescapeHTML,
    unsmuggle_url,
    url_or_none,
    urlencode_postdata,
)


class DailymotionBaseInfoExtractor(InfoExtractor):
    _FAMILY_FILTER = None
    _HEADERS = {
        'Content-Type': 'application/json',
        'Origin': 'https://www.dailymotion.com',
    }
    _NETRC_MACHINE = 'dailymotion'

    def _get_dailymotion_cookies(self):
        return self._get_cookies('https://www.dailymotion.com/')

    @staticmethod
    def _get_cookie_value(cookies, name):
        cookie = cookies.get(name)
        if cookie:
            return cookie.value

    def _set_dailymotion_cookie(self, name, value):
        self._set_cookie('www.dailymotion.com', name, value)

    def _real_initialize(self):
        cookies = self._get_dailymotion_cookies()

Review comment (suggestion):
```suggestion
    update_url,
    url_or_none,
```

Code after:
import functools
import json
import re
import urllib.parse

from .common import InfoExtractor
from ..networking.exceptions import HTTPError
from ..utils import (
    ExtractorError,
    OnDemandPagedList,
    age_restricted,
    clean_html,
    extract_attributes,
    int_or_none,
    traverse_obj,
    try_get,
    unescapeHTML,
    unsmuggle_url,
    update_url,
    url_or_none,
    urlencode_postdata,
)


class DailymotionBaseInfoExtractor(InfoExtractor):
    _FAMILY_FILTER = None
    _HEADERS = {
        'Content-Type': 'application/json',
        'Origin': 'https://www.dailymotion.com',
    }
    _NETRC_MACHINE = 'dailymotion'

    def _get_dailymotion_cookies(self):
        return self._get_cookies('https://www.dailymotion.com/')

    @staticmethod
    def _get_cookie_value(cookies, name):
        cookie = cookies.get(name)
        if cookie:
            return cookie.value

    def _set_dailymotion_cookie(self, name, value):
        self._set_cookie('www.dailymotion.com', name, value)

    def _real_initialize(self):
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/applepodcasts.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import (
    clean_podcast_url,
    get_element_by_id,
    parse_iso8601,
    traverse_obj,
)


class ApplePodcastsIE(InfoExtractor):
    _VALID_URL = r'https?://podcasts\.apple\.com/(?:[^/]+/)?podcast(?:/[^/]+){1,2}.*?\bi=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://podcasts.apple.com/us/podcast/ferreck-dawn-to-the-break-of-dawn-117/id1625658232?i=1000665010654',
        'md5': '82cc219b8cc1dcf8bfc5a5e99b23b172',
        'info_dict': {
            'id': '1000665010654',
            'ext': 'mp3',
            'title': 'Ferreck Dawn - To The Break of Dawn 117',
            'episode': 'Ferreck Dawn - To The Break of Dawn 117',
            'description': 'md5:1fc571102f79dbd0a77bfd71ffda23bc',
            'upload_date': '20240812',
            'timestamp': 1723449600,
            'duration': 3596,
            'series': 'Ferreck Dawn - To The Break of Dawn',
            'thumbnail': 're:.+[.](png|jpe?g|webp)',
        },
    }, {
        'url': 'https://podcasts.apple.com/us/podcast/207-whitney-webb-returns/id1135137367?i=1000482637777',
        'md5': 'baf8a6b8b8aa6062dbb4639ed73d0052',
        'info_dict': {
            'id': '1000482637777',
            'ext': 'mp3',

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

Code after:
from .common import InfoExtractor
from ..utils import (
    clean_podcast_url,
    int_or_none,
    parse_iso8601,
)
from ..utils.traversal import traverse_obj


class ApplePodcastsIE(InfoExtractor):
    _VALID_URL = r'https?://podcasts\.apple\.com/(?:[^/]+/)?podcast(?:/[^/]+){1,2}.*?\bi=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://podcasts.apple.com/us/podcast/ferreck-dawn-to-the-break-of-dawn-117/id1625658232?i=1000665010654',
        'md5': '82cc219b8cc1dcf8bfc5a5e99b23b172',
        'info_dict': {
            'id': '1000665010654',
            'ext': 'mp3',
            'title': 'Ferreck Dawn - To The Break of Dawn 117',
            'episode': 'Ferreck Dawn - To The Break of Dawn 117',
            'description': 'md5:1fc571102f79dbd0a77bfd71ffda23bc',
            'upload_date': '20240812',
            'timestamp': 1723449600,
            'duration': 3596,
            'series': 'Ferreck Dawn - To The Break of Dawn',
            'thumbnail': 're:.+[.](png|jpe?g|webp)',
        },
    }, {
        'url': 'https://podcasts.apple.com/us/podcast/207-whitney-webb-returns/id1135137367?i=1000482637777',
        'md5': 'baf8a6b8b8aa6062dbb4639ed73d0052',
        'info_dict': {
            'id': '1000482637777',
            'ext': 'mp3',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/manyvids.py (Python)

Code before:
from .common import InfoExtractor
from .. import traverse_obj
from ..utils import (
    determine_ext,
    int_or_none,
    parse_count,
    parse_duration,
    parse_iso8601,
    url_or_none,
)


class ManyVidsIE(InfoExtractor):
    _VALID_URL = r'(?i)https?://(?:www\.)?manyvids\.com/video/(?P<id>\d+)'
    _TESTS = [{
        # Dead preview video
        'skip': True,
        'url': 'https://www.manyvids.com/Video/133957/everthing-about-me/',
        'md5': '03f11bb21c52dd12a05be21a5c7dcc97',
        'info_dict': {
            'id': '133957',
            'ext': 'mp4',
            'title': 'everthing about me (Preview)',
            'uploader': 'ellyxxix',
            'view_count': int,
            'like_count': int,
        },

Review comment (refactor):
move this to the bottom of the imports like this:
```py
from ..utils.traversal import traverse_obj
```
```suggestion
```

Code after:
from .common import InfoExtractor
from ..utils import (
    clean_html,
    determine_ext,
    int_or_none,
    join_nonempty,
    parse_count,
    parse_duration,
    parse_iso8601,
    url_or_none,
)
from ..utils.traversal import traverse_obj


class ManyVidsIE(InfoExtractor):
    _VALID_URL = r'(?i)https?://(?:www\.)?manyvids\.com/video/(?P<id>\d+)'
    _TESTS = [{
        # preview video
        'url': 'https://www.manyvids.com/Video/530341/mv-tips-tricks',
        'md5': '738dc723f7735ee9602f7ea352a6d058',
        'info_dict': {
            'id': '530341-preview',
            'ext': 'mp4',
            'title': 'MV Tips & Tricks (Preview)',
            'description': r're:I will take you on a tour around .{1313}$',
            'thumbnail': r're:https://cdn5\.manyvids\.com/php_uploads/video_images/DestinyDiaz/.+\.jpg',
            'uploader': 'DestinyDiaz',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/manyvids.py (Python)

Code before:
from .common import InfoExtractor
from .. import traverse_obj
from ..utils import (
    determine_ext,
    int_or_none,
    parse_count,
    parse_duration,
    parse_iso8601,
    url_or_none,
)


class ManyVidsIE(InfoExtractor):
    _VALID_URL = r'(?i)https?://(?:www\.)?manyvids\.com/video/(?P<id>\d+)'
    _TESTS = [{
        # Dead preview video
        'skip': True,
        'url': 'https://www.manyvids.com/Video/133957/everthing-about-me/',
        'md5': '03f11bb21c52dd12a05be21a5c7dcc97',
        'info_dict': {
            'id': '133957',
            'ext': 'mp4',
            'title': 'everthing about me (Preview)',
            'uploader': 'ellyxxix',
            'view_count': int,
            'like_count': int,
        },
    }, {
        # preview video
        'url': 'https://www.manyvids.com/Video/530341/mv-tips-tricks',
        'md5': '738dc723f7735ee9602f7ea352a6d058',
        'info_dict': {
            'id': '530341',
            'ext': 'mp4',
            'title': 'MV Tips &amp; Tricks (Preview)',
            'description': 'md5:c3bae98c0f9453237c28b0f8795d9f83',

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

Code after:
from .common import InfoExtractor
from ..utils import (
    clean_html,
    determine_ext,
    int_or_none,
    join_nonempty,
    parse_count,
    parse_duration,
    parse_iso8601,
    url_or_none,
)
from ..utils.traversal import traverse_obj


class ManyVidsIE(InfoExtractor):
    _VALID_URL = r'(?i)https?://(?:www\.)?manyvids\.com/video/(?P<id>\d+)'
    _TESTS = [{
        # preview video
        'url': 'https://www.manyvids.com/Video/530341/mv-tips-tricks',
        'md5': '738dc723f7735ee9602f7ea352a6d058',
        'info_dict': {
            'id': '530341-preview',
            'ext': 'mp4',
            'title': 'MV Tips & Tricks (Preview)',
            'description': r're:I will take you on a tour around .{1313}$',
            'thumbnail': r're:https://cdn5\.manyvids\.com/php_uploads/video_images/DestinyDiaz/.+\.jpg',
            'uploader': 'DestinyDiaz',
            'view_count': int,
            'like_count': int,
            'release_timestamp': 1508419904,
            'tags': ['AdultSchool', 'BBW', 'SFW', 'TeacherFetish'],
            'release_date': '20171019',
            'duration': 3167.0,
        },
        'expected_warnings': ['Only extracting preview'],
    }, {