{"record":{"id":"cac4f6b9a244ad87","repo":"ytdl-org/youtube-dl","slug":"this-live-stream-has-already-finished","errorCode":null,"errorMessage":"This live stream has already finished.","messagePattern":"This live stream has already finished\\.","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/laola1tv.py","lineNumber":130,"sourceCode":"\n        return {\n            'id': video_id,\n            'title': self._live_title(title) if is_live else title,\n            'upload_date': unified_strdate(_v('time_date')),\n            'uploader': _v('meta_organisation'),\n            'categories': categories,\n            'is_live': is_live,\n            'formats': formats,\n        }\n\n\nclass Laola1TvBaseIE(Laola1TvEmbedIE):\n    def _extract_video(self, url):\n        display_id = self._match_id(url)\n        webpage = self._download_webpage(url, display_id)\n\n        if 'Dieser Livestream ist bereits beendet.' in webpage:\n            raise ExtractorError('This live stream has already finished.', expected=True)\n\n        conf = self._parse_json(self._search_regex(\n            r'(?s)conf\\s*=\\s*({.+?});', webpage, 'conf'),\n            display_id,\n            transform_source=lambda s: js_to_json(re.sub(r'shareurl:.+,', '', s)))\n        video_id = conf['videoid']\n\n        config = self._download_json(conf['configUrl'], video_id, query={\n            'videoid': video_id,\n            'partnerid': conf['partnerid'],\n            'language': conf.get('language', ''),\n            'portal': conf.get('portalid', ''),\n        })\n        error = config.get('error')\n        if error:\n            raise ExtractorError('%s said: %s' % (self.IE_NAME, error), expected=True)\n\n        video_data = config['video']","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/laola1tv.py#L112-L148","documentation":"Raised by the Laola1TvBaseIE._extract_video path when the video page contains the German text 'Dieser Livestream ist bereits beendet.', meaning the live stream is over. It is expected=True, so it reports cleanly that the content is finished rather than failing with a parse error.","triggerScenarios":"Opening any laola1.tv video page after its live stream ended — the site keeps the page up but embeds the German end-of-stream notice; the extractor checks the literal string before parsing the conf JSON.","commonSituations":"Downloading event VOD URLs while the event is still listed but the stream finished and no VOD was published yet; time-zone confusion about when a broadcast ends; following live links from schedules after the fact.","solutions":["Wait for the VOD/VOD-URL variant to be published and use that URL instead of the live one","Check the event page for a replay link once processing completes","Record the stream live next time (e.g. with livestream mode) rather than fetching afterwards","Verify in a browser that a replay actually exists before retrying"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if 'already finished' in str(e):\n        schedule_vod_check(url, later=True)  # retry once VOD is published\n    else:\n        raise","preventionTips":["Download live events while live; do not rely on the live URL afterwards","Before fetching, check the event end time in your local timezone"],"tags":["laola1tv","live-stream","ended","extractor"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}