{"id":50986878,"url":"https://github.com/frammenti/raiplaysoundrss","last_synced_at":"2026-06-19T20:04:44.817Z","repository":{"id":353330379,"uuid":"1218420209","full_name":"frammenti/raiplaysoundrss","owner":"frammenti","description":"RSS feed for RaiPlay Sound","archived":false,"fork":false,"pushed_at":"2026-06-10T16:05:57.000Z","size":73,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T18:05:40.640Z","etag":null,"topics":["radio","raiplay","raiplay-sound","raiplaysound","rss"],"latest_commit_sha":null,"homepage":"https://api.frammenti.dev/rss/programmi/battiti.xml","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/frammenti.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-22T21:27:42.000Z","updated_at":"2026-06-10T16:06:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/frammenti/raiplaysoundrss","commit_stats":null,"previous_names":["frammenti/raiplaysoundrss"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/frammenti/raiplaysoundrss","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frammenti%2Fraiplaysoundrss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frammenti%2Fraiplaysoundrss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frammenti%2Fraiplaysoundrss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frammenti%2Fraiplaysoundrss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frammenti","download_url":"https://codeload.github.com/frammenti/raiplaysoundrss/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frammenti%2Fraiplaysoundrss/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34546227,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["radio","raiplay","raiplay-sound","raiplaysound","rss"],"created_at":"2026-06-19T20:04:43.994Z","updated_at":"2026-06-19T20:04:44.812Z","avatar_url":"https://github.com/frammenti.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RaiPlay Sound RSS\n\n\u003cp align=\"center\" width=\"100%\"\u003e\n    \u003cimg width=\"750\" height=\"525\" alt=\"Example of use in the Podcasts app on Linux\" title=\"Example of use in the GNOME Podcasts app on Linux\" src=\"https://github.com/user-attachments/assets/85f0ef38-ad21-4d03-a35d-86f063e8c3e6\" /\u003e\n\u003c/p\u003e\n\n## What is this?\n\nThis Fastify service generates always up to date RSS podcast feeds for programs on RaiPlay Sound. It uses their undocumented JSON endpoints instead of vendor-locking you into the tracking circus that RaiPlay Sound is.\n\nUnlike tools that periodically rebuild static feeds, this service is **reactive** and regenerates feeds on demand only when a client requests them, typically when you open your podcast app.\n\nIt exposes endpoints structured like:\n\n```\n/:type/:name\n```\n\nfor example:\n\n```\n/programmi/battiti\n```\n\n\u003e [!NOTE]\n\u003e An earlier version of the API required paths structured as `/rss/programmi/battiti.xml`. The structure has been simplified, but the old paths still work.\n\n## Why?\n\nRaiPlay Sound provides:\n\n- structured JSON APIs with full metadata\n- direct downloadable audio (MP3)\n\n…but:\n\n- official RSS feeds were abandoned to force you to use their proprietary app\n- content is locked behind their web player and tracking-heavy frontend\n\nThis service restores open access to that content through standard podcast tools, as was the case until 2020.\n\n## What do I need to make this work?\n\nA Node.js server, the base for all greatness.\n\n```bash\ngit clone https://github.com/frammenti/raiplaysoundrss\ncd raiplaysoundrss\nnpm install\nnpm run build\nnpm run start\n```\n\nThen open:\n\n```\nhttp://localhost:3000/programmi/battiti\n```\n\nRun it behind a reverse proxy (Caddy, Nginx, etc.) and bind it to localhost.\nDo not expose Node's service port directly.\n\nOr, keep reading.\n\n## Where do I find the program type and name?\n\nCheck on the website:\n\n```\nhttps://www.raiplaysound.it/programmi/battiti\n                            ↑ type ↑  ↑ name ↑\n```\n\nWorks with _programmi_, _audiolibri_, _playlist_... (not _dirette_)\n\n\u003e [!NOTE]\n\u003e Some _programmi_ are not structured as a **list of episodes** but rather as a **collection of playlists**. You can only get the feed for the individual playlists by using the slug found on each playlist’s page. This is the case for shows like “Gettoni di Scienza” and “Alle otto della sera.”\n\n## How it works\n\n1. Fetch program data:\n\n```\nhttps://www.raiplaysound.it/:type/:name.json\n```\n\n2. Extract episodes:\n\n- title\n- description\n- publication date\n- metadata\n\n3. Resolve new audio:\n\n- follow either `downloadable_audio.url` or `audio.url`\n- extract a stable MP3 url (or MP4 if unavailable) from CDN\n\n4. Cache results:\n\n- avoids re-resolving URLs\n- incremental updates only\n\n5. Generate RSS:\n\n- RSS 2.0 + iTunes extensions\n- compatible with podcast apps\n\nHighlights:\n\n- Generic endpoint for any program\n- Exposes an `/health` endpoint for debugging and a `/stats` endpoint for fun\n- Processes queries in a limited concurrent pool so that new shows initialization is fast without flooding the upstream service with hundreds of simultaneous requests\n- Rate limits requests so that your server doesn't burn down\n- No scraping, no headless browser, no fragile selectors\n- No transcoding or storage required\n\n## Legal notice\n\nThis project only consumes data and media URLs already exposed by RaiPlay Sound's public frontend. It does not bypass authentication, DRM, or access controls.\n\n## Limitations\n\n- Depends on RaiPlay Sound’s internal API structure\n- MP3 URLs may change over time (handled via cache refresh every week)\n- No guarantee of long-term stability (as with any unofficial service, but also official, apparently)\n\n## Why did you make this?\n\nI'm approaching my thirties and fall asleep too early to listen to Battiti, but I don't want to lose my edge.\n\n## How long did it take?\n\nLess than writing this.\n\n## But I don't have a server\n\nCheck the repository URL. You might find a public instance.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fframmenti%2Fraiplaysoundrss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fframmenti%2Fraiplaysoundrss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fframmenti%2Fraiplaysoundrss/lists"}