Commit 8a3cac39 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

File: Add an active state

parent 672e0ad1
......@@ -54,6 +54,16 @@ public:
/// \brief isExternal returns true if this stream isn't managed by the medialibrary
///
virtual bool isExternal() const = 0;
/// \brief isActive Returns true if this is the active file for the specified Type
/// This only makes sense for Soundtrack & Subtitles types
///
virtual bool isActive() const = 0;
///
/// \brief setActive Mark this stream as the active one for its specific type, or deactivate it
/// This only makes sense for Soundtrack & Subtitles types
/// \return false in case of error, true otherwise.
///
virtual bool setActive( bool active ) = 0;
};
}
......@@ -49,7 +49,8 @@ File::File( MediaLibraryPtr ml, sqlite::Row& row )
>> m_folderId
>> m_isPresent
>> m_isRemovable
>> m_isExternal;
>> m_isExternal
>> m_isActive;
}
File::File( MediaLibraryPtr ml, int64_t mediaId, Type type, const fs::IFile& file, int64_t folderId, bool isRemovable )
......@@ -65,6 +66,7 @@ File::File( MediaLibraryPtr ml, int64_t mediaId, Type type, const fs::IFile& fil
, m_isPresent( true )
, m_isRemovable( isRemovable )
, m_isExternal( false )
, m_isActive( false )
{
}
......@@ -81,6 +83,7 @@ File::File(MediaLibraryPtr ml, int64_t mediaId, IFile::Type type, const std::str
, m_isPresent( true )
, m_isRemovable( false )
, m_isExternal( true )
, m_isActive( false )
, m_fullPath( mrl )
{
}
......@@ -125,6 +128,42 @@ bool File::isExternal() const
return m_isExternal;
}
bool File::isActive() const
{
assert( m_type == Type::Soundtrack || m_type == Type::Subtitles );
return m_isActive;
}
bool File::setActive( bool active )
{
if ( m_isActive == active )
return true;
// If we're activating this file, we also need to mark any existing File instance as inactive.
// So first, let's fetch the other active track
auto t = m_ml->getConn()->newTransaction();
if ( active == true )
{
static const std::string fetchActive = "SELECT * FROM " + policy::FileTable::Name + " WHERE "
"media_id = ? AND type = ?";
auto activeTrack = fetch( m_ml, fetchActive, m_mediaId, m_type );
if ( activeTrack != nullptr )
{
static const std::string disableTracks = "UPDATE " + policy::FileTable::Name +
" SET is_active = 0 WHERE media_id = ? AND type = ? LIMIT 1";
if ( sqlite::Tools::executeUpdate( m_ml->getConn(), disableTracks, m_mediaId, m_type ) == false )
return false;
activeTrack->m_isActive = false;
}
}
static const std::string enableTrack = "UPDATE " + policy::FileTable::Name +
" SET is_active = ? WHERE id_file = ?";
if ( sqlite::Tools::executeUpdate( m_ml->getConn(), enableTrack, active, m_id ) == false )
return false;
m_isActive = active;
t->commit();
return true;
}
void File::markStepCompleted( ParserStep step )
{
m_parserSteps = static_cast<ParserStep>( static_cast<uint8_t>( m_parserSteps ) |
......@@ -173,6 +212,7 @@ bool File::createTable( DBConnection dbConnection )
"is_present BOOLEAN NOT NULL DEFAULT 1,"
"is_removable BOOLEAN NOT NULL,"
"is_external BOOLEAN NOT NULL,"
"is_active BOOLEAN NOT NULL,"
"FOREIGN KEY (media_id) REFERENCES " + policy::MediaTable::Name
+ "(id_media) ON DELETE CASCADE,"
"FOREIGN KEY (folder_id) REFERENCES " + policy::FolderTable::Name
......@@ -195,10 +235,11 @@ std::shared_ptr<File> File::create( MediaLibraryPtr ml, int64_t mediaId, Type ty
{
auto self = std::make_shared<File>( ml, mediaId, type, fileFs, folderId, isRemovable );
static const std::string req = "INSERT INTO " + policy::FileTable::Name +
"(media_id, mrl, type, folder_id, last_modification_date, size, is_removable, is_external) VALUES(?, ?, ?, ?, ?, ?, ?, 0)";
"(media_id, mrl, type, folder_id, last_modification_date, size, is_removable, is_external, is_active) "
"VALUES(?, ?, ?, ?, ?, ?, ?, 0, ?)";
if ( insert( ml, self, req, mediaId, self->m_mrl, type, sqlite::ForeignKey( folderId ),
self->m_lastModificationDate, self->m_size, isRemovable ) == false )
self->m_lastModificationDate, self->m_size, isRemovable, type == Type::Main ) == false )
return nullptr;
self->m_fullPath = fileFs.fullPath();
return self;
......@@ -208,9 +249,9 @@ std::shared_ptr<File> File::create( MediaLibraryPtr ml, int64_t mediaId, IFile::
{
auto self = std::make_shared<File>( ml, mediaId, type, mrl );
static const std::string req = "INSERT INTO " + policy::FileTable::Name +
"(media_id, mrl, type, folder_id, is_removable, is_external) VALUES(?, ?, ?, NULL, 0, 1)";
"(media_id, mrl, type, folder_id, is_removable, is_external, is_active) VALUES(?, ?, ?, NULL, 0, 1, ?)";
if ( insert( ml, self, req, mediaId, mrl, type ) == false )
if ( insert( ml, self, req, mediaId, mrl, type, type == Type::Main ) == false )
return nullptr;
return self;
}
......
......@@ -67,6 +67,8 @@ public:
virtual unsigned int lastModificationDate() const override;
virtual unsigned int size() const override;
virtual bool isExternal() const override;
virtual bool isActive() const override;
virtual bool setActive( bool active ) override;
/*
* We need to decouple the current parser state and the saved one.
* For instance, metadata extraction won't save anything in DB, so while
......@@ -114,6 +116,7 @@ private:
bool m_isPresent;
bool m_isRemovable;
bool m_isExternal;
bool m_isActive;
mutable Cache<std::string> m_fullPath;
mutable Cache<std::weak_ptr<Media>> m_media;
......
......@@ -77,3 +77,40 @@ TEST_F( Files, Media )
f = std::static_pointer_cast<File>( files[0] );
ASSERT_EQ( m->id(), f->media()->id() );
}
TEST_F( Files, MarkActive )
{
auto m = ml->addFile( "media.mkv" );
auto audioStream1 = m->addExternalMrl( "foo://soundtrack.mp3", IFile::Type::Soundtrack );
auto audioStream2 = m->addExternalMrl( "foo://soundtrack2.mp3", IFile::Type::Soundtrack );
auto subs = m->addExternalMrl( "foo://subs.srt", IFile::Type::Subtitles );
ASSERT_NE( nullptr, audioStream1 );
ASSERT_NE( nullptr, audioStream2 );
ASSERT_NE( nullptr, subs );
ASSERT_FALSE( audioStream1->isActive() );
ASSERT_FALSE( audioStream2->isActive() );
ASSERT_FALSE( subs->isActive() );
audioStream1->setActive( true );
ASSERT_TRUE( audioStream1->isActive() );
ASSERT_FALSE( audioStream2->isActive() );
subs->setActive( true );
ASSERT_TRUE( subs->isActive() );
// Check that changing the active subs didn't change the active audio track
ASSERT_TRUE( audioStream1->isActive() );
ASSERT_FALSE( audioStream2->isActive() );
// Now change the active audio track
audioStream2->setActive( true );
ASSERT_TRUE( audioStream2->isActive() );
ASSERT_FALSE( audioStream1->isActive() );
// And that it again didn't change anything for subs
ASSERT_TRUE( subs->isActive() );
// Now deactivate all audio streams
audioStream2->setActive( false );
ASSERT_FALSE( audioStream2->isActive() );
ASSERT_FALSE( audioStream1->isActive() );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment