fix: structure thumbnails in subfolders
This commit is contained in:
@@ -203,12 +203,22 @@ export class MediaEngine extends EventEmitter {
|
|||||||
return path.join(this.getInternalDir(), 'thumbnails');
|
return path.join(this.getInternalDir(), 'thumbnails');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the thumbnail subdirectory for a media item.
|
||||||
|
* Uses first 2 characters of the media ID for organization.
|
||||||
|
* Returns: thumbnails/xx/ where xx is the first 2 chars of mediaId
|
||||||
|
*/
|
||||||
|
private getThumbnailSubDir(mediaId: string): string {
|
||||||
|
const prefix = mediaId.substring(0, 2).toLowerCase();
|
||||||
|
return path.join(this.getThumbnailsDir(), prefix);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate thumbnails for an image file
|
* Generate thumbnails for an image file
|
||||||
*/
|
*/
|
||||||
async generateThumbnails(mediaId: string, sourcePath: string): Promise<Record<ThumbnailSize, string>> {
|
async generateThumbnails(mediaId: string, sourcePath: string): Promise<Record<ThumbnailSize, string>> {
|
||||||
const thumbnailsDir = this.getThumbnailsDir();
|
const thumbnailSubDir = this.getThumbnailSubDir(mediaId);
|
||||||
await fs.mkdir(thumbnailsDir, { recursive: true });
|
await fs.mkdir(thumbnailSubDir, { recursive: true });
|
||||||
|
|
||||||
const thumbnails: Record<ThumbnailSize, string> = {} as Record<ThumbnailSize, string>;
|
const thumbnails: Record<ThumbnailSize, string> = {} as Record<ThumbnailSize, string>;
|
||||||
|
|
||||||
@@ -217,7 +227,7 @@ export class MediaEngine extends EventEmitter {
|
|||||||
const sharp = (await import('sharp')).default;
|
const sharp = (await import('sharp')).default;
|
||||||
|
|
||||||
for (const [size, dimensions] of Object.entries(THUMBNAIL_SIZES) as [ThumbnailSize, { width: number; height: number }][]) {
|
for (const [size, dimensions] of Object.entries(THUMBNAIL_SIZES) as [ThumbnailSize, { width: number; height: number }][]) {
|
||||||
const thumbnailPath = path.join(thumbnailsDir, `${mediaId}-${size}.webp`);
|
const thumbnailPath = path.join(thumbnailSubDir, `${mediaId}-${size}.webp`);
|
||||||
|
|
||||||
await sharp(sourcePath)
|
await sharp(sourcePath)
|
||||||
.resize(dimensions.width, dimensions.height, {
|
.resize(dimensions.width, dimensions.height, {
|
||||||
@@ -243,7 +253,7 @@ export class MediaEngine extends EventEmitter {
|
|||||||
* Get existing thumbnail paths for a media item
|
* Get existing thumbnail paths for a media item
|
||||||
*/
|
*/
|
||||||
async getThumbnailPaths(mediaId: string): Promise<Record<ThumbnailSize, string | null>> {
|
async getThumbnailPaths(mediaId: string): Promise<Record<ThumbnailSize, string | null>> {
|
||||||
const thumbnailsDir = this.getThumbnailsDir();
|
const thumbnailSubDir = this.getThumbnailSubDir(mediaId);
|
||||||
const result: Record<ThumbnailSize, string | null> = {
|
const result: Record<ThumbnailSize, string | null> = {
|
||||||
small: null,
|
small: null,
|
||||||
medium: null,
|
medium: null,
|
||||||
@@ -251,7 +261,7 @@ export class MediaEngine extends EventEmitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const size of Object.keys(THUMBNAIL_SIZES) as ThumbnailSize[]) {
|
for (const size of Object.keys(THUMBNAIL_SIZES) as ThumbnailSize[]) {
|
||||||
const thumbnailPath = path.join(thumbnailsDir, `${mediaId}-${size}.webp`);
|
const thumbnailPath = path.join(thumbnailSubDir, `${mediaId}-${size}.webp`);
|
||||||
try {
|
try {
|
||||||
await fs.access(thumbnailPath);
|
await fs.access(thumbnailPath);
|
||||||
result[size] = thumbnailPath;
|
result[size] = thumbnailPath;
|
||||||
@@ -267,8 +277,8 @@ export class MediaEngine extends EventEmitter {
|
|||||||
* Get thumbnail as base64 data URL for renderer
|
* Get thumbnail as base64 data URL for renderer
|
||||||
*/
|
*/
|
||||||
async getThumbnailDataUrl(mediaId: string, size: ThumbnailSize = 'small'): Promise<string | null> {
|
async getThumbnailDataUrl(mediaId: string, size: ThumbnailSize = 'small'): Promise<string | null> {
|
||||||
const thumbnailsDir = this.getThumbnailsDir();
|
const thumbnailSubDir = this.getThumbnailSubDir(mediaId);
|
||||||
const thumbnailPath = path.join(thumbnailsDir, `${mediaId}-${size}.webp`);
|
const thumbnailPath = path.join(thumbnailSubDir, `${mediaId}-${size}.webp`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await fs.readFile(thumbnailPath);
|
const data = await fs.readFile(thumbnailPath);
|
||||||
@@ -282,10 +292,10 @@ export class MediaEngine extends EventEmitter {
|
|||||||
* Delete thumbnails for a media item
|
* Delete thumbnails for a media item
|
||||||
*/
|
*/
|
||||||
private async deleteThumbnails(mediaId: string): Promise<void> {
|
private async deleteThumbnails(mediaId: string): Promise<void> {
|
||||||
const thumbnailsDir = this.getThumbnailsDir();
|
const thumbnailSubDir = this.getThumbnailSubDir(mediaId);
|
||||||
|
|
||||||
for (const size of Object.keys(THUMBNAIL_SIZES) as ThumbnailSize[]) {
|
for (const size of Object.keys(THUMBNAIL_SIZES) as ThumbnailSize[]) {
|
||||||
const thumbnailPath = path.join(thumbnailsDir, `${mediaId}-${size}.webp`);
|
const thumbnailPath = path.join(thumbnailSubDir, `${mediaId}-${size}.webp`);
|
||||||
try {
|
try {
|
||||||
await fs.unlink(thumbnailPath);
|
await fs.unlink(thumbnailPath);
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user