question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Podcast episodes no longer load, missing external_playback_url in metadata

See original GitHub issue

Since a few days it is no longer possible to download podcast episodes through librespot due to a missing metadata item (external_playback_url):

https://github.com/Yetangitu/Spodcast/issues/13

The problem is most likely caused by some missing scope or other authorisation-related item in the authorisation token, the question is - which? A similar problem seems to exist in the rust-based version (https://github.com/librespot-org/librespot/issues/818) where the absence of the required URL in the stream is also mentioned.

I do notice that the metadata returned by Spotify to the web based player is contradictory in that it claims an episode to not be externally hosted while serving an externally hosted stream:

{
  "episodes" : [ {
   ...
   ...
    "external_playback_url" : "https://traffic.megaphone.fm/GLT8613565834.mp3?updated=1655823165",
   ...
   ...
    "is_externally_hosted" : false,

This change seems to have taken place on or around the 16th of June since that is the last day things worked as intended.

I notice the token generated by the web player is quite a bit longer than the one generated by librespot suggesting it contains some extra authorisations missing from the latter. The question is, which?

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
Yetangitucommented, Jun 22, 2022

It used to work with the existing endpoints, now it no longer does - the endpoint still returns data but this no longer contains playable streams, only previews. Here’s what used to be returned for Spotify-hosted podcasts:

API call to https://api-partner.spotify.com/pathfinder/v1/query?operationName=getEpisode&variables={"uri":"spotify:episode:{epidodeId}"}...

      "audio": {
        "items": [
          {
            "url": "https://anon-podcast.scdn.co/d5fe1647e3fb98c7f074cf87c0a6fe6fbd3848b1",
            "format": "AAC_24",
            "fileId": "d5fe1647e3fb98c7f074cf87c0a6fe6fbd3848b1",
            "externallyHosted": false
          },
          {
            "url": "https://anon-podcast.scdn.co/47e7f56afca4719d33094c81dc826a63668a23a6",
            "format": "MP4_128",
            "fileId": "47e7f56afca4719d33094c81dc826a63668a23a6",
            "externallyHosted": false
          },
          {
            "url": "https://anon-podcast.scdn.co/ec2cd6625026c45273e8776c3779b80afc28ca36",
            "format": "MP4_128_DUAL",
            "fileId": "ec2cd6625026c45273e8776c3779b80afc28ca36",
            "externallyHosted": false
          },
          {
            "url": "https://anon-podcast.scdn.co/226e1bd59da25e023cbdb450485e43b6b1b9878b",
            "format": "OGG_VORBIS_96",
            "fileId": "226e1bd59da25e023cbdb450485e43b6b1b9878b",
            "externallyHosted": false
          }
        ]
      }

Notice the use of the anon-podcast.scdn.co domain for serving these streams.

Here’s what used to be returned for externally-hosted podcasts:

  "audio": {
    "items": [
      {
        "url": "https://anon-podcast.scdn.co/b16d6ecd88942a0fac5dea4e560fc553e7ba90fb",
        "format": "AAC_24",
        "fileId": "b16d6ecd88942a0fac5dea4e560fc553e7ba90fb",
        "externallyHosted": false
      },
      {
        "url": "https://anon-podcast.scdn.co/63437b0b71f6d332555b041441d760641e00dba8",
        "format": "MP4_128_DUAL",
        "fileId": "63437b0b71f6d332555b041441d760641e00dba8",
        "externallyHosted": false
      },
      {
        "url": "https://anon-podcast.scdn.co/30f1f2170606c5bc6ccd367ea163b9a1039336af",
        "format": "MP4_128",
        "fileId": "30f1f2170606c5bc6ccd367ea163b9a1039336af",
        "externallyHosted": false
      },
      {
        "url": "https://anon-podcast.scdn.co/ce101e45379048a8d41d21e352dfc076aa1cdbf1",
        "format": "OGG_VORBIS_96",
        "fileId": "ce101e45379048a8d41d21e352dfc076aa1cdbf1",
        "externallyHosted": false
      },
      {
        "url": "https://www.podtrac.com/pts/redirect.mp3/pdst.fm/e/pdst.fm/e/traffic.megaphone.fm/BENT9388265894.mp3?updated=1645154429",
        "format": "UNKNOWN",
        "fileId": null,
        "externallyHosted": true
      }
    ]
  }

Notice the last object in the array which contains an external url.

This is what is returned now for the same API call:

      "audio": {
        "items": [
          {
            "url": "https://p.scdn.co/mp3-preview/cbe2227b6c1ad338d86bcdb5ef9d4770cfe86941",
            "format": "AAC_24",
            "fileId": "cbe2227b6c1ad338d86bcdb5ef9d4770cfe86941",
            "externallyHosted": false
          },
          {
            "url": "https://p.scdn.co/mp3-preview/88f8d32962f3e9695af48f80ff5ddca43871b98d",
            "format": "MP4_128",
            "fileId": "88f8d32962f3e9695af48f80ff5ddca43871b98d",
            "externallyHosted": false
          },
          {
            "url": "https://p.scdn.co/mp3-preview/c5adb66015480fc18305dd6c248dec0bf4718c2a",
            "format": "MP4_128_DUAL",
            "fileId": "c5adb66015480fc18305dd6c248dec0bf4718c2a",
            "externallyHosted": false
          },
          {
            "url": "https://p.scdn.co/mp3-preview/4b1203a2153ef2bf642526a0ee1b53afd5c9ba47",
            "format": "OGG_VORBIS_96",
            "fileId": "4b1203a2153ef2bf642526a0ee1b53afd5c9ba47",
            "externallyHosted": false
          }
        ]
      }

The domain used for podcast streams (anon-podcast.scdn.co) does not exist any more:

$ host anon-podcast.scdn.co
Host anon-podcast.scdn.co not found: 3(NXDOMAIN)

…so it does look like something has changed on Spotify’s side. The returned data now only contains ‘preview’ URLs (which all return HTTP/1.1 404 Not Found when polled using the token from the web player, I guess these need special treatment in some way - are they Widevine-encumbered streams?). The actual playable stream has moved and is now found in the output from GET /v1/episodes/{episodeId}, in external_playback_url. Switching out the token returned by librespot for the one returned by the web player makes this url appear in the output, this seems to be the only difference:

Using a web player generated token:

curl -s 'https://api.spotify.com/v1/episodes?ids=5neDqDVLOPbISIt2IYXlc8' ' -H 'authorization: Bearer WARNING_HERE_BE_A_VERY_LONG_BEARER_TOKEN' |jq '.'
{
  "episodes": [
    {
      "audio_preview_url": "https://p.scdn.co/mp3-preview/8ce935cff039360f8c8e6bad7592641896139643",
      "content_type": "PODCAST_EPISODE",
      "description": "bla bla bla",
      "duration_ms": 1876349,
      "explicit": false,
      "external_playback_url": "https://traffic.megaphone.fm/GLT2438388645.mp3?updated=1652802576",
   ...
   ...

The external_playback_url is playable without any further problems but… it only appears when using a web player provided token. Using a librespot generated token produces the same output minus the external_playback_url, i.e. it does not provide a playable stream.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Podcasts on external URL's don't load · Issue #818 - GitHub
[BUG] Podcast episodes no longer load, missing external_playback_url in metadata kokarare1212/librespot-python#135.
Read more >
Update your podcast metadata - Apple Podcasts for Creators
Learn how to update your metadata via an RSS feed or directly in Apple Podcasts ... Some things, like the title and author...
Read more >
Troubleshooting - Podcasts Manager Help - Google Support
Open the Google Podcasts app, load your podcast, and see whether the episode appears there. If an episode was previously present in the...
Read more >
Solved: "New episodes" Playlist disappeared
I no longer have a New Episodes option in my app. I have to go to each individual podcast's page and either add...
Read more >
Seriously Simple Podcasting – WordPress plugin
Also include links to download the content or play it in a new window. Display episode meta data like episode durations and date...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found