Commit Graph

5 Commits

Author SHA1 Message Date
odin 1752870cee Show the calendar in the viewer's own timezone
An episode's air_date is a DATE in the broadcaster's country, so the calendar
could only ever file things under the network's day. Last Week Tonight airs
23:00 Sunday in New York, which is 05:00 MONDAY in Stockholm -- the calendar
put it on Sunday for everyone, and nothing anywhere showed a time.

series.airs_time and series.airs_timezone (0026) carry the network's local
airtime and its zone; the agent repository fills them from TVDB, which is the
only source that has them. Postgres does the conversion:

    ((e.air_date + se.airs_time) at time zone se.airs_timezone) at time zone $viewer

against the episode's own date, so it stays right across a DST boundary in a
way a stored offset would not.

THE BROWSER REPORTS ITS ZONE IN A COOKIE rather than the page converting after
hydration. Converting client-side would leave the server unable to group, sort
or decide what "today" is, and would make it send HTML it then disagrees with.
The cookie is validated against Intl before it reaches SQL -- it is passed as a
bound parameter either way, but a client-chosen string that ends up inside
`at time zone` is worth closing off at the door too.

The window is widened a day at each end, because an episode airing late on the
last day belongs to the next day for a viewer far enough east, and one on the
first day can move back. Anything landing outside the displayed days is simply
never looked up.

Series with no airtime -- 28 of 517, plus every film -- fall back to the bare
date and no time, which is exactly what this page did before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 15:42:31 +02:00
odin 1dfa2c0a04 Add the profile page, and publish it as an embeddable panel
Developed in a separate session; committed here alongside the calendar work
that shares this repository's migration journal.

A person can now see their own Plex link, their Watch Now slots and their watch
history at /profile. The same panel is published in two further forms so that
accounts.sticknife.com on charon can carry it as one section of a wider
sticknife profile, next to the other services' sections.

  - watch_history (0024) records what has been played, keyed on the Plex
    history id so a re-sync cannot duplicate a row. Partial unique index,
    because that id is null for anything entered by hand.
  - plex_accounts.is_server_owner (0025) marks the one account whose viewing
    the server files under local account 1 rather than under its plex.tv id.
  - The embed carries its own layout, origin allowlist and a frame-height
    reporter, so the host page can size it without guessing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 15:42:17 +02:00
Ryan 3ccae54259 Authentik moved to charon.sticknife.com
The identity provider's hostname changed. Only AUTHENTIK_ISSUER points at it,
so the live change is one line in .env.local; this commit carries the docs and
the example, which still named the old host.

The issuer string has to match the provider's own discovery document exactly,
trailing slash and all -- a host that answers is not the same as an issuer that
validates -- so the example now says how to check it. AUTH_URL is unrelated and
stays: it is this app's address, not Authentik's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 12:40:58 +02:00
Ryan cd08e15625 Commit the env example that .env* was swallowing
create-next-app's .gitignore matches .env*, which takes the example with it.
The file documenting every variable the app needs was the one file in the
pattern that has to be tracked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 12:12:33 +02:00
Ryan acdc25c797 Ampelos dashboard: the web face, and the owner of the schema
Split out of the single Ampelos repository. Next.js app, Drizzle schema and
migrations, brand art, planning notes.

What left: scripts/, which was the agent's job library misfiled under web/ and
imported nothing from src/; and deploy/truenas, whose broadcast posts to the
scan listener on :3427 -- an agent script -- so it belongs beside the thing it
talks to.

This repository keeps the schema. The agent speaks raw SQL against the same
tables and holds no copy of it, so a rename here can break it silently where it
used to be one commit. The README says so, and the agent carries a snapshot to
check against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 12:12:08 +02:00