Publish current app and server

This commit is contained in:
ponzischeme89
2026-08-02 22:10:19 +12:00
parent a265636139
commit 1ed180c739
203 changed files with 23933 additions and 2788 deletions
+75
View File
@@ -13,6 +13,7 @@ CREATE TABLE IF NOT EXISTS sessions (
device_name TEXT NOT NULL DEFAULT 'Memby TV',
client_version TEXT NOT NULL DEFAULT '',
client_protocol TEXT NOT NULL DEFAULT '',
client_capabilities TEXT[] NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
@@ -20,6 +21,7 @@ CREATE TABLE IF NOT EXISTS sessions (
ALTER TABLE sessions ADD COLUMN IF NOT EXISTS device_name TEXT NOT NULL DEFAULT 'Memby TV';
ALTER TABLE sessions ADD COLUMN IF NOT EXISTS client_version TEXT NOT NULL DEFAULT '';
ALTER TABLE sessions ADD COLUMN IF NOT EXISTS client_protocol TEXT NOT NULL DEFAULT '';
ALTER TABLE sessions ADD COLUMN IF NOT EXISTS client_capabilities TEXT[] NOT NULL DEFAULT '{}';
-- Older builds could create more than one token for the same physical TV. Keep the most
-- recently used row before adding the identity constraint.
@@ -119,6 +121,50 @@ CREATE TABLE IF NOT EXISTS search_history (
CREATE INDEX IF NOT EXISTS search_history_user_time_idx
ON search_history (emby_user_id, occurred_at DESC);
-- A user's explicitly followed TV series. Unlike library_items this is intentionally
-- user-scoped: following a show is a Memby preference, not Emby library state.
CREATE TABLE IF NOT EXISTS user_shows (
emby_user_id TEXT NOT NULL,
item_id TEXT NOT NULL,
title TEXT NOT NULL,
year INT,
image_tag TEXT NOT NULL DEFAULT '',
added_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (emby_user_id, item_id)
);
CREATE INDEX IF NOT EXISTS user_shows_user_added_idx
ON user_shows (emby_user_id, added_at);
CREATE TABLE IF NOT EXISTS user_notification_preferences (
emby_user_id TEXT PRIMARY KEY,
enabled BOOLEAN NOT NULL DEFAULT true,
show_return_alerts BOOLEAN NOT NULL DEFAULT true,
lead_days INT NOT NULL DEFAULT 7 CHECK (lead_days BETWEEN 1 AND 30),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Notifications are materialised so read/dismissed state follows the user to every TV.
-- source_key is deterministic, preventing the same return date from being announced
-- again whenever the app refreshes.
CREATE TABLE IF NOT EXISTS user_notifications (
id BIGSERIAL PRIMARY KEY,
emby_user_id TEXT NOT NULL,
source_key TEXT NOT NULL,
kind TEXT NOT NULL,
item_id TEXT NOT NULL DEFAULT '',
title TEXT NOT NULL,
message TEXT NOT NULL,
event_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
read_at TIMESTAMPTZ,
dismissed_at TIMESTAMPTZ,
UNIQUE (emby_user_id, source_key)
);
CREATE INDEX IF NOT EXISTS user_notifications_user_created_idx
ON user_notifications (emby_user_id, created_at DESC);
-- Recommendation-relevant Tracearr history. The public Tracearr API has no user or
-- since cursor, so stable source ids make these rows the durable deduplication boundary.
-- Deliberately omit artwork, stream-detail blobs and other fields unused by ranking.
@@ -180,7 +226,10 @@ CREATE TABLE IF NOT EXISTS recommendation_user_profiles (
genre_affinity JSONB NOT NULL DEFAULT '{}'::jsonb,
title_affinity JSONB NOT NULL DEFAULT '{}'::jsonb,
studio_affinity JSONB NOT NULL DEFAULT '{}'::jsonb,
context_affinity JSONB NOT NULL DEFAULT '{}'::jsonb,
codec_outcomes JSONB NOT NULL DEFAULT '{}'::jsonb,
weighted_profile JSONB NOT NULL DEFAULT '{}'::jsonb,
algorithm_version TEXT NOT NULL DEFAULT '',
signals_through TIMESTAMPTZ,
built_at TIMESTAMPTZ,
pool_built_at TIMESTAMPTZ,
@@ -188,6 +237,32 @@ CREATE TABLE IF NOT EXISTS recommendation_user_profiles (
last_error TEXT NOT NULL DEFAULT ''
);
ALTER TABLE recommendation_user_profiles
ADD COLUMN IF NOT EXISTS context_affinity JSONB NOT NULL DEFAULT '{}'::jsonb;
ALTER TABLE recommendation_user_profiles
ADD COLUMN IF NOT EXISTS algorithm_version TEXT NOT NULL DEFAULT '';
ALTER TABLE recommendation_user_profiles
ADD COLUMN IF NOT EXISTS weighted_profile JSONB NOT NULL DEFAULT '{}'::jsonb;
-- Explicit recommendation feedback is separate from Emby favourites: More Like This
-- changes discovery affinity, while Not for Me is a hard user-scoped exclusion.
CREATE TABLE IF NOT EXISTS recommendation_actions (
emby_user_id TEXT NOT NULL,
item_id TEXT NOT NULL,
action TEXT NOT NULL CHECK (action IN ('more_like_this', 'not_for_me')),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (emby_user_id, item_id)
);
CREATE INDEX IF NOT EXISTS recommendation_actions_user_idx
ON recommendation_actions (emby_user_id, updated_at DESC);
CREATE TABLE IF NOT EXISTS recommendation_onboarding (
emby_user_id TEXT PRIMARY KEY,
preferences JSONB NOT NULL DEFAULT '{}'::jsonb,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS recommendation_profiles_dirty_idx
ON recommendation_user_profiles (dirty_since)
WHERE dirty_since IS NOT NULL;