mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat: automatically detect media location changes (#20256)
This commit is contained in:
parent
0fdeac0417
commit
c6b25ef111
8 changed files with 43 additions and 8 deletions
|
|
@ -437,6 +437,15 @@ export class DatabaseRepository {
|
|||
}
|
||||
|
||||
async migrateFilePaths(sourceFolder: string, targetFolder: string): Promise<void> {
|
||||
// remove trailing slashes
|
||||
if (sourceFolder.endsWith('/')) {
|
||||
sourceFolder = sourceFolder.slice(0, -1);
|
||||
}
|
||||
|
||||
if (targetFolder.endsWith('/')) {
|
||||
targetFolder = targetFolder.slice(0, -1);
|
||||
}
|
||||
|
||||
// escaping regex special characters with a backslash
|
||||
const sourceRegex = '^' + sourceFolder.replaceAll(/[-[\]{}()*+?.,\\^$|#\s]/g, String.raw`\$&`);
|
||||
const source = sql.raw(`'${sourceRegex}'`);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ describe(StorageService.name, () => {
|
|||
describe('onBootstrap', () => {
|
||||
it('should enable mount folder checking', async () => {
|
||||
mocks.systemMetadata.get.mockResolvedValue(null);
|
||||
mocks.asset.getFileSamples.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.onBootstrap()).resolves.toBeUndefined();
|
||||
|
||||
|
|
@ -75,6 +76,7 @@ describe(StorageService.name, () => {
|
|||
upload: true,
|
||||
},
|
||||
});
|
||||
mocks.asset.getFileSamples.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.onBootstrap()).resolves.toBeUndefined();
|
||||
|
||||
|
|
@ -128,6 +130,7 @@ describe(StorageService.name, () => {
|
|||
error.code = 'EEXIST';
|
||||
mocks.systemMetadata.get.mockResolvedValue({ mountChecks: {} });
|
||||
mocks.storage.createFile.mockRejectedValue(error);
|
||||
mocks.asset.getFileSamples.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.onBootstrap()).resolves.toBeUndefined();
|
||||
|
||||
|
|
@ -149,6 +152,7 @@ describe(StorageService.name, () => {
|
|||
storage: { ignoreMountCheckErrors: true },
|
||||
}),
|
||||
);
|
||||
mocks.asset.getFileSamples.mockResolvedValue([]);
|
||||
mocks.storage.overwriteFile.mockRejectedValue(
|
||||
new Error("ENOENT: no such file or directory, open '/app/.immich'"),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -65,10 +65,26 @@ export class StorageService extends BaseService {
|
|||
await this.databaseRepository.withLock(DatabaseLock.MediaLocation, async () => {
|
||||
const current = APP_MEDIA_LOCATION;
|
||||
const savedValue = await this.systemMetadataRepository.get(SystemMetadataKey.MediaLocation);
|
||||
const previous = savedValue?.location || '';
|
||||
let previous = savedValue?.location || '';
|
||||
|
||||
if (previous !== current) {
|
||||
this.logger.log(`Media location changed (from=${previous}, to=${current})`);
|
||||
|
||||
const samples = await this.assetRepository.getFileSamples();
|
||||
if (samples.length > 0) {
|
||||
const originalPath = samples[0].originalPath;
|
||||
if (!previous) {
|
||||
previous = originalPath.startsWith('upload/') ? 'upload' : '/usr/src/app/upload';
|
||||
}
|
||||
|
||||
if (previous && originalPath.startsWith(previous)) {
|
||||
this.logger.warn(
|
||||
`Detected a change to IMMICH_MEDIA_LOCATION, performing an automatic migration of file paths from ${previous} to ${current}, this may take awhile`,
|
||||
);
|
||||
await this.databaseRepository.migrateFilePaths(previous, current);
|
||||
}
|
||||
}
|
||||
|
||||
await this.systemMetadataRepository.set(SystemMetadataKey.MediaLocation, { location: current });
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue