[vlc-commits] [Git][videolan/vlc][master] 14 commits: qml: fix identation
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Mon Jul 1 21:07:28 UTC 2024
Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits:
d67fa4ba by Prince Gupta at 2024-07-01T20:55:41+00:00
qml: fix identation
- - - - -
e145e7b1 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: make MLItemId hashable
- - - - -
20327806 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: define invalid state of MLItemId
- - - - -
ea002dd8 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: implement MLMedia class
- - - - -
72aa032c by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: fix networkmediamodel not notifying removed items
- - - - -
86ac0729 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: store items as uri indexable in NetworkMediaModel
required for efficient implementation for integrating medialibrary data
added in follow up commits
- - - - -
d085c69f by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: implement MLMediaStore
- - - - -
7844853c by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: provide associated media from medialibrary in NetworkMediaModel
- - - - -
5290f1ea by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: use medialibrary thumbnail (if available) in NetworkMediaModel
- - - - -
db8f2ff3 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: add progress field to NetworkMediaModel data
- - - - -
cb5c3748 by Prince Gupta at 2024-07-01T20:55:41+00:00
qml: show progressbar in NetworkGridItem
- - - - -
23ec44a9 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: add duration field in NetworkMediaModel
- - - - -
58e030c4 by Prince Gupta at 2024-07-01T20:55:41+00:00
qml: support duration column in BrowseTreeDisplay
- - - - -
31b383f5 by Prince Gupta at 2024-07-01T20:55:41+00:00
qt: optimize data initialization in NetworkMediaModel
eliminates N*M loop [N = NetworkMediaModel::count, M = folders
in NetworkMediaModel] generated to update indexing state of
indexes from medialibrary, use the fact that items are stored as
uri indexable to make this operation linear in size M.
- - - - -
10 changed files:
- modules/gui/qt/Makefile.am
- + modules/gui/qt/medialibrary/mlmedia.hpp
- + modules/gui/qt/medialibrary/mlmediastore.cpp
- + modules/gui/qt/medialibrary/mlmediastore.hpp
- modules/gui/qt/medialibrary/mlqmltypes.hpp
- modules/gui/qt/meson.build
- modules/gui/qt/network/networkmediamodel.cpp
- modules/gui/qt/network/networkmediamodel.hpp
- modules/gui/qt/network/qml/BrowseTreeDisplay.qml
- modules/gui/qt/network/qml/NetworkGridItem.qml
Changes:
=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -172,6 +172,8 @@ libqt_plugin_la_SOURCES = \
maininterface/windoweffects_module.hpp \
medialibrary/medialib.cpp \
medialibrary/medialib.hpp \
+ medialibrary/mlmediastore.cpp \
+ medialibrary/mlmediastore.hpp \
medialibrary/mlalbum.cpp \
medialibrary/mlalbum.hpp \
medialibrary/mlalbummodel.cpp \
@@ -204,6 +206,7 @@ libqt_plugin_la_SOURCES = \
medialibrary/mlthreadpool.cpp \
medialibrary/mlthreadpool.hpp \
medialibrary/mlqmltypes.hpp \
+ medialibrary/mlmedia.hpp \
medialibrary/mlqueryparams.cpp \
medialibrary/mlqueryparams.hpp \
medialibrary/mlrecentsmodel.cpp \
@@ -406,6 +409,7 @@ nodist_libqt_plugin_la_SOURCES = \
maininterface/videosurface.moc.cpp \
maininterface/video_window_handler.moc.cpp \
medialibrary/medialib.moc.cpp \
+ medialibrary/mlmediastore.moc.cpp \
medialibrary/mlalbummodel.moc.cpp \
medialibrary/mlalbumtrackmodel.moc.cpp \
medialibrary/mlartistmodel.moc.cpp \
@@ -415,6 +419,7 @@ nodist_libqt_plugin_la_SOURCES = \
medialibrary/mlgenremodel.moc.cpp \
medialibrary/mlthreadpool.moc.cpp \
medialibrary/mlqmltypes.moc.cpp \
+ medialibrary/mlmedia.moc.cpp \
medialibrary/mlrecentsmodel.moc.cpp \
medialibrary/mlrecentsvideomodel.moc.cpp \
medialibrary/mlurlmodel.moc.cpp \
=====================================
modules/gui/qt/medialibrary/mlmedia.hpp
=====================================
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Prince Gupta <guptaprince8832 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#pragma once
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "qt.hpp"
+#include "mlqmltypes.hpp"
+#include "util/vlctick.hpp"
+
+#include <QObject>
+
+class MLMedia : public MLItem
+{
+ Q_GADGET
+
+ Q_PROPERTY(MLItemId id READ getId CONSTANT)
+ Q_PROPERTY(QString title READ title CONSTANT FINAL)
+ Q_PROPERTY(QString fileName READ fileName CONSTANT FINAL)
+ Q_PROPERTY(QString smallCover READ smallCover CONSTANT FINAL)
+ Q_PROPERTY(QString bannerCover READ bannerCover CONSTANT FINAL)
+ Q_PROPERTY(VLCTick duration READ duration CONSTANT FINAL)
+ Q_PROPERTY(qreal progress READ progress CONSTANT FINAL)
+
+public:
+ MLMedia() : MLItem {MLItemId()} {}
+
+ MLMedia(const vlc_ml_media_t *media)
+ : MLItem {MLItemId(media->i_id, VLC_ML_PARENT_UNKNOWN)}
+ {
+ const auto getThumbnail = [](const vlc_ml_thumbnail_t & thumbnail)
+ {
+ return (thumbnail.i_status == VLC_ML_THUMBNAIL_STATUS_AVAILABLE)
+ ? qfu(thumbnail.psz_mrl) : QString {};
+ };
+
+ m_title = qfu(media->psz_title);
+ m_fileName = qfu(media->psz_filename);
+ m_smallCover = getThumbnail(media->thumbnails[VLC_ML_THUMBNAIL_SMALL]);
+ m_bannerCover = getThumbnail(media->thumbnails[VLC_ML_THUMBNAIL_BANNER]);
+ m_duration = VLCTick::fromMS(media->i_duration);
+ m_progress = media->f_progress;
+ }
+
+ QString title() const { return m_title; }
+ QString fileName() const { return m_fileName; }
+ QString smallCover() const { return m_smallCover; }
+ QString bannerCover() const { return m_bannerCover; }
+ VLCTick duration() const { return m_duration; }
+ qreal progress() const { return m_progress; }
+
+ Q_INVOKABLE bool valid() const { return getId().id != INVALID_MLITEMID_ID; }
+
+private:
+ QString m_title;
+ QString m_fileName;
+ QString m_smallCover;
+ QString m_bannerCover;
+ VLCTick m_duration;
+ qreal m_progress;
+};
+
=====================================
modules/gui/qt/medialibrary/mlmediastore.cpp
=====================================
@@ -0,0 +1,183 @@
+/*****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Prince Gupta <guptaprince8832 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+#include "mlmediastore.hpp"
+
+#include "mlhelper.hpp"
+#include "medialib.hpp"
+#include "mlmedia.hpp"
+
+static const char *UPDATE_QUEUE = "MLMEDIASTORE_UPDATEQUEUE";
+
+MLMediaStore::~MLMediaStore() = default;
+
+MLMediaStore::MLMediaStore(MediaLib *ml, QObject *parent)
+ : QObject(parent)
+ , m_ml {ml}
+ , m_ml_event_handle( nullptr, [this](vlc_ml_event_callback_t* cb )
+ {
+ assert( m_ml != nullptr );
+ m_ml->unregisterEventListener( cb );
+ })
+{
+ m_ml_event_handle.reset
+ (
+ m_ml->registerEventListener(MLMediaStore::onVlcMlEvent, this)
+ );
+}
+
+void MLMediaStore::insert(const QString &mrl)
+{
+ struct Ctx
+ {
+ MLMedia media;
+ };
+
+ m_files.insert(mrl);
+
+ m_ml->runOnMLThread<Ctx>(this,
+ //ML thread
+ [mrl](vlc_medialibrary_t *ml, Ctx &ctx)
+ {
+ ml_unique_ptr<vlc_ml_media_t> media {vlc_ml_get_media_by_mrl(ml, qtu(mrl))};
+ if (media)
+ ctx.media = MLMedia(media.get());
+ },
+ //UI thread
+ [this, mrl](quint64, Ctx &ctx)
+ {
+ if (!ctx.media.valid())
+ return; // failed to get media, TODO: notify??
+
+ setMedia(mrl, std::move(ctx.media));
+ });
+}
+
+void MLMediaStore::remove(const MLItemId &id)
+{
+ if (!m_mrls.contains(id))
+ return;
+
+ const QString mrl = m_mrls[id];
+
+ m_mrls.remove(id);
+ m_files.remove(mrl);
+}
+
+void MLMediaStore::clear()
+{
+ m_mrls.clear();
+}
+
+void MLMediaStore::onVlcMlEvent(void *data, const vlc_ml_event_t *event)
+{
+ auto self = static_cast<MLMediaStore*>(data);
+ switch (event->i_type)
+ {
+ case VLC_ML_EVENT_MEDIA_ADDED:
+ {
+ const vlc_ml_media_t *media = event->creation.p_media;
+ QString mrl;
+ for (const vlc_ml_file_t &file : ml_range_iterate<vlc_ml_file_t>(media->p_files))
+ {
+ if (file.i_type == VLC_ML_FILE_TYPE_MAIN)
+ {
+ mrl = QString::fromUtf8(file.psz_mrl);
+ break;
+ }
+ }
+
+ if (mrl.isEmpty())
+ break;
+
+ MLMedia mlMedia (media);
+ QMetaObject::invokeMethod(self, [self, mrl, mlMedia]()
+ {
+ self->setMedia(mrl, mlMedia);
+ });
+
+ break;
+ }
+
+ case VLC_ML_EVENT_MEDIA_UPDATED:
+ {
+ const MLItemId id(event->modification.i_entity_id, VLC_ML_PARENT_UNKNOWN);
+ QMetaObject::invokeMethod(self, [self, id] () mutable
+ {
+ self->update(id);
+ });
+
+ break;
+ }
+
+ case VLC_ML_EVENT_MEDIA_DELETED:
+ {
+ const MLItemId id{ event->deletion.i_entity_id, VLC_ML_PARENT_UNKNOWN };
+ QMetaObject::invokeMethod(self, [self, id]()
+ {
+ self->remove(id);
+ });
+
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void MLMediaStore::update(const MLItemId &id)
+{
+ if (!m_mrls.contains(id))
+ return;
+
+ struct Ctx
+ {
+ MLMedia media;
+ };
+
+ m_ml->runOnMLThread<Ctx>(this,
+ //ML thread
+ [id](vlc_medialibrary_t *ml, Ctx &ctx)
+ {
+ ml_unique_ptr<vlc_ml_media_t> media {vlc_ml_get_media(ml, id.id)};
+ ctx.media = media ? MLMedia(media.get()) : MLMedia {};
+ },
+ //UI thread
+ [this, id](quint64, Ctx &ctx)
+ {
+ if (!m_mrls.contains(id))
+ return; // item was removed?
+
+ const QString mrl = m_mrls[id];
+ emit updated(mrl, ctx.media);
+ }, UPDATE_QUEUE); // update in a single queue in case there
+ // is a overlap of same media update
+}
+
+void MLMediaStore::setMedia(const QString &mrl, MLMedia media)
+{
+ if (!m_files.contains(mrl))
+ return;
+
+ m_mrls[media.getId()] = mrl;
+ emit updated(mrl, media);
+}
=====================================
modules/gui/qt/medialibrary/mlmediastore.hpp
=====================================
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * Copyright (C) 2024 VLC authors and VideoLAN
+ *
+ * Authors: Prince Gupta <guptaprince8832 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#pragma once
+
+#include <vlc_media_library.h>
+
+#include <QObject>
+#include <QHash>
+#include <QSet>
+#include <QString>
+
+#include <memory>
+
+#include "mlmedia.hpp"
+
+class MediaLib;
+class MLItemId;
+class MLEvent;
+
+class MLMediaStore : public QObject
+{
+ Q_OBJECT
+
+public:
+ MLMediaStore(MediaLib *ml, QObject *parent = nullptr);
+ ~MLMediaStore();
+
+ void insert(const QString &mrl);
+ void remove(const MLItemId &id);
+ void clear();
+
+ bool contains(const QString &mrl) const;
+
+signals:
+ void updated(const QString &mrl, MLMedia media);
+
+private:
+ static void onVlcMlEvent(void* data
+ , const vlc_ml_event_t* event);
+
+ // updates associated Media
+ void update(const MLItemId &id);
+
+ void setMedia(const QString &mrl, MLMedia media);
+
+ MediaLib *m_ml;
+
+ std::unique_ptr<vlc_ml_event_callback_t,
+ std::function<void(vlc_ml_event_callback_t*)>> m_ml_event_handle;
+
+ // maintain set of MRL to handle media creation events
+ QSet<QString> m_files;
+
+ // MLEvent doesn't provide media mrl
+ // maintain a map for faster handling of ml events
+ QHash<MLItemId, QString> m_mrls;
+};
=====================================
modules/gui/qt/medialibrary/mlqmltypes.hpp
=====================================
@@ -27,11 +27,13 @@
#include <vlc_common.h>
#include <vlc_media_library.h>
+static constexpr int64_t INVALID_MLITEMID_ID = 0;
+
class MLItemId
{
Q_GADGET
public:
- MLItemId() : id(0), type( VLC_ML_PARENT_UNKNOWN ) {}
+ MLItemId() : id(INVALID_MLITEMID_ID), type( VLC_ML_PARENT_UNKNOWN ) {}
MLItemId( int64_t i, vlc_ml_parent_type t ) : id( i ), type( t ) {}
bool operator==( const MLItemId& other ) const
{
@@ -71,6 +73,12 @@ public:
}
};
+
+inline size_t qHash(const MLItemId& item, size_t seed = 0)
+{
+ return qHashMulti(seed, item.id, item.type);
+}
+
class MLItem
{
public:
=====================================
modules/gui/qt/meson.build
=====================================
@@ -78,6 +78,7 @@ moc_headers = files(
'maininterface/videosurface.hpp',
'maininterface/video_window_handler.hpp',
'medialibrary/medialib.hpp',
+ 'medialibrary/mlmediastore.hpp',
'medialibrary/mlalbum.hpp',
'medialibrary/mlalbummodel.hpp',
'medialibrary/mlalbumtrack.hpp',
@@ -90,6 +91,7 @@ moc_headers = files(
'medialibrary/mlgenremodel.hpp',
'medialibrary/mlthreadpool.hpp',
'medialibrary/mlqmltypes.hpp',
+ 'medialibrary/mlmedia.hpp',
'medialibrary/mlrecentsmodel.hpp',
'medialibrary/mlrecentsvideomodel.hpp',
'medialibrary/mlurlmodel.hpp',
@@ -300,6 +302,8 @@ some_sources = files(
'maininterface/windoweffects_module.hpp',
'medialibrary/medialib.cpp',
'medialibrary/medialib.hpp',
+ 'medialibrary/mlmediastore.cpp',
+ 'medialibrary/mlmediastore.hpp',
'medialibrary/mlalbum.cpp',
'medialibrary/mlalbum.hpp',
'medialibrary/mlalbummodel.cpp',
@@ -332,6 +336,7 @@ some_sources = files(
'medialibrary/mlthreadpool.cpp',
'medialibrary/mlthreadpool.hpp',
'medialibrary/mlqmltypes.hpp',
+ 'medialibrary/mlmedia.hpp',
'medialibrary/mlqueryparams.cpp',
'medialibrary/mlqueryparams.hpp',
'medialibrary/mlrecentsmodel.cpp',
=====================================
modules/gui/qt/network/networkmediamodel.cpp
=====================================
@@ -20,6 +20,8 @@
#include "mediatreelistener.hpp"
#include "maininterface/mainctx.hpp"
+#include "medialibrary/mlmedia.hpp"
+#include "medialibrary/mlmediastore.hpp"
#include "util/locallistbasemodel.hpp"
@@ -41,6 +43,7 @@ static const char* const ML_FOLDER_ADD_QUEUE = "ML_FOLDER_ADD_QUEUE";
struct NetworkMediaItem
{
QString name;
+ QString uri;
QUrl mainMrl;
QString protocol;
bool indexed;
@@ -50,6 +53,7 @@ struct NetworkMediaItem
QString artwork;
qint64 fileSize;
QDateTime fileModified;
+ MLMedia media;
};
using NetworkMediaItemPtr = std::shared_ptr<NetworkMediaItem>;
@@ -60,6 +64,20 @@ inline bool isADir(const NetworkMediaItemPtr& x)
return (x->type == NetworkMediaModel::ItemType::TYPE_DIRECTORY);
}
+int compareMediaDuration(const NetworkMediaItemPtr &l
+ , const NetworkMediaItemPtr &r)
+{
+ const bool lHasMedia = l->media.valid();
+ const bool rHasMedia = r->media.valid();
+ if (lHasMedia != rHasMedia) return lHasMedia ? 1 : - 1;
+ if (!lHasMedia && !rHasMedia) return 0;
+
+ const auto &lmedia = l->media.duration();
+ const auto &rmedia = r->media.duration();
+ if (lmedia == rmedia) return 0;
+ return lmedia > rmedia ? 1 : -1;
+}
+
}
// ListCache specialisation
@@ -93,22 +111,39 @@ public:
return nullptr;
}
- void setIntexedState(const NetworkMediaItemPtr& item, bool indexed)
+ void mediaUpdated(const QString &mrl, const MLMedia &media)
{
- if (item->indexed == indexed)
+ if (!m_items.contains(mrl))
return;
- auto it = std::find(m_items.begin(), m_items.end(), item);
- if (it != m_items.end())
- {
- //contruct by copy, don't mutate items in m_items,
- //we want the change to be notified
- auto newItem = std::make_shared<NetworkMediaItem>(*item);
- newItem->indexed = indexed;
-
- *it = newItem;
- ++m_revision;
- invalidateCache();
- }
+
+ //contruct by copy, don't mutate items in m_items,
+ //we want the change to be notified
+ auto newItem = std::make_shared<NetworkMediaItem>(*m_items[mrl]);
+ newItem->media = media;
+ m_items[mrl] = newItem;
+
+ ++m_revision;
+ invalidateCache();
+ }
+
+ void setIntexedState(const QString &uri, bool indexed)
+ {
+ auto itr = m_items.find(uri);
+ if (itr == m_items.end())
+ return;
+
+ auto &itemPtr = *itr;
+ if (itemPtr->indexed == indexed)
+ return;
+
+ //contruct by copy, don't mutate items in m_items,
+ //we want the change to be notified
+ auto newItem = std::make_shared<NetworkMediaItem>(*itemPtr);
+ newItem->indexed = indexed;
+
+ itemPtr = newItem;
+ ++m_revision;
+ invalidateCache();
}
void removeItem(const SharedInputItem& node, const std::vector<SharedInputItem>& itemsList)
@@ -129,8 +164,15 @@ public:
if ( it == m_items.end() )
continue;
+ if (m_MLMedias && (*it)->media.valid())
+ m_MLMedias->remove((*it)->media.getId());
+
m_items.erase( it );
}
+
+ // notify updates
+ ++m_revision;
+ invalidateCache();
}
void refreshMediaList(
@@ -141,7 +183,11 @@ public:
Q_Q(NetworkMediaModel);
if (clear)
+ {
m_items.clear();
+ if (m_MLMedias)
+ m_MLMedias->clear();
+ }
std::vector<NetworkMediaItem> items;
for (const auto& inputItem: children)
@@ -151,13 +197,13 @@ public:
item->protocol = "";
item->indexed = false;
item->type = static_cast<NetworkMediaModel::ItemType>(inputItem->i_type);
+ item->uri = QString(inputItem->psz_uri);
item->mainMrl = (item->type == NetworkMediaModel::TYPE_DIRECTORY || item->type == NetworkMediaModel::TYPE_NODE) ?
QUrl::fromEncoded(QByteArray(inputItem->psz_uri).append('/')) :
QUrl::fromEncoded(inputItem->psz_uri);
item->canBeIndexed = canBeIndexed( item->mainMrl , item->type );
-
input_item_t* intputItemRaw = inputItem.get();
char* str = input_item_GetArtworkURL(intputItemRaw);
if (str)
@@ -195,21 +241,31 @@ public:
bool succeed;
bool isIndexed;
};
+
+ const QString uri = item->uri;
m_mediaLib->runOnMLThread<Ctx>(q,
//ML thread
- [item](vlc_medialibrary_t* ml, Ctx& ctx){
- auto ret = vlc_ml_is_indexed( ml, qtu(item->mainMrl.toString( QUrl::FullyEncoded )), &ctx.isIndexed );
+ [uri](vlc_medialibrary_t* ml, Ctx& ctx){
+ // Medialibrary requires folders uri to be terminated with '/'
+ const QString mlURI = uri + "/";
+
+ auto ret = vlc_ml_is_indexed( ml, qtu( mlURI ), &ctx.isIndexed );
ctx.succeed = (ret == VLC_SUCCESS);
},
//UI thread
- [this, item](quint64, Ctx& ctx){
+ [this, uri](quint64, Ctx& ctx){
if (!ctx.succeed)
return;
- setIntexedState(item, ctx.isIndexed);
+
+ setIntexedState(uri, ctx.isIndexed);
});
}
- m_items.push_back(item);
+ m_items[item->uri] = item;
+ if (m_MLMedias && (item->type == NetworkMediaModel::TYPE_FILE))
+ {
+ m_MLMedias->insert(item->uri);
+ }
}
++m_revision;
@@ -266,6 +322,21 @@ public:
return a->fileModified > b->fileModified;
};
}
+ else if (m_sortCriteria == "duration")
+ {
+ if (m_sortOrder == Qt::SortOrder::DescendingOrder)
+ return [](const NetworkMediaItemPtr& a, const NetworkMediaItemPtr& b) -> bool
+ {
+ if(isADir(a) != isADir(b)) return isADir(a);
+ return compareMediaDuration(a, b) > 0;
+ };
+ else
+ return [](const NetworkMediaItemPtr& a, const NetworkMediaItemPtr& b) -> bool
+ {
+ if(isADir(a) != isADir(b)) return isADir(a);
+ return compareMediaDuration(a, b) < 0;
+ };
+ }
else // m_sortCriteria == "name"
{
if (m_sortOrder == Qt::SortOrder::DescendingOrder)
@@ -380,15 +451,14 @@ public:
protected:
std::vector<NetworkMediaItemPtr> getModelData(const QString& pattern) const override
{
- if (pattern.isEmpty())
- return m_items;
std::vector<NetworkMediaItemPtr> items;
- std::copy_if(
- m_items.cbegin(), m_items.cend(),
- std::back_inserter(items),
- [&pattern](const NetworkMediaItemPtr& item){
- return item->name.contains(pattern, Qt::CaseInsensitive);
- });
+ items.reserve(m_items.size() / 2);
+ for (const auto &item : m_items)
+ {
+ if (item->name.contains(pattern, Qt::CaseInsensitive))
+ items.push_back(item);
+ }
+
return items;
}
@@ -397,7 +467,8 @@ public:
bool m_hasTree = false;
QSemaphore m_preparseSem;
std::unique_ptr<MediaTreeListener> m_listener;
- std::vector<NetworkMediaItemPtr> m_items;
+ QHash<QString, NetworkMediaItemPtr> m_items;
+ std::unique_ptr<MLMediaStore> m_MLMedias;
};
// NetworkMediaModel::ListenerCb implementation
@@ -459,11 +530,45 @@ QVariant NetworkMediaModel::data( const QModelIndex& index, int role ) const
case NETWORK_TREE:
return QVariant::fromValue( item->tree );
case NETWORK_ARTWORK:
- return item->artwork;
+ {
+ if (!item->artwork.isEmpty())
+ return item->artwork;
+
+ /// XXX: request medialibrary for thumbnail if not available??
+ const MLMedia &media = item->media;
+ if (media.valid())
+ {
+ const QString bannerCover = media.bannerCover();
+ return !bannerCover.isEmpty() ? bannerCover : media.smallCover();
+ }
+
+ return {};
+ }
case NETWORK_FILE_SIZE:
return item->fileSize;
case NETWORK_FILE_MODIFIED:
return item->fileModified;
+ case NETWORK_MEDIA:
+ return item->media.valid()
+ ? QVariant::fromValue(item->media)
+ : QVariant {};
+ case NETWORK_MEDIA_PROGRESS:
+ {
+ if (item->media.valid())
+ return item->media.progress();
+
+ return {};
+ }
+ case NETWORK_MEDIA_DURATION:
+ {
+ if (item->media.valid())
+ {
+ const VLCTick duration = item->media.duration();
+ return duration <= 0 ? QVariant {} : QVariant::fromValue(duration);
+ }
+
+ return {};
+ }
default:
return {};
}
@@ -481,7 +586,10 @@ QHash<int, QByteArray> NetworkMediaModel::roleNames() const
{ NETWORK_TREE, "tree" },
{ NETWORK_ARTWORK, "artwork" },
{ NETWORK_FILE_SIZE, "fileSizeRaw64" },
- { NETWORK_FILE_MODIFIED, "fileModified" }
+ { NETWORK_FILE_MODIFIED, "fileModified" },
+ { NETWORK_MEDIA, "media" },
+ { NETWORK_MEDIA_PROGRESS, "progress" },
+ { NETWORK_MEDIA_DURATION, "duration" }
};
}
@@ -511,27 +619,36 @@ bool NetworkMediaModel::setData( const QModelIndex& idx, const QVariant& value,
if ( item->indexed == enabled )
return true;
- QUrl mainMrl = item->mainMrl;
- struct Ctx {
+ struct Ctx
+ {
bool succeed;
};
+
+ const QString uri = item->uri;
+
d->m_mediaLib->runOnMLThread<Ctx>(this,
//ML thread
- [enabled, mainMrl]
+ [enabled, uri]
(vlc_medialibrary_t* ml, Ctx& ctx){
int res;
+
+ // Medialibrary requires folders uri to be terminated with '/'
+ const QString mlURI = uri + "/";
+
if ( enabled )
- res = vlc_ml_add_folder( ml, qtu( mainMrl.toString( QUrl::FullyEncoded ) ) );
+ res = vlc_ml_add_folder( ml, qtu( mlURI ) );
else
- res = vlc_ml_remove_folder( ml, qtu( mainMrl.toString( QUrl::FullyEncoded ) ) );
+ res = vlc_ml_remove_folder( ml, qtu( mlURI ) );
+
ctx.succeed = res == VLC_SUCCESS;
},
//UI thread
- [this, item, enabled](qint64, Ctx& ctx){
+ [this, uri, enabled](qint64, Ctx& ctx){
Q_D(NetworkMediaModel);
if (!ctx.succeed)
return;
- d->setIntexedState(item, enabled);
+
+ d->setIntexedState(uri, enabled);
},
ML_FOLDER_ADD_QUEUE);
@@ -581,6 +698,17 @@ void NetworkMediaModel::setCtx(MainCtx* ctx)
m_ctx = ctx;
d->m_mediaLib = ctx->getMediaLibrary();
+ d->m_MLMedias.reset();
+ if (d->m_mediaLib)
+ {
+ d->m_MLMedias.reset(new MLMediaStore(d->m_mediaLib));
+ connect(d->m_MLMedias.get(), &MLMediaStore::updated, this, [this](const QString &mrl, const MLMedia &media)
+ {
+ Q_D(NetworkMediaModel);
+ d->mediaUpdated(mrl, media);
+ });
+ }
+
d->initializeModel();
emit ctxChanged();
}
=====================================
modules/gui/qt/network/networkmediamodel.hpp
=====================================
@@ -117,6 +117,9 @@ public:
NETWORK_ARTWORK,
NETWORK_FILE_SIZE,
NETWORK_FILE_MODIFIED,
+ NETWORK_MEDIA,
+ NETWORK_MEDIA_PROGRESS,
+ NETWORK_MEDIA_DURATION,
};
enum ItemType{
=====================================
modules/gui/qt/network/qml/BrowseTreeDisplay.qml
=====================================
@@ -267,6 +267,18 @@ MainInterface.MainViewLoader {
showContextButton: true
}
+ }, {
+ size: 1,
+
+ model: {
+ criteria: "duration",
+
+ text: qsTr("Duration"),
+
+ showContextButton: true,
+ headerDelegate: tableColumns.timeHeaderDelegate,
+ colDelegate: tableColumns.timeColDelegate
+ }
}]
dragItem: networkDragItem
@@ -307,6 +319,10 @@ MainInterface.MainViewLoader {
onRightClick: (_,_,globalMousePos) => {
contextMenu.popup(selectionModel.selectedIndexes, globalMousePos)
}
+
+ Widgets.TableColumns {
+ id: tableColumns
+ }
}
}
=====================================
modules/gui/qt/network/qml/NetworkGridItem.qml
=====================================
@@ -23,6 +23,7 @@ import Qt5Compat.GraphicalEffects
import org.videolan.vlc 0.1
import "qrc:///widgets/" as Widgets
+import "qrc:///util/Helpers.js" as Helpers
import "qrc:///style/"
Widgets.GridItem {
@@ -78,12 +79,34 @@ Widgets.GridItem {
title: model.name || qsTr("Unknown share")
subtitle: {
- if (!model.mrl) {
- return ""
- } else if ((model.type === NetworkMediaModel.TYPE_NODE || model.type === NetworkMediaModel.TYPE_DIRECTORY) && model.mrl.toString() === "vlc://nop") {
- return ""
- } else {
- return model.mrl
- }
+ if (!model.mrl) {
+ return ""
+ } else if ((model.type === NetworkMediaModel.TYPE_NODE || model.type === NetworkMediaModel.TYPE_DIRECTORY) && model.mrl.toString() === "vlc://nop") {
+ return ""
+ } else {
+ return model.mrl
+ }
+ }
+
+ pictureOverlay: Item {
+ width: root.pictureWidth
+ height: root.pictureHeight
+
+ Widgets.VideoProgressBar {
+ id: progressBar
+
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+
+ visible: (model.progress ?? - 1) > 0
+
+ radius: root.pictureRadius
+ value: visible
+ ? Helpers.clamp(model.progress, 0, 1)
+ : 0
+ }
}
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/8186585a1e1db8ce7b14c61e0123618378042e6e...31b383f5fe84e8ace741b4f28aafa467cc5b0b92
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/8186585a1e1db8ce7b14c61e0123618378042e6e...31b383f5fe84e8ace741b4f28aafa467cc5b0b92
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list