feat(playlist): compact rows with clean titles and durations (#13)

Co-authored-by: Tri Vo Khac <git@trivk.dev>
This commit was merged in pull request #13.
This commit is contained in:
tri authored and tri committed 2026-11-13 22:54:32 +07:00
1 parent 76b12d6632
commit ad50230829
9 files changed
+370 -55

No files matched your search

+6 -1
View File
@@ -16,7 +16,7 @@ target_include_directories(glossarystoretest PRIVATE ../src/translate)
ecm_add_test(playlistmodeltest.cpp ../src/playlist/playlistmodel.cpp
TEST_NAME playlistmodeltest
LINK_LIBRARIES Qt6::Qml Qt6::Test
LINK_LIBRARIES qtpotato_core Qt6::Qml Qt6::Concurrent Qt6::Test
)
target_include_directories(playlistmodeltest PRIVATE ../src/playlist)
@@ -29,3 +29,8 @@ ecm_add_test(translationstoretest.cpp
TEST_NAME translationstoretest
LINK_LIBRARIES qtpotato_core Qt6::Test
)
ecm_add_test(mediainfotest.cpp
TEST_NAME mediainfotest
LINK_LIBRARIES qtpotato_core Qt6::Test
)
+64
View File
@@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
// SPDX-License-Identifier: GPL-3.0-or-later
#include "mediainfo.h"
#include <QProcess>
#include <QStandardPaths>
#include <QTemporaryDir>
#include <QTest>
using namespace Qt::Literals::StringLiterals;
class MediaInfoTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void cleanTitle_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<QString>("title");
QTest::newRow("scene episode") << u"VisionQuest.S01E01.No.Strings.DSNP.DV.HDR.WEB-DL.DDP5.1.Atmos.H.265-GRP.mkv"_s
<< u"S01E01 · No Strings"_s;
QTest::newRow("episode without title") << u"The.Show.S02E10.1080p.WEB.h264-GRP.mkv"_s << u"The Show · S02E10"_s;
QTest::newRow("lowercase double episode") << u"show.s01e01e02.pilot.720p.hdtv.mkv"_s << u"S01E01E02 · pilot"_s;
QTest::newRow("spaced episode") << u"Mr. Robot - S01E01 - eps1.0_hellofriend.mov.mkv"_s << u"S01E01 · eps1.0 hellofriend.mov"_s;
QTest::newRow("movie with year") << u"Dune.Part.Two.2024.2160p.UHD.BluRay.x265-GRP.mkv"_s << u"Dune Part Two (2024)"_s;
QTest::newRow("anime release") << u"[SubsPlease] Frieren - 05 (1080p) [A1B2C3D4].mkv"_s << u"Frieren - 05"_s;
QTest::newRow("plain name") << u"Holiday 2019 at the beach.mp4"_s << u"Holiday 2019 at the beach"_s;
QTest::newRow("music") << u"01 - Intro.flac"_s << u"01 - Intro"_s;
QTest::newRow("only tags") << u"1080p.mkv"_s << u"1080p"_s;
}
void cleanTitle()
{
QFETCH(QString, fileName);
QFETCH(QString, title);
QCOMPARE(MediaInfo::cleanTitle(fileName), title);
}
void probeDurationReadsTheLength()
{
const QString ffmpeg = QStandardPaths::findExecutable(u"ffmpeg"_s);
if (ffmpeg.isEmpty()) {
QSKIP("ffmpeg is needed to make a sample file");
}
QTemporaryDir dir;
const QString path = dir.filePath(u"tone.mka"_s);
QProcess process;
process.start(ffmpeg, {u"-v"_s, u"error"_s, u"-f"_s, u"lavfi"_s, u"-i"_s, u"sine=duration=3"_s, path});
QVERIFY(process.waitForFinished());
QCOMPARE(process.exitCode(), 0);
const std::optional<double> seconds = MediaInfo::probeDuration(path);
QVERIFY(seconds);
QVERIFY2(qAbs(*seconds - 3) < 0.1, qPrintable(QString::number(*seconds)));
QVERIFY(!MediaInfo::probeDuration(dir.filePath(u"missing.mkv"_s)));
}
};
QTEST_GUILESS_MAIN(MediaInfoTest)
#include "mediainfotest.moc"
+27
View File
@@ -4,7 +4,9 @@
#include "playlistmodel.h"
#include <QFile>
#include <QProcess>
#include <QSignalSpy>
#include <QStandardPaths>
#include <QTemporaryDir>
#include <QTest>
@@ -98,6 +100,31 @@ private Q_SLOTS:
QCOMPARE(model.playingIndex(), -1);
QCOMPARE(model.count(), 1);
}
void titleAndDurationRoles()
{
const QString ffmpeg = QStandardPaths::findExecutable(u"ffmpeg"_s);
if (ffmpeg.isEmpty()) {
QSKIP("ffmpeg is needed to make a sample file");
}
QTemporaryDir dir;
const QString path = dir.filePath(u"Show.S01E02.The.Tone.1080p.WEB.mka"_s);
QProcess process;
process.start(ffmpeg, {u"-v"_s, u"error"_s, u"-f"_s, u"lavfi"_s, u"-i"_s, u"sine=duration=2"_s, path});
QVERIFY(process.waitForFinished());
QCOMPARE(process.exitCode(), 0);
PlaylistModel model;
QSignalSpy changed(&model, &QAbstractItemModel::dataChanged);
model.append({QUrl::fromLocalFile(path), QUrl(u"https://example.com/a"_s)});
QCOMPARE(model.data(model.index(0), PlaylistModel::TitleRole).toString(), u"S01E02 · The Tone"_s);
QCOMPARE(model.data(model.index(1), PlaylistModel::TitleRole).toString(), u"https://example.com/a"_s);
QCOMPARE(model.data(model.index(1), PlaylistModel::DurationRole).toDouble(), -1.0);
QTRY_COMPARE(changed.count(), 1);
QCOMPARE(changed.first().at(2).value<QList<int>>(), QList<int>{PlaylistModel::DurationRole});
QVERIFY(qAbs(model.data(model.index(0), PlaylistModel::DurationRole).toDouble() - 2) < 0.1);
}
};
QTEST_GUILESS_MAIN(PlaylistModelTest)