vlc/modules/misc/medialibrary/medialibrary.cpp

2224 lines
79 KiB
C++

/*****************************************************************************
* medialibrary.cpp: medialibrary module
*****************************************************************************
* Copyright © 2008-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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_configuration.h>
#include <vlc_plugin.h>
#include <vlc_url.h>
#include <vlc_media_library.h>
#include <vlc_dialog.h>
#include "medialibrary.h"
#include "fs/fs.h"
#include "fs/devicelister.h"
#include <medialibrary/IMedia.h>
#include <medialibrary/IAlbum.h>
#include <medialibrary/IArtist.h>
#include <medialibrary/IGenre.h>
#include <medialibrary/IMetadata.h>
#include <medialibrary/IShow.h>
#include <medialibrary/IMediaGroup.h>
#include <medialibrary/IPlaylist.h>
#include <medialibrary/IBookmark.h>
#include <medialibrary/IFolder.h>
#include <sstream>
#include <initializer_list>
class Logger : public medialibrary::ILogger
{
public:
Logger( vlc_object_t* obj ) : m_obj( obj ) {}
private:
void Error( const std::string& msg ) override
{
msg_Err( m_obj, "%s", msg.c_str() );
}
void Warning( const std::string& msg ) override
{
msg_Warn( m_obj, "%s", msg.c_str() );
}
void Info( const std::string& msg ) override
{
msg_Dbg( m_obj, "%s", msg.c_str() );
}
void Debug( const std::string& msg ) override
{
msg_Dbg( m_obj, "%s", msg.c_str() );
}
void Verbose( const std::string& msg ) override
{
msg_Dbg( m_obj, "%s", msg.c_str() );
}
private:
vlc_object_t* m_obj;
};
namespace
{
void assignToEvent( vlc_ml_event_t* ev, vlc_ml_media_t* m ) { ev->creation.p_media = m; }
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; }
void assignToEvent( vlc_ml_event_t* ev, vlc_ml_folder_t* f ) { ev->creation.p_folder = f; }
template <typename To, typename From>
void wrapEntityCreatedEventCallback( vlc_medialibrary_module_t* ml,
const std::vector<From>& entities,
vlc_ml_event_type evType )
{
vlc_ml_event_t ev;
ev.i_type = evType;
for ( const auto& e : entities )
{
auto val = vlc::wrap_cptr<To>( static_cast<To*>( calloc( 1, sizeof( To ) ) ),
static_cast<void(*)(To*)>( vlc_ml_release ) );
if ( unlikely( val == nullptr ) )
return;
if ( Convert( e.get(), *val ) == false )
return;
assignToEvent( &ev, val.get() );
ml->cbs->pf_send_event( ml, &ev );
}
}
void wrapEntityModifiedEventCallback( vlc_medialibrary_module_t* ml,
const std::set<int64_t>& ids,
vlc_ml_event_type evType )
{
vlc_ml_event_t ev;
ev.i_type = evType;
for ( const auto& id : ids )
{
ev.modification.i_entity_id = id;
ml->cbs->pf_send_event( ml, &ev );
}
}
void wrapEntityDeletedEventCallback( vlc_medialibrary_module_t* ml,
const std::set<int64_t>& ids, vlc_ml_event_type evType )
{
vlc_ml_event_t ev;
ev.i_type = evType;
for ( const auto& id : ids )
{
ev.deletion.i_entity_id = id;
ml->cbs->pf_send_event( ml, &ev );
}
}
} // end of anonymous namespace
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::set<int64_t> mediaIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, mediaIds, VLC_ML_EVENT_MEDIA_UPDATED );
}
void MediaLibrary::onMediaDeleted( std::set<int64_t> mediaIds )
{
wrapEntityDeletedEventCallback( m_vlc_ml, mediaIds, VLC_ML_EVENT_MEDIA_DELETED );
}
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::set<int64_t> artistIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, artistIds, VLC_ML_EVENT_ARTIST_UPDATED );
}
void MediaLibrary::onArtistsDeleted( std::set<int64_t> artistIds )
{
wrapEntityDeletedEventCallback( m_vlc_ml, artistIds, VLC_ML_EVENT_ARTIST_DELETED );
}
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::set<int64_t> albumIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, albumIds, VLC_ML_EVENT_ALBUM_UPDATED );
}
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 );
}
void MediaLibrary::onPlaylistsModified( std::set<int64_t> playlistIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, playlistIds, VLC_ML_EVENT_PLAYLIST_UPDATED );
}
void MediaLibrary::onPlaylistsDeleted( std::set<int64_t> playlistIds )
{
wrapEntityDeletedEventCallback( m_vlc_ml, playlistIds, VLC_ML_EVENT_PLAYLIST_DELETED );
}
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::set<int64_t> genreIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, genreIds, VLC_ML_EVENT_GENRE_UPDATED );
}
void MediaLibrary::onGenresDeleted( std::set<int64_t> genreIds )
{
wrapEntityDeletedEventCallback( m_vlc_ml, genreIds, VLC_ML_EVENT_GENRE_DELETED );
}
void MediaLibrary::onBookmarksAdded( std::vector<medialibrary::BookmarkPtr> bookmarks )
{
wrapEntityCreatedEventCallback<vlc_ml_bookmark_t>( m_vlc_ml, bookmarks,
VLC_ML_EVENT_BOOKMARKS_ADDED );
}
void MediaLibrary::onBookmarksModified( std::set<int64_t> bookmarkIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, bookmarkIds,
VLC_ML_EVENT_BOOKMARKS_UPDATED );
}
void MediaLibrary::onBookmarksDeleted( std::set<int64_t> bookmarkIds )
{
wrapEntityDeletedEventCallback( m_vlc_ml, bookmarkIds,
VLC_ML_EVENT_BOOKMARKS_DELETED );
}
void MediaLibrary::onFoldersAdded( std::vector<medialibrary::FolderPtr> folders )
{
wrapEntityCreatedEventCallback<vlc_ml_folder_t>( m_vlc_ml, folders,
VLC_ML_EVENT_FOLDER_ADDED );
}
void MediaLibrary::onFoldersModified( std::set<int64_t> folderIds )
{
wrapEntityModifiedEventCallback( m_vlc_ml, folderIds,
VLC_ML_EVENT_FOLDER_UPDATED );
}
void MediaLibrary::onFoldersDeleted( std::set<int64_t> folderIds )
{
wrapEntityDeletedEventCallback( m_vlc_ml, folderIds,
VLC_ML_EVENT_FOLDER_DELETED );
}
void MediaLibrary::onDiscoveryStarted()
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_DISCOVERY_STARTED;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onDiscoveryProgress( const std::string& entryPoint )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_DISCOVERY_PROGRESS;
ev.discovery_progress.psz_entry_point = entryPoint.c_str();
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onDiscoveryCompleted()
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_DISCOVERY_COMPLETED;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onDiscoveryFailed( const std::string& entryPoint )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_DISCOVERY_FAILED;
ev.discovery_failed.psz_entry_point = entryPoint.c_str();
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onRootAdded( const std::string& entryPoint, bool success )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_ENTRY_POINT_ADDED;
ev.entry_point_added.psz_entry_point = entryPoint.c_str();
ev.entry_point_added.b_success = success;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onRootRemoved( const std::string& entryPoint, bool success )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_ENTRY_POINT_REMOVED;
ev.entry_point_removed.psz_entry_point = entryPoint.c_str();
ev.entry_point_removed.b_success = success;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onRootBanned( const std::string& entryPoint, bool success )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_ENTRY_POINT_BANNED;
ev.entry_point_banned.psz_entry_point = entryPoint.c_str();
ev.entry_point_banned.b_success = success;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onRootUnbanned( const std::string& entryPoint, bool success )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_ENTRY_POINT_UNBANNED;
ev.entry_point_unbanned.psz_entry_point = entryPoint.c_str();
ev.entry_point_unbanned.b_success = success;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onParsingStatsUpdated( uint32_t done, uint32_t scheduled )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_PARSING_PROGRESS_UPDATED;
ev.parsing_progress.i_percent = (float)done / (float)scheduled * 100.f;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onBackgroundTasksIdleChanged( bool idle )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_BACKGROUND_IDLE_CHANGED;
ev.background_idle_changed.b_idle = idle;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onMediaThumbnailReady( medialibrary::MediaPtr media,
medialibrary::ThumbnailSizeType sizeType,
bool success )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED;
ev.media_thumbnail_generated.b_success = success;
ev.media_thumbnail_generated.i_size = static_cast<vlc_ml_thumbnail_size_t>( sizeType );
auto mPtr = vlc::wrap_cptr<vlc_ml_media_t>(
static_cast<vlc_ml_media_t*>( calloc( 1, sizeof( vlc_ml_media_t ) ) ),
vlc_ml_media_release );
if ( unlikely( mPtr == nullptr ) )
return;
ev.media_thumbnail_generated.p_media = mPtr.get();
if ( Convert( media.get(), *mPtr ) == false )
return;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onHistoryChanged( medialibrary::HistoryType historyType )
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_HISTORY_CHANGED;
switch ( historyType )
{
case medialibrary::HistoryType::Global:
ev.history_changed.history_type = VLC_ML_HISTORY_TYPE_GLOBAL;
break;
case medialibrary::HistoryType::Local:
ev.history_changed.history_type = VLC_ML_HISTORY_TYPE_LOCAL;
break;
case medialibrary::HistoryType::Network:
ev.history_changed.history_type = VLC_ML_HISTORY_TYPE_NETWORK;
break;
default:
vlc_assert_unreachable();
}
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
void MediaLibrary::onRescanStarted()
{
vlc_ml_event_t ev;
ev.i_type = VLC_ML_EVENT_RESCAN_STARTED;
m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev );
}
MediaLibrary* MediaLibrary::create( vlc_medialibrary_module_t* vlc_ml )
{
char *userdir = config_GetUserDir( VLC_USERDATA_DIR );
if (unlikely(userdir == nullptr))
return nullptr;
auto userDir = vlc::wrap_cptr( userdir );
auto mlDir = std::string{ userDir.get() } + "/ml/";
auto dbPath = mlDir + "ml.db";
auto mlFolderPath = mlDir + "mlstorage/";
medialibrary::SetupConfig cfg;
cfg.deviceListers = { { "smb://", std::make_shared<vlc::medialibrary::DeviceLister>(
VLC_OBJECT(vlc_ml) ) } };
cfg.fsFactories = {
std::make_shared<vlc::medialibrary::SDFileSystemFactory>(
VLC_OBJECT( vlc_ml ), "file://"),
std::make_shared<vlc::medialibrary::SDFileSystemFactory>(
VLC_OBJECT( vlc_ml ), "smb://")
};
cfg.parserServices = {
std::make_shared<MetadataExtractor>( VLC_OBJECT( vlc_ml ) )
};
cfg.logLevel = var_InheritBool( VLC_OBJECT( vlc_ml ), "ml-verbose" ) ?
medialibrary::LogLevel::Debug : medialibrary::LogLevel::Warning;
cfg.logger = std::make_shared<Logger>( VLC_OBJECT( vlc_ml ) );
msg_Dbg(VLC_OBJECT(vlc_ml), "Opening medialibrary from %s, db at %s",
dbPath.c_str(), mlFolderPath.c_str());
auto ml = NewMediaLibrary( dbPath.c_str(), mlFolderPath.c_str(), true, &cfg );
if ( !ml )
return nullptr;
return new MediaLibrary( vlc_ml, ml );
}
MediaLibrary::MediaLibrary( vlc_medialibrary_module_t* vlc_ml,
medialibrary::IMediaLibrary* ml )
: m_vlc_ml( vlc_ml )
, m_ml( ml )
{
}
bool MediaLibrary::Init()
{
vlc::threads::mutex_locker lock( m_mutex );
if( m_initialized )
return true;
auto initStatus = m_ml->initialize( this );
switch ( initStatus )
{
case medialibrary::InitializeResult::AlreadyInitialized:
assert(!"initialize() should not have been called if already initialized");
return true;
case medialibrary::InitializeResult::Failed:
msg_Err( m_vlc_ml, "Medialibrary failed to initialize" );
return false;
case medialibrary::InitializeResult::DbReset:
msg_Info( m_vlc_ml, "Database was reset" );
break;
case medialibrary::InitializeResult::Success:
msg_Dbg( m_vlc_ml, "MediaLibrary successfully initialized" );
break;
case medialibrary::InitializeResult::DbCorrupted:
{
auto res = vlc_dialog_wait_question(VLC_OBJECT( m_vlc_ml ),
VLC_DIALOG_QUESTION_NORMAL, _( "Ignore" ), _( "Recover" ),
_( "Recreate" ), _( "Media database corrupted" ),
"Your media database appears to be corrupted. You can try to "
"recover it, recreate it entirely, or ignore this error (the "
"mediacenter will be disabled)." );
switch ( res )
{
case 1:
m_ml->clearDatabase( true );
break;
case 2:
m_ml->clearDatabase( false );
break;
default:
return false;
}
break;
}
}
try
{
m_ml->addThumbnailer( std::make_shared<Thumbnailer>( m_vlc_ml ) );
}
catch ( const std::runtime_error& ex )
{
msg_Err( m_vlc_ml, "Failed to provide a thumbnailer module to the "
"medialib: %s", ex.what() );
return false;
}
m_ml->setDiscoverNetworkEnabled( true );
m_initialized = true;
return true;
}
int MediaLibrary::Control( int query, va_list args )
{
/*
* Contrary to Get and List requests, not all Control requests may acquire
* the priority access safely (without deadlocks) currently: some of them
* indirectly acquire the internal medialibrary mutex (for example,
* MediaLibrary::reload() calls startDiscoverer()), which may be locked by
* a non-priority caller.
*
* Therefore, priority access is only acquired for Control requests which
* do not suffer for this problem.
*
* See <https://code.videolan.org/videolan/vlc/-/merge_requests/223>
*/
switch ( query )
{
case VLC_ML_ADD_FOLDER:
case VLC_ML_REMOVE_FOLDER:
case VLC_ML_BAN_FOLDER:
case VLC_ML_UNBAN_FOLDER:
case VLC_ML_RELOAD_FOLDER:
case VLC_ML_SET_FOLDER_PUBLIC:
case VLC_ML_SET_FOLDER_PRIVATE:
case VLC_ML_RESUME_BACKGROUND:
case VLC_ML_NEW_EXTERNAL_MEDIA:
case VLC_ML_NEW_STREAM:
case VLC_ML_REMOVE_STREAM:
case VLC_ML_MEDIA_GENERATE_THUMBNAIL:
{
/* These operations require the media library to be started
* ie. that the background threads are started */
if ( !Init() )
return VLC_EGENERIC;
break;
}
default:
break;
}
switch ( query )
{
case VLC_ML_ADD_FOLDER:
case VLC_ML_REMOVE_FOLDER:
case VLC_ML_BAN_FOLDER:
case VLC_ML_UNBAN_FOLDER:
case VLC_ML_SET_FOLDER_PUBLIC:
case VLC_ML_SET_FOLDER_PRIVATE:
{
const char* mrl = va_arg( args, const char* );
switch( query )
{
case VLC_ML_ADD_FOLDER:
m_ml->discover( mrl );
break;
case VLC_ML_REMOVE_FOLDER:
m_ml->removeRoot( mrl );
break;
case VLC_ML_BAN_FOLDER:
m_ml->banFolder( mrl );
break;
case VLC_ML_UNBAN_FOLDER:
m_ml->unbanFolder( mrl );
break;
case VLC_ML_SET_FOLDER_PUBLIC:
case VLC_ML_SET_FOLDER_PRIVATE:
{
auto folder = m_ml->folder(mrl);
const bool is_public = query == VLC_ML_SET_FOLDER_PUBLIC;
if (folder)
folder->setPublic(is_public);
break;
}
}
break;
}
case VLC_ML_IS_INDEXED:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto mrl = va_arg( args, const char* );
auto res = va_arg( args, bool* );
*res = m_ml->isIndexed( mrl );
break;
}
case VLC_ML_RELOAD_FOLDER:
{
auto mrl = va_arg( args, const char* );
if ( mrl == nullptr )
m_ml->reload();
else
m_ml->reload( mrl );
break;
}
case VLC_ML_PAUSE_BACKGROUND:
m_ml->pauseBackgroundOperations();
break;
case VLC_ML_RESUME_BACKGROUND:
m_ml->resumeBackgroundOperations();
break;
case VLC_ML_CLEAR_HISTORY:
{
const auto type = static_cast<medialibrary::HistoryType>( va_arg(args, int) );
m_ml->clearHistory( type );
break;
}
case VLC_ML_NEW_EXTERNAL_MEDIA:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto mrl = va_arg( args, const char* );
auto media = m_ml->addExternalMedia( mrl, -1 );
if ( media == nullptr )
return VLC_EGENERIC;
*va_arg( args, vlc_ml_media_t**) = CreateAndConvert<vlc_ml_media_t>( media.get() );
return VLC_SUCCESS;
}
case VLC_ML_NEW_STREAM:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto mrl = va_arg( args, const char* );
auto media = m_ml->addStream( mrl );
if ( media == nullptr )
return VLC_EGENERIC;
*va_arg( args, vlc_ml_media_t**) = CreateAndConvert<vlc_ml_media_t>( media.get() );
return VLC_SUCCESS;
}
case VLC_ML_REMOVE_STREAM:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto id = va_arg( args, int64_t );
auto media = m_ml->media( id );
if ( media == nullptr )
return VLC_EGENERIC;
m_ml->removeExternalMedia( media );
return VLC_SUCCESS;
}
case VLC_ML_MEDIA_GENERATE_THUMBNAIL:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto mediaId = va_arg( args, int64_t );
auto sizeType = va_arg( args, int );
auto width = va_arg( args, uint32_t );
auto height = va_arg( args, uint32_t );
auto position = va_arg( args, double );
auto res = m_ml->requestThumbnail( mediaId,
static_cast<medialibrary::ThumbnailSizeType>( sizeType ),
width, height, position );
return res == true ? VLC_SUCCESS : VLC_EGENERIC;
}
case VLC_ML_MEDIA_UPDATE_PROGRESS:
case VLC_ML_MEDIA_GET_MEDIA_PLAYBACK_STATE:
case VLC_ML_MEDIA_SET_MEDIA_PLAYBACK_STATE:
case VLC_ML_MEDIA_GET_ALL_MEDIA_PLAYBACK_STATES:
case VLC_ML_MEDIA_SET_ALL_MEDIA_PLAYBACK_STATES:
case VLC_ML_MEDIA_SET_THUMBNAIL:
case VLC_ML_MEDIA_ADD_EXTERNAL_MRL:
case VLC_ML_MEDIA_SET_TYPE:
case VLC_ML_MEDIA_SET_PLAYED:
case VLC_ML_MEDIA_SET_FAVORITE:
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:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
return controlMedia( query, args );
}
case VLC_ML_MEDIA_SET_GENRE_THUMBNAIL:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto id = va_arg( args, int64_t );
auto mrl = va_arg( args, const char* );
auto sizeType = va_arg( args, int );
auto genre = m_ml->genre( id );
if ( !genre || !genre->setThumbnail( mrl, static_cast<medialibrary::ThumbnailSizeType>( sizeType ), true ) )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_CREATE:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto name = va_arg( args, const char * );
auto playlist = m_ml->createPlaylist( name );
if ( playlist == nullptr )
return VLC_EGENERIC;
auto result = va_arg( args, vlc_ml_playlist_t** );
*result = CreateAndConvert<vlc_ml_playlist_t>( playlist.get() );
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_DELETE:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
if ( m_ml->deletePlaylist( va_arg( args, int64_t ) ) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_APPEND:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto playlist = m_ml->playlist( va_arg( args, int64_t ) );
if ( playlist == nullptr )
return VLC_EGENERIC;
if ( playlist->append(va_arg( args, int64_t )) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_INSERT:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto playlist = m_ml->playlist( va_arg( args, int64_t ) );
if ( playlist == nullptr )
return VLC_EGENERIC;
int64_t mediaId = va_arg( args, int64_t );
uint32_t position = va_arg( args, uint32_t );
if ( playlist->add(mediaId, position) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_MOVE:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto playlist = m_ml->playlist( va_arg( args, int64_t ) );
if ( playlist == nullptr )
return VLC_EGENERIC;
uint32_t from = va_arg( args, uint32_t );
uint32_t to = va_arg( args, uint32_t );
if ( playlist->move(from, to) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_REMOVE:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto playlist = m_ml->playlist( va_arg( args, int64_t ) );
if ( playlist == nullptr )
return VLC_EGENERIC;
uint32_t position = va_arg( args, uint32_t );
if ( playlist->remove(position) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_PLAYLIST_RENAME:
{
auto priorityAccess = m_ml->acquirePriorityAccess();
auto playlist = m_ml->playlist( va_arg( args, int64_t ) );
if ( playlist == nullptr )
return VLC_EGENERIC;
const char * name = va_arg( args, const char * );
if ( playlist->setName(name) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
default:
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
int MediaLibrary::List( int listQuery, const vlc_ml_query_params_t* params, va_list args )
{
if ( Init() == false )
return VLC_EGENERIC;
auto priorityAccess = m_ml->acquirePriorityAccess();
medialibrary::QueryParameters p{};
medialibrary::QueryParameters* paramsPtr = nullptr;
uint32_t nbItems = 0;
uint32_t offset = 0;
const char* psz_pattern = nullptr;
if ( params )
{
p.desc = params->b_desc;
p.sort = sortingCriteria( params->i_sort );
p.favoriteOnly = params->b_favorite_only;
p.publicOnly = params->b_public_only;
nbItems = params->i_nbResults;
offset = params->i_offset;
psz_pattern = params->psz_pattern;
paramsPtr = &p;
}
medialibrary::IMedia::Type type = medialibrary::IMedia::Type::Unknown;
switch ( listQuery )
{
case VLC_ML_LIST_MEDIA_OF:
case VLC_ML_COUNT_MEDIA_OF:
// N/A default value
break;
case VLC_ML_LIST_VIDEO_OF:
case VLC_ML_COUNT_VIDEO_OF:
type = medialibrary::IMedia::Type::Video;
break;
case VLC_ML_LIST_AUDIO_OF:
case VLC_ML_COUNT_AUDIO_OF:
type = medialibrary::IMedia::Type::Audio;
break;
case VLC_ML_LIST_FOLDERS_BY_TYPE:
case VLC_ML_COUNT_FOLDERS_BY_TYPE:
type = static_cast<medialibrary::IMedia::Type>(va_arg(args, int));
break;
default:
break;
}
switch ( listQuery )
{
case VLC_ML_LIST_MEDIA_OF:
case VLC_ML_COUNT_MEDIA_OF:
case VLC_ML_LIST_VIDEO_OF:
case VLC_ML_COUNT_VIDEO_OF:
case VLC_ML_LIST_AUDIO_OF:
case VLC_ML_COUNT_AUDIO_OF:
case VLC_ML_LIST_ARTISTS_OF:
case VLC_ML_COUNT_ARTISTS_OF:
case VLC_ML_LIST_ALBUMS_OF:
case VLC_ML_COUNT_ALBUMS_OF:
{
auto parentType = va_arg( args, int );
listQuery = filterListChildrenQuery( listQuery, parentType );
}
default:
break;
}
switch( listQuery )
{
case VLC_ML_LIST_ALBUM_TRACKS:
case VLC_ML_COUNT_ALBUM_TRACKS:
case VLC_ML_LIST_ALBUM_ARTISTS:
case VLC_ML_COUNT_ALBUM_ARTISTS:
return listAlbums( listQuery, paramsPtr, psz_pattern, nbItems, offset, args );
case VLC_ML_LIST_ARTIST_ALBUMS:
case VLC_ML_COUNT_ARTIST_ALBUMS:
case VLC_ML_LIST_ARTIST_TRACKS:
case VLC_ML_COUNT_ARTIST_TRACKS:
return listArtists( listQuery, paramsPtr, psz_pattern, nbItems, offset, args );
case VLC_ML_LIST_VIDEOS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( psz_pattern != nullptr )
query = m_ml->searchVideo( psz_pattern, paramsPtr );
else
query = m_ml->videoFiles( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
auto res = ml_convert_list<vlc_ml_media_list_t, vlc_ml_media_t>(
query->items( nbItems, offset ) );
*va_arg( args, vlc_ml_media_list_t**) = res;
break;
}
case VLC_ML_COUNT_VIDEOS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( psz_pattern != nullptr )
query = m_ml->searchVideo( psz_pattern, paramsPtr );
else
query = m_ml->videoFiles( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, size_t* ) = query->count();
break;
}
case VLC_ML_LIST_AUDIOS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( psz_pattern != nullptr )
query = m_ml->searchAudio( psz_pattern, paramsPtr );
else
query = m_ml->audioFiles( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
auto res = ml_convert_list<vlc_ml_media_list_t, vlc_ml_media_t>(
query->items( nbItems, offset ) );
*va_arg( args, vlc_ml_media_list_t**) = res;
break;
}
case VLC_ML_COUNT_AUDIOS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( psz_pattern != nullptr )
query = m_ml->searchAudio( psz_pattern, paramsPtr );
else
query = m_ml->audioFiles( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, size_t* ) = query->count();
break;
}
case VLC_ML_LIST_ALBUMS:
{
medialibrary::Query<medialibrary::IAlbum> query;
if ( psz_pattern != nullptr )
query = m_ml->searchAlbums( psz_pattern, paramsPtr );
else
query = m_ml->albums( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
auto res = ml_convert_list<vlc_ml_album_list_t, vlc_ml_album_t>(
query->items( nbItems, offset ) );
*va_arg( args, vlc_ml_album_list_t**) = res;
break;
}
case VLC_ML_COUNT_ALBUMS:
{
medialibrary::Query<medialibrary::IAlbum> query;
if ( psz_pattern != nullptr )
query = m_ml->searchAlbums( psz_pattern, paramsPtr );
else
query = m_ml->albums( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, size_t* ) = query->count();
break;
}
case VLC_ML_LIST_GENRES:
{
medialibrary::Query<medialibrary::IGenre> query;
if ( psz_pattern != nullptr )
query = m_ml->searchGenre( psz_pattern, paramsPtr );
else
query = m_ml->genres( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
auto res = ml_convert_list<vlc_ml_genre_list_t,vlc_ml_genre_t>(
query->items( nbItems, offset ) );
*va_arg( args, vlc_ml_genre_list_t**) = res;
break;
}
case VLC_ML_COUNT_GENRES:
{
medialibrary::Query<medialibrary::IGenre> query;
if ( psz_pattern != nullptr )
query = m_ml->searchGenre( psz_pattern, paramsPtr );
else
query = m_ml->genres( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, size_t* ) = query->count();
break;
}
case VLC_ML_LIST_ARTISTS:
{
medialibrary::Query<medialibrary::IArtist> query;
bool includeAll = va_arg( args, int ) != 0;
auto artistsIncluded = includeAll ? medialibrary::ArtistIncluded::All :
medialibrary::ArtistIncluded::AlbumArtistOnly;
if ( psz_pattern != nullptr )
query = m_ml->searchArtists( psz_pattern, artistsIncluded, paramsPtr );
else
query = m_ml->artists( artistsIncluded, paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
auto res = ml_convert_list<vlc_ml_artist_list_t, vlc_ml_artist_t>(
query->items( nbItems, offset ) );
*va_arg( args, vlc_ml_artist_list_t**) = res;
break;
}
case VLC_ML_COUNT_ARTISTS:
{
medialibrary::Query<medialibrary::IArtist> query;
bool includeAll = va_arg( args, int ) != 0;
auto artistsIncluded = includeAll ? medialibrary::ArtistIncluded::All :
medialibrary::ArtistIncluded::AlbumArtistOnly;
if ( psz_pattern != nullptr )
query = m_ml->searchArtists( psz_pattern, artistsIncluded, paramsPtr );
else
query = m_ml->artists( artistsIncluded, paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, size_t* ) = query->count();
break;
}
case VLC_ML_LIST_GENRE_ARTISTS:
case VLC_ML_COUNT_GENRE_ARTISTS:
case VLC_ML_LIST_GENRE_TRACKS:
case VLC_ML_COUNT_GENRE_TRACKS:
case VLC_ML_LIST_GENRE_ALBUMS:
case VLC_ML_COUNT_GENRE_ALBUMS:
return listGenre( listQuery, paramsPtr, psz_pattern, nbItems, offset, args );
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:
{
medialibrary::Query<medialibrary::IShow> query;
if ( psz_pattern != nullptr )
query = m_ml->searchShows( psz_pattern, paramsPtr );
else
query = m_ml->shows( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, vlc_ml_show_list_t** ) =
ml_convert_list<vlc_ml_show_list_t, vlc_ml_show_t>(
query->items( nbItems, offset ) );
return VLC_SUCCESS;
}
case VLC_ML_COUNT_SHOWS:
{
auto query = m_ml->shows( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
*va_arg( args, int64_t* ) = query->count();
return VLC_SUCCESS;
}
case VLC_ML_LIST_SHOW_EPISODES:
case VLC_ML_COUNT_SHOW_EPISODES:
{
auto show = m_ml->show( va_arg( args, int64_t ) );
if ( show == nullptr )
return VLC_EGENERIC;
medialibrary::Query<medialibrary::IMedia> query;
if ( psz_pattern != nullptr )
query = show->searchEpisodes( psz_pattern, paramsPtr );
else
query = show->episodes( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_SHOW_EPISODES:
*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_SHOW_EPISODES:
*va_arg( args, int64_t* ) = query->count();
return VLC_SUCCESS;
default:
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, type, psz_pattern, nbItems, offset, args );
case VLC_ML_LIST_FOLDERS:
case VLC_ML_COUNT_FOLDERS:
case VLC_ML_LIST_FOLDERS_BY_TYPE:
case VLC_ML_COUNT_FOLDERS_BY_TYPE:
case VLC_ML_LIST_FOLDER_MEDIA:
case VLC_ML_COUNT_FOLDER_MEDIA:
return listFolder( listQuery, paramsPtr, type, psz_pattern, nbItems, offset, args );
case VLC_ML_LIST_PLAYLIST_MEDIA:
case VLC_ML_COUNT_PLAYLIST_MEDIA:
case VLC_ML_LIST_PLAYLISTS:
case VLC_ML_COUNT_PLAYLISTS:
return listPlaylist( listQuery, paramsPtr, psz_pattern, nbItems, offset, args );
case VLC_ML_COUNT_HISTORY:
case VLC_ML_LIST_HISTORY:
case VLC_ML_COUNT_VIDEO_HISTORY:
case VLC_ML_LIST_VIDEO_HISTORY:
case VLC_ML_COUNT_AUDIO_HISTORY:
case VLC_ML_LIST_AUDIO_HISTORY:
{
medialibrary::Query<medialibrary::IMedia> query;
switch ( listQuery )
{
case VLC_ML_COUNT_HISTORY:
case VLC_ML_LIST_HISTORY:
{
const auto type = static_cast<medialibrary::HistoryType>( va_arg(args, int) );
query = m_ml->history( type, paramsPtr );
break;
}
case VLC_ML_COUNT_VIDEO_HISTORY:
case VLC_ML_LIST_VIDEO_HISTORY:
query = m_ml->videoHistory( paramsPtr );
break;
case VLC_ML_COUNT_AUDIO_HISTORY:
case VLC_ML_LIST_AUDIO_HISTORY:
query = m_ml->audioHistory( paramsPtr );
break;
default:
vlc_assert_unreachable();
}
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_HISTORY:
case VLC_ML_LIST_VIDEO_HISTORY:
case VLC_ML_LIST_AUDIO_HISTORY:
*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_HISTORY:
case VLC_ML_COUNT_VIDEO_HISTORY:
case VLC_ML_COUNT_AUDIO_HISTORY:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_ENTRY_POINTS:
{
const bool banned = va_arg( args, int ) != 0;
const auto query = banned ? m_ml->bannedRoots() : m_ml->roots( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
auto* res =
ml_convert_list<vlc_ml_folder_list_t, vlc_ml_folder_t>( query->all() );
*( va_arg( args, vlc_ml_folder_list_t** ) ) = res;
break;
}
case VLC_ML_COUNT_ENTRY_POINTS:
{
const bool banned = va_arg( args, int ) != 0;
const auto query = banned ? m_ml->bannedRoots() : m_ml->roots( paramsPtr );
*( va_arg( args, size_t* ) ) = query ? query->count() : 0;
break;
}
case VLC_ML_LIST_SUBFOLDERS:
{
const auto parent = m_ml->folder( va_arg( args, int64_t ) );
if ( parent == nullptr )
return VLC_EGENERIC;
const auto query = parent->subfolders();
if ( query == nullptr )
return VLC_EGENERIC;
auto* res = ml_convert_list<vlc_ml_folder_list_t, vlc_ml_folder_t>( query->all() );
*( va_arg( args, vlc_ml_folder_list_t** ) ) = res;
break;
}
case VLC_ML_COUNT_SUBFOLDERS:
{
const auto parent = m_ml->folder( va_arg( args, int64_t ) );
if ( parent == nullptr )
return VLC_EGENERIC;
const auto query = parent->subfolders();
*( va_arg( args, size_t* ) ) = query == nullptr ? 0 : query->count();
break;
}
}
return VLC_SUCCESS;
}
void* MediaLibrary::Get( int query, va_list args )
{
if ( Init() == false )
return nullptr;
auto priorityAccess = m_ml->acquirePriorityAccess();
switch ( query )
{
case VLC_ML_GET_MEDIA:
{
auto id = va_arg( args, int64_t );
auto media = m_ml->media( id );
return CreateAndConvert<vlc_ml_media_t>( media.get() );
}
case VLC_ML_GET_INPUT_ITEM:
{
auto id = va_arg( args, int64_t );
auto media = m_ml->media( id );
return MediaToInputItem( media.get() );
}
case VLC_ML_GET_ALBUM:
{
auto id = va_arg( args, int64_t );
auto album = m_ml->album( id );
return CreateAndConvert<vlc_ml_album_t>( album.get() );
}
case VLC_ML_GET_ARTIST:
{
auto id = va_arg( args, int64_t );
auto artist = m_ml->artist( id );
return CreateAndConvert<vlc_ml_artist_t>( artist.get() );
}
case VLC_ML_GET_GENRE:
{
auto id = va_arg( args, int64_t );
auto genre = m_ml->genre( id );
return CreateAndConvert<vlc_ml_genre_t>( genre.get() );
}
case VLC_ML_GET_SHOW:
{
auto id = va_arg( args, int64_t );
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 );
auto playlist = m_ml->playlist( id );
return CreateAndConvert<vlc_ml_playlist_t>( playlist.get() );
}
case VLC_ML_GET_FOLDER:
{
auto id = va_arg( args, int64_t );
auto folder = m_ml->folder( id );
return CreateAndConvert<vlc_ml_folder_t>( folder.get() );
}
case VLC_ML_GET_MEDIA_BY_MRL:
{
auto mrl = va_arg( args, const char* );
auto media = m_ml->media( mrl );
return CreateAndConvert<vlc_ml_media_t>( media.get() );
}
case VLC_ML_GET_INPUT_ITEM_BY_MRL:
{
auto mrl = va_arg( args, const char* );
auto media = m_ml->media( mrl );
if ( media == nullptr )
return nullptr;
return MediaToInputItem( media.get() );
}
default:
vlc_assert_unreachable();
}
return nullptr;
}
medialibrary::IMedia::MetadataType MediaLibrary::metadataType( int meta )
{
switch ( meta )
{
case VLC_ML_PLAYBACK_STATE_RATING:
return medialibrary::IMedia::MetadataType::Rating;
case VLC_ML_PLAYBACK_STATE_SPEED:
return medialibrary::IMedia::MetadataType::Speed;
case VLC_ML_PLAYBACK_STATE_TITLE:
return medialibrary::IMedia::MetadataType::Title;
case VLC_ML_PLAYBACK_STATE_CHAPTER:
return medialibrary::IMedia::MetadataType::Chapter;
case VLC_ML_PLAYBACK_STATE_PROGRAM:
return medialibrary::IMedia::MetadataType::Program;
case VLC_ML_PLAYBACK_STATE_VIDEO_TRACK:
return medialibrary::IMedia::MetadataType::VideoTrack;
case VLC_ML_PLAYBACK_STATE_ASPECT_RATIO:
return medialibrary::IMedia::MetadataType::AspectRatio;
case VLC_ML_PLAYBACK_STATE_ZOOM:
return medialibrary::IMedia::MetadataType::Zoom;
case VLC_ML_PLAYBACK_STATE_CROP:
return medialibrary::IMedia::MetadataType::Crop;
case VLC_ML_PLAYBACK_STATE_DEINTERLACE:
return medialibrary::IMedia::MetadataType::Deinterlace;
case VLC_ML_PLAYBACK_STATE_VIDEO_FILTER:
return medialibrary::IMedia::MetadataType::VideoFilter;
case VLC_ML_PLAYBACK_STATE_AUDIO_TRACK:
return medialibrary::IMedia::MetadataType::AudioTrack;
case VLC_ML_PLAYBACK_STATE_GAIN:
return medialibrary::IMedia::MetadataType::Gain;
case VLC_ML_PLAYBACK_STATE_AUDIO_DELAY:
return medialibrary::IMedia::MetadataType::AudioDelay;
case VLC_ML_PLAYBACK_STATE_SUBTITLE_TRACK:
return medialibrary::IMedia::MetadataType::SubtitleTrack;
case VLC_ML_PLAYBACK_STATE_SUBTITLE_DELAY:
return medialibrary::IMedia::MetadataType::SubtitleDelay;
case VLC_ML_PLAYBACK_STATE_APP_SPECIFIC:
return medialibrary::IMedia::MetadataType::ApplicationSpecific;
default:
vlc_assert_unreachable();
}
}
medialibrary::SortingCriteria MediaLibrary::sortingCriteria(int sort)
{
switch ( sort )
{
case VLC_ML_SORTING_DEFAULT:
return medialibrary::SortingCriteria::Default;
case VLC_ML_SORTING_ALPHA:
return medialibrary::SortingCriteria::Alpha;
case VLC_ML_SORTING_DURATION:
return medialibrary::SortingCriteria::Duration;
case VLC_ML_SORTING_INSERTIONDATE:
return medialibrary::SortingCriteria::InsertionDate;
case VLC_ML_SORTING_LASTMODIFICATIONDATE:
return medialibrary::SortingCriteria::LastModificationDate;
case VLC_ML_SORTING_RELEASEDATE:
return medialibrary::SortingCriteria::ReleaseDate;
case VLC_ML_SORTING_FILESIZE:
return medialibrary::SortingCriteria::FileSize;
case VLC_ML_SORTING_ARTIST:
return medialibrary::SortingCriteria::Artist;
case VLC_ML_SORTING_PLAYCOUNT:
return medialibrary::SortingCriteria::PlayCount;
case VLC_ML_SORTING_ALBUM:
return medialibrary::SortingCriteria::Album;
case VLC_ML_SORTING_FILENAME:
return medialibrary::SortingCriteria::Filename;
case VLC_ML_SORTING_TRACKNUMBER:
return medialibrary::SortingCriteria::TrackNumber;
default:
vlc_assert_unreachable();
}
}
int MediaLibrary::getMeta( const medialibrary::IMedia& media, int meta, char** result )
{
auto& md = media.metadata( metadataType( meta ) );
if ( md.isSet() == false )
{
*result = nullptr;
return VLC_SUCCESS;
}
*result = strdup( md.asStr().c_str() );
if ( *result == nullptr )
return VLC_ENOMEM;
return VLC_SUCCESS;
}
int MediaLibrary::getMeta( const medialibrary::IMedia& media,
vlc_ml_playback_states_all* res )
{
auto metas = media.metadata();
res->rate = .0f;
res->zoom = -1.f;
res->current_title = -1;
// For tracks, -1 means disabled, so we can't use it for "unset"
res->current_video_track = res->current_audio_track =
res->current_subtitle_track = nullptr;
res->aspect_ratio = res->crop = res->deinterlace =
res->video_filter = nullptr;
for ( const auto& meta : metas )
{
#define COPY_META( field ) res->field = strdup( meta.second.c_str() ); \
if ( res->field == nullptr ) return VLC_ENOMEM;
switch ( meta.first )
{
case medialibrary::IMedia::MetadataType::Speed:
res->rate = atof( meta.second.c_str() );
break;
case medialibrary::IMedia::MetadataType::Title:
res->current_title = atoi( meta.second.c_str() );
break;
case medialibrary::IMedia::MetadataType::VideoTrack:
COPY_META( current_video_track );
break;
case medialibrary::IMedia::MetadataType::AspectRatio:
COPY_META( aspect_ratio );
break;
case medialibrary::IMedia::MetadataType::Zoom:
res->zoom = atof( meta.second.c_str() );
break;
case medialibrary::IMedia::MetadataType::Crop:
COPY_META( crop );
break;
case medialibrary::IMedia::MetadataType::Deinterlace:
COPY_META( deinterlace );
break;
case medialibrary::IMedia::MetadataType::VideoFilter:
COPY_META( video_filter );
break;
case medialibrary::IMedia::MetadataType::AudioTrack:
COPY_META( current_audio_track );
break;
case medialibrary::IMedia::MetadataType::SubtitleTrack:
COPY_META( current_subtitle_track );
break;
default:
break;
}
#undef COPY_META
}
return VLC_SUCCESS;
}
int MediaLibrary::setMeta( medialibrary::IMedia& media, int meta, const char* value )
{
bool res;
if ( value == nullptr )
res = media.unsetMetadata( metadataType( meta ) );
else
res = media.setMetadata( metadataType( meta ), value );
if ( res == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
int MediaLibrary::setMeta( medialibrary::IMedia& media,
const vlc_ml_playback_states_all* values )
{
using MT = medialibrary::IMedia::MetadataType;
std::unordered_map<MT, std::string> metas;
if ( values->rate != .0f )
metas[MT::Speed] = std::to_string( values->rate );
if ( values->zoom != .0f )
metas[MT::Zoom] = std::to_string( values->zoom );
if ( values->current_title >= 0 )
metas[MT::Title] = std::to_string( values->current_title );
if ( values->aspect_ratio != nullptr )
metas[MT::AspectRatio] = values->aspect_ratio;
if ( values->crop != nullptr )
metas[MT::Crop] = values->crop;
if ( values->deinterlace != nullptr )
metas[MT::Deinterlace] = values->deinterlace;
if ( values->video_filter != nullptr )
metas[MT::VideoFilter] = values->video_filter;
if ( values->current_video_track != nullptr )
metas[MT::VideoTrack] = values->current_video_track;
if ( values->current_audio_track != nullptr )
metas[MT::AudioTrack] = values->current_audio_track;
if ( values->current_subtitle_track != nullptr )
metas[MT::SubtitleTrack] = values->current_subtitle_track;
if ( media.setMetadata( std::move( metas ) ) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
int MediaLibrary::controlMedia( int query, va_list args )
{
auto mediaId = va_arg( args, int64_t );
auto m = m_ml->media( mediaId );
if ( m == nullptr )
return VLC_EGENERIC;
switch( query )
{
case VLC_ML_MEDIA_UPDATE_PROGRESS:
if ( m->setLastPosition( va_arg( args, double ) ) ==
medialibrary::IMedia::ProgressResult::Error )
return VLC_EGENERIC;
return VLC_SUCCESS;
case VLC_ML_MEDIA_GET_MEDIA_PLAYBACK_STATE:
{
auto meta = va_arg( args, int );
auto res = va_arg( args, char** );
return getMeta( *m, meta, res );
}
case VLC_ML_MEDIA_SET_MEDIA_PLAYBACK_STATE:
{
auto meta = va_arg( args, int );
auto value = va_arg( args, const char* );
return setMeta( *m, meta, value );
}
case VLC_ML_MEDIA_GET_ALL_MEDIA_PLAYBACK_STATES:
{
auto res = va_arg( args, vlc_ml_playback_states_all* );
return getMeta( *m, res );
}
case VLC_ML_MEDIA_SET_ALL_MEDIA_PLAYBACK_STATES:
{
auto res = va_arg( args, const vlc_ml_playback_states_all* );
return setMeta( *m, res );
}
case VLC_ML_MEDIA_SET_THUMBNAIL:
{
auto mrl = va_arg( args, const char* );
auto sizeType = va_arg( args, int );
m->setThumbnail( mrl, static_cast<medialibrary::ThumbnailSizeType>( sizeType ) );
return VLC_SUCCESS;
}
case VLC_ML_MEDIA_ADD_EXTERNAL_MRL:
{
auto mrl = va_arg( args, const char* );
auto type = va_arg( args, int );
medialibrary::IFile::Type mlType;
switch ( type )
{
case VLC_ML_FILE_TYPE_UNKNOWN:
// The type can't be main since this is added to an existing media
// which must already have a file
case VLC_ML_FILE_TYPE_MAIN:
case VLC_ML_FILE_TYPE_PLAYLIST:
return VLC_EGENERIC;
case VLC_ML_FILE_TYPE_PART:
mlType = medialibrary::IFile::Type::Part;
break;
case VLC_ML_FILE_TYPE_SOUNDTRACK:
mlType = medialibrary::IFile::Type::Soundtrack;
break;
case VLC_ML_FILE_TYPE_SUBTITLE:
mlType = medialibrary::IFile::Type::Subtitles;
break;
default:
vlc_assert_unreachable();
}
if ( m->addExternalMrl( mrl, mlType ) == nullptr )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_MEDIA_SET_TYPE:
{
auto type = va_arg( args, int );
if ( m->setType( static_cast<medialibrary::IMedia::Type>( type ) ) == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_MEDIA_SET_PLAYED:
{
if ( va_arg( args, int ) )
{
if ( m->markAsPlayed() == false )
return VLC_EGENERIC;
}
else if ( m->removeFromHistory() == false )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
case VLC_ML_MEDIA_SET_FAVORITE:
{
bool favorite = va_arg( args, int );
if ( m->setFavorite( favorite ) == false )
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();
}
}
int MediaLibrary::filterListChildrenQuery( int query, int parentType )
{
switch( query )
{
case VLC_ML_LIST_MEDIA_OF:
case VLC_ML_LIST_VIDEO_OF:
case VLC_ML_LIST_AUDIO_OF:
switch ( parentType )
{
case VLC_ML_PARENT_ALBUM:
return VLC_ML_LIST_ALBUM_TRACKS;
case VLC_ML_PARENT_ARTIST:
return VLC_ML_LIST_ARTIST_TRACKS;
case VLC_ML_PARENT_SHOW:
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_FOLDER:
return VLC_ML_LIST_FOLDER_MEDIA;
case VLC_ML_PARENT_PLAYLIST:
return VLC_ML_LIST_PLAYLIST_MEDIA;
default:
vlc_assert_unreachable();
}
case VLC_ML_COUNT_MEDIA_OF:
case VLC_ML_COUNT_VIDEO_OF:
case VLC_ML_COUNT_AUDIO_OF:
switch ( parentType )
{
case VLC_ML_PARENT_ALBUM:
return VLC_ML_COUNT_ALBUM_TRACKS;
case VLC_ML_PARENT_ARTIST:
return VLC_ML_COUNT_ARTIST_TRACKS;
case VLC_ML_PARENT_SHOW:
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_FOLDER:
return VLC_ML_COUNT_FOLDER_MEDIA;
case VLC_ML_PARENT_PLAYLIST:
return VLC_ML_COUNT_PLAYLIST_MEDIA;
default:
vlc_assert_unreachable();
}
case VLC_ML_LIST_ALBUMS_OF:
switch ( parentType )
{
case VLC_ML_PARENT_ARTIST:
return VLC_ML_LIST_ARTIST_ALBUMS;
case VLC_ML_PARENT_GENRE:
return VLC_ML_LIST_GENRE_ALBUMS;
default:
vlc_assert_unreachable();
}
case VLC_ML_COUNT_ALBUMS_OF:
switch ( parentType )
{
case VLC_ML_PARENT_ARTIST:
return VLC_ML_COUNT_ARTIST_ALBUMS;
case VLC_ML_PARENT_GENRE:
return VLC_ML_COUNT_GENRE_ALBUMS;
default:
vlc_assert_unreachable();
}
case VLC_ML_LIST_ARTISTS_OF:
switch ( parentType )
{
case VLC_ML_PARENT_ALBUM:
return VLC_ML_LIST_ALBUM_ARTISTS;
case VLC_ML_PARENT_GENRE:
return VLC_ML_LIST_GENRE_ARTISTS;
default:
vlc_assert_unreachable();
}
case VLC_ML_COUNT_ARTISTS_OF:
switch ( parentType )
{
case VLC_ML_PARENT_ALBUM:
return VLC_ML_COUNT_ALBUM_ARTISTS;
case VLC_ML_PARENT_GENRE:
return VLC_ML_COUNT_GENRE_ARTISTS;
default:
vlc_assert_unreachable();
}
default:
vlc_assert_unreachable();
}
}
int MediaLibrary::listAlbums( int listQuery, const medialibrary::QueryParameters* paramsPtr,
const char* pattern, uint32_t nbItems, uint32_t offset, va_list args )
{
auto album = m_ml->album( va_arg( args, int64_t ) );
if ( album == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_ALBUM_TRACKS:
case VLC_ML_COUNT_ALBUM_TRACKS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( pattern != nullptr )
query = album->searchTracks( pattern, paramsPtr );
else
query = album->tracks( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_ALBUM_TRACKS:
*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_ALBUM_TRACKS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_ALBUM_ARTISTS:
case VLC_ML_COUNT_ALBUM_ARTISTS:
{
auto query = album->artists( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_ALBUM_ARTISTS:
*va_arg( args, vlc_ml_artist_list_t**) =
ml_convert_list<vlc_ml_artist_list_t, vlc_ml_artist_t>(
query->items( nbItems, offset ) );
return VLC_SUCCESS;
case VLC_ML_COUNT_ALBUM_ARTISTS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
default:
vlc_assert_unreachable();
}
}
int MediaLibrary::listArtists( int listQuery, const medialibrary::QueryParameters* paramsPtr,
const char* pattern, uint32_t nbItems, uint32_t offset,
va_list args )
{
auto artist = m_ml->artist( va_arg( args, int64_t ) );
if ( artist == nullptr )
return VLC_EGENERIC;
switch( listQuery )
{
case VLC_ML_LIST_ARTIST_ALBUMS:
case VLC_ML_COUNT_ARTIST_ALBUMS:
{
medialibrary::Query<medialibrary::IAlbum> query;
if ( pattern != nullptr )
query = artist->searchAlbums( pattern, paramsPtr );
else
query = artist->albums( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_ARTIST_ALBUMS:
*va_arg( args, vlc_ml_album_list_t**) =
ml_convert_list<vlc_ml_album_list_t, vlc_ml_album_t>(
query->items( nbItems, offset ) );
return VLC_SUCCESS;
case VLC_ML_COUNT_ARTIST_ALBUMS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_ARTIST_TRACKS:
case VLC_ML_COUNT_ARTIST_TRACKS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( pattern != nullptr )
query = artist->searchTracks( pattern, paramsPtr );
else
query = artist->tracks( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_ARTIST_TRACKS:
*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_ARTIST_TRACKS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
default:
vlc_assert_unreachable();
}
}
int MediaLibrary::listGenre( int listQuery, const medialibrary::QueryParameters* paramsPtr,
const char* pattern, uint32_t nbItems, uint32_t offset, va_list args )
{
auto genre = m_ml->genre( va_arg( args, int64_t ) );
if ( genre == nullptr )
return VLC_EGENERIC;
switch( listQuery )
{
case VLC_ML_LIST_GENRE_ARTISTS:
case VLC_ML_COUNT_GENRE_ARTISTS:
{
medialibrary::Query<medialibrary::IArtist> query;
if ( pattern != nullptr )
query = genre->searchArtists( pattern, paramsPtr );
else
query = genre->artists( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_GENRE_ARTISTS:
*va_arg( args, vlc_ml_artist_list_t**) =
ml_convert_list<vlc_ml_artist_list_t, vlc_ml_artist_t>(
query->items( nbItems, offset ) );
return VLC_SUCCESS;
case VLC_ML_COUNT_GENRE_ARTISTS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_GENRE_TRACKS:
case VLC_ML_COUNT_GENRE_TRACKS:
{
medialibrary::Query<medialibrary::IMedia> query;
if ( pattern != nullptr )
query = genre->searchTracks( pattern, paramsPtr );
else
query = genre->tracks( medialibrary::IGenre::TracksIncluded::All,
paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_GENRE_TRACKS:
*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_GENRE_TRACKS:
*va_arg( args, size_t*) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_GENRE_ALBUMS:
case VLC_ML_COUNT_GENRE_ALBUMS:
{
medialibrary::Query<medialibrary::IAlbum> query;
if ( pattern != nullptr )
query = genre->searchAlbums( pattern, paramsPtr );
else
query = genre->albums( paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_GENRE_ALBUMS:
*va_arg( args, vlc_ml_album_list_t**) =
ml_convert_list<vlc_ml_album_list_t, vlc_ml_album_t>(
query->items( nbItems, offset ) );
return VLC_SUCCESS;
case VLC_ML_COUNT_GENRE_ALBUMS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
default:
vlc_assert_unreachable();
}
}
int MediaLibrary::listGroup( int listQuery, const medialibrary::QueryParameters* paramsPtr,
medialibrary::IMedia::Type type, 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( type, 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, type, paramsPtr );
else
query = group->media( type, 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::listFolder(int listQuery, const medialibrary::QueryParameters * paramsPtr,
medialibrary::IMedia::Type type, const char * pattern,
uint32_t nbItems, uint32_t offset, va_list args)
{
switch (listQuery)
{
case VLC_ML_LIST_FOLDERS:
case VLC_ML_COUNT_FOLDERS:
case VLC_ML_LIST_FOLDERS_BY_TYPE:
case VLC_ML_COUNT_FOLDERS_BY_TYPE:
{
medialibrary::Query<medialibrary::IFolder> query;
if (pattern)
query = m_ml->searchFolders(pattern, type, paramsPtr);
else
query = m_ml->folders(type, paramsPtr);
if (query == nullptr)
return VLC_EGENERIC;
switch (listQuery)
{
case VLC_ML_LIST_FOLDERS:
case VLC_ML_LIST_FOLDERS_BY_TYPE:
*va_arg(args, vlc_ml_folder_list_t **) =
ml_convert_list<vlc_ml_folder_list_t, vlc_ml_folder_t>
(query->items(nbItems, offset));
return VLC_SUCCESS;
case VLC_ML_COUNT_FOLDERS:
case VLC_ML_COUNT_FOLDERS_BY_TYPE:
*va_arg(args, size_t *) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_FOLDER_MEDIA:
case VLC_ML_COUNT_FOLDER_MEDIA:
{
medialibrary::FolderPtr folder = m_ml->folder(va_arg(args, int64_t));
if (folder == nullptr)
return VLC_EGENERIC;
medialibrary::Query<medialibrary::IMedia> query;
if (pattern)
query = folder->searchMedia(pattern, type, paramsPtr);
else
query = folder->media(type, paramsPtr);
if (query == nullptr)
return VLC_EGENERIC;
switch (listQuery)
{
case VLC_ML_LIST_FOLDER_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_FOLDER_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 )
{
switch( listQuery )
{
case VLC_ML_LIST_PLAYLISTS:
case VLC_ML_COUNT_PLAYLISTS:
{
auto vlcPlaylistType = static_cast<vlc_ml_playlist_type_t>(va_arg( args, int ));
medialibrary::PlaylistType mlPlaylistType;
switch (vlcPlaylistType)
{
case VLC_ML_PLAYLIST_TYPE_ALL:
mlPlaylistType = medialibrary::PlaylistType::All;
break;
case VLC_ML_PLAYLIST_TYPE_VIDEO:
mlPlaylistType = medialibrary::PlaylistType::Video;
break;
case VLC_ML_PLAYLIST_TYPE_AUDIO:
mlPlaylistType = medialibrary::PlaylistType::Audio;
break;
case VLC_ML_PLAYLIST_TYPE_VIDEO_ONLY:
mlPlaylistType = medialibrary::PlaylistType::VideoOnly;
break;
case VLC_ML_PLAYLIST_TYPE_AUDIO_ONLY:
mlPlaylistType = medialibrary::PlaylistType::AudioOnly;
break;
default:
vlc_assert_unreachable();
}
medialibrary::Query<medialibrary::IPlaylist> query;
if ( pattern != nullptr )
query = m_ml->searchPlaylists( pattern, mlPlaylistType, paramsPtr );
else
query = m_ml->playlists( mlPlaylistType, paramsPtr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_PLAYLISTS:
*va_arg( args, vlc_ml_playlist_list_t** ) =
ml_convert_list<vlc_ml_playlist_list_t, vlc_ml_playlist_t>(
query->items( nbItems, offset ) );
return VLC_SUCCESS;
case VLC_ML_COUNT_PLAYLISTS:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
case VLC_ML_LIST_PLAYLIST_MEDIA:
case VLC_ML_COUNT_PLAYLIST_MEDIA:
{
auto playlist = m_ml->playlist( va_arg( args, int64_t ) );
if ( playlist == nullptr )
return VLC_EGENERIC;
medialibrary::Query<medialibrary::IMedia> query;
if ( pattern != nullptr )
query = playlist->searchMedia( pattern, paramsPtr );
else
query = playlist->media( nullptr );
if ( query == nullptr )
return VLC_EGENERIC;
switch ( listQuery )
{
case VLC_ML_LIST_PLAYLIST_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_PLAYLIST_MEDIA:
*va_arg( args, size_t* ) = query->count();
return VLC_SUCCESS;
default:
vlc_assert_unreachable();
}
}
default:
vlc_assert_unreachable();
}
}
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;
switch ( listQuery )
{
case VLC_ML_LIST_MEDIA_LABELS:
case VLC_ML_COUNT_MEDIA_LABELS:
{
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<vlc_ml_label_list_t, vlc_ml_label_t>(
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<vlc_ml_bookmark_list_t, vlc_ml_bookmark_t>(
media->bookmarks( params )->all() );
return VLC_SUCCESS;
}
default:
vlc_assert_unreachable();
}
}
medialibrary::PriorityAccess MediaLibrary::acquirePriorityAccess()
{
return m_ml->acquirePriorityAccess();
}
static void* Get( vlc_medialibrary_module_t* module, int query, va_list args )
{
auto ml = static_cast<MediaLibrary*>( module->p_sys );
return ml->Get( query, args );
}
static int List( vlc_medialibrary_module_t* module, int query,
const vlc_ml_query_params_t* params, va_list args )
{
auto ml = static_cast<MediaLibrary*>( module->p_sys );
return ml->List( query, params, args );
}
static int Control( vlc_medialibrary_module_t* module, int query, va_list args )
{
auto ml = static_cast<MediaLibrary*>( module->p_sys );
return ml->Control( query, args );
}
static int Open( vlc_object_t* obj )
{
auto* p_ml = reinterpret_cast<vlc_medialibrary_module_t*>( obj );
try
{
p_ml->p_sys = MediaLibrary::create( p_ml );
if ( !p_ml->p_sys)
return VLC_EGENERIC;
}
catch ( const std::exception& ex )
{
msg_Err( obj, "Failed to instantiate/initialize medialibrary: %s", ex.what() );
return VLC_EGENERIC;
}
p_ml->pf_control = Control;
p_ml->pf_get = Get;
p_ml->pf_list = List;
return VLC_SUCCESS;
}
static void Close( vlc_object_t* obj )
{
vlc_medialibrary_module_t *module = reinterpret_cast<vlc_medialibrary_module_t*>( obj );
MediaLibrary* p_ml = static_cast<MediaLibrary*>( module->p_sys );
delete p_ml;
}
#define ML_FOLDER_TEXT N_( "Folders discovered by the media library" )
#define ML_FOLDER_LONGTEXT N_( "Semicolon separated list of folders to discover " \
"media from" )
#define ML_VERBOSE _( "Extra verbose media library logs" )
vlc_module_begin()
set_shortname(N_("media library"))
set_description(N_( "Organize your media" ))
set_subcategory(SUBCAT_ADVANCED_MISC)
set_capability("medialibrary", 100)
set_callbacks(Open, Close)
add_bool( "ml-verbose", false, ML_VERBOSE, nullptr )
vlc_module_end()