1 /*****************************************************************************
2 * medialibrary.cpp: medialibrary module
3 *****************************************************************************
4 * Copyright © 2008-2018 VLC authors, VideoLAN and VideoLabs
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
28 #include <vlc_media_library.h>
29 #include <vlc_dialog.h>
30 #include "medialibrary.h"
32 #include "fs/devicelister.h"
34 #include <medialibrary/IMedia.h>
35 #include <medialibrary/IAlbumTrack.h>
36 #include <medialibrary/IAlbum.h>
37 #include <medialibrary/IArtist.h>
38 #include <medialibrary/IGenre.h>
39 #include <medialibrary/IMetadata.h>
40 #include <medialibrary/IShow.h>
41 #include <medialibrary/IPlaylist.h>
42 #include <medialibrary/IBookmark.h>
45 #include <initializer_list>
47 class Logger
: public medialibrary::ILogger
50 Logger( vlc_object_t
* obj
) : m_obj( obj
) {}
53 virtual void Error( const std::string
& msg
) override
55 msg_Err( m_obj
, "%s", msg
.c_str() );
57 virtual void Warning( const std::string
& msg
) override
59 msg_Warn( m_obj
, "%s", msg
.c_str() );
61 virtual void Info( const std::string
& msg
) override
63 msg_Dbg( m_obj
, "%s", msg
.c_str() );
65 virtual void Debug( const std::string
& msg
) override
67 msg_Dbg( m_obj
, "%s", msg
.c_str() );
69 virtual void Verbose( const std::string
& msg
) override
71 msg_Dbg( m_obj
, "%s", msg
.c_str() );
81 void assignToEvent( vlc_ml_event_t
* ev
, vlc_ml_media_t
* m
) { ev
->creation
.p_media
= m
; }
82 void assignToEvent( vlc_ml_event_t
* ev
, vlc_ml_artist_t
* a
) { ev
->creation
.p_artist
= a
; }
83 void assignToEvent( vlc_ml_event_t
* ev
, vlc_ml_album_t
* a
) { ev
->creation
.p_album
= a
; }
84 void assignToEvent( vlc_ml_event_t
* ev
, vlc_ml_genre_t
* g
) { ev
->creation
.p_genre
= g
; }
85 void assignToEvent( vlc_ml_event_t
* ev
, vlc_ml_playlist_t
* p
) { ev
->creation
.p_playlist
= p
; }
86 void assignToEvent( vlc_ml_event_t
* ev
, vlc_ml_bookmark_t
* b
) { ev
->creation
.p_bookmark
= b
; }
88 template <typename To
, typename From
>
89 void wrapEntityCreatedEventCallback( vlc_medialibrary_module_t
* ml
,
90 const std::vector
<From
>& entities
,
91 vlc_ml_event_type evType
)
95 for ( const auto& e
: entities
)
97 auto val
= vlc::wrap_cptr
<To
>( static_cast<To
*>( calloc( 1, sizeof( To
) ) ),
98 static_cast<void(*)(To
*)>( vlc_ml_release
) );
99 if ( unlikely( val
== nullptr ) )
101 if ( Convert( e
.get(), *val
) == false )
103 assignToEvent( &ev
, val
.get() );
104 ml
->cbs
->pf_send_event( ml
, &ev
);
108 void wrapEntityModifiedEventCallback( vlc_medialibrary_module_t
* ml
,
109 const std::set
<int64_t>& ids
,
110 vlc_ml_event_type evType
)
114 for ( const auto& id
: ids
)
116 ev
.modification
.i_entity_id
= id
;
117 ml
->cbs
->pf_send_event( ml
, &ev
);
121 void wrapEntityDeletedEventCallback( vlc_medialibrary_module_t
* ml
,
122 const std::set
<int64_t>& ids
, vlc_ml_event_type evType
)
126 for ( const auto& id
: ids
)
128 ev
.deletion
.i_entity_id
= id
;
129 ml
->cbs
->pf_send_event( ml
, &ev
);
133 } // end of anonymous namespace
135 void MediaLibrary::onMediaAdded( std::vector
<medialibrary::MediaPtr
> media
)
137 wrapEntityCreatedEventCallback
<vlc_ml_media_t
>( m_vlc_ml
, media
, VLC_ML_EVENT_MEDIA_ADDED
);
140 void MediaLibrary::onMediaModified( std::set
<int64_t> mediaIds
)
142 wrapEntityModifiedEventCallback( m_vlc_ml
, mediaIds
, VLC_ML_EVENT_MEDIA_UPDATED
);
145 void MediaLibrary::onMediaDeleted( std::set
<int64_t> mediaIds
)
147 wrapEntityDeletedEventCallback( m_vlc_ml
, mediaIds
, VLC_ML_EVENT_MEDIA_DELETED
);
150 void MediaLibrary::onArtistsAdded( std::vector
<medialibrary::ArtistPtr
> artists
)
152 wrapEntityCreatedEventCallback
<vlc_ml_artist_t
>( m_vlc_ml
, artists
, VLC_ML_EVENT_ARTIST_ADDED
);
155 void MediaLibrary::onArtistsModified( std::set
<int64_t> artistIds
)
157 wrapEntityModifiedEventCallback( m_vlc_ml
, artistIds
, VLC_ML_EVENT_ARTIST_UPDATED
);
160 void MediaLibrary::onArtistsDeleted( std::set
<int64_t> artistIds
)
162 wrapEntityDeletedEventCallback( m_vlc_ml
, artistIds
, VLC_ML_EVENT_ARTIST_DELETED
);
165 void MediaLibrary::onAlbumsAdded( std::vector
<medialibrary::AlbumPtr
> albums
)
167 wrapEntityCreatedEventCallback
<vlc_ml_album_t
>( m_vlc_ml
, albums
, VLC_ML_EVENT_ALBUM_ADDED
);
170 void MediaLibrary::onAlbumsModified( std::set
<int64_t> albumIds
)
172 wrapEntityModifiedEventCallback( m_vlc_ml
, albumIds
, VLC_ML_EVENT_ALBUM_UPDATED
);
175 void MediaLibrary::onAlbumsDeleted( std::set
<int64_t> albumIds
)
177 wrapEntityDeletedEventCallback( m_vlc_ml
, albumIds
, VLC_ML_EVENT_ALBUM_DELETED
);
180 void MediaLibrary::onPlaylistsAdded( std::vector
<medialibrary::PlaylistPtr
> playlists
)
182 wrapEntityCreatedEventCallback
<vlc_ml_playlist_t
>( m_vlc_ml
, playlists
, VLC_ML_EVENT_PLAYLIST_ADDED
);
185 void MediaLibrary::onPlaylistsModified( std::set
<int64_t> playlistIds
)
187 wrapEntityModifiedEventCallback( m_vlc_ml
, playlistIds
, VLC_ML_EVENT_PLAYLIST_UPDATED
);
190 void MediaLibrary::onPlaylistsDeleted( std::set
<int64_t> playlistIds
)
192 wrapEntityDeletedEventCallback( m_vlc_ml
, playlistIds
, VLC_ML_EVENT_PLAYLIST_DELETED
);
195 void MediaLibrary::onGenresAdded( std::vector
<medialibrary::GenrePtr
> genres
)
197 wrapEntityCreatedEventCallback
<vlc_ml_genre_t
>( m_vlc_ml
, genres
, VLC_ML_EVENT_GENRE_ADDED
);
200 void MediaLibrary::onGenresModified( std::set
<int64_t> genreIds
)
202 wrapEntityModifiedEventCallback( m_vlc_ml
, genreIds
, VLC_ML_EVENT_GENRE_UPDATED
);
205 void MediaLibrary::onGenresDeleted( std::set
<int64_t> genreIds
)
207 wrapEntityDeletedEventCallback( m_vlc_ml
, genreIds
, VLC_ML_EVENT_GENRE_DELETED
);
210 void MediaLibrary::onMediaGroupsAdded( std::vector
<medialibrary::MediaGroupPtr
> )
214 void MediaLibrary::onMediaGroupsModified( std::set
<int64_t> )
218 void MediaLibrary::onMediaGroupsDeleted( std::set
<int64_t> )
222 void MediaLibrary::onBookmarksAdded( std::vector
<medialibrary::BookmarkPtr
> bookmarks
)
224 wrapEntityCreatedEventCallback
<vlc_ml_bookmark_t
>( m_vlc_ml
, bookmarks
,
225 VLC_ML_EVENT_BOOKMARKS_ADDED
);
228 void MediaLibrary::onBookmarksModified( std::set
<int64_t> bookmarkIds
)
230 wrapEntityModifiedEventCallback( m_vlc_ml
, bookmarkIds
,
231 VLC_ML_EVENT_BOOKMARKS_UPDATED
);
234 void MediaLibrary::onBookmarksDeleted( std::set
<int64_t> bookmarkIds
)
236 wrapEntityDeletedEventCallback( m_vlc_ml
, bookmarkIds
,
237 VLC_ML_EVENT_BOOKMARKS_DELETED
);
240 void MediaLibrary::onDiscoveryStarted( const std::string
& entryPoint
)
243 ev
.i_type
= VLC_ML_EVENT_DISCOVERY_STARTED
;
244 ev
.discovery_started
.psz_entry_point
= entryPoint
.c_str();
245 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
248 void MediaLibrary::onDiscoveryProgress( const std::string
& entryPoint
)
251 ev
.i_type
= VLC_ML_EVENT_DISCOVERY_PROGRESS
;
252 ev
.discovery_progress
.psz_entry_point
= entryPoint
.c_str();
253 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
256 void MediaLibrary::onDiscoveryCompleted( const std::string
& entryPoint
, bool success
)
259 ev
.i_type
= VLC_ML_EVENT_DISCOVERY_COMPLETED
;
260 ev
.discovery_completed
.psz_entry_point
= entryPoint
.c_str();
261 ev
.discovery_completed
.b_success
= success
;
262 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
265 void MediaLibrary::onReloadStarted( const std::string
& entryPoint
)
268 ev
.i_type
= VLC_ML_EVENT_RELOAD_STARTED
;
269 ev
.reload_started
.psz_entry_point
= entryPoint
.c_str();
270 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
273 void MediaLibrary::onReloadCompleted( const std::string
& entryPoint
, bool success
)
276 ev
.i_type
= VLC_ML_EVENT_RELOAD_COMPLETED
;
277 ev
.reload_completed
.psz_entry_point
= entryPoint
.c_str();
278 ev
.reload_completed
.b_success
= success
;
279 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
282 void MediaLibrary::onEntryPointAdded( const std::string
& entryPoint
, bool success
)
285 ev
.i_type
= VLC_ML_EVENT_ENTRY_POINT_ADDED
;
286 ev
.entry_point_added
.psz_entry_point
= entryPoint
.c_str();
287 ev
.entry_point_added
.b_success
= success
;
288 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
291 void MediaLibrary::onEntryPointRemoved( const std::string
& entryPoint
, bool success
)
294 ev
.i_type
= VLC_ML_EVENT_ENTRY_POINT_REMOVED
;
295 ev
.entry_point_removed
.psz_entry_point
= entryPoint
.c_str();
296 ev
.entry_point_removed
.b_success
= success
;
297 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
300 void MediaLibrary::onEntryPointBanned( const std::string
& entryPoint
, bool success
)
303 ev
.i_type
= VLC_ML_EVENT_ENTRY_POINT_BANNED
;
304 ev
.entry_point_banned
.psz_entry_point
= entryPoint
.c_str();
305 ev
.entry_point_banned
.b_success
= success
;
306 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
309 void MediaLibrary::onEntryPointUnbanned( const std::string
& entryPoint
, bool success
)
312 ev
.i_type
= VLC_ML_EVENT_ENTRY_POINT_UNBANNED
;
313 ev
.entry_point_unbanned
.psz_entry_point
= entryPoint
.c_str();
314 ev
.entry_point_unbanned
.b_success
= success
;
315 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
318 void MediaLibrary::onParsingStatsUpdated( uint32_t progress
)
321 ev
.i_type
= VLC_ML_EVENT_PARSING_PROGRESS_UPDATED
;
322 ev
.parsing_progress
.i_percent
= progress
;
323 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
326 void MediaLibrary::onBackgroundTasksIdleChanged( bool idle
)
329 ev
.i_type
= VLC_ML_EVENT_BACKGROUND_IDLE_CHANGED
;
330 ev
.background_idle_changed
.b_idle
= idle
;
331 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
334 void MediaLibrary::onMediaThumbnailReady( medialibrary::MediaPtr media
,
335 medialibrary::ThumbnailSizeType sizeType
,
339 ev
.i_type
= VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED
;
340 ev
.media_thumbnail_generated
.b_success
= success
;
341 ev
.media_thumbnail_generated
.i_size
= static_cast<vlc_ml_thumbnail_size_t
>( sizeType
);
342 auto mPtr
= vlc::wrap_cptr
<vlc_ml_media_t
>(
343 static_cast<vlc_ml_media_t
*>( calloc( 1, sizeof( vlc_ml_media_t
) ) ),
344 vlc_ml_media_release
);
345 if ( unlikely( mPtr
== nullptr ) )
347 ev
.media_thumbnail_generated
.p_media
= mPtr
.get();
348 if ( Convert( media
.get(), *mPtr
) == false )
350 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
353 void MediaLibrary::onHistoryChanged( medialibrary::HistoryType historyType
)
356 ev
.i_type
= VLC_ML_EVENT_HISTORY_CHANGED
;
357 switch ( historyType
)
359 case medialibrary::HistoryType::Media
:
360 ev
.history_changed
.history_type
= VLC_ML_HISTORY_TYPE_MEDIA
;
362 case medialibrary::HistoryType::Network
:
363 ev
.history_changed
.history_type
= VLC_ML_HISTORY_TYPE_NETWORK
;
366 vlc_assert_unreachable();
368 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
371 void MediaLibrary::onRescanStarted()
374 ev
.i_type
= VLC_ML_EVENT_RESCAN_STARTED
;
375 m_vlc_ml
->cbs
->pf_send_event( m_vlc_ml
, &ev
);
378 MediaLibrary::MediaLibrary( vlc_medialibrary_module_t
* ml
)
381 m_ml
.reset( NewMediaLibrary() );
383 m_logger
.reset( new Logger( VLC_OBJECT( m_vlc_ml
) ) );
384 m_ml
->setVerbosity( var_InheritBool( VLC_OBJECT( m_vlc_ml
), "ml-verbose" ) ?
385 medialibrary::LogLevel::Debug
: medialibrary::LogLevel::Warning
);
386 m_ml
->setLogger( m_logger
.get() );
389 bool MediaLibrary::Init()
391 vlc::threads::mutex_locker
lock( m_mutex
);
395 auto userDir
= vlc::wrap_cptr( config_GetUserDir( VLC_USERDATA_DIR
) );
396 std::string mlDir
= std::string
{ userDir
.get() } + "/ml/";
398 m_ml
->registerDeviceLister( std::make_shared
<vlc::medialibrary::DeviceLister
>(
399 VLC_OBJECT(m_vlc_ml
) ), "smb://" );
400 m_ml
->addFileSystemFactory( std::make_shared
<vlc::medialibrary::SDFileSystemFactory
>(
401 VLC_OBJECT( m_vlc_ml
), m_ml
.get(), "file://") );
402 m_ml
->addFileSystemFactory( std::make_shared
<vlc::medialibrary::SDFileSystemFactory
>(
403 VLC_OBJECT( m_vlc_ml
), m_ml
.get(), "smb://") );
404 auto initStatus
= m_ml
->initialize( mlDir
+ "ml.db", mlDir
+ "/mlstorage/", this );
405 switch ( initStatus
)
407 case medialibrary::InitializeResult::AlreadyInitialized
:
408 assert(!"initialize() should not have been called if already initialized");
410 case medialibrary::InitializeResult::Failed
:
411 msg_Err( m_vlc_ml
, "Medialibrary failed to initialize" );
413 case medialibrary::InitializeResult::DbReset
:
414 msg_Info( m_vlc_ml
, "Database was reset" );
416 case medialibrary::InitializeResult::Success
:
417 msg_Dbg( m_vlc_ml
, "MediaLibrary successfully initialized" );
419 case medialibrary::InitializeResult::DbCorrupted
:
421 auto res
= vlc_dialog_wait_question(VLC_OBJECT( m_vlc_ml
),
422 VLC_DIALOG_QUESTION_NORMAL
, _( "Ignore" ), _( "Recover" ),
423 _( "Recreate" ), _( "Media database corrupted" ),
424 "Your media database appears to be corrupted. You can try to "
425 "recover it, recreate it entirely, or ignore this error (the "
426 "mediacenter will be disabled)." );
430 m_ml
->clearDatabase( true );
433 m_ml
->clearDatabase( false );
442 m_ml
->addParserService( std::make_shared
<MetadataExtractor
>( VLC_OBJECT( m_vlc_ml
) ) );
445 m_ml
->addThumbnailer( std::make_shared
<Thumbnailer
>( m_vlc_ml
) );
447 catch ( const std::runtime_error
& ex
)
449 msg_Err( m_vlc_ml
, "Failed to provide a thumbnailer module to the "
450 "medialib: %s", ex
.what() );
454 m_ml
->setDiscoverNetworkEnabled( true );
456 m_initialized
= true;
460 bool MediaLibrary::Start()
462 if ( Init() == false )
465 if ( m_started
.test_and_set() )
466 /* The code below should be executed at most once */
470 * If we already provided the medialib with some entry points, then we have
473 auto entryPoints
= m_ml
->entryPoints()->all();
474 if ( entryPoints
.empty() == false )
477 auto folders
= vlc::wrap_cptr( var_InheritString( m_vlc_ml
, "ml-folders" ) );
478 if ( folders
!= nullptr && strlen( folders
.get() ) > 0 )
480 std::istringstream
ss( folders
.get() );
482 while ( std::getline( ss
, folder
, ';' ) )
483 m_ml
->discover( folder
);
487 std::string varValue
;
488 for( auto&& target
: { VLC_VIDEOS_DIR
, VLC_MUSIC_DIR
} )
490 auto folder
= vlc::wrap_cptr( config_GetUserDir( target
) );
491 if( folder
== nullptr )
493 auto folderMrl
= vlc::wrap_cptr( vlc_path2uri( folder
.get(), nullptr ) );
494 m_ml
->discover( folderMrl
.get() );
495 varValue
+= std::string
{ ";" } + folderMrl
.get();
497 if ( varValue
.empty() == false )
498 config_PutPsz( "ml-folders", varValue
.c_str()+1 ); /* skip initial ';' */
503 int MediaLibrary::Control( int query
, va_list args
)
507 case VLC_ML_ADD_FOLDER
:
508 case VLC_ML_REMOVE_FOLDER
:
509 case VLC_ML_BAN_FOLDER
:
510 case VLC_ML_UNBAN_FOLDER
:
511 case VLC_ML_RELOAD_FOLDER
:
512 case VLC_ML_RESUME_BACKGROUND
:
513 case VLC_ML_MEDIA_GENERATE_THUMBNAIL
:
515 /* These operations require the media library to be started
516 * ie. that the background threads are started */
517 if ( Start() == false )
527 case VLC_ML_ADD_FOLDER
:
528 case VLC_ML_REMOVE_FOLDER
:
529 case VLC_ML_BAN_FOLDER
:
530 case VLC_ML_UNBAN_FOLDER
:
532 const char* mrl
= va_arg( args
, const char* );
535 case VLC_ML_ADD_FOLDER
:
536 m_ml
->discover( mrl
);
538 case VLC_ML_REMOVE_FOLDER
:
539 m_ml
->removeEntryPoint( mrl
);
541 case VLC_ML_BAN_FOLDER
:
542 m_ml
->banFolder( mrl
);
544 case VLC_ML_UNBAN_FOLDER
:
545 m_ml
->unbanFolder( mrl
);
550 case VLC_ML_LIST_FOLDERS
:
552 auto entryPoints
= m_ml
->entryPoints()->all();
553 auto res
= ml_convert_list
<vlc_ml_entry_point_list_t
,
554 vlc_ml_entry_point_t
>( entryPoints
);
555 *(va_arg( args
, vlc_ml_entry_point_list_t
**) ) = res
;
558 case VLC_ML_IS_INDEXED
:
560 auto mrl
= va_arg( args
, const char* );
561 auto res
= va_arg( args
, bool* );
562 *res
= m_ml
->isIndexed( mrl
);
565 case VLC_ML_RELOAD_FOLDER
:
567 auto mrl
= va_arg( args
, const char* );
568 if ( mrl
== nullptr )
574 case VLC_ML_PAUSE_BACKGROUND
:
575 m_ml
->pauseBackgroundOperations();
577 case VLC_ML_RESUME_BACKGROUND
:
578 m_ml
->resumeBackgroundOperations();
580 case VLC_ML_CLEAR_HISTORY
:
581 m_ml
->clearHistory();
583 case VLC_ML_NEW_EXTERNAL_MEDIA
:
585 auto mrl
= va_arg( args
, const char* );
586 auto media
= m_ml
->addExternalMedia( mrl
, -1 );
587 if ( media
== nullptr )
589 *va_arg( args
, vlc_ml_media_t
**) = CreateAndConvert
<vlc_ml_media_t
>( media
.get() );
592 case VLC_ML_NEW_STREAM
:
594 auto mrl
= va_arg( args
, const char* );
595 auto media
= m_ml
->addStream( mrl
);
596 if ( media
== nullptr )
598 *va_arg( args
, vlc_ml_media_t
**) = CreateAndConvert
<vlc_ml_media_t
>( media
.get() );
601 case VLC_ML_MEDIA_GENERATE_THUMBNAIL
:
603 auto mediaId
= va_arg( args
, int64_t );
604 auto sizeType
= va_arg( args
, int );
605 auto width
= va_arg( args
, uint32_t );
606 auto height
= va_arg( args
, uint32_t );
607 auto position
= va_arg( args
, double );
608 auto res
= m_ml
->requestThumbnail( mediaId
,
609 static_cast<medialibrary::ThumbnailSizeType
>( sizeType
),
610 width
, height
, position
);
611 return res
== true ? VLC_SUCCESS
: VLC_EGENERIC
;
613 case VLC_ML_MEDIA_UPDATE_PROGRESS
:
614 case VLC_ML_MEDIA_GET_MEDIA_PLAYBACK_STATE
:
615 case VLC_ML_MEDIA_SET_MEDIA_PLAYBACK_STATE
:
616 case VLC_ML_MEDIA_GET_ALL_MEDIA_PLAYBACK_STATES
:
617 case VLC_ML_MEDIA_SET_ALL_MEDIA_PLAYBACK_STATES
:
618 case VLC_ML_MEDIA_SET_THUMBNAIL
:
619 case VLC_ML_MEDIA_ADD_EXTERNAL_MRL
:
620 case VLC_ML_MEDIA_SET_TYPE
:
621 case VLC_ML_MEDIA_ADD_BOOKMARK
:
622 case VLC_ML_MEDIA_REMOVE_BOOKMARK
:
623 case VLC_ML_MEDIA_REMOVE_ALL_BOOKMARKS
:
624 case VLC_ML_MEDIA_UPDATE_BOOKMARK
:
625 return controlMedia( query
, args
);
626 case VLC_ML_PLAYLIST_CREATE
:
628 auto name
= va_arg( args
, const char * );
629 auto playlist
= m_ml
->createPlaylist( name
);
630 if ( playlist
== nullptr )
632 auto result
= va_arg( args
, vlc_ml_playlist_t
** );
633 *result
= CreateAndConvert
<vlc_ml_playlist_t
>( playlist
.get() );
636 case VLC_ML_PLAYLIST_DELETE
:
638 if ( m_ml
->deletePlaylist( va_arg( args
, int64_t ) ) == false )
642 case VLC_ML_PLAYLIST_APPEND
:
644 auto playlist
= m_ml
->playlist( va_arg( args
, int64_t ) );
645 if ( playlist
== nullptr )
647 if ( playlist
->append(va_arg( args
, int64_t )) == false )
657 int MediaLibrary::List( int listQuery
, const vlc_ml_query_params_t
* params
, va_list args
)
659 if ( Init() == false )
662 medialibrary::QueryParameters p
{};
663 medialibrary::QueryParameters
* paramsPtr
= nullptr;
664 uint32_t nbItems
= 0;
666 const char* psz_pattern
= nullptr;
669 p
.desc
= params
->b_desc
;
670 p
.sort
= sortingCriteria( params
->i_sort
);
671 nbItems
= params
->i_nbResults
;
672 offset
= params
->i_offset
;
673 psz_pattern
= params
->psz_pattern
;
678 case VLC_ML_LIST_MEDIA_OF
:
679 case VLC_ML_COUNT_MEDIA_OF
:
680 case VLC_ML_LIST_ARTISTS_OF
:
681 case VLC_ML_COUNT_ARTISTS_OF
:
682 case VLC_ML_LIST_ALBUMS_OF
:
683 case VLC_ML_COUNT_ALBUMS_OF
:
685 auto parentType
= va_arg( args
, int );
686 listQuery
= filterListChildrenQuery( listQuery
, parentType
);
693 case VLC_ML_LIST_ALBUM_TRACKS
:
694 case VLC_ML_COUNT_ALBUM_TRACKS
:
695 case VLC_ML_LIST_ALBUM_ARTISTS
:
696 case VLC_ML_COUNT_ALBUM_ARTISTS
:
697 return listAlbums( listQuery
, paramsPtr
, psz_pattern
, nbItems
, offset
, args
);
699 case VLC_ML_LIST_ARTIST_ALBUMS
:
700 case VLC_ML_COUNT_ARTIST_ALBUMS
:
701 case VLC_ML_LIST_ARTIST_TRACKS
:
702 case VLC_ML_COUNT_ARTIST_TRACKS
:
703 return listArtists( listQuery
, paramsPtr
, psz_pattern
, nbItems
, offset
, args
);
705 case VLC_ML_LIST_VIDEOS
:
707 medialibrary::Query
<medialibrary::IMedia
> query
;
708 if ( psz_pattern
!= nullptr )
709 query
= m_ml
->searchVideo( psz_pattern
, paramsPtr
);
711 query
= m_ml
->videoFiles( paramsPtr
);
712 if ( query
== nullptr )
714 auto res
= ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
715 query
->items( nbItems
, offset
) );
716 *va_arg( args
, vlc_ml_media_list_t
**) = res
;
719 case VLC_ML_COUNT_VIDEOS
:
721 medialibrary::Query
<medialibrary::IMedia
> query
;
722 if ( psz_pattern
!= nullptr )
723 query
= m_ml
->searchVideo( psz_pattern
, paramsPtr
);
725 query
= m_ml
->videoFiles( paramsPtr
);
726 if ( query
== nullptr )
728 *va_arg( args
, size_t* ) = query
->count();
731 case VLC_ML_LIST_AUDIOS
:
733 medialibrary::Query
<medialibrary::IMedia
> query
;
734 if ( psz_pattern
!= nullptr )
735 query
= m_ml
->searchAudio( psz_pattern
, paramsPtr
);
737 query
= m_ml
->audioFiles( paramsPtr
);
738 if ( query
== nullptr )
740 auto res
= ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
741 query
->items( nbItems
, offset
) );
742 *va_arg( args
, vlc_ml_media_list_t
**) = res
;
745 case VLC_ML_COUNT_AUDIOS
:
747 medialibrary::Query
<medialibrary::IMedia
> query
;
748 if ( psz_pattern
!= nullptr )
749 query
= m_ml
->searchAudio( psz_pattern
, paramsPtr
);
751 query
= m_ml
->audioFiles( paramsPtr
);
752 if ( query
== nullptr )
754 *va_arg( args
, size_t* ) = query
->count();
757 case VLC_ML_LIST_ALBUMS
:
759 medialibrary::Query
<medialibrary::IAlbum
> query
;
760 if ( psz_pattern
!= nullptr )
761 query
= m_ml
->searchAlbums( psz_pattern
, paramsPtr
);
763 query
= m_ml
->albums( paramsPtr
);
764 if ( query
== nullptr )
766 auto res
= ml_convert_list
<vlc_ml_album_list_t
, vlc_ml_album_t
>(
767 query
->items( nbItems
, offset
) );
768 *va_arg( args
, vlc_ml_album_list_t
**) = res
;
771 case VLC_ML_COUNT_ALBUMS
:
773 medialibrary::Query
<medialibrary::IAlbum
> query
;
774 if ( psz_pattern
!= nullptr )
775 query
= m_ml
->searchAlbums( psz_pattern
, paramsPtr
);
777 query
= m_ml
->albums( paramsPtr
);
778 if ( query
== nullptr )
780 *va_arg( args
, size_t* ) = query
->count();
783 case VLC_ML_LIST_GENRES
:
785 medialibrary::Query
<medialibrary::IGenre
> query
;
786 if ( psz_pattern
!= nullptr )
787 query
= m_ml
->searchGenre( psz_pattern
, paramsPtr
);
789 query
= m_ml
->genres( paramsPtr
);
790 if ( query
== nullptr )
792 auto res
= ml_convert_list
<vlc_ml_genre_list_t
,vlc_ml_genre_t
>(
793 query
->items( nbItems
, offset
) );
794 *va_arg( args
, vlc_ml_genre_list_t
**) = res
;
797 case VLC_ML_COUNT_GENRES
:
799 medialibrary::Query
<medialibrary::IGenre
> query
;
800 if ( psz_pattern
!= nullptr )
801 query
= m_ml
->searchGenre( psz_pattern
, paramsPtr
);
803 query
= m_ml
->genres( paramsPtr
);
804 if ( query
== nullptr )
806 *va_arg( args
, size_t* ) = query
->count();
809 case VLC_ML_LIST_ARTISTS
:
811 medialibrary::Query
<medialibrary::IArtist
> query
;
812 bool includeAll
= va_arg( args
, int ) != 0;
813 auto artistsIncluded
= includeAll
? medialibrary::ArtistIncluded::All
:
814 medialibrary::ArtistIncluded::AlbumArtistOnly
;
815 if ( psz_pattern
!= nullptr )
816 query
= m_ml
->searchArtists( psz_pattern
, artistsIncluded
, paramsPtr
);
818 query
= m_ml
->artists( artistsIncluded
, paramsPtr
);
819 if ( query
== nullptr )
821 auto res
= ml_convert_list
<vlc_ml_artist_list_t
, vlc_ml_artist_t
>(
822 query
->items( nbItems
, offset
) );
823 *va_arg( args
, vlc_ml_artist_list_t
**) = res
;
826 case VLC_ML_COUNT_ARTISTS
:
828 medialibrary::Query
<medialibrary::IArtist
> query
;
829 bool includeAll
= va_arg( args
, int ) != 0;
830 auto artistsIncluded
= includeAll
? medialibrary::ArtistIncluded::All
:
831 medialibrary::ArtistIncluded::AlbumArtistOnly
;
832 if ( psz_pattern
!= nullptr )
833 query
= m_ml
->searchArtists( psz_pattern
, artistsIncluded
, paramsPtr
);
835 query
= m_ml
->artists( artistsIncluded
, paramsPtr
);
836 if ( query
== nullptr )
838 *va_arg( args
, size_t* ) = query
->count();
841 case VLC_ML_LIST_GENRE_ARTISTS
:
842 case VLC_ML_COUNT_GENRE_ARTISTS
:
843 case VLC_ML_LIST_GENRE_TRACKS
:
844 case VLC_ML_COUNT_GENRE_TRACKS
:
845 case VLC_ML_LIST_GENRE_ALBUMS
:
846 case VLC_ML_COUNT_GENRE_ALBUMS
:
847 return listGenre( listQuery
, paramsPtr
, psz_pattern
, nbItems
, offset
, args
);
849 case VLC_ML_LIST_MEDIA_LABELS
:
850 case VLC_ML_COUNT_MEDIA_LABELS
:
851 case VLC_ML_LIST_MEDIA_BOOKMARKS
:
852 return listMedia( listQuery
, paramsPtr
, psz_pattern
, nbItems
, offset
, args
);
854 case VLC_ML_LIST_SHOWS
:
856 medialibrary::Query
<medialibrary::IShow
> query
;
857 if ( psz_pattern
!= nullptr )
858 query
= m_ml
->searchShows( psz_pattern
, paramsPtr
);
860 query
= m_ml
->shows( paramsPtr
);
861 if ( query
== nullptr )
863 *va_arg( args
, vlc_ml_show_list_t
** ) =
864 ml_convert_list
<vlc_ml_show_list_t
, vlc_ml_show_t
>(
865 query
->items( nbItems
, offset
) );
868 case VLC_ML_COUNT_SHOWS
:
870 auto query
= m_ml
->shows( paramsPtr
);
871 if ( query
== nullptr )
873 *va_arg( args
, int64_t* ) = query
->count();
876 case VLC_ML_LIST_SHOW_EPISODES
:
877 case VLC_ML_COUNT_SHOW_EPISODES
:
879 auto show
= m_ml
->show( va_arg( args
, int64_t ) );
880 if ( show
== nullptr )
882 medialibrary::Query
<medialibrary::IMedia
> query
;
883 if ( psz_pattern
!= nullptr )
884 query
= show
->searchEpisodes( psz_pattern
, paramsPtr
);
886 query
= show
->episodes( paramsPtr
);
887 if ( query
== nullptr )
891 case VLC_ML_LIST_SHOW_EPISODES
:
892 *va_arg( args
, vlc_ml_media_list_t
**) =
893 ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
894 query
->items( nbItems
, offset
) );
896 case VLC_ML_COUNT_SHOW_EPISODES
:
897 *va_arg( args
, int64_t* ) = query
->count();
900 vlc_assert_unreachable();
903 case VLC_ML_LIST_PLAYLIST_MEDIA
:
904 case VLC_ML_COUNT_PLAYLIST_MEDIA
:
905 case VLC_ML_LIST_PLAYLISTS
:
906 case VLC_ML_COUNT_PLAYLISTS
:
907 return listPlaylist( listQuery
, paramsPtr
, psz_pattern
, nbItems
, offset
, args
);
908 case VLC_ML_COUNT_HISTORY
:
909 case VLC_ML_LIST_HISTORY
:
910 case VLC_ML_COUNT_HISTORY_BY_TYPE
:
911 case VLC_ML_LIST_HISTORY_BY_TYPE
:
912 case VLC_ML_COUNT_STREAM_HISTORY
:
913 case VLC_ML_LIST_STREAM_HISTORY
:
915 medialibrary::Query
<medialibrary::IMedia
> query
;
919 case VLC_ML_COUNT_HISTORY
:
920 case VLC_ML_LIST_HISTORY
:
921 query
= m_ml
->history();
923 case VLC_ML_COUNT_HISTORY_BY_TYPE
:
924 case VLC_ML_LIST_HISTORY_BY_TYPE
:
926 auto type
= va_arg(args
, int);
927 query
= m_ml
->history(static_cast<medialibrary::IMedia::Type
>( type
));
930 case VLC_ML_COUNT_STREAM_HISTORY
:
931 case VLC_ML_LIST_STREAM_HISTORY
:
932 query
= m_ml
->streamHistory();
935 vlc_assert_unreachable();
938 if ( query
== nullptr )
943 case VLC_ML_LIST_HISTORY
:
944 case VLC_ML_LIST_HISTORY_BY_TYPE
:
945 case VLC_ML_LIST_STREAM_HISTORY
:
946 *va_arg( args
, vlc_ml_media_list_t
**) =
947 ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
948 query
->items( nbItems
, offset
) );
950 case VLC_ML_COUNT_HISTORY
:
951 case VLC_ML_COUNT_HISTORY_BY_TYPE
:
952 case VLC_ML_COUNT_STREAM_HISTORY
:
953 *va_arg( args
, size_t* ) = query
->count();
956 vlc_assert_unreachable();
964 void* MediaLibrary::Get( int query
, va_list args
)
966 if ( Init() == false )
971 case VLC_ML_GET_MEDIA
:
973 auto id
= va_arg( args
, int64_t );
974 auto media
= m_ml
->media( id
);
975 return CreateAndConvert
<vlc_ml_media_t
>( media
.get() );
977 case VLC_ML_GET_INPUT_ITEM
:
979 auto id
= va_arg( args
, int64_t );
980 auto media
= m_ml
->media( id
);
981 return MediaToInputItem( media
.get() );
983 case VLC_ML_GET_ALBUM
:
985 auto id
= va_arg( args
, int64_t );
986 auto album
= m_ml
->album( id
);
987 return CreateAndConvert
<vlc_ml_album_t
>( album
.get() );
989 case VLC_ML_GET_ARTIST
:
991 auto id
= va_arg( args
, int64_t );
992 auto artist
= m_ml
->artist( id
);
993 return CreateAndConvert
<vlc_ml_artist_t
>( artist
.get() );
995 case VLC_ML_GET_GENRE
:
997 auto id
= va_arg( args
, int64_t );
998 auto genre
= m_ml
->genre( id
);
999 return CreateAndConvert
<vlc_ml_genre_t
>( genre
.get() );
1001 case VLC_ML_GET_SHOW
:
1003 auto id
= va_arg( args
, int64_t );
1004 auto show
= m_ml
->show( id
);
1005 return CreateAndConvert
<vlc_ml_show_t
>( show
.get() );
1007 case VLC_ML_GET_PLAYLIST
:
1009 auto id
= va_arg( args
, int64_t );
1010 auto playlist
= m_ml
->playlist( id
);
1011 return CreateAndConvert
<vlc_ml_playlist_t
>( playlist
.get() );
1013 case VLC_ML_GET_MEDIA_BY_MRL
:
1015 auto mrl
= va_arg( args
, const char* );
1016 auto media
= m_ml
->media( mrl
);
1017 return CreateAndConvert
<vlc_ml_media_t
>( media
.get() );
1019 case VLC_ML_GET_INPUT_ITEM_BY_MRL
:
1021 auto mrl
= va_arg( args
, const char* );
1022 auto media
= m_ml
->media( mrl
);
1023 if ( media
== nullptr )
1025 return MediaToInputItem( media
.get() );
1028 vlc_assert_unreachable();
1034 medialibrary::IMedia::MetadataType
MediaLibrary::metadataType( int meta
)
1038 case VLC_ML_PLAYBACK_STATE_RATING
:
1039 return medialibrary::IMedia::MetadataType::Rating
;
1040 case VLC_ML_PLAYBACK_STATE_SPEED
:
1041 return medialibrary::IMedia::MetadataType::Speed
;
1042 case VLC_ML_PLAYBACK_STATE_TITLE
:
1043 return medialibrary::IMedia::MetadataType::Title
;
1044 case VLC_ML_PLAYBACK_STATE_CHAPTER
:
1045 return medialibrary::IMedia::MetadataType::Chapter
;
1046 case VLC_ML_PLAYBACK_STATE_PROGRAM
:
1047 return medialibrary::IMedia::MetadataType::Program
;
1048 case VLC_ML_PLAYBACK_STATE_SEEN
:
1049 return medialibrary::IMedia::MetadataType::Seen
;
1050 case VLC_ML_PLAYBACK_STATE_VIDEO_TRACK
:
1051 return medialibrary::IMedia::MetadataType::VideoTrack
;
1052 case VLC_ML_PLAYBACK_STATE_ASPECT_RATIO
:
1053 return medialibrary::IMedia::MetadataType::AspectRatio
;
1054 case VLC_ML_PLAYBACK_STATE_ZOOM
:
1055 return medialibrary::IMedia::MetadataType::Zoom
;
1056 case VLC_ML_PLAYBACK_STATE_CROP
:
1057 return medialibrary::IMedia::MetadataType::Crop
;
1058 case VLC_ML_PLAYBACK_STATE_DEINTERLACE
:
1059 return medialibrary::IMedia::MetadataType::Deinterlace
;
1060 case VLC_ML_PLAYBACK_STATE_VIDEO_FILTER
:
1061 return medialibrary::IMedia::MetadataType::VideoFilter
;
1062 case VLC_ML_PLAYBACK_STATE_AUDIO_TRACK
:
1063 return medialibrary::IMedia::MetadataType::AudioTrack
;
1064 case VLC_ML_PLAYBACK_STATE_GAIN
:
1065 return medialibrary::IMedia::MetadataType::Gain
;
1066 case VLC_ML_PLAYBACK_STATE_AUDIO_DELAY
:
1067 return medialibrary::IMedia::MetadataType::AudioDelay
;
1068 case VLC_ML_PLAYBACK_STATE_SUBTITLE_TRACK
:
1069 return medialibrary::IMedia::MetadataType::SubtitleTrack
;
1070 case VLC_ML_PLAYBACK_STATE_SUBTITLE_DELAY
:
1071 return medialibrary::IMedia::MetadataType::SubtitleDelay
;
1072 case VLC_ML_PLAYBACK_STATE_APP_SPECIFIC
:
1073 return medialibrary::IMedia::MetadataType::ApplicationSpecific
;
1075 vlc_assert_unreachable();
1079 medialibrary::SortingCriteria
MediaLibrary::sortingCriteria(int sort
)
1083 case VLC_ML_SORTING_DEFAULT
:
1084 return medialibrary::SortingCriteria::Default
;
1085 case VLC_ML_SORTING_ALPHA
:
1086 return medialibrary::SortingCriteria::Alpha
;
1087 case VLC_ML_SORTING_DURATION
:
1088 return medialibrary::SortingCriteria::Duration
;
1089 case VLC_ML_SORTING_INSERTIONDATE
:
1090 return medialibrary::SortingCriteria::InsertionDate
;
1091 case VLC_ML_SORTING_LASTMODIFICATIONDATE
:
1092 return medialibrary::SortingCriteria::LastModificationDate
;
1093 case VLC_ML_SORTING_RELEASEDATE
:
1094 return medialibrary::SortingCriteria::ReleaseDate
;
1095 case VLC_ML_SORTING_FILESIZE
:
1096 return medialibrary::SortingCriteria::FileSize
;
1097 case VLC_ML_SORTING_ARTIST
:
1098 return medialibrary::SortingCriteria::Artist
;
1099 case VLC_ML_SORTING_PLAYCOUNT
:
1100 return medialibrary::SortingCriteria::PlayCount
;
1101 case VLC_ML_SORTING_ALBUM
:
1102 return medialibrary::SortingCriteria::Album
;
1103 case VLC_ML_SORTING_FILENAME
:
1104 return medialibrary::SortingCriteria::Filename
;
1105 case VLC_ML_SORTING_TRACKNUMBER
:
1106 return medialibrary::SortingCriteria::TrackNumber
;
1108 vlc_assert_unreachable();
1112 int MediaLibrary::getMeta( const medialibrary::IMedia
& media
, int meta
, char** result
)
1114 auto& md
= media
.metadata( metadataType( meta
) );
1115 if ( md
.isSet() == false )
1120 *result
= strdup( md
.asStr().c_str() );
1121 if ( *result
== nullptr )
1126 int MediaLibrary::getMeta( const medialibrary::IMedia
& media
,
1127 vlc_ml_playback_states_all
* res
)
1129 auto metas
= media
.metadata();
1132 res
->current_title
= -1;
1133 // For tracks, -1 means disabled, so we can't use it for "unset"
1134 res
->current_video_track
= res
->current_audio_track
=
1135 res
->current_subtitle_track
= nullptr;
1136 res
->aspect_ratio
= res
->crop
= res
->deinterlace
=
1137 res
->video_filter
= nullptr;
1138 for ( const auto& meta
: metas
)
1140 #define COPY_META( field ) res->field = strdup( meta.second.c_str() ); \
1141 if ( res->field == nullptr ) return VLC_ENOMEM;
1143 switch ( meta
.first
)
1145 case medialibrary::IMedia::MetadataType::Speed
:
1146 res
->rate
= atof( meta
.second
.c_str() );
1148 case medialibrary::IMedia::MetadataType::Title
:
1149 res
->current_title
= atoi( meta
.second
.c_str() );
1151 case medialibrary::IMedia::MetadataType::VideoTrack
:
1152 COPY_META( current_video_track
);
1154 case medialibrary::IMedia::MetadataType::AspectRatio
:
1155 COPY_META( aspect_ratio
);
1157 case medialibrary::IMedia::MetadataType::Zoom
:
1158 res
->zoom
= atof( meta
.second
.c_str() );
1160 case medialibrary::IMedia::MetadataType::Crop
:
1163 case medialibrary::IMedia::MetadataType::Deinterlace
:
1164 COPY_META( deinterlace
);
1166 case medialibrary::IMedia::MetadataType::VideoFilter
:
1167 COPY_META( video_filter
);
1169 case medialibrary::IMedia::MetadataType::AudioTrack
:
1170 COPY_META( current_audio_track
);
1172 case medialibrary::IMedia::MetadataType::SubtitleTrack
:
1173 COPY_META( current_subtitle_track
);
1183 int MediaLibrary::setMeta( medialibrary::IMedia
& media
, int meta
, const char* value
)
1186 if ( value
== nullptr )
1187 res
= media
.unsetMetadata( metadataType( meta
) );
1189 res
= media
.setMetadata( metadataType( meta
), value
);
1191 return VLC_EGENERIC
;
1195 int MediaLibrary::setMeta( medialibrary::IMedia
& media
,
1196 const vlc_ml_playback_states_all
* values
)
1198 using MT
= medialibrary::IMedia::MetadataType
;
1199 std::unordered_map
<MT
, std::string
> metas
;
1200 if ( values
->rate
!= .0f
)
1201 metas
[MT::Speed
] = std::to_string( values
->rate
);
1202 if ( values
->zoom
!= .0f
)
1203 metas
[MT::Zoom
] = std::to_string( values
->zoom
);
1204 if ( values
->current_title
>= 0 )
1205 metas
[MT::Title
] = std::to_string( values
->current_title
);
1206 if ( values
->aspect_ratio
!= nullptr )
1207 metas
[MT::AspectRatio
] = values
->aspect_ratio
;
1208 if ( values
->crop
!= nullptr )
1209 metas
[MT::Crop
] = values
->crop
;
1210 if ( values
->deinterlace
!= nullptr )
1211 metas
[MT::Deinterlace
] = values
->deinterlace
;
1212 if ( values
->video_filter
!= nullptr )
1213 metas
[MT::VideoFilter
] = values
->video_filter
;
1214 if ( values
->current_video_track
!= nullptr )
1215 metas
[MT::VideoTrack
] = values
->current_video_track
;
1216 if ( values
->current_audio_track
!= nullptr )
1217 metas
[MT::AudioTrack
] = values
->current_audio_track
;
1218 if ( values
->current_subtitle_track
!= nullptr )
1219 metas
[MT::SubtitleTrack
] = values
->current_subtitle_track
;
1221 if ( media
.setMetadata( std::move( metas
) ) == false )
1222 return VLC_EGENERIC
;
1226 int MediaLibrary::controlMedia( int query
, va_list args
)
1228 auto mediaId
= va_arg( args
, int64_t );
1229 auto m
= m_ml
->media( mediaId
);
1231 return VLC_EGENERIC
;
1234 case VLC_ML_MEDIA_UPDATE_PROGRESS
:
1235 if ( m
->setProgress( va_arg( args
, double ) ) == false )
1236 return VLC_EGENERIC
;
1238 case VLC_ML_MEDIA_GET_MEDIA_PLAYBACK_STATE
:
1240 auto meta
= va_arg( args
, int );
1241 auto res
= va_arg( args
, char** );
1242 return getMeta( *m
, meta
, res
);
1244 case VLC_ML_MEDIA_SET_MEDIA_PLAYBACK_STATE
:
1246 auto meta
= va_arg( args
, int );
1247 auto value
= va_arg( args
, const char* );
1248 return setMeta( *m
, meta
, value
);
1250 case VLC_ML_MEDIA_GET_ALL_MEDIA_PLAYBACK_STATES
:
1252 auto res
= va_arg( args
, vlc_ml_playback_states_all
* );
1253 return getMeta( *m
, res
);
1255 case VLC_ML_MEDIA_SET_ALL_MEDIA_PLAYBACK_STATES
:
1257 auto res
= va_arg( args
, const vlc_ml_playback_states_all
* );
1258 return setMeta( *m
, res
);
1260 case VLC_ML_MEDIA_SET_THUMBNAIL
:
1262 auto mrl
= va_arg( args
, const char* );
1263 auto sizeType
= va_arg( args
, int );
1264 m
->setThumbnail( mrl
, static_cast<medialibrary::ThumbnailSizeType
>( sizeType
) );
1267 case VLC_ML_MEDIA_ADD_EXTERNAL_MRL
:
1269 auto mrl
= va_arg( args
, const char* );
1270 auto type
= va_arg( args
, int );
1271 medialibrary::IFile::Type mlType
;
1274 case VLC_ML_FILE_TYPE_UNKNOWN
:
1275 // The type can't be main since this is added to an existing media
1276 // which must already have a file
1277 case VLC_ML_FILE_TYPE_MAIN
:
1278 case VLC_ML_FILE_TYPE_PLAYLIST
:
1279 return VLC_EGENERIC
;
1280 case VLC_ML_FILE_TYPE_PART
:
1281 mlType
= medialibrary::IFile::Type::Part
;
1283 case VLC_ML_FILE_TYPE_SOUNDTRACK
:
1284 mlType
= medialibrary::IFile::Type::Soundtrack
;
1286 case VLC_ML_FILE_TYPE_SUBTITLE
:
1287 mlType
= medialibrary::IFile::Type::Subtitles
;
1290 vlc_assert_unreachable();
1292 if ( m
->addExternalMrl( mrl
, mlType
) == nullptr )
1293 return VLC_EGENERIC
;
1296 case VLC_ML_MEDIA_SET_TYPE
:
1298 auto type
= va_arg( args
, int );
1299 if ( m
->setType( static_cast<medialibrary::IMedia::Type
>( type
) ) == false )
1300 return VLC_EGENERIC
;
1303 case VLC_ML_MEDIA_ADD_BOOKMARK
:
1305 auto time
= va_arg( args
, int64_t );
1306 if ( m
->addBookmark( time
) == nullptr )
1307 return VLC_EGENERIC
;
1308 return VLC_EGENERIC
;
1310 case VLC_ML_MEDIA_REMOVE_BOOKMARK
:
1312 auto time
= va_arg( args
, int64_t );
1313 if ( m
->removeBookmark( time
) == false )
1314 return VLC_EGENERIC
;
1317 case VLC_ML_MEDIA_REMOVE_ALL_BOOKMARKS
:
1319 if ( m
->removeAllBookmarks() == false )
1320 return VLC_EGENERIC
;
1323 case VLC_ML_MEDIA_UPDATE_BOOKMARK
:
1325 auto time
= va_arg( args
, int64_t );
1326 auto name
= va_arg( args
, const char* );
1327 auto desc
= va_arg( args
, const char* );
1328 auto bookmark
= m
->bookmark( time
);
1329 if ( bookmark
== nullptr )
1330 return VLC_EGENERIC
;
1332 if ( name
!= nullptr && desc
!= nullptr )
1333 res
= bookmark
->setNameAndDescription( name
, desc
);
1334 else if ( name
!= nullptr )
1335 res
= bookmark
->setName( name
);
1336 else if ( desc
!= nullptr )
1337 res
= bookmark
->setDescription( desc
);
1338 return res
? VLC_SUCCESS
: VLC_EGENERIC
;
1341 vlc_assert_unreachable();
1345 int MediaLibrary::filterListChildrenQuery( int query
, int parentType
)
1349 case VLC_ML_LIST_MEDIA_OF
:
1350 switch ( parentType
)
1352 case VLC_ML_PARENT_ALBUM
:
1353 return VLC_ML_LIST_ALBUM_TRACKS
;
1354 case VLC_ML_PARENT_ARTIST
:
1355 return VLC_ML_LIST_ARTIST_TRACKS
;
1356 case VLC_ML_PARENT_SHOW
:
1357 return VLC_ML_LIST_SHOW_EPISODES
;
1358 case VLC_ML_PARENT_GENRE
:
1359 return VLC_ML_LIST_GENRE_TRACKS
;
1360 case VLC_ML_PARENT_PLAYLIST
:
1361 return VLC_ML_LIST_PLAYLIST_MEDIA
;
1363 vlc_assert_unreachable();
1365 case VLC_ML_COUNT_MEDIA_OF
:
1366 switch ( parentType
)
1368 case VLC_ML_PARENT_ALBUM
:
1369 return VLC_ML_COUNT_ALBUM_TRACKS
;
1370 case VLC_ML_PARENT_ARTIST
:
1371 return VLC_ML_COUNT_ARTIST_TRACKS
;
1372 case VLC_ML_PARENT_SHOW
:
1373 return VLC_ML_COUNT_SHOW_EPISODES
;
1374 case VLC_ML_PARENT_GENRE
:
1375 return VLC_ML_COUNT_GENRE_TRACKS
;
1376 case VLC_ML_PARENT_PLAYLIST
:
1377 return VLC_ML_COUNT_PLAYLIST_MEDIA
;
1379 vlc_assert_unreachable();
1381 case VLC_ML_LIST_ALBUMS_OF
:
1382 switch ( parentType
)
1384 case VLC_ML_PARENT_ARTIST
:
1385 return VLC_ML_LIST_ARTIST_ALBUMS
;
1386 case VLC_ML_PARENT_GENRE
:
1387 return VLC_ML_LIST_GENRE_ALBUMS
;
1389 vlc_assert_unreachable();
1391 case VLC_ML_COUNT_ALBUMS_OF
:
1392 switch ( parentType
)
1394 case VLC_ML_PARENT_ARTIST
:
1395 return VLC_ML_COUNT_ARTIST_ALBUMS
;
1396 case VLC_ML_PARENT_GENRE
:
1397 return VLC_ML_COUNT_GENRE_ALBUMS
;
1399 vlc_assert_unreachable();
1401 case VLC_ML_LIST_ARTISTS_OF
:
1402 switch ( parentType
)
1404 case VLC_ML_PARENT_ALBUM
:
1405 return VLC_ML_LIST_ALBUM_ARTISTS
;
1406 case VLC_ML_PARENT_GENRE
:
1407 return VLC_ML_LIST_GENRE_ARTISTS
;
1409 vlc_assert_unreachable();
1411 case VLC_ML_COUNT_ARTISTS_OF
:
1412 switch ( parentType
)
1414 case VLC_ML_PARENT_ALBUM
:
1415 return VLC_ML_COUNT_ALBUM_ARTISTS
;
1416 case VLC_ML_PARENT_GENRE
:
1417 return VLC_ML_COUNT_GENRE_ARTISTS
;
1419 vlc_assert_unreachable();
1422 vlc_assert_unreachable();
1426 int MediaLibrary::listAlbums( int listQuery
, const medialibrary::QueryParameters
* paramsPtr
,
1427 const char* pattern
, uint32_t nbItems
, uint32_t offset
, va_list args
)
1429 auto album
= m_ml
->album( va_arg( args
, int64_t ) );
1430 if ( album
== nullptr )
1431 return VLC_EGENERIC
;
1432 switch ( listQuery
)
1434 case VLC_ML_LIST_ALBUM_TRACKS
:
1435 case VLC_ML_COUNT_ALBUM_TRACKS
:
1437 medialibrary::Query
<medialibrary::IMedia
> query
;
1438 if ( pattern
!= nullptr )
1439 query
= album
->searchTracks( pattern
, paramsPtr
);
1441 query
= album
->tracks( paramsPtr
);
1442 if ( query
== nullptr )
1443 return VLC_EGENERIC
;
1444 switch ( listQuery
)
1446 case VLC_ML_LIST_ALBUM_TRACKS
:
1447 *va_arg( args
, vlc_ml_media_list_t
**) =
1448 ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
1449 query
->items( nbItems
, offset
) );
1451 case VLC_ML_COUNT_ALBUM_TRACKS
:
1452 *va_arg( args
, size_t* ) = query
->count();
1455 vlc_assert_unreachable();
1458 case VLC_ML_LIST_ALBUM_ARTISTS
:
1459 case VLC_ML_COUNT_ALBUM_ARTISTS
:
1461 auto query
= album
->artists( paramsPtr
);
1462 if ( query
== nullptr )
1463 return VLC_EGENERIC
;
1464 switch ( listQuery
)
1466 case VLC_ML_LIST_ALBUM_ARTISTS
:
1467 *va_arg( args
, vlc_ml_artist_list_t
**) =
1468 ml_convert_list
<vlc_ml_artist_list_t
, vlc_ml_artist_t
>(
1469 query
->items( nbItems
, offset
) );
1471 case VLC_ML_COUNT_ALBUM_ARTISTS
:
1472 *va_arg( args
, size_t* ) = query
->count();
1475 vlc_assert_unreachable();
1479 vlc_assert_unreachable();
1483 int MediaLibrary::listArtists( int listQuery
, const medialibrary::QueryParameters
* paramsPtr
,
1484 const char* pattern
, uint32_t nbItems
, uint32_t offset
,
1487 auto artist
= m_ml
->artist( va_arg( args
, int64_t ) );
1488 if ( artist
== nullptr )
1489 return VLC_EGENERIC
;
1492 case VLC_ML_LIST_ARTIST_ALBUMS
:
1493 case VLC_ML_COUNT_ARTIST_ALBUMS
:
1495 medialibrary::Query
<medialibrary::IAlbum
> query
;
1496 if ( pattern
!= nullptr )
1497 query
= artist
->searchAlbums( pattern
, paramsPtr
);
1499 query
= artist
->albums( paramsPtr
);
1500 if ( query
== nullptr )
1501 return VLC_EGENERIC
;
1502 switch ( listQuery
)
1504 case VLC_ML_LIST_ARTIST_ALBUMS
:
1505 *va_arg( args
, vlc_ml_album_list_t
**) =
1506 ml_convert_list
<vlc_ml_album_list_t
, vlc_ml_album_t
>(
1507 query
->items( nbItems
, offset
) );
1509 case VLC_ML_COUNT_ARTIST_ALBUMS
:
1510 *va_arg( args
, size_t* ) = query
->count();
1513 vlc_assert_unreachable();
1516 case VLC_ML_LIST_ARTIST_TRACKS
:
1517 case VLC_ML_COUNT_ARTIST_TRACKS
:
1519 medialibrary::Query
<medialibrary::IMedia
> query
;
1520 if ( pattern
!= nullptr )
1521 query
= artist
->searchTracks( pattern
, paramsPtr
);
1523 query
= artist
->tracks( paramsPtr
);
1524 if ( query
== nullptr )
1525 return VLC_EGENERIC
;
1526 switch ( listQuery
)
1528 case VLC_ML_LIST_ARTIST_TRACKS
:
1529 *va_arg( args
, vlc_ml_media_list_t
**) =
1530 ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
1531 query
->items( nbItems
, offset
) );
1533 case VLC_ML_COUNT_ARTIST_TRACKS
:
1534 *va_arg( args
, size_t* ) = query
->count();
1537 vlc_assert_unreachable();
1541 vlc_assert_unreachable();
1545 int MediaLibrary::listGenre( int listQuery
, const medialibrary::QueryParameters
* paramsPtr
,
1546 const char* pattern
, uint32_t nbItems
, uint32_t offset
, va_list args
)
1548 auto genre
= m_ml
->genre( va_arg( args
, int64_t ) );
1549 if ( genre
== nullptr )
1550 return VLC_EGENERIC
;
1553 case VLC_ML_LIST_GENRE_ARTISTS
:
1554 case VLC_ML_COUNT_GENRE_ARTISTS
:
1556 medialibrary::Query
<medialibrary::IArtist
> query
;
1557 if ( pattern
!= nullptr )
1558 query
= genre
->searchArtists( pattern
, paramsPtr
);
1560 query
= genre
->artists( paramsPtr
);
1561 if ( query
== nullptr )
1562 return VLC_EGENERIC
;
1563 switch ( listQuery
)
1565 case VLC_ML_LIST_GENRE_ARTISTS
:
1566 *va_arg( args
, vlc_ml_artist_list_t
**) =
1567 ml_convert_list
<vlc_ml_artist_list_t
, vlc_ml_artist_t
>(
1568 query
->items( nbItems
, offset
) );
1570 case VLC_ML_COUNT_GENRE_ARTISTS
:
1571 *va_arg( args
, size_t* ) = query
->count();
1574 vlc_assert_unreachable();
1577 case VLC_ML_LIST_GENRE_TRACKS
:
1578 case VLC_ML_COUNT_GENRE_TRACKS
:
1580 medialibrary::Query
<medialibrary::IMedia
> query
;
1581 if ( pattern
!= nullptr )
1582 query
= genre
->searchTracks( pattern
, paramsPtr
);
1584 query
= genre
->tracks( medialibrary::IGenre::TracksIncluded::All
,
1586 if ( query
== nullptr )
1587 return VLC_EGENERIC
;
1588 switch ( listQuery
)
1590 case VLC_ML_LIST_GENRE_TRACKS
:
1591 *va_arg( args
, vlc_ml_media_list_t
**) =
1592 ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
1593 query
->items( nbItems
, offset
) );
1595 case VLC_ML_COUNT_GENRE_TRACKS
:
1596 *va_arg( args
, size_t*) = query
->count();
1599 vlc_assert_unreachable();
1602 case VLC_ML_LIST_GENRE_ALBUMS
:
1603 case VLC_ML_COUNT_GENRE_ALBUMS
:
1605 medialibrary::Query
<medialibrary::IAlbum
> query
;
1606 if ( pattern
!= nullptr )
1607 query
= genre
->searchAlbums( pattern
, paramsPtr
);
1609 query
= genre
->albums( paramsPtr
);
1610 if ( query
== nullptr )
1611 return VLC_EGENERIC
;
1612 switch ( listQuery
)
1614 case VLC_ML_LIST_GENRE_ALBUMS
:
1615 *va_arg( args
, vlc_ml_album_list_t
**) =
1616 ml_convert_list
<vlc_ml_album_list_t
, vlc_ml_album_t
>(
1617 query
->items( nbItems
, offset
) );
1619 case VLC_ML_COUNT_GENRE_ALBUMS
:
1620 *va_arg( args
, size_t* ) = query
->count();
1623 vlc_assert_unreachable();
1627 vlc_assert_unreachable();
1631 int MediaLibrary::listPlaylist( int listQuery
, const medialibrary::QueryParameters
* paramsPtr
,
1632 const char* pattern
, uint32_t nbItems
, uint32_t offset
, va_list args
)
1636 case VLC_ML_LIST_PLAYLISTS
:
1637 case VLC_ML_COUNT_PLAYLISTS
:
1639 medialibrary::Query
<medialibrary::IPlaylist
> query
;
1640 if ( pattern
!= nullptr )
1641 query
= m_ml
->searchPlaylists( pattern
, paramsPtr
);
1643 query
= m_ml
->playlists( paramsPtr
);
1644 if ( query
== nullptr )
1645 return VLC_EGENERIC
;
1646 switch ( listQuery
)
1648 case VLC_ML_LIST_PLAYLISTS
:
1649 *va_arg( args
, vlc_ml_playlist_list_t
** ) =
1650 ml_convert_list
<vlc_ml_playlist_list_t
, vlc_ml_playlist_t
>(
1651 query
->items( nbItems
, offset
) );
1653 case VLC_ML_COUNT_PLAYLISTS
:
1654 *va_arg( args
, size_t* ) = query
->count();
1657 vlc_assert_unreachable();
1660 case VLC_ML_LIST_PLAYLIST_MEDIA
:
1661 case VLC_ML_COUNT_PLAYLIST_MEDIA
:
1663 auto playlist
= m_ml
->playlist( va_arg( args
, int64_t ) );
1664 if ( playlist
== nullptr )
1665 return VLC_EGENERIC
;
1666 medialibrary::Query
<medialibrary::IMedia
> query
;
1667 if ( pattern
!= nullptr )
1668 query
= playlist
->searchMedia( pattern
, paramsPtr
);
1670 query
= playlist
->media();
1671 if ( query
== nullptr )
1672 return VLC_EGENERIC
;
1673 switch ( listQuery
)
1675 case VLC_ML_LIST_PLAYLIST_MEDIA
:
1676 *va_arg( args
, vlc_ml_media_list_t
**) =
1677 ml_convert_list
<vlc_ml_media_list_t
, vlc_ml_media_t
>(
1678 query
->items( nbItems
, offset
) );
1680 case VLC_ML_COUNT_PLAYLIST_MEDIA
:
1681 *va_arg( args
, size_t* ) = query
->count();
1684 vlc_assert_unreachable();
1688 vlc_assert_unreachable();
1692 int MediaLibrary::listMedia( int listQuery
, const medialibrary::QueryParameters
*params
,
1693 const char *, uint32_t nbItems
, uint32_t offset
,
1696 auto media
= m_ml
->media( va_arg( args
, int64_t ) );
1697 if ( media
== nullptr )
1698 return VLC_EGENERIC
;
1699 switch ( listQuery
)
1701 case VLC_ML_LIST_MEDIA_LABELS
:
1702 case VLC_ML_COUNT_MEDIA_LABELS
:
1704 auto query
= media
->labels();
1705 if ( query
== nullptr )
1706 return VLC_EGENERIC
;
1707 switch ( listQuery
)
1709 case VLC_ML_LIST_MEDIA_LABELS
:
1710 *va_arg( args
, vlc_ml_label_list_t
**) =
1711 ml_convert_list
<vlc_ml_label_list_t
, vlc_ml_label_t
>(
1712 query
->items( nbItems
, offset
) );
1714 case VLC_ML_COUNT_MEDIA_LABELS
:
1715 *va_arg( args
, size_t* ) = query
->count();
1718 vlc_assert_unreachable();
1721 case VLC_ML_LIST_MEDIA_BOOKMARKS
:
1723 *va_arg( args
, vlc_ml_bookmark_list_t
** ) =
1724 ml_convert_list
<vlc_ml_bookmark_list_t
, vlc_ml_bookmark_t
>(
1725 media
->bookmarks( params
)->all() );
1729 vlc_assert_unreachable();
1733 static void* Get( vlc_medialibrary_module_t
* module
, int query
, va_list args
)
1735 auto ml
= static_cast<MediaLibrary
*>( module
->p_sys
);
1736 return ml
->Get( query
, args
);
1739 static int List( vlc_medialibrary_module_t
* module
, int query
,
1740 const vlc_ml_query_params_t
* params
, va_list args
)
1742 auto ml
= static_cast<MediaLibrary
*>( module
->p_sys
);
1743 return ml
->List( query
, params
, args
);
1746 static int Control( vlc_medialibrary_module_t
* module
, int query
, va_list args
)
1748 auto ml
= static_cast<MediaLibrary
*>( module
->p_sys
);
1749 return ml
->Control( query
, args
);
1752 static int Open( vlc_object_t
* obj
)
1754 auto* p_ml
= reinterpret_cast<vlc_medialibrary_module_t
*>( obj
);
1758 p_ml
->p_sys
= new MediaLibrary( p_ml
);
1760 catch ( const std::exception
& ex
)
1762 msg_Err( obj
, "Failed to instantiate/initialize medialibrary: %s", ex
.what() );
1763 return VLC_EGENERIC
;
1765 p_ml
->pf_control
= Control
;
1767 p_ml
->pf_list
= List
;
1771 static void Close( vlc_object_t
* obj
)
1773 vlc_medialibrary_module_t
*module
= reinterpret_cast<vlc_medialibrary_module_t
*>( obj
);
1774 MediaLibrary
* p_ml
= static_cast<MediaLibrary
*>( module
->p_sys
);
1778 #define ML_FOLDER_TEXT _( "Folders discovered by the media library" )
1779 #define ML_FOLDER_LONGTEXT _( "Semicolon separated list of folders to discover " \
1782 #define ML_VERBOSE _( "Extra verbose media library logs" )
1785 set_shortname(N_("media library"))
1786 set_description(N_( "Organize your media" ))
1787 set_category(CAT_ADVANCED
)
1788 set_subcategory(SUBCAT_ADVANCED_MISC
)
1789 set_capability("medialibrary", 100)
1790 set_callbacks(Open
, Close
)
1791 add_string( "ml-folders", nullptr, ML_FOLDER_TEXT
, ML_FOLDER_LONGTEXT
, false )
1792 add_bool( "ml-verbose", false, ML_VERBOSE
, ML_VERBOSE
, false )