media_library.cpp 11.2 KB
Newer Older
1
/*****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
2
 * Copyright © 2015-2016 VideoLAN, VideoLabs SAS
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *****************************************************************************
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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.
 *****************************************************************************/
/*
 * By committing to this project, you allow VideoLAN and VideoLabs to relicense
 * the code to a different OSI approved license, in case it is required for
 * compatibility with the Store
 *****************************************************************************/

27
#include "common.h"
28 29 30

#include <Ecore.h>

31
#include "IMediaLibrary.h"
32
#include "IVideoTrack.h"
33
#include "IArtist.h"
34
#include "IAlbum.h"
35
#include "media_library_private.hpp"
36
#include "system_storage.h"
37

38

39
media_library::media_library()
40
    : ml( NewMediaLibrary() )
41 42 43
    , m_progressCb( nullptr )
    , m_progressData( nullptr )

44
{
45 46
    if ( ml == nullptr )
        throw std::runtime_error( "Failed to initialize MediaLibrary" );
47 48
}

49
void
50
media_library::onMediaAdded( MediaPtr file )
51
{
52
    sendFileUpdate( file, true );
53 54
}

55
void
56
media_library::onFileUpdated( MediaPtr file )
57 58 59 60 61
{
    sendFileUpdate( file, false );
}

void
62
media_library::sendFileUpdate( MediaPtr file, bool added )
63
{
64
    auto item = fileToMediaItem( file );
65 66
    auto ctx = new FileUpdateCallbackCtx{this, item, added};
    ecore_main_loop_thread_safe_call_async([](void* data) {
67
        std::unique_ptr<FileUpdateCallbackCtx> ctx( reinterpret_cast<FileUpdateCallbackCtx*>(data) );
68 69 70
        auto ml = ctx->wml.lock();
        if ( ml == nullptr )
            return;
71 72
        for ( auto& p : ctx->ml->m_onItemUpdatedCb )
        {
73
            if ( p.first( p.second, reinterpret_cast<library_item*>(ctx->item.get()), ctx->added ) == true )
74 75 76
                break;
        }
    }, ctx);
77 78
}

79 80 81 82 83 84 85 86 87 88 89 90
void
media_library::onDiscoveryStarted( const std::string& entryPoint )
{
    LOGI( "Starting [%s] discovery", entryPoint.c_str() );
}

void
media_library::onDiscoveryCompleted( const std::string& entryPoint )
{
    LOGI("Completed [%s] discovery", entryPoint.c_str() );
}

91
void
92
media_library::onReloadStarted( const std::string& entryPoint )
93
{
94 95 96 97
    if ( entryPoint.empty() == true )
        LOGI( "Reloading media library..." );
    else
        LOGI( "Reloading media library folder %s...", entryPoint.c_str() );
98 99 100
}

void
101
media_library::onReloadCompleted( const std::string& entryPoint )
102
{
103 104 105 106
    if ( entryPoint.empty() == true )
        LOGI( "Media library reload completed" );
    else
        LOGI( "Media library folder %s reload completed", entryPoint.c_str() );
107 108 109 110
    for (auto &p : m_onChangeCb)
    {
        ecore_main_loop_thread_safe_call_async( p.first, p.second );
    }
111 112
}

113
void
114
media_library::onParsingStatsUpdated( uint32_t percent )
115
{
116 117 118 119 120 121 122 123
    auto ctx = new ProgressUpdateCallbackCtx{ this, (uint8_t)percent };
    ecore_main_loop_thread_safe_call_async( [](void* p_data) {
        std::unique_ptr<ProgressUpdateCallbackCtx> ctx( reinterpret_cast<ProgressUpdateCallbackCtx*>( p_data ) );
        auto mlptr = ctx->wml.lock();
        if ( mlptr == nullptr )
            return;
        ctx->ml->m_progressCb( ctx->ml->m_progressData, ctx->percent );
    }, ctx);
124 125
}

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
void
media_library::registerOnChange(media_library_file_list_changed_cb cb, void* cbUserData)
{
    m_onChangeCb.emplace_back(cb, cbUserData);
}

void
media_library::unregisterOnChange(media_library_file_list_changed_cb cb, void* cbUserData)
{
    auto ite = end(m_onChangeCb);
    for (auto it = begin(m_onChangeCb); it != ite; ++it)
    {
        if ((*it).first == cb && (*it).second == cb)
        {
            m_onChangeCb.erase(it);
            return;
        }
    }
}
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

void
media_library::registerOnItemUpdated(media_library_item_updated_cb cb, void* userData)
{
    m_onItemUpdatedCb.emplace_back( cb, userData );
}

void
media_library::unregisterOnItemUpdated(media_library_item_updated_cb cb, void* userData)
{
    auto ite = end(m_onItemUpdatedCb);
    for (auto it = begin(m_onItemUpdatedCb); it != ite; ++it)
    {
        if ((*it).first == cb && (*it).second == cb)
        {
            m_onItemUpdatedCb.erase(it);
            return;
        }
    }
}
165

166 167 168 169 170 171
void media_library::registerProgressCb( media_library_scan_progress_cb pf_progress, void* p_data )
{
    m_progressCb = pf_progress;
    m_progressData = p_data;
}

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
media_library *
media_library_create(application *p_app)
{
    try
    {
        return new media_library;
    }
    catch (std::exception& ex)
    {
        LOGE( "%s", ex.what() );
        return nullptr;
    }
}

bool
187
media_library_start(media_library* p_media_library)
188 189 190 191 192 193 194 195
{
    auto appDataCStr = std::unique_ptr<char, void(*)(void*)>( system_storage_appdata_get(), &free );
    std::string appData( appDataCStr.get() );
    if ( appDataCStr == nullptr )
    {
        LOGE( "Failed to fetch application data directory" );
        return false;
    }
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    // Always ensure the folder exists
    errno = 0;
    auto res = mkdir( appData.c_str(), 0700 );
    if ( res != 0 && errno != EEXIST)
    {
        LOGE("Failed to create data directory: %s", strerror(errno));
        return false;
    }
    auto snapshotPath = appData + "/snapshots";
    res = mkdir( snapshotPath.c_str(), 0700 );
    if ( res != 0 && errno != EEXIST)
    {
        LOGE("Failed to create snapshot directory: %s", strerror(errno));
        return false;
    }
211
    p_media_library->logger.reset( new TizenLogger );
212
    p_media_library->ml->setVerbosity( LogLevel::Info );
213
    p_media_library->ml->setLogger( p_media_library->logger.get() );
214
    return p_media_library->ml->initialize( appData + "vlc.db", snapshotPath, p_media_library );
215 216 217 218 219 220 221 222 223
}

void
media_library_delete(media_library* p_media_library)
{
    delete p_media_library;
}

void
224
media_library_discover( const media_library* p_ml, const char* psz_location )
225 226 227 228
{
    p_ml->ml->discover( psz_location );
}

229
template <typename SourceFunc, typename ConvertorFunc>
230
struct ml_callback_context
231
{
232 233 234
    ml_callback_context( media_library_list_cb c, void* p_user_data, SourceFunc s, ConvertorFunc conv )
        : cb(c), list(nullptr), p_data(p_user_data)
          , source(s), convertor(conv){}
235 236
    media_library_list_cb cb;
    Eina_List* list;
237
    void* p_data;
238 239
    SourceFunc source;
    ConvertorFunc convertor;
240
};
241

242
template <typename SourceFunc, typename ConvertorFunc>
243
void
244
intermediate_list_callback( void* p_data )
245
{
246
    auto ctx = reinterpret_cast<ml_callback_context<SourceFunc, ConvertorFunc>*>( p_data );
247 248 249 250
    ctx->cb( ctx->list, ctx->p_data );
    delete ctx;
}

251 252
template <typename SourceFunc, typename ConvertorFunc>
static void media_library_common_getter(media_library_list_cb cb, void* p_user_data, SourceFunc source, ConvertorFunc conv)
253
{
254
    auto ctx = new ml_callback_context<SourceFunc, ConvertorFunc>( cb, p_user_data, source, conv );
255

256
    ecore_thread_run( [](void* data, Ecore_Thread* ) {
257 258
        auto ctx = reinterpret_cast<ml_callback_context<SourceFunc, ConvertorFunc>*>( data );
        auto items = ctx->source();
259
        Eina_List *list = nullptr;
260
        for ( auto& f : items )
261
        {
262
            auto elem = ctx->convertor( f );
263 264 265 266
            if ( elem == nullptr )
                continue;
            list = eina_list_append( list, elem );
        }
267
        ctx->list = list;
268
        ecore_main_loop_thread_safe_call_async( intermediate_list_callback<SourceFunc, ConvertorFunc>, ctx );
269
    }, nullptr, nullptr, ctx );
270 271
}

Thomas Guillem's avatar
Thomas Guillem committed
272
void
273
media_library_get_audio_files( media_library* p_ml, media_library_list_cb cb, void* p_user_data )
274
{
275
    media_library_common_getter(cb, p_user_data,
276
            [p_ml](){ return p_ml->ml->audioFiles(); },
277 278
            fileToMediaItem);
}
279

280 281 282 283
void
media_library_get_video_files( media_library* p_ml, media_library_list_cb cb, void* p_user_data )
{
    media_library_common_getter(cb, p_user_data,
284
            [p_ml](){ return p_ml->ml->videoFiles(); },
285
            fileToMediaItem);
286
}
287

288 289 290
void
media_library_get_albums(media_library* p_ml, media_library_list_cb cb, void* p_user_data)
{
291
    media_library_common_getter(cb, p_user_data,
292
            [p_ml](){ return p_ml->ml->albums(); },
293
            albumToAlbumItem);
294 295
}

296 297 298
void
media_library_get_artists( media_library* p_ml, media_library_list_cb cb, void* p_user_data )
{
299
    media_library_common_getter(cb, p_user_data,
300
                [p_ml](){ return p_ml->ml->artists(); },
301
                artistToArtistItem);
302 303
}

304
void
305
media_library_get_artist_albums( media_library* p_ml, unsigned int i_artist_id, media_library_list_cb cb, void* p_user_data )
306
{
307
    ArtistPtr artist = p_ml->ml->artist( i_artist_id );
308 309
    if (artist == nullptr)
    {
310
        LOGE("Can't find artist %d", i_artist_id);
311 312 313
        return;
    }
    media_library_common_getter(cb, p_user_data,
314
                [artist](){ return artist->albums(); },
315 316 317
                &albumToAlbumItem);
}

318
void
319
media_library_get_album_songs(media_library* p_ml, unsigned int i_album_id, media_library_list_cb cb, void* p_user_data)
320
{
321
    auto album = p_ml->ml->album(i_album_id);
322 323
    if (album == nullptr)
    {
324
        LOGE("Can't find album #%d", i_album_id);
325 326 327
        return;
    }
    media_library_common_getter(cb, p_user_data,
328
            [album](){ return album->tracks(); },
329
            fileToMediaItem);
330 331
}

332
void
333
media_library_get_artist_songs(media_library* p_ml, unsigned int i_artist_id, media_library_list_cb cb, void* p_user_data)
334
{
335
    ArtistPtr artist = p_ml->ml->artist(i_artist_id);
336 337
    if (artist == nullptr)
    {
338
        LOGE("Can't find artist %u", i_artist_id);
339 340 341
        return;
    }
    media_library_common_getter(cb, p_user_data,
342
                [artist](){ return artist->media(); },
343 344 345
                &fileToMediaItem);
}

346 347 348 349 350 351 352 353 354 355 356
void
media_library_register_on_change(media_library* ml, media_library_file_list_changed_cb cb, void* p_data)
{
    ml->registerOnChange(cb, p_data);
}

void
media_library_unregister_on_change(media_library* ml, media_library_file_list_changed_cb cb, void* p_data)
{
    ml->unregisterOnChange(cb, p_data);
}
357 358 359 360 361 362 363 364 365 366 367 368

void
media_library_register_item_updated(media_library* ml, media_library_item_updated_cb cb, void* p_data )
{
    ml->registerOnItemUpdated(cb, p_data);
}

void
media_library_unregister_item_updated(media_library* ml, media_library_item_updated_cb cb, void* p_data )
{
    ml->unregisterOnItemUpdated(cb, p_data);
}
369

370 371 372 373 374 375
void
media_library_register_progress_cb( media_library* ml, media_library_scan_progress_cb pf_progress, void* p_data )
{
    ml->registerProgressCb( pf_progress, p_data );
}

376 377 378 379 380
void
media_library_reload(media_library* ml)
{
    ml->ml->reload();
}
381 382 383 384 385 386

bool
media_library_is_various_artist(const artist_item* p_item)
{
    return p_item->i_id == medialibrary::VariousArtistID;
}