Add Emby webhook integration and remove unused username field

Add Emby as a third media server integration alongside Plex and Jellyfin.
Emby webhooks use a similar payload format (JSON with nested Item object
and ProviderIds). Also removes the mediaServerUsername field from all
webhook connections since it was never used for authentication — the
token-in-URL is the sole auth mechanism. This simplifies the connection
UX to a single "Connect" button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 00:50:32 -05:00
co-authored by Claude Opus 4.6
parent 0409a65a56
commit bafa45ec79
11 changed files with 2292 additions and 178 deletions
+5 -4
View File
@@ -181,7 +181,7 @@ export const userMovieWatches = sqliteTable(
.references(() => titles.id, { onDelete: "cascade" }),
watchedAt: int("watchedAt", { mode: "timestamp" }).notNull(),
source: text("source", {
enum: ["manual", "import", "plex", "jellyfin"],
enum: ["manual", "import", "plex", "jellyfin", "emby"],
})
.notNull()
.default("manual"),
@@ -207,7 +207,7 @@ export const userEpisodeWatches = sqliteTable(
.references(() => episodes.id, { onDelete: "cascade" }),
watchedAt: int("watchedAt", { mode: "timestamp" }).notNull(),
source: text("source", {
enum: ["manual", "import", "plex", "jellyfin"],
enum: ["manual", "import", "plex", "jellyfin", "emby"],
})
.notNull()
.default("manual"),
@@ -297,9 +297,10 @@ export const webhookConnections = sqliteTable(
userId: text("userId")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
provider: text("provider", { enum: ["plex", "jellyfin"] }).notNull(),
provider: text("provider", {
enum: ["plex", "jellyfin", "emby"],
}).notNull(),
token: text("token").notNull().unique(),
mediaServerUsername: text("mediaServerUsername").notNull(),
enabled: int("enabled", { mode: "boolean" }).notNull().default(true),
createdAt: int("createdAt", { mode: "timestamp" }).notNull(),
lastEventAt: int("lastEventAt", { mode: "timestamp" }),