feat: add playlist, recent files and MPRIS backends
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6dc9377de1
commit
54ad4eecf3
18 files changed
+2240
-4
No files matched your search
@@ -0,0 +1,105 @@
|
||||
// SPDX-FileCopyrightText: 2026 Tri Vo Khac
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "playlistmodel.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QSignalSpy>
|
||||
#include <QTemporaryDir>
|
||||
#include <QTest>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
class PlaylistModelTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
static void touch(const QTemporaryDir &dir, const QString &name)
|
||||
{
|
||||
QFile file(dir.filePath(name));
|
||||
QVERIFY(file.open(QIODevice::WriteOnly));
|
||||
}
|
||||
|
||||
static QStringList names(const PlaylistModel &model)
|
||||
{
|
||||
QStringList result;
|
||||
for (int i = 0; i < model.rowCount(); ++i) {
|
||||
result.append(model.data(model.index(i), PlaylistModel::NameRole).toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void sortsEpisodesNaturallyAndSkipsOtherFiles()
|
||||
{
|
||||
QTemporaryDir dir;
|
||||
for (const QString &name : {u"Show - 10.mkv"_s, u"show - 2.mkv"_s, u"Show - 1.mkv"_s, u"notes.txt"_s, u"Show - 1.srt"_s, u"theme.mp3"_s}) {
|
||||
touch(dir, name);
|
||||
}
|
||||
|
||||
const QList<QUrl> urls = PlaylistModel::mediaFilesIn(dir.path());
|
||||
QStringList fileNames;
|
||||
for (const QUrl &url : urls) {
|
||||
fileNames.append(url.fileName());
|
||||
}
|
||||
QCOMPARE(fileNames, (QStringList{u"Show - 1.mkv"_s, u"show - 2.mkv"_s, u"Show - 10.mkv"_s, u"theme.mp3"_s}));
|
||||
}
|
||||
|
||||
void openFileLoadsSiblingsAndPlaysTheFile()
|
||||
{
|
||||
QTemporaryDir dir;
|
||||
for (const QString &name : {u"Ep 1.mkv"_s, u"Ep 2.mkv"_s, u"Ep 3.mkv"_s}) {
|
||||
touch(dir, name);
|
||||
}
|
||||
|
||||
PlaylistModel model;
|
||||
QSignalSpy played(&model, &PlaylistModel::playRequested);
|
||||
const QUrl second = QUrl::fromLocalFile(dir.filePath(u"Ep 2.mkv"_s));
|
||||
model.openFile(second, true);
|
||||
|
||||
QCOMPARE(names(model), (QStringList{u"Ep 1.mkv"_s, u"Ep 2.mkv"_s, u"Ep 3.mkv"_s}));
|
||||
QCOMPARE(model.playingIndex(), 1);
|
||||
QCOMPARE(played.count(), 1);
|
||||
QCOMPARE(played.first().first().toUrl(), second);
|
||||
|
||||
model.openFile(second, false);
|
||||
QCOMPARE(names(model), (QStringList{u"Ep 2.mkv"_s}));
|
||||
}
|
||||
|
||||
void nextAndPreviousStopAtTheEndsUnlessWrapping()
|
||||
{
|
||||
PlaylistModel model;
|
||||
model.append({QUrl(u"https://example.com/a"_s), QUrl(u"https://example.com/b"_s)});
|
||||
model.play(1);
|
||||
|
||||
QVERIFY(!model.playNext());
|
||||
QCOMPARE(model.playingIndex(), 1);
|
||||
QVERIFY(model.playNext(true));
|
||||
QCOMPARE(model.playingIndex(), 0);
|
||||
QVERIFY(!model.playPrevious());
|
||||
QVERIFY(model.playPrevious(true));
|
||||
QCOMPARE(model.playingIndex(), 1);
|
||||
}
|
||||
|
||||
void playingIndexFollowsRemoveAndMove()
|
||||
{
|
||||
PlaylistModel model;
|
||||
model.append({QUrl(u"https://example.com/a"_s), QUrl(u"https://example.com/b"_s), QUrl(u"https://example.com/c"_s)});
|
||||
model.play(1);
|
||||
|
||||
model.move(1, 2);
|
||||
QCOMPARE(model.playingIndex(), 2);
|
||||
model.move(0, 2);
|
||||
QCOMPARE(model.playingIndex(), 1);
|
||||
model.remove(0);
|
||||
QCOMPARE(model.playingIndex(), 0);
|
||||
model.remove(0);
|
||||
QCOMPARE(model.playingIndex(), -1);
|
||||
QCOMPARE(model.count(), 1);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(PlaylistModelTest)
|
||||
|
||||
#include "playlistmodeltest.moc"
|
||||
Reference in new issue
Block a user