{"record":{"id":"941e3f25ae4429d0","repo":"ytdl-org/youtube-dl","slug":"s-said-s-941e3f","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/pornhd.py","lineNumber":74,"sourceCode":"        title = self._html_search_regex(\n            [r'<span[^>]+class=[\"\\']video-name[\"\\'][^>]*>([^<]+)',\n             r'<title>(.+?) - .*?[Pp]ornHD.*?</title>'], webpage, 'title')\n\n        sources = self._parse_json(js_to_json(self._search_regex(\n            r\"(?s)sources'?\\s*[:=]\\s*(\\{.+?\\})\",\n            webpage, 'sources', default='{}')), video_id)\n\n        info = {}\n        if not sources:\n            entries = self._parse_html5_media_entries(url, webpage, video_id)\n            if entries:\n                info = entries[0]\n\n        if not sources and not info:\n            message = self._html_search_regex(\n                r'(?s)<(div|p)[^>]+class=\"no-video\"[^>]*>(?P<value>.+?)</\\1',\n                webpage, 'error message', group='value')\n            raise ExtractorError('%s said: %s' % (self.IE_NAME, message), expected=True)\n\n        formats = []\n        for format_id, video_url in sources.items():\n            video_url = urljoin(url, video_url)\n            if not video_url:\n                continue\n            height = int_or_none(self._search_regex(\n                r'^(\\d+)[pP]', format_id, 'height', default=None))\n            formats.append({\n                'url': video_url,\n                'ext': determine_ext(video_url, 'mp4'),\n                'format_id': format_id,\n                'height': height,\n            })\n        if formats:\n            info['formats'] = formats\n        self._sort_formats(info['formats'])\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/pornhd.py#L56-L92","documentation":"PornHdIE raises ExtractorError('%s said: %s' % (IE_NAME, message), expected=True) when the video page yields neither a 'sources' JSON object nor any parseable HTML5 <video> entries, and the page instead contains an element (div or p) with class 'no-video'. The message interpolated into the error is the text scraped from that no-video block, so the actual wording comes from the site (typically 'video has been removed' style notices).","triggerScenarios":"Extracting a pornhd.com video URL whose content was taken down or is region-blocked: sources JSON is empty/absent, _parse_html5_media_entries returns nothing, and the regex '(?s)<(div|p)[^>]+class=\"no-video\"...' matches. If the no-video block itself is missing, _html_search_regex raises a different 'unable to extract error message' error instead.","commonSituations":"Dead/removed video links from old playlists; DMCA takedowns; geo-restrictions rendering the player empty; site template changes that rename the no-video class (then the inner regex fails first).","solutions":["Open the URL in a browser to read the actual no-video message (removed, private, region-locked) and act accordingly.","If region-blocked, route through an egress point where the video is available.","Remove the dead entry from your queue/playlist and retry the remainder of the batch.","Update youtube-dl — if the site changed its markup, a newer extractor revision may parse sources correctly again."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    info = ydl.extract_info(url)\nexcept ExtractorError as e:\n    if 'PornHD said:' in str(e):\n        mark_dead(url)  # content removed; drop from queue","preventionTips":["Treat any '... said:' expected error as terminal for that URL — do not retry.","Scrub playlists of removed videos periodically.","Log the site message; it distinguishes removal from geo-blocking."],"tags":["pornhd","content-removed","html-scraping","expected-error"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}