Skip to content

iTunes provider response mishandling creates fake episodes for every podcast #1737

@kar731

Description

@kar731

Description

Every podcast contains a fake episode due to the iTunes provider not filtering out the main podcast object in the response.

When fetching podcast episodes via the iTunes lookup, the API will return the parent collection object alongside real episodes. The collection item sometimes has a track_id equal to collection_id (or otherwise appears like an episode). Current code only filters out results with None track_id and therefore can treat the collection as a real episode, producing a “fake” episode entry with the podcast title.

Steps to Reproduce

  1. In Ryot search for any podcast (EX: "Video Palace")
  2. Click on the podcast result
  3. Click on episodes
  4. There will be a fake episode that solely is the name of the podcast (see image)
Image

To verify episode with the name "Video Palace" does not exist on iTunes: https://podcasts.apple.com/us/podcast/video-palace/id1439247558
Repeat with any podcast in Ryot

Python Script to Show Error in Ryot

import requests

URL = "https://itunes.apple.com"
identifier = "1439247558" # Podcast called: "Video Palace"

# first get collection to read iTunes trackCount
podcast_params = {
    "id": identifier, 
    "media": "podcast", 
    "entity": "podcast", 
    "lang": "en_us"
}
col = requests.get(f"{URL}/lookup", params=podcast_params).json()
track_count = None
if col.get("results"):
    track_count = col["results"][0].get("trackCount")
    print("track_count:", track_count)

# now request episodes and count how many actually get returned
episode_params = {
    "id": identifier,
    "media": "podcast",
    "entity": "podcastEpisode",
    "lang": "en_us",
}
r = requests.get(f"{URL}/lookup", params=episode_params)
episodes_resp = r.json()
items = episodes_resp.get("results", [])

ryot_track_count = 1
for it in items:
    print(f"found track {ryot_track_count} - api data: {it}")
    ryot_track_count += 1

    track_id = it.get("trackId")
    collection_id = it.get("collectionId")
    if track_id is None:
        # Ryot already filters for this
        print("Track_id was None")
        continue
    if collection_id is not None and track_id == collection_id:
        # Ryot does not filter for this
        print("FAKE EPISODE: Track_id was the same as collection ID")
        print(f"Collection Name: {it.get('collectionName')}")
        print(f"Found Episode Name: {it.get('trackName')}")
        continue
    
    print("Real episode found")

print(f"iTunes says there are {track_count} episodes meanwhile Ryot added {ryot_track_count - 1} episodes")

iTunes says there are 14 episodes meanwhile Ryot added 15 episodes

Suggested Partial Fix

This fix is partial as a ryot database cleanup will still be required, otherwise everyone will still have the fake episodes that have already been added. Every podcast that has been added currently has one fake episode where track_id == collection_id.

context: crates/providers/itunes/src/lib.rs#L171

let track_id = itunes_episode.track_id?;
if track_id == itunes_episode.collection_id {
    // do not add the fake episode
    return None;
}
let episode_id = track_id.to_string();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions