Compare commits

..
Author SHA1 Message Date
Jonah Brüchert 5112d0bd1b MultiIterableView: Add convinience std::vector constructor 2022-02-14 17:58:55 +01:00
Dimitris Kardarakos 2b60ae8745 Power search page list sections
The Search Page list view can present content in sections according to media type (artist, playlist, song, video). For sections to work, the model that provides the search results should sort the results accordingly.
2022-02-14 17:25:41 +01:00
Jonah Brüchert 15f439c38e Simplify std::sort use 2022-02-14 17:21:34 +01:00
Jonah Brüchert ca4d5d8b77 MultiIterableView: Add documentation 2022-02-14 17:17:12 +01:00
Jonah Brüchert 06338900dc Fix some implicit this captures 2022-02-14 17:14:46 +01:00
Jonah Brüchert 8ec674fbef MultiIterableView: Generalize by using std::span
Requires upgrading to C++20
2022-02-14 17:10:06 +01:00
Jonah Brüchert 58eefc29eb ArtistModel: Simplify use of MultiIterableView
Now that it is truly a view type, it is possible to just modify the
underlying data, instead of recreating the view.
This allows to get rid of the optional, in which the view was previously
stored.
2022-02-14 15:52:25 +01:00
Jonah Brüchert 9312331755 MultiIterableView: Refactor into an actual view type 2022-02-14 15:52:25 +01:00
Jonah Brüchert 1d25f46f52 MultiIterableView: Try to make code easier to understand 2022-02-14 15:52:22 +01:00
Jonah Brüchert a775cd58be flatpak: Update pybind11 2022-02-13 20:16:18 +01:00
13 changed files with 152 additions and 134 deletions

No files matched your search

+1 -1
View File
@@ -12,7 +12,7 @@ set(PROJECT_VERSION "22.02")
set(QT5_MIN_VERSION 5.15)
set(KF5_MIN_VERSION 5.81)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
+1 -1
View File
@@ -28,7 +28,7 @@
"config-opts": ["-DPYBIND11_FINDPYTHON=ON", "-DPYBIND11_TEST=OFF"],
"buildsystem": "cmake-ninja",
"builddir": true,
"sources": [ { "type": "git", "url": "https://github.com/pybind/pybind11", "tag": "v2.6.2" } ]
"sources": [ { "type": "git", "url": "https://github.com/pybind/pybind11", "tag": "v2.9.1" } ]
},
{
"name": "org.kde.audiotube",
+3 -3
View File
@@ -9,11 +9,11 @@
AlbumModel::AlbumModel(QObject *parent)
: AbstractYTMusicModel(parent)
{
connect(this, &AlbumModel::browseIdChanged, this, [=] {
connect(this, &AlbumModel::browseIdChanged, this, [this] {
setLoading(true);
YTMusicThread::instance()->fetchAlbum(m_browseId);
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchAlbumFinished, this, [=](const album::Album &album) {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchAlbumFinished, this, [this](const album::Album &album) {
setLoading(false);
beginResetModel();
@@ -25,7 +25,7 @@ AlbumModel::AlbumModel(QObject *parent)
Q_EMIT thumbnailUrlChanged();
Q_EMIT playlistIdChanged();
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
setLoading(false);
});
}
+28 -36
View File
@@ -8,8 +8,9 @@
ArtistModel::ArtistModel(QObject *parent)
: AbstractYTMusicModel(parent)
, m_view(albums, singles, songs, videos)
{
connect(this, &ArtistModel::channelIdChanged, this, [=] {
connect(this, &ArtistModel::channelIdChanged, this, [this] {
if (m_channelId.isEmpty()) {
return;
}
@@ -18,44 +19,37 @@ ArtistModel::ArtistModel(QObject *parent)
YTMusicThread::instance()->fetchArtist(m_channelId);
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchArtistFinished, this, [=](const artist::Artist &artist) {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchArtistFinished, this, [this](const artist::Artist &artist) {
setLoading(false);
beginResetModel();
m_artist = artist;
std::sort(m_artist.thumbnails.begin(), m_artist.thumbnails.end());
auto albums = m_artist.albums ? m_artist.albums->results : std::vector<artist::Artist::Album>();
auto singles = m_artist.singles ? m_artist.singles->results : std::vector<artist::Artist::Single>();
auto songs = m_artist.songs ? m_artist.songs->results : std::vector<artist::Artist::Song>();
auto videos = m_artist.videos ? m_artist.videos->results : std::vector<artist::Artist::Video>();
albums = m_artist.albums ? m_artist.albums->results : std::vector<artist::Artist::Album>();
singles = m_artist.singles ? m_artist.singles->results : std::vector<artist::Artist::Single>();
songs = m_artist.songs ? m_artist.songs->results : std::vector<artist::Artist::Song>();
videos = m_artist.videos ? m_artist.videos->results : std::vector<artist::Artist::Video>();
m_view = std::optional(MultiIterableView(std::move(albums),
std::move(singles),
std::move(songs),
std::move(videos)));
// std::span can't know if the data pointer underneath it was changed, so re-create
m_view = MultiIterableView(albums, singles, songs, videos);
endResetModel();
Q_EMIT titleChanged();
Q_EMIT thumbnailUrlChanged();
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
setLoading(false);
});
}
int ArtistModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_view ? int(m_view->size()) : 0;
return parent.isValid() ? 0 : m_view.size();
}
QVariant ArtistModel::data(const QModelIndex &index, int role) const
{
if (!m_view) {
return {};
}
switch (role) {
case Title:
return QString::fromStdString(std::visit([&](auto&& item) {
@@ -71,7 +65,7 @@ QVariant ArtistModel::data(const QModelIndex &index, int role) const
}
Q_UNREACHABLE();
}, m_view.value()[index.row()]));
}, m_view[index.row()]));
case Type:
return std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
@@ -86,7 +80,7 @@ QVariant ArtistModel::data(const QModelIndex &index, int role) const
}
Q_UNREACHABLE();
}, m_view.value()[index.row()]);
}, m_view[index.row()]);
case Artists:
return QVariant::fromValue(std::vector<meta::Artist> {
{
@@ -108,7 +102,7 @@ QVariant ArtistModel::data(const QModelIndex &index, int role) const
}
Q_UNREACHABLE();
}, m_view.value()[index.row()]);
}, m_view[index.row()]);
}
Q_UNREACHABLE();
@@ -153,20 +147,18 @@ QUrl ArtistModel::thumbnailUrl() const
void ArtistModel::triggerItem(int row)
{
if (m_view) {
std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
Q_EMIT openSong(QString::fromStdString(item.video_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
Q_EMIT openVideo(QString::fromStdString(item.video_id), QString::fromStdString(item.title));
} else {
Q_UNREACHABLE();
}
}, m_view.value()[row]);
}
std::visit([&](auto&& item) {
using T = std::decay_t<decltype(item)>;
if constexpr(std::is_same_v<T, artist::Artist::Album>) {
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Single>) {
Q_EMIT openAlbum(QString::fromStdString(item.browse_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Song>) {
Q_EMIT openSong(QString::fromStdString(item.video_id));
} else if constexpr(std::is_same_v<T, artist::Artist::Video>) {
Q_EMIT openVideo(QString::fromStdString(item.video_id), QString::fromStdString(item.title));
} else {
Q_UNREACHABLE();
}
}, m_view[row]);
}
+8 -2
View File
@@ -66,7 +66,13 @@ private:
QString m_channelId;
artist::Artist m_artist;
std::optional<MultiIterableView<
std::vector<artist::Artist::Album> albums;
std::vector<artist::Artist::Single> singles;
std::vector<artist::Artist::Song> songs;
std::vector<artist::Artist::Video> videos;
MultiIterableView<
artist::Artist::Album, artist::Artist::Single, artist::Artist::Song, artist::Artist::Video
>> m_view;
> m_view;
};
+9 -9
View File
@@ -51,7 +51,7 @@ AsyncYTMusic::AsyncYTMusic(QObject *parent)
//
void AsyncYTMusic::search(const QString &query)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT searchFinished(m_ytm->search(query.toStdString()));
});
}
@@ -61,7 +61,7 @@ void AsyncYTMusic::search(const QString &query)
//
void AsyncYTMusic::fetchArtist(const QString &channelId)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT fetchArtistFinished(m_ytm->get_artist(channelId.toStdString()));
});
}
@@ -71,7 +71,7 @@ void AsyncYTMusic::fetchArtist(const QString &channelId)
//
void AsyncYTMusic::fetchAlbum(const QString &browseId)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT fetchAlbumFinished(m_ytm->get_album(browseId.toStdString()));
});
}
@@ -81,7 +81,7 @@ void AsyncYTMusic::fetchAlbum(const QString &browseId)
//
void AsyncYTMusic::fetchSong(const QString &videoId)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
auto maybeSong = m_ytm->get_song(videoId.toStdString());
if (maybeSong.has_value()) {
Q_EMIT fetchSongFinished(*maybeSong);
@@ -93,7 +93,7 @@ void AsyncYTMusic::fetchSong(const QString &videoId)
// fetchPlaylist
//
void AsyncYTMusic::fetchPlaylist(const QString &playlistId) {
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT fetchPlaylistFinished(m_ytm->get_playlist(playlistId.toStdString()));
});
}
@@ -103,7 +103,7 @@ void AsyncYTMusic::fetchPlaylist(const QString &playlistId) {
//
void AsyncYTMusic::fetchArtistAlbums(const QString &channelId, const QString &params)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT fetchArtistAlbumsFinished(m_ytm->get_artist_albums(channelId.toStdString(), params.toStdString()));
});
}
@@ -113,7 +113,7 @@ void AsyncYTMusic::fetchArtistAlbums(const QString &channelId, const QString &pa
//
void AsyncYTMusic::extractVideoInfo(const QString &videoId)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT extractVideoInfoFinished(m_ytm->extract_video_info(videoId.toStdString()));
});
}
@@ -123,7 +123,7 @@ void AsyncYTMusic::extractVideoInfo(const QString &videoId)
//
void AsyncYTMusic::fetchWatchPlaylist(const std::optional<QString> &videoId, const std::optional<QString> &playlistId)
{
invokeAndCatchOnThread([=]() {
invokeAndCatchOnThread([=, this]() {
Q_EMIT fetchWatchPlaylistFinished(m_ytm->get_watch_playlist(
map_optional<std::string>(videoId, &QString::toStdString),
map_optional<std::string>(playlistId, &QString::toStdString)
@@ -132,7 +132,7 @@ void AsyncYTMusic::fetchWatchPlaylist(const std::optional<QString> &videoId, con
}
void AsyncYTMusic::invokeAndCatchOnThread(const std::function<void()> &fun) {
QMetaObject::invokeMethod(this, [=]() {
QMetaObject::invokeMethod(this, [=, this]() {
try {
fun();
} catch (const py::error_already_set &err) {
+49 -52
View File
@@ -6,71 +6,68 @@
#include <variant>
#include <tuple>
#include <vector>
#include <span>
#include <QtGlobal>
// MultiIterableView is usually used on a small number of vectors.
// The number is already known, so we can convert this into an if else if else etc tree
// instead of recursively calling the function
#ifdef __GNUC__
#define REMOVE_RECURSION __attribute__((always_inline))
#else
#define REMOVE_RECURSION
#endif
template <typename Tuple, typename Func, std::size_t i>
inline constexpr void iterate_impl(Tuple &tup, Func fun)
{
if constexpr(i >= std::tuple_size_v<std::decay_t<decltype(tup)>>) {
return;
} else {
fun(std::get<i>(tup));
return iterate_impl<Tuple, Func, i + 1>(tup, fun);
}
}
template <typename Tuple, typename Func>
inline constexpr void iterate_tuple(Tuple &tup, Func fun)
{
iterate_impl<Tuple, Func, 0>(tup, fun);
}
/// MultiIterableView is a view over multiple contigous memory arrays, like std::vector or std::array.
/// The elements of the arrays do not need to be of the same type.
template <typename... Arguments>
class MultiIterableView {
private:
template<typename T, size_t i, size_t len>
REMOVE_RECURSION inline size_t count(const T &tuple, int initial_size = 0) const {
if constexpr(i < len) {
return count<T, i + 1, len>(tuple, initial_size + std::get<i>(tuple).size());
} else {
return initial_size;
}
}
template<typename T, size_t tuple_i, size_t tuple_len>
REMOVE_RECURSION inline std::variant<Arguments...> get_item(const T &tuple, size_t i) const {
if constexpr(tuple_i < tuple_len) {
if (i < std::get<tuple_i>(tuple).size()) {
return std::get<tuple_i>(tuple)[i];
} else {
return get_item<T, tuple_i + 1, tuple_len>(tuple, i - std::get<tuple_i>(tuple).size());
}
} else {
Q_UNREACHABLE();
}
}
template<typename T, size_t i, size_t len>
REMOVE_RECURSION inline bool everything_empty(const T &tuple, bool initial_state = true) const {
if constexpr(i < len) {
return everything_empty<T, i + 1, len>(tuple, initial_state && std::get<i>(tuple).empty());
} else {
return initial_state;
}
}
public:
explicit MultiIterableView(std::vector<Arguments> &&...lists)
: m_vectors(std::make_tuple(lists...))
explicit MultiIterableView(std::span<Arguments>... lists)
: m_vectors(std::forward_as_tuple(lists...))
{
}
size_t size() const {
constexpr size_t nvecs = std::tuple_size_v<decltype(m_vectors)>;
return count<decltype(m_vectors), 0, nvecs>(m_vectors);
explicit MultiIterableView(std::vector<Arguments> &...lists)
: MultiIterableView(std::span{lists}...)
{
}
std::variant<Arguments...> operator[](size_t i) const {
constexpr size_t nvecs = std::tuple_size_v<decltype(m_vectors)>;
return get_item<decltype(m_vectors), 0, nvecs>(m_vectors, i);
[[nodiscard]] constexpr size_t size() const {
size_t s = 0;
iterate_tuple(m_vectors, [&](auto &vec) {
s += vec.size();
});
return s;
}
bool empty() const {
constexpr size_t nvecs = std::tuple_size_v<decltype(m_vectors)>;
return everything_empty<decltype(m_vectors), 0, nvecs>(m_vectors);
[[nodiscard]] constexpr std::variant<Arguments...> operator[](size_t i) const {
size_t s = 0;
std::variant<Arguments...> out;
iterate_tuple(m_vectors, [&](auto &vec) {
if (i >= s && i < s + vec.size()) {
out = vec[i - s];
}
s += vec.size();
});
return out;
}
[[nodiscard]] constexpr bool empty() const {
bool empty = true;
iterate_tuple(m_vectors, [&](auto &elem) {
empty &= elem.empty();
});
return empty;
}
private:
std::tuple<std::vector<Arguments>...> m_vectors;
std::tuple<std::span<Arguments>...> m_vectors;
};
+2 -2
View File
@@ -13,11 +13,11 @@
PlaylistModel::PlaylistModel(QObject *parent)
: AbstractYTMusicModel(parent)
{
connect(this, &PlaylistModel::playlistIdChanged, this, [=] {
connect(this, &PlaylistModel::playlistIdChanged, this, [=, this] {
setLoading(true);
YTMusicThread::instance()->fetchPlaylist(m_playlistId);
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchPlaylistFinished, this, [=](const playlist::Playlist &playlist) {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchPlaylistFinished, this, [this](const playlist::Playlist &playlist) {
setLoading(false);
beginResetModel();
m_playlist = playlist;
+5 -4
View File
@@ -15,11 +15,12 @@ namespace PlaylistUtils {
QString artistsToString(const std::vector<meta::Artist> &artists)
{
if (!artists.empty()) {
return std::accumulate(artists.begin() + 1, artists.end(),
QString::fromStdString(artists.front().name),
[](QString &string, const meta::Artist &artist) {
return string.append(QStringLiteral(", %1").arg(QString::fromStdString(artist.name)));
QString string = QString::fromStdString(artists.front().name);
std::for_each(artists.begin() + 1, artists.end(),
[&string](const meta::Artist &artist) {
string.append(QStringLiteral(", %1").arg(QString::fromStdString(artist.name)));
});
return string;
}
return {};
+28 -3
View File
@@ -7,7 +7,7 @@
SearchModel::SearchModel(QObject *parent)
: AbstractYTMusicModel(parent)
{
connect(this, &SearchModel::searchQueryChanged, this, [=] {
connect(this, &SearchModel::searchQueryChanged, this, [this] {
if (m_searchQuery.isEmpty()) {
beginResetModel();
m_searchResults.clear();
@@ -18,13 +18,17 @@ SearchModel::SearchModel(QObject *parent)
setLoading(true);
YTMusicThread::instance()->search(m_searchQuery);
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::searchFinished, this, [=](const std::vector<search::SearchResultItem> &results) {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::searchFinished, this, [this](const std::vector<search::SearchResultItem> &results) {
beginResetModel();
setLoading(false);
m_searchResults = results;
std::sort(m_searchResults.begin(), m_searchResults.end(),
[](search::SearchResultItem const & a, search::SearchResultItem const & b) {
return SearchModel::itemType(a) < SearchModel::itemType(b);
});
endResetModel();
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
setLoading(false);
});
}
@@ -165,3 +169,24 @@ void SearchModel::triggerItem(int row)
}
}, m_searchResults.at(row));
}
int SearchModel::itemType(search::SearchResultItem const &item)
{
return std::visit([&](auto &&arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr(std::is_same_v<T, search::Album>) {
return SearchModel::Type::Album;
} else if constexpr(std::is_same_v<T, search::Artist>) {
return SearchModel::Type::Artist;
} else if constexpr(std::is_same_v<T, search::Playlist>) {
return SearchModel::Type::Playlist;
} else if constexpr(std::is_same_v<T, search::Song>) {
return SearchModel::Type::Song;
} else if constexpr(std::is_same_v<T, search::Video>) {
return SearchModel::Type::Video;
} else {
Q_UNREACHABLE();
}
}, item);
}
+1
View File
@@ -55,4 +55,5 @@ public:
private:
QString m_searchQuery;
std::vector<search::SearchResultItem> m_searchResults;
static int itemType(search::SearchResultItem const &item);
};
+9 -9
View File
@@ -15,7 +15,7 @@
UserPlaylistModel::UserPlaylistModel(QObject *parent)
: AbstractYTMusicModel(parent)
{
connect(this, &UserPlaylistModel::initialVideoIdChanged, this, [=] {
connect(this, &UserPlaylistModel::initialVideoIdChanged, this, [this] {
if (m_initialVideoId.isEmpty()) {
return;
}
@@ -23,7 +23,7 @@ UserPlaylistModel::UserPlaylistModel(QObject *parent)
setLoading(true);
YTMusicThread::instance()->fetchWatchPlaylist(m_initialVideoId);
});
connect(this, &UserPlaylistModel::playlistIdChanged, this, [=] {
connect(this, &UserPlaylistModel::playlistIdChanged, this, [this] {
if (m_playlistId.isEmpty()) {
return;
}
@@ -31,7 +31,7 @@ UserPlaylistModel::UserPlaylistModel(QObject *parent)
setLoading(true);
YTMusicThread::instance()->fetchWatchPlaylist(std::nullopt, m_playlistId);
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchWatchPlaylistFinished, this, [=](const watch::Playlist &playlist) {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::fetchWatchPlaylistFinished, this, [this](const watch::Playlist &playlist) {
setLoading(false);
beginResetModel();
@@ -49,7 +49,7 @@ UserPlaylistModel::UserPlaylistModel(QObject *parent)
setCurrentVideoId({});
}
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [=] {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::errorOccurred, this, [this] {
setLoading(false);
});
}
@@ -101,7 +101,7 @@ void UserPlaylistModel::setInitialVideoId(const QString &videoId)
QString UserPlaylistModel::nextVideoId() const
{
auto currentTrack = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
[=](const watch::Playlist::Track &track) {
[this](const watch::Playlist::Track &track) {
return track.video_id == m_currentVideoId.toStdString();
});
@@ -129,7 +129,7 @@ void UserPlaylistModel::setCurrentVideoId(const QString &videoId)
bool UserPlaylistModel::canSkip() const
{
const auto currentTrackIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
[=](const watch::Playlist::Track &track) {
[this](const watch::Playlist::Track &track) {
return track.video_id == m_currentVideoId.toStdString();
});
@@ -157,7 +157,7 @@ void UserPlaylistModel::skipTo(const QString &videoId)
void UserPlaylistModel::playNext(const QString &videoId, const QString &title, const std::vector<meta::Artist> &artists)
{
const auto currentIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
[=](const watch::Playlist::Track &track) {
[this](const watch::Playlist::Track &track) {
return track.video_id == m_currentVideoId.toStdString();
});
@@ -239,7 +239,7 @@ void UserPlaylistModel::shufflePlaylist()
// Only shuffle playlist after current track
if (!m_currentVideoId.isEmpty()) {
const auto currentIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
[=](const watch::Playlist::Track &track) {
[this](const watch::Playlist::Track &track) {
return track.video_id == m_currentVideoId.toStdString();
});
@@ -257,7 +257,7 @@ void UserPlaylistModel::emitCurrentVideoChanged(const QString &oldVideoId)
return track.video_id == oldVideoId.toStdString();
});
const auto currentVideoIt = std::find_if(m_playlist.tracks.begin(), m_playlist.tracks.end(),
[=](const watch::Playlist::Track &track) {
[this](const watch::Playlist::Track &track) {
return track.video_id == m_currentVideoId.toStdString();
});
+8 -12
View File
@@ -9,7 +9,7 @@
VideoInfoExtractor::VideoInfoExtractor(QObject *parent)
: QObject(parent)
{
connect(this, &VideoInfoExtractor::videoIdChanged, this, [=] {
connect(this, &VideoInfoExtractor::videoIdChanged, this, [this] {
if (m_videoId.isEmpty()) {
m_videoInfo = {};
Q_EMIT audioUrlChanged();
@@ -23,7 +23,7 @@ VideoInfoExtractor::VideoInfoExtractor(QObject *parent)
YTMusicThread::instance()->extractVideoInfo(QString::fromStdString(m_videoId.toStdString()));
});
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::extractVideoInfoFinished, this, [=](const video_info::VideoInfo &info) {
connect(&YTMusicThread::instance().get(), &AsyncYTMusic::extractVideoInfoFinished, this, [this](const video_info::VideoInfo &info) {
m_videoInfo = info;
setLoading(false);
Q_EMIT audioUrlChanged();
@@ -36,7 +36,7 @@ VideoInfoExtractor::VideoInfoExtractor(QObject *parent)
QUrl VideoInfoExtractor::audioUrl() const
{
if (m_videoInfo.formats.empty()) {
return QUrl();
return {};
}
std::vector<video_info::Format> audioFormats;
@@ -48,17 +48,13 @@ QUrl VideoInfoExtractor::audioUrl() const
});
if (audioFormats.empty()) {
return QUrl();
return {};
}
struct {
bool operator()(const video_info::Format &a, const video_info::Format &b) {
return a.quality > b.quality;
}
} qualitySort;
std::sort(audioFormats.begin(), audioFormats.end(), qualitySort);
std::sort(audioFormats.begin(), audioFormats.end(),
[](const video_info::Format &a, const video_info::Format &b) {
return a.quality > b.quality;
});
return QUrl(QString::fromStdString(audioFormats.front().url));
}