// SPDX-FileCopyrightText: 2026 Tri Vo Khac // SPDX-License-Identifier: GPL-3.0-or-later #include "subtitleextractor.h" #include #include #include #include #include using namespace Qt::Literals::StringLiterals; class SubtitleExtractorTest : public QObject { Q_OBJECT private: // Makes \a name in \a dir with a German audio track plus \a subtitleLanguages as // SRT subtitle tracks, in that order. static QString makeSample(const QTemporaryDir &dir, const QString &name, const QStringList &subtitleLanguages) { const QString ffmpeg = QStandardPaths::findExecutable(u"ffmpeg"_s); const QString srt = dir.filePath(u"line.srt"_s); QFile file(srt); if (!file.open(QIODevice::WriteOnly) || file.write("1\n00:00:00,000 --> 00:00:01,000\nHello\n") < 0) { return {}; } file.close(); QStringList args{u"-v"_s, u"error"_s, u"-f"_s, u"lavfi"_s, u"-i"_s, u"sine=duration=1"_s}; for (qsizetype i = 0; i < subtitleLanguages.size(); ++i) { args << u"-i"_s << srt; } args << u"-map"_s << u"0:a"_s << u"-metadata:s:a:0"_s << u"language=ger"_s; for (qsizetype i = 0; i < subtitleLanguages.size(); ++i) { args << u"-map"_s << u"%1:s"_s.arg(i + 1) << u"-metadata:s:s:%1"_s.arg(i) << u"language=%1"_s.arg(subtitleLanguages.at(i)); } const QString path = dir.filePath(name); args << u"-c:s"_s << u"srt"_s << path; QProcess process; process.start(ffmpeg, args); if (!process.waitForFinished() || process.exitCode() != 0) { qWarning() << process.readAllStandardError(); return {}; } return path; } private Q_SLOTS: void initTestCase() { if (QStandardPaths::findExecutable(u"ffmpeg"_s).isEmpty()) { QSKIP("ffmpeg is needed to make sample files"); } } void findTranslationSourcePrefersEnglish() { QTemporaryDir dir; const QString path = makeSample(dir, u"episode.mkv"_s, {u"fre"_s, u"eng"_s}); QVERIFY(!path.isEmpty()); const Subtitles::SourceResult result = Subtitles::findTranslationSource(path); QVERIFY2(result.error.isEmpty(), qPrintable(result.error)); // Stream 0 is the audio, 1 French, 2 English. QCOMPARE(result.streamIndex, 2); std::atomic_bool cancelled = false; const Subtitles::ExtractResult cues = Subtitles::extractEmbedded(path, result.streamIndex, cancelled); QCOMPARE(cues.cues.size(), 1); QCOMPARE(cues.cues.first().text, u"Hello"_s); } void findTranslationSourceFallsBackToTheAudioLanguage() { QTemporaryDir dir; const QString path = makeSample(dir, u"episode.mkv"_s, {u"fre"_s, u"ger"_s}); QVERIFY(!path.isEmpty()); QCOMPARE(Subtitles::findTranslationSource(path).streamIndex, 2); } void findTranslationSourceWithoutSubtitles() { QTemporaryDir dir; const QString path = makeSample(dir, u"episode.mkv"_s, {}); QVERIFY(!path.isEmpty()); const Subtitles::SourceResult result = Subtitles::findTranslationSource(path); QVERIFY(result.error.isEmpty()); QCOMPARE(result.streamIndex, -1); QVERIFY(!Subtitles::findTranslationSource(dir.filePath(u"missing.mkv"_s)).error.isEmpty()); } }; QTEST_GUILESS_MAIN(SubtitleExtractorTest) #include "subtitleextractortest.moc"