vlc | branch: master | Hugo Beauzée-Luyssen <[email protected]> | Mon Mar 2 15:52:50 2020 +0100| [c287ab86034daf98d8b3a2459326dbb9c272319e] | committer: Hugo Beauzée-Luyssen
medialib: Bump contrib version & adapt to API changes This moves the network device management in a specific IDeviceLister implementation, and now handles all filesystem (local and network) from the same code > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c287ab86034daf98d8b3a2459326dbb9c272319e --- configure.ac | 2 +- ...dialibrary-IDeviceLister.h-Include-string.patch | 25 --- ...se-GetFullPathNameW-for-the-wide-char-API.patch | 26 --- contrib/src/medialibrary/rules.mak | 6 +- modules/misc/Makefile.am | 2 + modules/misc/medialibrary/fs/device.cpp | 112 ++++++----- modules/misc/medialibrary/fs/device.h | 25 ++- modules/misc/medialibrary/fs/devicelister.cpp | 177 ++++++++++++++++++ modules/misc/medialibrary/fs/devicelister.h | 91 +++++++++ modules/misc/medialibrary/fs/directory.h | 12 +- modules/misc/medialibrary/fs/fs.cpp | 208 ++++++++------------- modules/misc/medialibrary/fs/fs.h | 32 ++-- modules/misc/medialibrary/medialib.cpp | 77 ++++---- modules/misc/medialibrary/medialibrary.h | 29 +-- 14 files changed, 526 insertions(+), 298 deletions(-) diff --git a/configure.ac b/configure.ac index 977029016e..e6fb7da932 100644 --- a/configure.ac +++ b/configure.ac @@ -4441,7 +4441,7 @@ dnl Libnotify notification plugin dnl PKG_ENABLE_MODULES_VLC([NOTIFY], [], [libnotify], [libnotify notification], [auto]) -PKG_ENABLE_MODULES_VLC([MEDIALIBRARY], [medialibrary], [medialibrary >= 0.7.1], (medialibrary support), [auto]) +PKG_ENABLE_MODULES_VLC([MEDIALIBRARY], [medialibrary], [medialibrary >= 0.8.0], (medialibrary support), [auto]) dnl dnl Endianness check diff --git a/contrib/src/medialibrary/0001-include-medialibrary-IDeviceLister.h-Include-string.patch b/contrib/src/medialibrary/0001-include-medialibrary-IDeviceLister.h-Include-string.patch deleted file mode 100644 index 0827a7e09b..0000000000 --- a/contrib/src/medialibrary/0001-include-medialibrary-IDeviceLister.h-Include-string.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 168ae35bde46a713bf08cbb4bc3456a427531e32 Mon Sep 17 00:00:00 2001 -From: Christopher Degawa <[email protected]> -Date: Wed, 13 May 2020 19:53:28 +0000 -Subject: [PATCH] include/medialibrary/IDeviceLister.h: Include string - -`std::string` is used, but string is not included, causing errors when compiling with mingw-w64 ---- - include/medialibrary/IDeviceLister.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/medialibrary/IDeviceLister.h b/include/medialibrary/IDeviceLister.h -index f6324610..299e5995 100644 ---- a/include/medialibrary/IDeviceLister.h -+++ b/include/medialibrary/IDeviceLister.h -@@ -24,6 +24,7 @@ - - #include <tuple> - #include <vector> -+#include <string> - - namespace medialibrary - { --- -2.26.0.windows.1 - diff --git a/contrib/src/medialibrary/0001-use-GetFullPathNameW-for-the-wide-char-API.patch b/contrib/src/medialibrary/0001-use-GetFullPathNameW-for-the-wide-char-API.patch deleted file mode 100644 index e2222565c7..0000000000 --- a/contrib/src/medialibrary/0001-use-GetFullPathNameW-for-the-wide-char-API.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 2ac516186cd23213f7ef290c7aab9a16c7bdceba Mon Sep 17 00:00:00 2001 -From: Steve Lhomme <[email protected]> -Date: Fri, 3 Apr 2020 15:09:35 +0200 -Subject: [PATCH] use GetFullPathNameW for the wide char API - -Fixes the build with mingw64 in winrt mode. ---- - src/utils/Directory.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/utils/Directory.cpp b/src/utils/Directory.cpp -index b34fab28..fdfd6e66 100644 ---- a/src/utils/Directory.cpp -+++ b/src/utils/Directory.cpp -@@ -91,7 +91,7 @@ std::string toAbsolute( const std::string& path ) - #else - wchar_t buff[MAX_PATH]; - auto wpath = charset::ToWide( path.c_str() ); -- if ( GetFullPathName( wpath.get(), MAX_PATH, buff, nullptr ) == 0 ) -+ if ( GetFullPathNameW( wpath.get(), MAX_PATH, buff, nullptr ) == 0 ) - { - LOG_ERROR( "Failed to convert ", path, " to absolute path" ); - throw errors::System{ GetLastError(), "Failed to convert to absolute path" }; --- -2.26.0.windows.1 - diff --git a/contrib/src/medialibrary/rules.mak b/contrib/src/medialibrary/rules.mak index dac169e946..1d95831841 100644 --- a/contrib/src/medialibrary/rules.mak +++ b/contrib/src/medialibrary/rules.mak @@ -1,9 +1,9 @@ -MEDIALIBRARY_HASH := 137eb0ac50c0c8493421c8e209c2c4b16195aec5 +MEDIALIBRARY_HASH := cfc889fcd97ee9b1a71e100888715389025b12ea MEDIALIBRARY_VERSION := git-$(MEDIALIBRARY_HASH) MEDIALIBRARY_GITURL := https://code.videolan.org/videolan/medialibrary.git PKGS += medialibrary -ifeq ($(call need_pkg,"medialibrary >= 0.7.1"),) +ifeq ($(call need_pkg,"medialibrary >= 0.8"),) PKGS_FOUND += medialibrary endif @@ -20,8 +20,6 @@ medialibrary: medialibrary-$(MEDIALIBRARY_VERSION).tar.xz .sum-medialibrary rm -rf $@-$(MEDIALIBRARY_VERSION) $@ mkdir -p $@-$(MEDIALIBRARY_VERSION) tar xvf "$<" --strip-components=1 -C $@-$(MEDIALIBRARY_VERSION) - $(APPLY) $(SRC)/medialibrary/0001-include-medialibrary-IDeviceLister.h-Include-string.patch - $(APPLY) $(SRC)/medialibrary/0001-use-GetFullPathNameW-for-the-wide-char-API.patch $(call pkg_static, "medialibrary.pc.in") $(UPDATE_AUTOCONFIG) $(MOVE) diff --git a/modules/misc/Makefile.am b/modules/misc/Makefile.am index 78f9b09710..8f84c3c3dd 100644 --- a/modules/misc/Makefile.am +++ b/modules/misc/Makefile.am @@ -119,6 +119,8 @@ libmedialibrary_plugin_la_SOURCES = \ misc/medialibrary/fs/file.cpp \ misc/medialibrary/fs/fs.h \ misc/medialibrary/fs/fs.cpp \ + misc/medialibrary/fs/devicelister.cpp \ + misc/medialibrary/fs/devicelister.h \ misc/medialibrary/fs/util.h \ misc/medialibrary/fs/util.cpp diff --git a/modules/misc/medialibrary/fs/device.cpp b/modules/misc/medialibrary/fs/device.cpp index 88b655dc5f..226f158bad 100644 --- a/modules/misc/medialibrary/fs/device.cpp +++ b/modules/misc/medialibrary/fs/device.cpp @@ -23,8 +23,6 @@ #endif #include "device.h" -#include <vlc_common.h> -#include <vlc_url.h> #include <algorithm> #include <cassert> @@ -33,14 +31,12 @@ namespace vlc { namespace medialibrary { -SDDevice::SDDevice( const std::string& uuid, std::string mrl ) +SDDevice::SDDevice(const std::string& uuid, std::string scheme, bool removable, bool isNetwork) : m_uuid(uuid) + , m_scheme( std::move( scheme ) ) + , m_removable(removable) + , m_isNetwork(isNetwork) { - // Ensure the mountpoint always ends with a '/' to avoid mismatch between - // smb://foo and smb://foo/ - if ( *mrl.crbegin() != '/' ) - mrl += '/'; - m_mountpoints.push_back( std::move( mrl ) ); } const std::string & @@ -52,7 +48,7 @@ SDDevice::uuid() const bool SDDevice::isRemovable() const { - return true; + return m_removable; } bool @@ -61,20 +57,42 @@ SDDevice::isPresent() const return m_mountpoints.empty() == false; } +bool SDDevice::isNetwork() const +{ + return m_isNetwork; +} + const std::string &SDDevice::mountpoint() const { - return m_mountpoints[0]; + return m_mountpoints[0].mrl; } void SDDevice::addMountpoint( std::string mrl ) { - m_mountpoints.push_back( std::move( mrl ) ); + // Ensure the mountpoint always ends with a '/' to avoid mismatch between + // smb://foo and smb://foo/ + if ( *mrl.crbegin() != '/' ) + mrl += '/'; + auto it = std::find_if( cbegin( m_mountpoints ), cend( m_mountpoints ), + [&mrl]( const Mountpoint& mp ) { return mp.mrl == mrl; } ); + if ( it != cend( m_mountpoints ) ) + return; + + try + { + auto mp = Mountpoint{ std::move( mrl ) }; + m_mountpoints.push_back( std::move( mp ) ); + } + catch ( const vlc::url::invalid& ) + { + } } void SDDevice::removeMountpoint( const std::string& mrl ) { - auto it = std::find( begin( m_mountpoints ), end( m_mountpoints ), mrl ); + auto it = std::find_if( begin( m_mountpoints ), end( m_mountpoints ), + [&mrl]( const Mountpoint& mp ) { return mp.mrl == mrl; } ); if ( it != end( m_mountpoints ) ) m_mountpoints.erase( it ); } @@ -82,24 +100,31 @@ void SDDevice::removeMountpoint( const std::string& mrl ) std::tuple<bool, std::string> SDDevice::matchesMountpoint( const std::string& mrl ) const { - vlc_url_t probedUrl; - vlc_UrlParse( &probedUrl, mrl.c_str() ); + vlc::url probedUrl; + try + { + probedUrl = vlc::url{ mrl }; + } + catch ( const vlc::url::invalid& ) + { + return std::make_tuple( false, "" ); + } for ( const auto& m : m_mountpoints ) { - vlc_url_t url; - vlc_UrlParse( &url, m.c_str() ); - if ( strcasecmp( probedUrl.psz_protocol, url.psz_protocol ) ) - { - vlc_UrlClean( &url ); + if ( strcasecmp( probedUrl.psz_protocol, m.url.psz_protocol ) ) continue; - } - if ( strcasecmp( probedUrl.psz_host, url.psz_host ) ) + if ( strcasecmp( probedUrl.psz_host, m.url.psz_host ) ) + continue; + /* Ignore path for plain network hosts, ie. without any path specified */ + if ( m.url.psz_path != nullptr && *m.url.psz_path != 0 && + probedUrl.psz_path != nullptr && + strncasecmp( m.url.psz_path, probedUrl.psz_path, + strlen( m.url.psz_path ) ) != 0 ) { - vlc_UrlClean( &url ); continue; } - if ( probedUrl.i_port != url.i_port ) + if ( probedUrl.i_port != m.url.i_port ) { unsigned int defaultPort = 0; if ( !strcasecmp( probedUrl.psz_protocol, "smb" ) ) @@ -107,35 +132,23 @@ SDDevice::matchesMountpoint( const std::string& mrl ) const if ( defaultPort != 0 ) { if ( probedUrl.i_port != 0 && probedUrl.i_port != defaultPort && - url.i_port != 0 && url.i_port != defaultPort ) + m.url.i_port != 0 && m.url.i_port != defaultPort ) { - vlc_UrlClean( &url ); continue; } - else - { - url.i_port = probedUrl.i_port; - char* tmpUrl_psz = vlc_uri_compose(&url); - vlc_UrlClean( &url ); - if (!tmpUrl_psz) - continue; - std::string tmpUrl(tmpUrl_psz); - free(tmpUrl_psz); - vlc_UrlClean( &probedUrl ); - return std::make_tuple( true, tmpUrl ); - } - } - else - { - vlc_UrlClean( &url ); - continue; + vlc_url_t url = m.url; + url.i_port = probedUrl.i_port; + char* tmpUrl_psz = vlc_uri_compose(&url); + if (!tmpUrl_psz) + continue; + std::string tmpUrl(tmpUrl_psz); + free(tmpUrl_psz); + return std::make_tuple( true, tmpUrl ); } + continue; } - vlc_UrlClean( &url ); - vlc_UrlClean( &probedUrl ); - return std::make_tuple( true, m ); + return std::make_tuple( true, m.mrl ); } - vlc_UrlClean( &probedUrl ); return std::make_tuple( false, "" ); } @@ -151,7 +164,12 @@ std::string SDDevice::relativeMrl( const std::string& absoluteMrl ) const std::string SDDevice::absoluteMrl( const std::string& relativeMrl ) const { assert( m_mountpoints.empty() == false ); - return m_mountpoints[0] + relativeMrl; + return m_mountpoints[0].mrl + relativeMrl; +} + +const std::string& SDDevice::scheme() const +{ + return m_scheme; } } /* namespace medialibrary */ diff --git a/modules/misc/medialibrary/fs/device.h b/modules/misc/medialibrary/fs/device.h index 0ee6984d99..ba9eb2822a 100644 --- a/modules/misc/medialibrary/fs/device.h +++ b/modules/misc/medialibrary/fs/device.h @@ -24,6 +24,10 @@ #include <medialibrary/filesystem/IDevice.h> #include <vector> +#include <vlc_common.h> +#include <vlc_url.h> +#include <vlc_cxx_helpers.hpp> + namespace vlc { namespace medialibrary { @@ -32,22 +36,37 @@ using namespace ::medialibrary::fs; class SDDevice : public IDevice { public: - SDDevice( const std::string& uuid, std::string mrl ); + SDDevice(const std::string& uuid, std::string scheme, + bool removable, bool isNetwork); const std::string &uuid() const override; bool isRemovable() const override; bool isPresent() const override; + bool isNetwork() const override; const std::string &mountpoint() const override; void addMountpoint( std::string mrl ) override; void removeMountpoint( const std::string& mrl ) override; std::tuple<bool, std::string> matchesMountpoint( const std::string& mrl ) const override; std::string relativeMrl( const std::string& absoluteMrl ) const override; std::string absoluteMrl( const std::string& relativeMrl ) const override; - + const std::string& scheme() const override; private: + struct Mountpoint + { + Mountpoint( std::string m ) + : mrl( std::move( m ) ) + , url( mrl ) + { + } + std::string mrl; + vlc::url url; + }; std::string m_uuid; - std::vector<std::string> m_mountpoints; + std::vector<Mountpoint> m_mountpoints; + std::string m_scheme; + bool m_removable; + bool m_isNetwork; }; } /* namespace medialibrary */ diff --git a/modules/misc/medialibrary/fs/devicelister.cpp b/modules/misc/medialibrary/fs/devicelister.cpp new file mode 100644 index 0000000000..a93ce9bf37 --- /dev/null +++ b/modules/misc/medialibrary/fs/devicelister.cpp @@ -0,0 +1,177 @@ +/***************************************************************************** + * devicelister.h: Media library network file system + ***************************************************************************** + * Copyright (C) 2018 VLC authors, VideoLAN and VideoLabs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + *****************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "devicelister.h" + +#include <vlc_services_discovery.h> + +namespace vlc +{ +namespace medialibrary +{ + +DeviceLister::DeviceLister( vlc_object_t* parent ) + : m_parent( parent ) +{ +} + +void DeviceLister::refresh() +{ + /* + * This can be left empty since we always propagate devices changes through + * the media source/media tree callbacks + */ +} + +bool DeviceLister::start( ml::IDeviceListerCb* cb ) +{ + vlc::threads::mutex_locker lock( m_mutex ); + + auto provider = vlc_media_source_provider_Get( vlc_object_instance( m_parent ) ); + + using SourceMetaPtr = std::unique_ptr<vlc_media_source_meta_list_t, + decltype( &vlc_media_source_meta_list_Delete )>; + + SourceMetaPtr providerList{ + vlc_media_source_provider_List( provider, SD_CAT_LAN ), + &vlc_media_source_meta_list_Delete + }; + + m_cb = cb; + + auto nbProviders = vlc_media_source_meta_list_Count( providerList.get() ); + + for ( auto i = 0u; i < nbProviders; ++i ) + { + auto meta = vlc_media_source_meta_list_Get( providerList.get(), i ); + auto mediaSource = vlc_media_source_provider_GetMediaSource( provider, + meta->name ); + if ( mediaSource == nullptr ) + continue; + MediaSource s{ mediaSource }; + + static const vlc_media_tree_callbacks cbs { + &onChildrenReset, &onChildrenAdded, &onChildrenRemoved, nullptr + }; + + s.l = vlc_media_tree_AddListener( s.s->tree, &cbs, this, true ); + m_mediaSources.push_back( std::move( s ) ); + } + return m_mediaSources.empty() == false; +} + +void DeviceLister::stop() +{ + vlc::threads::mutex_locker lock( m_mutex ); + + m_mediaSources.clear(); + m_cb = nullptr; +} + +void DeviceLister::onChildrenReset( vlc_media_tree_t* tree, input_item_node_t* node, + void* data ) +{ + auto self = static_cast<DeviceLister*>( data ); + self->onChildrenReset( tree, node ); +} + +void DeviceLister::onChildrenAdded( vlc_media_tree_t* tree, input_item_node_t* node, + input_item_node_t* const children[], size_t count, + void* data ) +{ + auto self = static_cast<DeviceLister*>( data ); + self->onChildrenAdded( tree, node, children, count ); +} + +void DeviceLister::onChildrenRemoved( vlc_media_tree_t* tree, input_item_node_t* node, + input_item_node_t* const children[], size_t count, + void* data ) +{ + auto self = static_cast<DeviceLister*>( data ); + self->onChildrenRemoved( tree, node, children, count ); +} + +void DeviceLister::onChildrenReset( vlc_media_tree_t* tree, input_item_node_t* ) +{ + for ( auto i = 0; i < tree->root.i_children; ++i ) + { + auto c = tree->root.pp_children[i]; + m_cb->onDeviceMounted( c->p_item->psz_name, c->p_item->psz_uri, true ); + } +} + +void DeviceLister::onChildrenAdded( vlc_media_tree_t*, input_item_node_t*, + input_item_node_t* const children[], size_t count ) +{ + for ( auto i = 0u; i < count; ++i ) + { + auto c = children[i]; + m_cb->onDeviceMounted( c->p_item->psz_name, c->p_item->psz_uri, true ); + } +} + +void DeviceLister::onChildrenRemoved(vlc_media_tree_t*, input_item_node_t*, + input_item_node_t* const children[], size_t count ) +{ + for ( auto i = 0u; i < count; ++i ) + { + auto c = children[i]; + m_cb->onDeviceUnmounted( c->p_item->psz_name, c->p_item->psz_uri ); + } +} + +DeviceLister::MediaSource::MediaSource( vlc_media_source_t *ms ) + : s( ms ) + , l( nullptr ) +{ +} + +DeviceLister::MediaSource::~MediaSource() +{ + if ( l != nullptr ) + vlc_media_tree_RemoveListener( s->tree, l ); + if ( s != nullptr ) + vlc_media_source_Release( s ); +} + +DeviceLister::MediaSource::MediaSource( DeviceLister::MediaSource&& rhs ) noexcept + : s( rhs.s ) + , l( rhs.l ) +{ + rhs.s = nullptr; + rhs.l = nullptr; +} + +DeviceLister::MediaSource& +DeviceLister::MediaSource::operator=( DeviceLister::MediaSource&& rhs ) noexcept +{ + s = rhs.s; + l = rhs.l; + rhs.s = nullptr; + rhs.l = nullptr; + return *this; +} + +} +} diff --git a/modules/misc/medialibrary/fs/devicelister.h b/modules/misc/medialibrary/fs/devicelister.h new file mode 100644 index 0000000000..ffd7e11d50 --- /dev/null +++ b/modules/misc/medialibrary/fs/devicelister.h @@ -0,0 +1,91 @@ +/***************************************************************************** + * devicelister.h: Media library network file system + ***************************************************************************** + * Copyright (C) 2018 VLC authors, VideoLAN and VideoLabs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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. + *****************************************************************************/ + +#ifndef ML_DEVICELISTER_H +#define ML_DEVICELISTER_H + +#include <medialibrary/IDeviceLister.h> + +#include <vlc_media_source.h> +#include <vlc_threads.h> +#include <vlc_cxx_helpers.hpp> + +#include <memory> + +namespace vlc +{ +namespace medialibrary +{ + +namespace ml = ::medialibrary; + +class DeviceLister : public ml::IDeviceLister +{ +public: + DeviceLister(vlc_object_t* parent); + +private: + /* + * Only used by the media library through the IDeviceLister interface, so + * it's fine to keep those private for the implementation + */ + virtual void refresh() override; + virtual bool start( ml::IDeviceListerCb* cb ) override; + virtual void stop() override; + + static void onChildrenReset( vlc_media_tree_t* tree, input_item_node_t* node, + void* data ); + static void onChildrenAdded( vlc_media_tree_t* tree, input_item_node_t* node, + input_item_node_t* const children[], size_t count, + void *data ); + static void onChildrenRemoved( vlc_media_tree_t* tree, input_item_node_t* node, + input_item_node_t* const children[], size_t count, + void* data ); + + + void onChildrenReset( vlc_media_tree_t* tree, input_item_node_t* node ); + void onChildrenAdded( vlc_media_tree_t* tree, input_item_node_t* node, + input_item_node_t* const children[], size_t count ); + void onChildrenRemoved( vlc_media_tree_t* tree, input_item_node_t* node, + input_item_node_t* const children[], size_t count ); + +private: + vlc_object_t* m_parent; + ml::IDeviceListerCb* m_cb; + vlc::threads::mutex m_mutex; + struct MediaSource + { + MediaSource( vlc_media_source_t* ); + ~MediaSource(); + MediaSource( const MediaSource& ) = delete; + MediaSource& operator=( const MediaSource& ) = delete; + MediaSource( MediaSource&& ) noexcept; + MediaSource& operator=( MediaSource&& ) noexcept; + vlc_media_source_t* s; + vlc_media_tree_listener_id* l; + }; + std::vector<MediaSource> m_mediaSources; +}; + +} +} + + +#endif // ML_DEVICELISTER_H diff --git a/modules/misc/medialibrary/fs/directory.h b/modules/misc/medialibrary/fs/directory.h index 948cd7eca2..c73ef1b1a3 100644 --- a/modules/misc/medialibrary/fs/directory.h +++ b/modules/misc/medialibrary/fs/directory.h @@ -36,10 +36,10 @@ class SDDirectory : public IDirectory public: explicit SDDirectory(const std::string &mrl, SDFileSystemFactory &fs); const std::string &mrl() const override; - const std::vector<std::shared_ptr<IFile>> &files() const override; - const std::vector<std::shared_ptr<IDirectory>> &dirs() const override; - std::shared_ptr<IDevice> device() const override; - std::shared_ptr<IFile> file( const std::string& mrl ) const override; + const std::vector<std::shared_ptr<fs::IFile>> &files() const override; + const std::vector<std::shared_ptr<fs::IDirectory>> &dirs() const override; + std::shared_ptr<fs::IDevice> device() const override; + std::shared_ptr<fs::IFile> file( const std::string& mrl ) const override; private: void read() const; @@ -48,8 +48,8 @@ private: SDFileSystemFactory &m_fs; mutable bool m_read_done = false; - mutable std::vector<std::shared_ptr<IFile>> m_files; - mutable std::vector<std::shared_ptr<IDirectory>> m_dirs; + mutable std::vector<std::shared_ptr<fs::IFile>> m_files; + mutable std::vector<std::shared_ptr<fs::IDirectory>> m_dirs; mutable std::shared_ptr<IDevice> m_device; }; diff --git a/modules/misc/medialibrary/fs/fs.cpp b/modules/misc/medialibrary/fs/fs.cpp index 8d0375bf13..b8d326a3f0 100644 --- a/modules/misc/medialibrary/fs/fs.cpp +++ b/modules/misc/medialibrary/fs/fs.cpp @@ -22,45 +22,16 @@ # include "config.h" #endif -#include "fs.h" - #include <algorithm> #include <vlc_services_discovery.h> #include <medialibrary/IDeviceLister.h> #include <medialibrary/filesystem/IDevice.h> +#include <medialibrary/IMediaLibrary.h> #include "device.h" #include "directory.h" #include "util.h" - -extern "C" { - -static void -services_discovery_item_added(services_discovery_t *sd, - input_item_t *parent, input_item_t *media, - const char *cat) -{ - VLC_UNUSED(parent); - VLC_UNUSED(cat); - vlc::medialibrary::SDFileSystemFactory *that = - static_cast<vlc::medialibrary::SDFileSystemFactory *>(sd->owner.sys); - that->onDeviceAdded(media); -} - -static void -services_discovery_item_removed(services_discovery_t *sd, input_item_t *media) -{ - vlc::medialibrary::SDFileSystemFactory *that = - static_cast<vlc::medialibrary::SDFileSystemFactory *>(sd->owner.sys); - that->onDeviceRemoved(media); -} - -static const struct services_discovery_callbacks sd_cbs = { - .item_added = services_discovery_item_added, - .item_removed = services_discovery_item_removed, -}; - -} +#include "fs.h" namespace vlc { namespace medialibrary { @@ -68,19 +39,25 @@ namespace vlc { using namespace ::medialibrary; SDFileSystemFactory::SDFileSystemFactory(vlc_object_t *parent, + IMediaLibrary* ml, const std::string &scheme) : m_parent(parent) + , m_ml( ml ) , m_scheme(scheme) + , m_deviceLister( m_ml->deviceLister( scheme ) ) + , m_callbacks( nullptr ) { + m_isNetwork = strncasecmp( m_scheme.c_str(), "file://", + m_scheme.length() ) != 0; } -std::shared_ptr<IDirectory> +std::shared_ptr<fs::IDirectory> SDFileSystemFactory::createDirectory(const std::string &mrl) { return std::make_shared<SDDirectory>(mrl, *this); } -std::shared_ptr<IFile> +std::shared_ptr<fs::IFile> SDFileSystemFactory::createFile(const std::string& mrl) { auto dir = createDirectory(mrl); @@ -93,21 +70,9 @@ SDFileSystemFactory::createDevice(const std::string &uuid) { vlc::threads::mutex_locker locker(m_mutex); - vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_SEC(15); - while ( true ) - { - auto it = std::find_if(m_devices.cbegin(), m_devices.cend(), - [&uuid](const std::shared_ptr<IDevice>& device) { - return strcasecmp( uuid.c_str(), device->uuid().c_str() ) == 0; - }); - if (it != m_devices.cend()) - return (*it); - /* wait a bit, maybe the device is not detected yet */ - int timeout = m_itemAddedCond.timedwait(m_mutex, deadline); - if (timeout) - return nullptr; - } - vlc_assert_unreachable(); + assert( isStarted() == true ); + + return deviceByUuid(uuid); } std::shared_ptr<IDevice> @@ -115,20 +80,14 @@ SDFileSystemFactory::createDeviceFromMrl(const std::string &mrl) { vlc::threads::mutex_locker locker(m_mutex); - auto it = std::find_if(m_devices.cbegin(), m_devices.cend(), - [&mrl](const std::shared_ptr<IDevice>& device) { - auto match = device->matchesMountpoint( mrl ); - return std::get<0>( match ); - }); - if (it != m_devices.cend()) - return (*it); - return nullptr; + assert( isStarted() == true ); + return deviceByMrl(mrl); } void SDFileSystemFactory::refreshDevices() { - /* nothing to do */ + m_deviceLister->refresh(); } bool @@ -140,7 +99,7 @@ SDFileSystemFactory::isMrlSupported(const std::string &path) const bool SDFileSystemFactory::isNetworkFileSystem() const { - return true; + return m_isNetwork; } const std::string & @@ -152,40 +111,16 @@ SDFileSystemFactory::scheme() const bool SDFileSystemFactory::start(IFileSystemFactoryCb *callbacks) { - this->m_callbacks = callbacks; - struct services_discovery_owner_t owner = { - .cbs = &sd_cbs, - .sys = this, - }; - char** sdLongNames; - int* categories; - auto releaser = [](char** ptr) { - for ( auto i = 0u; ptr[i] != nullptr; ++i ) - free( ptr[i] ); - free( ptr ); - }; - auto sdNames = vlc_sd_GetNames( libvlc(), &sdLongNames, &categories ); - if ( sdNames == nullptr ) - return false; - auto sdNamesPtr = vlc::wrap_carray( sdNames, releaser ); - auto sdLongNamesPtr = vlc::wrap_carray( sdLongNames, releaser ); - auto categoriesPtr = vlc::wrap_carray( categories ); - for ( auto i = 0u; sdNames[i] != nullptr; ++i ) - { - if ( categories[i] != SD_CAT_LAN ) - continue; - SdPtr sd{ vlc_sd_Create( libvlc(), sdNames[i], &owner ), &vlc_sd_Destroy }; - if ( sd == nullptr ) - continue; - m_sds.push_back( std::move( sd ) ); - } - return m_sds.empty() == false; + assert( isStarted() == false ); + m_callbacks = callbacks; + return m_deviceLister->start( this ); } void SDFileSystemFactory::stop() { - m_sds.clear(); + assert( isStarted() == true ); + m_deviceLister->stop(); m_callbacks = nullptr; } @@ -195,65 +130,82 @@ SDFileSystemFactory::libvlc() const return vlc_object_instance(m_parent); } -void -SDFileSystemFactory::onDeviceAdded(input_item_t *media) +void SDFileSystemFactory::onDeviceMounted(const std::string& uuid, + const std::string& mountpoint, + bool removable) { - auto mrl = std::string{ media->psz_uri }; - auto name = media->psz_name; - if ( *mrl.crbegin() != '/' ) - mrl += '/'; - - if ( strncasecmp( mrl.c_str(), m_scheme.c_str(), m_scheme.length() ) != 0 ) + if ( strncasecmp( mountpoint.c_str(), m_scheme.c_str(), m_scheme.length() ) != 0 ) return; + std::shared_ptr<fs::IDevice> device; { - vlc::threads::mutex_locker locker(m_mutex); - auto it = std::find_if(m_devices.begin(), m_devices.end(), - [name](const std::shared_ptr<IDevice>& device) { - return strcasecmp( name, device->uuid().c_str() ) == 0; - }); - if (it != m_devices.end()) + vlc::threads::mutex_locker lock(m_mutex); + device = deviceByUuid(uuid); + if (device == nullptr) { - auto& device = (*it); - auto match = device->matchesMountpoint( mrl ); - if ( std::get<0>( match ) == false ) - { - device->addMountpoint( mrl ); - m_callbacks->onDeviceMounted( *device, mrl ); - } - return; /* already exists */ + device = std::make_shared<SDDevice>(uuid, m_scheme, + removable, isNetworkFileSystem() ); + m_devices.push_back(device); } - auto device = std::make_shared<SDDevice>( name, mrl ); - m_devices.push_back( device ); - m_callbacks->onDeviceMounted( *device, mrl ); + device->addMountpoint(mountpoint); } - m_itemAddedCond.signal(); + m_callbacks->onDeviceMounted( *device ); } -void -SDFileSystemFactory::onDeviceRemoved(input_item_t *media) +void vlc::medialibrary::SDFileSystemFactory::onDeviceUnmounted(const std::string& uuid, + const std::string& mountpoint) { - auto name = media->psz_name; - auto mrl = std::string{ media->psz_uri }; - if ( *mrl.crbegin() != '/' ) - mrl += '/'; + if ( strncasecmp( mountpoint.c_str(), m_scheme.c_str(), m_scheme.length() ) != 0 ) + return; - if ( strncasecmp( mrl.c_str(), m_scheme.c_str(), m_scheme.length() ) != 0 ) + std::shared_ptr<fs::IDevice> device; + { + vlc::threads::mutex_locker lock(m_mutex); + device = deviceByUuid(uuid); + } + if ( device == nullptr ) + { + assert( !"Unknown device was unmounted" ); return; + } + device->removeMountpoint(mountpoint); + m_callbacks->onDeviceUnmounted(*device); +} +std::shared_ptr<IDevice> SDFileSystemFactory::deviceByUuid(const std::string& uuid) +{ + auto it = std::find_if( begin( m_devices ), end( m_devices ), + [&uuid]( const std::shared_ptr<fs::IDevice>& d ) { + return strcasecmp( d->uuid().c_str(), uuid.c_str() ) == 0; + }); + if ( it == end( m_devices ) ) + return nullptr; + return *it; +} + +bool SDFileSystemFactory::isStarted() const +{ + return m_callbacks != nullptr; +} + +std::shared_ptr<IDevice> SDFileSystemFactory::deviceByMrl(const std::string& mrl) +{ + std::shared_ptr<fs::IDevice> res; + std::string mountpoint; + for ( const auto& d : m_devices ) { - vlc::threads::mutex_locker locker(m_mutex); - auto it = std::find_if(m_devices.begin(), m_devices.end(), - [&name](const std::shared_ptr<IDevice>& device) { - return strcasecmp( name, device->uuid().c_str() ) == 0; - }); - if ( it != m_devices.end() ) + auto match = d->matchesMountpoint( mrl ); + if ( std::get<0>( match ) == false ) + continue; + auto newMountpoint = std::get<1>( match ); + if ( res == nullptr || newMountpoint.length() > mountpoint.length() ) { - (*it)->removeMountpoint( mrl ); - m_callbacks->onDeviceUnmounted( *(*it), mrl ); + res = d; + mountpoint = std::move( newMountpoint ); } } + return res; } } /* namespace medialibrary */ diff --git a/modules/misc/medialibrary/fs/fs.h b/modules/misc/medialibrary/fs/fs.h index d56853f457..38867c0ca0 100644 --- a/modules/misc/medialibrary/fs/fs.h +++ b/modules/misc/medialibrary/fs/fs.h @@ -27,16 +27,13 @@ #include <vlc_threads.h> #include <vlc_cxx_helpers.hpp> #include <medialibrary/filesystem/IFileSystemFactory.h> +#include <medialibrary/IDeviceLister.h> -struct input_item_t; -struct services_discovery_t; struct libvlc_int_t; -extern "C" { -void vlc_sd_Destroy(services_discovery_t *sd); -} namespace medialibrary { class IDeviceListerCb; +class IMediaLibrary; } namespace vlc { @@ -45,9 +42,10 @@ namespace vlc { using namespace ::medialibrary; using namespace ::medialibrary::fs; -class SDFileSystemFactory : public IFileSystemFactory { +class SDFileSystemFactory : public IFileSystemFactory, private IDeviceListerCb { public: SDFileSystemFactory(vlc_object_t *m_parent, + IMediaLibrary* ml, const std::string &scheme); std::shared_ptr<IDirectory> @@ -83,20 +81,30 @@ public: libvlc_int_t * libvlc() const; - /* public to be called from C callback */ - void onDeviceAdded(input_item_t *media); - void onDeviceRemoved(input_item_t *media); + void + onDeviceMounted(const std::string& uuid, const std::string& mountpoint, bool removable) override; + + void + onDeviceUnmounted(const std::string& uuid, const std::string& mountpoint) override; + +private: + std::shared_ptr<fs::IDevice> + deviceByUuid(const std::string& uuid); + + bool isStarted() const; + + std::shared_ptr<fs::IDevice> deviceByMrl(const std::string& mrl); private: vlc_object_t *const m_parent; + IMediaLibrary* m_ml; const std::string m_scheme; + std::shared_ptr<IDeviceLister> m_deviceLister; IFileSystemFactoryCb *m_callbacks; + bool m_isNetwork; vlc::threads::mutex m_mutex; - vlc::threads::condition_variable m_itemAddedCond; std::vector<std::shared_ptr<IDevice>> m_devices; - using SdPtr = std::unique_ptr<services_discovery_t, decltype(&vlc_sd_Destroy)>; - std::vector<SdPtr> m_sds; }; } /* namespace medialibrary */ diff --git a/modules/misc/medialibrary/medialib.cpp b/modules/misc/medialibrary/medialib.cpp index 4ba802c88d..0d884711fb 100644 --- a/modules/misc/medialibrary/medialib.cpp +++ b/modules/misc/medialibrary/medialib.cpp @@ -29,6 +29,7 @@ #include <vlc_dialog.h> #include "medialibrary.h" #include "fs/fs.h" +#include "fs/devicelister.h" #include <medialibrary/IMedia.h> #include <medialibrary/IAlbumTrack.h> @@ -103,7 +104,7 @@ void wrapEntityCreatedEventCallback( vlc_medialibrary_module_t* ml, } void wrapEntityModifiedEventCallback( vlc_medialibrary_module_t* ml, - const std::vector<int64_t>& ids, + const std::set<int64_t>& ids, vlc_ml_event_type evType ) { vlc_ml_event_t ev; @@ -116,7 +117,7 @@ void wrapEntityModifiedEventCallback( vlc_medialibrary_module_t* ml, } void wrapEntityDeletedEventCallback( vlc_medialibrary_module_t* ml, - const std::vector<int64_t>& ids, vlc_ml_event_type evType ) + const std::set<int64_t>& ids, vlc_ml_event_type evType ) { vlc_ml_event_t ev; ev.i_type = evType; @@ -134,12 +135,12 @@ void MediaLibrary::onMediaAdded( std::vector<medialibrary::MediaPtr> media ) wrapEntityCreatedEventCallback<vlc_ml_media_t>( m_vlc_ml, media, VLC_ML_EVENT_MEDIA_ADDED ); } -void MediaLibrary::onMediaModified( std::vector<int64_t> mediaIds ) +void MediaLibrary::onMediaModified( std::set<int64_t> mediaIds ) { wrapEntityModifiedEventCallback( m_vlc_ml, mediaIds, VLC_ML_EVENT_MEDIA_UPDATED ); } -void MediaLibrary::onMediaDeleted( std::vector<int64_t> mediaIds ) +void MediaLibrary::onMediaDeleted( std::set<int64_t> mediaIds ) { wrapEntityDeletedEventCallback( m_vlc_ml, mediaIds, VLC_ML_EVENT_MEDIA_DELETED ); } @@ -149,12 +150,12 @@ void MediaLibrary::onArtistsAdded( std::vector<medialibrary::ArtistPtr> artists wrapEntityCreatedEventCallback<vlc_ml_artist_t>( m_vlc_ml, artists, VLC_ML_EVENT_ARTIST_ADDED ); } -void MediaLibrary::onArtistsModified( std::vector<int64_t> artistIds ) +void MediaLibrary::onArtistsModified( std::set<int64_t> artistIds ) { wrapEntityModifiedEventCallback( m_vlc_ml, artistIds, VLC_ML_EVENT_ARTIST_UPDATED ); } -void MediaLibrary::onArtistsDeleted( std::vector<int64_t> artistIds ) +void MediaLibrary::onArtistsDeleted( std::set<int64_t> artistIds ) { wrapEntityDeletedEventCallback( m_vlc_ml, artistIds, VLC_ML_EVENT_ARTIST_DELETED ); } @@ -164,12 +165,12 @@ void MediaLibrary::onAlbumsAdded( std::vector<medialibrary::AlbumPtr> albums ) wrapEntityCreatedEventCallback<vlc_ml_album_t>( m_vlc_ml, albums, VLC_ML_EVENT_ALBUM_ADDED ); } -void MediaLibrary::onAlbumsModified( std::vector<int64_t> albumIds ) +void MediaLibrary::onAlbumsModified( std::set<int64_t> albumIds ) { wrapEntityModifiedEventCallback( m_vlc_ml, albumIds, VLC_ML_EVENT_ALBUM_UPDATED ); } -void MediaLibrary::onAlbumsDeleted( std::vector<int64_t> albumIds ) +void MediaLibrary::onAlbumsDeleted( std::set<int64_t> albumIds ) { wrapEntityDeletedEventCallback( m_vlc_ml, albumIds, VLC_ML_EVENT_ALBUM_DELETED ); } @@ -179,12 +180,12 @@ void MediaLibrary::onPlaylistsAdded( std::vector<medialibrary::PlaylistPtr> play wrapEntityCreatedEventCallback<vlc_ml_playlist_t>( m_vlc_ml, playlists, VLC_ML_EVENT_PLAYLIST_ADDED ); } -void MediaLibrary::onPlaylistsModified( std::vector<int64_t> playlistIds ) +void MediaLibrary::onPlaylistsModified( std::set<int64_t> playlistIds ) { wrapEntityModifiedEventCallback( m_vlc_ml, playlistIds, VLC_ML_EVENT_PLAYLIST_UPDATED ); } -void MediaLibrary::onPlaylistsDeleted( std::vector<int64_t> playlistIds ) +void MediaLibrary::onPlaylistsDeleted( std::set<int64_t> playlistIds ) { wrapEntityDeletedEventCallback( m_vlc_ml, playlistIds, VLC_ML_EVENT_PLAYLIST_DELETED ); } @@ -194,28 +195,43 @@ void MediaLibrary::onGenresAdded( std::vector<medialibrary::GenrePtr> genres ) wrapEntityCreatedEventCallback<vlc_ml_genre_t>( m_vlc_ml, genres, VLC_ML_EVENT_GENRE_ADDED ); } -void MediaLibrary::onGenresModified( std::vector<int64_t> genreIds ) +void MediaLibrary::onGenresModified( std::set<int64_t> genreIds ) { wrapEntityModifiedEventCallback( m_vlc_ml, genreIds, VLC_ML_EVENT_GENRE_UPDATED ); } -void MediaLibrary::onGenresDeleted( std::vector<int64_t> genreIds ) +void MediaLibrary::onGenresDeleted( std::set<int64_t> genreIds ) { wrapEntityDeletedEventCallback( m_vlc_ml, genreIds, VLC_ML_EVENT_GENRE_DELETED ); } -void MediaLibrary::onMediaGroupAdded( std::vector<medialibrary::MediaGroupPtr> ) +void MediaLibrary::onMediaGroupsAdded( std::vector<medialibrary::MediaGroupPtr> ) { } -void MediaLibrary::onMediaGroupModified( std::vector<int64_t> ) +void MediaLibrary::onMediaGroupsModified( std::set<int64_t> ) { } -void MediaLibrary::onMediaGroupDeleted( std::vector<int64_t> ) +void MediaLibrary::onMediaGroupsDeleted( std::set<int64_t> ) { } +void MediaLibrary::onBookmarksAdded( std::vector<medialibrary::BookmarkPtr> ) +{ + +} + +void MediaLibrary::onBookmarksModified( std::set<int64_t> ) +{ + +} + +void MediaLibrary::onBookmarksDeleted( std::set<int64_t> ) +{ + +} + void MediaLibrary::onDiscoveryStarted( const std::string& entryPoint ) { vlc_ml_event_t ev; @@ -372,6 +388,12 @@ bool MediaLibrary::Init() auto userDir = vlc::wrap_cptr( config_GetUserDir( VLC_USERDATA_DIR ) ); std::string mlDir = std::string{ userDir.get() } + "/ml/"; + m_ml->registerDeviceLister( std::make_shared<vlc::medialibrary::DeviceLister>( + VLC_OBJECT(m_vlc_ml) ), "smb://" ); + m_ml->addFileSystemFactory( std::make_shared<vlc::medialibrary::SDFileSystemFactory>( + VLC_OBJECT( m_vlc_ml ), m_ml.get(), "file://") ); + m_ml->addFileSystemFactory( std::make_shared<vlc::medialibrary::SDFileSystemFactory>( + VLC_OBJECT( m_vlc_ml ), m_ml.get(), "smb://") ); auto initStatus = m_ml->initialize( mlDir + "ml.db", mlDir + "/mlstorage/", this ); switch ( initStatus ) { @@ -421,8 +443,6 @@ bool MediaLibrary::Init() return false; } - auto networkFs = std::make_shared<vlc::medialibrary::SDFileSystemFactory>( VLC_OBJECT( m_vlc_ml ), "smb://"); - m_ml->addNetworkFileSystemFactory( networkFs ); m_ml->setDiscoverNetworkEnabled( true ); return true; @@ -433,22 +453,13 @@ bool MediaLibrary::Start() if ( Init() == false ) return false; - auto startRes = m_ml->start(); - switch ( startRes ) - { - case medialibrary::StartResult::Failed: - msg_Err( m_vlc_ml, "Failed to start the MediaLibrary" ); - return false; - case medialibrary::StartResult::AlreadyStarted: - return true; - case medialibrary::StartResult::Success: - break; - } - - // Reload entry points we already know about, and then add potential new ones. - // Doing it the other way around would cause the initial scan to be performed - // twice, as we start discovering the new folders, then reload them. - m_ml->reload(); + /* + * If we already provided the medialib with some entry points, then we have + * nothing left to do + */ + auto entryPoints = m_ml->entryPoints()->all(); + if ( entryPoints.empty() == false ) + return true; auto folders = vlc::wrap_cptr( var_InheritString( m_vlc_ml, "ml-folders" ) ); if ( folders != nullptr && strlen( folders.get() ) > 0 ) diff --git a/modules/misc/medialibrary/medialibrary.h b/modules/misc/medialibrary/medialibrary.h index c2d8359383..fee466b62d 100644 --- a/modules/misc/medialibrary/medialibrary.h +++ b/modules/misc/medialibrary/medialibrary.h @@ -168,23 +168,26 @@ private: // IMediaLibraryCb interface public: virtual void onMediaAdded(std::vector<medialibrary::MediaPtr> media) override; - virtual void onMediaModified(std::vector<int64_t> media) override; - virtual void onMediaDeleted(std::vector<int64_t> mediaIds) override; + virtual void onMediaModified(std::set<int64_t> media) override; + virtual void onMediaDeleted(std::set<int64_t> mediaIds) override; virtual void onArtistsAdded(std::vector<medialibrary::ArtistPtr> artists) override; - virtual void onArtistsModified(std::vector<int64_t> artists) override; - virtual void onArtistsDeleted(std::vector<int64_t> artistsIds) override; + virtual void onArtistsModified(std::set<int64_t> artists) override; + virtual void onArtistsDeleted(std::set<int64_t> artistsIds) override; virtual void onAlbumsAdded(std::vector<medialibrary::AlbumPtr> albums) override; - virtual void onAlbumsModified(std::vector<int64_t> albums) override; - virtual void onAlbumsDeleted(std::vector<int64_t> albumsIds) override; + virtual void onAlbumsModified(std::set<int64_t> albums) override; + virtual void onAlbumsDeleted(std::set<int64_t> albumsIds) override; virtual void onPlaylistsAdded(std::vector<medialibrary::PlaylistPtr> playlists) override; - virtual void onPlaylistsModified(std::vector<int64_t> playlists) override; - virtual void onPlaylistsDeleted(std::vector<int64_t> playlistIds) override; + virtual void onPlaylistsModified(std::set<int64_t> playlists) override; + virtual void onPlaylistsDeleted(std::set<int64_t> playlistIds) override; virtual void onGenresAdded(std::vector<medialibrary::GenrePtr> genres) override; - virtual void onGenresModified(std::vector<int64_t> genres) override; - virtual void onGenresDeleted(std::vector<int64_t> genreIds) override; - virtual void onMediaGroupAdded( std::vector<medialibrary::MediaGroupPtr> mediaGroups ) override; - virtual void onMediaGroupModified( std::vector<int64_t> mediaGroupsIds ) override; - virtual void onMediaGroupDeleted( std::vector<int64_t> mediaGroupsIds ) override; + virtual void onGenresModified(std::set<int64_t> genres) override; + virtual void onGenresDeleted(std::set<int64_t> genreIds) override; + virtual void onMediaGroupsAdded( std::vector<medialibrary::MediaGroupPtr> mediaGroups ) override; + virtual void onMediaGroupsModified( std::set<int64_t> mediaGroupsIds ) override; + virtual void onMediaGroupsDeleted( std::set<int64_t> mediaGroupsIds ) override; + virtual void onBookmarksAdded( std::vector<medialibrary::BookmarkPtr> bookmarks ) override; + virtual void onBookmarksModified( std::set<int64_t> bookmarksIds ) override; + virtual void onBookmarksDeleted( std::set<int64_t> bookmarksIds ) override; virtual void onDiscoveryStarted(const std::string& entryPoint) override; virtual void onDiscoveryProgress(const std::string& entryPoint) override; virtual void onDiscoveryCompleted(const std::string& entryPoint, bool success) override; _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
