update formating and schemas

This commit is contained in:
Pas 2025-03-12 22:34:56 -06:00
parent c9bb651995
commit 950c1e051a
7 changed files with 163 additions and 156 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ dist
.env
.vscode
.metrics.json
.metrics.json

View file

@ -5,7 +5,7 @@ const bookmarkMetaSchema = z.object({
title: z.string(),
year: z.number().optional(),
poster: z.string().optional(),
type: z.enum(['movie', 'tv']),
type: z.enum(['movie', 'show']),
});
const bookmarkDataSchema = z.object({
@ -33,7 +33,6 @@ export default defineEventHandler(async (event) => {
return bookmarks.map(bookmark => ({
tmdbId: bookmark.tmdb_id,
userId: bookmark.user_id,
meta: bookmark.meta,
updatedAt: bookmark.updated_at
}));
@ -68,7 +67,6 @@ export default defineEventHandler(async (event) => {
results.push({
tmdbId: bookmark.tmdb_id,
userId: bookmark.user_id,
meta: bookmark.meta,
updatedAt: bookmark.updated_at
});
@ -111,7 +109,6 @@ export default defineEventHandler(async (event) => {
return {
tmdbId: bookmark.tmdb_id,
userId: bookmark.user_id,
meta: bookmark.meta,
updatedAt: bookmark.updated_at
};

View file

@ -1,3 +1,13 @@
import { useAuth } from '~/utils/auth';
import { z } from 'zod';
const bookmarkMetaSchema = z.object({
title: z.string(),
year: z.number(),
poster: z.string().optional(),
type: z.enum(['movie', 'show'])
});
export default defineEventHandler(async (event) => {
const userId = getRouterParam(event, 'id')
const tmdbId = getRouterParam(event, 'tmdbid')
@ -12,34 +22,35 @@ export default defineEventHandler(async (event) => {
}
if (event.method === "POST") {
const body = await readBody(event);
const bookmark = await prisma.bookmarks.create({
data: {
user_id: session.user,
tmdb_id: tmdbId,
meta: body.meta,
updated_at: new Date()
}
});
return {
tmdbId: bookmark.tmdb_id,
userId: bookmark.user_id,
meta: bookmark.meta,
updatedAt: bookmark.updated_at
};
} else if (event.method === "DELETE") {
await prisma.bookmarks.delete({
where: {
tmdb_id_user_id: {
const body = await readBody(event);
const validatedBody = bookmarkMetaSchema.parse(body);
const bookmark = await prisma.bookmarks.create({
data: {
user_id: session.user,
tmdb_id: tmdbId,
user_id: session.user
meta: validatedBody,
updated_at: new Date()
}
}
});
return { success: true, tmdbId };
}
});
return {
tmdbId: bookmark.tmdb_id,
meta: bookmark.meta,
updatedAt: bookmark.updated_at
};
} else if (event.method === "DELETE") {
await prisma.bookmarks.delete({
where: {
tmdb_id_user_id: {
tmdb_id: tmdbId,
user_id: session.user
}
}
});
return { success: true, tmdbId };
}
throw createError({
statusCode: 405,

View file

@ -4,16 +4,16 @@ import { randomUUID } from 'crypto';
const progressMetaSchema = z.object({
title: z.string(),
year: z.number().optional(),
poster: z.string().optional(),
type: z.enum(['movie', 'tv', 'show']),
year: z.number().optional()
type: z.enum(['movie', 'show'])
});
const progressItemSchema = z.object({
meta: progressMetaSchema,
tmdbId: z.string(),
duration: z.number().transform((n) => Math.round(n)),
watched: z.number().transform((n) => Math.round(n)),
duration: z.number().transform((n) => n.toString()),
watched: z.number().transform((n) => n.toString()),
seasonId: z.string().optional(),
episodeId: z.string().optional(),
seasonNumber: z.number().optional(),
@ -45,7 +45,7 @@ export default defineEventHandler(async (event) => {
if (session.user !== userId) {
throw createError({
statusCode: 403,
message: 'Cannot modify user other than yourself'
message: 'Cannot access other user information'
});
}
@ -57,15 +57,18 @@ export default defineEventHandler(async (event) => {
return items.map(item => ({
id: item.id,
tmdbId: item.tmdb_id,
userId: item.user_id,
seasonId: item.season_id,
episodeId: item.episode_id,
seasonNumber: item.season_number,
episodeNumber: item.episode_number,
episode: {
id: item.episode_id || null,
number: item.episode_number || null
},
season: {
id: item.season_id || null,
number: item.season_number || null
},
meta: item.meta,
duration: Number(item.duration),
watched: Number(item.watched),
updatedAt: item.updated_at
duration: item.duration.toString(),
watched: item.watched.toString(),
updatedAt: item.updated_at.toISOString()
}));
}

View file

@ -4,21 +4,21 @@ import { randomUUID } from 'crypto';
const progressMetaSchema = z.object({
title: z.string(),
poster: z.string().optional(),
type: z.enum(['movie', 'tv', 'show']),
year: z.number().optional()
type: z.enum(['movie', 'show']),
year: z.number(),
poster: z.string().optional()
});
const progressItemSchema = z.object({
meta: progressMetaSchema,
tmdbId: z.string(),
duration: z.number().transform((n) => Math.round(n)),
watched: z.number().transform((n) => Math.round(n)),
duration: z.number(),
watched: z.number(),
seasonId: z.string().optional(),
episodeId: z.string().optional(),
seasonNumber: z.number().optional(),
episodeNumber: z.number().optional(),
updatedAt: z.string().datetime({ offset: true }).optional(),
updatedAt: z.string().datetime({ offset: true }).optional()
});
// 13th July 2021 - movie-web epoch
@ -90,50 +90,61 @@ export default defineEventHandler(async (event) => {
}
}
for (const newItem of newItems) {
// Create new items
for (const item of newItems) {
itemsToUpsert.push({
id: randomUUID(),
tmdb_id: newItem.tmdbId,
tmdb_id: item.tmdbId,
user_id: userId,
season_id: newItem.seasonId || null,
episode_id: newItem.episodeId || null,
season_number: newItem.seasonNumber || null,
episode_number: newItem.episodeNumber || null,
duration: BigInt(newItem.duration),
watched: BigInt(newItem.watched),
meta: newItem.meta,
updated_at: defaultAndCoerceDateTime(newItem.updatedAt)
season_id: item.seasonId || null,
episode_id: item.episodeId || null,
season_number: item.seasonNumber || null,
episode_number: item.episodeNumber || null,
duration: BigInt(item.duration),
watched: BigInt(item.watched),
meta: item.meta,
updated_at: defaultAndCoerceDateTime(item.updatedAt)
});
}
const result = await prisma.$transaction(
itemsToUpsert.map(item =>
prisma.progress_items.upsert({
where: {
id: item.id
},
update: {
watched: item.watched,
duration: item.duration,
meta: item.meta,
updated_at: item.updated_at
},
create: item
})
)
);
// Upsert all items
const results = [];
for (const item of itemsToUpsert) {
const result = await prisma.progress_items.upsert({
where: {
tmdb_id_user_id_season_id_episode_id: {
tmdb_id: item.tmdb_id,
user_id: item.user_id,
season_id: item.season_id,
episode_id: item.episode_id
}
},
create: item,
update: {
duration: item.duration,
watched: item.watched,
meta: item.meta,
updated_at: item.updated_at
}
});
results.push({
id: result.id,
tmdbId: result.tmdb_id,
episode: {
id: result.episode_id || null,
number: result.episode_number || null
},
season: {
id: result.season_id || null,
number: result.season_number || null
},
meta: result.meta,
duration: result.duration.toString(),
watched: result.watched.toString(),
updatedAt: result.updated_at.toISOString()
});
}
return result.map(item => ({
id: item.id,
tmdbId: item.tmdb_id,
userId: item.user_id,
seasonId: item.season_id,
episodeId: item.episode_id,
seasonNumber: item.season_number,
episodeNumber: item.episode_number,
meta: item.meta,
duration: Number(item.duration),
watched: Number(item.watched),
updatedAt: item.updated_at
}));
return results;
});

View file

@ -18,12 +18,10 @@ export default defineEventHandler(async (event) => {
return sessions.map(s => ({
id: s.id,
user: s.user,
createdAt: s.created_at,
accessedAt: s.accessed_at,
expiresAt: s.expires_at,
userId: s.user,
createdAt: s.created_at.toISOString(),
accessedAt: s.accessed_at.toISOString(),
device: s.device,
userAgent: s.user_agent,
current: s.id === session.id
userAgent: s.user_agent
}));
});

View file

@ -2,12 +2,12 @@ import { useAuth } from '~/utils/auth';
import { z } from 'zod';
const userSettingsSchema = z.object({
application_theme: z.string().optional(),
application_language: z.string().optional(),
default_subtitle_language: z.string().optional(),
proxy_urls: z.array(z.string()).optional(),
trakt_key: z.string().optional(),
febbox_key: z.string().optional()
applicationTheme: z.string().nullable().optional(),
applicationLanguage: z.string(),
defaultSubtitleLanguage: z.string().nullable().optional(),
proxyUrls: z.array(z.string()).nullable().optional(),
traktKey: z.string().nullable().optional(),
febboxKey: z.string().nullable().optional()
});
export default defineEventHandler(async (event) => {
@ -22,46 +22,60 @@ export default defineEventHandler(async (event) => {
});
}
if (event.method === 'GET') {
const settings = await prisma.user_settings.findUnique({
where: { id: userId }
});
return {
id: userId,
applicationTheme: settings?.application_theme || null,
applicationLanguage: settings?.application_language || 'en',
defaultSubtitleLanguage: settings?.default_subtitle_language || null,
proxyUrls: settings?.proxy_urls || null,
traktKey: settings?.trakt_key || null,
febboxKey: settings?.febbox_key || null
};
}
if (event.method === 'PUT') {
try {
const body = await readBody(event);
const validatedSettings = userSettingsSchema.parse(body);
const validatedBody = userSettingsSchema.parse(body);
const existingSettings = await prisma.user_settings.findUnique({
where: { id: userId }
const data = {
application_theme: validatedBody.applicationTheme,
application_language: validatedBody.applicationLanguage,
default_subtitle_language: validatedBody.defaultSubtitleLanguage ?? null,
proxy_urls: validatedBody.proxyUrls ?? null,
trakt_key: validatedBody.traktKey ?? null,
febbox_key: validatedBody.febboxKey ?? null
};
const settings = await prisma.user_settings.upsert({
where: { id: userId },
update: data,
create: {
id: userId,
...data
}
});
let settings;
if (existingSettings) {
settings = await prisma.user_settings.update({
where: { id: userId },
data: validatedSettings
});
} else {
settings = await prisma.user_settings.create({
data: {
id: userId,
...validatedSettings
}
});
}
return {
settings: {
applicationTheme: settings.application_theme,
applicationLanguage: settings.application_language,
defaultSubtitleLanguage: settings.default_subtitle_language,
proxyUrls: settings.proxy_urls,
traktKey: settings.trakt_key,
febboxKey: settings.febbox_key
}
id: userId,
applicationTheme: settings.application_theme,
applicationLanguage: settings.application_language,
defaultSubtitleLanguage: settings.default_subtitle_language,
proxyUrls: settings.proxy_urls,
traktKey: settings.trakt_key,
febboxKey: settings.febbox_key
};
} catch (error) {
if (error instanceof z.ZodError) {
throw createError({
statusCode: 400,
message: 'Invalid settings data'
message: 'Invalid settings data',
cause: error.errors
});
}
@ -70,34 +84,6 @@ export default defineEventHandler(async (event) => {
message: 'Failed to update settings'
});
}
} else if (event.method === 'GET') {
const settings = await prisma.user_settings.findUnique({
where: { id: userId }
});
if (!settings) {
return {
settings: {
applicationTheme: null,
applicationLanguage: null,
defaultSubtitleLanguage: null,
proxyUrls: [],
traktKey: null,
febboxKey: null
}
};
}
return {
settings: {
applicationTheme: settings.application_theme,
applicationLanguage: settings.application_language,
defaultSubtitleLanguage: settings.default_subtitle_language,
proxyUrls: settings.proxy_urls,
traktKey: settings.trakt_key,
febboxKey: settings.febbox_key
}
};
}
throw createError({