[vlc-commits] medialib: Bump contrib version & adapt to API changes

Hugo Beauzée-Luyssen git at videolan.org
Mon Jun 22 15:24:12 CEST 2020


vlc | branch: master | Hugo Beauzée-Luyssen <hugo at beauzee.fr> | 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 <ccom at randomderp.com>
-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 <robux4 at ycbcr.xyz>
-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;




More information about the vlc-commits mailing list