Source code for podme_api.models

"""podme_api models."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, time
from enum import IntEnum, StrEnum, auto
from typing import TYPE_CHECKING, TypedDict

from mashumaro import field_options
from mashumaro.config import BaseConfig
from mashumaro.mixins.orjson import DataClassORJSONMixin
from mashumaro.types import Discriminator

if TYPE_CHECKING:
    from yarl import URL


[docs] @dataclass class BaseDataClassORJSONMixin(DataClassORJSONMixin): class Config(BaseConfig): omit_none = True allow_deserialization_not_by_alias = True
[docs] class PodMeModels(StrEnum): """Enumeration of utilized PodMe models.""" CATEGORY = auto() PODCAST = auto() EPISODE = auto() SEARCH_RESULT = auto() EPISODE_EXCERPT = auto() SUBSCRIPTION_PLAN = auto() SUBSCRIPTION = auto()
[docs] class PodMeLanguage(StrEnum): """Enumeration of supported PodMe languages.""" SE = auto() NO = auto() FI = auto() def __repr__(self): return self.value.lower()
[docs] class PodMeRegion(IntEnum): """Enumeration of PodMe regions.""" SE = 1 NO = 2 FI = 3 def __repr__(self): return self.name def __str__(self): return self.name.lower() @property def default_language(self): # pragma: no cover """Get the default language for the region.""" return PodMeLanguage[self.name]
[docs] class PodMeDownloadProgressTask(StrEnum): """Enumeration of PodMe download progress tasks.""" INITIALIZE = auto() RESOLVE_URL = auto() DOWNLOAD_FILE = auto() TRANSCODE_FILE = auto() COMPLETE = auto()
[docs] @dataclass class PodMeCategory(BaseDataClassORJSONMixin): """Represents a PodMe category.""" id: int name: str key: str image_url: str | None = field(default=None, metadata=field_options(alias="imageUrl"))
[docs] @dataclass class PodMeCategoryPageSectionContent(BaseDataClassORJSONMixin): """Base class for PodMe category page section content.""" title: str type: str class Config(BaseConfig): discriminator = Discriminator( field="type", include_subtypes=True, )
[docs] @dataclass class PodMeCategoryPagePodcastCarousel(PodMeCategoryPageSectionContent): """Represents a podcast carousel in a PodMe category page section.""" type = "podcastCarousel" podcasts: list[PodMeHomeSectionPodcast] is_top_list: bool | None = field(default=None, metadata=field_options(alias="isTopList")) show_release_date: bool | None = field(default=None, metadata=field_options(alias="showReleaseDate")) destination: str | None = field(default=None, metadata=field_options(alias="destination"))
[docs] @dataclass class PodMeCategoryPagePodcastPromoCarousel(PodMeCategoryPageSectionContent): """Represents a podcast promo carousel in a PodMe category page section.""" type = "podcastPromoCarousel" promoted_podcasts: list[PodMeHomeSectionPodcast] = field(metadata=field_options(alias="promotedPodcasts")) is_top_list: bool | None = field(default=None, metadata=field_options(alias="isTopList"))
[docs] @dataclass class PodMeCategoryPageEpisodePromoCarousel(PodMeCategoryPageSectionContent): """Represents an episode promo carousel in a PodMe category page section.""" type = "episodePromoCarousel" promoted_episodes: list[PodMeHomeSectionEpisode] = field(metadata=field_options(alias="promotedEpisodes")) is_top_list: bool | None = field(default=None, metadata=field_options(alias="isTopList"))
[docs] @dataclass class PodMeCategoryPageBannerWithEpisodeList(PodMeCategoryPageSectionContent): """Represents a banner with episode list in a PodMe category page section.""" type = "bannerWithEpisodeList" description: str hide_title: bool = field(metadata=field_options(alias="hideTitle")) image_url: str = field(metadata=field_options(alias="imageUrl")) episodes: list[PodMeHomeSectionEpisode]
[docs] @dataclass class PodMeHomeEpisodeList(BaseDataClassORJSONMixin): """Represents a list of episodes in the PodMe home screen.""" title: str type: str episodes: list[PodMeHomeSectionEpisode]
[docs] @dataclass class PodMeHomeSectionHeroCard(BaseDataClassORJSONMixin): """Base class for PodMe home section hero cards.""" type: str class Config(BaseConfig): discriminator = Discriminator( field="type", include_subtypes=True, )
[docs] @dataclass class PodMeHomeSectionEpisodeHeroCard(PodMeHomeSectionHeroCard): """Represents an episode hero card in a PodMe home section.""" type = "episode" podcast_id: int = field(metadata=field_options(alias="podcastId")) has_podcast_bookmark: bool = field(metadata=field_options(alias="hasPodcastBookmark")) episode_data: PodMeEpisodeData = field(metadata=field_options(alias="episodeData")) is_playable: bool = field(metadata=field_options(alias="isPlayable")) image_url: str = field(metadata=field_options(alias="imageUrl")) destination: str = field(metadata=field_options(alias="destination")) destination_path: str = field(metadata=field_options(alias="destinationPath")) main_header: str = field(metadata=field_options(alias="mainHeader")) short_description: str = field(metadata=field_options(alias="shortDescription")) sub_header: str | None = field(default=None, metadata=field_options(alias="subHeader"))
[docs] @dataclass class PodMeCategoryPagePodcastNuggets(PodMeCategoryPageSectionContent): """Represents podcast nuggets in a PodMe category page section.""" type = "podcastNuggets" subtitle: str episode_lists: list[PodMeHomeEpisodeList] = field(metadata=field_options(alias="episodeLists"))
[docs] @dataclass class PodMeCategoryPageEpisodeCarousel(PodMeCategoryPageSectionContent): """Represents an episode carousel in a PodMe category page section.""" type = "episodeCarousel" episodes: list[PodMeHomeSectionEpisode]
[docs] @dataclass class PodMeSectionHeroCards(PodMeCategoryPageSectionContent): """Represents a list of hero cards in a PodMe section.""" type = "listOfHeroCards" hero_cards: list[PodMeHomeSectionHeroCard] = field(metadata=field_options(alias="heroCards"))
[docs] @dataclass class PodMeCategoryPageSection(BaseDataClassORJSONMixin): """Represents a section in a PodMe category page.""" content: PodMeCategoryPageSectionContent
[docs] @dataclass class PodMeHomeScreen(BaseDataClassORJSONMixin): """Represents the PodMe home screen.""" sections: list[PodMeCategoryPageSection] type: str
[docs] @dataclass class PodMeCategoryPage(PodMeHomeScreen): """Represents a PodMe category page.""" title: str display_title: str = field(metadata=field_options(alias="displayTitle")) description: str
[docs] @dataclass class PodMePodcastBase(BaseDataClassORJSONMixin): """Base class for PodMe podcasts.""" id: int title: str is_premium: bool = field(metadata=field_options(alias="isPremium")) slug: str image_url: str | None = field(default=None, metadata=field_options(alias="imageUrl"))
[docs] @dataclass class PodMePodcast(PodMePodcastBase): """Represents a PodMe podcast with extended information.""" small_image_url: str | None = field(default=None, metadata=field_options(alias="smallImageUrl")) medium_image_url: str | None = field(default=None, metadata=field_options(alias="mediumImageUrl")) large_image_url: str | None = field(default=None, metadata=field_options(alias="largeImageUrl")) author_id: int | None = field(default=None, metadata=field_options(alias="authorId")) author_full_name: str | None = field(default=None, metadata=field_options(alias="authorFullName")) has_bookmark: bool | None = field(default=None, metadata=field_options(alias="hasBookmark")) has_subscription: bool | None = field(default=None, metadata=field_options(alias="hasSubscription")) has_free_options: bool | None = field(default=None, metadata=field_options(alias="hasFreeOptions")) has_buy_options: bool | None = field(default=None, metadata=field_options(alias="hasBuyOptions")) is_featured: bool | None = field(default=None, metadata=field_options(alias="isFeatured")) is_in_spotlight: bool | None = field(default=None, metadata=field_options(alias="isInSpotlight")) categories: list[PodMeCategory] | None = field(default=None) subscription_type: int | None = field(default=None, metadata=field_options(alias="subscriptionType")) description: str | None = None only_as_package_subscription: bool | None = field( default=None, metadata=field_options(alias="onlyAsPackageSubscription") ) only_as_podcast_subscription: bool | None = field( default=None, metadata=field_options(alias="onlyAsPodcastSubscription") ) requires_importing: bool | None = field(default=None, metadata=field_options(alias="requiresImporting"))
[docs] @dataclass class PodMeHomeSectionPodcast(PodMePodcastBase): """Represents a podcast in a PodMe home section.""" destination: str | None = None destination_path: str | None = field(default=None, metadata=field_options(alias="destinationPath")) description: str | None = None categories: list[PodMeCategory] | None = None
[docs] @dataclass class PodMeHomeSection(BaseDataClassORJSONMixin): """Represents a section in the PodMe home screen.""" title: str podcasts: list[PodMeHomeSectionPodcast]
[docs] @dataclass class PodMeSearchResult(BaseDataClassORJSONMixin): """Represents a search result in PodMe.""" podcast_id: int | str = field(metadata=field_options(alias="podcastId")) podcast_title: str = field(metadata=field_options(alias="podcastTitle")) image_url: str = field(metadata=field_options(alias="imageUrl")) author_full_name: str = field(metadata=field_options(alias="authorFullName")) date_added: datetime = field(metadata=field_options(alias="dateAdded")) slug: str is_premium: bool = field(metadata=field_options(alias="isPremium")) types: list | None = None
[docs] @dataclass(kw_only=True) class PodMeEpisodeBase(BaseDataClassORJSONMixin): """Base class for PodMe episodes.""" id: int podcast_id: int = field(metadata=field_options(alias="podcastId")) title: str podcast_title: str = field(metadata=field_options(alias="podcastTitle")) length: time = field( metadata=field_options( deserialize=time.fromisoformat, serialize=time.isoformat, ) ) description: str | None = None html_description: str | None = field(default=None, metadata=field_options(alias="htmlDescription")) image_url: str | None = field(default=None, metadata=field_options(alias="imageUrl")) date_added: datetime = field(metadata=field_options(alias="dateAdded")) is_premium: bool = field(metadata=field_options(alias="isPremium"))
[docs] @dataclass(kw_only=True) class PodMeHomeSectionEpisode(PodMeEpisodeBase): """Represents an episode in a PodMe home section.""" audio_length: int = field(metadata=field_options(alias="audioLength")) is_playable: bool = field(metadata=field_options(alias="isPlayable")) podcast_slug: str = field(metadata=field_options(alias="podcastSlug")) destination: str | None = None destination_path: str | None = field(default=None, metadata=field_options(alias="destinationPath"))
[docs] @dataclass(kw_only=True) class PodMeEpisode(PodMeEpisodeBase): """Represents a PodMe episode with extended information.""" author_full_name: str = field(metadata=field_options(alias="authorFullName")) small_image_url: str = field(metadata=field_options(alias="smallImageUrl")) medium_image_url: str = field(metadata=field_options(alias="mediumImageUrl")) stream_url: str | None = field(default=None, metadata=field_options(alias="streamUrl")) slug: str | None = None current_spot: time = field( metadata=field_options( alias="currentSpot", deserialize=time.fromisoformat, serialize=time.isoformat, ) ) current_spot_sec: int = field(metadata=field_options(alias="currentSpotSec")) episode_can_be_played: bool = field(metadata=field_options(alias="episodeCanBePlayed")) only_as_package_subscription: bool = field(metadata=field_options(alias="onlyAsPackageSubscription")) has_completed: bool = field(metadata=field_options(alias="hasCompleted")) is_rss: bool | None = field(default=None, metadata=field_options(alias="isRss")) total_no_of_episodes: int | None = field(default=None, metadata=field_options(alias="totalNoOfEpisodes"))
[docs] @dataclass class PodMeEpisodeData(PodMeEpisode): """Represents detailed data for a PodMe episode.""" number: int = field(metadata=field_options(alias="number")) byte_length: int = field(metadata=field_options(alias="byteLength")) url: str = field(metadata=field_options(alias="url")) type: str = field(metadata=field_options(alias="type")) smooth_streaming_url: str = field(metadata=field_options(alias="smoothStreamingUrl")) mpeg_dash_url: str = field(metadata=field_options(alias="mpegDashUrl")) hls_v3_url: str = field(metadata=field_options(alias="hlsV3Url")) hls_v4_url: str = field(metadata=field_options(alias="hlsV4Url")) publish_date: datetime = field(metadata=field_options(alias="publishDate")) has_played: bool = field(metadata=field_options(alias="hasPlayed")) episode_created_at: datetime = field(metadata=field_options(alias="episodeCreatedAt")) episode_updated_at: datetime = field(metadata=field_options(alias="episodeUpdatedAt")) podcast_image_url: str = field(metadata=field_options(alias="podcastImageUrl")) play_info_updated_at: datetime | None = field( default=None, metadata=field_options(alias="playInfoUpdatedAt") )
[docs] @dataclass class PodMeSubscriptionPlan(BaseDataClassORJSONMixin): """Represents a PodMe subscription plan.""" name: str package_id: int = field(metadata=field_options(alias="packageId")) price_decimal: float = field(metadata=field_options(alias="priceDecimal")) currency: str product_id: str = field(metadata=field_options(alias="productId")) plan_guid: str | None = field(default=None, metadata=field_options(alias="planGuid")) month_limit: str | None = field(default=None, metadata=field_options(alias="monthLimit")) next_plan_id: int | None = field(default=None, metadata=field_options(alias="nextPlanId")) next_plan_price_decimal: float | None = field( default=None, metadata=field_options(alias="nextPlanPriceDecimal") ) next_plan_product_id: float | None = field( default=None, metadata=field_options(alias="nextPlanProductId") ) price: int | None = field(default=None)
[docs] @dataclass class PodMeSubscription(BaseDataClassORJSONMixin): """Represents a PodMe subscription.""" subscription_state: int = field(metadata=field_options(alias="subscriptionState")) subscription_type: int = field(metadata=field_options(alias="subscriptionType")) subscription_platform: int = field(metadata=field_options(alias="subscriptionPlatform")) expiration_date: datetime = field( metadata=field_options( alias="expirationDate", deserialize=datetime.fromisoformat, serialize=datetime.isoformat, ) ) start_date: datetime = field( metadata=field_options( alias="startDate", deserialize=datetime.fromisoformat, serialize=datetime.isoformat, ) ) will_be_renewed: bool = field(metadata=field_options(alias="willBeRenewed")) subscription_plan: PodMeSubscriptionPlan = field(metadata=field_options(alias="subscriptionPlan")) discriminator: str reward_month_credit: str | None = field(default=None, metadata=field_options(alias="rewardMonthCredit")) image_url: str | None = field(default=None, metadata=field_options(alias="imageUrl")) podcast_id: int | None = field(default=None, metadata=field_options(alias="podcastId")) podcast_title: str | None = field(default=None, metadata=field_options(alias="podcastTitle"))
[docs] class FetchedFileInfo(TypedDict): """Fetched file info.""" content_length: int content_type: str | None url: URL