self.limit = limit
self.offset = offset
self.total = total
- if total is None and offset == 0 and count > limit:
- self.total = count
- if total is None and offset and count < limit:
+ if total is None and count != limit:
+ # total is important so always calculate it from count if omitted
self.total = offset + count
def to_dict(self, *args, **kwargs) -> dict[str, Any]:
# store (serializable items) in cache
if prov.is_streaming_provider:
self.mass.create_task(self.mass.cache.set(cache_key, [x.to_dict() for x in items]))
+ for item in items:
+ # if this is a complete track object, pre-cache it as
+ # that will save us an (expensive) lookup later
+ if item.image and item.artist_str and item.album and prov.domain != "builtin":
+ await self.mass.cache.set(
+ f"provider_item.track.{prov.lookup_key}.{item_id}", item.to_dict()
+ )
return items
async def _get_provider_dynamic_tracks(
if isinstance(update, ItemMapping):
# NOTE that artist is the only mediatype where its accepted we
# receive an itemmapping from streaming providers
- update = Artist.from_item_mapping(update)
+ update = self._artist_from_item_mapping(update)
metadata = cur_item.metadata
else:
metadata = update.metadata if overwrite else cur_item.metadata.update(update.metadata)
"position": "position ASC",
"position_desc": "position DESC",
"random": "RANDOM()",
+ "random_play_count": "RANDOM(), play_count",
}
)
if not prov:
return PagedItems(items=prepend_items, limit=limit, offset=offset)
- else:
+ elif offset == 0:
back_path = f"{provider_instance}://" + "/".join(sub_path.split("/")[:-1])
prepend_items.append(
BrowseFolder(item_id="back", provider=provider_instance, path=back_path, name="..")
)
- prov_items = await prov.browse(path, offset, limit)
+ # limit -1 to account for the prepended items
+ prov_items = await prov.browse(path, offset=offset, limit=limit)
prov_items.items = prepend_items + prov_items.items
return prov_items
continue
with suppress(MediaNotFoundError, ProviderUnavailableError):
media_type = MediaType(db_row["media_type"])
- item = await self.get_item(media_type, db_row["item_id"], db_row["provider"])
+ ctrl = self.get_controller(media_type)
+ item = await ctrl.get_provider_item(db_row["item_id"], db_row["provider"])
result.append(item)
return result
# we may NOT use the default implementation if the provider does not support browse
raise NotImplementedError
items: list[MediaItemType] = []
- index = 0
+ index = -1
subpath = path.split("://", 1)[1]
# this reference implementation can be overridden with a provider specific approach
generator: AsyncGenerator[MediaItemType, None] | None = None
if generator:
# grab items from library generator
async for item in generator:
+ index += 1
if index < offset:
continue
items.append(item)
- index += 1
if len(items) >= limit:
break
else:
result: list[Track] = []
if builtin_playlist_id == ALL_FAVORITE_TRACKS:
res = await self.mass.music.tracks.library_items(
- favorite=True, limit=2500, order_by="RANDOM(), play_count"
+ favorite=True, limit=2500, order_by="random_play_count"
)
for idx, item in enumerate(res.items, 1):
item.position = idx
return result
if builtin_playlist_id == RANDOM_TRACKS:
res = await self.mass.music.tracks.library_items(
- limit=500, order_by="RANDOM(), play_count"
+ limit=500, order_by="random_play_count"
)
for idx, item in enumerate(res.items, 1):
item.position = idx
return result
if builtin_playlist_id == RANDOM_ALBUM:
for random_album in (
- await self.mass.music.albums.library_items(limit=1, order_by="RANDOM()")
+ await self.mass.music.albums.library_items(limit=1, order_by="random")
).items:
# use the function specified in the queue controller as that
# already handles unwrapping an album by user preference
return result
if builtin_playlist_id == RANDOM_ARTIST:
for random_artist in (
- await self.mass.music.artists.library_items(limit=1, order_by="RANDOM()")
+ await self.mass.music.artists.library_items(limit=1, order_by="random")
).items:
# use the function specified in the queue controller as that
# already handles unwrapping an artist by user preference
type=ImageType.THUMB,\r
path=thumb,\r
provider=self.instance_id,\r
- remotely_accessible=True,\r
+ remotely_accessible=False,\r
)\r
]\r
if ITEM_KEY_OVERVIEW in current_jellyfin_album:\r
type=ImageType.THUMB,\r
path=thumb,\r
provider=self.instance_id,\r
- remotely_accessible=True,\r
+ remotely_accessible=False,\r
)\r
]\r
return artist\r
type=ImageType.THUMB,\r
path=thumb,\r
provider=self.instance_id,\r
- remotely_accessible=True,\r
+ remotely_accessible=False,\r
)\r
]\r
if len(current_jellyfin_track[ITEM_KEY_ARTIST_ITEMS]) >= 1:\r
parent_album[ITEM_KEY_ALBUM_ARTIST],\r
)\r
)\r
- track.artists.append(\r
- self._get_item_mapping(\r
- MediaType.ARTIST,\r
- parent_album[ITEM_KEY_PARENT_ID],\r
- parent_album[ITEM_KEY_ALBUM_ARTIST],\r
- )\r
- )\r
else:\r
track.artists.append(await self._parse_artist(name=VARIOUS_ARTISTS_NAME))\r
if (\r
type=ImageType.THUMB,\r
path=thumb,\r
provider=self.instance_id,\r
- remotely_accessible=True,\r
+ remotely_accessible=False,\r
)\r
]\r
playlist.is_editable = False\r
) -> list[Track]:\r
"""Get playlist tracks."""\r
result: list[Track] = []\r
+ # TODO: Does Jellyfin support paging here?\r
jellyfin_playlist = API.get_item(self._jellyfin_server.jellyfin, prov_playlist_id)\r
playlist_items = await self._get_children(\r
self._jellyfin_server, jellyfin_playlist[ITEM_KEY_ID], ITEM_TYPE_AUDIO\r
if not playlist_items:\r
return result\r
for index, jellyfin_track in enumerate(playlist_items):\r
- if track := await self._parse_track(jellyfin_track):\r
- if not track.position:\r
- track.position = index\r
- result.append(track)\r
+ try:\r
+ if track := await self._parse_track(jellyfin_track):\r
+ if not track.position:\r
+ track.position = index\r
+ result.append(track)\r
+ except (KeyError, ValueError) as err:\r
+ self.logger.error(\r
+ "Skipping track %s: %s", jellyfin_track.get(ITEM_KEY_NAME, index), str(err)\r
+ )\r
return result\r
\r
async def get_artist_albums(self, prov_artist_id) -> list[Album]:\r
return result
- async def browse(self, path: str, limit: int, offset: int) -> PagedItems[MediaItemType]:
+ async def browse(self, path: str, offset: int, limit: int) -> PagedItems[MediaItemType]:
"""Browse this provider's items.
:param path: The path to browse, (e.g. provid://artists).