Abs + Feed Parsers: release_date as datetime (#2064)
authorFabian Munkes <105975993+fmunkes@users.noreply.github.com>
Wed, 26 Mar 2025 22:38:32 +0000 (23:38 +0100)
committerGitHub <noreply@github.com>
Wed, 26 Mar 2025 22:38:32 +0000 (23:38 +0100)
music_assistant/helpers/podcast_parsers.py
music_assistant/providers/audiobookshelf/parsers.py

index c4ae147316766025a0c8eeab92eff24626a5435d..9ed3079181c5894ef591434dd5516f8f9823adf9 100644 (file)
@@ -1,5 +1,6 @@
 """Podcastfeed -> Mass."""
 
+from datetime import datetime
 from typing import Any
 
 from music_assistant_models.enums import ContentType, ImageType, MediaType
@@ -106,7 +107,11 @@ def parse_podcast_episode(
     episode_duration = episode.get("total_time", 0.0)
     episode_title = episode.get("title", "NO_EPISODE_TITLE")
     episode_cover = episode.get("episode_art_url", podcast_cover)
-    episode_published = episode.get("published")
+
+    # this is unix epoch in s, and 0 if unknown
+    episode_published: int | None = episode.get("published")
+    if episode_published == 0:
+        episode_published = None
 
     stream_url, guid = get_stream_url_and_guid_from_episode(episode=episode)
     guid_or_stream_url = guid if guid is not None else stream_url
@@ -139,7 +144,8 @@ def parse_podcast_episode(
             )
         },
     )
-    mass_episode.metadata.release_date = episode_published
+    if episode_published is not None:
+        mass_episode.metadata.release_date = datetime.fromtimestamp(episode_published)
 
     # chapter
     if chapters := episode.get("chapters"):
index 9ca6d1af714d799045c7973a67ac42ab60bb9dc5..19ac868fb89869da15dc9cd286091555a80fc518 100644 (file)
@@ -1,5 +1,8 @@
 """Parser for ABS -> MASS."""
 
+from contextlib import suppress
+from datetime import datetime
+
 from aioaudiobookshelf.schema.library import (
     LibraryItemExpandedBook as AbsLibraryItemExpandedBook,
 )
@@ -71,7 +74,13 @@ def parse_podcast(
         mass_podcast.metadata.languages = UniqueList([abs_podcast.media.metadata.language])
     if abs_podcast.media.metadata.genres is not None:
         mass_podcast.metadata.genres = set(abs_podcast.media.metadata.genres)
-    mass_podcast.metadata.release_date = abs_podcast.media.metadata.release_date
+
+    # podcast object has no published_at int, but an iso string
+    if abs_podcast.media.metadata.release_date is not None:
+        with suppress(ValueError):
+            mass_podcast.metadata.release_date = datetime.fromisoformat(
+                abs_podcast.media.metadata.release_date
+            )
 
     if isinstance(abs_podcast, AbsLibraryItemExpandedPodcast | AbsLibraryItemPodcast):
         mass_podcast.total_episodes = len(abs_podcast.media.episodes)
@@ -102,8 +111,11 @@ def parse_podcast_episode(
     url = f"{base_url}{episode.audio_track.content_url}"
     episode_id = f"{prov_podcast_id} {episode.id_}"
 
+    release_date: datetime | None = None
     if episode.published_at is not None:
         position = -episode.published_at
+        # abs published_at is ms epoch
+        release_date = datetime.fromtimestamp(episode.published_at / 1000)
     else:
         position = 0
         if fallback_episode_cnt is not None:
@@ -113,7 +125,6 @@ def parse_podcast_episode(
         provider=lookup_key,
         name=episode.title,
         duration=int(episode.duration),
-        publish_date=None,
         position=position,
         podcast=ItemMapping(
             item_id=prov_podcast_id,
@@ -134,6 +145,8 @@ def parse_podcast_episode(
         },
     )
 
+    mass_episode.metadata.release_date = release_date
+
     # cover image
     if token is not None:
         url_api = f"/api/items/{prov_podcast_id}/cover?token={token}"
@@ -184,7 +197,19 @@ def parse_audiobook(
     mass_audiobook.metadata.description = abs_audiobook.media.metadata.description
     if abs_audiobook.media.metadata.language is not None:
         mass_audiobook.metadata.languages = UniqueList([abs_audiobook.media.metadata.language])
-    mass_audiobook.metadata.release_date = abs_audiobook.media.metadata.published_date
+
+    if abs_audiobook.media.metadata.published_date is not None:
+        with suppress(ValueError):
+            mass_audiobook.metadata.release_date = datetime.fromisoformat(
+                abs_audiobook.media.metadata.published_date
+            )
+    elif abs_audiobook.media.metadata.published_year is not None:
+        with suppress(ValueError):
+            # ruff: noqa: DTZ001 # ignore tzinfo, this is a fallback attempt
+            mass_audiobook.metadata.release_date = datetime(
+                year=int(abs_audiobook.media.metadata.published_year), month=1, day=1
+            )
+
     if abs_audiobook.media.metadata.genres is not None:
         mass_audiobook.metadata.genres = set(abs_audiobook.media.metadata.genres)