Library.cpp 9.45 KB
Newer Older
1 2 3
/*****************************************************************************
 * Library.cpp: Multimedia library
 *****************************************************************************
4
 * Copyright (C) 2008-2016 VideoLAN
5
 *
6
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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.
 *****************************************************************************/

23 24
/** \file
  * This file the library contains class implementation.
25
  * It's the backend part of the Library widget of vlmc.
26
  * It can load and unload Medias (Medias.h/Media.cpp)
27
  * It can load and unload Clips (Clip.h/Clip.cpp)
28 29
  */

30 31 32 33
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

34
#include "Library.h"
35 36
#include "Media/Clip.h"
#include "Media/Media.h"
37
#include "MediaLibraryModel.h"
38
#include "Project/Project.h"
39
#include "Settings/Settings.h"
40
#include "Tools/VlmcDebug.h"
41

luyikei's avatar
luyikei committed
42
#include <QVariant>
43 44 45
#include <QHash>
#include <QUuid>

46 47 48
Library::Library( Settings* vlmcSettings, Settings *projectSettings )
    : m_initialized( false )
    , m_cleanState( true )
luyikei's avatar
luyikei committed
49
    , m_settings( new Settings )
50
{
51 52
    // Setting up the external media library
    m_ml.reset( NewMediaLibrary() );
53
    m_ml->setVerbosity( medialibrary::LogLevel::Warning );
54
    m_model = new MediaLibraryModel( *m_ml, this );
55 56 57 58 59 60 61 62 63

    auto s = vlmcSettings->createVar( SettingValue::List, QStringLiteral( "vlmc/mlDirs" ), QVariantList(),
                        "Media Library folders", "List of folders VLMC will search for media files",
                         SettingValue::Folders );
    connect( s, &SettingValue::changed, this, &Library::mlDirsChanged );
    auto ws = vlmcSettings->value( "vlmc/WorkspaceLocation" );
    connect( ws, &SettingValue::changed, this, &Library::workspaceChanged );

    // Setting up the project section of the Library
luyikei's avatar
luyikei committed
64
    m_settings->createVar( SettingValue::List, QStringLiteral( "medias" ), QVariantList(), "", "", SettingValue::Nothing );
65 66
    connect( m_settings.get(), &Settings::postLoad, this, &Library::postLoad, Qt::DirectConnection );
    connect( m_settings.get(), &Settings::preSave, this, &Library::preSave, Qt::DirectConnection );
luyikei's avatar
luyikei committed
67
    projectSettings->addSettings( QStringLiteral( "Library" ), *m_settings );
luyikei's avatar
luyikei committed
68 69
}

luyikei's avatar
luyikei committed
70 71 72 73
void
Library::preSave()
{
    QVariantList l;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
74
    for ( auto val : m_media )
luyikei's avatar
luyikei committed
75 76
        l << val->toVariant();
    m_settings->value( "medias" )->set( l );
77
    setCleanState( true );
luyikei's avatar
luyikei committed
78 79 80 81 82 83
}

void
Library::postLoad()
{
    for ( const auto& var : m_settings->value( "medias" )->get().toList() )
84
    {
85 86
        auto map = var.toMap();
        auto m = Media::fromVariant( map );
87
        addMedia( m );
88 89 90 91 92 93
        if ( map.contains( "clips" ) == true )
        {
            const auto& subClipsList = map["clips"].toList();
            for ( const auto& subClip : subClipsList )
                m->loadSubclip( subClip.toMap() );
        }
94
    }
luyikei's avatar
luyikei committed
95 96
}

luyikei's avatar
luyikei committed
97 98
Library::~Library()
{
99 100 101
}

void
102
Library::addMedia( QSharedPointer<Media> media )
103 104
{
    setCleanState( false );
105
    if ( m_media.contains( media->id() ) )
106
        return;
107
    m_media[media->id()] = media;
108
    m_clips[media->baseClip()->uuid()] = media->baseClip();
109
    emit clipAdded( media->baseClip()->uuid().toString() );
110
    vlmcDebug() << "Clip" << media->baseClip()->uuid().toString() << "is added to Library";
111
    connect( media.data(), &Media::subclipAdded, [this]( QSharedPointer<Clip> c ) {
112
        m_clips[c->uuid()] = c;
113
        emit clipAdded( c->uuid().toString() );
114
        vlmcDebug() << "Clip" << c->uuid().toString() << "is added to Library";
115 116 117 118
        setCleanState( false );
    });
    connect( media.data(), &Media::subclipRemoved, [this]( const QUuid& uuid ) {
        m_clips.remove( uuid );
119
        emit clipRemoved( uuid.toString() );
120
        vlmcDebug() << "Clip" << uuid.toString() << "is removed in Library";
121 122 123
        // This seems wrong, for instance if we undo a clip splitting
        setCleanState( false );
    } );
124 125 126 127 128 129 130 131
}

bool
Library::isInCleanState() const
{
    return m_cleanState;
}

132
QSharedPointer<Media>
133
Library::media( qint64 mediaId )
134
{
135
    return m_media.value( mediaId );
136 137
}

138 139 140 141 142 143 144
medialibrary::MediaPtr
Library::mlMedia( qint64 mediaId )
{
    return m_ml->media( mediaId );
}

MediaLibraryModel*
145
Library::model() const
146
{
147
    return m_model;
148 149 150 151
}

QSharedPointer<Clip>
Library::clip( const QUuid& uuid )
152 153 154 155 156 157 158 159
{
    return m_clips.value( uuid );

}

void
Library::clear()
{
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
160
    m_media.clear();
161 162 163 164
    m_clips.clear();
    setCleanState( true );
}

165 166 167 168 169 170 171 172 173
void
Library::setCleanState( bool newState )
{
    if ( newState != m_cleanState )
    {
        m_cleanState = newState;
        emit cleanStateChanged( newState );
    }
}
174 175 176 177 178 179 180 181 182 183 184 185

void
Library::mlDirsChanged(const QVariant& value)
{
    // We can't handle this event without an initialized media library, and therefor without a valid
    // workspace. In theory, the workspace SettingValue is created before the mlDirs,
    // so it should be loaded before.
    Q_ASSERT( m_initialized == true );

    const auto list = value.toStringList();
    Q_ASSERT( list.empty() == false );
    for ( const auto f : list )
186 187
        // To use FsDiscoverer
        m_ml->discover( std::string( "file://" ) + f.toStdString() );
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
}

void
Library::workspaceChanged(const QVariant& workspace)
{
    Q_ASSERT( workspace.isNull() == false && workspace.canConvert<QString>() );

    if ( m_initialized == false )
    {
        auto w = workspace.toString().toStdString();
        Q_ASSERT( w.empty() == false );
        // Initializing the medialibrary doesn't start new folders discovery.
        // This will happen after the first call to IMediaLibrary::discover()
        m_ml->initialize( w + "/ml.db", w + "/thumbnails/", this );
        m_initialized = true;
203
        m_ml->start();
204
        m_ml->reload();
205 206 207 208 209 210 211 212 213
    }
    //else FIXME, and relocate the media library
}

void
Library::onMediaAdded( std::vector<medialibrary::MediaPtr> mediaList )
{
    for ( auto m : mediaList )
    {
214 215 216
        QMetaObject::invokeMethod( m_model, "addMedia",
                                   Qt::QueuedConnection,
                                   Q_ARG( medialibrary::MediaPtr, m ) );
217 218 219 220 221 222 223 224
    }
}

void
Library::onMediaUpdated( std::vector<medialibrary::MediaPtr> mediaList )
{
    for ( auto m : mediaList )
    {
225 226 227
        QMetaObject::invokeMethod( m_model, "updateMedia",
                                   Qt::QueuedConnection,
                                   Q_ARG( medialibrary::MediaPtr, m ) );
228 229 230 231 232 233 234
    }
}

void
Library::onMediaDeleted( std::vector<int64_t> mediaList )
{
    for ( auto id : mediaList )
235 236 237
        QMetaObject::invokeMethod( m_model, "removeMedia",
                                   Qt::QueuedConnection,
                                   Q_ARG( int64_t, id ) );
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
}

void
Library::onArtistsAdded( std::vector<medialibrary::ArtistPtr> )
{
}

void
Library::onArtistsModified( std::vector<medialibrary::ArtistPtr> )
{
}

void
Library::onArtistsDeleted( std::vector<int64_t> )
{
}

void
Library::onAlbumsAdded( std::vector<medialibrary::AlbumPtr> )
{
}

void
Library::onAlbumsModified( std::vector<medialibrary::AlbumPtr> )
{
}

void
Library::onAlbumsDeleted( std::vector<int64_t> )
{
}

void
Library::onTracksAdded( std::vector<medialibrary::AlbumTrackPtr> )
{
}

void
Library::onTracksDeleted( std::vector<int64_t> )
{
}

void
281
Library::onDiscoveryStarted( const std::string& )
282
{
283 284 285 286 287 288
}

void
Library::onDiscoveryProgress( const std::string& entryPoint )
{
    emit discoveryProgress( QString::fromStdString( entryPoint ) );
289 290 291 292 293 294
}

void
Library::onDiscoveryCompleted( const std::string& entryPoint )
{
    if ( entryPoint.empty() == true )
295 296
        QMetaObject::invokeMethod( m_model, "refresh",
                                   Qt::QueuedConnection );
297

298 299 300 301 302 303 304 305
    emit discoveryCompleted( QString::fromStdString( entryPoint ) );
}

void
Library::onParsingStatsUpdated( uint32_t percent )
{
    emit progressUpdated( static_cast<int>( percent ) );
}
306

luyikei's avatar
luyikei committed
307 308
void
Library::onPlaylistsAdded( std::vector<medialibrary::PlaylistPtr> )
309 310 311
{
}

luyikei's avatar
luyikei committed
312 313
void
Library::onPlaylistsModified( std::vector<medialibrary::PlaylistPtr> )
314 315 316
{
}

luyikei's avatar
luyikei committed
317 318
void
Library::onPlaylistsDeleted( std::vector<int64_t> )
319 320
{
}
321

luyikei's avatar
luyikei committed
322 323
void
Library::onReloadStarted( const std::string& )
324 325 326
{
}

luyikei's avatar
luyikei committed
327
void
328
Library::onReloadCompleted( const std::string& entryPoint )
329
{
330 331 332
    if ( entryPoint.empty() == true )
    {
        for ( auto media : m_ml->videoFiles() )
333 334 335
            QMetaObject::invokeMethod( m_model, "addMedia",
                                       Qt::QueuedConnection,
                                       Q_ARG( medialibrary::MediaPtr, media ) );
336 337

        for ( auto media : m_ml->audioFiles() )
338 339 340
            QMetaObject::invokeMethod( m_model, "addMedia",
                                       Qt::QueuedConnection,
                                       Q_ARG( medialibrary::MediaPtr, media ) );
341
    }
342 343
}

luyikei's avatar
luyikei committed
344 345
void
Library::onEntryPointRemoved( const std::string&, bool )
346 347 348
{
}

luyikei's avatar
luyikei committed
349 350
void
Library::onEntryPointBanned( const std::string&, bool )
351 352 353
{
}

luyikei's avatar
luyikei committed
354 355
void
Library::onEntryPointUnbanned( const std::string&, bool )
356 357
{
}
358 359 360 361 362 363

void
Library::onBackgroundTasksIdleChanged( bool )
{

}