{"record":{"id":"4609434a1c0c60e0","repo":"ytdl-org/youtube-dl","slug":"s-is-not-available","errorCode":null,"errorMessage":"%s is not available","messagePattern":"(.+?) is not available","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"warning","filePath":"youtube_dl/extractor/francetv.py","lineNumber":537,"sourceCode":"        'url': 'https://www.ludo.fr/heros/ninjago',\n        'info_dict': {\n            'id': 'ninjago',\n        },\n        'playlist_count': 10,\n    }, {\n        'url': 'https://www.zouzous.fr/heros/simon?abc',\n        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        mobj = re.match(self._VALID_URL, url)\n        playlist_id = mobj.group('id')\n\n        playlist = self._download_json(\n            '%s/%s' % (mobj.group('url'), 'playlist'), playlist_id)\n\n        if not playlist.get('count'):\n            raise ExtractorError(\n                '%s is not available' % playlist_id, expected=True)\n\n        entries = []\n        for item in playlist['items']:\n            identity = item.get('identity')\n            if identity and isinstance(identity, compat_str):\n                entries.append(self._make_url_result(identity))\n\n        return self.playlist_result(entries, playlist_id)\n","sourceCodeStart":519,"sourceCodeEnd":547,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/francetv.py#L519-L547","documentation":"Raised by FranceTVJeunesseIE (zouzous.fr / ludo.fr hero pages) when the playlist API responds but its 'count' field is falsy — zero or missing. A zero-count playlist means the hero page has no episodes attached, so the extractor reports the playlist id as unavailable. Expected=True; a content state, not a bug.","triggerScenarios":"_download_json of <hero-url>/playlist returns an object whose 'count' key is 0, null, or absent, triggering the raise. Produced by retired/zouzous hero pages whose episode sets were emptied during site restructuring.","commonSituations":"Kids-content archives pointing at zouzous.fr/heros/<name> pages after France TV moved children's content to france.tv; scraping all hero URLs and hitting deprecated ones.","solutions":["Search the character/show on www.france.tv (zouzous/ludo content was migrated) and use the new URL","Verify the hero page in a browser still lists episodes","Treat 0-count heroes as permanently retired and remove them from crawl lists","Update youtube-dl/yt-dlp in case the playlist endpoint moved"],"exampleFix":"# before\nyoutube_dl 'https://www.zouzous.fr/heros/retired-character'\n# ERROR: retired-character is not available\n\n# after\nyt-dlp 'https://www.france.tv/zouzous/current-show-episode.html'","handlingStrategy":"try-catch","validationCode":"# Pre-check playlist count before extraction\nplaylist = fetch_json(hero_url + '/playlist')\nif not playlist.get('count'):\n    skip_hero(hero_id)  # empty/retired hero page","typeGuard":"def has_episodes(playlist: dict) -> bool:\n    return (\n        isinstance(playlist, dict)\n        and bool(playlist.get('count'))\n        and isinstance(playlist.get('items'), list)\n        and len(playlist['items']) > 0\n    )","tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if str(e).endswith('is not available'):\n        prune_retired_hero(url)","preventionTips":["Prefer france.tv URLs over legacy zouzous/ludo hero pages","Prune zero-count heroes from crawls permanently"],"tags":["francetv","extractor","empty-playlist","deprecated"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}