69 lines
2.2 KiB
Python
69 lines
2.2 KiB
Python
"""Jellyfin API client."""
|
|
import os
|
|
from datetime import date, datetime, timezone
|
|
import requests
|
|
|
|
JELLYFIN_HOST = os.environ["JELLYFIN_HOST"].rstrip("/")
|
|
JELLYFIN_API_KEY = os.environ["JELLYFIN_API_KEY"]
|
|
JELLYFIN_USER_ID = os.environ["JELLYFIN_USER_ID"]
|
|
|
|
HEADERS = {"X-Emby-Token": JELLYFIN_API_KEY}
|
|
|
|
|
|
def _get_one_piece_series_id():
|
|
"""Return the Jellyfin item ID for One Piece."""
|
|
url = f"{JELLYFIN_HOST}/Users/{JELLYFIN_USER_ID}/Items"
|
|
params = {
|
|
"searchTerm": "One Piece",
|
|
"IncludeItemTypes": "Series",
|
|
"Recursive": "true",
|
|
"Limit": 5,
|
|
}
|
|
resp = requests.get(url, headers=HEADERS, params=params, timeout=10)
|
|
resp.raise_for_status()
|
|
items = resp.json().get("Items", [])
|
|
if not items:
|
|
raise RuntimeError("One Piece series not found in Jellyfin")
|
|
return items[0]["Id"]
|
|
|
|
|
|
def get_last_watched_episode(up_to_date: date) -> dict:
|
|
"""Return the last watched One Piece episode up to (and including) up_to_date.
|
|
|
|
Returns a dict with keys: season, episode, name, jellyfin_id, watched_at
|
|
"""
|
|
series_id = _get_one_piece_series_id()
|
|
|
|
url = f"{JELLYFIN_HOST}/Users/{JELLYFIN_USER_ID}/Items"
|
|
params = {
|
|
"ParentId": series_id,
|
|
"IncludeItemTypes": "Episode",
|
|
"Recursive": "true",
|
|
"Filters": "IsPlayed",
|
|
"SortBy": "DatePlayed",
|
|
"SortOrder": "Descending",
|
|
"Fields": "UserData",
|
|
"Limit": 200,
|
|
}
|
|
resp = requests.get(url, headers=HEADERS, params=params, timeout=15)
|
|
resp.raise_for_status()
|
|
items = resp.json().get("Items", [])
|
|
|
|
cutoff = datetime(up_to_date.year, up_to_date.month, up_to_date.day, 23, 59, 59, tzinfo=timezone.utc)
|
|
|
|
for item in items:
|
|
played_str = item.get("UserData", {}).get("LastPlayedDate")
|
|
if not played_str:
|
|
continue
|
|
played_dt = datetime.fromisoformat(played_str.replace("Z", "+00:00"))
|
|
if played_dt <= cutoff:
|
|
return {
|
|
"season": item["ParentIndexNumber"],
|
|
"episode": item["IndexNumber"],
|
|
"name": item.get("Name", ""),
|
|
"jellyfin_id": item["Id"],
|
|
"watched_at": played_str,
|
|
}
|
|
|
|
raise RuntimeError(f"No watched episodes found up to {up_to_date}")
|