{"record":{"id":"d5422b2c4405b324","repo":"ytdl-org/youtube-dl","slug":"s-said-s-d5422b","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/meta.py","lineNumber":52,"sourceCode":"        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        video_id = self._match_id(url)\n        webpage = self._download_webpage(url, video_id)\n\n        st_html5 = self._search_regex(\n            r\"st_html5\\s*=\\s*'#([^']+)'\", webpage, 'uppod html5 st', default=None)\n\n        if st_html5:\n            # uppod st decryption algorithm is reverse engineered from function un(s) at uppod.js\n            json_str = ''\n            for i in range(0, len(st_html5), 3):\n                json_str += '&#x0%s;' % st_html5[i:i + 3]\n            uppod_data = self._parse_json(unescapeHTML(json_str), video_id)\n            error = uppod_data.get('customnotfound')\n            if error:\n                raise ExtractorError('%s said: %s' % (self.IE_NAME, error), expected=True)\n\n            video_url = uppod_data['file']\n            info = {\n                'id': video_id,\n                'url': video_url,\n                'title': uppod_data.get('comment') or self._og_search_title(webpage),\n                'description': self._og_search_description(webpage, default=None),\n                'thumbnail': uppod_data.get('poster') or self._og_search_thumbnail(webpage),\n                'duration': int_or_none(self._og_search_property(\n                    'video:duration', webpage, default=None)),\n            }\n            if 'youtube.com/' in video_url:\n                info.update({\n                    '_type': 'url_transparent',\n                    'ie_key': 'Youtube',\n                })\n            return info\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/meta.py#L34-L70","documentation":"Raised by the Meta (meta.ua) extractor when the page embeds an uppod player whose decrypted 'st' configuration JSON contains a 'customnotfound' key. The uppod st blob is hex-escaped HTML entities decoded in the loop above; a customnotfound entry means the site's player itself declares the video gone. Expected=True.","triggerScenarios":"Page contains st_html5 (the '#hex' uppod parameter), it decrypts to valid JSON, and that JSON has a truthy 'customnotfound' value — typically a human-readable message such as 'video not found'.","commonSituations":"Video deleted from meta.ua storage; regional or copyright takedown causing the player config to swap the file entry for a customnotfound message; site template changes altering the uppod parameters.","solutions":["Open the page in a browser — the uppod player will display the same 'not found' message.","Search meta.ua for the content again; deleted files have no client-side recovery.","Update youtube-dl in case the uppod decryption or page structure changed, then retry with -v."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def uppod_custom_notfound(uppod_data):\n    return isinstance(uppod_data, dict) and bool(uppod_data.get('customnotfound'))","tryCatchPattern":"try:\n    info = ydl.extract_info(url, download=False)\nexcept ExtractorError as e:\n    if 'Meta said:' in str(e):\n        mark_video_removed(url)  # site's own player declared it gone\n    else:\n        raise","preventionTips":["Verify meta.ua videos still play in a browser before queueing.","Treat customnotfound as permanent; do not retry."],"tags":["uppod-player","decryption","expected-error"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}