feat(series): watch series and suggest new parts once a day

This commit is contained in:
Steppenstreuner committed 2026-10-25 20:17:13 +01:00
1 parent 175dface50
commit 55d7c8bdda
4 files changed
+277 -1

No files matched your search

+65
View File
@@ -1359,3 +1359,68 @@ def test_recent_logs_newest_first(client):
rows = client.get("/api/system/logs").json()
assert [r["message"] for r in rows[:2]] == ["second", "first"]
assert rows[0]["level"] == "WARNING"
def test_watched_series_suggests_only_new_parts(client, monkeypatch):
import asyncio
import datetime
from wordarr import db
from wordarr.api import series
from wordarr.metadata import SERIES_PROVIDERS
from wordarr.metadata.base import MetadataResult
def part(volume, external_id=""):
return MetadataResult(media_type="ebook", title=f"Band {volume}", volume=volume,
series="Saga", external_id=external_id, source="hardcover")
hits = [part(1, "a1"), part(2, "a2")]
calls = []
async def lookup(series_id, title, language, source):
calls.append(series_id)
if hits is None:
raise RuntimeError("offline")
return hits
monkeypatch.setitem(SERIES_PROVIDERS, "ebook", lookup)
lib = client.post("/api/libraries", json={
"name": "Saga", "media_type": "ebook", "root_path": str(client.tmp_path)}).json()
client.post("/api/requests", json={"library_id": lib["id"], "title": "Band 3", "volume": 3})
watch = {"media_type": "ebook", "library_id": lib["id"], "series_id": "s1",
"source": "hardcover", "title": "Saga"}
resp = client.post("/api/series", json=watch)
assert resp.status_code == 200
assert resp.json()["new"] == [] # what exists today is not news
assert client.post("/api/series", json=watch).status_code == 409
hits += [part(3), part(4, "a4"), part(5, "a5")] # 3 is requested already
[w] = client.post("/api/series/check").json()
new = {p["title"]: p["id"] for p in w["new"]}
assert set(new) == {"Band 4", "Band 5"}
client.post("/api/series/parts", json={"ids": [new["Band 4"]], "action": "request"})
client.post("/api/series/parts", json={"ids": [new["Band 5"]], "action": "ignore"})
missing = client.get("/api/requests?status=missing").json()
assert {r["title"] for r in missing} == {"Band 3", "Band 4"}
assert client.post("/api/series/check").json()[0]["new"] == []
hits = None
[w] = client.post("/api/series/check").json()
assert w["error"] == "offline"
assert client.post("/api/series", json={**watch, "series_id": "s2"}).status_code == 502
# the daily run only picks up what was checked more than a day ago
hits, calls[:] = [], []
asyncio.run(series.check_due())
assert calls == []
with db.SessionLocal() as session:
session.get(db.WatchedSeries, w["id"]).checked_at = (
datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=2))
session.commit()
asyncio.run(series.check_due())
assert calls == ["s1"]
assert client.delete(f"/api/series/{w['id']}").status_code == 200
assert client.get("/api/series").json() == []