fix(home): shelf honours the Plex gate; hero unpins its origin; palette asks for a surprise

- A13: with Plex off, the Home shelf and the hero's comfort tier go YouTube-only like the rails
  beside them (owner's call: hide the tiles). The pins are kept; GET /pins still lists them.
- Reorder deals the listed pins into the slots they already hold, so a partial list (hidden Plex
  pins, a stale tab) no longer puts two pins on one position; repeats are ignored.
- A21: a comfort hero carries `pinned_from`, the shelf entry it was resolved from; its menu acts on
  that pin, so a pinned show's next episode offers "Unpin" instead of creating a second pin.
- B12: the palette's "Meglepetés" asks for the surprise tier (the next press leading with it); the
  rotation carries on from there.
- B13: the surprise token names the history entry it was requested for (minted by setPage's new
  `then`, after the push) and is dropped on any other entry, so a navigation that never mounted
  Home cannot replay it later.
This commit is contained in:
2026-09-19 17:07:11 +02:00
parent c6bf84a578
commit 7b94e9a651
15 changed files with 291 additions and 60 deletions
+62
View File
@@ -1007,3 +1007,65 @@ def test_deleting_a_pin_reports_what_went(db, as_user):
r = c.delete(f"/api/discover/pins/{pin_id}")
assert r.status_code == 200 and r.json() == {"deleted": pin_id}
assert c.get("/api/discover/pins").json()["items"] == []
def test_with_plex_off_the_home_shelf_hides_plex_pins_but_keeps_them(db, as_user):
"""The owner's call (2026-09-19): with the deployment's Plex toggle off, the Home shelf goes
YouTube-only like the rails beside it — a Plex tile there offered a Play that landed on a gated
module. The hero's comfort tier draws from the same filtered shelf, and the pin menus' own
listing still sees every pin, so nothing the user curated is lost."""
user, _ = _seed_yt(db)
_seed_plex(db, user)
db.add_all(
[
ComfortPin(
user_id=user.id,
plex_item_id=db.scalar(select(PlexItem.id).where(PlexItem.rating_key == "pm1")),
position=0,
),
ComfortPin(user_id=user.id, video_id="vlong", position=1),
]
)
db.commit()
c = as_user(user)
assert [t["id"] for t in c.get("/api/discover").json()["comfort"]] == ["vlong"]
assert c.get("/api/discover/pick?start=1").json()["hero"]["card"]["id"] == "vlong"
assert {t["id"] for t in c.get("/api/discover/pins").json()["items"]} == {"pm1", "vlong"}
_enable_plex(db)
assert [t["id"] for t in c.get("/api/discover").json()["comfort"]] == ["pm1", "vlong"]
def test_a_reorder_of_the_visible_pins_keeps_the_hidden_ones_in_place(db, as_user):
"""The client sends the order it SHOWS. With Plex off that leaves the Plex pins out, and
numbering only the listed ids 0..n-1 put two pins on one position and moved the hidden one about
when Plex came back. The listed pins trade the slots they hold; the rest stay put."""
user, ch = _seed_yt(db)
_seed_plex(db, user)
c = as_user(user)
_enable_plex(db)
a = c.post("/api/discover/pins", json={"kind": "video", "ref": "vmed"}).json()["id"]
hidden = c.post("/api/discover/pins", json={"kind": "plex_item", "ref": "pm1"}).json()["id"]
b = c.post("/api/discover/pins", json={"kind": "channel", "ref": ch.id}).json()["id"]
assert c.post("/api/discover/pins/reorder", json={"ids": [b, b, a]}).status_code == 200
assert [p["pin_id"] for p in c.get("/api/discover/pins").json()["items"]] == [b, hidden, a]
positions = db.scalars(select(ComfortPin.position).where(ComfortPin.user_id == user.id)).all()
assert sorted(positions) == [0, 1, 2]
def test_a_hero_from_a_show_pin_names_the_pin_it_came_from(db, as_user):
"""A show's next EPISODE is not itself pinned, so the hero's menu used to look the episode up,
miss, and offer "Pin" under "From your shelf" — creating a second pin. The card now carries
the pin it was resolved from, which the menu acts on (owner's call: "Unpin")."""
user, _ = _seed_yt(db)
_seed_plex(db, user)
_enable_plex(db)
c = as_user(user)
assert c.post("/api/discover/pins", json={"kind": "plex_show", "ref": "ps1"}).status_code == 200
got = c.get("/api/discover/pick?start=1").json()["hero"]
assert got["tier"] == "comfort" and got["card"]["id"] == "ps1e1"
assert got["card"]["pinned_from"] == {
"source": "plex",
"kind": "show",
"id": "ps1",
"title": "A Show",
}