80 lines
1.6 KiB
TypeScript
80 lines
1.6 KiB
TypeScript
/**
|
|
* rTube Automerge document schemas.
|
|
*
|
|
* Syncs shared playlists and watch party state across space members.
|
|
* Actual video files remain on R2/S3; this doc manages collaborative
|
|
* curation and viewing sessions.
|
|
*
|
|
* DocId format: {space}:tube:playlists
|
|
*/
|
|
|
|
import type { DocSchema } from '../../shared/local-first/document';
|
|
|
|
// ── Document types ──
|
|
|
|
export interface PlaylistEntry {
|
|
videoName: string;
|
|
addedBy: string | null;
|
|
addedAt: number;
|
|
}
|
|
|
|
export interface Playlist {
|
|
id: string;
|
|
name: string;
|
|
entries: PlaylistEntry[];
|
|
createdBy: string | null;
|
|
createdAt: number;
|
|
}
|
|
|
|
export interface WatchParty {
|
|
videoName: string;
|
|
startedBy: string | null;
|
|
startedAt: number;
|
|
/** Playback position in seconds */
|
|
position: number;
|
|
playing: boolean;
|
|
}
|
|
|
|
export interface TubeDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
playlists: Record<string, Playlist>;
|
|
watchParty: WatchParty | null;
|
|
}
|
|
|
|
// ── Schema registration ──
|
|
|
|
export const tubeSchema: DocSchema<TubeDoc> = {
|
|
module: 'tube',
|
|
collection: 'playlists',
|
|
version: 1,
|
|
init: (): TubeDoc => ({
|
|
meta: {
|
|
module: 'tube',
|
|
collection: 'playlists',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
playlists: {},
|
|
watchParty: null,
|
|
}),
|
|
migrate: (doc: any, _fromVersion: number) => {
|
|
if (!doc.playlists) doc.playlists = {};
|
|
if (!('watchParty' in doc)) doc.watchParty = null;
|
|
doc.meta.version = 1;
|
|
return doc;
|
|
},
|
|
};
|
|
|
|
// ── Helpers ──
|
|
|
|
export function tubeDocId(space: string) {
|
|
return `${space}:tube:playlists` as const;
|
|
}
|