more stuff

This commit is contained in:
Pas 2026-01-16 19:24:58 -07:00
parent 011a5a7791
commit c40aeabfb1
2 changed files with 136 additions and 107 deletions

View file

@ -1,6 +1,6 @@
generator client { generator client {
provider = "prisma-client" provider = "prisma-client"
output = "../generated" output = "../generated"
moduleFormat = "esm" moduleFormat = "esm"
} }
@ -9,11 +9,11 @@ datasource db {
} }
model bookmarks { model bookmarks {
tmdb_id String @db.VarChar(255) tmdb_id String @db.VarChar(255)
user_id String @db.VarChar(255) user_id String @db.VarChar(255)
meta Json meta Json
updated_at DateTime @db.Timestamptz(0) updated_at DateTime @db.Timestamptz(0)
group String[] group String[]
favorite_episodes String[] @default([]) favorite_episodes String[] @default([])
@@id([tmdb_id, user_id]) @@id([tmdb_id, user_id])
@ -61,50 +61,50 @@ model sessions {
} }
model user_settings { model user_settings {
id String @id id String @id
application_theme String? @db.VarChar(255) application_theme String? @db.VarChar(255)
application_language String? @db.VarChar(255) application_language String? @db.VarChar(255)
default_subtitle_language String? @db.VarChar(255) default_subtitle_language String? @db.VarChar(255)
proxy_urls String[] proxy_urls String[]
trakt_key String? @db.VarChar(255) trakt_key String? @db.VarChar(255)
febbox_key String? @db.VarChar(255) febbox_key String? @db.VarChar(255)
debrid_token String? @db.VarChar(255) enable_autoplay Boolean @default(true)
debrid_service String? @db.VarChar(255) enable_carousel_view Boolean @default(false)
enable_thumbnails Boolean @default(false) enable_details_modal Boolean @default(false)
enable_autoplay Boolean @default(true) enable_discover Boolean @default(true)
enable_skip_credits Boolean @default(true) enable_featured Boolean @default(false)
enable_discover Boolean @default(true) enable_image_logos Boolean @default(true)
enable_featured Boolean @default(false) enable_skip_credits Boolean @default(true)
enable_details_modal Boolean @default(false) enable_source_order Boolean @default(false)
enable_image_logos Boolean @default(true) enable_thumbnails Boolean @default(false)
enable_carousel_view Boolean @default(false) proxy_tmdb Boolean @default(false)
force_compact_episode_view Boolean @default(false) source_order String[] @default([])
source_order String[] @default([]) disabled_embeds String[] @default([])
enable_source_order Boolean @default(false) disabled_sources String[] @default([])
disabled_sources String[] @default([]) embed_order String[] @default([])
embed_order String[] @default([]) enable_double_click_to_seek Boolean @default(false)
enable_embed_order Boolean @default(false) enable_embed_order Boolean @default(false)
disabled_embeds String[] @default([]) enable_hold_to_boost Boolean @default(false)
proxy_tmdb Boolean @default(false) enable_low_performance_mode Boolean @default(false)
enable_low_performance_mode Boolean @default(false) enable_native_subtitles Boolean @default(false)
enable_native_subtitles Boolean @default(false) force_compact_episode_view Boolean @default(false)
enable_hold_to_boost Boolean @default(false) home_section_order String[] @default([])
home_section_order String[] @default([]) manual_source_selection Boolean @default(false)
manual_source_selection Boolean @default(false) debrid_service String? @db.VarChar(255)
enable_double_click_to_seek Boolean @default(false) debrid_token String? @db.VarChar(255)
enable_auto_resume_on_playback_error Boolean @default(false) enable_auto_resume_on_playback_error Boolean @default(false)
} }
model users { model users {
id String @id id String @id
public_key String @unique(map: "users_public_key_unique") public_key String @unique(map: "users_public_key_unique")
namespace String @db.VarChar(255) namespace String @db.VarChar(255)
nickname String @db.VarChar(255)
created_at DateTime @db.Timestamptz(0) created_at DateTime @db.Timestamptz(0)
last_logged_in DateTime? @db.Timestamptz(0) last_logged_in DateTime? @db.Timestamptz(0)
permissions String[] permissions String[]
profile Json profile Json
ratings Json @default("[]") ratings Json @default("[]")
nickname String @db.VarChar(255)
} }
model lists { model lists {
@ -132,13 +132,11 @@ model list_items {
} }
model user_group_order { model user_group_order {
id String @id @default(uuid()) @db.Uuid id String @id @default(uuid()) @db.Uuid
user_id String @db.VarChar(255) user_id String @unique(map: "user_group_order_user_id_unique") @db.VarChar(255)
group_order String[] @default([]) group_order String[] @default([])
created_at DateTime @default(now()) @db.Timestamptz(0) created_at DateTime @default(now()) @db.Timestamptz(0)
updated_at DateTime @default(now()) @db.Timestamptz(0) updated_at DateTime @default(now()) @db.Timestamptz(0)
@@unique([user_id], map: "user_group_order_user_id_unique")
} }
model watch_history { model watch_history {

View file

@ -52,75 +52,106 @@ export default defineEventHandler(async event => {
} }
if (method === 'PUT') { if (method === 'PUT') {
const body = await readBody(event); try {
const validatedBody = watchHistoryItemSchema.parse(body); const body = await readBody(event);
console.error('Watch history PUT body:', JSON.stringify(body, null, 2));
const watchedAt = defaultAndCoerceDateTime(validatedBody.watchedAt); let validatedBody;
const now = new Date(); try {
validatedBody = watchHistoryItemSchema.parse(body);
console.error('Validation successful');
} catch (validationError) {
console.error('Validation error:', validationError);
throw createError({
statusCode: 400,
message: `Validation error: ${validationError.message}`,
});
}
const existingItem = await prisma.watch_history.findUnique({ const watchedAt = defaultAndCoerceDateTime(validatedBody.watchedAt);
where: { const now = new Date();
tmdb_id_user_id_season_id_episode_id: {
tmdb_id: tmdbId,
user_id: userId,
season_id: validatedBody.seasonId || null,
episode_id: validatedBody.episodeId || null,
},
},
});
let watchHistoryItem; const existingItem = await prisma.watch_history.findUnique({
if (existingItem) {
watchHistoryItem = await prisma.watch_history.update({
where: { where: {
id: existingItem.id, tmdb_id_user_id_season_id_episode_id: {
}, tmdb_id: tmdbId,
data: { user_id: userId,
duration: parseFloat(validatedBody.duration), season_id: validatedBody.seasonId || null,
watched: parseFloat(validatedBody.watched), episode_id: validatedBody.episodeId || null,
watched_at: watchedAt, },
completed: validatedBody.completed,
meta: validatedBody.meta,
updated_at: now,
}, },
}); });
} else {
watchHistoryItem = await prisma.watch_history.create({ let watchHistoryItem;
data: {
id: randomUUID(), const data = {
tmdb_id: tmdbId, duration: parseFloat(validatedBody.duration),
user_id: userId, watched: parseFloat(validatedBody.watched),
season_id: validatedBody.seasonId || null, watched_at: watchedAt,
episode_id: validatedBody.episodeId || null, completed: validatedBody.completed,
season_number: validatedBody.seasonNumber || null, meta: validatedBody.meta,
episode_number: validatedBody.episodeNumber || null, updated_at: now,
duration: parseFloat(validatedBody.duration), };
watched: parseFloat(validatedBody.watched),
watched_at: watchedAt, try {
completed: validatedBody.completed, if (existingItem) {
meta: validatedBody.meta, console.error('Updating existing watch history item');
updated_at: now, watchHistoryItem = await prisma.watch_history.update({
}, where: {
id: existingItem.id,
},
data,
});
} else {
console.error('Creating new watch history item');
watchHistoryItem = await prisma.watch_history.create({
data: {
id: randomUUID(),
tmdb_id: tmdbId,
user_id: userId,
season_id: validatedBody.seasonId || null,
episode_id: validatedBody.episodeId || null,
season_number: validatedBody.seasonNumber || null,
episode_number: validatedBody.episodeNumber || null,
...data,
},
});
}
console.error('Database operation successful');
return {
success: true,
id: watchHistoryItem.id,
tmdbId: watchHistoryItem.tmdb_id,
userId: watchHistoryItem.user_id,
seasonId: watchHistoryItem.season_id,
episodeId: watchHistoryItem.episode_id,
seasonNumber: watchHistoryItem.season_number,
episodeNumber: watchHistoryItem.episode_number,
meta: watchHistoryItem.meta,
duration: watchHistoryItem.duration,
watched: watchHistoryItem.watched,
watchedAt: watchHistoryItem.watched_at.toISOString(),
completed: watchHistoryItem.completed,
updatedAt: watchHistoryItem.updated_at.toISOString(),
};
} catch (dbError) {
console.error('Database error:', dbError);
throw createError({
statusCode: 500,
message: `Database error: ${dbError.message}`,
});
}
} catch (error) {
console.error('Error in watch history PUT:', error);
if (error.statusCode) {
throw error; // Re-throw createError instances
}
throw createError({
statusCode: 500,
message: 'Failed to save watch history',
}); });
} }
return {
success: true,
id: watchHistoryItem.id,
tmdbId: watchHistoryItem.tmdb_id,
userId: watchHistoryItem.user_id,
seasonId: watchHistoryItem.season_id,
episodeId: watchHistoryItem.episode_id,
seasonNumber: watchHistoryItem.season_number,
episodeNumber: watchHistoryItem.episode_number,
meta: watchHistoryItem.meta,
duration: watchHistoryItem.duration,
watched: watchHistoryItem.watched,
watchedAt: watchHistoryItem.watched_at.toISOString(),
completed: watchHistoryItem.completed,
updatedAt: watchHistoryItem.updated_at.toISOString(),
};
} }
if (method === 'DELETE') { if (method === 'DELETE') {