mirror of
https://github.com/immich-app/immich.git
synced 2025-01-16 00:36:47 +01:00
fix(server): Allow commas and braces in import paths (#13259)
fix commas and braces in paths
This commit is contained in:
parent
94d213bbb9
commit
5b00bc499f
2 changed files with 65 additions and 6 deletions
|
@ -347,6 +347,62 @@ describe('/libraries', () => {
|
|||
expect(assets.items.find((asset) => asset.originalPath.includes('directoryB'))).toBeDefined();
|
||||
});
|
||||
|
||||
it('should scan multiple import paths with commas', async () => {
|
||||
// https://github.com/immich-app/immich/issues/10699
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
importPaths: [`${testAssetDirInternal}/temp/folder, a`, `${testAssetDirInternal}/temp/folder, b`],
|
||||
});
|
||||
|
||||
utils.createImageFile(`${testAssetDir}/temp/folder, a/assetA.png`);
|
||||
utils.createImageFile(`${testAssetDir}/temp/folder, b/assetB.png`);
|
||||
|
||||
const { status } = await request(app)
|
||||
.post(`/libraries/${library.id}/scan`)
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send();
|
||||
expect(status).toBe(204);
|
||||
|
||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
||||
|
||||
const { assets } = await utils.metadataSearch(admin.accessToken, { libraryId: library.id });
|
||||
|
||||
expect(assets.count).toBe(2);
|
||||
expect(assets.items.find((asset) => asset.originalPath.includes('folder, a'))).toBeDefined();
|
||||
expect(assets.items.find((asset) => asset.originalPath.includes('folder, b'))).toBeDefined();
|
||||
|
||||
utils.removeImageFile(`${testAssetDir}/temp/folder, a/assetA.png`);
|
||||
utils.removeImageFile(`${testAssetDir}/temp/folder, b/assetB.png`);
|
||||
});
|
||||
|
||||
it('should scan multiple import paths with braces', async () => {
|
||||
// https://github.com/immich-app/immich/issues/10699
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
importPaths: [`${testAssetDirInternal}/temp/folder{ a`, `${testAssetDirInternal}/temp/folder} b`],
|
||||
});
|
||||
|
||||
utils.createImageFile(`${testAssetDir}/temp/folder{ a/assetA.png`);
|
||||
utils.createImageFile(`${testAssetDir}/temp/folder} b/assetB.png`);
|
||||
|
||||
const { status } = await request(app)
|
||||
.post(`/libraries/${library.id}/scan`)
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||
.send();
|
||||
expect(status).toBe(204);
|
||||
|
||||
await utils.waitForQueueFinish(admin.accessToken, 'library');
|
||||
|
||||
const { assets } = await utils.metadataSearch(admin.accessToken, { libraryId: library.id });
|
||||
|
||||
expect(assets.count).toBe(2);
|
||||
expect(assets.items.find((asset) => asset.originalPath.includes('folder{ a'))).toBeDefined();
|
||||
expect(assets.items.find((asset) => asset.originalPath.includes('folder} b'))).toBeDefined();
|
||||
|
||||
utils.removeImageFile(`${testAssetDir}/temp/folder{ a/assetA.png`);
|
||||
utils.removeImageFile(`${testAssetDir}/temp/folder} b/assetB.png`);
|
||||
});
|
||||
|
||||
it('should reimport a modified file', async () => {
|
||||
const library = await utils.createLibrary(admin.accessToken, {
|
||||
ownerId: admin.userId,
|
||||
|
|
|
@ -156,7 +156,9 @@ export class StorageRepository implements IStorageRepository {
|
|||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return glob(this.asGlob(pathsToCrawl), {
|
||||
const globbedPaths = pathsToCrawl.map((path) => this.asGlob(path));
|
||||
|
||||
return glob(globbedPaths, {
|
||||
absolute: true,
|
||||
caseSensitiveMatch: false,
|
||||
onlyFiles: true,
|
||||
|
@ -172,7 +174,9 @@ export class StorageRepository implements IStorageRepository {
|
|||
return emptyGenerator();
|
||||
}
|
||||
|
||||
const stream = globStream(this.asGlob(pathsToCrawl), {
|
||||
const globbedPaths = pathsToCrawl.map((path) => this.asGlob(path));
|
||||
|
||||
const stream = globStream(globbedPaths, {
|
||||
absolute: true,
|
||||
caseSensitiveMatch: false,
|
||||
onlyFiles: true,
|
||||
|
@ -206,10 +210,9 @@ export class StorageRepository implements IStorageRepository {
|
|||
return () => watcher.close();
|
||||
}
|
||||
|
||||
private asGlob(pathsToCrawl: string[]): string {
|
||||
const escapedPaths = pathsToCrawl.map((path) => escapePath(path));
|
||||
const base = escapedPaths.length === 1 ? escapedPaths[0] : `{${escapedPaths.join(',')}}`;
|
||||
private asGlob(pathToCrawl: string): string {
|
||||
const escapedPath = escapePath(pathToCrawl);
|
||||
const extensions = `*{${mimeTypes.getSupportedFileExtensions().join(',')}}`;
|
||||
return `${base}/**/${extensions}`;
|
||||
return `${escapedPath}/**/${extensions}`;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue