{"record":{"id":"78c7015a77d8ba91","repo":"soimort/you-get","slug":"no-url","errorCode":null,"errorMessage":"No url","messagePattern":"No url","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/you_get/extractors/youku.py","lineNumber":131,"sourceCode":"        # at least a little more recoverable from HTTP 403\n        if cls.dispatcher_url in url:\n            return url\n        elif 'k.youku.com' in url:\n            return url\n        else:\n            url_seg_list = list(urllib.parse.urlsplit(url))\n            url_seg_list[1] = cls.dispatcher_url\n            return urllib.parse.urlunsplit(url_seg_list)\n\n    def get_vid_from_url(self):\n        # It's unreliable. check #1633\n        b64p = r'([a-zA-Z0-9=]+)'\n        p_list = [r'youku\\.com/v_show/id_'+b64p,\n                  r'player\\.youku\\.com/player\\.php/sid/'+b64p+r'/v\\.swf',\n                  r'loader\\.swf\\?VideoIDS='+b64p,\n                  r'player\\.youku\\.com/embed/'+b64p]\n        if not self.url:\n            raise Exception('No url')\n        for p in p_list:\n            hit = re.search(p, self.url)\n            if hit is not None:\n                self.vid = hit.group(1)\n                return\n\n    def get_vid_from_page(self):\n        if not self.url:\n            raise Exception('No url')\n        self.page = get_content(self.url)\n        hit = re.search(r'videoId2:\"([A-Za-z0-9=]+)\"', self.page)\n        if hit is not None:\n            self.vid = hit.group(1)\n\n    def prepare(self, **kwargs):\n        assert self.url or self.vid\n\n        if self.url and not self.vid:","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/soimort/you-get/blob/049548f3f3f35e67ba8d3181c71fdc71d11cf260/src/you_get/extractors/youku.py#L113-L149","documentation":"YoukuExtractor.get_vid_from_url dereferences self.url to regex out the video id from four known URL shapes; if self.url is None/empty (caller constructed the extractor with only a vid, or nothing at all) it raises Exception('No url') as a precondition guard before any pattern matching.","triggerScenarios":"Instantiating YoukuExtractor() and calling get_vid_from_url() without passing a URL (e.g. vid supplied separately or neither), or calling it manually after url was never set; prepare() itself guards with assert self.url or self.vid, so reaching this raise means an internal/manual call path.","commonSituations":"Programmatic use of the extractor class where the caller sets .vid but a stale code path still calls get_vid_from_url; subclass overrides skipping initialization; library misuse calling private methods directly.","solutions":["Pass the URL when constructing: YoukuExtractor('https://v.youku.com/v_show/id_X.html')","Or set extractor.url before calling get_vid_from_url","Skip the call entirely when you already have self.vid — mirror prepare()'s 'if self.url and not self.vid' condition","Wrap extraction in prepare(), which handles the url-or-vid precondition itself"],"exampleFix":"# before\nextractor = YoukuExtractor()\nextractor.get_vid_from_url()  # Exception: No url\n\n# after\nextractor = YoukuExtractor('https://v.youku.com/v_show/id_XNTQwMzg4OTA0.html')\nextractor.prepare()  # resolves vid from url internally","handlingStrategy":"type-guard","validationCode":"def youku_has_url(extractor):\n    return bool(getattr(extractor, 'url', None))","typeGuard":"def can_resolve_from_url(extractor) -> bool:\n    return bool(extractor.url) and extractor.vid is None","tryCatchPattern":"try:\n    extractor.get_vid_from_url()\nexcept Exception as e:\n    if str(e) == 'No url':\n        raise RuntimeError('construct YoukuExtractor with a URL, or set .url first') from e\n    raise","preventionTips":["Always construct YoukuExtractor(url) or set .url before calling vid-resolution helpers","Drive the extractor through prepare(), which checks url-or-vid itself","Skip get_vid_from_url when .vid is already populated"],"tags":["youku","precondition","extractor-api","misuse"],"backgroundTag":null,"analyzedSha":"049548f3f3f35e67ba8d3181c71fdc71d11cf260","analyzedAt":"2026-08-15T03:58:15.069Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}