[vlc-devel] [PATCH 01/12] medialibrary: Add comprehensive group support

Benjamin Arnaud benjamin.arnaud at videolabs.io
Wed Apr 14 08:05:48 UTC 2021


---
 include/vlc_media_library.h                |  83 ++++++++++++++
 modules/gui/qt/medialibrary/mlevent.hpp    |   5 +
 modules/gui/qt/medialibrary/mlqmltypes.hpp |   1 +
 modules/misc/medialibrary/entities.cpp     |  17 +++
 modules/misc/medialibrary/medialibrary.cpp | 125 +++++++++++++++++++--
 modules/misc/medialibrary/medialibrary.h   |   3 +
 src/libvlccore.sym                         |   2 +
 src/misc/medialibrary.c                    |  27 +++++
 8 files changed, 251 insertions(+), 12 deletions(-)

diff --git a/include/vlc_media_library.h b/include/vlc_media_library.h
index b038566d7a..27b2150ab4 100644
--- a/include/vlc_media_library.h
+++ b/include/vlc_media_library.h
@@ -226,6 +226,19 @@ typedef struct vlc_ml_media_t
     };
 } vlc_ml_media_t;
 
+typedef struct vlc_ml_group_t
+{
+    int64_t i_id;
+
+    char* psz_name;
+
+    unsigned int i_nb_total_media;
+
+    unsigned int i_duration;
+
+    uint32_t i_creation_date;
+} vlc_ml_group_t;
+
 typedef struct vlc_ml_playlist_t
 {
     int64_t i_id;
@@ -303,6 +316,12 @@ typedef struct vlc_ml_genre_list_t
     vlc_ml_genre_t p_items[];
 } vlc_ml_genre_list_t;
 
+typedef struct vlc_ml_group_list_t
+{
+    size_t i_nb_items;
+    vlc_ml_group_t p_items[];
+} vlc_ml_group_list_t;
+
 typedef struct vlc_ml_playlist_list_t
 {
     size_t i_nb_items;
@@ -384,6 +403,7 @@ enum vlc_ml_get_queries
     VLC_ML_GET_ARTIST,          /**< arg1: Artist   ID; ret: vlc_ml_artist_t*   */
     VLC_ML_GET_GENRE,           /**< arg1: Genre    ID; ret: vlc_ml_genre_t*    */
     VLC_ML_GET_SHOW,            /**< arg1: Show     ID; ret: vlc_ml_show_t*     */
+    VLC_ML_GET_GROUP,           /**< arg1: Group    ID; ret: vlc_ml_group_t*    */
     VLC_ML_GET_PLAYLIST,        /**< arg1: Playlist ID; ret: vlc_ml_playlist_t* */
 };
 
@@ -403,6 +423,8 @@ enum vlc_ml_list_queries
     VLC_ML_COUNT_ARTISTS,         /**< arg1 bool: includeAll; arg2 (out): size_t*                   */
     VLC_ML_LIST_SHOWS,            /**< arg1 (out): vlc_ml_show_list_t**                             */
     VLC_ML_COUNT_SHOWS,           /**< arg1 (out): size_t*                                          */
+    VLC_ML_LIST_GROUPS,           /**< arg1 (out): vlc_ml_group_list_t**                            */
+    VLC_ML_COUNT_GROUPS,          /**< arg1 (out): size_t*                                          */
     VLC_ML_LIST_PLAYLISTS,        /**< arg1 (out): vlc_ml_playlist_list_t**                         */
     VLC_ML_COUNT_PLAYLISTS,       /**< arg1 (out): size_t*                                          */
     VLC_ML_LIST_HISTORY,          /**< arg1 (out): vlc_ml_media_list_t**                            */
@@ -441,6 +463,10 @@ enum vlc_ml_list_queries
     VLC_ML_COUNT_MEDIA_LABELS,    /**< arg1: media id;  arg2 (out): size_t*              */
     VLC_ML_LIST_MEDIA_BOOKMARKS,  /**< arg1: media id;  arg2 (out): vlc_ml_bookmark_list_t** */
 
+    /* Groups specific listings */
+    VLC_ML_LIST_GROUP_MEDIA,   /**< arg1: playlist id; arg2 (out): vlc_ml_media_list_t** */
+    VLC_ML_COUNT_GROUP_MEDIA,  /**< arg1: playlist id; arg2 (out): size_t* */
+
     /* Playlist specific listings */
     VLC_ML_LIST_PLAYLIST_MEDIA,   /**< arg1: playlist id; arg2 (out): vlc_ml_media_list_t** */
     VLC_ML_COUNT_PLAYLIST_MEDIA,  /**< arg1: playlist id; arg2 (out): size_t* */
@@ -461,6 +487,7 @@ enum vlc_ml_parent_type
     VLC_ML_PARENT_ARTIST,
     VLC_ML_PARENT_SHOW,
     VLC_ML_PARENT_GENRE,
+    VLC_ML_PARENT_GROUP,
     VLC_ML_PARENT_PLAYLIST,
 };
 
@@ -582,6 +609,9 @@ enum vlc_ml_event_type
     VLC_ML_EVENT_ALBUM_ADDED,
     VLC_ML_EVENT_ALBUM_UPDATED,
     VLC_ML_EVENT_ALBUM_DELETED,
+    VLC_ML_EVENT_GROUP_ADDED,
+    VLC_ML_EVENT_GROUP_UPDATED,
+    VLC_ML_EVENT_GROUP_DELETED,
     VLC_ML_EVENT_PLAYLIST_ADDED,
     VLC_ML_EVENT_PLAYLIST_UPDATED,
     VLC_ML_EVENT_PLAYLIST_DELETED,
@@ -752,6 +782,7 @@ typedef struct vlc_ml_event_t
             const vlc_ml_media_t* p_media;
             const vlc_ml_artist_t* p_artist;
             const vlc_ml_album_t* p_album;
+            const vlc_ml_group_t* p_group;
             const vlc_ml_playlist_t* p_playlist;
             const vlc_ml_genre_t* p_genre;
             const vlc_ml_bookmark_t* p_bookmark;
@@ -866,6 +897,7 @@ VLC_API void vlc_ml_artist_release( vlc_ml_artist_t* p_artist );
 VLC_API void vlc_ml_genre_release( vlc_ml_genre_t* p_genre );
 VLC_API void vlc_ml_media_release( vlc_ml_media_t* p_media );
 VLC_API void vlc_ml_album_release( vlc_ml_album_t* p_album );
+VLC_API void vlc_ml_group_release( vlc_ml_group_t* p_group );
 VLC_API void vlc_ml_playlist_release( vlc_ml_playlist_t* p_playlist );
 
 VLC_API void vlc_ml_label_list_release( vlc_ml_label_list_t* p_list );
@@ -875,6 +907,7 @@ VLC_API void vlc_ml_media_list_release( vlc_ml_media_list_t* p_list );
 VLC_API void vlc_ml_album_list_release( vlc_ml_album_list_t* p_list );
 VLC_API void vlc_ml_show_list_release( vlc_ml_show_list_t* p_list );
 VLC_API void vlc_ml_genre_list_release( vlc_ml_genre_list_t* p_list );
+VLC_API void vlc_ml_group_list_release( vlc_ml_group_list_t* p_list );
 VLC_API void vlc_ml_playlist_list_release( vlc_ml_playlist_list_t* p_list );
 VLC_API void vlc_ml_entry_point_list_release( vlc_ml_entry_point_list_t* p_list );
 VLC_API void vlc_ml_playback_states_all_release( vlc_ml_playback_states_all* prefs );
@@ -1164,6 +1197,11 @@ static inline vlc_ml_show_t* vlc_ml_get_show( vlc_medialibrary_t* p_ml, int64_t
     return (vlc_ml_show_t*)vlc_ml_get( p_ml, VLC_ML_GET_SHOW, i_show_id );
 }
 
+static inline vlc_ml_group_t* vlc_ml_get_group( vlc_medialibrary_t* p_ml, int64_t i_group_id )
+{
+    return (vlc_ml_group_t*)vlc_ml_get( p_ml, VLC_ML_GET_GROUP, i_group_id );
+}
+
 static inline vlc_ml_playlist_t* vlc_ml_get_playlist( vlc_medialibrary_t* p_ml, int64_t i_playlist_id )
 {
     return (vlc_ml_playlist_t*)vlc_ml_get( p_ml, VLC_ML_GET_PLAYLIST, i_playlist_id );
@@ -1556,6 +1594,47 @@ static inline size_t vlc_ml_count_stream_history( vlc_medialibrary_t* p_ml, cons
     return count;
 }
 
+//-------------------------------------------------------------------------------------------------
+// Groups
+
+static inline vlc_ml_group_list_t* vlc_ml_list_groups( vlc_medialibrary_t* p_ml, const vlc_ml_query_params_t* params )
+{
+    vlc_assert( p_ml != NULL );
+    vlc_ml_group_list_t* res;
+    if ( vlc_ml_list( p_ml, VLC_ML_LIST_GROUPS, params, &res ) != VLC_SUCCESS )
+        return NULL;
+    return res;
+}
+
+static inline size_t vlc_ml_count_groups( vlc_medialibrary_t* p_ml, const vlc_ml_query_params_t* params )
+{
+    vlc_assert( p_ml != NULL );
+    size_t count;
+    if ( vlc_ml_list( p_ml, VLC_ML_COUNT_GROUPS, params, &count ) != VLC_SUCCESS )
+        return 0;
+    return count;
+}
+
+static inline vlc_ml_media_list_t* vlc_ml_list_group_media( vlc_medialibrary_t* p_ml, const vlc_ml_query_params_t* params, int64_t i_group_id )
+{
+    vlc_assert( p_ml != NULL );
+    vlc_ml_media_list_t* res;
+    if ( vlc_ml_list( p_ml, VLC_ML_LIST_GROUP_MEDIA, params, i_group_id, &res ) != VLC_SUCCESS )
+        return NULL;
+    return res;
+}
+
+static inline size_t vlc_ml_count_group_media( vlc_medialibrary_t* p_ml, const vlc_ml_query_params_t* params, int64_t i_group_id )
+{
+    vlc_assert( p_ml != NULL );
+    size_t count;
+    if ( vlc_ml_list( p_ml, VLC_ML_COUNT_GROUP_MEDIA, params, i_group_id, &count ) != VLC_SUCCESS )
+        return 0;
+    return count;
+}
+
+//-------------------------------------------------------------------------------------------------
+
 static inline vlc_ml_playlist_list_t* vlc_ml_list_playlists( vlc_medialibrary_t* p_ml, const vlc_ml_query_params_t* params )
 {
     vlc_assert( p_ml != NULL );
@@ -1603,6 +1682,7 @@ static inline size_t vlc_ml_count_playlist_media( vlc_medialibrary_t* p_ml, cons
     vlc_ml_album_t*: vlc_ml_album_release, \
     vlc_ml_genre_t*: vlc_ml_genre_release, \
     vlc_ml_media_t*: vlc_ml_media_release, \
+    vlc_ml_group_t*: vlc_ml_group_release, \
     vlc_ml_playlist_t*: vlc_ml_playlist_release, \
     vlc_ml_label_list_t*: vlc_ml_label_list_release, \
     vlc_ml_file_list_t*: vlc_ml_file_list_release, \
@@ -1611,6 +1691,7 @@ static inline size_t vlc_ml_count_playlist_media( vlc_medialibrary_t* p_ml, cons
     vlc_ml_album_list_t*: vlc_ml_album_list_release, \
     vlc_ml_show_list_t*: vlc_ml_show_list_release, \
     vlc_ml_genre_list_t*: vlc_ml_genre_list_release, \
+    vlc_ml_group_list_t*: vlc_ml_group_list_release, \
     vlc_ml_playlist_list_t*: vlc_ml_playlist_list_release, \
     vlc_ml_entry_point_list_t*: vlc_ml_entry_point_list_release, \
     vlc_ml_playback_states_all*: vlc_ml_playback_states_all_release, \
@@ -1623,6 +1704,7 @@ static inline void vlc_ml_release( vlc_ml_artist_t* artist ) { vlc_ml_artist_rel
 static inline void vlc_ml_release( vlc_ml_album_t* album ) { vlc_ml_album_release( album ); }
 static inline void vlc_ml_release( vlc_ml_genre_t* genre ) { vlc_ml_genre_release( genre ); }
 static inline void vlc_ml_release( vlc_ml_media_t* media ) { vlc_ml_media_release( media ); }
+static inline void vlc_ml_release( vlc_ml_group_t* group ) { vlc_ml_group_release( group ); }
 static inline void vlc_ml_release( vlc_ml_playlist_t* playlist ) { vlc_ml_playlist_release( playlist ); }
 static inline void vlc_ml_release( vlc_ml_label_list_t* list ) { vlc_ml_label_list_release( list ); }
 static inline void vlc_ml_release( vlc_ml_file_list_t* list ) { vlc_ml_file_list_release( list ); }
@@ -1631,6 +1713,7 @@ static inline void vlc_ml_release( vlc_ml_media_list_t* list ) { vlc_ml_media_li
 static inline void vlc_ml_release( vlc_ml_album_list_t* list ) { vlc_ml_album_list_release( list ); }
 static inline void vlc_ml_release( vlc_ml_show_list_t* list ) { vlc_ml_show_list_release( list ); }
 static inline void vlc_ml_release( vlc_ml_genre_list_t* list ) { vlc_ml_genre_list_release( list ); }
+static inline void vlc_ml_release( vlc_ml_group_list_t* list ) { vlc_ml_group_list_release( list ); }
 static inline void vlc_ml_release( vlc_ml_playlist_list_t* list ) { vlc_ml_playlist_list_release( list ); }
 static inline void vlc_ml_release( vlc_ml_entry_point_list_t* list ) { vlc_ml_entry_point_list_release( list ); }
 static inline void vlc_ml_release( vlc_ml_playback_states_all* prefs ) { vlc_ml_playback_states_all_release( prefs ); }
diff --git a/modules/gui/qt/medialibrary/mlevent.hpp b/modules/gui/qt/medialibrary/mlevent.hpp
index 9ff34f2c3f..10bf4a83a3 100644
--- a/modules/gui/qt/medialibrary/mlevent.hpp
+++ b/modules/gui/qt/medialibrary/mlevent.hpp
@@ -71,6 +71,9 @@ struct MLEvent
             case VLC_ML_EVENT_ALBUM_ADDED:
                 creation.i_entity_id = event->creation.p_album->i_id;
                 break;
+            case VLC_ML_EVENT_GROUP_ADDED:
+                creation.i_entity_id = event->creation.p_group->i_id;
+                break;
             case VLC_ML_EVENT_PLAYLIST_ADDED:
                 creation.i_entity_id = event->creation.p_playlist->i_id;
                 break;
@@ -83,6 +86,7 @@ struct MLEvent
             case VLC_ML_EVENT_MEDIA_UPDATED:
             case VLC_ML_EVENT_ARTIST_UPDATED:
             case VLC_ML_EVENT_ALBUM_UPDATED:
+            case VLC_ML_EVENT_GROUP_UPDATED:
             case VLC_ML_EVENT_PLAYLIST_UPDATED:
             case VLC_ML_EVENT_GENRE_UPDATED:
             case VLC_ML_EVENT_BOOKMARKS_UPDATED:
@@ -91,6 +95,7 @@ struct MLEvent
             case VLC_ML_EVENT_MEDIA_DELETED:
             case VLC_ML_EVENT_ARTIST_DELETED:
             case VLC_ML_EVENT_ALBUM_DELETED:
+            case VLC_ML_EVENT_GROUP_DELETED:
             case VLC_ML_EVENT_PLAYLIST_DELETED:
             case VLC_ML_EVENT_GENRE_DELETED:
             case VLC_ML_EVENT_BOOKMARKS_DELETED:
diff --git a/modules/gui/qt/medialibrary/mlqmltypes.hpp b/modules/gui/qt/medialibrary/mlqmltypes.hpp
index cc4f75e4e0..672f14c793 100644
--- a/modules/gui/qt/medialibrary/mlqmltypes.hpp
+++ b/modules/gui/qt/medialibrary/mlqmltypes.hpp
@@ -52,6 +52,7 @@ public:
             ML_PARENT_TYPE_CASE(VLC_ML_PARENT_ARTIST);
             ML_PARENT_TYPE_CASE(VLC_ML_PARENT_SHOW);
             ML_PARENT_TYPE_CASE(VLC_ML_PARENT_GENRE);
+            ML_PARENT_TYPE_CASE(VLC_ML_PARENT_GROUP);
             ML_PARENT_TYPE_CASE(VLC_ML_PARENT_PLAYLIST);
         default:
             return QString("UNKNONW - %2").arg(id);
diff --git a/modules/misc/medialibrary/entities.cpp b/modules/misc/medialibrary/entities.cpp
index 1e7bbd1cef..5af678c3b4 100644
--- a/modules/misc/medialibrary/entities.cpp
+++ b/modules/misc/medialibrary/entities.cpp
@@ -34,6 +34,7 @@
 #include <medialibrary/IAlbumTrack.h>
 #include <medialibrary/IGenre.h>
 #include <medialibrary/ILabel.h>
+#include <medialibrary/IMediaGroup.h>
 #include <medialibrary/IPlaylist.h>
 #include <medialibrary/IAudioTrack.h>
 #include <medialibrary/IVideoTrack.h>
@@ -406,6 +407,22 @@ bool Convert( const medialibrary::ILabel* input, vlc_ml_label_t& output )
     return strdup_helper( input->name(), output.psz_name );
 }
 
+bool Convert( const medialibrary::IMediaGroup* input, vlc_ml_group_t& output )
+{
+    output.i_id = input->id();
+
+    output.i_nb_total_media = input->nbTotalMedia();
+
+    output.i_duration = input->duration();
+
+    output.i_creation_date = input->creationDate();
+
+    if( strdup_helper( input->name(), output.psz_name ) == false )
+        return false;
+
+    return true;
+}
+
 bool Convert( const medialibrary::IPlaylist* input, vlc_ml_playlist_t& output )
 {
     output.i_id = input->id();
diff --git a/modules/misc/medialibrary/medialibrary.cpp b/modules/misc/medialibrary/medialibrary.cpp
index 7f9c218c3d..62cccb7d13 100644
--- a/modules/misc/medialibrary/medialibrary.cpp
+++ b/modules/misc/medialibrary/medialibrary.cpp
@@ -38,6 +38,7 @@
 #include <medialibrary/IGenre.h>
 #include <medialibrary/IMetadata.h>
 #include <medialibrary/IShow.h>
+#include <medialibrary/IMediaGroup.h>
 #include <medialibrary/IPlaylist.h>
 #include <medialibrary/IBookmark.h>
 
@@ -82,6 +83,7 @@ void assignToEvent( vlc_ml_event_t* ev, vlc_ml_media_t* m )    { ev->creation.p_
 void assignToEvent( vlc_ml_event_t* ev, vlc_ml_artist_t* a )   { ev->creation.p_artist   = a; }
 void assignToEvent( vlc_ml_event_t* ev, vlc_ml_album_t* a )    { ev->creation.p_album    = a; }
 void assignToEvent( vlc_ml_event_t* ev, vlc_ml_genre_t* g )    { ev->creation.p_genre    = g; }
+void assignToEvent( vlc_ml_event_t* ev, vlc_ml_group_t* g )    { ev->creation.p_group    = g; }
 void assignToEvent( vlc_ml_event_t* ev, vlc_ml_playlist_t* p ) { ev->creation.p_playlist = p; }
 void assignToEvent( vlc_ml_event_t* ev, vlc_ml_bookmark_t* b ) { ev->creation.p_bookmark = b; }
 
@@ -177,6 +179,26 @@ void MediaLibrary::onAlbumsDeleted( std::set<int64_t> albumIds )
     wrapEntityDeletedEventCallback( m_vlc_ml, albumIds, VLC_ML_EVENT_ALBUM_DELETED );
 }
 
+//-------------------------------------------------------------------------------------------------
+// Groups
+
+void MediaLibrary::onMediaGroupsAdded( std::vector<medialibrary::MediaGroupPtr> groups )
+{
+    wrapEntityCreatedEventCallback<vlc_ml_group_t>( m_vlc_ml, groups, VLC_ML_EVENT_GROUP_ADDED );
+}
+
+void MediaLibrary::onMediaGroupsModified( std::set<int64_t> groupIds )
+{
+    wrapEntityModifiedEventCallback( m_vlc_ml, groupIds, VLC_ML_EVENT_GROUP_UPDATED );
+}
+
+void MediaLibrary::onMediaGroupsDeleted( std::set<int64_t> groupIds )
+{
+    wrapEntityDeletedEventCallback( m_vlc_ml, groupIds, VLC_ML_EVENT_GROUP_DELETED );
+}
+
+//-------------------------------------------------------------------------------------------------
+
 void MediaLibrary::onPlaylistsAdded( std::vector<medialibrary::PlaylistPtr> playlists )
 {
     wrapEntityCreatedEventCallback<vlc_ml_playlist_t>( m_vlc_ml, playlists, VLC_ML_EVENT_PLAYLIST_ADDED );
@@ -207,18 +229,6 @@ void MediaLibrary::onGenresDeleted( std::set<int64_t> genreIds )
     wrapEntityDeletedEventCallback( m_vlc_ml, genreIds, VLC_ML_EVENT_GENRE_DELETED );
 }
 
-void MediaLibrary::onMediaGroupsAdded( std::vector<medialibrary::MediaGroupPtr> )
-{
-}
-
-void MediaLibrary::onMediaGroupsModified( std::set<int64_t> )
-{
-}
-
-void MediaLibrary::onMediaGroupsDeleted( std::set<int64_t> )
-{
-}
-
 void MediaLibrary::onBookmarksAdded( std::vector<medialibrary::BookmarkPtr> bookmarks )
 {
     wrapEntityCreatedEventCallback<vlc_ml_bookmark_t>( m_vlc_ml, bookmarks,
@@ -935,6 +945,11 @@ int MediaLibrary::List( int listQuery, const vlc_ml_query_params_t* params, va_l
                     vlc_assert_unreachable();
             }
         }
+        case VLC_ML_LIST_GROUPS:
+        case VLC_ML_COUNT_GROUPS:
+        case VLC_ML_LIST_GROUP_MEDIA:
+        case VLC_ML_COUNT_GROUP_MEDIA:
+            return listGroup( listQuery, paramsPtr, psz_pattern, nbItems, offset, args );
         case VLC_ML_LIST_PLAYLIST_MEDIA:
         case VLC_ML_COUNT_PLAYLIST_MEDIA:
         case VLC_ML_LIST_PLAYLISTS:
@@ -1039,6 +1054,12 @@ void* MediaLibrary::Get( int query, va_list args )
             auto show = m_ml->show( id );
             return CreateAndConvert<vlc_ml_show_t>( show.get() );
         }
+        case VLC_ML_GET_GROUP:
+        {
+            auto id = va_arg( args, int64_t );
+            auto group = m_ml->mediaGroup( id );
+            return CreateAndConvert<vlc_ml_group_t>( group.get() );
+        }
         case VLC_ML_GET_PLAYLIST:
         {
             auto id = va_arg( args, int64_t );
@@ -1392,6 +1413,8 @@ int MediaLibrary::filterListChildrenQuery( int query, int parentType )
                     return VLC_ML_LIST_SHOW_EPISODES;
                 case VLC_ML_PARENT_GENRE:
                     return VLC_ML_LIST_GENRE_TRACKS;
+                case VLC_ML_PARENT_GROUP:
+                    return VLC_ML_LIST_GROUP_MEDIA;
                 case VLC_ML_PARENT_PLAYLIST:
                     return VLC_ML_LIST_PLAYLIST_MEDIA;
                 default:
@@ -1408,6 +1431,8 @@ int MediaLibrary::filterListChildrenQuery( int query, int parentType )
                     return VLC_ML_COUNT_SHOW_EPISODES;
                 case VLC_ML_PARENT_GENRE:
                     return VLC_ML_COUNT_GENRE_TRACKS;
+                case VLC_ML_PARENT_GROUP:
+                    return VLC_ML_COUNT_GROUP_MEDIA;
                 case VLC_ML_PARENT_PLAYLIST:
                     return VLC_ML_COUNT_PLAYLIST_MEDIA;
                 default:
@@ -1663,6 +1688,82 @@ int MediaLibrary::listGenre( int listQuery, const medialibrary::QueryParameters*
     }
 }
 
+int MediaLibrary::listGroup( int listQuery, const medialibrary::QueryParameters* paramsPtr,
+                             const char* pattern, uint32_t nbItems, uint32_t offset, va_list args )
+{
+    switch( listQuery )
+    {
+        case VLC_ML_LIST_GROUPS:
+        case VLC_ML_COUNT_GROUPS:
+        {
+            medialibrary::Query<medialibrary::IMediaGroup> query;
+
+            if ( pattern )
+                query = m_ml->searchMediaGroups( pattern, paramsPtr );
+            else
+                query = m_ml->mediaGroups( medialibrary::IMedia::Type::Unknown, paramsPtr );
+
+            if ( query == nullptr )
+                return VLC_EGENERIC;
+
+            switch ( listQuery )
+            {
+                case VLC_ML_LIST_GROUPS:
+                    *va_arg( args, vlc_ml_group_list_t** ) =
+                            ml_convert_list<vlc_ml_group_list_t, vlc_ml_group_t>(
+                                query->items( nbItems, offset ) );
+                    return VLC_SUCCESS;
+
+                case VLC_ML_COUNT_GROUPS:
+                    *va_arg( args, size_t* ) = query->count();
+                    return VLC_SUCCESS;
+
+                default:
+                    vlc_assert_unreachable();
+            }
+        }
+
+        case VLC_ML_LIST_GROUP_MEDIA:
+        case VLC_ML_COUNT_GROUP_MEDIA:
+        {
+            auto group = m_ml->mediaGroup( va_arg( args, int64_t ) );
+
+            if ( group == nullptr )
+                return VLC_EGENERIC;
+
+            medialibrary::Query<medialibrary::IMedia> query;
+
+            if ( pattern )
+                query = group->searchMedia( pattern, medialibrary::IMedia::Type::Unknown,
+                                            paramsPtr );
+            else
+                query = group->media( medialibrary::IMedia::Type::Unknown, paramsPtr );
+
+            if ( query == nullptr )
+                return VLC_EGENERIC;
+
+            switch ( listQuery )
+            {
+                case VLC_ML_LIST_GROUP_MEDIA:
+                    *va_arg( args, vlc_ml_media_list_t**) =
+                            ml_convert_list<vlc_ml_media_list_t, vlc_ml_media_t>(
+                                query->items( nbItems, offset ) );
+                    return VLC_SUCCESS;
+
+                case VLC_ML_COUNT_GROUP_MEDIA:
+                    *va_arg( args, size_t* ) = query->count();
+                    return VLC_SUCCESS;
+
+                default:
+                    vlc_assert_unreachable();
+            }
+        }
+
+        default:
+            vlc_assert_unreachable();
+    }
+}
+
 int MediaLibrary::listPlaylist( int listQuery, const medialibrary::QueryParameters* paramsPtr,
                                 const char* pattern, uint32_t nbItems, uint32_t offset, va_list args )
 {
diff --git a/modules/misc/medialibrary/medialibrary.h b/modules/misc/medialibrary/medialibrary.h
index 8ba8d5c108..70c489a387 100644
--- a/modules/misc/medialibrary/medialibrary.h
+++ b/modules/misc/medialibrary/medialibrary.h
@@ -154,6 +154,8 @@ private:
                     const char* pattern, uint32_t nbItems, uint32_t offset, va_list args );
     int listGenre( int listQuery, const medialibrary::QueryParameters* paramsPtr,
                    const char* pattern, uint32_t nbItems, uint32_t offset, va_list args );
+    int listGroup( int listQuery, const medialibrary::QueryParameters* paramsPtr,
+                   const char* pattern, uint32_t nbItems, uint32_t offset, va_list args );
     int listPlaylist( int listQuery, const medialibrary::QueryParameters* paramsPtr,
                       const char* pattern, uint32_t nbItems, uint32_t offset, va_list args );
     int listMedia( int listQuery, const medialibrary::QueryParameters* paramsPtr,
@@ -223,6 +225,7 @@ bool Convert( const medialibrary::IArtist* input, vlc_ml_artist_t& output );
 bool Convert( const medialibrary::IGenre* input, vlc_ml_genre_t& output );
 bool Convert( const medialibrary::IShow* input, vlc_ml_show_t& output );
 bool Convert( const medialibrary::ILabel* input, vlc_ml_label_t& output );
+bool Convert( const medialibrary::IMediaGroup* input, vlc_ml_group_t& output );
 bool Convert( const medialibrary::IPlaylist* input, vlc_ml_playlist_t& output );
 bool Convert( const medialibrary::IFolder* input, vlc_ml_entry_point_t& output );
 bool Convert( const medialibrary::IBookmark* input, vlc_ml_bookmark_t& output );
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 0c130543e5..45ab569146 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -582,6 +582,7 @@ vlc_ml_artist_release
 vlc_ml_genre_release
 vlc_ml_media_release
 vlc_ml_album_release
+vlc_ml_group_release
 vlc_ml_playlist_release
 vlc_ml_label_list_release
 vlc_ml_file_list_release
@@ -590,6 +591,7 @@ vlc_ml_media_list_release
 vlc_ml_album_list_release
 vlc_ml_show_list_release
 vlc_ml_genre_list_release
+vlc_ml_group_list_release
 vlc_ml_playlist_list_release
 vlc_ml_entry_point_list_release
 vlc_ml_bookmark_release
diff --git a/src/misc/medialibrary.c b/src/misc/medialibrary.c
index f83fc8584b..cc98f2bc94 100644
--- a/src/misc/medialibrary.c
+++ b/src/misc/medialibrary.c
@@ -231,6 +231,24 @@ void vlc_ml_genre_release( vlc_ml_genre_t* p_genre )
     free( p_genre );
 }
 
+//-------------------------------------------------------------------------------------------------
+// Group
+
+static void vlc_ml_group_release_inner( vlc_ml_group_t* p_group )
+{
+    free( p_group->psz_name );
+}
+
+void vlc_ml_group_release( vlc_ml_group_t* p_group )
+{
+    if ( p_group == NULL )
+        return;
+    vlc_ml_group_release_inner( p_group );
+    free( p_group );
+}
+
+//-------------------------------------------------------------------------------------------------
+
 static void vlc_ml_playlist_release_inner( vlc_ml_playlist_t* p_playlist )
 {
     free( p_playlist->psz_name );
@@ -320,6 +338,15 @@ void vlc_ml_genre_list_release( vlc_ml_genre_list_t* p_list )
     free( p_list );
 }
 
+void vlc_ml_group_list_release( vlc_ml_group_list_t* p_list )
+{
+    if ( p_list == NULL )
+        return;
+    for ( size_t i = 0; i < p_list->i_nb_items; ++i )
+        vlc_ml_group_release_inner( &p_list->p_items[i] );
+    free( p_list );
+}
+
 void vlc_ml_playlist_list_release( vlc_ml_playlist_list_t* p_list )
 {
     if ( p_list == NULL )
-- 
2.25.1



More information about the vlc-devel mailing list