Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions music_assistant/controllers/media/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from abc import ABCMeta, abstractmethod
from collections.abc import Iterable
from contextlib import suppress
from datetime import datetime
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any, TypeVar, cast, final

from music_assistant_models.enums import EventType, ExternalID, MediaType, ProviderFeature
Expand Down Expand Up @@ -1105,7 +1105,7 @@ def _parse_db_row(db_row: Mapping[str, Any]) -> dict[str, Any]:
db_row_dict["favorite"] = bool(db_row_dict["favorite"])
db_row_dict["item_id"] = str(db_row_dict["item_id"])
db_row_dict["date_added"] = datetime.fromtimestamp(
Comment thread
OzGav marked this conversation as resolved.
db_row_dict["timestamp_added"]
db_row_dict["timestamp_added"], tz=UTC
).isoformat()

for key in JSON_KEYS:
Expand Down
10 changes: 10 additions & 0 deletions music_assistant/helpers/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,21 @@ def from_utc_timestamp(timestamp: float) -> datetime.datetime:
return datetime.datetime.fromtimestamp(timestamp, datetime.UTC)


def from_utc_timestamp_to_local(timestamp: float) -> datetime.datetime:
"""Convert UTC timestamp to datetime in local timezone."""
return from_utc_timestamp(timestamp).astimezone(LOCAL_TIMEZONE)


Comment thread
OzGav marked this conversation as resolved.
Outdated
def iso_from_utc_timestamp(timestamp: float) -> str:
"""Return ISO 8601 datetime string from UTC timestamp."""
return from_utc_timestamp(timestamp).isoformat()


def iso_local_from_utc_timestamp(timestamp: float) -> str:
"""Return ISO 8601 datetime string in local timezone from UTC timestamp."""
return from_utc_timestamp_to_local(timestamp).isoformat()


Comment thread
OzGav marked this conversation as resolved.
Outdated
def from_iso_string(iso_datetime: str) -> datetime.datetime:
"""Return datetime from ISO datetime string."""
return datetime.datetime.fromisoformat(iso_datetime)
Expand Down
4 changes: 2 additions & 2 deletions music_assistant/helpers/podcast_parsers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Podcastfeed -> Mass."""

from datetime import datetime
from datetime import UTC, datetime
from io import BytesIO
from typing import Any

Expand Down Expand Up @@ -193,7 +193,7 @@ def parse_podcast_episode(
},
)
if episode_published is not None:
mass_episode.metadata.release_date = datetime.fromtimestamp(episode_published)
mass_episode.metadata.release_date = datetime.fromtimestamp(episode_published, tz=UTC)

# chapter
if chapters := episode.get("chapters"):
Expand Down
4 changes: 2 additions & 2 deletions music_assistant/providers/ard_audiothek/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from collections.abc import AsyncGenerator, Sequence
from datetime import datetime, timedelta
from datetime import UTC, datetime, timedelta
from typing import TYPE_CHECKING, Any

from gql import Client
Expand Down Expand Up @@ -249,7 +249,7 @@ async def get_client(self) -> Client:
self.token = self.config.get_value(CONF_TOKEN_BEARER)
self.user_id = self.config.get_value(CONF_USERID)
self.token_expire = datetime.fromtimestamp(
float(str(self.config.get_value(CONF_EXPIRY_TIME)))
float(str(self.config.get_value(CONF_EXPIRY_TIME))), tz=UTC
)

self.max_bitrate = int(float(str(self.config.get_value(CONF_MAX_BITRATE))))
Expand Down
6 changes: 3 additions & 3 deletions music_assistant/providers/audiobookshelf/parsers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Parser for ABS -> MASS."""

from contextlib import suppress
from datetime import datetime
from datetime import UTC, datetime

from aioaudiobookshelf.schema.library import (
LibraryItemExpandedBook as AbsLibraryItemExpandedBook,
Expand Down Expand Up @@ -182,7 +182,7 @@ def parse_podcast_episode(
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)
release_date = datetime.fromtimestamp(episode.published_at / 1000, tz=UTC)
else:
position = 0
if fallback_episode_cnt is not None:
Expand Down Expand Up @@ -303,6 +303,6 @@ def parse_audiobook(
mass_audiobook.resume_position_ms = int(media_progress.current_time * 1000)
mass_audiobook.fully_played = media_progress.is_finished

mass_audiobook.date_added = datetime.fromtimestamp(abs_audiobook.added_at / 1000)
mass_audiobook.date_added = datetime.fromtimestamp(abs_audiobook.added_at / 1000, tz=UTC)

return mass_audiobook
6 changes: 4 additions & 2 deletions music_assistant/providers/bandcamp/converters.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Converters for Bandcamp API models to Music Assistant models."""

from contextlib import suppress
from datetime import datetime
from datetime import UTC, datetime
from typing import TypedDict

from bandcamp_async_api.models import BCAlbum as APIAlbum
Expand Down Expand Up @@ -362,7 +362,9 @@ def album_from_api(self, album: APIAlbum) -> MAAlbum:
url=album.url,
)
},
year=datetime.fromtimestamp(album.release_date).year if album.release_date else None,
year=datetime.fromtimestamp(album.release_date, tz=UTC).year
if album.release_date
else None,
)
output.metadata.add_image(
MediaItemImage(
Expand Down
4 changes: 2 additions & 2 deletions music_assistant/providers/opensubsonic/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

import logging
from datetime import datetime
from datetime import UTC, datetime
from typing import TYPE_CHECKING

from music_assistant_models.enums import ContentType, ImageType, MediaType
Expand Down Expand Up @@ -535,7 +535,7 @@ def parse_structured_lyrics(lyrics: StructuredLyrics) -> tuple[str, bool]:
if line.start is None:
raise InvalidDataError("Open Subsonic Synced lyric missing time index")
ms = int(line.start) + offset
dt = datetime.fromtimestamp(ms / 1000)
dt = datetime.fromtimestamp(ms / 1000, tz=UTC)
ts = dt.strftime("%M:%S.%f")[:-4]
lines.append(f"[{ts}]{line.value}")
else:
Expand Down
3 changes: 2 additions & 1 deletion music_assistant/providers/qobuz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import hashlib
import time
from contextlib import suppress
from datetime import UTC
from typing import TYPE_CHECKING, Any, cast

from aiohttp import client_exceptions
Expand Down Expand Up @@ -665,7 +666,7 @@ async def _parse_album(
album.metadata.label = album_obj["label"]["name"]
if released_at := album_obj.get("released_at"):
with suppress(ValueError):
album.year = datetime.datetime.fromtimestamp(released_at).year
album.year = datetime.datetime.fromtimestamp(released_at, tz=UTC).year
if album_obj.get("copyright"):
album.metadata.copyright = album_obj["copyright"]
if album_obj.get("description"):
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ ignore = [
"B904",
"TRY401",
"S324",
"DTZ006",
"ERA001",
"PTH206",
"C901",
Expand Down
Loading