51 lines
1.7 KiB
Python
51 lines
1.7 KiB
Python
"""Per-user watch history.
|
|||
|
|
|
||
|
|
Every query here is scoped to a single ``user_id`` via the ``/Users/{id}/Items``
|
||
|
|
endpoint, so one user's history is never mixed with another's.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from .emby_collections import ITEM_FIELDS, normalize_item
|
||
|
|
|
||
|
|
# Movies and series are what we recommend; episodes are folded into their series.
|
||
|
|
WATCHED_ITEM_TYPES = "Movie,Series"
|
||
|
|
|
||
|
|
|
||
|
|
async def get_watched_items(client, user_id: str, item_types: str = WATCHED_ITEM_TYPES) -> list[dict]:
|
||
|
|
"""Return the user's played items (normalized) for the given types."""
|
||
|
|
if not user_id:
|
||
|
|
return []
|
||
|
|
raw_items = await client.get_all(
|
||
|
|
f"/Users/{user_id}/Items",
|
||
|
|
{
|
||
|
|
"Recursive": "true",
|
||
|
|
"IsPlayed": "true",
|
||
|
|
"Filters": "IsPlayed",
|
||
|
|
"IncludeItemTypes": item_types,
|
||
|
|
"Fields": ITEM_FIELDS,
|
||
|
|
"EnableUserData": "true",
|
||
|
|
},
|
||
|
|
)
|
||
|
|
return [normalize_item(raw) for raw in raw_items]
|
||
|
|
|
||
|
|
|
||
|
|
async def get_watched_item_ids(client, user_id: str, item_types: str = WATCHED_ITEM_TYPES) -> set[str]:
|
||
|
|
"""Return the set of item ids the user has watched."""
|
||
|
|
return {item["id"] for item in await get_watched_items(client, user_id, item_types) if item["id"]}
|
||
|
|
|
||
|
|
|
||
|
|
async def is_item_watched(client, user_id: str, item_id: str) -> bool:
|
||
|
|
"""Whether ``user_id`` has played ``item_id`` (user-specific)."""
|
||
|
|
if not (user_id and item_id):
|
||
|
|
return False
|
||
|
|
data = await client.get(
|
||
|
|
f"/Users/{user_id}/Items",
|
||
|
|
{"Ids": item_id, "EnableUserData": "true"},
|
||
|
|
)
|
||
|
|
items = data.get("Items", []) if isinstance(data, dict) else (data or [])
|
||
|
|
if not items:
|
||
|
|
return False
|
||
|
|
user_data = items[0].get("UserData") or {}
|
||
|
|
return bool(user_data.get("Played", False))
|