mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
* refactor: entity imports * refactor: rename user repository token * chore: merge imports * refactor: rename album repository token * refactor: rename asset repository token * refactor: rename tag repository token
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { AssetEntity } from '@app/database';
|
|
import { QueueNameEnum } from '@app/job';
|
|
import { Process, Processor } from '@nestjs/bull';
|
|
import { Logger } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { createHash } from 'node:crypto';
|
|
import fs from 'node:fs';
|
|
import { FindOptionsWhere, IsNull, MoreThan, QueryFailedError, Repository } from 'typeorm';
|
|
|
|
// TODO: just temporary task to generate previous uploaded assets.
|
|
@Processor(QueueNameEnum.CHECKSUM_GENERATION)
|
|
export class GenerateChecksumProcessor {
|
|
constructor(
|
|
@InjectRepository(AssetEntity)
|
|
private assetRepository: Repository<AssetEntity>,
|
|
) {}
|
|
|
|
@Process()
|
|
async generateChecksum() {
|
|
const pageSize = 200;
|
|
let hasNext = true;
|
|
let lastErrAssetId: string | undefined = undefined;
|
|
|
|
while (hasNext) {
|
|
const whereStat: FindOptionsWhere<AssetEntity> = {
|
|
checksum: IsNull(),
|
|
};
|
|
|
|
if (lastErrAssetId) {
|
|
whereStat.id = MoreThan(lastErrAssetId);
|
|
}
|
|
|
|
const assets = await this.assetRepository.find({
|
|
where: whereStat,
|
|
take: pageSize,
|
|
order: { id: 'ASC' },
|
|
});
|
|
|
|
if (!assets?.length) {
|
|
hasNext = false; // avoid using break
|
|
} else {
|
|
for (const asset of assets) {
|
|
try {
|
|
await this.generateAssetChecksum(asset);
|
|
} catch (err: any) {
|
|
lastErrAssetId = asset.id;
|
|
|
|
if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
|
|
Logger.error(`${asset.originalPath} duplicated`);
|
|
} else {
|
|
Logger.error(`checksum generation ${err}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// break when reach to the last page
|
|
if (assets.length < pageSize) {
|
|
hasNext = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Logger.log(`checksum generation done!`);
|
|
}
|
|
|
|
private async generateAssetChecksum(asset: AssetEntity) {
|
|
if (!asset.originalPath) return;
|
|
if (!fs.existsSync(asset.originalPath)) return;
|
|
|
|
const fileReadStream = fs.createReadStream(asset.originalPath);
|
|
const sha1Hash = createHash('sha1');
|
|
const deferred = new Promise<Buffer>((resolve, reject) => {
|
|
sha1Hash.once('error', (err) => reject(err));
|
|
sha1Hash.once('finish', () => resolve(sha1Hash.read()));
|
|
});
|
|
|
|
fileReadStream.pipe(sha1Hash);
|
|
const checksum = await deferred;
|
|
|
|
await this.assetRepository.update(asset.id, { checksum });
|
|
}
|
|
}
|