From df6464add087a57a37c6d8b536375d562872f136 Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 17:53:31 +0200 Subject: [PATCH 01/13] First attempt for HLS support --- main.py | 168 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 132 insertions(+), 36 deletions(-) diff --git a/main.py b/main.py index d540132..4e625cd 100644 --- a/main.py +++ b/main.py @@ -24,8 +24,10 @@ from os import getenv from podimo.client import PodimoClient from feedgen.feed import FeedGenerator +from feedgen.ext.base import BaseExtension, BaseEntryExtension +from lxml import etree from mimetypes import guess_type -from aiohttp import ClientSession, CookieJar, ClientTimeout +from aiohttp import ClientSession, CookieJar from quart import Quart, Response, render_template, request from hashlib import sha256 from hypercorn.config import Config @@ -37,6 +39,48 @@ import cloudscraper import traceback +PODCAST_NAMESPACE = "https://podcastindex.org/namespace/1.0" + +class PodcastHlsExtension(BaseExtension): + def extend_ns(self): + return { + "podcast": PODCAST_NAMESPACE + } + +class PodcastHlsEntryExtension(BaseEntryExtension): + def __init__(self): + self._alternate_enclosures = [] + + def alternate_enclosure(self, uri, type, length=0, title=None): + self._alternate_enclosures.append({ + "uri": uri, + "type": type, + "length": length, + "title": title, + }) + def extend_rss(self, entry): + for enclosure in self._alternate_enclosures: + alternate = etree.SubElement( + entry, + etree.QName( + PODCAST_NAMESPACE, + "alternateEnclosure" + ), + type=enclosure["type"], + length=str(enclosure["length"]) + ) + if enclosure["title"] is not None: + alternate.set("title", enclosure["title"]) + etree.SubElement( + alternate, + etree.QName( + PODCAST_NAMESPACE, + "source" + ), + uri=enclosure["uri"] + ) + return entry + # Setup Quart, used for serving the web pages app = Quart(__name__) proxies = dict() @@ -248,34 +292,20 @@ async def urlHeadInfo(session, id, url, locale): if entry: return entry - retries = 3 # Number of retries - timeout = ClientTimeout(total=10) # 10 seconds timeout for each try - - for attempt in range(retries): - try: - logging.debug(f"HEAD request to {url} (Attempt {attempt + 1})") - async with session.head(url, allow_redirects=True, - headers=generateHeaders(None, locale), - timeout=timeout) as response: - content_length = 0 - content_type, _ = guess_type(url) - if 'content-length' in response.headers: - content_length = response.headers['content-length'] - if content_type is None and 'content-type' in response.headers: - content_type = response.headers['content-type'] - else: - content_type = 'audio/mpeg' - cache.insertIntoHeadCache(id, content_length, content_type) - return (content_length, content_type) - - except asyncio.TimeoutError: - if attempt < retries - 1: - logging.info(f"Retrying HEAD request to {url} (Attempt {attempt + 2})") - await asyncio.sleep(1) # Wait for 1 second before retrying - else: - logging.error(f"All retries failed for HEAD request to {url}") - raise # Re-raise the last exception if all retries fail - + logging.debug(f"HEAD request to {url}") + async with session.head( + url, allow_redirects=True, headers=generateHeaders(None, locale), timeout=3.05 + ) as response: + content_length = 0 + content_type, _ = guess_type(url) + if "content-length" in response.headers: + content_length = response.headers["content-length"] + if content_type == None and "content-type" in response.headers: + content_type = response.headers["content-type"] + else: + content_type = "audio/mpeg" + cache.insertIntoHeadCache(id, content_length, content_type) + return (content_length, content_type) def extract_audio_url(episode): @@ -293,35 +323,101 @@ def extract_audio_url(episode): url = url.replace("hls-media", "audios") url = url.replace("/main.m3u8", ".mp3") + # SJC + #url = url.replace('&', '&') + #logging.info(f"Media URL: {url}") return url, duration async def addFeedEntry(fg, episode, session, locale): + episode_id = episode.get("id", "") + logging.debug(f"Starting feed entry for episode {episode_id}") + fe = fg.add_entry() fe.guid(episode["id"]) fe.title(episode["title"]) fe.description(episode["description"]) - fe.pubDate(episode.get("publishDatetime", episode.get("datetime"))) + fe.pubDate(episode["publishDatetime"]) fe.podcast.itunes_image(episode["imageUrl"]) url, duration = extract_audio_url(episode) if url is None: + logging.warning(f"No audio URL found for episode {episode_id}") return - logging.debug(f"Found podcast '{episode['title']}'") + + logging.debug( + f"Audio URL found for episode {episode_id}, duration={duration}, " + f"is_hls={url.split('?', 1)[0].lower().endswith('.m3u8')}" + ) + fe.podcast.itunes_duration(duration) - content_length, content_type = await urlHeadInfo(session, episode['id'], url, locale) + content_length, content_type = await urlHeadInfo( + session, + episode['id'], + url, + locale + ) + + # Podimo returns HLS manifests as .m3u8 URLs. + is_hls = url.split("?", 1)[0].lower().endswith(".m3u8") + + if is_hls: + logging.debug(f"Episode {episode_id} detected as HLS; overriding MIME type") + content_type = "application/x-mpegURL" + fe.enclosure(url, content_length, content_type) + if is_hls: + logging.debug(f"Adding Podcasting 2.0 alternateEnclosure for episode {episode_id}") + fe.podcast_hls.alternate_enclosure( + uri=url, + type="application/x-mpegURL", + length=content_length, + title="HLS", + ) + + logging.debug(f"Finished feed entry for episode {episode_id}") + def chunks(x, n): for i in range(0, len(x), n): yield x[i:i + n] async def podcastsToRss(podcast_id, data, locale): - fg = FeedGenerator() - fg.load_extension("podcast") + logging.debug(f"podcastsToRss: START podcast_id={podcast_id}") - podcast = data["podcast"] - episodes = data["episodes"] + try: + logging.debug("podcastsToRss: creating FeedGenerator") + fg = FeedGenerator() + logging.debug("podcastsToRss: FeedGenerator created") + + logging.debug("podcastsToRss: loading podcast extension") + fg.load_extension("podcast") + logging.debug("podcastsToRss: podcast extension loaded") + + logging.debug("podcastsToRss: registering HLS extension") + fg.register_extension( + "podcast_hls", + extension_class_feed=PodcastHlsExtension, + extension_class_entry=PodcastHlsEntryExtension, + atom=False, + rss=True, + ) + logging.debug("podcastsToRss: HLS extension registered") + + logging.debug("podcastsToRss: reading podcast data") + podcast = data["podcast"] + episodes = data["episodes"] + + logging.debug( + f"podcastsToRss: podcast={podcast.get('title')!r}, " + f"episodes={len(episodes)}" + ) + + except Exception: + logging.exception( + f"podcastsToRss: FAILED for podcast_id={podcast_id}" + ) + raise if len(episodes) > 0: last_episode = episodes[0] From 248d5d29c28a686b8eb83928dbc5555b1d7a2966 Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 18:12:01 +0200 Subject: [PATCH 02/13] Style Python code (not fully tested) --- CHANGELOG.md | 20 ++++++ main.py | 182 +++++++++++++++++++++++++++-------------------- podimo/cache.py | 23 +++--- podimo/client.py | 113 +++++++++++++++++------------ podimo/config.py | 81 ++++++++++++--------- podimo/utils.py | 20 +++--- 6 files changed, 265 insertions(+), 174 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3d0ae4a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## Unreleased + +### Changed + +- Formatted the Python source with Black. +- Normalized import ordering with isort. +- Corrected PEP 8 whitespace, indentation, quoting, and `None` comparison style. +- Preserved the existing public camelCase APIs to avoid breaking current callers. + +### Validation + +- Python bytecode compilation, formatter, import-order, pycodestyle, whitespace, + and focused utility smoke checks pass. +- **Not fully tested:** the application has not undergone end-to-end or live Podimo + API testing. The local Python 3.8 environment could not build the pinned + `aiohttp` dependency required for a full application import test. diff --git a/main.py b/main.py index 4e625cd..9e236a4 100644 --- a/main.py +++ b/main.py @@ -18,80 +18,81 @@ # permissions and limitations under the Licence. import asyncio +import logging import re import sys -import logging +import traceback +from hashlib import sha256 +from mimetypes import guess_type from os import getenv -from podimo.client import PodimoClient +from urllib.parse import quote + +import cloudscraper +from aiohttp import ClientSession, CookieJar +from feedgen.ext.base import BaseEntryExtension, BaseExtension from feedgen.feed import FeedGenerator -from feedgen.ext.base import BaseExtension, BaseEntryExtension +from hypercorn.asyncio import serve +from hypercorn.config import Config from lxml import etree -from mimetypes import guess_type -from aiohttp import ClientSession, CookieJar from quart import Quart, Response, render_template, request -from hashlib import sha256 -from hypercorn.config import Config -from hypercorn.asyncio import serve -from urllib.parse import quote + +import podimo.cache as cache +from podimo.client import PodimoClient from podimo.config import * from podimo.utils import generateHeaders, randomHexId -import podimo.cache as cache -import cloudscraper -import traceback PODCAST_NAMESPACE = "https://podcastindex.org/namespace/1.0" + class PodcastHlsExtension(BaseExtension): def extend_ns(self): - return { - "podcast": PODCAST_NAMESPACE - } + return {"podcast": PODCAST_NAMESPACE} + class PodcastHlsEntryExtension(BaseEntryExtension): def __init__(self): self._alternate_enclosures = [] def alternate_enclosure(self, uri, type, length=0, title=None): - self._alternate_enclosures.append({ - "uri": uri, - "type": type, - "length": length, - "title": title, - }) + self._alternate_enclosures.append( + { + "uri": uri, + "type": type, + "length": length, + "title": title, + } + ) + def extend_rss(self, entry): for enclosure in self._alternate_enclosures: alternate = etree.SubElement( entry, - etree.QName( - PODCAST_NAMESPACE, - "alternateEnclosure" - ), + etree.QName(PODCAST_NAMESPACE, "alternateEnclosure"), type=enclosure["type"], - length=str(enclosure["length"]) + length=str(enclosure["length"]), ) if enclosure["title"] is not None: alternate.set("title", enclosure["title"]) etree.SubElement( alternate, - etree.QName( - PODCAST_NAMESPACE, - "source" - ), - uri=enclosure["uri"] + etree.QName(PODCAST_NAMESPACE, "source"), + uri=enclosure["uri"], ) return entry + # Setup Quart, used for serving the web pages app = Quart(__name__) proxies = dict() -#Setup logging +# Setup logging logging.basicConfig( format="%(levelname)s | %(asctime)s | %(message)s", datefmt="%Y-%m-%dT%H:%M:%SZ", level=logging.INFO, ) + def example(): return f"""Example ------------ @@ -106,14 +107,18 @@ def example(): a tool like https://gchq.github.io/CyberChef/#recipe=URL_Encode(true) """ + @app.after_request def allow_cors(response): - response.headers.set('Access-Control-Allow-Origin', '*') - response.headers.set('Access-Control-Allow-Methods', 'GET, POST') - response.headers.set('Cache-Control', 'max-age=900') - logging.debug(f"Incoming {request.method} request for '{request.url}' from User-Agent {request.user_agent} at {request.remote_addr}.") + response.headers.set("Access-Control-Allow-Origin", "*") + response.headers.set("Access-Control-Allow-Methods", "GET, POST") + response.headers.set("Cache-Control", "max-age=900") + logging.debug( + f"Incoming {request.method} request for '{request.url}' from User-Agent {request.user_agent} at {request.remote_addr}." + ) return response + def authenticate(): return Response( f"""401 Unauthorized. @@ -123,11 +128,14 @@ def authenticate(): 401, { "Content-Type": "text/plain", - "WWW-Authenticate": "Basic realm='Podimo credentials'" + "WWW-Authenticate": "Basic realm='Podimo credentials'", }, ) -def initialize_client(username: str, password: str, region: str, locale: str) -> PodimoClient: + +def initialize_client( + username: str, password: str, region: str, locale: str +) -> PodimoClient: client = PodimoClient(username, password, region, locale) # Check if there is an authentication token already in memory. If so, use that one. @@ -141,6 +149,7 @@ def initialize_client(username: str, password: str, region: str, locale: str) -> client.cookie_jar = cache.cookie_jars[key] return client + async def check_auth(username, password, region, locale, scraper): try: client = initialize_client(username, password, region, locale) @@ -157,8 +166,10 @@ async def check_auth(username, password, region, locale, scraper): traceback.print_exc() return None + podcast_id_pattern = re.compile(r"[0-9a-fA-F\-]+") + @app.route("/", methods=["POST", "GET"]) async def index(): error = "" @@ -192,20 +203,26 @@ async def index(): podcast_id = quote(str(podcast_id), safe="") region = quote(str(region), safe="") locale = quote(str(locale), safe="") - + if LOCAL_CREDENTIALS: url = f"{PODIMO_PROTOCOL}://{PODIMO_HOSTNAME}/feed/{podcast_id}.xml?{randomHexId(10)}®ion={region}&locale={locale}" else: email = quote(str(email), safe="") - comma = quote(',', safe="") + comma = quote(",", safe="") username = f"{email}{comma}{region}{comma}{locale}" - password = quote(str(password), safe="") + password = quote(str(password), safe="") url = f"{PODIMO_PROTOCOL}://{username}:{password}@{PODIMO_HOSTNAME}/feed/{podcast_id}.xml?{randomHexId(10)}®ion={region}&locale={locale}" - + logging.debug(f"Created an URL: {url}.") return await render_template("feed_location.html", url=url) - return await render_template("index.html", error=error, locales=LOCALES, regions=REGIONS, need_credentials=not(LOCAL_CREDENTIALS)) + return await render_template( + "index.html", + error=error, + locales=LOCALES, + regions=REGIONS, + need_credentials=not (LOCAL_CREDENTIALS), + ) @app.errorhandler(404) @@ -221,7 +238,9 @@ async def serve_basic_auth_feed(podcast_id): args = request.args region = args.get("region") locale = args.get("locale") - return await serve_feed(PODIMO_EMAIL, PODIMO_PASSWORD, podcast_id, region, locale) + return await serve_feed( + PODIMO_EMAIL, PODIMO_PASSWORD, podcast_id, region, locale + ) else: auth = request.authorization if not auth: @@ -232,11 +251,11 @@ async def serve_basic_auth_feed(podcast_id): def split_username_region_locale(string): - s = string.split(',') + s = string.split(",") if len(s) == 3: return tuple(s) else: - return (s[0], 'nl', 'nl-NL') + return (s[0], "nl", "nl-NL") def token_key(username, password): @@ -248,23 +267,25 @@ def token_key(username, password): @app.route("/feed///.xml") async def serve_feed(username, password, podcast_id, region, locale): - - logging.debug(f"Feed request for podcast {podcast_id} from IP {request.remote_addr} with User-Agent:{request.user_agent}.") - + + logging.debug( + f"Feed request for podcast {podcast_id} from IP {request.remote_addr} with User-Agent:{request.user_agent}." + ) + # Check if it is a valid podcast id string if podcast_id_pattern.fullmatch(podcast_id) is None: return Response("Invalid podcast id format", 400, {}) - + if region not in [region_code for (region_code, _) in REGIONS]: return Response("Invalid region", 400, {}) if locale not in LOCALES: return Response("Invalid locale", 400, {}) - # Check if url contains unique ID or podcastID in blocked list. If so, return HTTP code 410 GONE + # Return HTTP 410 GONE if the URL contains a blocked ID or podcast ID. if any(item in request.url for item in BLOCKED): logging.debug(f"Blocked! Podcast {podcast_id} is on local block list") - return Response("Podcast is gone", 410, {}) - + return Response("Podcast is gone", 410, {}) + with cloudscraper.create_scraper() as scraper: scraper.proxies = proxies client = await check_auth(username, password, region, locale, scraper) @@ -300,7 +321,7 @@ async def urlHeadInfo(session, id, url, locale): content_type, _ = guess_type(url) if "content-length" in response.headers: content_length = response.headers["content-length"] - if content_type == None and "content-type" in response.headers: + if content_type is None and "content-type" in response.headers: content_type = response.headers["content-type"] else: content_type = "audio/mpeg" @@ -311,9 +332,9 @@ async def urlHeadInfo(session, id, url, locale): def extract_audio_url(episode): duration = 0 url = None - if episode['audio']: - url = episode['audio']['url'] - duration = episode['audio']['duration'] + if episode["audio"]: + url = episode["audio"]["url"] + duration = episode["audio"]["duration"] if url is None or url == "": if episode["streamMedia"]: @@ -324,8 +345,8 @@ def extract_audio_url(episode): url = url.replace("/main.m3u8", ".mp3") # SJC - #url = url.replace('&', '&') - #logging.info(f"Media URL: {url}") + # url = url.replace('&', '&') + # logging.info(f"Media URL: {url}") return url, duration @@ -343,7 +364,7 @@ async def addFeedEntry(fg, episode, session, locale): url, duration = extract_audio_url(episode) if url is None: logging.warning(f"No audio URL found for episode {episode_id}") - return + return logging.debug( f"Audio URL found for episode {episode_id}, duration={duration}, " @@ -352,13 +373,10 @@ async def addFeedEntry(fg, episode, session, locale): fe.podcast.itunes_duration(duration) content_length, content_type = await urlHeadInfo( - session, - episode['id'], - url, - locale - ) + session, episode["id"], url, locale + ) - # Podimo returns HLS manifests as .m3u8 URLs. + # Podimo returns HLS manifests as .m3u8 URLs. is_hls = url.split("?", 1)[0].lower().endswith(".m3u8") if is_hls: @@ -368,7 +386,9 @@ async def addFeedEntry(fg, episode, session, locale): fe.enclosure(url, content_length, content_type) if is_hls: - logging.debug(f"Adding Podcasting 2.0 alternateEnclosure for episode {episode_id}") + logging.debug( + f"Adding Podcasting 2.0 alternateEnclosure for episode {episode_id}" + ) fe.podcast_hls.alternate_enclosure( uri=url, type="application/x-mpegURL", @@ -378,9 +398,11 @@ async def addFeedEntry(fg, episode, session, locale): logging.debug(f"Finished feed entry for episode {episode_id}") + def chunks(x, n): for i in range(0, len(x), n): - yield x[i:i + n] + yield x[i : i + n] + async def podcastsToRss(podcast_id, data, locale): logging.debug(f"podcastsToRss: START podcast_id={podcast_id}") @@ -414,9 +436,7 @@ async def podcastsToRss(podcast_id, data, locale): ) except Exception: - logging.exception( - f"podcastsToRss: FAILED for podcast_id={podcast_id}" - ) + logging.exception(f"podcastsToRss: FAILED for podcast_id={podcast_id}") raise if len(episodes) > 0: @@ -435,7 +455,7 @@ async def podcastsToRss(podcast_id, data, locale): image = podcast["images"]["coverImageUrl"] if image is None: - image = last_episode['imageUrl'] + image = last_episode["imageUrl"] fg.image(image) language = podcast["language"] @@ -467,21 +487,26 @@ async def spawn_web_server(): config.read_timeout = 60 config.graceful_timeout = 5 config.backlog = 1000 - app.config['TEMPLATES_AUTO_RELOAD'] = True + app.config["TEMPLATES_AUTO_RELOAD"] = True await serve(app, config) + async def main(): if HTTP_PROXY: global proxies - logging.info(f"Running with https proxy defined in environmental variable HTTP_PROXY: {HTTP_PROXY}") - proxies['https'] = HTTP_PROXY + logging.info( + f"Running with https proxy defined in environmental variable HTTP_PROXY: {HTTP_PROXY}" + ) + proxies["https"] = HTTP_PROXY tasks = [spawn_web_server()] await asyncio.gather(*tasks) + if __name__ == "__main__": if DEBUG: - logging.info(f"""Spawning server on {PODIMO_BIND_HOST} -Configuration: + logging.info( + f"""Spawning server on {PODIMO_BIND_HOST} +Configuration: - DEBUG: {DEBUG} - LOCAL CREDENTIALS: {LOCAL_CREDENTIALS} ({PODIMO_EMAIL}) - PODIMO_HOSTNAME: {PODIMO_HOSTNAME} @@ -497,5 +522,6 @@ async def main(): - PODCAST_CACHE_TIME: {PODCAST_CACHE_TIME} sec - HEAD_CACHE_TIME: {HEAD_CACHE_TIME} sec - BLOCKING: {BLOCKED} -""") +""" + ) asyncio.run(main()) diff --git a/podimo/cache.py b/podimo/cache.py index a289aaa..d830b80 100644 --- a/podimo/cache.py +++ b/podimo/cache.py @@ -17,32 +17,35 @@ # See the Licence for the specific language governing # permissions and limitations under the Licence. -from podimo.config import * -from typing import Dict, Tuple +from os.path import join from time import time +from typing import Dict, Tuple + from diskcache import Cache -from os.path import join + +from podimo.config import * # Store the authentication token in a dictionary # so it is not necessary to request a new token for every request. The key is # derived from the provided username and password (see the `token_key` function). TOKENS = dict() if STORE_TOKENS_ON_DISK: - TOKENS = Cache(join(CACHE_DIR, 'tokens_cache')) + TOKENS = Cache(join(CACHE_DIR, "tokens_cache")) # Give each user its own cookie jar to keep track of cookies that are # being set and used between different requests. cookie_jars = dict() -url_cache = Cache(join(CACHE_DIR, 'url_cache')) -podcast_cache = Cache(join(CACHE_DIR, 'podcast_cache')) +url_cache = Cache(join(CACHE_DIR, "url_cache")) +podcast_cache = Cache(join(CACHE_DIR, "podcast_cache")) # Podcast players support the display of the file size of each episode. # Podimo does not provide this information directly, so we do a HEAD request # to the episode file locations. This gives us the Content-Length which is # the file size of the episode. The file size of an episode doesn't change often, # which makes it perfect for caching. -head_cache = Cache(join(CACHE_DIR, 'head_cache')) +head_cache = Cache(join(CACHE_DIR, "head_cache")) + def getCacheEntry(key: str, cache, delete=True): if key in cache: @@ -54,18 +57,22 @@ def getCacheEntry(key: str, cache, delete=True): else: return value + def getHeadEntry(id: str): return getCacheEntry(id, head_cache, False) + def insertCacheEntry(key, value, timeout, cache): cache[key] = (time() + timeout, value) + def insertIntoTokenCache(key, value): insertCacheEntry(key, value, TOKEN_CACHE_TIME, TOKENS) + def insertIntoHeadCache(key, content_length, content_type): insertCacheEntry(key, (content_length, content_type), HEAD_CACHE_TIME, head_cache) + def insertIntoPodcastCache(key, podcast): insertCacheEntry(key, podcast, PODCAST_CACHE_TIME, podcast_cache) - diff --git a/podimo/client.py b/podimo/client.py index 265d941..33b7d54 100644 --- a/podimo/client.py +++ b/podimo/client.py @@ -17,16 +17,19 @@ # See the Licence for the specific language governing # permissions and limitations under the Licence. -from podimo.config import GRAPHQL_URL, SCRAPER_API, ZENROWS_API -from podimo.utils import (is_correct_email_address, token_key, - randomFlyerId, generateHeaders as gHdrs, - async_wrap) -from podimo.cache import insertIntoPodcastCache, getCacheEntry, podcast_cache -from time import time import logging +from time import time + +from podimo.cache import getCacheEntry, insertIntoPodcastCache, podcast_cache +from podimo.config import GRAPHQL_URL, SCRAPER_API, ZENROWS_API +from podimo.utils import async_wrap +from podimo.utils import generateHeaders as gHdrs +from podimo.utils import is_correct_email_address, randomFlyerId, token_key + if ZENROWS_API is not None: from zenrows import ZenRowsClient + class PodimoClient: def __init__(self, username: str, password: str, region: str, locale: str): self.username = username @@ -56,19 +59,26 @@ async def post(self, headers, query, variables, scraper): POST_URL = GRAPHQL_URL else: POST_URL = GRAPHQL_URL - response = await async_wrap(scraper.post)(POST_URL, - headers=headers, - cookies=self.cookie_jar, - json={"query": query, "variables": variables}, - timeout=(6.05, 30) - ) + response = await async_wrap(scraper.post)( + POST_URL, + headers=headers, + cookies=self.cookie_jar, + json={"query": query, "variables": variables}, + timeout=(6.05, 30), + ) if response is None: - raise RuntimeError(f"Could not receive response for query: {query.strip()[:30]}...") + raise RuntimeError( + f"Could not receive response for query: {query.strip()[:30]}..." + ) if response.status_code != 200: - raise RuntimeError(f"Podimo returned an error code. Response code was: {response.status_code} for query \"{query.strip()[:30]}...\"") + raise RuntimeError( + f'Podimo returned an error code. Response code was: {response.status_code} for query "{query.strip()[:30]}..."' + ) result = response.json()["data"] if result is None: - raise RuntimeError(f"Podimo returned no valid data for query {query.strip()[:30]}") + raise RuntimeError( + f"Podimo returned no valid data for query {query.strip()[:30]}" + ) return result # This gets the authentication token that is required for subsequent requests @@ -90,17 +100,22 @@ async def getPreregisterToken(self, scraper): } } """ - variables = {"locale": self.locale, "countryCode": self.region, "appsFlyerId": randomFlyerId()} + variables = { + "locale": self.locale, + "countryCode": self.region, + "appsFlyerId": randomFlyerId(), + } result = await self.post(headers, query, variables, scraper) tokenWithPreregisterUser = result["tokenWithPreregisterUser"] if not tokenWithPreregisterUser: raise RuntimeError("Podimo did not provide a tokenWithPreregisterUser") self.preauth_token = result["tokenWithPreregisterUser"]["token"] if not self.preauth_token: - raise RuntimeError("Podimo did not provide a tokenWithPreregisterUser token") + raise RuntimeError( + "Podimo did not provide a tokenWithPreregisterUser token" + ) return self.preauth_token - # Gets an "onboarding ID" that is used during login async def getOnboardingId(self, scraper): headers = self.generateHeaders(self.preauth_token) @@ -112,19 +127,22 @@ async def getOnboardingId(self, scraper): } } """ - variables = {"locale": self.locale, "countryCode": self.region, "appsFlyerId": randomFlyerId()} + variables = { + "locale": self.locale, + "countryCode": self.region, + "appsFlyerId": randomFlyerId(), + } result = await self.post(headers, query, variables, scraper) self.prereg_id = result["userOnboardingFlow"]["id"] return self.prereg_id - async def podimoLogin(self, scraper): - await self.getPreregisterToken(scraper) - await self.getOnboardingId(scraper) + await self.getPreregisterToken(scraper) + await self.getOnboardingId(scraper) - headers = self.generateHeaders(self.preauth_token) - logging.debug(f"AuthorizationAuthorize user: {self.username}") - query = """ + headers = self.generateHeaders(self.preauth_token) + logging.debug(f"AuthorizationAuthorize user: {self.username}") + query = """ query AuthorizationAuthorize($email: String!, $password: String!, $locale: String!, $preregisterId: String) { tokenWithCredentials( email: $email @@ -136,29 +154,33 @@ async def podimoLogin(self, scraper): } } """ - variables = { - "email": self.username, - "password": self.password, - "locale": self.locale, - "preregisterId": self.prereg_id, - } - result = await self.post(headers, query, variables, scraper) - tokenWithCredentials = result["tokenWithCredentials"] - if not tokenWithCredentials: - raise ValueError("Invalid Podimo credentials, did not receive tokenWithCredentials") + variables = { + "email": self.username, + "password": self.password, + "locale": self.locale, + "preregisterId": self.prereg_id, + } + result = await self.post(headers, query, variables, scraper) + tokenWithCredentials = result["tokenWithCredentials"] + if not tokenWithCredentials: + raise ValueError( + "Invalid Podimo credentials, did not receive tokenWithCredentials" + ) - self.token = result["tokenWithCredentials"]["token"] - if self.token: - return self.token - else: - raise ValueError("Invalid Podimo credentials, did not receive token") + self.token = result["tokenWithCredentials"]["token"] + if self.token: + return self.token + else: + raise ValueError("Invalid Podimo credentials, did not receive token") async def getPodcasts(self, podcast_id, scraper): podcast = getCacheEntry(podcast_id, podcast_cache) if podcast: timestamp, _ = podcast_cache[podcast_id] podcastName = self.getPodcastName(podcast) - logging.debug(f"Got podcast '{podcastName}' ({podcast_id}) from cache ({int(timestamp-time())} seconds left)") + logging.debug( + f"Got podcast '{podcastName}' ({podcast_id}) from cache ({int(timestamp-time())} seconds left)" + ) return podcast headers = self.generateHeaders(self.token) @@ -220,7 +242,9 @@ async def getPodcasts(self, podcast_id, scraper): if offset == 0: # podcastName = result[0]['podcastName'] podcastName = self.getPodcastName(result) - logging.debug(f"Fetched podcast '{podcastName}' ({podcast_id}) directly") + logging.debug( + f"Fetched podcast '{podcastName}' ({podcast_id}) directly" + ) fullResult = result else: fullResult["episodes"] += result["episodes"] @@ -231,10 +255,9 @@ async def getPodcasts(self, podcast_id, scraper): else: logging.debug(f"Fetched {numEpisodes} episodes; no more to fetch") break - + insertIntoPodcastCache(podcast_id, fullResult) return fullResult - def getPodcastName (self, podcast): + def getPodcastName(self, podcast): return list(podcast.values())[1]["title"] - diff --git a/podimo/config.py b/podimo/config.py index b9bb6cb..e5210ab 100644 --- a/podimo/config.py +++ b/podimo/config.py @@ -17,16 +17,14 @@ # See the Licence for the specific language governing # permissions and limitations under the Licence. -import os import logging +import os + from dotenv import dotenv_values # Load variables from the `.env` file first, # and overwrite them with environment variables -config = { - **dotenv_values(".env"), - **os.environ -} +config = {**dotenv_values(".env"), **os.environ} # You can overwrite the following four values with environmental variables # - `PODIMO_HOSTNAME`: the hostname that is displayed to the user. @@ -45,10 +43,12 @@ BLOCK_LIST_FILE = str(config.get("BLOCK_LIST_FILE", "./.block-list")) # Enable extra logging in debugging mode -DEBUG = bool(str(config.get("DEBUG", None)).lower() in ['true', '1', 't', 'y', 'yes']) +DEBUG = bool(str(config.get("DEBUG", None)).lower() in ["true", "1", "t", "y", "yes"]) # Enable local credentials -LOCAL_CREDENTIALS = bool(str(config.get("LOCAL_CREDENTIALS", None)).lower() in ['true', '1', 't', 'y', 'yes']) +LOCAL_CREDENTIALS = bool( + str(config.get("LOCAL_CREDENTIALS", None)).lower() in ["true", "1", "t", "y", "yes"] +) PODIMO_EMAIL = config.get("PODIMO_EMAIL", None) PODIMO_PASSWORD = config.get("PODIMO_PASSWORD", None) @@ -57,42 +57,53 @@ GRAPHQL_URL = "https://podimo.com/graphql" # Whether login tokens should be cached on disk, or only in memory -STORE_TOKENS_ON_DISK = bool(str(config.get("STORE_TOKENS_ON_DISK", True)).lower() in ['true', '1', 't', 'y', 'yes']) +STORE_TOKENS_ON_DISK = bool( + str(config.get("STORE_TOKENS_ON_DISK", True)).lower() + in ["true", "1", "t", "y", "yes"] +) # The time that a token is stored in cache -TOKEN_CACHE_TIME = int(config.get("TOKEN_CACHE_TIME", 3600 * 24 * 5)) # seconds = 5 days by default +TOKEN_CACHE_TIME = int( + config.get("TOKEN_CACHE_TIME", 3600 * 24 * 5) +) # seconds = 5 days by default # The time that a podcast feed is stored in cache -PODCAST_CACHE_TIME = int(config.get("PODCAST_CACHE_TIME", "21600")) # Default = 3600 * 6 = 6 hours +PODCAST_CACHE_TIME = int( + config.get("PODCAST_CACHE_TIME", "21600") +) # Default = 3600 * 6 = 6 hours # The time that the content information is cached -HEAD_CACHE_TIME = int(config.get("HEAD_CACHE_TIME", 7 * 60 * 60 * 24)) # seconds = 7 days by default +HEAD_CACHE_TIME = int( + config.get("HEAD_CACHE_TIME", 7 * 60 * 60 * 24) +) # seconds = 7 days by default # Whether the feeds generated with this tool should show up in public podcast catalogues -PUBLIC_FEEDS = bool(str(config.get("PUBLIC_FEEDS", None)).lower() in ['true', '1', 't', 'y', 'yes']) +PUBLIC_FEEDS = bool( + str(config.get("PUBLIC_FEEDS", None)).lower() in ["true", "1", "t", "y", "yes"] +) LOCALES = [ - 'nl-NL', - 'de-DE', - 'da-DK', - 'es-ES', - 'en-US', - 'es-MX', - 'no-NO', - 'fi-FI', - 'en-GB' + "nl-NL", + "de-DE", + "da-DK", + "es-ES", + "en-US", + "es-MX", + "no-NO", + "fi-FI", + "en-GB", ] REGIONS = [ - ('nl', 'Nederland'), - ('de', 'Deutschland'), - ('dk', 'Danmark'), - ('es', 'España'), - ('latam', 'America latina'), - ('en', 'International'), - ('mx', 'Mexico'), - ('no', 'Norge'), - ('fi', 'Suomi'), - ('uk', 'United Kingdom') + ("nl", "Nederland"), + ("de", "Deutschland"), + ("dk", "Danmark"), + ("es", "España"), + ("latam", "America latina"), + ("en", "International"), + ("mx", "Mexico"), + ("no", "Norge"), + ("fi", "Suomi"), + ("uk", "United Kingdom"), ] # If DEBUG mode is enabled, modify the logging output @@ -103,15 +114,15 @@ logging.basicConfig( format="%(levelname)s | %(asctime)s | %(message)s", datefmt="%Y-%m-%dT%H:%M:%SZ", - level=log_level + level=log_level, ) # Load block list from file '.block-list' if it exists BLOCKED = set() if os.path.exists(BLOCK_LIST_FILE): - with open (BLOCK_LIST_FILE, 'r') as file: + with open(BLOCK_LIST_FILE, "r") as file: for line in file: line = line.strip() - if line and not line.startswith('#'): - line = line.split(' ', 1)[0] + if line and not line.startswith("#"): + line = line.split(" ", 1)[0] BLOCKED.add(line) diff --git a/podimo/utils.py b/podimo/utils.py index 9d6803b..df8ceb8 100644 --- a/podimo/utils.py +++ b/podimo/utils.py @@ -17,11 +17,12 @@ # See the Licence for the specific language governing # permissions and limitations under the Licence. +import asyncio from email.utils import parseaddr -from random import choice, randint +from functools import partial, wraps from hashlib import sha256 -import asyncio -from functools import wraps, partial +from random import choice, randint + def randomHexId(length: int): string = [] @@ -43,6 +44,7 @@ def token_key(username, password): ).hexdigest() return key + # Verify if it is actually an email address def is_correct_email_address(username): return "@" in parseaddr(username)[1] @@ -50,16 +52,17 @@ def is_correct_email_address(username): def generateHeaders(authorization, locale): headers = { - 'user-os': 'android', - 'user-agent': 'Podimo/2.45.1 build 566/Android 33', - 'user-version': '2.45.1', - 'user-locale': locale, - "user-unique-id": randomHexId(16) + "user-os": "android", + "user-agent": "Podimo/2.45.1 build 566/Android 33", + "user-version": "2.45.1", + "user-locale": locale, + "user-unique-id": randomHexId(16), } if authorization: headers["authorization"] = authorization return headers + def async_wrap(func): @wraps(func) async def run(*args, loop=None, executor=None, **kwargs): @@ -67,4 +70,5 @@ async def run(*args, loop=None, executor=None, **kwargs): loop = asyncio.get_event_loop() pfunc = partial(func, *args, **kwargs) return await loop.run_in_executor(executor, pfunc) + return run From aa097070543f1a5e7d1a893795401a4cec6be9bc Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 18:51:17 +0200 Subject: [PATCH 03/13] Further removed temporary HLS in enclosure and only use podcast:alternateEnclosure (untested) --- main.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/main.py b/main.py index 9e236a4..194d468 100644 --- a/main.py +++ b/main.py @@ -340,9 +340,6 @@ def extract_audio_url(episode): if episode["streamMedia"]: url = episode["streamMedia"]["url"] duration = episode["streamMedia"]["duration"] - if "hls-media" in url and "/main.m3u8" in url: - url = url.replace("hls-media", "audios") - url = url.replace("/main.m3u8", ".mp3") # SJC # url = url.replace('&', '&') @@ -379,15 +376,10 @@ async def addFeedEntry(fg, episode, session, locale): # Podimo returns HLS manifests as .m3u8 URLs. is_hls = url.split("?", 1)[0].lower().endswith(".m3u8") - if is_hls: - logging.debug(f"Episode {episode_id} detected as HLS; overriding MIME type") - content_type = "application/x-mpegURL" - - fe.enclosure(url, content_length, content_type) - if is_hls: logging.debug( - f"Adding Podcasting 2.0 alternateEnclosure for episode {episode_id}" + f"Adding HLS alternateEnclosure without a standard enclosure " + f"for episode {episode_id}" ) fe.podcast_hls.alternate_enclosure( uri=url, @@ -395,8 +387,10 @@ async def addFeedEntry(fg, episode, session, locale): length=content_length, title="HLS", ) + else: + fe.enclosure(url, content_length, content_type) - logging.debug(f"Finished feed entry for episode {episode_id}") + logging.debug(f"Finished feed entry for episode {episode_id}") def chunks(x, n): From cf3c36ee5efc964ce5b5dde2a722c6fd3858986d Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 18:56:56 +0200 Subject: [PATCH 04/13] Document GPG-signed updates --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d0ae4a..8de6bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Normalized import ordering with isort. - Corrected PEP 8 whitespace, indentation, quoting, and `None` comparison style. - Preserved the existing public camelCase APIs to avoid breaking current callers. +- Git commits for updates are now signed with GPG. ### Validation From c71011d189e45b5e40d5dcb1613879745d35d282 Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 21:34:57 +0200 Subject: [PATCH 05/13] Integrate artwork proxy support --- CHANGELOG.md | 8 +- Dockerfile | 2 +- main.py | 168 ++++++++++++++++++++++++++++++- podimo/cache.py | 32 ++++++ requirements.txt | 1 + tests/__init__.py | 0 tests/test_artwork.py | 226 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 429 insertions(+), 8 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/test_artwork.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 8de6bf6..b6084ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,15 @@ All notable changes to this project will be documented in this file. - Corrected PEP 8 whitespace, indentation, quoting, and `None` comparison style. - Preserved the existing public camelCase APIs to avoid breaking current callers. - Git commits for updates are now signed with GPG. +- Added a cached JPEG artwork proxy for formats such as WebP, with download, + image-size, redirect, and private-address protections. +- Added channel-level iTunes artwork, News category, non-explicit status, and + episodic show type metadata. ### Validation - Python bytecode compilation, formatter, import-order, pycodestyle, whitespace, and focused utility smoke checks pass. - **Not fully tested:** the application has not undergone end-to-end or live Podimo - API testing. The local Python 3.8 environment could not build the pinned - `aiohttp` dependency required for a full application import test. + API testing. The artwork and feed test suite passes, and the application starts + successfully with the configured Hypercorn server. diff --git a/Dockerfile b/Dockerfile index a64d34d..6d930e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM python:3.10-alpine WORKDIR /src COPY requirements.txt /src/ -RUN apk add libxml2-dev libxslt-dev gcc libc-dev && pip3 install --no-cache-dir -r requirements.txt +RUN apk add libxml2-dev libxslt-dev jpeg-dev zlib-dev libwebp-dev gcc libc-dev && pip3 install --no-cache-dir -r requirements.txt COPY . /src diff --git a/main.py b/main.py index 194d468..f3d8ae7 100644 --- a/main.py +++ b/main.py @@ -23,17 +23,23 @@ import sys import traceback from hashlib import sha256 +from io import BytesIO +from ipaddress import ip_address from mimetypes import guess_type from os import getenv -from urllib.parse import quote +from urllib.parse import quote, urlsplit +from weakref import WeakValueDictionary import cloudscraper -from aiohttp import ClientSession, CookieJar +from aiohttp import ClientSession, ClientTimeout, CookieJar, TCPConnector +from aiohttp.abc import AbstractResolver +from aiohttp.resolver import DefaultResolver from feedgen.ext.base import BaseEntryExtension, BaseExtension from feedgen.feed import FeedGenerator from hypercorn.asyncio import serve from hypercorn.config import Config from lxml import etree +from PIL import Image from quart import Quart, Response, render_template, request import podimo.cache as cache @@ -42,12 +48,63 @@ from podimo.utils import generateHeaders, randomHexId PODCAST_NAMESPACE = "https://podcastindex.org/namespace/1.0" +ITUNES_NAMESPACE = "http://www.itunes.com/dtds/podcast-1.0.dtd" +MAX_ARTWORK_SIZE = 10 * 1024 * 1024 +MAX_ARTWORK_DIMENSION = 3000 +MAX_ARTWORK_PIXELS = 20_000_000 +artwork_downloads = asyncio.Semaphore(2) +artwork_locks = WeakValueDictionary() + + +async def runInThread(function, *args): + loop = asyncio.get_running_loop() + return await loop.run_in_executor(None, function, *args) + + +def ensurePublicAddresses(addresses): + if any(not ip_address(address["host"]).is_global for address in addresses): + raise OSError("Artwork host resolves to a non-public address") + return addresses + + +class PublicResolver(AbstractResolver): + def __init__(self): + self.resolver = DefaultResolver() + + async def resolve(self, host, port=0, family=0): + addresses = await self.resolver.resolve(host, port, family) + return ensurePublicAddresses(addresses) + + async def close(self): + await self.resolver.close() + + +class PublicConnector(TCPConnector): + async def _resolve_host(self, host, port, traces=None): + addresses = await super()._resolve_host(host, port, traces) + return ensurePublicAddresses(addresses) class PodcastHlsExtension(BaseExtension): + def __init__(self): + self._itunes_type = None + + def itunes_type(self, value=None): + if value is not None: + self._itunes_type = value + return self._itunes_type + def extend_ns(self): return {"podcast": PODCAST_NAMESPACE} + def extend_rss(self, feed): + if self._itunes_type is not None: + podcast_type = etree.SubElement( + feed[0], etree.QName(ITUNES_NAMESPACE, "type") + ) + podcast_type.text = self._itunes_type + return feed + class PodcastHlsEntryExtension(BaseEntryExtension): def __init__(self): @@ -250,6 +307,99 @@ async def serve_basic_auth_feed(podcast_id): return await serve_feed(username, auth.password, podcast_id, region, locale) +def artworkUrl(image_url): + if not image_url: + return None + + parsed_url = urlsplit(image_url) + if parsed_url.scheme not in ("http", "https") or not parsed_url.netloc: + logging.warning("Skipping invalid artwork URL") + return None + + if parsed_url.path.lower().endswith((".jpg", ".jpeg", ".png")): + return image_url + + key = cache.registerArtworkSource(image_url) + return f"{PODIMO_PROTOCOL}://{PODIMO_HOSTNAME}/artwork/{key}.jpg" + + +def artworkToJpeg(data): + with Image.open(BytesIO(data)) as source: + if source.width * source.height > MAX_ARTWORK_PIXELS: + raise ValueError("Artwork exceeds maximum pixel count") + source.load() + source.thumbnail( + (MAX_ARTWORK_DIMENSION, MAX_ARTWORK_DIMENSION), Image.Resampling.LANCZOS + ) + + if source.mode in ("RGBA", "LA") or "transparency" in source.info: + rgba = source.convert("RGBA") + image = Image.new("RGB", rgba.size, "white") + image.paste(rgba, mask=rgba.getchannel("A")) + else: + image = source.convert("RGB") + + output = BytesIO() + image.save(output, format="JPEG", quality=90, optimize=True) + return output.getvalue() + + +async def fetchArtwork(image_url): + timeout = ClientTimeout(total=20) + connector = PublicConnector(resolver=PublicResolver()) + async with ClientSession(timeout=timeout, connector=connector) as session: + async with session.get( + image_url, allow_redirects=True, max_redirects=5 + ) as response: + response.raise_for_status() + if response.content_length and response.content_length > MAX_ARTWORK_SIZE: + raise ValueError("Artwork exceeds maximum download size") + + data = bytearray() + async for chunk in response.content.iter_chunked(64 * 1024): + data.extend(chunk) + if len(data) > MAX_ARTWORK_SIZE: + raise ValueError("Artwork exceeds maximum download size") + return bytes(data) + + +@app.route("/artwork/.jpg") +async def serve_artwork(key): + if not re.fullmatch(r"[0-9a-f]{64}", key): + return Response("Artwork not found", 404, {}) + + artwork = await runInThread(cache.getArtwork, key) + if artwork is None and await runInThread(cache.getArtworkFailure, key): + return Response("Something went wrong while fetching artwork", 502, {}) + + if artwork is None: + lock = artwork_locks.setdefault(key, asyncio.Lock()) + async with lock: + artwork = await runInThread(cache.getArtwork, key) + if artwork is None: + if await runInThread(cache.getArtworkFailure, key): + return Response( + "Something went wrong while fetching artwork", 502, {} + ) + source_url = await runInThread(cache.getArtworkSource, key) + if source_url is None: + return Response("Artwork not found", 404, {}) + + try: + async with artwork_downloads: + source = await fetchArtwork(source_url) + artwork = await runInThread(artworkToJpeg, source) + await runInThread(cache.insertArtwork, key, artwork) + except Exception as error: + await runInThread(cache.insertArtworkFailure, key) + logging.error(f"Error while fetching artwork {key}: {error}") + return Response( + "Something went wrong while fetching artwork", 502, {} + ) + + return Response(artwork, mimetype="image/jpeg") + + def split_username_region_locale(string): s = string.split(",") if len(s) == 3: @@ -355,8 +505,10 @@ async def addFeedEntry(fg, episode, session, locale): fe.guid(episode["id"]) fe.title(episode["title"]) fe.description(episode["description"]) - fe.pubDate(episode["publishDatetime"]) - fe.podcast.itunes_image(episode["imageUrl"]) + fe.pubDate(episode.get("publishDatetime", episode.get("datetime"))) + image = artworkUrl(episode.get("imageUrl")) + if image: + fe.podcast.itunes_image(image) url, duration = extract_audio_url(episode) if url is None: @@ -450,7 +602,13 @@ async def podcastsToRss(podcast_id, data, locale): image = podcast["images"]["coverImageUrl"] if image is None: image = last_episode["imageUrl"] - fg.image(image) + image = artworkUrl(image) + if image: + fg.image(image) + fg.podcast.itunes_image(image) + fg.podcast.itunes_category("News") + fg.podcast.itunes_explicit("no") + fg.podcast_hls.itunes_type("episodic") language = podcast["language"] if language is None: diff --git a/podimo/cache.py b/podimo/cache.py index d830b80..9472468 100644 --- a/podimo/cache.py +++ b/podimo/cache.py @@ -17,6 +17,7 @@ # See the Licence for the specific language governing # permissions and limitations under the Licence. +from hashlib import sha256 from os.path import join from time import time from typing import Dict, Tuple @@ -45,6 +46,9 @@ # the file size of the episode. The file size of an episode doesn't change often, # which makes it perfect for caching. head_cache = Cache(join(CACHE_DIR, "head_cache")) +artwork_cache = Cache(join(CACHE_DIR, "artwork_cache")) +ARTWORK_CACHE_TIME = 7 * 24 * 60 * 60 +ARTWORK_FAILURE_CACHE_TIME = 5 * 60 def getCacheEntry(key: str, cache, delete=True): @@ -76,3 +80,31 @@ def insertIntoHeadCache(key, content_length, content_type): def insertIntoPodcastCache(key, podcast): insertCacheEntry(key, podcast, PODCAST_CACHE_TIME, podcast_cache) + + +def registerArtworkSource(url): + key = sha256(url.encode("utf-8")).hexdigest() + source_key = f"source:{key}" + if artwork_cache.get(source_key) != url: + artwork_cache[source_key] = url + return key + + +def getArtworkSource(key): + return artwork_cache.get(f"source:{key}") + + +def getArtwork(key): + return artwork_cache.get(f"image:{key}") + + +def insertArtwork(key, artwork): + artwork_cache.set(f"image:{key}", artwork, expire=ARTWORK_CACHE_TIME) + + +def getArtworkFailure(key): + return artwork_cache.get(f"failure:{key}") + + +def insertArtworkFailure(key): + artwork_cache.set(f"failure:{key}", True, expire=ARTWORK_FAILURE_CACHE_TIME) diff --git a/requirements.txt b/requirements.txt index 4b31488..ec5b6db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ werkzeug~=2.3.7 zenrows~=1.3.2 diskcache~=5.6.3 python-dotenv~=1.0.0 +Pillow~=10.4.0 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_artwork.py b/tests/test_artwork.py new file mode 100644 index 0000000..26e6a93 --- /dev/null +++ b/tests/test_artwork.py @@ -0,0 +1,226 @@ +import asyncio +import unittest +from datetime import datetime, timezone +from io import BytesIO +from unittest.mock import AsyncMock, patch + +from lxml import etree +from PIL import Image, features + +import main + + +class ArtworkUrlTests(unittest.TestCase): + def test_supported_image_url_is_used_directly(self): + url = "https://cdn.example.com/episode.jpg" + + self.assertEqual(main.artworkUrl(url), url) + + @patch("main.cache.registerArtworkSource") + def test_supported_image_url_with_query_is_used_directly(self, register_artwork): + url = "https://cdn.example.com/episode.JPEG?token=abc" + + self.assertEqual(main.artworkUrl(url), url) + register_artwork.assert_not_called() + + @patch("main.cache.registerArtworkSource", return_value="a" * 64) + def test_webp_image_uses_local_jpeg_url(self, register_artwork): + url = "https://cdn.example.com/episode.webp" + + result = main.artworkUrl(url) + + register_artwork.assert_called_once_with(url) + self.assertEqual( + result, + f"{main.PODIMO_PROTOCOL}://{main.PODIMO_HOSTNAME}/artwork/{'a' * 64}.jpg", + ) + + @patch("main.cache.registerArtworkSource", return_value="b" * 64) + def test_extensionless_image_uses_local_jpeg_url(self, register_artwork): + result = main.artworkUrl("https://cdn.example.com/image/123") + + self.assertTrue(result.endswith(f"/{'b' * 64}.jpg")) + register_artwork.assert_called_once() + + def test_invalid_image_url_is_omitted(self): + self.assertIsNone(main.artworkUrl("file:///etc/passwd")) + self.assertIsNone(main.artworkUrl(None)) + + +class ArtworkConversionTests(unittest.TestCase): + @unittest.skipUnless(features.check("webp"), "Pillow has no WebP support") + def test_webp_is_converted_to_rgb_jpeg(self): + source = BytesIO() + Image.new("RGBA", (32, 24), (255, 0, 0, 128)).save(source, format="WEBP") + + result = main.artworkToJpeg(source.getvalue()) + + with Image.open(BytesIO(result)) as image: + self.assertEqual(image.format, "JPEG") + self.assertEqual(image.mode, "RGB") + self.assertEqual(image.size, (32, 24)) + + +class ArtworkRouteTests(unittest.IsolatedAsyncioTestCase): + async def test_unknown_artwork_returns_404(self): + client = main.app.test_client() + + response = await client.get(f"/artwork/{'c' * 64}.jpg") + + self.assertEqual(response.status_code, 404) + + @patch("main.cache.getArtwork", return_value=b"jpeg-data") + async def test_cached_artwork_is_served_as_jpeg(self, get_artwork): + client = main.app.test_client() + + response = await client.get(f"/artwork/{'d' * 64}.jpg") + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content_type, "image/jpeg") + self.assertEqual(await response.get_data(), b"jpeg-data") + + @patch("main.cache.insertArtwork") + @patch("main.cache.getArtworkFailure", return_value=None) + @patch( + "main.cache.getArtworkSource", return_value="https://cdn.example.com/image.webp" + ) + @patch("main.cache.getArtwork", return_value=None) + @patch("main.fetchArtwork", new_callable=AsyncMock) + async def test_uncached_artwork_is_converted_and_cached( + self, fetch_artwork, get_artwork, get_source, get_failure, insert_artwork + ): + source = BytesIO() + Image.new("RGB", (16, 16), "blue").save(source, format="PNG") + fetch_artwork.return_value = source.getvalue() + client = main.app.test_client() + + response = await client.get(f"/artwork/{'e' * 64}.jpg") + + self.assertEqual(response.status_code, 200) + result = await response.get_data() + self.assertTrue(result.startswith(b"\xff\xd8")) + insert_artwork.assert_called_once_with("e" * 64, result) + + +class PublicResolverTests(unittest.IsolatedAsyncioTestCase): + async def test_connector_rejects_literal_private_address(self): + connector = main.PublicConnector(resolver=main.PublicResolver()) + self.addAsyncCleanup(connector.close) + + with self.assertRaisesRegex(OSError, "non-public"): + await connector._resolve_host("127.0.0.1", 80) + + async def test_private_address_is_rejected(self): + resolver = main.PublicResolver() + resolver.resolver.resolve = AsyncMock(return_value=[{"host": "127.0.0.1"}]) + + with self.assertRaisesRegex(OSError, "non-public"): + await resolver.resolve("example.com", 443) + + async def test_public_address_is_returned(self): + resolver = main.PublicResolver() + addresses = [{"host": "93.184.216.34"}] + resolver.resolver.resolve = AsyncMock(return_value=addresses) + + self.assertEqual(await resolver.resolve("example.com", 443), addresses) + + +class FeedArtworkTests(unittest.IsolatedAsyncioTestCase): + @patch( + "main.urlHeadInfo", new_callable=AsyncMock, return_value=("123", "audio/mpeg") + ) + @patch("main.cache.registerArtworkSource", return_value="f" * 64) + async def test_webp_artwork_does_not_prevent_feed_generation( + self, register_artwork, url_head_info + ): + data = { + "podcast": { + "title": "Test podcast", + "description": "Description", + "images": {"coverImageUrl": "https://cdn.example.com/show.webp"}, + "language": "nl-NL", + "authorName": "Author", + }, + "episodes": [ + { + "id": "episode-1", + "title": "Episode one", + "description": "Episode description", + "publishDatetime": datetime(2026, 7, 22, tzinfo=timezone.utc), + "imageUrl": "https://cdn.example.com/episode.webp", + "audio": { + "url": "https://cdn.example.com/episode.mp3", + "duration": 60, + }, + "streamMedia": None, + "podcastName": "Test podcast", + "artist": "Author", + } + ], + } + + feed = await main.podcastsToRss("podcast-id", data, "nl-NL") + feed_text = feed.decode("utf-8") + + self.assertIn("Episode one", feed_text) + self.assertIn(f"/artwork/{'f' * 64}.jpg", feed_text) + self.assertNotIn(".webp", feed_text) + self.assertIn('no", feed_text) + self.assertIn("episodic", feed_text) + url_head_info.assert_awaited_once() + + @patch( + "main.urlHeadInfo", + new_callable=AsyncMock, + return_value=("123", "application/octet-stream"), + ) + async def test_hls_uses_only_alternate_enclosure(self, url_head_info): + data = { + "podcast": { + "title": "Test podcast", + "description": "Description", + "images": {"coverImageUrl": "https://cdn.example.com/show.jpg"}, + "language": "nl-NL", + "authorName": "Author", + }, + "episodes": [ + { + "id": "episode-hls", + "title": "HLS episode", + "description": "Episode description", + "publishDatetime": datetime(2026, 7, 22, tzinfo=timezone.utc), + "imageUrl": "https://cdn.example.com/episode.jpg", + "audio": None, + "streamMedia": { + "url": "https://cdn.example.com/main.m3u8?token=abc", + "duration": 60, + }, + "podcastName": "Test podcast", + "artist": "Author", + } + ], + } + + feed = await main.podcastsToRss("podcast-id", data, "nl-NL") + feed_xml = etree.fromstring(feed) + item = feed_xml.find("./channel/item") + + self.assertIsNone(item.find("enclosure")) + alternate = item.find(f"{{{main.PODCAST_NAMESPACE}}}alternateEnclosure") + self.assertIsNotNone(alternate) + self.assertEqual(alternate.get("type"), "application/x-mpegURL") + source = alternate.find(f"{{{main.PODCAST_NAMESPACE}}}source") + self.assertEqual( + source.get("uri"), "https://cdn.example.com/main.m3u8?token=abc" + ) + url_head_info.assert_awaited_once() + + +if __name__ == "__main__": + unittest.main() From 5369a51dc9f6145afb3696d792f8e8d7cc2cd42e Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 21:43:08 +0200 Subject: [PATCH 06/13] Set iTunes explicit flag to false --- main.py | 13 ++++++++++++- tests/test_artwork.py | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index f3d8ae7..835328c 100644 --- a/main.py +++ b/main.py @@ -87,8 +87,14 @@ async def _resolve_host(self, host, port, traces=None): class PodcastHlsExtension(BaseExtension): def __init__(self): + self._itunes_explicit = None self._itunes_type = None + def itunes_explicit(self, value=None): + if value is not None: + self._itunes_explicit = value + return self._itunes_explicit + def itunes_type(self, value=None): if value is not None: self._itunes_type = value @@ -98,6 +104,11 @@ def extend_ns(self): return {"podcast": PODCAST_NAMESPACE} def extend_rss(self, feed): + if self._itunes_explicit is not None: + explicit = etree.SubElement( + feed[0], etree.QName(ITUNES_NAMESPACE, "explicit") + ) + explicit.text = self._itunes_explicit if self._itunes_type is not None: podcast_type = etree.SubElement( feed[0], etree.QName(ITUNES_NAMESPACE, "type") @@ -607,7 +618,7 @@ async def podcastsToRss(podcast_id, data, locale): fg.image(image) fg.podcast.itunes_image(image) fg.podcast.itunes_category("News") - fg.podcast.itunes_explicit("no") + fg.podcast_hls.itunes_explicit("false") fg.podcast_hls.itunes_type("episodic") language = podcast["language"] diff --git a/tests/test_artwork.py b/tests/test_artwork.py index 26e6a93..788049e 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -171,7 +171,7 @@ async def test_webp_artwork_does_not_prevent_feed_generation( f'/artwork/{"f" * 64}.jpg"', feed_text, ) - self.assertIn("no", feed_text) + self.assertIn("false", feed_text) self.assertIn("episodic", feed_text) url_head_info.assert_awaited_once() From 25154f4544f31e0733aae6dcb012dc5b0f8ac9aa Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Sun, 23 Aug 2026 21:45:44 +0200 Subject: [PATCH 07/13] Add iTunes feed owner metadata --- main.py | 1 + tests/test_artwork.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/main.py b/main.py index 835328c..d89a72f 100644 --- a/main.py +++ b/main.py @@ -619,6 +619,7 @@ async def podcastsToRss(podcast_id, data, locale): fg.podcast.itunes_image(image) fg.podcast.itunes_category("News") fg.podcast_hls.itunes_explicit("false") + fg.podcast.itunes_owner(name="Example", email="you@example.com") fg.podcast_hls.itunes_type("episodic") language = podcast["language"] diff --git a/tests/test_artwork.py b/tests/test_artwork.py index 788049e..634f948 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -172,6 +172,8 @@ async def test_webp_artwork_does_not_prevent_feed_generation( feed_text, ) self.assertIn("false", feed_text) + self.assertIn("Example", feed_text) + self.assertIn("you@example.com", feed_text) self.assertIn("episodic", feed_text) url_head_info.assert_awaited_once() From e6a927fb1f748e7a44f19343a8f0473fbf29b1c6 Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Tue, 25 Aug 2026 16:28:51 +0200 Subject: [PATCH 08/13] Add MP3 enclosure fallback for HLS episodes --- main.py | 4 +++- tests/test_artwork.py | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index d89a72f..92d16cf 100644 --- a/main.py +++ b/main.py @@ -540,10 +540,12 @@ async def addFeedEntry(fg, episode, session, locale): is_hls = url.split("?", 1)[0].lower().endswith(".m3u8") if is_hls: + enclosure_url = url.replace(".m3u8", ".mp3") logging.debug( - f"Adding HLS alternateEnclosure without a standard enclosure " + f"Adding MP3 enclosure {enclosure_url} and HLS alternate enclosure " f"for episode {episode_id}" ) + fe.enclosure(enclosure_url, content_length, "audio/mpeg") fe.podcast_hls.alternate_enclosure( uri=url, type="application/x-mpegURL", diff --git a/tests/test_artwork.py b/tests/test_artwork.py index 634f948..af9d05a 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -182,7 +182,7 @@ async def test_webp_artwork_does_not_prevent_feed_generation( new_callable=AsyncMock, return_value=("123", "application/octet-stream"), ) - async def test_hls_uses_only_alternate_enclosure(self, url_head_info): + async def test_hls_uses_standard_and_alternate_enclosures(self, url_head_info): data = { "podcast": { "title": "Test podcast", @@ -213,7 +213,13 @@ async def test_hls_uses_only_alternate_enclosure(self, url_head_info): feed_xml = etree.fromstring(feed) item = feed_xml.find("./channel/item") - self.assertIsNone(item.find("enclosure")) + enclosure = item.find("enclosure") + self.assertIsNotNone(enclosure) + self.assertEqual( + enclosure.get("url"), + "https://cdn.example.com/main.mp3?token=abc", + ) + self.assertEqual(enclosure.get("type"), "audio/mpeg") alternate = item.find(f"{{{main.PODCAST_NAMESPACE}}}alternateEnclosure") self.assertIsNotNone(alternate) self.assertEqual(alternate.get("type"), "application/x-mpegURL") From eaefd24ecb4ef4445833cbd9c4185a9ec7d2a52a Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Thu, 27 Aug 2026 08:13:20 +0200 Subject: [PATCH 09/13] Use dummy MP3 fallback for HLS episodes --- main.py | 7 ++++--- tests/test_artwork.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 92d16cf..fbb3c36 100644 --- a/main.py +++ b/main.py @@ -49,6 +49,7 @@ PODCAST_NAMESPACE = "https://podcastindex.org/namespace/1.0" ITUNES_NAMESPACE = "http://www.itunes.com/dtds/podcast-1.0.dtd" +HLS_FALLBACK_MP3_URL = "https://sjc.nl/pc/audio/dummy.mp3" MAX_ARTWORK_SIZE = 10 * 1024 * 1024 MAX_ARTWORK_DIMENSION = 3000 MAX_ARTWORK_PIXELS = 20_000_000 @@ -540,12 +541,12 @@ async def addFeedEntry(fg, episode, session, locale): is_hls = url.split("?", 1)[0].lower().endswith(".m3u8") if is_hls: - enclosure_url = url.replace(".m3u8", ".mp3") logging.debug( - f"Adding MP3 enclosure {enclosure_url} and HLS alternate enclosure " + f"Adding fallback MP3 enclosure {HLS_FALLBACK_MP3_URL} and " + f"HLS alternate enclosure " f"for episode {episode_id}" ) - fe.enclosure(enclosure_url, content_length, "audio/mpeg") + fe.enclosure(HLS_FALLBACK_MP3_URL, 0, "audio/mpeg") fe.podcast_hls.alternate_enclosure( uri=url, type="application/x-mpegURL", diff --git a/tests/test_artwork.py b/tests/test_artwork.py index af9d05a..86d038f 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -217,8 +217,9 @@ async def test_hls_uses_standard_and_alternate_enclosures(self, url_head_info): self.assertIsNotNone(enclosure) self.assertEqual( enclosure.get("url"), - "https://cdn.example.com/main.mp3?token=abc", + main.HLS_FALLBACK_MP3_URL, ) + self.assertEqual(enclosure.get("length"), "0") self.assertEqual(enclosure.get("type"), "audio/mpeg") alternate = item.find(f"{{{main.PODCAST_NAMESPACE}}}alternateEnclosure") self.assertIsNotNone(alternate) From 83da5237fe7c82247ad218bc17d668fae4bfd60c Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Thu, 27 Aug 2026 11:54:14 +0200 Subject: [PATCH 10/13] Serve HLS fallback audio from app --- README.md | 7 +++++++ audio/.gitkeep | 1 + main.py | 9 ++++++++- tests/test_artwork.py | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 audio/.gitkeep diff --git a/README.md b/README.md index 6e8d9f8..a15ea0b 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,13 @@ docker run --rm \ 3. Visit http://localhost:12104. You should see the site now! +## HLS fallback audio + +Podcast clients without HLS support receive `/audio/dummy.mp3` as their standard +RSS enclosure. Place the fallback MP3 at `audio/dummy.mp3`. The app serves this +directory at `/audio/`; a reverse proxy may expose it under a prefix such as +`/pc/audio/`. + ## Configuration A complete list of all configuration options can be found in the [.env.example file](.env.example) diff --git a/audio/.gitkeep b/audio/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/audio/.gitkeep @@ -0,0 +1 @@ + diff --git a/main.py b/main.py index fbb3c36..c8bc1b7 100644 --- a/main.py +++ b/main.py @@ -27,6 +27,7 @@ from ipaddress import ip_address from mimetypes import guess_type from os import getenv +from pathlib import Path from urllib.parse import quote, urlsplit from weakref import WeakValueDictionary @@ -40,7 +41,7 @@ from hypercorn.config import Config from lxml import etree from PIL import Image -from quart import Quart, Response, render_template, request +from quart import Quart, Response, render_template, request, send_from_directory import podimo.cache as cache from podimo.client import PodimoClient @@ -50,6 +51,7 @@ PODCAST_NAMESPACE = "https://podcastindex.org/namespace/1.0" ITUNES_NAMESPACE = "http://www.itunes.com/dtds/podcast-1.0.dtd" HLS_FALLBACK_MP3_URL = "https://sjc.nl/pc/audio/dummy.mp3" +AUDIO_DIR = Path(__file__).resolve().parent / "audio" MAX_ARTWORK_SIZE = 10 * 1024 * 1024 MAX_ARTWORK_DIMENSION = 3000 MAX_ARTWORK_PIXELS = 20_000_000 @@ -301,6 +303,11 @@ async def not_found(error): ) +@app.route("/audio/") +async def serve_audio(filename): + return await send_from_directory(AUDIO_DIR, filename) + + @app.route("/feed/.xml") async def serve_basic_auth_feed(podcast_id): if LOCAL_CREDENTIALS: diff --git a/tests/test_artwork.py b/tests/test_artwork.py index 86d038f..8646dae 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -102,6 +102,20 @@ async def test_uncached_artwork_is_converted_and_cached( insert_artwork.assert_called_once_with("e" * 64, result) +class AudioRouteTests(unittest.IsolatedAsyncioTestCase): + @patch("main.send_from_directory", new_callable=AsyncMock) + async def test_audio_file_is_served_from_audio_directory(self, send_file): + send_file.return_value = main.Response(b"mp3-data", mimetype="audio/mpeg") + client = main.app.test_client() + + response = await client.get("/audio/dummy.mp3") + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content_type, "audio/mpeg") + self.assertEqual(await response.get_data(), b"mp3-data") + send_file.assert_awaited_once_with(main.AUDIO_DIR, "dummy.mp3") + + class PublicResolverTests(unittest.IsolatedAsyncioTestCase): async def test_connector_rejects_literal_private_address(self): connector = main.PublicConnector(resolver=main.PublicResolver()) From 3f8a4dba5ddb9e2315266bb91607cbdd72eb4af3 Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Fri, 28 Aug 2026 14:02:58 +0200 Subject: [PATCH 11/13] Remove hardcoded HLS fallback host --- main.py | 10 +++++++--- tests/test_artwork.py | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index c8bc1b7..b565ab4 100644 --- a/main.py +++ b/main.py @@ -50,7 +50,7 @@ PODCAST_NAMESPACE = "https://podcastindex.org/namespace/1.0" ITUNES_NAMESPACE = "http://www.itunes.com/dtds/podcast-1.0.dtd" -HLS_FALLBACK_MP3_URL = "https://sjc.nl/pc/audio/dummy.mp3" +HLS_FALLBACK_MP3 = "audio/dummy.mp3" AUDIO_DIR = Path(__file__).resolve().parent / "audio" MAX_ARTWORK_SIZE = 10 * 1024 * 1024 MAX_ARTWORK_DIMENSION = 3000 @@ -549,11 +549,15 @@ async def addFeedEntry(fg, episode, session, locale): if is_hls: logging.debug( - f"Adding fallback MP3 enclosure {HLS_FALLBACK_MP3_URL} and " + f"Adding fallback MP3 enclosure {HLS_FALLBACK_MP3} and " f"HLS alternate enclosure " f"for episode {episode_id}" ) - fe.enclosure(HLS_FALLBACK_MP3_URL, 0, "audio/mpeg") + fe.enclosure( + f"{PODIMO_PROTOCOL}://{PODIMO_HOSTNAME}/{HLS_FALLBACK_MP3}", + "187288", + "audio/mpeg", + ) fe.podcast_hls.alternate_enclosure( uri=url, type="application/x-mpegURL", diff --git a/tests/test_artwork.py b/tests/test_artwork.py index 8646dae..49fdb90 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -231,9 +231,10 @@ async def test_hls_uses_standard_and_alternate_enclosures(self, url_head_info): self.assertIsNotNone(enclosure) self.assertEqual( enclosure.get("url"), - main.HLS_FALLBACK_MP3_URL, + f"{main.PODIMO_PROTOCOL}://{main.PODIMO_HOSTNAME}/" + f"{main.HLS_FALLBACK_MP3}", ) - self.assertEqual(enclosure.get("length"), "0") + self.assertEqual(enclosure.get("length"), "187288") self.assertEqual(enclosure.get("type"), "audio/mpeg") alternate = item.find(f"{{{main.PODCAST_NAMESPACE}}}alternateEnclosure") self.assertIsNotNone(alternate) From 1f274583f4f64e49bdf95d09af27fae2ba9e9d50 Mon Sep 17 00:00:00 2001 From: Stijn Jonker Date: Fri, 28 Aug 2026 14:11:11 +0200 Subject: [PATCH 12/13] Bundle HLS fallback audio --- audio/dummy.mp3 | Bin 0 -> 187288 bytes main.py | 11 ++++++++++- tests/test_artwork.py | 22 +++++++++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 audio/dummy.mp3 diff --git a/audio/dummy.mp3 b/audio/dummy.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..e4b6df53b921ae109b0fa9bfff83093e44d6ef5d GIT binary patch literal 187288 zcmeFYXH=8H_wW0p5CQ}YJ@inelh8Y%7eg;nCG@IN6u|PYlgXN7WzT$O_OqWo-!aycg92woz{c8I z|MZ;!03dj`FmFYyw30LyBln-i|GH5ArIY`MkN;IQzT$oLv~~^vK%D^ieINjV!D$(g zOsptQ9zK5I^I{S*SUE)%HBFq3fsu)+g_Z3^M;BK&4IDF1?sg>WD*$3CP&J@N24N;`Z^Ho-2$i7R zoSdtRyv44FooeAsMXW*#GWyqUeu44*l7b=lV02Gz(3^zwbWp4g7_2JB(6!e1uBTef zJcb2iDkuT(5MtdPRbw<J$D?NxpenZtqU0V|oy$FR7XL6P<~2 zm6ZrlB(!UH=Qa`w0(7an_9>L_YZE&-q>A*p&Ld4U!13WyexnX2w>DSZH+rgdP@F-% z5H(kY59FHB>_qliN&Lj8N`OE+SOg!i5JwZ#%g2hD>_rB$FrjT2H zKWqAH7RgudRKFKo8xWG}^?0OUzi5IXl8>@)`TPChZXMua#AJs8dcIZ!3L*kEXkn?E zWs2g?y*o2A(9wR%zs%lq0LPq!X2du^cTVK%Jry$Ok8Du3q?H6ZAEWFQizJ~v=dcN& zUUW+mH(i=L&QXGsl~&R&dH}aBN3G>fWJc0E_st5?P@%c6;V`HaghF#&KZFJnyW#y& zK1ARfNhg&3cQJX{rt^Utqgax5-HBK{-IuU2$JyDx!+oUSfy7TgjrvkI0-rCF1+_;g zBAFwBZdX+e!p1)bePC}n^ueT=)Ha{kO(1G^9^S8&jQ&;9y7d0d7s`K?-4w+pFdi^_ zgM(e+&wn&1DbC3d!woa>E;^sjKu1NDFd#eZwL#kwy#k{=e zo$SAC^B>RFr;K zk-kOrj1U6g;9=K{_y9mSD;}Dwkb!Jwqz0Gy98aQyoyh1^xaOsvuc znAuotYdXen?DUoGawjaj=FROt2g3$NA$AH{9Qza%gtT}elK*EA9tUkgQ=#lxgr1vZO#VzaCJ?!SF9>26S&$aY8E5S+ z#*GTM`!jbxg2QT`((1^6Q_#?H>~U3Xp4PvkAKUgkO5ZQ~Z)$N<-Gg#GQ(qjTXRT+) z9{-yEr)K&<`Qi`%Q|k{Y9{=gZ_GWGfbp#cl1gGzX10!{@nW`yIBd~;n@%5H7LbODb z7qxQ47!krPAOv|)3K-lUQ;yXnv%C%O!NNu#Kop`af;A}}7U-}473)p7%3b6mveMq<=w*VMq?vtFTm^P9vsMj|mb!4! zt>DA3hh=^92j^C?mJTNs+p3heBV5YU)2oi0UMB9zHFc$r^!swB``v191h2b%P^)T5 zQ}7Gi<&9MS)vBPV-e9^I@$V5U6`^il97u~Ic4JNXCuc_RBplq)TdLpIO2YSy5MAu7 z3&XtBiWC_D^HYFhi$?WmjkOQ-bW;U2Mca4{wVQ9V2& zQm#nP6dxxj01l;otEXfCNs*7^c6K9ke|ow2b%Vu&A)C60&VxB;B}G}h5pUES)7`$+ z;O9q?G7MlMaBkl(JD=rU@V|Qp%Dl8R#g#U4H56Ami+>EdZf!xFv~(zL)E}7jtzal* z91DCK#wl8h!g-IR10^5%z;IwgqDeN)MgU~-qvxwJ9nm>fl}-TH1tDP2EC}d%2s%EB z+dUMG@DGIP2m|fP2yQ;exftzOG%w=B*T$?m>GKsL8n{iGd_doFLRrY*ki*SEFz#k) zF*hibU)L6%d%9=DtSN7egJV`9NpZ1a83x~Sbd57Au=lmgh^1l{FgmCRA8DNnQ3mCY z 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%0AhFFBE#@dcGUXSnFO)3{g zej66`YgN;r2U@E92r#i3yhxniNpq>=4&&inbKya4@5;U9`G_Iv8eZdB(vNi8w0Qc6=ImRW2|r3ThjVEI_3a8Yw06{S~bk_}3U%bjc_Aq;>|u_8QklAIPDi75|#C8)*(uhR5!u6SnlDeAvDq(Tk!2H{_ybBn6iCR^=p+o4g(o%kUX`7!uEu;5 zBj1n;E^amFZ&d2K@3mEVvpFrKAiP@+#e(|K=a!~PC{wJ_8-jqRubcZ~9%1>hutx*r z8FB4=Z-of@=@qlF^J|ekkE-tO)PHrEa?Sebr07mR*wAX54DI=mtxhrvLjq_(;Ei5V zHCKJ!k9vVDdyo7}sF}X5WPw=bT6v}@pI#m~QLXm}7c`cjW1k57!~;@&hhnhejGR0T znoOb^N)@d4T8E*lz!ozsOhs zj!!=NIl+i~9d^$DV#?r&kQsU}cE+g)&SA1UaA-bpdVcjELJS{Tr#0C;Mtf+p(4+iJ z19+C;Fd@L?F@Q{`i0eu_GV0DwN|1O3(z+5mxJuG)cUo94v&F`o1JwknlCeC2vVk2_ zjiCr|4Yz1sukPky|9~}!j0AQyq0!Rd*zJT_zzG%8#I)g9)?`INbu`9Wx0TSi`qm&6_k8xI#e+oMSmY%JuhtrG2BrtNnw)fwpLWrUI)CobkJkO3o}2%b1q)L!#m(wy->%frf2iFT zspfMZd!3+mrbJEI5l?)E4%5TFJjP!~;;#Keh?{ASN}Xnqu^2Br13*Y3IzS!Meg_lA ziGgHc4~Mi9%!~W!OS^sS*GNfut~F#=BPK>UZaJrmmz=SGqS!8L;Nf!adKVJ`g+>^{ zlLLyZo;HKqq`^@x-U`Y^D#*EPErk@buGC7)I@Ow*;_^PpJ~7|kmG!6^>u0>8f{eH{ z#$(0~Aor3isw2)LKnz_6$MNUyqbIQR9i!EEBfWIH%i&K?8lT)dRF7jrPvGf)Z`}bU zgMxeON9$`((hsUPOy20nS!WUvbN9Z?(f&J0r#r)s?B{P+-+8(lCfVW*9G-ZX8kpWg zr>}oM$dT*xT)h^&eZx=wmsk6HR$q9s?7tg&Fm(^{qi>=Tn@ zT%#ZCZ$1uf2LnvtsB#u^KZ`CpNOX;=$3t~QQ7@nP_aF5CJ@n~&uqXmjZc@Y(@VKvC z7INzK?8e@$=ebwQlLn>*#h4ys!1+>rtm{tCJe-m-!hYJ=#Z<>mCf42TSZB{mCWyBE z$q#cyH8crOV&6TY7rQ(BLnxVn%>T$(l8&+;+Ek~3r#>Tp+*jLumptP?tt^JV>UFhn z`mLJ%8Gje7{#R>9wXOd5&$LE6FO;z>s)_`=%*-<(j%Yr<8#$p>AJCij*@G92RFGiA z+~q|Nd`qEiex?81_nh=Bris6bE&+nLSb$#gQY^11+XOENj%CrI?{3n6cP;L@tcr0i zr|Rr1|LK9ZzJ+Ip5CD(>yPed0pfg3pNLTM-`c?mYmI$h9!tkd zN|=)mB1QA8JuS!hoXU1in^(BYy1pozx-cI@h{(XOOK~D+gTrDb@L@#KaB&QDS6oKUkuPk8jAisQ;=_J@`_ zSH>MLiLZiL^96J!mn^*IxpEZj@|XXHXu3Z8=cb(VubebIgVnb9U1<+D%$pmIPIHKC zBs(vY18FlNy)`1&Sn>Z5+F+FB5Z61VO1L>>w%i|(K~eFtm-4UAHveY+<*g(wa}HpA z$053VpI)S@Hq(943~*SFx?I`qY|LcGpP>jShA5wI9?Oe=w8VQR z)=kvf-m-EbQ9Rn2BFcI*FPcpb8+IX)HWL(UhSrOFZ2g(mdb!;69NJ=_L(|W+ zlt%b(-u`KC=?Js1(U6=#lkl)fl*ahC8H|i!0;-RRkn3jih*d}qXt4G4RcU#Q)4g)^ z>|>uZk5qTVCFN`-R^X!F8D$^lQ})Uu+g&31QXyfkYPm|n&Kt2#4=2stkm2jTU6CbC2J&DwJn^iVn~5yRuxEVpf`aV^G!6(Ft4c z@1vVh2>@6UV-5^Rt!{Z%4?IRr9mD&xeZKMmw+iFoFsMLdp*vh~K$bi1Z@L;^tsM4x zRMbNP`~;@gVu)N0n>_08F8O=epREtX+CYykntXFRRY`qTbt&%7>PO9_nww9A%J?BbtPBdE%^aIto~7e_{Bq2% zYEFI4IRYMi(qf-Iw-snHy5ZU5B0^WX`c(CI4}BfayQW$l@a}o!JF~zq*<=`38DsP? zG76tO)2Mq9#ToS~?wcyLy-2@4r zx<2U@dDuEa9v*NCok*g^xfeMRUvlD$?T2IbI1m#Rs&<0$HKH+k@xovT=$(%S-F3ZsE^~<@6{GZ*QDbI%i;(EultT(B-+C9M$9VXmpBm^v)GhY|O9(Tj` zT1-n;!hljhd$3SSq#9(`5Wyc=$Op0UzCLos$&r%s?>_~cRG{M4D< zzY{vf)pHP8hEMSNELw*tRu9BkWGi}??N7d#7zE7%f?>=@fL^5d2XaZnln*-4XII#R z#O|GX7|?seO|Hc)9f>r8$7~=o2)(;wx;_)C6My%Ri+Y3)T?V~<+7mJO(O#u7X-IF$ zqr`s*H3Pyk{AXS<{Qr)ts<;^lokT;#^fmHQrE4gx45rHnL9cy6nMJoxJj#`c{Z{p> z!V9QKistg<1EUW?a2NX1ZxIVImgeVFRKBX?AiXiXhr}fhR@&Z9e#1?(l@(Npw+qmEK+BazEE%YUtVP7UdK_*UM&Eql`w!G zj`%ZCexEwzD{tO)?{HwkkND2isgKHHubE^4KU>9Ca*duF{LTJ@7@!RbV23G0WhG6* zc?p>;kW8oP=9?KzJVxd6m3!rBcq4413?2x;1i9)!Rk0Cs?2!}I;HYyZ@xxo)x$Q_M z&BnV}4P{)*irT<3{zy_zKD)6Bb*##EB1ZS`-c`i0BHT=x=*|2tA;kFDu#8{S_!-~+ zg{v#^&p+#@hy5^B;$@jIXPqzrPF8i85u!;jp4_HEy97xBSq_eb0^hfx3_m~`v-Iew z?H%8rcm39Wv<1BecxD~=^9$QB?zj6{Pv>{j4-S8udD9>K+LD*wQo57|03nPW)Bi}p z@qk#Kx=P*-84jzev}PbAPI#-)tg*({Cxv}3CdvFWNA-tHC@cERWhf^(SrF|BGW?Nw ztzPp{E~#~Id}FM}DD&kY`O!#s&~K|OV{Tl8toqA1cK!);)l~OAO7Y56FlS1H^Z96T ziiD;)#+oKMnzPy4$&K0Oj(WJQnX@}H&Dqgvu%G#EuJ~b!rNnSnD6&_T|JiK?xhsT2 zZ(}cL8W;&J9(`!PboO5o^;b-1k8;dBxb?&e z!$Jkcb3e^V14JIcSBzTWSU>UZzmQ4G&}Vxf5N0*+p2yL+stbZH@1u3`0sVoF68#x{ zf4j3yq=ld1BS|6yz#u*YzNGhNJp0N-sXSNMu_5e==4RK)Oa# zDv!}(4XyGz#i+||pm)Hba0`7m%4eFA62*I1Y`{r?0ubcQ^RF+t{w=;k1r^mMcuz>=rHlz$VltE0*5+|`;D@Zmk zzFW3jRm?{2h_Xkf0}*~ARV8`VBrsDvgd~RtEUW9)Y#;f(>CsmhOr(gi%o&z~jq@BYLe-gCZL zct>!38m;?bC`T+B-MbY7LT@)Z9%848x9yd0q?`9t5YHP^%tuB=M2kY~>JHSqV^XW@FpprEC&t%aG`n7kJ()s+w^ zRG1uXN!Xm8b9yCbW2Tr}x-W}2Y$-(fvFp#$Q zU+c=wh320UE=-mMRK;$uRt{N0C6grl-jzG^~Ks{@hjsPB=aW<#Bk-E z1A}-z@<4n;>Ogk6j*Rost}(Lbwf_O=?5^{OtZ?w5r_O#Pm!BKNKR z1>Z0@vkz7_zx_FMVg_IgpQSt;;Bk5U)vGJ9guRC;I{y$t0(^**S32qe!O?PG>qasN zVwOoinQ)5mghS`E>H4;6(;f2*Prt6O0+MnhFz-p+i^3h@%im(9V!818De1URxu-UE zE@rFRgi1iW*~{0=G>(O(wXa*V_cY#SqgTmff8q4QpP=g+=#?Av#)_*FOgKPURx4Aj z2UO4SH$C?D^ix?a!*C?TIVHQW+Z-nnN!RRQ424erQ=#sE+OH&<-&hXx1S{>6Akio{ z`z!Cd)QkGC@C;ktEXT}Ajf{_zuRQTp-6EgYrt=_8YHwbf_48eoK!_iHz9D>H|5SlY z{G$FowAWq#{Exa*-~0zFETDRzdr!$mro0Pf$-2j$lgSz)$qE8`KlQ$UZ@$sXtPmaD zn|klwnN%IFq_j45BX;9~TQ?k;E50hR!ka$SL)}3*c>_&2mfz~8dWfXg-TNVb)TA%A z)qI+J^`$mj3o)?S$00)oc&nlUOy^h{hRW8MNydgekn$Q;1?x3i!}m?KN?uz^*jvrN zn_z2%-2RB71XpU|{nN0Fxgdw=!1@;5Yj1dF3BFlu^OFA%k_Hwy`AsRf6Jxby3`Y`K z2LnZZIWI`^X~%uP9pd2Gc1D2B@&y}aG-QMHF?A6luICtddVGr=7T#i?Risxq`?o5( zpiGP19>wcm>r8if#Kmv=OmuK*b8b*_XCnUT`nQzjT>FB;4o$baHwvz`UVR+I*?n`o z5&40kX?_`P8(lf7oubbsw64cEF`W9;&z$F&7iS~!=xO3F7b!&==oZ%NPCa*PUwB*2ZoFte~Z6QjyOU!Yc=D2rD=Z=v?+&aQGcTkzcI+TIaXmyZ&j ze$eXIf_eu0uX8YL6w90r)4*v<&3RXgtTYEjPWCiGk~U(I|9fDLXp985F+_|(p+z2X z+Oj8?pOVhzNI#q6PqpQ>Co|Zi#sjO=aa#Sf{xag}X^m3Mb(|6U@5Vk>eIZ5aZNd2Sw{MJn;ULKjwuUt5Y#=yB20}tjnix|bXfWe?~anhsX zmVsICum3TH7YKNQhCN3<=O{qZ#);K#OLAPv{QI|X|4Z;XLtfzJKhGdEjt!P?F+5`& zo+;oZ*}0f9c59{I^s<T&DfGOEf}QPYM&YGws2}2EtwAV;y0u3{fxo3LVa|JBNo~e1$iOrwWOYZPM3V>OJ1NBQdxhX>GF6f7GiXM zqlfEGk;g5ny$`$Cf*r1;e20~VYv_;zuB9BV@SHs6KUD`R%G94?J)@PBc)4Q8X3`Sy zOBc7PSA1iq@oG7D<6d~Y+BbEFdp|uh6r29$R(-Xw{+|TT8sM!LvB;(X2(YaCKf{ZY zW=G2@MX?)Run+zl0r6a==iTJ=hunNdu9_zfpBgjrjL_PECy2Sqp%Vm#)jXxnNf5N% z97U?2t9~S!m>0L0lADsS7t`mn9uY{WeqW1w3tIxrJ=F&;0udvU`b^?c;$RXMtcPR- z(!lgt$w6o@Cv%I^Ps7i&9<ymt z-@}k;kSMZ}0^mb~LH0n?EH>6J<0bn3x}Rrv2Vi(usPAvYa~Ae5PfX6+J)Rq?DPWCx zKAFC)_kI%&xJGH{QkBV;QPaRZGJbA)V1OjU418OKIT;@x%csYXPV?&9_wBO8k%Tul zdm@K(Ut8A*g#2eS#v{W^1XyOr}ozrbm<*vnPlng46=JcF8ezrMeL z5CVi4dO{5ldNHAcD4|LTN|)X{h!h1uh0r?!(nX{f0i_D4Na!6=6ai5|ih>9tA|NGC z_&xXA|IG8ex#$1lw=JFAKTlwuFket6>+S#9yh9}iCY zL=phalG?1`KO zv$0u6bmm8u&+6(sjPT#DX@LGp)*pnqlspX;C?dv2cM>7dJ{NQ$&l89Jao}4soIcw1 z(m-kGJM-o$s9zqC_8BIq;MiD+5f#TSC5=T5sFhJw+I4!42cd?>lK(7PcgS03E|h zRXo#TifK&mRFq6#oG`ZpgzAe9QXF*?-$dXg;6#Nblf7V>@R=bwik_BN9vcGnVserf z?14pcXF(i^TCzE$7*j#&MP>7F2Fvx3)z1gv%MsqKA97_o@8TMB|9t=BxPbSkdfY1H z2Q}2ZvbU>wVQKD5g~{G#xSzxG?2jVf_sDmTU#K~d$u4_wtxw2@Djua>kg*v+A3!58 z)m4}*Kn&RvazmduRvje0@o@m^>cQHWe%I|SL6gzzF*;GqP&{bT?$SlP)R(JW*io9? z**isFkNPrnM0MiS^NMFyN35>#M*ZOj(K$l7P-`7>8$W-2Z#- z6|^VE90n>jVUR^Lf<-o4hnJZTRDGp^4KWu-Qj4T=n?Mr*kKcZ?dE2 z8Tn&1-=NMX+1AtqPTwZKy7TJ(7Wr?F0+KFX9ZP*IYxD>J!BvYUijT+6vcVV`BC6gp z3SY%6pchF0Bn2}9Y&M44L z)J@|^#SIwUMnr+jlr@=6?Va$Y7pxUV`Qa@#3&^qrdS-3 ziEdhK0@Rrj)|m!J30c|#5EvpdN*i!CN>`w_-o@npWCw^wV09MrWI2*s#<3np*OFEM z7psxA{Ho3nd7AA8eWFImYtI&IA<8%lIJ0*!jGZh0`7Gk65do|y%jr3idv?!xt&`FH z&~TB&fIuFNK>RQJLm+@rgUN!2c>>D#4P=RD-#ZGbpN2&Ok;Pz=vk4T5q1nDD6z3bz zE@@2-N+2a5=;MjKfZDu2>&P-84wR~icEu?vz&JEQDdUfb0yf4;^%DPuPl%_{GQ5kb zTpq{X?)$&g6DQZ8{CVSP_V{fl39hNBw zu8LLHlmMV-FHY*3gsBODjJ3*QKtxeAqLM$8Z9he;o0nf3k-m`#ZHNMRUb`5mf&OU< z9!?oh{NGaW;mWTe%0?iSno=Is&?MohGx}}PiRVz_4U&I#SeLL$LT57lUkFW_%Y0Hc zVlMJc$q&G;XiWGvG#Ur@auj?yYx8uuJrgu7qGoyiX_?uVsq4D)!vvrm|_SNL`gQ%Ch=_mns_H2>vyQcvKCY!y?j{B&^X zcgD~QY=(_j)wRb!*20xck&N=Ds_DJ>mFhsnaIRF6-wTDUw#WA3dQ~niZ=Dj05UdWM5|Ud4J-no83b{_ohugb8;EdK$ zip*CDak`^VCSWgYuK2kRr{TshZ%y&&{Wo{f3Zb+-6JcrWz zzEjVlgs?m>hzufSUqN*j0wOtcWT@_q8`UZYF$~zrladU_$LR^TYIwQxU0k#|61mK* zz}Ns!Gn&7lykC+Vi*m>BX0D2iy$J&2$4^=?VpwRM#ff%6VD z90i_}dBj{Rc6DH)!(~86qQ86_9d4k%fq2&XSiIEjaqsh*avd6ymMb?Xj*~jdsYhc~ zP7~oZgkEJ5w{~V1sZ`S-x=|_WXwo7a0lqi|B3^^q(TFzL&~U(`c>3F6kEKk1?77$} zZT@#8Y{{>o`$fhJMx1{SUQyB4*3G1eQPgsoMaR6EdzlNd+&a7n2t5qOBt-2d5sYeLQsx&> zlDxtG;+H`IXFwIrWPzr{PP_SmjFVjDZo}hmu1(loAX1Pi%S}1aARuu|`EIIla}8?5 zwy^>`o0GI%rol9^qg?ZNIJH|>vW_E1?E|kZ+wVyKKBUzSuL5jd9Ip3nXRJ) zAEI+RP^yeh*#>6?g<^kHo}=h*7*g#IDNVTFd_B(?2Q#+x5^6B%?r$~~c6BKgMzWsJ zLOJf_4ixL%()CGAeLp-Df>!*Zu{9Tg{^rM58UJOgY+Gh)`*+SL8rqj*|D%~!G=VY~ zoBgF5qdsP$4PSQd?PfX{B4!FCWVF6bQ@C4Qc5Yi|UG#Ouy>b@ApMBG5nXOTH5Ws;b za>e3OhgRv8^OlkR8BPWEmEJ0Oax-pa2lvL}vS>0lToa|u9<4MXqnk8l(Jk4|Pu;Vn zvkj_OB)-ujEO#am7x5!nPiY1?gudqXVkP=E=Jc17FI$JI?yBk*GHNg>>02AhYa(nB zWy-;$9Tk&BU%uD3)F;dBhcN1^f7`#YyYi~C`LUa8wf^D}SZm3)}YD+P45e|3ZsK25mH?0W8#H6Wl+5 z3eL|!o!FQLESL+?x*oW6TP?c;TRuj;vwAh|+l3V+&%=+s;%k(88Fcu0sOSb*;Cc8{ zLTgkgF&;VTAGlHa+Um8j##?|hIuIdo!1nCD@K+8hV!cwQ0awqDk!$UDOx<&Q-_2`( zD68z!E+b(CVAO(MHk-)EQX#K;(}{tQ9j+#pmj_a>#Uf;tmhH8@{UXRLAt%p^BO~KG z?x!IIkbRGed($IlSTkaijh0YssPs6hRAfzpd;86G=d;NUO`#u-Hkx z>0{=)2>H(2d``OA&+2U2MIY;m%4RimRo;`}R_piGTON9Pn%0l&y02#RX~oFueH*=! zWZptbzl62Ji00q&D@ZPXG!b;^DwWL02%)9dlSThaONgQf4O_Y|*fn6=$+?!bQ%S=?rQM=Ctd7o)IPfV%=7Fj*AmtxI z(b@H7I)0L2y%#WF`^PI)?$LlXp?HiJr9;()d`?kn&kR~IVwJHB0oa+mwQrl_=TpO1E?itfV~Ss6)OM#mv;IwP16eWq2_+6P@qJd%c`#gL#jJg6F>1 zkw-iQvA-3i;vNqPzIU4vh-7Bzao$KYyTI4uQVmT^Ezv6%KX2LL13CL6K~y1+*9aAu zjeL0(mB7Hm>KVCx&lVBQ{=Q5ri^YyXlh(qh{S6~zj%)SDxl0B+BOV7Q@%1JHHAP>g zGzqLwLLe9xcMhOmVBLaQ+&tz|(Lpe~E2a0b&RejGLd}ijn!mlb%X2sPuB((aNHebS zecJassKuX8^Q@;axH_|6BF#5^wRs+%+(UnaE7@c zUZgu)u@7R#Qy-3VM_kmZmi_ zS86ZOqGQgGu14NG9-jGxbn~FZw6>=Y$A9I9ggOK!KRqBn8RYBvsE{QHG!$Vw=%+wE z3RpoA7OKd7Y$WqNh{iNFLt_X0296cya$(M(#&%0KJ4d7-ggmNGmQ9`X&J{j;ywLux z?Uzvl@Y*Z(%s?XaKB&bte7N>ol|G8=x`pQ|f2KZvx0ZqlB}uR4CcN=r;6aJTdg1+n zC!zN9gTD5oc{}D3^BsSGd|-aO`F4~2>O2wUFD76vwg1}C87^@-N1ae%VDWcXs_~kQ zCp)D1;f}-cz|*e$Js$F{v5?x2^>wXRyuO$NDff5{r{rK6cgB-c$7!-s`S5q=axWEh zFxnAdEBLf4moG(MPirI)GBpSxFv4XT0vCE#>*H%3d-ST+wJy041*5@_SAwu0+QrkU_jB@viY|RcU$AFc zm*A{TGHp@RZy()Oj%_rh4Lc)CWf?6~YNhPd7-X>slD}=abOtLRqkln`dXnxuXFxO~ zfMEb+8XAnM0ggf?DjK3B0??sfRG7-P>_+p%MEaA!fJT{_r+-`}4lLtgrtFM0!S=I6 zGm?_9H)(sRCK0l4;nA%83)oezW~NC!Yy!&;-NI8&S|=muML`hO4a)~+!qYdD#6+z+ zH!-Rczje&~Qg4lGu@kl&d1x?QQz>vp;6_&i%U5oX%RZ})2u6Oq4>k%M1UP!$ajLA$ zcL$*%7$5=d6=_6!7b!#)5CiBTX`)b3O8j|>U=$G#QYX-SyeqOkdKJL`6CTiWB1$0xA6PJ5i^;1R6VKc0C zcYY#_`%VDKF^o|4`ZuXs`IY2M_3+XClyh|RLkn^+|LpYFy81D6kFVb3EAK%?qeG(> zP0k^&J7uf0dO@fvY40avrRk8anu1h3DaKsm4?I$;v{IEXq}V{mIpttFTB%C%Ff*z& zG?8%SVv4-P*mW)ff|cNZW=tHk)<+cNN)p6G7ZU?VkjPJ0kzoj8H1k|4pr6Ed)8+$q ztg+L>PgQ2c%f^i-3vW#G1r35pAVBDVXiCn10jTp ztc1ZJPaC0SRgw{l>H`KThpCx*PTh+~B>Y$}$*r%FG9$gi6<(9hIk!V5haJ+rx;!uG zbElUr&h&$S^WY6j?!W@S^_*uWZ{k2hvO2UsB?cJtlLvep8!AtIr~(j?Qs%OvRI#=Q zmujj_0`z!p2#=^egp265%76^0EYE8frddePVet&op(9GHg77!o5&PDaP;^YCs%5ke zv_ZL2&~aF}IeHZz8{gM3zzIMuvQ}cLg|?9Z6#_xxCJ_tYvc79$J2N(RaZHLkMFX9p z%a3@wA!OO#ZuCa8d>{ie!7oP&0Q$F$x{b7YN$I2pG&d6y;01AeWZ~-nyPbx(U98%( z*f)Uh^ket7J-ovjD8`bb6d-aUuyC#;I5@ogt#hdp<~C=!Km)ZIGgXQVLw7$?Niyt7 z8|JC*s!qSnP%(c`Mr7Z}&ne7NN1wSK4|{FdN6au0w?C_#c>S5TtG&EBCR6XMHmfmCI@dOz`whLF zYo;EnG3AHvl=ZitZ!f$h+LQhk)DU*9Iv-^r&0F8^U)gfrt6p-E6D5J%SM`?ylYhYUYm2Z-@cc9fv>H~XPnd=q}pZ+5(!EtPYNM-0nQ z!x1~*@;)t&N(O#Q*ZAE1J8^m?wl}f^iJ-|5r-Exb6!gN?JohJfwA1<){B_Ol+8LMb zBa&quZ*}$FZ`st546l=Z8hl)JtFYPj_Zvf+ZzBxKMdbXckJCyK6rUo0j&FLg`n-sn z(y$%?@jejAZWK^j8o0`#k>O<{B7F^zDs6N2LR^i(wUrZJFXT9&s<~hY??uv?p z9`UZtzL!F9{l(nQsd&t$r0VizgY3QseVNj3O1Dve`C_$Uc5zQ!z!t$d>uxeySmgD7 z{e~|>&=zMH%9#bE#ZD`Y@_=UR$G#R1Fe4T-c!hD)C1Rj2hb!o`s95HbRS|HzMhz&H z1w=y}D>o#G&`b*cWcZrM6hlWu)O9n*ZqdM>BcR@S+@x&{H2X*iZ)p60{mt`T!q6-h zj2s#aCAa>*?6|RMK~{WxBi?wbI89w{c zQnMta@-$q)Onar`P|adisZ54VrmxQQ7F=ZU=z})P9%F~1cI}(x2$t*eRKeYwEV+oh zFeJ+%i-5!p-^pG(Jj2s!V{w~~_%}toIq&_LAj=Iu-X#gM$lQ2PJ#{oa=^l$Z{%iY9pNzZ&os- z>pgyUdtmndbekX}j^rZ|$dEu94~UnkG^)>>1()>s(7jC^Fcx86xz78JD*p3Oi?wcr zKCGaAC*X?Eut|B(#hmJ2y^}1mR?jQk3~C<8_Y1+=YfS2E&`wmAj}#iSI`9?0s>DJ> z;YJ4PR#Ni5^8StnCi#zYju2bt#`>Mg1HR4w09$iD%(&Ex-O%9BA#)k{Jq5 z7@+B&O1I&f-6A_9?MqoQ?4TiK74J8geLvqBG#N+r;Dlbsc#pOsjSV>NMTAprf zJM!X~K52Q9z&mzvG^^kD1xx^7;v~TO{CjmTdlCSmEh&X91)>2Rz#^g+utvO~3Kt&W00OAcFKm7^zHoj)u@w}N1u0>Ub zXHQRLO+Uj`u-4CsJtZ^=ARj1dw59;y?;_=QDQ^mL;4x|-Oj)!oxKE~zrp-h04k!jd zJNi@WK+r*8ap9foKaWyRvKn+xRGu?U3;@NEaM07dO$B9>z3Yz#97UbYl^yQ%c8zAs zermm|xFzx82c=R&Ju zqjylQqq352OArH?1N##2cLXD?frCh0aNZSaujrrFc^B_8-P=DxMxeHgQ_derG)3A*rN=OS5t_xmKrHb@VyM9a&+X!v`ea-;#9h?6 zbnXq^30CNEuly>Q&dL*@j({zc^cw~_KB=?L@44s#!lJQUpo_)^i~HS1G%yy>Q1=3y zLy}Q6IRTF)+0w+}W6x$ML$j=Avu3i9=c2@jGgMEvem8L!H{T?21Nml#HaSgg>U9>o zJ|^7q7#vfHw zVij zm;ODcVNA-vT3>5o@7b}^wsk}>OU4DRXyt6f-)-u656Py_qt2TcW#|6zfghXfqyE_r z^TEpWA#1Y7OSf!t*ZaFBURwIl&N(O>$X~QBcx>~24<143Sp!pphjVSoQrdRzFFkuv z>tP;He^-t2^f+BQz8>uDoP4r2UxT7GwG3i2LhwVIisr1{AGbC09a0UCecAzC>;DU}NJ zP!-%4!CUDnn^}em+Jee7*vCdjBr)wQI;K~|2cssX?v`6xG`>Y|21bi@Um} zCgei!_4rkSiC5x+n`dqwe>=+lx+Ah51RD#8K*Xas#WmT(*wTdNunUl#`?7LQ(B%7_ zIsx^Dou)HiLmr&JA2xc1d{E`}=_H~z@9WV)`=L}pT5nt9YG}mspU32*omY!_KHJYj zy2vB59I*Z?GsLg;vqT2w)D`LWS)u^5hdOG8$R8YO=d#k1^8zV1|nA#G3!#hgEeZ*vlAD+XqiK4v+ZK?qC}QOam>$kbPc5B~ZWm>PQv^2Pz@;(ljwe|5SD5}a zekcy1)8(V|f`Kim%m4QCf}<`5)z9J6$V&s)zK+S>d2PvQ};xD%UNd z$FAf1x!@bF-O;eyH(ypJ0L!dkM+=&z{+6~$4`(#Wc?*YNIRgT7qTVSN<{{?-?-tOZ zynEpU7^ZWT(m3ytjx;!}Qc1w6v{(pI_kpvq#B2Jiem{2UZKJMVDzIMAGPi~P2+VA)icc|hiH|8`~W!M1UQ9*#q-u~%rxv*cSDVG&B>bbH$w1^dra3=LA#|=t zxa}MXa7M(>K5v73qr83-FhV&6>99wuc|eKK)n`!`+j3)o>+7?YL|A`AN@@D!1VQx+ zEf9&aN*u!6*GK(T;d-41h4vxGV%wWyr*(SUs^DW(F$F5aFV5x3VjYi#%3wgq75OJ} zi&N+91k@4&uc-SKj6Z9wnENbWZ?^TB-1KOK^Jm0&$$Ag+E-!{Vl&kc8=_iGVv)OJT zYrf*m2jUqzgnJE>0aWV1sOE`6nBg2+IB{< zw{{}t+lHKweiBWvC-S0V3zX>(pHoLZ%ED7|v7*-zq1@#l9Lj)X;`Y+)ZZU>5U87{m z!D;d%13g_{zcg4#_ZMZpde5rOM28Q|tUac$g5CGe(`G6KQ>7Gp%K*$)T3)iRQ^tke zK@A_LyR!B^Y{@>+8x6U2%kJnUC($kG-Ngr;oP4e&pt%G&GJzWq^-l zhG?-vGrhzBB!ZRRabij(psMWgTdVRCAxkYMh|X;vDV^zd2v$yEDKSe~$tB5rWDET&82EttxGsZo#wWTXSC{c&Udz60PfB@CF}o{fs&mNHth zvF7EwN0w~bv~o#P9cfjtqj&^oOG{@(Me}Y=P19-<`PkIdWR`~Qr?$Tzzr)WcyGbJx z{;FR>n0#H4H!(Bv>Wp+)=LGE4ILG)H5)91+l!7Pu@!y~`!l0M(gKOeg!)O>ubcCPx zve_S_ckbr$W@hU|bTNV^NnE4kB2*CN$1w1uzf${6#_e{8vvBpH>tZaBMv^8oA)kI!$0V}-_X&fWDajVJuz)<-76p8+EKJ( z@p*s9AlE%G@qX5s1ZeRYzgj2LzWRRVxzvy)2swXF=^l#n%3Gsls3^Uo zy7ct<24|;ejn>BAF(X!PyWGWV)D%f5Bo0xycl2<;{w^(M*(ss&k;KcbyB`hce@O@D z=u}tU@U0TDzPb`|5V9tDt>fEJ-zENqPsOP-L&}ofk>`qTjXwO_Gk93(NRU z-6BLUjV|Bk?qD1rbLjCaaxgGm4`17Kvq=%sZB5t+t!pS2FBPNfh{pbYbXh2ff4Wv~ z)|MhQ11@@_>8oE^^dOb4`F0t2c2$F>eOzL!6#bMgQPgQ`2_BNqb8|G%Y{;`BRs0N! z{UabZ?4)Ha)l^Q<&eeUvX>oj7fPL zD#X3qo|l_07mXxS+eSA*GNCfC5)&set(#IrBW4BuH8)9JA5PwD5ao8oVruZqBI@ho z^qJc*@)cC?nof@a?O_rk_z_iyWZK!4FDN<(IfG@S(cABgDF&s^8^S_xs;Z03%zCiZ z)LD7A#>&!n0{2YIsiG~0E9Bx6U%#BAH1hhV^uZo@CnaPO-znSkv~2Bld^107*P9`; z^Qh5aN4Ax9xcZEruP^M3#w=d=KEeS@o!7RXAeLLS!oT;zEdck(q z2F;RXI(3jRBR`^~JAj$%an>i;7)i>1bJFwQ-(-7l)MGwstTJl0?|bK5n>7dkrjv_2 z#2&cM-nYLN`t|GKLyW&aD$Uie#ohtgXmDB3$M?KlE{wa`h{4h>PR=3rrX=%pbNuUu zCR)QBx!A0SG^coDJ~Eu3zckN;2*%--@;$&er<){_8!}iinazmx-z8DUaOUlRI+;s}JU^48NtW z|N4-#Dlpyj`J?8si%diWc%adY(8=lb`>WFX`0H{_6@yFsD^N1ugBLo(AUpuFXE(s#`h*K7>5Xj{u`+!dV8gujp@mJ*FmRW3USY{kQ!IVTVz5yp?BRvQ7!whW zFk#GPE;Xar)JL9A+oYP0Qa`U8VP8GJS$3n<`^x28HiLN~50A+!;d}5PGI{+~?`IFk zB+4rfI0lSv0?y`}6<|LSl%SJ1#97=?4z~S7cGyCttNC1>ISs!sElqc~oQg|2j8Y?~ zzy(Qyft9dKuHU70sF33o=dnzLo0%>$Yli}HH+XoeuLocfBWVZ9LXp?6p{0~#d%oh% zrov#teDawKbIXgxZwm6X;2j_$P1kebL?K2+V_wS>iBn2w!Idi5A{CZ-s z$ro5a{_{$$i%g~({`^P85N>K>-#PI<<MOW?7%bKs7b-SaTW+sK@X!Bq+Eqjwa z@k_6rUIFR6+i~6#!W!e;*tB3Wy8&9mDeSegtGy0Qpvjh}(;8l4!({l>^%e62blCNm#exeMPF3o*>4*B2zMb9%mcIJD8&j>6 z2glW+KoLQ|k6f)Ip59B=;axTpX~-mD?q?ZOM#1o5UPXI>X}h`i>(kk$E|(vYcZw?0 zgakO-YU$do<4V-EU>c|z zWo(ol}o4$xh z)b(53jzU0nX$`o2-K@&k3a1p`Z2u2~84 zO_uq%Hz)XrG@yCsS^9F5nv7NEQCn6S%3{gzCs zYYL>zdUbU$d{Z{J$3HhC*b_aSzkmG2boGH_&1ad&L=LE@L;p#|k+ zL8Aq6M@N~*>fNRr5N=vxG@#`IWyXPA8q=wT^O-CI=-)qfBxbZH)C76lXCfjIZ;0al z?WiRF=%%~r2S0es`xfz(_K<9rOSj_c|_&?hEYT#o0wWomTqMo`o z>+0Hm&|GuzGcT@KU07!HbOw zuF>~JyT@A0-}WLN=($5YSv$E!?^$Q)KQ|A2(H2s~*IDCQe}V6wlj}ISzk))?6Of>M z%7|qu`aQ?`n&ZCZ%VJImF%Xd(+h>(O0o1&ep0$eU)J+P9Zxrw{h{#HBT2W^|e*_!- zObwdU3j=|Z)0~yv{iZOtZ+dIdC@F7vN=ZE%E&R(aOQkB_r|KyCvrvN`I}+0?fHszF z{lc$z7Y<0_Vq@bnFCi@pobU)bNc2=mbkmeVoyqkP3^fV?Xud`>?x&Qp#hDa7Hal7G zSCGwOzJEBaaw{&1>*S8j=;&T9A2kTLHxENaAEsStJy2)99YH=^CXHIC)<>dx8n|t%R(x^*<^Ts)hYch0}+R8cxXh4h-}d zf@~3I&*v?GEweq)9NxAU*g&QIC1J7`3$8MwTwO)RE>Q>`K7FJ=gJ^6HMvwn>@hx$eDH5hl5k}{JMW6*-#DfCvkj2C4(yIr61XU?BVYt%;Q>G|@qR=DFhb2ZVI>r` z*njFmlxaCHMT3J*fSSE>U6JBK7A^!kh5a{7fF~$DnYcZUiL@MpHhR#3_(RL7QEt&6 z;?B@RaOW8(Z^-Ev*OagLErBSl-6btEloK>uz(mfoM$8a_niSh0&-2QufD4k1mpV~x zwi?{`a*wWnsP#xs?PwR{mvb!jedh9>WI$xa!!fni+0oaOTF!<~$T`32LM_na&nY@} zdTZOISs~529WUgbxcEz+u$UY@vATcwN9cFw*OMy&opDe0$h+56!^t3k7D2hup(zEm zdXAuHNG0WhtRx0xMt(6WuSqOq?7)-flb7kLxTF&(P6i9`(&}bMA$6m%##v`Cv>?Q9 zyVnPE?&rYw<$pzbYM=2UoPWcRf-w4JKp2<&-C6xqX1WoQ)ElyxE}tE7YmuhO{&Njs zC6C?e*)Q+O8|-XNMe*Jg#q3&Can-=IxcfwAbHss`ZC%( zkGjoTXWO>M{i>}CjVB+e!F4`M>H0SoogeVoduG=JFpy5?7OBlX1F-U}A??I$#>&wD zc?>Zr8(2~F{}hC4+bD#TGk<@`O#5;BxBf&$de0fdO&*%!2IFrS(PBS;`mybIfZlm1 z@^ul>8(({ilR9U?BqN7Ao*HoKm45aMOS(%*tj1`_2rWRi-4eRv71aghUdc*ZTCvC< zP1#urbv>TY|JCaJN5N;O@#2zdjW}6tO^{tNchj6F>1$D!<*fs_%ji+tC-an>-%kvX9mso2zr6DOBIY9&Lftk3%X6+?H-adE&cl6hN22JA$AhpuD{C}9{fnoNdV_wi{{_gUnxKlS?6`WOA&nk& z9keDXm)kD8-*nb$AR~tRnFMo!rpei#CUpFF_Y-g=WBd#6zNpqm$95~|lqJKUnz1+o zLo7o~k~CjvTH~m4!SAL&8Xy|XZmID-pKmhDqz~J-?YZx}-R6*@ zU9XBmxgN{gHq_@v?2@-7WKdVqhgArUiRUun-o@k1oGPv$o%peZsP(Y|Fx9BCo z3T{~$jcvt`7hflWNAHef2;zX-2ra!R4X6Az{~}WOC%F1m6yK1v+%=7r2XTbL*WqGf zj~9@aT6hVnL&LG@Ge7JMXNx*NndQE1+*2NXPTt(LFh676d$9Af?`y>VHh!n^k&o?> z%=4{*!}*=BcXo5a$q&0ej%}a5Y>%%vkax*@fvbx4=gWtu%bCUU`3}8KJ^-A*s7I(# zRXT|F%yc$qCHKV!RA@A-i!OJQuHLzd$=jvv3milprb14YUsZI>58o^&UUZ8STK`fO z?=GD{V&ubs{_(RgIbj@s{(8cBBn*I`Sj53N3HMDPHmP52$vPY5%@!+e@v(aPtMr<}d_8jd>*&r3mz*^0Z@9=&<96`>cK%Hp{4R2GA@KJR8M`wv!V_416=SW`grN$_u&9 z%?nYhaDYQGxFT9S?CAfLL7YNvyWCL=IeLEPcT_ zA5>a4onSUydNsSA{~H23I0*B4!I?lnx-7)WsR+Vp1v6M>J^qwG^}cdWFI(Cn{71^c z^ZcdJ>9)FacTdbigU-GEmFUy5@#g%SxtxtRlLlLEdpDoicO6QptBDFJgmvaFi30#A zie5I+b9iu)rTBwL85ljjp{(q?|7B;YkY8OQS|D=FND9nw!HpD{esJNG5C?U(+<}7M zRfdtW0(ZLc#?UeKK5b0MjlujL?;f2Agd?7xhzHE@vYDDD@#kWxD~!PRqoP^aMu?@7 z3)0;D=VhtxDO+d+q$ePa_LZ_mweQ_QI$6C-R`RM#AM|!LPo0`wO|su8@J7TCVbmH3 zh@`gi1RJ;Hof~}X89sN6HUB0GC-=R&f5<#&h(_Y+WW51EQ$Dk9w93W0Dpeh%TsF2> z8gwNS4qO$sMperOST{&y>u2bIdEJIY&Y*8q(;kOkryh8QrK1LMsJP3~J3C*DD|9!l zih;NaMQgbAguL63E0vUd9ZNtVKWM>V)q2S8_@M%r>P=lkM%N7QiuW8ASM2k3x>g%~ zm*k&#EKlcjz3BZ?;Uq@PD%_1PxLM2co~l*vd7;>g?8mB{(4Q|98LtL_)@sNYX3CC1OwT0Yu3dy zKLqHr?pP3lLj*(k2900To-@fCh5fa1zog^f8CUP$c>Ueav`1EjipecS;w!$LW3dQJG)8 z-nv8TA;hae)i9@d&6nyUPv=k-Er>t0D&?*B zazig2r1ip0iHjxlUDC6x>cj53UsSc&pM7+@Cfm0+x(s>-6LdTUL?Y{vHNcI z?7Ow3fnWFKtqRmntqqoP>`iv7&}*H0E%NsV>&r5afbgeZ{Me@E^w@mOy)$n#mygMO zurF<@HhTCSOuC)fGh@IiE#k~*IqwE`Aetx!3DfJdyt{~80w|8%l_W8 z8tZw?RjH3IKPya~{lYd)+By#Xu68wx-mz#ErYN2r1_^7%s+zHY-5CcsL!2k5vy%g_ zue59k`(9F0l42M&nEc&%C2RRf%9G-Y(wf29Y*0sv(o;fD_Qmf;8)9evDNb=9zUySu z8(b_HsV%GC9}__*tN;9a-y);4WZ&b`rOzs($)R`RnT*q~3uO!je&garaMeBjs}}Ox#io96cjh4vk|qe|Mg;-=jy_32Y1*BUhxej<{XP)CZ_w(`AcCe zKA2Pp2vs|#oUd>%$U;zNw*j`7_vAa;svq*keaZUn{M?pnH^`~y)4=xkdoj@DyyRE` zDJSOVF$>|l!GT|_Ad zxJJ#wt2&mq9hj%wS|4E!WBkQad0)O=zEN~H^YZtUh8p%owE(YML3&zBs(vh|J`_rv zWV(E@JKTxWz1K(BfT=eRrH3Somcsjz3+i za08-Bj6GTJePzr4?vl{*DDv+koGZhnVBmvXwpJ!g|14ws^>M?GH%rH(%yil%6R=`< zQAhvCD9;l6Yqxc@p06n+MGBr?-s;E4dz&k^BJXvc4gcL$O1k~K#`$u8G}VFa4@0_3 zGc{+$dlNG2 zk-9n>U&`*M6j%@&==et`WmrklUZ}Lm$Dy7lyJyg6+n{+u7fPha6IH~!%eJT9WeM;K zeyn7^U1>6H6{ZezW3>CU^|myB<*&PlU}55ACku0UyJzty5%0-3PKLit9?ZBMPSMn1 z;tNwJR_eNGNX+}m8UeH6VCe%>(&#IP$rPQ zg3>-EL=vceMp0;lQ)$Xxtj~~_k2q77pj_uAQe$)f#rMaaQS0GClX5qH$IUBwoixjf z6?ZTDyT~x$!tI}bdRz0NN{V(-ygDaGP*a-p z8TcZReNDOAeSNH}asI*cfSca37TGItD;pPdM{C94gi&Wh9LYvC%-QG*Ut{UJU#(%@ zi?pUP=@-(tFbX_urmfmpcb1yPtAayd!&9v``494>p2po{%s8JuM*l-TFZp?#c}*rR zx5i8_{M?QaM)kP`^VI^gR88xs3uZqoDk}&1f@KGG)5sxYrcOOC`{$)ZfWJ&oaBJ>; zKJGj*>yj^+$jBAd=Wsv$?K8LIR#{Zan_n&7@*aC)DFfH^AATDz6f&;45%O+0_u4(9 zx8BdK>{|RrcX(|_Ir%PT&UJYT;TeVshg3i3$_*)0+N3iXO=EitJ!zaAs*^L9pEozI zn)Q{^yEc}7&vx!jaJ3R1i_`vMJ?Z`9hP@EssPExgi1(W}OBS-IoE_H+OpC(EY|$r Date: Fri, 28 Aug 2026 14:32:25 +0200 Subject: [PATCH 13/13] Fix Podcasting 2.0 fallback metadata --- README.md | 9 +++--- main.py | 39 ++++++++++++++++++++--- tests/test_artwork.py | 73 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a15ea0b..ae658ae 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,11 @@ docker run --rm \ ## HLS fallback audio -Podcast clients without HLS support receive `/audio/dummy.mp3` as their standard -RSS enclosure. Place the fallback MP3 at `audio/dummy.mp3`. The app serves this -directory at `/audio/`; a reverse proxy may expose it under a prefix such as -`/pc/audio/`. +Podcast clients without HLS support receive an episode-specific URL such as +`/audio/dummy-.mp3` as their standard RSS enclosure. Every generated URL +serves the same physical fallback file at `audio/dummy.mp3`. The legacy +`/audio/dummy.mp3` URL remains available. A reverse proxy may expose these URLs +under a prefix such as `/pc/audio/`. ## Configuration A complete list of all configuration options can be found in the [.env.example file](.env.example) diff --git a/main.py b/main.py index 5f53413..8a7d078 100644 --- a/main.py +++ b/main.py @@ -93,6 +93,7 @@ class PodcastHlsExtension(BaseExtension): def __init__(self): self._itunes_explicit = None self._itunes_type = None + self._podcast_block = None def itunes_explicit(self, value=None): if value is not None: @@ -104,6 +105,11 @@ def itunes_type(self, value=None): self._itunes_type = value return self._itunes_type + def podcast_block(self, value=None): + if value is not None: + self._podcast_block = value + return self._podcast_block + def extend_ns(self): return {"podcast": PODCAST_NAMESPACE} @@ -118,6 +124,11 @@ def extend_rss(self, feed): feed[0], etree.QName(ITUNES_NAMESPACE, "type") ) podcast_type.text = self._itunes_type + if self._podcast_block is not None: + podcast_block = etree.SubElement( + feed[0], etree.QName(PODCAST_NAMESPACE, "block") + ) + podcast_block.text = self._podcast_block return feed @@ -306,7 +317,11 @@ async def not_found(error): @app.route("/audio/") async def serve_audio(filename): - return await send_from_directory(AUDIO_DIR, filename) + if filename != "dummy.mp3" and not re.fullmatch( + r"dummy-[0-9a-f]{64}\.mp3", filename + ): + return Response("Audio not found", 404, {}) + return await send_from_directory(AUDIO_DIR, "dummy.mp3") @app.route("/feed/.xml") @@ -549,13 +564,14 @@ async def addFeedEntry(fg, episode, session, locale): is_hls = url.split("?", 1)[0].lower().endswith(".m3u8") if is_hls: + fallback_url = hlsFallbackMp3Url(episode_id) logging.debug( - f"Adding fallback MP3 enclosure {HLS_FALLBACK_MP3} and " + f"Adding fallback MP3 enclosure {fallback_url} and " f"HLS alternate enclosure " f"for episode {episode_id}" ) fe.enclosure( - f"{PODIMO_PROTOCOL}://{PODIMO_HOSTNAME}/{HLS_FALLBACK_MP3}", + fallback_url, hlsFallbackMp3Size(), "audio/mpeg", ) @@ -584,6 +600,20 @@ def hlsFallbackMp3Size(): return str(HLS_FALLBACK_MP3_PATH.stat().st_size) +def hlsFallbackMp3Url(episode_id): + episode_hash = sha256(str(episode_id).encode("utf-8")).hexdigest() + return ( + f"{PODIMO_PROTOCOL}://{PODIMO_HOSTNAME}/audio/" + f"dummy-{episode_hash}.mp3" + ) + + +def normalizeLanguageTag(language): + if language and language.lower() == "nl-nl": + return "nl-NL" + return language + + async def podcastsToRss(podcast_id, data, locale): logging.debug(f"podcastsToRss: START podcast_id={podcast_id}") @@ -648,7 +678,7 @@ async def podcastsToRss(podcast_id, data, locale): language = podcast["language"] if language is None: language = locale - fg.language(language) + fg.language(normalizeLanguageTag(language)) artist = podcast["authorName"] if artist is None: @@ -657,6 +687,7 @@ async def podcastsToRss(podcast_id, data, locale): if not PUBLIC_FEEDS: fg.podcast.itunes_block(True) + fg.podcast_hls.podcast_block("yes") async with ClientSession() as session: for chunk in chunks(episodes, 5): diff --git a/tests/test_artwork.py b/tests/test_artwork.py index 60c5eb8..e4e492a 100644 --- a/tests/test_artwork.py +++ b/tests/test_artwork.py @@ -115,8 +115,36 @@ async def test_audio_file_is_served_from_audio_directory(self, send_file): self.assertEqual(await response.get_data(), b"mp3-data") send_file.assert_awaited_once_with(main.AUDIO_DIR, "dummy.mp3") + @patch("main.send_from_directory", new_callable=AsyncMock) + async def test_unique_audio_url_serves_shared_dummy_file(self, send_file): + send_file.return_value = main.Response(b"mp3-data", mimetype="audio/mpeg") + client = main.app.test_client() + filename = main.hlsFallbackMp3Url("episode-1").rsplit("/", 1)[-1] + + response = await client.get(f"/audio/{filename}") + + self.assertEqual(response.status_code, 200) + self.assertEqual(await response.get_data(), b"mp3-data") + send_file.assert_awaited_once_with(main.AUDIO_DIR, "dummy.mp3") + + @patch("main.send_from_directory", new_callable=AsyncMock) + async def test_unknown_audio_filename_returns_404(self, send_file): + client = main.app.test_client() + + response = await client.get("/audio/not-an-enclosure.mp3") + + self.assertEqual(response.status_code, 404) + send_file.assert_not_awaited() + class HlsFallbackTests(unittest.TestCase): + def test_url_is_stable_and_unique_per_episode(self): + first = main.hlsFallbackMp3Url("episode-1") + + self.assertEqual(first, main.hlsFallbackMp3Url("episode-1")) + self.assertNotEqual(first, main.hlsFallbackMp3Url("episode-2")) + self.assertRegex(first, r"/audio/dummy-[0-9a-f]{64}\.mp3$") + @patch("main.HLS_FALLBACK_MP3_PATH") def test_size_is_read_from_file(self, fallback_path): fallback_path.is_file.return_value = True @@ -156,6 +184,7 @@ async def test_public_address_is_returned(self): class FeedArtworkTests(unittest.IsolatedAsyncioTestCase): + @patch("main.PUBLIC_FEEDS", False) @patch( "main.urlHeadInfo", new_callable=AsyncMock, return_value=("123", "audio/mpeg") ) @@ -205,6 +234,47 @@ async def test_webp_artwork_does_not_prevent_feed_generation( self.assertIn("Example", feed_text) self.assertIn("you@example.com", feed_text) self.assertIn("episodic", feed_text) + self.assertIn("yes", feed_text) + self.assertIn("yes", feed_text) + url_head_info.assert_awaited_once() + + @patch("main.PUBLIC_FEEDS", True) + @patch( + "main.urlHeadInfo", new_callable=AsyncMock, return_value=("123", "audio/mpeg") + ) + async def test_public_feed_omits_block_tags(self, url_head_info): + data = { + "podcast": { + "title": "Test podcast", + "description": "Description", + "images": {"coverImageUrl": "https://cdn.example.com/show.jpg"}, + "language": "nl-nl", + "authorName": "Author", + }, + "episodes": [ + { + "id": "episode-1", + "title": "Episode one", + "description": "Episode description", + "publishDatetime": datetime(2026, 7, 22, tzinfo=timezone.utc), + "imageUrl": "https://cdn.example.com/episode.jpg", + "audio": { + "url": "https://cdn.example.com/episode.mp3", + "duration": 60, + }, + "streamMedia": None, + "podcastName": "Test podcast", + "artist": "Author", + } + ], + } + + feed = await main.podcastsToRss("podcast-id", data, "nl-NL") + feed_text = feed.decode("utf-8") + + self.assertIn("nl-NL", feed_text) + self.assertNotIn("", feed_text) + self.assertNotIn("", feed_text) url_head_info.assert_awaited_once() @patch( @@ -250,8 +320,7 @@ async def test_hls_uses_standard_and_alternate_enclosures( self.assertIsNotNone(enclosure) self.assertEqual( enclosure.get("url"), - f"{main.PODIMO_PROTOCOL}://{main.PODIMO_HOSTNAME}/" - f"{main.HLS_FALLBACK_MP3}", + main.hlsFallbackMp3Url("episode-hls"), ) self.assertEqual(enclosure.get("length"), "187288") self.assertEqual(enclosure.get("type"), "audio/mpeg")