import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { DriveFilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import type { RemoteUser } from '@/models/entities/User.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import { MetaService } from '@/core/MetaService.js'; import { truncate } from '@/misc/truncate.js'; import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/const.js'; import { DriveService } from '@/core/DriveService.js'; import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; import { ApResolverService } from '../ApResolverService.js'; import { ApLoggerService } from '../ApLoggerService.js'; @Injectable() export class ApImageService { private logger: Logger; constructor( @Inject(DI.config) private config: Config, @Inject(DI.driveFilesRepository) private driveFilesRepository: DriveFilesRepository, private metaService: MetaService, private apResolverService: ApResolverService, private driveService: DriveService, private apLoggerService: ApLoggerService, ) { this.logger = this.apLoggerService.logger; } /** * Imageを作成します。 */ @bindThis public async createImage(actor: RemoteUser, value: any): Promise { // 投稿者が凍結されていたらスキップ if (actor.isSuspended) { throw new Error('actor has been suspended'); } const image = await this.apResolverService.createResolver().resolve(value) as any; if (image.url == null) { throw new Error('invalid image: url not privided'); } if (!image.url.startsWith('https://')) { throw new Error('invalid image: unexpected shcema of url: ' + image.url); } this.logger.info(`Creating the Image: ${image.url}`); const instance = await this.metaService.fetch(); let file = await this.driveService.uploadFromUrl({ url: image.url, user: actor, uri: image.url, sensitive: image.sensitive, isLink: !instance.cacheRemoteFiles, comment: truncate(image.name, DB_MAX_IMAGE_COMMENT_LENGTH), }); if (file.isLink) { // URLが異なっている場合、同じ画像が以前に異なるURLで登録されていたということなので、 // URLを更新する if (file.url !== image.url) { await this.driveFilesRepository.update({ id: file.id }, { url: image.url, uri: image.url, }); file = await this.driveFilesRepository.findOneByOrFail({ id: file.id }); } } return file; } /** * Imageを解決します。 * * Misskeyに対象のImageが登録されていればそれを返し、そうでなければ * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 */ @bindThis public async resolveImage(actor: RemoteUser, value: any): Promise { // TODO // リモートサーバーからフェッチしてきて登録 return await this.createImage(actor, value); } }