{"record":{"id":"638e6be816a3fb5e","repo":"ytdl-org/youtube-dl","slug":"s-said-s-638e6b","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/vvvvid.py","lineNumber":102,"sourceCode":"\n    def _real_initialize(self):\n        self._conn_id = self._download_json(\n            'https://www.vvvvid.it/user/login',\n            None, headers=self.geo_verification_headers())['data']['conn_id']\n\n    def _download_info(self, show_id, path, video_id, fatal=True, query=None):\n        q = {\n            'conn_id': self._conn_id,\n        }\n        if query:\n            q.update(query)\n        response = self._download_json(\n            'https://www.vvvvid.it/vvvvid/ondemand/%s/%s' % (show_id, path),\n            video_id, headers=self.geo_verification_headers(), query=q, fatal=fatal)\n        if not (response or fatal):\n            return\n        if response.get('result') == 'error':\n            raise ExtractorError('%s said: %s' % (\n                self.IE_NAME, response['message']), expected=True)\n        return response['data']\n\n    def _extract_common_video_info(self, video_data):\n        return {\n            'thumbnail': video_data.get('thumbnail'),\n            'episode_id': str_or_none(video_data.get('id')),\n        }\n\n    def _real_extract(self, url):\n        show_id, season_id, video_id = re.match(self._VALID_URL, url).groups()\n\n        response = self._download_info(\n            show_id, 'season/%s' % season_id,\n            video_id, query={'video_id': video_id})\n\n        vid = int(video_id)\n        video_data = list(filter(","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/vvvvid.py#L84-L120","documentation":"Raised by the VVVVID extractor's _download_info helper when the on-demand API (https://www.vvvvid.it/vvvvid/ondemand/...) returns a JSON object with result == 'error'. The API includes a message field which is forwarded with the extractor name; typical causes are geo-restriction to Italy, expired episodes, or invalid show/season IDs.","triggerScenarios":"Any VVVVID API call whose response JSON has response['result'] == 'error'; _download_info is used for show, season, and video metadata, so bad IDs or unavailable content produce it.","commonSituations":"Accessing VVVVID (Italian streaming service) from outside Italy; following links to episodes whose rights have lapsed; malformed URLs where season_id or video_id does not exist.","solutions":["Read the forwarded 'VVVVID said: ...' message for the exact cause.","If geo-related, use an Italian IP or accept the content is unavailable in your region.","Verify the show/season/video IDs in the URL against the site.","Pass cookies with --cookies if the content requires authentication."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    info = ydl.extract_info(url)\nexcept ExtractorError as e:\n    if str(e).startswith('VVVVID said:'):\n        msg = str(e).split('said:', 1)[1].strip()\n        if 'geo' in msg.lower():\n            mark_geo_blocked(url)\n        else:\n            log_skip(url, msg)\n    else:\n        raise","preventionTips":["Use an Italian IP for VVVVID extraction in automated pipelines.","Validate show/season IDs against the site before bulk runs.","Cache successful extractions so geo-blocked retries are minimized."],"tags":["geo-restriction","api-error","extractor","vvvvid"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}