98 lines
3.4 KiB
C++
98 lines
3.4 KiB
C++
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "subtitleextractor.h"
|
|
|
|
#include <QFile>
|
|
#include <QProcess>
|
|
#include <QStandardPaths>
|
|
#include <QTemporaryDir>
|
|
#include <QTest>
|
|
|
|
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"
|