Some tweaks to MediaItem models (#981)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sun, 31 Dec 2023 00:13:45 +0000 (01:13 +0100)
committerGitHub <noreply@github.com>
Sun, 31 Dec 2023 00:13:45 +0000 (01:13 +0100)
Copy shared attributes to _MediaItemBase

music_assistant/common/models/media_items.py

index e9e8ddb9e4282ab6b16d3dc3493780e5f99b8da4..85c2ec6fb87ad8935fddc6f81ca96b3b4fb0426a 100755 (executable)
@@ -192,26 +192,18 @@ class MediaItemMetadata(DataClassDictMixin):
 
 
 @dataclass(kw_only=True)
-class MediaItem(DataClassDictMixin):
-    """Base representation of a media item."""
+class _MediaItemBase(DataClassDictMixin):
+    """Base representation of a Media Item or ItemMapping item object."""
 
-    media_type: MediaType
     item_id: str
     provider: str  # provider instance id or provider domain
     name: str
-    provider_mappings: set[ProviderMapping]
-
-    # optional fields below
-    external_ids: set[tuple[ExternalID, str]] = field(default_factory=set)
-    metadata: MediaItemMetadata = field(default_factory=MediaItemMetadata)
-    favorite: bool = False
-    media_type: MediaType = MediaType.UNKNOWN
+    version: str = ""
     # sort_name and uri are auto generated, do not override unless really needed
     sort_name: str | None = None
     uri: str | None = None
-    # timestamps to determine when the item was added/modified to the db
-    timestamp_added: int = 0
-    timestamp_modified: int = 0
+    external_ids: set[tuple[ExternalID, str]] = field(default_factory=set)
+    media_type: MediaType = MediaType.UNKNOWN
 
     def __post_init__(self):
         """Call after init."""
@@ -220,18 +212,6 @@ class MediaItem(DataClassDictMixin):
         if not self.sort_name:
             self.sort_name = create_sort_name(self.name)
 
-    @property
-    def available(self):
-        """Return (calculated) availability."""
-        return any(x.available for x in self.provider_mappings)
-
-    @property
-    def image(self) -> MediaItemImage | None:
-        """Return (first/random) image/thumb from metadata (if any)."""
-        if self.metadata is None or self.metadata.images is None:
-            return None
-        return next((x for x in self.metadata.images if x.type == ImageType.THUMB), None)
-
     @property
     def mbid(self) -> str | None:
         """Return MusicBrainz ID."""
@@ -265,6 +245,31 @@ class MediaItem(DataClassDictMixin):
         """Check equality of two items."""
         return self.uri == other.uri
 
+
+@dataclass(kw_only=True)
+class MediaItem(_MediaItemBase):
+    """Base representation of a media item."""
+
+    provider_mappings: set[ProviderMapping]
+    # optional fields below
+    metadata: MediaItemMetadata = field(default_factory=MediaItemMetadata)
+    favorite: bool = False
+    # timestamps to determine when the item was added/modified to the db
+    timestamp_added: int = 0
+    timestamp_modified: int = 0
+
+    @property
+    def available(self):
+        """Return (calculated) availability."""
+        return any(x.available for x in self.provider_mappings)
+
+    @property
+    def image(self) -> MediaItemImage | None:
+        """Return (first/random) image/thumb from metadata (if any)."""
+        if self.metadata is None or self.metadata.images is None:
+            return None
+        return next((x for x in self.metadata.images if x.type == ImageType.THUMB), None)
+
     @classmethod
     def from_item_mapping(cls: type, item: ItemMapping) -> Self:
         """Instantiate MediaItem from ItemMapping."""
@@ -283,41 +288,16 @@ class MediaItem(DataClassDictMixin):
 
 
 @dataclass(kw_only=True)
-class ItemMapping(DataClassDictMixin):
+class ItemMapping(_MediaItemBase):
     """Representation of a minimized item object."""
 
-    media_type: MediaType
-    item_id: str
-    provider: str  # provider instance id or provider domain
-    name: str
-    version: str = ""
-    sort_name: str | None = None
-    uri: str | None = None
     available: bool = True
-    external_ids: set[tuple[ExternalID, str]] = field(default_factory=set)
 
     @classmethod
     def from_item(cls, item: MediaItem):
         """Create ItemMapping object from regular item."""
         return cls.from_dict(item.to_dict())
 
-    def __post_init__(self):
-        """Call after init."""
-        if not self.uri:
-            self.uri = create_uri(self.media_type, self.provider, self.item_id)
-        if not self.sort_name:
-            self.sort_name = create_sort_name(self.name)
-
-    def __hash__(self) -> int:
-        """Return custom hash."""
-        return hash(self.uri)
-
-    def __eq__(self, other: ItemMapping) -> bool:
-        """Check equality of two items."""
-        if other is None:
-            return False  # guard
-        return self.uri == other.uri
-
 
 @dataclass(kw_only=True)
 class Artist(MediaItem):