Files
Musify/web-player/src/routes/(app)/albums/[id]/+page.server.ts
T

112 lines
3.7 KiB
TypeScript

import type { PageServerLoad, Actions } from './$types';
import { fail, redirect } from '@sveltejs/kit';
import {
apiFor,
authedAction,
failOnError,
formFile,
formString,
optionalUser,
unwrapOrError
} from '$lib/server/api';
import { toAlbum, toTrack } from '$lib/server/mappers';
import { ALBUM_TRACKS_PAGE_SIZE, LIBRARY_PICKER_PAGE_SIZE } from '$lib/config';
import { parseAlbumForm } from '$lib/server/albumForm';
import { uploadPresignedImage } from '$lib/server/upload';
export const load: PageServerLoad = async ({ params, locals, url, fetch, parent }) => {
const { allowAnonymousListening } = await parent();
const user = optionalUser(locals, url, allowAnonymousListening);
const api = apiFor({ fetch, locals });
const [albumRes, tracksRes, libraryRes] = await Promise.all([
api.GET('/albums/{id}', { params: { path: { id: params.id } } }),
api.GET('/albums/{albumId}/tracks', {
params: {
path: { albumId: params.id },
query: { pageNumber: 1, pageSize: ALBUM_TRACKS_PAGE_SIZE }
}
}),
user
? api.GET('/tracks/users/{userId}', {
params: {
path: { userId: user.sub },
query: { pageNumber: 1, pageSize: LIBRARY_PICKER_PAGE_SIZE }
}
})
: Promise.resolve(null)
]);
const album = toAlbum(unwrapOrError(albumRes, 'Álbum no encontrado.', 404));
const tracks = (tracksRes.data?.items ?? []).map(toTrack);
const inAlbum = new Set(tracks.map((track) => track.id));
const library = (libraryRes?.data?.items ?? [])
.filter((track) => !inAlbum.has(track.id))
.map(toTrack);
const isOwner = user !== null && String(album.ownerUserId) === user.sub;
return { album, tracks, library, isOwner, section: isOwner ? '/albums' : null };
};
export const actions: Actions = {
addTrack: authedAction(async ({ api, form, params }) => {
const trackId = formString(form, 'trackId');
if (!trackId) return fail(400, { message: 'Falta la canción.' });
const result = await api.POST('/albums/{albumId}/tracks/{trackId}', {
params: { path: { albumId: params.id, trackId } }
});
return failOnError(result, 'No se pudo añadir la canción.') ?? { added: true };
}),
removeTrack: authedAction(async ({ api, form, params }) => {
const trackId = formString(form, 'trackId');
if (!trackId) return fail(400, { message: 'Falta la canción.' });
const result = await api.DELETE('/albums/{albumId}/tracks/{trackId}', {
params: { path: { albumId: params.id, trackId } }
});
return failOnError(result, 'No se pudo quitar la canción.') ?? { removed: true };
}),
edit: authedAction(async ({ api, form, params }) => {
const parsed = parseAlbumForm(form);
if ('failMessage' in parsed) return fail(400, { message: parsed.failMessage });
let newPictureIntentId: string | null = null;
const cover = formFile(form, 'cover');
if (cover) {
const uploaded = await uploadPresignedImage(
(args) => api.POST('/albums/upload-picture', { body: args }),
cover
);
if ('failMessage' in uploaded) {
return fail(502, { message: uploaded.failMessage, detail: uploaded.detail });
}
newPictureIntentId = uploaded.intentId;
}
const result = await api.PUT('/albums/{albumId}', {
params: { path: { albumId: params.id } },
body: {
newTitle: parsed.body.title,
newDescription: parsed.body.description,
newReleaseYear: parsed.body.releaseYear,
newPictureIntentId
}
});
return failOnError(result, 'No se pudo actualizar el álbum.') ?? { edited: true };
}),
delete: authedAction(async ({ api, params }) => {
const result = await api.DELETE('/albums/{albumId}', {
params: { path: { albumId: params.id } }
});
const failure = failOnError(result, 'No se pudo eliminar el álbum.');
if (failure) return failure;
redirect(303, '/albums');
})
};