From 7cbdb33cce3f3a59562e0e042b3b93c9fda407ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Beauz=C3=A9e-Luyssen?= Date: Wed, 11 Mar 2020 12:22:17 +0100 Subject: [PATCH] medialib: Add bookmark support --- include/vlc_media_library.h | 74 ++++++++++++++++++- modules/misc/medialibrary/entities.cpp | 11 +++ modules/misc/medialibrary/medialib.cpp | 93 ++++++++++++++++++++---- modules/misc/medialibrary/medialibrary.h | 1 + src/libvlccore.sym | 2 + src/misc/medialibrary.c | 23 ++++++ 6 files changed, 188 insertions(+), 16 deletions(-) diff --git a/include/vlc_media_library.h b/include/vlc_media_library.h index e5ed68604e..fd82a71a23 100644 --- a/include/vlc_media_library.h +++ b/include/vlc_media_library.h @@ -305,6 +305,20 @@ typedef struct vlc_ml_entry_point_list_t vlc_ml_entry_point_t p_items[]; } vlc_ml_entry_point_list_t; +typedef struct vlc_ml_bookmark_t +{ + int64_t i_media_id; /**< The associated media ID */ + int64_t i_time; /**< The bookmark time. The unit is arbitrary */ + char* psz_name; /**< The bookmark name */ + char* psz_description; /**< The bookmark description */ +} vlc_ml_bookmark_t; + +typedef struct vlc_ml_boomkmark_list_t +{ + size_t i_nb_items; + vlc_ml_bookmark_t p_items[]; +} vlc_ml_bookmark_list_t; + /* Opaque medialibrary pointer, to be used by any non-medialibrary module */ typedef struct vlc_medialibrary_t vlc_medialibrary_t; /* "Private" medialibrary pointer, to be used by the core & medialibrary modules */ @@ -404,6 +418,7 @@ enum vlc_ml_list_queries /* Media specific listings */ VLC_ML_LIST_MEDIA_LABELS, /**< arg1: media id; arg2 (out): vlc_ml_label_list_t** */ 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** */ /* Playlist specific listings */ VLC_ML_LIST_PLAYLIST_MEDIA, /**< arg1: playlist id; arg2 (out): vlc_ml_media_list_t** */ @@ -465,6 +480,10 @@ enum vlc_ml_control VLC_ML_MEDIA_GENERATE_THUMBNAIL, /**< arg1: media id; arg2: vlc_ml_thumbnail_size_t; arg3: width; arg4: height; arg5: position */ VLC_ML_MEDIA_ADD_EXTERNAL_MRL, /**< arg1: media id; arg2: const char*; arg3: type(vlc_ml_file_type_t) */ VLC_ML_MEDIA_SET_TYPE, /**< arg1: media id; arg2: vlc_ml_media_type_t */ + VLC_ML_MEDIA_ADD_BOOKMARK, /**< arg1: media id; arg2: int64_t */ + VLC_ML_MEDIA_REMOVE_BOOKMARK, /**< arg1: media id; arg2: int64_t */ + VLC_ML_MEDIA_REMOVE_ALL_BOOKMARKS, /**< arg1: media id */ + VLC_ML_MEDIA_UPDATE_BOOKMARK, /**< arg1: media id; arg2: int64_t; arg3: const char*; arg4: const char* */ }; /** @@ -541,6 +560,9 @@ enum vlc_ml_event_type VLC_ML_EVENT_GENRE_ADDED, VLC_ML_EVENT_GENRE_UPDATED, VLC_ML_EVENT_GENRE_DELETED, + VLC_ML_EVENT_BOOKMARKS_ADDED, + VLC_ML_EVENT_BOOKMARKS_UPDATED, + VLC_ML_EVENT_BOOKMARKS_DELETED, /** * A discovery started. * For each VLC_ML_EVENT_DISCOVERY_STARTED event, there will be @@ -704,6 +726,7 @@ typedef struct vlc_ml_event_t const vlc_ml_album_t* p_album; const vlc_ml_playlist_t* p_playlist; const vlc_ml_genre_t* p_genre; + const vlc_ml_bookmark_t* p_bookmark; } creation; struct { @@ -827,6 +850,8 @@ VLC_API void vlc_ml_genre_list_release( vlc_ml_genre_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 ); +VLC_API void vlc_ml_bookmark_release( vlc_ml_bookmark_t* p_bookmark ); +VLC_API void vlc_ml_bookmark_list_release( vlc_ml_bookmark_list_t* p_list ); static inline vlc_ml_query_params_t vlc_ml_query_params_create() { @@ -964,6 +989,49 @@ static inline int vlc_ml_media_set_type( vlc_medialibrary_t* p_ml, int64_t i_med return vlc_ml_control( p_ml, VLC_ML_MEDIA_SET_TYPE, i_media_id, (int)i_type ); } +static inline vlc_ml_bookmark_list_t* +vlc_ml_list_media_bookmarks( vlc_medialibrary_t* p_ml, const vlc_ml_query_params_t* params, + int64_t i_media_id ) +{ + assert( p_ml != NULL ); + vlc_ml_bookmark_list_t* res; + if ( vlc_ml_list( p_ml, VLC_ML_LIST_MEDIA_BOOKMARKS, params, i_media_id, + &res ) != VLC_SUCCESS ) + return NULL; + return res; +} + +static inline int +vlc_ml_media_add_bookmark( vlc_medialibrary_t* p_ml, int64_t i_media_id, int64_t i_time ) +{ + assert( p_ml != NULL ); + return vlc_ml_control( p_ml, VLC_ML_MEDIA_ADD_BOOKMARK, i_media_id, i_time ); +} + +static inline int +vlc_ml_media_remove_bookmark( vlc_medialibrary_t* p_ml, int64_t i_media_id, int64_t i_time ) +{ + assert( p_ml != NULL ); + return vlc_ml_control( p_ml, VLC_ML_MEDIA_REMOVE_BOOKMARK, i_media_id, i_time ); +} + +static inline int +vlc_ml_media_update_bookmark( vlc_medialibrary_t* p_ml, int64_t i_media_id, + int64_t i_time, const char* psz_name, + const char* psz_desc ) +{ + assert( p_ml != NULL ); + return vlc_ml_control( p_ml, VLC_ML_MEDIA_UPDATE_BOOKMARK, i_media_id, + i_time, psz_name, psz_desc ); +} + +static inline int +vlc_ml_media_remove_all_bookmarks( vlc_medialibrary_t* p_ml, int64_t i_media_id ) +{ + assert( p_ml != NULL ); + return vlc_ml_control( p_ml, VLC_ML_MEDIA_REMOVE_ALL_BOOKMARKS, i_media_id ); +} + static inline vlc_ml_media_t* vlc_ml_get_media( vlc_medialibrary_t* p_ml, int64_t i_media_id ) { return (vlc_ml_media_t*)vlc_ml_get( p_ml, VLC_ML_GET_MEDIA, i_media_id ); @@ -1416,7 +1484,9 @@ static inline size_t vlc_ml_count_playlist_media( vlc_medialibrary_t* p_ml, cons vlc_ml_genre_list_t*: vlc_ml_genre_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 \ + vlc_ml_playback_states_all*: vlc_ml_playback_states_all_release, \ + vlc_ml_bookmark_t*: vlc_ml_bookmark_release, \ + vlc_ml_bookmark_list_t*: vlc_ml_bookmark_list_release \ )( OBJ ) #else static inline void vlc_ml_release( vlc_ml_show_t* show ) { vlc_ml_show_release( show ); } @@ -1435,6 +1505,8 @@ static inline void vlc_ml_release( vlc_ml_genre_list_t* list ) { vlc_ml_genre_li 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 ); } +static inline void vlc_ml_release( vlc_ml_bookmark_t* bookmark ) { vlc_ml_bookmark_release( bookmark ); } +static inline void vlc_ml_release( vlc_ml_bookmark_list_t* list ) { vlc_ml_bookmark_list_release( list ); } #endif #endif /* VLC_MEDIA_LIBRARY_H */ diff --git a/modules/misc/medialibrary/entities.cpp b/modules/misc/medialibrary/entities.cpp index d41fb9632c..8c567f954a 100644 --- a/modules/misc/medialibrary/entities.cpp +++ b/modules/misc/medialibrary/entities.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -416,6 +417,16 @@ bool Convert( const medialibrary::IFolder* input, vlc_ml_entry_point_t& output ) return true; } +bool Convert( const medialibrary::IBookmark* input, vlc_ml_bookmark_t& output ) +{ + if ( strdup_helper( input->name(), output.psz_name ) == false || + strdup_helper( input->description(), output.psz_description ) == false ) + return false; + output.i_media_id = input->mediaId(); + output.i_time = input->time(); + return true; +} + input_item_t* MediaToInputItem( const medialibrary::IMedia* media ) { if ( media == nullptr ) diff --git a/modules/misc/medialibrary/medialib.cpp b/modules/misc/medialibrary/medialib.cpp index 9239a768ef..b73cd46c55 100644 --- a/modules/misc/medialibrary/medialib.cpp +++ b/modules/misc/medialibrary/medialib.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,7 @@ void assignToEvent( vlc_ml_event_t* ev, vlc_ml_artist_t* a ) { ev->creation.p_ 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_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; } template void wrapEntityCreatedEventCallback( vlc_medialibrary_module_t* ml, @@ -217,19 +219,22 @@ void MediaLibrary::onMediaGroupsDeleted( std::set ) { } -void MediaLibrary::onBookmarksAdded( std::vector ) +void MediaLibrary::onBookmarksAdded( std::vector bookmarks ) { - + wrapEntityCreatedEventCallback( m_vlc_ml, bookmarks, + VLC_ML_EVENT_BOOKMARKS_ADDED ); } -void MediaLibrary::onBookmarksModified( std::set ) +void MediaLibrary::onBookmarksModified( std::set bookmarkIds ) { - + wrapEntityModifiedEventCallback( m_vlc_ml, bookmarkIds, + VLC_ML_EVENT_BOOKMARKS_UPDATED ); } -void MediaLibrary::onBookmarksDeleted( std::set ) +void MediaLibrary::onBookmarksDeleted( std::set bookmarkIds ) { - + wrapEntityDeletedEventCallback( m_vlc_ml, bookmarkIds, + VLC_ML_EVENT_BOOKMARKS_DELETED ); } void MediaLibrary::onDiscoveryStarted( const std::string& entryPoint ) @@ -594,6 +599,10 @@ int MediaLibrary::Control( int query, va_list args ) case VLC_ML_MEDIA_GENERATE_THUMBNAIL: case VLC_ML_MEDIA_ADD_EXTERNAL_MRL: case VLC_ML_MEDIA_SET_TYPE: + case VLC_ML_MEDIA_ADD_BOOKMARK: + case VLC_ML_MEDIA_REMOVE_BOOKMARK: + case VLC_ML_MEDIA_REMOVE_ALL_BOOKMARKS: + case VLC_ML_MEDIA_UPDATE_BOOKMARK: return controlMedia( query, args ); default: return VLC_EGENERIC; @@ -795,6 +804,7 @@ int MediaLibrary::List( int listQuery, const vlc_ml_query_params_t* params, va_l case VLC_ML_LIST_MEDIA_LABELS: case VLC_ML_COUNT_MEDIA_LABELS: + case VLC_ML_LIST_MEDIA_BOOKMARKS: return listMedia( listQuery, paramsPtr, psz_pattern, nbItems, offset, args ); case VLC_ML_LIST_SHOWS: @@ -1232,6 +1242,43 @@ int MediaLibrary::controlMedia( int query, va_list args ) return VLC_EGENERIC; return VLC_SUCCESS; } + case VLC_ML_MEDIA_ADD_BOOKMARK: + { + auto time = va_arg( args, int64_t ); + if ( m->addBookmark( time ) == nullptr ) + return VLC_EGENERIC; + return VLC_EGENERIC; + } + case VLC_ML_MEDIA_REMOVE_BOOKMARK: + { + auto time = va_arg( args, int64_t ); + if ( m->removeBookmark( time ) == false ) + return VLC_EGENERIC; + return VLC_SUCCESS; + } + case VLC_ML_MEDIA_REMOVE_ALL_BOOKMARKS: + { + if ( m->removeAllBookmarks() == false ) + return VLC_EGENERIC; + return VLC_SUCCESS; + } + case VLC_ML_MEDIA_UPDATE_BOOKMARK: + { + auto time = va_arg( args, int64_t ); + auto name = va_arg( args, const char* ); + auto desc = va_arg( args, const char* ); + auto bookmark = m->bookmark( time ); + if ( bookmark == nullptr ) + return VLC_EGENERIC; + auto res = false; + if ( name != nullptr && desc != nullptr ) + res = bookmark->setNameAndDescription( name, desc ); + else if ( name != nullptr ) + res = bookmark->setName( name ); + else if ( desc != nullptr ) + res = bookmark->setDescription( desc ); + return res ? VLC_SUCCESS : VLC_EGENERIC; + } default: vlc_assert_unreachable(); } @@ -1584,26 +1631,42 @@ int MediaLibrary::listPlaylist( int listQuery, const medialibrary::QueryParamete } } -int MediaLibrary::listMedia( int listQuery, const medialibrary::QueryParameters *, +int MediaLibrary::listMedia( int listQuery, const medialibrary::QueryParameters *params, const char *, uint32_t nbItems, uint32_t offset, va_list args ) { auto media = m_ml->media( va_arg( args, int64_t ) ); if ( media == nullptr ) return VLC_EGENERIC; - auto query = media->labels(); - if ( query == nullptr ) - return VLC_EGENERIC; switch ( listQuery ) { case VLC_ML_LIST_MEDIA_LABELS: - *va_arg( args, vlc_ml_label_list_t**) = - ml_convert_list( - query->items( nbItems, offset ) ); - return VLC_SUCCESS; case VLC_ML_COUNT_MEDIA_LABELS: - *va_arg( args, size_t* ) = query->count(); + { + auto query = media->labels(); + if ( query == nullptr ) + return VLC_EGENERIC; + switch ( listQuery ) + { + case VLC_ML_LIST_MEDIA_LABELS: + *va_arg( args, vlc_ml_label_list_t**) = + ml_convert_list( + query->items( nbItems, offset ) ); + return VLC_SUCCESS; + case VLC_ML_COUNT_MEDIA_LABELS: + *va_arg( args, size_t* ) = query->count(); + return VLC_SUCCESS; + default: + vlc_assert_unreachable(); + } + } + case VLC_ML_LIST_MEDIA_BOOKMARKS: + { + *va_arg( args, vlc_ml_bookmark_list_t** ) = + ml_convert_list( + media->bookmarks( params )->all() ); return VLC_SUCCESS; + } default: vlc_assert_unreachable(); } diff --git a/modules/misc/medialibrary/medialibrary.h b/modules/misc/medialibrary/medialibrary.h index 80fcc68ac4..5fc0e28d99 100644 --- a/modules/misc/medialibrary/medialibrary.h +++ b/modules/misc/medialibrary/medialibrary.h @@ -220,6 +220,7 @@ 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::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 ); input_item_t* MediaToInputItem( const medialibrary::IMedia* media ); template diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 88d558f39f..116b5d8d2b 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -575,6 +575,8 @@ vlc_ml_show_list_release vlc_ml_genre_list_release vlc_ml_playlist_list_release vlc_ml_entry_point_list_release +vlc_ml_bookmark_release +vlc_ml_bookmark_list_release vlc_poll_i11e vlc_read_i11e vlc_readv_i11e diff --git a/src/misc/medialibrary.c b/src/misc/medialibrary.c index 895f010ae9..140f055b5f 100644 --- a/src/misc/medialibrary.c +++ b/src/misc/medialibrary.c @@ -348,6 +348,29 @@ void vlc_ml_playback_states_all_release( vlc_ml_playback_states_all* prefs ) free( prefs->video_filter ); } +static void vlc_ml_bookmark_release_inner( vlc_ml_bookmark_t* bookmark ) +{ + free( bookmark->psz_name ); + free( bookmark->psz_description ); +} + +void vlc_ml_bookmark_release( vlc_ml_bookmark_t* bookmark ) +{ + if ( bookmark == NULL ) + return; + vlc_ml_bookmark_release_inner( bookmark ); + free( bookmark ); +} + +void vlc_ml_bookmark_list_release( vlc_ml_bookmark_list_t* list ) +{ + if ( list == NULL ) + return; + for ( size_t i = 0; i < list->i_nb_items; ++i ) + vlc_ml_bookmark_release_inner( &list->p_items[i] ); + free( list ); +} + void* vlc_ml_get( vlc_medialibrary_t* p_ml, int i_query, ... ) { assert( p_ml != NULL );