Merge pull request #32 from eehkay/fix/audio-asset-proxy-and-gc-thumbnails

fix: audio asset playback and orphan-cleanup thumbnail deletion
This commit is contained in:
Yusuf İpek
2026-07-22 19:50:28 +03:00
committed by GitHub
2 changed files with 37 additions and 22 deletions
+32 -20
View File
@@ -39,38 +39,50 @@ export async function GET(
// Parallelize the DB lookup and session check to narrow the timing delta // Parallelize the DB lookup and session check to narrow the timing delta
// between "asset not found" and "asset found, access denied" responses. // between "asset not found" and "asset found, access denied" responses.
const voiceUrl = `/api/upload/audio/${filename}`; const voiceUrl = `/api/upload/audio/${filename}`;
const [comment, session] = await Promise.all([ const projectSelect = {
db.comment.findFirst({ id: true,
ownerId: true,
workspaceId: true,
visibility: true,
} as const;
const videoSelect = {
id: true,
projectId: true,
project: { select: projectSelect },
} as const;
const [comments, videoAssets, session] = await Promise.all([
db.comment.findMany({
where: { voiceUrl }, where: { voiceUrl },
take: 2,
select: { select: {
version: { version: {
select: { select: { video: { select: videoSelect } },
video: {
select: {
id: true,
projectId: true,
project: {
select: {
id: true,
ownerId: true,
workspaceId: true,
visibility: true,
},
},
},
},
},
}, },
}, },
}), }),
db.videoAsset.findMany({
where: { sourceUrl: voiceUrl },
take: 2,
select: { video: { select: videoSelect } },
}),
auth(), auth(),
]); ]);
if (!comment) { const uniqueVideos = new Map<string, (typeof videoAssets)[number]['video']>();
comments.forEach((comment) => {
if (comment.version?.video) uniqueVideos.set(comment.version.video.id, comment.version.video);
});
videoAssets.forEach((videoAsset) => uniqueVideos.set(videoAsset.video.id, videoAsset.video));
if (uniqueVideos.size > 1) {
return apiErrors.forbidden('Access denied');
}
const video = uniqueVideos.values().next().value ?? null;
if (!video) {
return apiErrors.forbidden('Access denied'); return apiErrors.forbidden('Access denied');
} }
const { video } = comment.version;
const access = await checkProjectAccess(video.project, session?.user?.id); const access = await checkProjectAccess(video.project, session?.user?.id);
if (!access.hasAccess) { if (!access.hasAccess) {
+5 -2
View File
@@ -119,8 +119,10 @@ async function findReferencedUrls(urls: string[]): Promise<Set<string>> {
}) })
: Promise.resolve([] as Array<{ url: string }>), : Promise.resolve([] as Array<{ url: string }>),
db.videoAsset.findMany({ db.videoAsset.findMany({
where: { sourceUrl: { in: group } }, where: {
select: { sourceUrl: true }, OR: [{ sourceUrl: { in: group } }, { thumbnailUrl: { in: group } }],
},
select: { sourceUrl: true, thumbnailUrl: true },
}), }),
db.videoVersion.findMany({ db.videoVersion.findMany({
where: { where: {
@@ -142,6 +144,7 @@ async function findReferencedUrls(urls: string[]): Promise<Set<string>> {
} }
for (const row of assetRows) { for (const row of assetRows) {
if (row.sourceUrl) referenced.add(row.sourceUrl); if (row.sourceUrl) referenced.add(row.sourceUrl);
if (row.thumbnailUrl) referenced.add(row.thumbnailUrl);
} }
for (const row of versionRows) { for (const row of versionRows) {
if (row.originalUrl) referenced.add(row.originalUrl); if (row.originalUrl) referenced.add(row.originalUrl);