From efafa02f6820a31df5dded620cf0f6ef30454e0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sun, 31 Mar 2024 12:43:39 +0900
Subject: [PATCH] =?UTF-8?q?enhance(backend):=20=E3=83=93=E3=83=87=E3=82=AA?=
 =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AB=E3=83=93=E3=83=87?=
 =?UTF-8?q?=E3=82=AA=E3=83=88=E3=83=A9=E3=83=83=E3=82=AF=E3=81=8C=E3=81=82?=
 =?UTF-8?q?=E3=82=8B=E3=81=8B=E3=82=92=E7=A2=BA=E8=AA=8D=E3=81=99=E3=82=8B?=
 =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#13568)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* enhance(backend): ビデオファイルにビデオトラックがあるかを確認するように

(cherry picked from commit 23d38a2d6492a2b24e9b2c031d66c3e8a5d382ef)

* Update Changelog

* Update Changelog

* Revert "Update Changelog"

This reverts commit 93fd996932b87ef550c38b48bd0678060f3ed1af.

* fix(test) ffmpegをインストールするように

* 入れる方間違えた

* fix test

* 拡張子変わらなかったのでそのまま行く

* ログを出力するように

* msg

* remove unused import

* add log

* attempt to fix test error

* Revert "attempt to fix test error"

This reverts commit d9d6524cadd655e6d8e9398b26fdfef332f30f4d.

* Update FileInfoService.ts

* oggも検査の対象にする
---
 .github/workflows/test-backend.yml            |   2 +
 CHANGELOG.md                                  |   1 +
 packages/backend/src/core/FileInfoService.ts  |  49 +++++++++++++++++-
 .../backend/test/resources/kick_gaba7.m4a     | Bin 0 -> 9817 bytes
 packages/backend/test/unit/FileInfoService.ts |  27 ++++++++--
 5 files changed, 74 insertions(+), 5 deletions(-)
 create mode 100644 packages/backend/test/resources/kick_gaba7.m4a

diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml
index 49a6a39805..a803db4508 100644
--- a/.github/workflows/test-backend.yml
+++ b/.github/workflows/test-backend.yml
@@ -45,6 +45,8 @@ jobs:
       with:
         version: 8
         run_install: false
+    - name: Install FFmpeg
+      uses: FedericoCarboni/setup-ffmpeg@v3
     - name: Use Node.js ${{ matrix.node-version }}
       uses: actions/setup-node@v4.0.2
       with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 390639bd69..f6b9cf0939 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,7 @@
   (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440)
 - Fix: エンドポイント`notes/translate`のエラーを改善
 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632)
+- Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正
 
 ## 2024.3.1
 
diff --git a/packages/backend/src/core/FileInfoService.ts b/packages/backend/src/core/FileInfoService.ts
index b8babcb3a7..169285f033 100644
--- a/packages/backend/src/core/FileInfoService.ts
+++ b/packages/backend/src/core/FileInfoService.ts
@@ -14,11 +14,12 @@ import FFmpeg from 'fluent-ffmpeg';
 import isSvg from 'is-svg';
 import probeImageSize from 'probe-image-size';
 import { type predictionType } from 'nsfwjs';
-import sharp from 'sharp';
 import { sharpBmp } from '@misskey-dev/sharp-read-bmp';
 import { encode } from 'blurhash';
 import { createTempDir } from '@/misc/create-temp.js';
 import { AiService } from '@/core/AiService.js';
+import { LoggerService } from '@/core/LoggerService.js';
+import type Logger from '@/logger.js';
 import { bindThis } from '@/decorators.js';
 
 export type FileInfo = {
@@ -49,9 +50,13 @@ const TYPE_SVG = {
 
 @Injectable()
 export class FileInfoService {
+	private logger: Logger;
+
 	constructor(
 		private aiService: AiService,
+		private loggerService: LoggerService,
 	) {
+		this.logger = this.loggerService.getLogger('file-info');
 	}
 
 	/**
@@ -317,6 +322,34 @@ export class FileInfoService {
 		return mime;
 	}
 
+	/**
+	 * ビデオファイルにビデオトラックがあるかどうかチェック
+	 * (ない場合:m4a, webmなど)
+	 *
+	 * @param path ファイルパス
+	 * @returns ビデオトラックがあるかどうか(エラー発生時は常に`true`を返す)
+	 */
+	@bindThis
+	private hasVideoTrackOnVideoFile(path: string): Promise<boolean> {
+		const sublogger = this.logger.createSubLogger('ffprobe');
+		sublogger.info(`Checking the video file. File path: ${path}`);
+		return new Promise((resolve) => {
+			try {
+				FFmpeg.ffprobe(path, (err, metadata) => {
+					if (err) {
+						sublogger.warn(`Could not check the video file. Returns true. File path: ${path}`, err);
+						resolve(true);
+						return;
+					}
+					resolve(metadata.streams.some((stream) => stream.codec_type === 'video'));
+				});
+			} catch (err) {
+				sublogger.warn(`Could not check the video file. Returns true. File path: ${path}`, err as Error);
+				resolve(true);
+			}
+		});
+	}
+
 	/**
 	 * Detect MIME Type and extension
 	 */
@@ -339,6 +372,20 @@ export class FileInfoService {
 				return TYPE_SVG;
 			}
 
+			if ((type.mime.startsWith('video') || type.mime === 'application/ogg') && !(await this.hasVideoTrackOnVideoFile(path))) {
+				const newMime = `audio/${type.mime.split('/')[1]}`;
+				if (newMime === 'audio/mp4') {
+					return {
+						mime: 'audio/mp4',
+						ext: 'm4a',
+					};
+				}
+				return {
+					mime: newMime,
+					ext: type.ext,
+				};
+			}
+
 			return {
 				mime: this.fixMime(type.mime),
 				ext: type.ext,
diff --git a/packages/backend/test/resources/kick_gaba7.m4a b/packages/backend/test/resources/kick_gaba7.m4a
new file mode 100644
index 0000000000000000000000000000000000000000..321df6349f016358b24b7bac2df8273ec5c448e5
GIT binary patch
literal 9817
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
Vj64|zC_}ug_yjq)IN=xP{{mAaTcH2|

literal 0
HcmV?d00001

diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts
index 2eec80d763..40d187f5a8 100644
--- a/packages/backend/test/unit/FileInfoService.ts
+++ b/packages/backend/test/unit/FileInfoService.ts
@@ -15,6 +15,7 @@ import { GlobalModule } from '@/GlobalModule.js';
 import { FileInfoService } from '@/core/FileInfoService.js';
 //import { DI } from '@/di-symbols.js';
 import { AiService } from '@/core/AiService.js';
+import { LoggerService } from '@/core/LoggerService.js';
 import type { TestingModule } from '@nestjs/testing';
 import type { MockFunctionMetadata } from 'jest-mock';
 
@@ -35,6 +36,7 @@ describe('FileInfoService', () => {
 			],
 			providers: [
 				AiService,
+				LoggerService,
 				FileInfoService,
 			],
 		})
@@ -323,8 +325,26 @@ describe('FileInfoService', () => {
 			});
 		});
 
-		/*
-		 * video/webmとして検出されてしまう
+		test('MPEG-4 AUDIO (M4A)', async () => {
+			const path = `${resources}/kick_gaba7.m4a`;
+			const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
+			delete info.warnings;
+			delete info.blurhash;
+			delete info.sensitive;
+			delete info.porn;
+			delete info.width;
+			delete info.height;
+			delete info.orientation;
+			assert.deepStrictEqual(info, {
+				size: 9817,
+				md5: '74c9279a4abe98789565f1dc1a541a42',
+				type: {
+					mime: 'audio/mp4',
+					ext: 'm4a',
+				},
+			});
+		});
+
 		test('WEBM AUDIO', async () => {
 			const path = `${resources}/kick_gaba7.webm`;
 			const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any;
@@ -337,13 +357,12 @@ describe('FileInfoService', () => {
 			delete info.orientation;
 			assert.deepStrictEqual(info, {
 				size: 8879,
-				md5: '3350083dec312419cfdc06c16413aca7',
+				md5: '53bc1adcb6acbbda67ff9bd484896438',
 				type: {
 					mime: 'audio/webm',
 					ext: 'webm',
 				},
 			});
 		});
-		 */
 	});
 });