Optimized the progress/[tmdb_id]/ endpoint to be less verbose

This commit is contained in:
FifthWit 2025-10-25 13:06:07 -05:00
parent 0e45ff1b70
commit e3a59bc3b2

View file

@ -12,8 +12,8 @@ const progressMetaSchema = z.object({
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(Math.round),
watched: z.number().transform(Math.round),
seasonId: z.string().optional(),
episodeId: z.string().optional(),
seasonNumber: z.number().optional(),
@ -24,139 +24,97 @@ const progressItemSchema = z.object({
// 13th July 2021 - movie-web epoch
const minEpoch = 1626134400000;
function defaultAndCoerceDateTime(dateTime: string | undefined) {
const coerceDateTime = (dateTime?: string) => {
const epoch = dateTime ? new Date(dateTime).getTime() : Date.now();
const clampedEpoch = Math.max(minEpoch, Math.min(epoch, Date.now()));
return new Date(clampedEpoch);
}
return new Date(Math.max(minEpoch, Math.min(epoch, Date.now())));
};
export default defineEventHandler(async event => {
const userId = event.context.params?.id;
const tmdbId = event.context.params?.tmdb_id;
const normalizeIds = (metaType: string, seasonId?: string, episodeId?: string) => ({
seasonId: metaType === 'movie' ? '\n' : seasonId || null,
episodeId: metaType === 'movie' ? '\n' : episodeId || null,
});
const formatProgressItem = (item: any) => ({
id: item.id,
tmdbId: item.tmdb_id,
userId: item.user_id,
seasonId: item.season_id === '\n' ? null : item.season_id,
episodeId: item.episode_id === '\n' ? null : 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,
});
export default defineEventHandler(async (event) => {
const { id: userId, tmdb_id: tmdbId } = event.context.params!;
const method = event.method;
const session = await useAuth().getCurrentSession();
if (session.user !== userId) {
throw createError({
statusCode: 403,
message: 'Different userId than authenticated session',
});
throw createError({ statusCode: 403, message: 'Unauthorized' });
}
if (method === 'PUT') {
const body = await readBody(event);
const validatedBody = progressItemSchema.parse(body);
let parsedBody;
try {
parsedBody = progressItemSchema.parse(body);
} catch (error) {
throw createError({ statusCode: 400, message: error.message });
}
const { meta, tmdbId: duration, watched, seasonId, episodeId, seasonNumber, episodeNumber, updatedAt } = parsedBody;
const now = defaultAndCoerceDateTime(validatedBody.updatedAt);
const now = coerceDateTime(updatedAt);
const { seasonId: normSeasonId, episodeId: normEpisodeId } = normalizeIds(meta.type, seasonId, episodeId);
const isMovie = validatedBody.meta.type === 'movie';
const seasonId = isMovie ? '\n' : validatedBody.seasonId || null;
const episodeId = isMovie ? '\n' : validatedBody.episodeId || null;
const existingItem = await prisma.progress_items.findUnique({
where: {
tmdb_id_user_id_season_id_episode_id: {
tmdb_id: tmdbId,
user_id: userId,
season_id: seasonId,
episode_id: episodeId,
},
},
const existing = await prisma.progress_items.findUnique({
where: { tmdb_id_user_id_season_id_episode_id: { tmdb_id: tmdbId, user_id: userId, season_id: normSeasonId, episode_id: normEpisodeId } },
});
let progressItem;
if (existingItem) {
progressItem = await prisma.progress_items.update({
where: {
id: existingItem.id,
},
data: {
duration: BigInt(validatedBody.duration),
watched: BigInt(validatedBody.watched),
meta: validatedBody.meta,
updated_at: now,
},
});
} else {
progressItem = await prisma.progress_items.create({
data: {
id: randomUUID(),
tmdb_id: tmdbId,
user_id: userId,
season_id: seasonId,
episode_id: episodeId,
season_number: validatedBody.seasonNumber || null,
episode_number: validatedBody.episodeNumber || null,
duration: BigInt(validatedBody.duration),
watched: BigInt(validatedBody.watched),
meta: validatedBody.meta,
updated_at: now,
},
});
}
return {
id: progressItem.id,
tmdbId: progressItem.tmdb_id,
userId: progressItem.user_id,
seasonId: progressItem.season_id === '\n' ? null : progressItem.season_id,
episodeId: progressItem.episode_id === '\n' ? null : progressItem.episode_id,
seasonNumber: progressItem.season_number,
episodeNumber: progressItem.episode_number,
meta: progressItem.meta,
duration: Number(progressItem.duration),
watched: Number(progressItem.watched),
updatedAt: progressItem.updated_at,
};
} else if (method === 'DELETE') {
const body = await readBody(event).catch(() => ({}));
const whereClause: any = {
user_id: userId,
tmdb_id: tmdbId,
const data = {
duration: BigInt(duration),
watched: BigInt(watched),
meta,
updated_at: now,
};
if (body.seasonId) {
whereClause.season_id = body.seasonId;
} else if (body.meta?.type === 'movie') {
whereClause.season_id = '\n';
}
const progressItem = existing
? await prisma.progress_items.update({ where: { id: existing.id }, data })
: await prisma.progress_items.create({
data: {
id: randomUUID(),
tmdb_id: tmdbId,
user_id: userId,
season_id: normSeasonId,
episode_id: normEpisodeId,
season_number: seasonNumber || null,
episode_number: episodeNumber || null,
...data,
},
});
if (body.episodeId) {
whereClause.episode_id = body.episodeId;
} else if (body.meta?.type === 'movie') {
whereClause.episode_id = '\n';
}
const itemsToDelete = await prisma.progress_items.findMany({
where: whereClause,
});
if (itemsToDelete.length === 0) {
return {
count: 0,
tmdbId,
episodeId: body.episodeId,
seasonId: body.seasonId,
};
}
await prisma.progress_items.deleteMany({
where: whereClause,
});
return {
count: itemsToDelete.length,
tmdbId,
episodeId: body.episodeId,
seasonId: body.seasonId,
};
return formatProgressItem(progressItem);
}
throw createError({
statusCode: 405,
message: 'Method not allowed',
});
if (method === 'DELETE') {
const body = await readBody(event).catch(() => ({}));
const where: any = { user_id: userId, tmdb_id: tmdbId };
if (body.seasonId) where.season_id = body.seasonId;
else if (body.meta?.type === 'movie') where.season_id = '\n';
if (body.episodeId) where.episode_id = body.episodeId;
else if (body.meta?.type === 'movie') where.episode_id = '\n';
const items = await prisma.progress_items.findMany({ where });
if (items.length === 0) return { count: 0, tmdbId, episodeId: body.episodeId, seasonId: body.seasonId };
await prisma.progress_items.deleteMany({ where });
return { count: items.length, tmdbId, episodeId: body.episodeId, seasonId: body.seasonId };
}
throw createError({ statusCode: 405, message: 'Method not allowed' });
});