Fix library repair failing on playback session foreign keys.
Delete stale playback sessions before removing unavailable or duplicate media file rows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d044106f77
commit
7c808e9167
1 changed files with 24 additions and 7 deletions
|
|
@ -910,11 +910,7 @@ export class MetadataService {
|
||||||
const seriesMerged = await this.mergeAllDuplicateSeries();
|
const seriesMerged = await this.mergeAllDuplicateSeries();
|
||||||
|
|
||||||
// Unavailable rows left after the /media/movies → /mnt/user migration
|
// Unavailable rows left after the /media/movies → /mnt/user migration
|
||||||
const staleFilesRemoved = (
|
const staleFilesRemoved = await this.deleteUnavailableMediaFiles();
|
||||||
await prisma.mediaFile.deleteMany({
|
|
||||||
where: { available: false },
|
|
||||||
})
|
|
||||||
).count;
|
|
||||||
|
|
||||||
const duplicateFilesRemoved = await this.removeDuplicateMediaFiles();
|
const duplicateFilesRemoved = await this.removeDuplicateMediaFiles();
|
||||||
|
|
||||||
|
|
@ -1135,8 +1131,29 @@ export class MetadataService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toDelete.length === 0) return 0;
|
if (toDelete.length === 0) return 0;
|
||||||
const result = await prisma.mediaFile.deleteMany({ where: { id: { in: toDelete } } });
|
return this.deleteMediaFilesSafely(toDelete);
|
||||||
return result.count;
|
}
|
||||||
|
|
||||||
|
/** Remove playback sessions first — FK blocks direct media_file deletes. */
|
||||||
|
private async deleteMediaFilesSafely(ids: string[]): Promise<number> {
|
||||||
|
if (ids.length === 0) return 0;
|
||||||
|
const chunkSize = 500;
|
||||||
|
let deleted = 0;
|
||||||
|
for (let i = 0; i < ids.length; i += chunkSize) {
|
||||||
|
const chunk = ids.slice(i, i + chunkSize);
|
||||||
|
await prisma.playbackSession.deleteMany({ where: { mediaFileId: { in: chunk } } });
|
||||||
|
const result = await prisma.mediaFile.deleteMany({ where: { id: { in: chunk } } });
|
||||||
|
deleted += result.count;
|
||||||
|
}
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async deleteUnavailableMediaFiles(): Promise<number> {
|
||||||
|
const stale = await prisma.mediaFile.findMany({
|
||||||
|
where: { available: false },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
return this.deleteMediaFilesSafely(stale.map((f) => f.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Admin: search TMDB by title (or resolve a single IMDb id). */
|
/** Admin: search TMDB by title (or resolve a single IMDb id). */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue