project-standalo-sonic-cloud/app/api/share/[token]/route.ts

105 lines
3.4 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import type { ResolveShareResponse, SongShareContent, PlaylistShareContent, AlbumShareContent, ApiError, ShareType } from '@/types/api-types';
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ token: string }> }
) {
try {
const { token } = await params;
const share = await prisma.share.findUnique({
where: { token },
});
if (!share) {
return NextResponse.json<ApiError>(
{ error: 'Share not found' },
{ status: 404 }
);
}
let content: SongShareContent | PlaylistShareContent | AlbumShareContent;
if (share.type === 'SONG') {
const song = await prisma.song.findUnique({
where: { id: share.targetId },
include: { artist: true },
});
if (!song) {
return NextResponse.json<ApiError>({ error: 'Content not found' }, { status: 404 });
}
content = {
id: song.id,
title: song.title,
duration: song.duration,
coverArtUrl: song.coverUrl || '',
fileUrl: song.audioUrl,
artist: { id: song.artist.id, stage_name: song.artist.name },
};
} else if (share.type === 'PLAYLIST') {
const playlist = await prisma.playlist.findUnique({
where: { id: share.targetId },
include: {
user: true,
songs: { include: { song: { include: { artist: true } } } }
},
});
if (!playlist) {
return NextResponse.json<ApiError>({ error: 'Content not found' }, { status: 404 });
}
content = {
id: playlist.id,
name: playlist.title,
description: playlist.description || '',
coverImageUrl: playlist.coverUrl || '',
songCount: playlist.songs.length,
curator: { id: playlist.user.id, name: playlist.user.displayName || playlist.user.username },
songs: playlist.songs.map(ps => ({
id: ps.song.id,
title: ps.song.title,
duration: ps.song.duration,
cover_art_url: ps.song.coverUrl || '',
play_count: ps.song.playCount,
})),
};
} else {
const album = await prisma.album.findUnique({
where: { id: share.targetId },
include: { artist: true, songs: true },
});
if (!album) {
return NextResponse.json<ApiError>({ error: 'Content not found' }, { status: 404 });
}
content = {
id: album.id,
title: album.title,
description: album.description || '',
coverArtUrl: album.coverUrl || '',
releaseDate: album.releaseDate?.toISOString() || '',
artist: { id: album.artist.id, stage_name: album.artist.name },
songs: album.songs.map(s => ({
id: s.id,
title: s.title,
duration: s.duration,
cover_art_url: s.coverUrl || '',
play_count: s.playCount,
})),
};
}
const response: ResolveShareResponse = {
type: share.type as ShareType,
targetId: share.targetId,
content,
shareUrl: `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/s/${token}`,
};
return NextResponse.json(response);
} catch (error) {
console.error('Resolve share error:', error);
return NextResponse.json<ApiError>({ error: 'Failed to resolve share' }, { status: 500 });
}
}