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:
1 parent
76b12d6632
commit
ad50230829
9 files changed
+370
-55
No files matched your search
@@ -3,10 +3,13 @@
|
||||
|
||||
#include "playlistmodel.h"
|
||||
|
||||
#include "mediainfo.h"
|
||||
|
||||
#include <QCollator>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QMimeDatabase>
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -15,6 +18,13 @@ using namespace Qt::Literals::StringLiterals;
|
||||
PlaylistModel::PlaylistModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
// Reading many files at once from one disk is slower than a few at a time.
|
||||
m_probePool.setMaxThreadCount(2);
|
||||
}
|
||||
|
||||
PlaylistModel::~PlaylistModel()
|
||||
{
|
||||
m_probePool.clear();
|
||||
}
|
||||
|
||||
int PlaylistModel::rowCount(const QModelIndex &parent) const
|
||||
@@ -36,6 +46,10 @@ QVariant PlaylistModel::data(const QModelIndex &index, int role) const
|
||||
return url.isLocalFile() ? url.fileName() : url.toDisplayString();
|
||||
case IsPlayingRole:
|
||||
return index.row() == m_playingIndex;
|
||||
case TitleRole:
|
||||
return url.isLocalFile() ? MediaInfo::cleanTitle(url.fileName()) : url.toDisplayString();
|
||||
case DurationRole:
|
||||
return m_durations.value(url, -1);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -46,6 +60,8 @@ QHash<int, QByteArray> PlaylistModel::roleNames() const
|
||||
{UrlRole, "url"},
|
||||
{NameRole, "name"},
|
||||
{IsPlayingRole, "isPlaying"},
|
||||
{TitleRole, "title"},
|
||||
{DurationRole, "duration"},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,6 +143,7 @@ void PlaylistModel::openFile(const QUrl &url, bool loadSiblings)
|
||||
m_playingIndex = -1;
|
||||
endResetModel();
|
||||
Q_EMIT countChanged();
|
||||
probeDurations(m_urls);
|
||||
play(std::max<int>(0, int(m_urls.indexOf(url))));
|
||||
}
|
||||
|
||||
@@ -140,6 +157,7 @@ void PlaylistModel::append(const QList<QUrl> &urls)
|
||||
m_urls.append(added);
|
||||
endInsertRows();
|
||||
Q_EMIT countChanged();
|
||||
probeDurations(added);
|
||||
}
|
||||
|
||||
void PlaylistModel::replace(const QList<QUrl> &urls)
|
||||
@@ -153,6 +171,7 @@ void PlaylistModel::replace(const QList<QUrl> &urls)
|
||||
m_playingIndex = -1;
|
||||
endResetModel();
|
||||
Q_EMIT countChanged();
|
||||
probeDurations(m_urls);
|
||||
play(0);
|
||||
}
|
||||
|
||||
@@ -274,3 +293,25 @@ void PlaylistModel::setPlayingIndex(int index)
|
||||
}
|
||||
Q_EMIT playingIndexChanged();
|
||||
}
|
||||
|
||||
void PlaylistModel::probeDurations(const QList<QUrl> &urls)
|
||||
{
|
||||
for (const QUrl &url : urls) {
|
||||
// Streams are skipped: opening them can take long and costs bandwidth.
|
||||
if (!url.isLocalFile() || m_durations.contains(url)) {
|
||||
continue;
|
||||
}
|
||||
m_durations.insert(url, -1);
|
||||
QtConcurrent::run(&m_probePool, MediaInfo::probeDuration, url.toLocalFile()).then(this, [this, url](std::optional<double> seconds) {
|
||||
if (!seconds) {
|
||||
return;
|
||||
}
|
||||
m_durations.insert(url, *seconds);
|
||||
for (int row = 0; row < m_urls.size(); ++row) {
|
||||
if (m_urls.at(row) == url) {
|
||||
Q_EMIT dataChanged(index(row), index(row), {DurationRole});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QThreadPool>
|
||||
#include <QUrl>
|
||||
#include <QtQml/qqmlregistration.h>
|
||||
|
||||
@@ -24,10 +26,15 @@ public:
|
||||
UrlRole = Qt::UserRole + 1,
|
||||
NameRole,
|
||||
IsPlayingRole,
|
||||
// Short name without release tags; see MediaInfo::cleanTitle().
|
||||
TitleRole,
|
||||
// Length in seconds, or -1 while unknown. Local files are read in the background.
|
||||
DurationRole,
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
explicit PlaylistModel(QObject *parent = nullptr);
|
||||
~PlaylistModel() override;
|
||||
|
||||
int rowCount(const QModelIndex &parent = {}) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
@@ -66,7 +73,12 @@ Q_SIGNALS:
|
||||
private:
|
||||
QList<QUrl> expand(const QList<QUrl> &urls) const;
|
||||
void setPlayingIndex(int index);
|
||||
void probeDurations(const QList<QUrl> &urls);
|
||||
|
||||
QList<QUrl> m_urls;
|
||||
int m_playingIndex = -1;
|
||||
// Known lengths in seconds; -1 for files that couldn't be read or are still being read.
|
||||
QHash<QUrl, double> m_durations;
|
||||
// Declared last so it is destroyed first and waits for running probes.
|
||||
QThreadPool m_probePool;
|
||||
};
|
||||
Reference in new issue
Block a user