{"record":{"id":"aaaf804ee7eecb13","repo":"ytdl-org/youtube-dl","slug":"no-downloadable-streams-found","errorCode":null,"errorMessage":"No downloadable streams found","messagePattern":"No downloadable streams found","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/tunein.py","lineNumber":32,"sourceCode":"    @staticmethod\n    def _extract_urls(webpage):\n        return re.findall(\n            r'<iframe[^>]+src=[\"\\'](?P<url>(?:https?://)?tunein\\.com/embed/player/[pst]\\d+)',\n            webpage)\n\n    def _real_extract(self, url):\n        content_id = self._match_id(url)\n\n        content_info = self._download_json(\n            self._API_BASE_URL + self._API_URL_QUERY % content_id,\n            content_id, note='Downloading JSON metadata')\n\n        title = content_info['Title']\n        thumbnail = content_info.get('Logo')\n        location = content_info.get('Location')\n        streams_url = content_info.get('StreamUrl')\n        if not streams_url:\n            raise ExtractorError('No downloadable streams found', expected=True)\n        if not streams_url.startswith('http://'):\n            streams_url = compat_urlparse.urljoin(url, streams_url)\n\n        streams = self._download_json(\n            streams_url, content_id, note='Downloading stream data',\n            transform_source=lambda s: re.sub(r'^\\s*\\((.*)\\);\\s*$', r'\\1', s))['Streams']\n\n        is_live = None\n        formats = []\n        for stream in streams:\n            if stream.get('Type') == 'Live':\n                is_live = True\n            reliability = stream.get('Reliability')\n            format_note = (\n                'Reliability: %d%%' % reliability\n                if reliability is not None else None)\n            formats.append({\n                'preference': (","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/tunein.py#L14-L50","documentation":"Raised by TuneInBaseIE when the content JSON contains no 'StreamUrl' field: the id resolved (title/logo present) but TuneIn exposes no playable stream list for it. Expected=True, meaning 'nothing to download for this station/show'.","triggerScenarios":"Extracting a tunein.com station id whose API entry has StreamUrl empty/absent: station currently off-air in the API, a stub/placeholder page (e.g. an upcoming show id), or content Tunein no longer carries.","commonSituations":"Podcast-show pages whose episodes must be extracted individually rather than the show id; temporarily offline streams; regional variants of stations lacking stream URLs for your market.","solutions":["Open the tunein.com page in a browser and confirm a player actually streams","If it is a show/podcast page, list and extract the individual episode URLs instead of the parent id","Retry later if the station is temporarily down; stream availability changes","Update to yt-dlp for current TuneIn API handling"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"info = ydl.extract_info(api_url, download=False)\n# equivalent pre-check: fetch content JSON and confirm 'StreamUrl' is present\nif not content_info.get('StreamUrl'):\n    raise Skip('no streams for %s' % content_id)","typeGuard":null,"tryCatchPattern":"try:\n    ydl.extract_info(tunein_url)\nexcept ExtractorError as e:\n    if e.expected and 'No downloadable streams' in str(e):\n        if is_show_page(tunein_url):\n            extract_episodes_individually(tunein_url)\n        else:\n            schedule_retry(url)","preventionTips":["Extract episode-level URLs for podcast/show pages, not the show id","Confirm the station actually streams in a browser first","Retry later — station streams come and go"],"tags":["extractor","tunein","no-streams","expected"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}