mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
feat: playback position persistence for all players and grid indicators
This commit is contained in:
1 parent
d218dc0ad2
commit
adb89145a3
46 files changed
+2310
-146
No files matched your search
@@ -157,6 +157,24 @@ const CREATE_TABLE_STATEMENTS = [
|
||||
INSERT INTO epg_programs_fts(rowid, title, description, category)
|
||||
VALUES (new.id, new.title, new.description, new.category);
|
||||
END`,
|
||||
// Playback Positions table
|
||||
`CREATE TABLE IF NOT EXISTS playback_positions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
playlist_id TEXT NOT NULL,
|
||||
content_xtream_id INTEGER NOT NULL,
|
||||
content_type TEXT NOT NULL CHECK (content_type IN ('vod', 'episode')),
|
||||
series_xtream_id INTEGER,
|
||||
season_number INTEGER,
|
||||
episode_number INTEGER,
|
||||
position_seconds INTEGER NOT NULL DEFAULT 0,
|
||||
duration_seconds INTEGER,
|
||||
updated_at TEXT DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (playlist_id) REFERENCES playlists (id) ON DELETE CASCADE
|
||||
)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS playback_positions_content_playlist_unique ON playback_positions(content_xtream_id, playlist_id, content_type)`,
|
||||
`CREATE INDEX IF NOT EXISTS playback_positions_playlist_idx ON playback_positions(playlist_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS playback_positions_series_idx ON playback_positions(series_xtream_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS playback_positions_updated_idx ON playback_positions(updated_at)`,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -169,6 +169,48 @@ export const epgPrograms = sqliteTable(
|
||||
})
|
||||
);
|
||||
|
||||
// Playback Positions table
|
||||
export const playbackPositions = sqliteTable(
|
||||
'playback_positions',
|
||||
{
|
||||
id: integer('id').primaryKey({ autoIncrement: true }),
|
||||
playlistId: text('playlist_id')
|
||||
.notNull()
|
||||
.references(() => playlists.id, { onDelete: 'cascade' }),
|
||||
// For VOD: store xtream_id of the movie
|
||||
// For Series: store episode ID (from XtreamSerieEpisode.id)
|
||||
contentXtreamId: integer('content_xtream_id').notNull(),
|
||||
// 'vod' | 'episode'
|
||||
contentType: text('content_type', {
|
||||
enum: ['vod', 'episode'],
|
||||
}).notNull(),
|
||||
// For episodes: store series xtream_id for grouping
|
||||
seriesXtreamId: integer('series_xtream_id'),
|
||||
// For episodes: store season and episode numbers for display
|
||||
seasonNumber: integer('season_number'),
|
||||
episodeNumber: integer('episode_number'),
|
||||
// Playback position in seconds
|
||||
positionSeconds: integer('position_seconds').notNull().default(0),
|
||||
// Total duration in seconds (for percentage calculation)
|
||||
durationSeconds: integer('duration_seconds'),
|
||||
// Last updated timestamp
|
||||
updatedAt: text('updated_at').default(sql`CURRENT_TIMESTAMP`),
|
||||
},
|
||||
(table) => ({
|
||||
// Unique constraint: one position per content per playlist
|
||||
contentPlaylistUnique: uniqueIndex(
|
||||
'playback_positions_content_playlist_unique'
|
||||
).on(table.contentXtreamId, table.playlistId, table.contentType),
|
||||
playlistIdx: index('playback_positions_playlist_idx').on(
|
||||
table.playlistId
|
||||
),
|
||||
seriesIdx: index('playback_positions_series_idx').on(
|
||||
table.seriesXtreamId
|
||||
),
|
||||
updatedIdx: index('playback_positions_updated_idx').on(table.updatedAt),
|
||||
})
|
||||
);
|
||||
|
||||
// Type exports for TypeScript
|
||||
export type Playlist = typeof playlists.$inferSelect;
|
||||
export type NewPlaylist = typeof playlists.$inferInsert;
|
||||
@@ -190,3 +232,6 @@ export type NewEpgChannel = typeof epgChannels.$inferInsert;
|
||||
|
||||
export type EpgProgramDb = typeof epgPrograms.$inferSelect;
|
||||
export type NewEpgProgramDb = typeof epgPrograms.$inferInsert;
|
||||
|
||||
export type PlaybackPosition = typeof playbackPositions.$inferSelect;
|
||||
export type NewPlaybackPosition = typeof playbackPositions.$inferInsert;
|
||||
Reference in new issue
Block a user