mirror of
https://github.com/p-stream/backend.git
synced 2026-03-11 17:55:35 +00:00
parent
950c1e051a
commit
2e27016e81
7 changed files with 156 additions and 163 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,4 +7,3 @@ dist
|
||||||
.env
|
.env
|
||||||
.vscode
|
.vscode
|
||||||
.metrics.json
|
.metrics.json
|
||||||
.metrics.json
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ const bookmarkMetaSchema = z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
year: z.number().optional(),
|
year: z.number().optional(),
|
||||||
poster: z.string().optional(),
|
poster: z.string().optional(),
|
||||||
type: z.enum(['movie', 'show']),
|
type: z.enum(['movie', 'tv']),
|
||||||
});
|
});
|
||||||
|
|
||||||
const bookmarkDataSchema = z.object({
|
const bookmarkDataSchema = z.object({
|
||||||
|
|
@ -33,6 +33,7 @@ export default defineEventHandler(async (event) => {
|
||||||
|
|
||||||
return bookmarks.map(bookmark => ({
|
return bookmarks.map(bookmark => ({
|
||||||
tmdbId: bookmark.tmdb_id,
|
tmdbId: bookmark.tmdb_id,
|
||||||
|
userId: bookmark.user_id,
|
||||||
meta: bookmark.meta,
|
meta: bookmark.meta,
|
||||||
updatedAt: bookmark.updated_at
|
updatedAt: bookmark.updated_at
|
||||||
}));
|
}));
|
||||||
|
|
@ -67,6 +68,7 @@ export default defineEventHandler(async (event) => {
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
tmdbId: bookmark.tmdb_id,
|
tmdbId: bookmark.tmdb_id,
|
||||||
|
userId: bookmark.user_id,
|
||||||
meta: bookmark.meta,
|
meta: bookmark.meta,
|
||||||
updatedAt: bookmark.updated_at
|
updatedAt: bookmark.updated_at
|
||||||
});
|
});
|
||||||
|
|
@ -109,6 +111,7 @@ export default defineEventHandler(async (event) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tmdbId: bookmark.tmdb_id,
|
tmdbId: bookmark.tmdb_id,
|
||||||
|
userId: bookmark.user_id,
|
||||||
meta: bookmark.meta,
|
meta: bookmark.meta,
|
||||||
updatedAt: bookmark.updated_at
|
updatedAt: bookmark.updated_at
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,3 @@
|
||||||
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) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const userId = getRouterParam(event, 'id')
|
const userId = getRouterParam(event, 'id')
|
||||||
const tmdbId = getRouterParam(event, 'tmdbid')
|
const tmdbId = getRouterParam(event, 'tmdbid')
|
||||||
|
|
@ -22,35 +12,34 @@ export default defineEventHandler(async (event) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.method === "POST") {
|
if (event.method === "POST") {
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
const validatedBody = bookmarkMetaSchema.parse(body);
|
const bookmark = await prisma.bookmarks.create({
|
||||||
|
data: {
|
||||||
const bookmark = await prisma.bookmarks.create({
|
user_id: session.user,
|
||||||
data: {
|
tmdb_id: tmdbId,
|
||||||
user_id: session.user,
|
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: {
|
||||||
tmdb_id: tmdbId,
|
tmdb_id: tmdbId,
|
||||||
meta: validatedBody,
|
user_id: session.user
|
||||||
updated_at: new Date()
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
return {
|
|
||||||
tmdbId: bookmark.tmdb_id,
|
return { success: true, tmdbId };
|
||||||
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({
|
throw createError({
|
||||||
statusCode: 405,
|
statusCode: 405,
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
const progressMetaSchema = z.object({
|
const progressMetaSchema = z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
year: z.number().optional(),
|
|
||||||
poster: z.string().optional(),
|
poster: z.string().optional(),
|
||||||
type: z.enum(['movie', 'show'])
|
type: z.enum(['movie', 'tv', 'show']),
|
||||||
|
year: z.number().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
const progressItemSchema = z.object({
|
const progressItemSchema = z.object({
|
||||||
meta: progressMetaSchema,
|
meta: progressMetaSchema,
|
||||||
tmdbId: z.string(),
|
tmdbId: z.string(),
|
||||||
duration: z.number().transform((n) => n.toString()),
|
duration: z.number().transform((n) => Math.round(n)),
|
||||||
watched: z.number().transform((n) => n.toString()),
|
watched: z.number().transform((n) => Math.round(n)),
|
||||||
seasonId: z.string().optional(),
|
seasonId: z.string().optional(),
|
||||||
episodeId: z.string().optional(),
|
episodeId: z.string().optional(),
|
||||||
seasonNumber: z.number().optional(),
|
seasonNumber: z.number().optional(),
|
||||||
|
|
@ -45,7 +45,7 @@ export default defineEventHandler(async (event) => {
|
||||||
if (session.user !== userId) {
|
if (session.user !== userId) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
message: 'Cannot access other user information'
|
message: 'Cannot modify user other than yourself'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,18 +57,15 @@ export default defineEventHandler(async (event) => {
|
||||||
return items.map(item => ({
|
return items.map(item => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
tmdbId: item.tmdb_id,
|
tmdbId: item.tmdb_id,
|
||||||
episode: {
|
userId: item.user_id,
|
||||||
id: item.episode_id || null,
|
seasonId: item.season_id,
|
||||||
number: item.episode_number || null
|
episodeId: item.episode_id,
|
||||||
},
|
seasonNumber: item.season_number,
|
||||||
season: {
|
episodeNumber: item.episode_number,
|
||||||
id: item.season_id || null,
|
|
||||||
number: item.season_number || null
|
|
||||||
},
|
|
||||||
meta: item.meta,
|
meta: item.meta,
|
||||||
duration: item.duration.toString(),
|
duration: Number(item.duration),
|
||||||
watched: item.watched.toString(),
|
watched: Number(item.watched),
|
||||||
updatedAt: item.updated_at.toISOString()
|
updatedAt: item.updated_at
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,21 @@ import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
const progressMetaSchema = z.object({
|
const progressMetaSchema = z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
type: z.enum(['movie', 'show']),
|
poster: z.string().optional(),
|
||||||
year: z.number(),
|
type: z.enum(['movie', 'tv', 'show']),
|
||||||
poster: z.string().optional()
|
year: z.number().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
const progressItemSchema = z.object({
|
const progressItemSchema = z.object({
|
||||||
meta: progressMetaSchema,
|
meta: progressMetaSchema,
|
||||||
tmdbId: z.string(),
|
tmdbId: z.string(),
|
||||||
duration: z.number(),
|
duration: z.number().transform((n) => Math.round(n)),
|
||||||
watched: z.number(),
|
watched: z.number().transform((n) => Math.round(n)),
|
||||||
seasonId: z.string().optional(),
|
seasonId: z.string().optional(),
|
||||||
episodeId: z.string().optional(),
|
episodeId: z.string().optional(),
|
||||||
seasonNumber: z.number().optional(),
|
seasonNumber: z.number().optional(),
|
||||||
episodeNumber: 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
|
// 13th July 2021 - movie-web epoch
|
||||||
|
|
@ -90,61 +90,50 @@ export default defineEventHandler(async (event) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new items
|
for (const newItem of newItems) {
|
||||||
for (const item of newItems) {
|
|
||||||
itemsToUpsert.push({
|
itemsToUpsert.push({
|
||||||
id: randomUUID(),
|
id: randomUUID(),
|
||||||
tmdb_id: item.tmdbId,
|
tmdb_id: newItem.tmdbId,
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
season_id: item.seasonId || null,
|
season_id: newItem.seasonId || null,
|
||||||
episode_id: item.episodeId || null,
|
episode_id: newItem.episodeId || null,
|
||||||
season_number: item.seasonNumber || null,
|
season_number: newItem.seasonNumber || null,
|
||||||
episode_number: item.episodeNumber || null,
|
episode_number: newItem.episodeNumber || null,
|
||||||
duration: BigInt(item.duration),
|
duration: BigInt(newItem.duration),
|
||||||
watched: BigInt(item.watched),
|
watched: BigInt(newItem.watched),
|
||||||
meta: item.meta,
|
meta: newItem.meta,
|
||||||
updated_at: defaultAndCoerceDateTime(item.updatedAt)
|
updated_at: defaultAndCoerceDateTime(newItem.updatedAt)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upsert all items
|
const result = await prisma.$transaction(
|
||||||
const results = [];
|
itemsToUpsert.map(item =>
|
||||||
for (const item of itemsToUpsert) {
|
prisma.progress_items.upsert({
|
||||||
const result = await prisma.progress_items.upsert({
|
where: {
|
||||||
where: {
|
id: item.id
|
||||||
tmdb_id_user_id_season_id_episode_id: {
|
},
|
||||||
tmdb_id: item.tmdb_id,
|
update: {
|
||||||
user_id: item.user_id,
|
watched: item.watched,
|
||||||
season_id: item.season_id,
|
duration: item.duration,
|
||||||
episode_id: item.episode_id
|
meta: item.meta,
|
||||||
}
|
updated_at: item.updated_at
|
||||||
},
|
},
|
||||||
create: item,
|
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 results;
|
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
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
@ -18,10 +18,12 @@ export default defineEventHandler(async (event) => {
|
||||||
|
|
||||||
return sessions.map(s => ({
|
return sessions.map(s => ({
|
||||||
id: s.id,
|
id: s.id,
|
||||||
userId: s.user,
|
user: s.user,
|
||||||
createdAt: s.created_at.toISOString(),
|
createdAt: s.created_at,
|
||||||
accessedAt: s.accessed_at.toISOString(),
|
accessedAt: s.accessed_at,
|
||||||
|
expiresAt: s.expires_at,
|
||||||
device: s.device,
|
device: s.device,
|
||||||
userAgent: s.user_agent
|
userAgent: s.user_agent,
|
||||||
|
current: s.id === session.id
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
@ -2,12 +2,12 @@ import { useAuth } from '~/utils/auth';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const userSettingsSchema = z.object({
|
const userSettingsSchema = z.object({
|
||||||
applicationTheme: z.string().nullable().optional(),
|
application_theme: z.string().optional(),
|
||||||
applicationLanguage: z.string(),
|
application_language: z.string().optional(),
|
||||||
defaultSubtitleLanguage: z.string().nullable().optional(),
|
default_subtitle_language: z.string().optional(),
|
||||||
proxyUrls: z.array(z.string()).nullable().optional(),
|
proxy_urls: z.array(z.string()).optional(),
|
||||||
traktKey: z.string().nullable().optional(),
|
trakt_key: z.string().optional(),
|
||||||
febboxKey: z.string().nullable().optional()
|
febbox_key: z.string().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
|
|
@ -22,60 +22,46 @@ 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') {
|
if (event.method === 'PUT') {
|
||||||
try {
|
try {
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
const validatedBody = userSettingsSchema.parse(body);
|
const validatedSettings = userSettingsSchema.parse(body);
|
||||||
|
|
||||||
const data = {
|
const existingSettings = await prisma.user_settings.findUnique({
|
||||||
application_theme: validatedBody.applicationTheme,
|
where: { id: userId }
|
||||||
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 {
|
return {
|
||||||
id: userId,
|
settings: {
|
||||||
applicationTheme: settings.application_theme,
|
applicationTheme: settings.application_theme,
|
||||||
applicationLanguage: settings.application_language,
|
applicationLanguage: settings.application_language,
|
||||||
defaultSubtitleLanguage: settings.default_subtitle_language,
|
defaultSubtitleLanguage: settings.default_subtitle_language,
|
||||||
proxyUrls: settings.proxy_urls,
|
proxyUrls: settings.proxy_urls,
|
||||||
traktKey: settings.trakt_key,
|
traktKey: settings.trakt_key,
|
||||||
febboxKey: settings.febbox_key
|
febboxKey: settings.febbox_key
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof z.ZodError) {
|
if (error instanceof z.ZodError) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
message: 'Invalid settings data',
|
message: 'Invalid settings data'
|
||||||
cause: error.errors
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,6 +70,34 @@ export default defineEventHandler(async (event) => {
|
||||||
message: 'Failed to update settings'
|
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({
|
throw createError({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue