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>
This commit is contained in:
@@ -14,6 +14,17 @@ type WatchKind = "television" | "movies";
|
||||
|
||||
type WatchNowResult = { ok: true } | { ok: false; message: string };
|
||||
|
||||
/**
|
||||
* The board, the profile page and the embed all show Watch Now, so all three
|
||||
* are stale the moment any of them changes. Revalidating only "/" was correct
|
||||
* when the board was the only place slots were visible; it no longer is.
|
||||
*/
|
||||
function revalidateWatchNow() {
|
||||
revalidatePath("/");
|
||||
revalidatePath("/profile");
|
||||
revalidatePath("/embed/profile");
|
||||
}
|
||||
|
||||
function validDate(value: FormDataEntryValue | null) {
|
||||
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
||||
return null;
|
||||
@@ -169,7 +180,7 @@ export async function addToWatchNow(formData: FormData): Promise<WatchNowResult
|
||||
: await firstOpenSlot(session.user.id, mediaType, quota);
|
||||
|
||||
if (!targetSlot) {
|
||||
revalidatePath("/");
|
||||
revalidateWatchNow();
|
||||
return { ok: false, message: "No Watch Now slots are open." };
|
||||
}
|
||||
const overview = optionalString(formData.get("overview"));
|
||||
@@ -217,7 +228,7 @@ export async function addToWatchNow(formData: FormData): Promise<WatchNowResult
|
||||
});
|
||||
}
|
||||
|
||||
revalidatePath("/");
|
||||
revalidateWatchNow();
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
@@ -253,7 +264,7 @@ export async function removeFromWatchNowByTmdbId(formData: FormData): Promise<Wa
|
||||
);
|
||||
}
|
||||
|
||||
revalidatePath("/");
|
||||
revalidateWatchNow();
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
@@ -271,7 +282,7 @@ export async function removeFromWatchNow(formData: FormData) {
|
||||
.set({ removedAt: new Date() })
|
||||
.where(and(eq(watchingNowItems.id, itemId), eq(watchingNowItems.userId, session.user.id)));
|
||||
|
||||
revalidatePath("/");
|
||||
revalidateWatchNow();
|
||||
}
|
||||
|
||||
export async function moveWatchNowItem(formData: FormData) {
|
||||
@@ -312,5 +323,5 @@ export async function moveWatchNowItem(formData: FormData) {
|
||||
await clearSlot(session.user.id, mediaType, targetSlot, itemId);
|
||||
await db.update(watchingNowItems).set({ slotNumber: targetSlot }).where(eq(watchingNowItems.id, itemId));
|
||||
|
||||
revalidatePath("/");
|
||||
revalidateWatchNow();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user