MediaLibrary.cpp 18.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * 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 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.
 *****************************************************************************/

23
24
#include <algorithm>
#include <functional>
25
26
27

#include "Fixup.h"

28
29
#include "Album.h"
#include "AlbumTrack.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
30
#include "Artist.h"
31
#include "AudioTrack.h"
32
#include "discoverer/DiscovererWorker.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
33
#include "Device.h"
34
#include "File.h"
35
#include "Folder.h"
36
#include "Genre.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
37
#include "History.h"
38
#include "Media.h"
39
#include "MediaLibrary.h"
40
#include "Label.h"
41
#include "logging/Logger.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
42
#include "Movie.h"
43
#include "parser/Parser.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
44
#include "Playlist.h"
45
46
#include "Show.h"
#include "ShowEpisode.h"
47
#include "database/SqliteTools.h"
48
#include "database/SqliteConnection.h"
49
#include "utils/Filename.h"
50
#include "VideoTrack.h"
51

52
53
54
// Discoverers:
#include "discoverer/FsDiscoverer.h"

55
56
57
// Metadata services:
#include "metadata_services/vlc/VLCMetadataService.h"
#include "metadata_services/vlc/VLCThumbnailer.h"
58
#include "metadata_services/MetadataParser.h"
59

60
61
#include "filesystem/IDirectory.h"
#include "filesystem/IFile.h"
62
#include "filesystem/IDevice.h"
63
64
#include "factory/FileSystem.h"

65
const std::vector<std::string> MediaLibrary::supportedVideoExtensions {
66
67
68
69
70
    // Videos
    "avi", "3gp", "amv", "asf", "divx", "dv", "flv", "gxf",
    "iso", "m1v", "m2v", "m2t", "m2ts", "m4v", "mkv", "mov",
    "mp2", "mp4", "mpeg", "mpeg1", "mpeg2", "mpeg4", "mpg",
    "mts", "mxf", "nsv", "nuv", "ogg", "ogm", "ogv", "ogx", "ps",
71
72
73
74
    "rec", "rm", "rmvb", "tod", "ts", "vob", "vro", "webm", "wmv"
};

const std::vector<std::string> MediaLibrary::supportedAudioExtensions {
75
76
77
78
79
80
81
82
    // Audio
    "a52", "aac", "ac3", "aiff", "amr", "aob", "ape",
    "dts", "flac", "it", "m4a", "m4p", "mid", "mka", "mlp",
    "mod", "mp1", "mp2", "mp3", "mpc", "oga", "ogg", "oma",
    "rmi", "s3m", "spx", "tta", "voc", "vqf", "w64", "wav",
    "wma", "wv", "xa", "xm"
};

83
const uint32_t MediaLibrary::DbModelVersion = 2;
84

85
MediaLibrary::MediaLibrary()
86
    : m_verbosity( LogLevel::Error )
87
{
88
    Log::setLogLevel( m_verbosity );
89
90
}

91
92
MediaLibrary::~MediaLibrary()
{
93
    // Explicitely stop the discoverer, to avoid it writting while tearing down.
94
95
    if ( m_discoverer != nullptr )
        m_discoverer->stop();
96
    Media::clear();
97
    Folder::clear();
98
99
100
101
102
    Label::clear();
    Album::clear();
    AlbumTrack::clear();
    Show::clear();
    ShowEpisode::clear();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
103
    Movie::clear();
104
    VideoTrack::clear();
105
    AudioTrack::clear();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
106
    Artist::clear();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
107
    Device::clear();
108
    File::clear();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
109
    Playlist::clear();
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
110
    History::clear();
111
    Genre::clear();
112
    // Explicitely release the connection's TLS
113
114
    if ( m_dbConnection != nullptr )
        m_dbConnection->release();
115
116
}

117
void MediaLibrary::setFsFactory(std::shared_ptr<factory::IFileSystem> fsFactory)
118
{
119
120
121
    m_fsFactory = fsFactory;
}

122
123
bool MediaLibrary::createAllTables()
{
124
    auto t = m_dbConnection->newTransaction();
125
    auto res = Device::createTable( m_dbConnection.get() ) &&
126
        Folder::createTable( m_dbConnection.get() ) &&
127
        Media::createTable( m_dbConnection.get() ) &&
128
        File::createTable( m_dbConnection.get() ) &&
129
        Label::createTable( m_dbConnection.get() ) &&
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
130
        Playlist::createTable( m_dbConnection.get() ) &&
131
        Genre::createTable( m_dbConnection.get() ) &&
132
133
        Album::createTable( m_dbConnection.get() ) &&
        AlbumTrack::createTable( m_dbConnection.get() ) &&
134
        Album::createTriggers( m_dbConnection.get() ) &&
135
136
137
138
139
        Show::createTable( m_dbConnection.get() ) &&
        ShowEpisode::createTable( m_dbConnection.get() ) &&
        Movie::createTable( m_dbConnection.get() ) &&
        VideoTrack::createTable( m_dbConnection.get() ) &&
        AudioTrack::createTable( m_dbConnection.get() ) &&
140
        Artist::createTable( m_dbConnection.get() ) &&
141
        Artist::createDefaultArtists( m_dbConnection.get() ) &&
142
        Artist::createTriggers( m_dbConnection.get() ) &&
143
        Media::createTriggers( m_dbConnection.get() ) &&
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
144
        Playlist::createTriggers( m_dbConnection.get() ) &&
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
145
        History::createTable( m_dbConnection.get() ) &&
146
147
148
149
150
151
152
        Settings::createTable( m_dbConnection.get() );
    if ( res == false )
        return false;
    t->commit();
    return true;
}

153
154
155
156
157
bool MediaLibrary::validateSearchPattern( const std::string& pattern )
{
    return pattern.size() >= 3;
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
158
bool MediaLibrary::initialize( const std::string& dbPath, const std::string& thumbnailPath, IMediaLibraryCb* mlCallback )
159
160
161
162
{
    if ( m_fsFactory == nullptr )
        m_fsFactory.reset( new factory::FileSystemFactory );
    Folder::setFileSystemFactory( m_fsFactory );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
163
    m_thumbnailPath = thumbnailPath;
164
165
166
167
168
169
170
171
    m_callback = mlCallback;
    m_dbConnection.reset( new SqliteConnection( dbPath ) );

    // We need to create the tables in order of triggers creation
    // Device is the "root of all evil". When a device is modified,
    // we will trigger an update on folder, which will trigger
    // an update on files, and so on.
    if ( createAllTables() == false )
172
    {
173
        LOG_ERROR( "Failed to create database structure" );
174
175
        return false;
    }
176
177
178
    if ( m_settings.load( m_dbConnection.get() ) == false )
        return false;
    if ( m_settings.dbModelVersion() != DbModelVersion )
179
180
181
182
    {
        if ( updateDatabaseModel( m_settings.dbModelVersion() ) == false )
            return false;
    }
183
184
    startDiscoverer();
    startParser();
185
    return true;
186
187
}

188
189
190
191
192
193
void MediaLibrary::setVerbosity(LogLevel v)
{
    m_verbosity = v;
    Log::setLogLevel( v );
}

194
std::vector<MediaPtr> MediaLibrary::files()
195
{
196
197
    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name + " WHERE is_present = 1";
    return Media::fetchAll<IMedia>( m_dbConnection.get(), req );
198
}
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
199

200
std::vector<MediaPtr> MediaLibrary::audioFiles()
201
{
202
    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name + " WHERE type = ? AND is_present = 1 ORDER BY title";
203
    return Media::fetchAll<IMedia>( m_dbConnection.get(), req, IMedia::Type::AudioType );
204
205
}

206
std::vector<MediaPtr> MediaLibrary::videoFiles()
207
{
208
    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name + " WHERE type = ? AND is_present = 1 ORDER BY title";
209
    return Media::fetchAll<IMedia>( m_dbConnection.get(), req, IMedia::Type::VideoType );
210
211
}

212
std::shared_ptr<Media> MediaLibrary::addFile( const std::string& path, Folder& parentFolder, fs::IDirectory& parentFolderFs )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
213
{
214
    std::unique_ptr<fs::IFile> fileFs;
215
216
    try
    {
217
        fileFs = m_fsFactory->createFile( path );
218
219
220
221
222
223
224
    }
    catch (std::exception& ex)
    {
        LOG_ERROR( "Failed to create an IFile for ", path, ": ", ex.what() );
        return nullptr;
    }

225
    auto type = IMedia::Type::UnknownType;
226
    auto ext = fileFs->extension();
227
228
229
230
231
232
    auto predicate = [ext](const std::string& v) {
        return strcasecmp(v.c_str(), ext.c_str()) == 0;
    };

    if ( std::find_if( begin( supportedVideoExtensions ), end( supportedVideoExtensions ),
                    predicate ) != end( supportedVideoExtensions ) )
233
    {
234
        type = IMedia::Type::VideoType;
235
    }
236
237
    else if ( std::find_if( begin( supportedAudioExtensions ), end( supportedAudioExtensions ),
                         predicate ) != end( supportedAudioExtensions ) )
238
    {
239
        type = IMedia::Type::AudioType;
240
    }
241
    if ( type == IMedia::Type::UnknownType )
242
        return nullptr;
243

244
    LOG_INFO( "Adding ", path );
245
246
247
248
249
250
    auto mptr = Media::create( m_dbConnection.get(), type, fileFs.get() );
    if ( mptr == nullptr )
    {
        LOG_ERROR( "Failed to add media ", fileFs->fullPath(), " to the media library" );
        return nullptr;
    }
251
252
    // For now, assume all media are made of a single file
    auto file = mptr->addFile( *fileFs, parentFolder, parentFolderFs, File::Type::Entire );
253
    if ( file == nullptr )
254
    {
255
256
        LOG_ERROR( "Failed to add file ", fileFs->fullPath(), " to media #", mptr->id() );
        Media::destroy( m_dbConnection.get(), mptr->id() );
257
258
259
        return nullptr;
    }
    if ( m_callback != nullptr )
260
        m_callback->onMediaAdded( mptr );
261
    if ( m_parser != nullptr )
262
263
        m_parser->parse( mptr, file );
    return mptr;
264
265
}

266
bool MediaLibrary::deleteFolder( const Folder& folder )
267
{
268
    if ( Folder::destroy( m_dbConnection.get(), folder.id() ) == false )
269
        return false;
270
    Media::clear();
271
    return true;
272
273
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
274
std::shared_ptr<Device> MediaLibrary::device( const std::string& uuid )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
275
{
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
276
    return Device::fromUuid( m_dbConnection.get(), uuid );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
277
278
}

279
280
LabelPtr MediaLibrary::createLabel( const std::string& label )
{
281
    return Label::create( m_dbConnection.get(), label );
282
}
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
283
284
285

bool MediaLibrary::deleteLabel( LabelPtr label )
{
286
    return Label::destroy( m_dbConnection.get(), label->id() );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
287
}
288

289
AlbumPtr MediaLibrary::album( unsigned int id )
290
{
291
    return Album::fetch( m_dbConnection.get(), id );
292
293
}

294
std::shared_ptr<Album> MediaLibrary::createAlbum(const std::string& title )
295
{
296
    return Album::create( m_dbConnection.get(), title );
297
298
}

299
300
std::vector<AlbumPtr> MediaLibrary::albums()
{
301
    static const std::string req = "SELECT * FROM " + policy::AlbumTable::Name +
302
            " WHERE is_present=1"
303
            " ORDER BY title ASC";
304
    return Album::fetchAll<IAlbum>( m_dbConnection.get(), req );
305
306
}

307
308
309
310
311
std::vector<GenrePtr> MediaLibrary::genres() const
{
    return Genre::fetchAll<IGenre>( m_dbConnection.get() );
}

312
313
314
315
ShowPtr MediaLibrary::show(const std::string& name)
{
    static const std::string req = "SELECT * FROM " + policy::ShowTable::Name
            + " WHERE name = ?";
316
    return Show::fetch( m_dbConnection.get(), req, name );
317
318
}

319
std::shared_ptr<Show> MediaLibrary::createShow(const std::string& name)
320
{
321
    return Show::create( m_dbConnection.get(), name );
322
323
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
324
325
326
327
MoviePtr MediaLibrary::movie( const std::string& title )
{
    static const std::string req = "SELECT * FROM " + policy::MovieTable::Name
            + " WHERE title = ?";
328
    return Movie::fetch( m_dbConnection.get(), req, title );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
329
330
}

331
std::shared_ptr<Movie> MediaLibrary::createMovie( Media& media, const std::string& title )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
332
{
333
334
    auto movie = Movie::create( m_dbConnection.get(), media.id(), title );
    media.setMovie( movie );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
335
    media.save();
336
    return movie;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
337
338
}

339
340
341
342
343
344
ArtistPtr MediaLibrary::artist(unsigned int id)
{
    return Artist::fetch( m_dbConnection.get(), id );
}

ArtistPtr MediaLibrary::artist( const std::string& name )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
345
346
{
    static const std::string req = "SELECT * FROM " + policy::ArtistTable::Name
347
            + " WHERE name = ? AND is_present = 1";
348
    return Artist::fetch( m_dbConnection.get(), req, name );
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
349
350
}

351
std::shared_ptr<Artist> MediaLibrary::createArtist( const std::string& name )
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
352
{
353
354
355
356
357
358
359
360
361
    try
    {
        return Artist::create( m_dbConnection.get(), name );
    }
    catch( sqlite::errors::ConstraintViolation &ex )
    {
        LOG_WARN( "ContraintViolation while creating an artist (", ex.what(), ") attempting to fetch it instead" );
        return std::static_pointer_cast<Artist>( artist( name ) );
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
362
363
}

364
365
std::vector<ArtistPtr> MediaLibrary::artists() const
{
366
    static const std::string req = "SELECT * FROM " + policy::ArtistTable::Name +
367
            " WHERE nb_albums > 0 AND is_present = 1";
368
    return Artist::fetchAll<IArtist>( m_dbConnection.get(), req );
369
370
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
PlaylistPtr MediaLibrary::createPlaylist( const std::string& name )
{
    return Playlist::create( m_dbConnection.get(), name );
}

std::vector<PlaylistPtr> MediaLibrary::playlists()
{
    return Playlist::fetchAll<IPlaylist>( m_dbConnection.get() );
}

bool MediaLibrary::deletePlaylist( unsigned int playlistId )
{
    return Playlist::destroy( m_dbConnection.get(), playlistId );
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
bool MediaLibrary::addToHistory( MediaPtr media )
{
    if ( media == nullptr )
        return false;
    return History::insert( m_dbConnection.get(), *media );
}

bool MediaLibrary::addToHistory( const std::string& mrl )
{
    return History::insert( m_dbConnection.get(), mrl );
}

std::vector<HistoryPtr> MediaLibrary::history() const
{
    return History::fetch( m_dbConnection.get() );
}

403
medialibrary::MediaSearchAggregate MediaLibrary::searchMedia( const std::string& title ) const
404
{
405
406
    if ( validateSearchPattern( title ) == false )
        return {};
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
    auto tmp = Media::search( m_dbConnection.get(), title );
    medialibrary::MediaSearchAggregate res;
    for ( auto& m : tmp )
    {
        switch ( m->subType() )
        {
        case IMedia::SubType::AlbumTrack:
            res.tracks.emplace_back( std::move( m ) );
            break;
        case IMedia::SubType::Movie:
            res.movies.emplace_back( std::move( m ) );
            break;
        case IMedia::SubType::ShowEpisode:
            res.episodes.emplace_back( std::move( m ) );
            break;
        default:
            res.others.emplace_back( std::move( m ) );
            break;
        }
    }
    return res;
428
429
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
430
431
std::vector<PlaylistPtr> MediaLibrary::searchPlaylists( const std::string& name ) const
{
432
433
    if ( validateSearchPattern( name ) == false )
        return {};
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
434
435
436
    return Playlist::search( m_dbConnection.get(), name );
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
437
438
std::vector<AlbumPtr> MediaLibrary::searchAlbums( const std::string& pattern ) const
{
439
440
    if ( validateSearchPattern( pattern ) == false )
        return {};
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
441
442
443
    return Album::search( m_dbConnection.get(), pattern );
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
444
445
std::vector<GenrePtr> MediaLibrary::searchGenre( const std::string& genre ) const
{
446
447
    if ( validateSearchPattern( genre ) == false )
        return {};
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
448
449
450
    return Genre::search( m_dbConnection.get(), genre );
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
451
452
453
454
455
456
457
std::vector<ArtistPtr> MediaLibrary::searchArtists(const std::string& name ) const
{
    if ( validateSearchPattern( name ) == false )
        return {};
    return Artist::search( m_dbConnection.get(), name );
}

458
459
460
461
462
medialibrary::SearchAggregate MediaLibrary::search( const std::string& pattern ) const
{
    medialibrary::SearchAggregate res;
    res.albums = searchAlbums( pattern );
    res.artists = searchArtists( pattern );
463
    res.genres = searchGenre( pattern );
464
465
466
467
468
    res.media = searchMedia( pattern );
    res.playlists = searchPlaylists( pattern );
    return res;
}

469
470
void MediaLibrary::startParser()
{
471
    m_parser.reset( new Parser( m_dbConnection.get(), this, m_callback ) );
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

    const char* args[] = {
        "-vv",
    };
    m_vlcInstance = VLC::Instance( sizeof(args) / sizeof(args[0]), args );
    m_vlcInstance.logSet([this](int lvl, const libvlc_log_t*, std::string msg) {
        if ( m_verbosity != LogLevel::Verbose )
            return ;
        if ( lvl == LIBVLC_ERROR )
            Log::Error( msg );
        else if ( lvl == LIBVLC_WARNING )
            Log::Warning( msg );
        else
            Log::Info( msg );
    });

488
489
    auto vlcService = std::unique_ptr<VLCMetadataService>( new VLCMetadataService( m_vlcInstance ) );
    auto metadataService = std::unique_ptr<MetadataParser>( new MetadataParser( m_dbConnection.get(), m_fsFactory ) );
490
    auto thumbnailerService = std::unique_ptr<VLCThumbnailer>( new VLCThumbnailer( m_vlcInstance ) );
491
    m_parser->addService( std::move( vlcService ) );
492
    m_parser->addService( std::move( metadataService ) );
493
    m_parser->addService( std::move( thumbnailerService ) );
494
495
496
497
    m_parser->start();
}

void MediaLibrary::startDiscoverer()
498
{
499
500
501
    m_discoverer.reset( new DiscovererWorker );
    m_discoverer->setCallback( m_callback );
    m_discoverer->addDiscoverer( std::unique_ptr<IDiscoverer>( new FsDiscoverer( m_fsFactory, this, m_dbConnection.get() ) ) );
502
    m_discoverer->reload();
503
504
}

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
bool MediaLibrary::updateDatabaseModel( unsigned int previousVersion )
{
    if ( previousVersion == 1 )
    {
        // Way too much differences, introduction of devices, and almost unused in the wild, just drop everything
        std::string req = "PRAGMA writable_schema = 1;"
                            "delete from sqlite_master;"
                            "PRAGMA writable_schema = 0;";
        if ( sqlite::Tools::executeRequest( m_dbConnection.get(), req ) == false )
            return false;
        if ( createAllTables() == false )
            return false;
        ++previousVersion;
    }
    // To be continued in the future!

    // Safety check: ensure we didn't forget a migration along the way
    assert( previousVersion == DbModelVersion );
    m_settings.setDbModelVersion( DbModelVersion );
    m_settings.save();
    return true;
}

528
529
530
531
532
533
void MediaLibrary::reload()
{
    if ( m_discoverer != nullptr )
        m_discoverer->reload();
}

534
535
536
537
538
539
void MediaLibrary::reload( const std::string& entryPoint )
{
    if ( m_discoverer != nullptr )
        m_discoverer->reload( entryPoint );
}

540
541
void MediaLibrary::pauseBackgroundOperations()
{
542
543
    if ( m_parser != nullptr )
        m_parser->pause();
544
545
546
547
}

void MediaLibrary::resumeBackgroundOperations()
{
548
549
    if ( m_parser != nullptr )
        m_parser->resume();
550
551
}

552
553
void MediaLibrary::discover( const std::string &entryPoint )
{
554
555
    if ( m_discoverer != nullptr )
        m_discoverer->discover( entryPoint );
556
557
}

558
bool MediaLibrary::banFolder( const std::string& path )
559
560
561
562
{
    return Folder::blacklist( m_dbConnection.get(), path );
}

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
bool MediaLibrary::unbanFolder( const std::string& path )
{
    auto folder = Folder::blacklistedFolder( m_dbConnection.get(), path );
    if ( folder == nullptr )
        return false;
    deleteFolder( *folder );

    // We are about to refresh the folder we blacklisted earlier, if we don't have a discoverer, stop early
    if ( m_discoverer == nullptr )
        return true;

    auto parentPath = utils::file::parentDirectory( path );
    // If the parent folder was never added to the media library, the discoverer will reject it.
    // We could check it from here, but that would mean fetching the folder twice, which would be a waste.
    m_discoverer->reload( parentPath );
    return true;
}

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
581
const std::string& MediaLibrary::thumbnailPath() const
582
{
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
583
    return m_thumbnailPath;
584
585
}

586
587
588
589
590
void MediaLibrary::setLogger( ILogger* logger )
{
    Log::SetLogger( logger );
}