Commit 99a12d8c authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

Media: Use the new separated Thumbnail table

parent 445e58d7
......@@ -127,6 +127,16 @@ class IMedia
///
virtual const std::string& thumbnail() = 0;
///
/// \brief isThumbnailGenerated Returns true if a thumbnail generation was
/// attempted.
/// In case the thumbnail generation failed, this will still be true, but
/// the thumbnail returned by \sa{thumbnail} will be empty.
/// This is intended as a helper for the client application, so it doesn't
/// attempt ask for a new thumbmail generation.
/// \return
///
virtual bool isThumbnailGenerated() const = 0;
///
/// \brief setThumbnail Sets a thumbnail for the current media
/// \param mrl A mrl pointing the the thumbnail file.
/// \return true in case the thumbnail was successfully stored to database
......
......@@ -41,6 +41,7 @@
#include "logging/Logger.h"
#include "Movie.h"
#include "ShowEpisode.h"
#include "database/SqliteTools.h"
#include "VideoTrack.h"
#include "filesystem/IFile.h"
......@@ -69,7 +70,8 @@ Media::Media( MediaLibraryPtr ml, sqlite::Row& row )
>> m_lastPlayedDate
>> m_insertionDate
>> m_releaseDate
>> m_thumbnail
>> m_thumbnailId
>> m_thumbnailGenerated
>> m_title
>> m_filename
>> m_isFavorite
......@@ -86,6 +88,8 @@ Media::Media( MediaLibraryPtr ml, const std::string& title, Type type )
, m_lastPlayedDate( 0 )
, m_insertionDate( time( nullptr ) )
, m_releaseDate( 0 )
, m_thumbnailId( 0 )
, m_thumbnailGenerated( false )
, m_title( title )
// When creating a Media, meta aren't parsed, and therefor, is the filename
, m_filename( title )
......@@ -259,7 +263,20 @@ std::vector<AudioTrackPtr> Media::audioTracks()
const std::string& Media::thumbnail()
{
return m_thumbnail;
if ( m_thumbnailId == 0 || m_thumbnailGenerated == false )
{
static const std::string empty;
return empty;
}
auto lock = m_thumbnail.lock();
if ( m_thumbnail.isCached() == false )
m_thumbnail = Thumbnail::fetch( m_ml, m_thumbnailId );
return m_thumbnail.get()->mrl();
}
bool Media::isThumbnailGenerated() const
{
return m_thumbnailGenerated;
}
unsigned int Media::insertionDate() const
......@@ -350,33 +367,54 @@ void Media::setReleaseDate( unsigned int date )
m_changed = true;
}
void Media::setThumbnailCached( const std::string& thumbnail )
{
if ( m_thumbnail == thumbnail )
return;
m_thumbnail = thumbnail;
m_changed = true;
}
bool Media::setThumbnail(const std::string& thumbnail )
bool Media::setThumbnail( const std::string& thumbnailMrl, Thumbnail::Origin origin )
{
if ( m_thumbnailId != 0 )
{
auto lock = m_thumbnail.lock();
if ( m_thumbnail.isCached() == false )
{
m_thumbnail = Thumbnail::fetch( m_ml, m_thumbnailId );
if ( m_thumbnail.get() == nullptr )
{
LOG_WARN( "Failed to fetch thumbnail entity #", m_thumbnailId );
return false;
}
}
return m_thumbnail.get()->setMrl( thumbnailMrl );
}
std::unique_ptr<sqlite::Transaction> t;
if ( sqlite::Transaction::transactionInProgress() == false )
t = m_ml->getConn()->newTransaction();
auto lock = m_thumbnail.lock();
m_thumbnail = Thumbnail::create( m_ml, thumbnailMrl, origin );
if ( m_thumbnail.get() == nullptr )
return false;
static const std::string req = "UPDATE " + policy::MediaTable::Name + " SET "
"thumbnail = ? WHERE id_media = ?";
if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, thumbnail, m_id ) == false )
"thumbnail_id = ?, thumbnail_generated = 1 WHERE id_media = ?";
if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, m_thumbnail.get()->id(), m_id ) == false )
return false;
m_thumbnail = thumbnail;
m_thumbnailId = m_thumbnail.get()->id();
m_thumbnailGenerated = true;
if ( t != nullptr )
t->commit();
return true;
}
bool Media::setThumbnail( const std::string& thumbnailMrl )
{
return setThumbnail( thumbnailMrl, Thumbnail::Origin::UserProvided );
}
bool Media::save()
{
static const std::string req = "UPDATE " + policy::MediaTable::Name + " SET "
"type = ?, subtype = ?, duration = ?, release_date = ?,"
"thumbnail = ?, title = ? WHERE id_media = ?";
"title = ? WHERE id_media = ?";
if ( m_changed == false )
return true;
if ( sqlite::Tools::executeUpdate( m_ml->getConn(), req, m_type, m_subType, m_duration,
m_releaseDate, m_thumbnail, m_title, m_id ) == false )
m_releaseDate, m_title, m_id ) == false )
{
return false;
}
......@@ -539,11 +577,14 @@ void Media::createTable( sqlite::Connection* connection )
"last_played_date UNSIGNED INTEGER,"
"insertion_date UNSIGNED INTEGER,"
"release_date UNSIGNED INTEGER,"
"thumbnail TEXT,"
"thumbnail_id INTEGER,"
"thumbnail_generated BOOLEAN NOT NULL DEFAULT 0,"
"title TEXT COLLATE NOCASE,"
"filename TEXT,"
"is_favorite BOOLEAN NOT NULL DEFAULT 0,"
"is_present BOOLEAN NOT NULL DEFAULT 1"
"is_present BOOLEAN NOT NULL DEFAULT 1,"
"FOREIGN KEY(thumbnail_id) REFERENCES " + policy::ThumbnailTable::Name
+ "(id_thumbnail)"
")";
const std::string vtableReq = "CREATE VIRTUAL TABLE IF NOT EXISTS "
......
......@@ -27,6 +27,7 @@
#include "medialibrary/IMedia.h"
#include "factory/IFileSystem.h"
#include "File.h"
#include "Thumbnail.h"
#include "database/DatabaseHelpers.h"
#include "utils/Cache.h"
......@@ -123,7 +124,9 @@ class Media : public IMedia, public DatabaseHelpers<Media, policy::MediaTable>
unsigned int nbChannels, const std::string& language, const std::string& desc );
virtual std::vector<AudioTrackPtr> audioTracks() override;
virtual const std::string& thumbnail() override;
virtual bool isThumbnailGenerated() const override;
virtual bool setThumbnail( const std::string &thumbnail );
bool setThumbnail( const std::string& thumbnail, Thumbnail::Origin origin );
virtual unsigned int insertionDate() const override;
virtual unsigned int releaseDate() const override;
......@@ -132,7 +135,6 @@ class Media : public IMedia, public DatabaseHelpers<Media, policy::MediaTable>
virtual bool setMetadata( MetadataType type, int64_t value ) override;
void setReleaseDate( unsigned int date );
void setThumbnailCached( const std::string& thumbnail );
bool save();
std::shared_ptr<File> addFile( const fs::IFile& fileFs, int64_t parentFolderId,
......@@ -158,7 +160,8 @@ private:
std::time_t m_lastPlayedDate;
std::time_t m_insertionDate;
unsigned int m_releaseDate;
std::string m_thumbnail;
int64_t m_thumbnailId;
unsigned int m_thumbnailGenerated;
std::string m_title;
// We store the filename as a shortcut when sorting. The filename (*not* the title
// might be used as a fallback
......@@ -172,6 +175,7 @@ private:
mutable Cache<MoviePtr> m_movie;
mutable Cache<std::vector<FilePtr>> m_files;
mutable Cache<std::vector<MediaMetadata>> m_metadata;
mutable Cache<std::shared_ptr<Thumbnail>> m_thumbnail;
bool m_changed;
friend policy::MediaTable;
......
......@@ -843,6 +843,11 @@ InitializeResult MediaLibrary::updateDatabaseModel( unsigned int previousVersion
parser::Task::recoverUnscannedFiles( this );
previousVersion = 12;
}
if ( previousVersion == 12 )
{
migrateModel12to13();
previousVersion = 13;
}
// To be continued in the future!
if ( needRescan == true )
......@@ -1011,6 +1016,24 @@ void MediaLibrary::migrateModel10to11()
t->commit();
}
void MediaLibrary::migrateModel12to13()
{
sqlite::Connection::WeakDbContext weakConnCtx{ getConn() };
auto t = getConn()->newTransaction();
using namespace policy;
std::string reqs[] = {
# include "database/migrations/migration12-13.sql"
};
for ( const auto& req : reqs )
sqlite::Tools::executeRequest( getConn(), req );
// Re-create triggers removed in the process
Media::createTriggers( getConn() );
// Also fix a trigger that was wrongly created & deleted during this migration
AlbumTrack::createTriggers( getConn() );
t->commit();
}
void MediaLibrary::reload()
{
if ( m_discovererWorker != nullptr )
......
......@@ -178,6 +178,7 @@ class MediaLibrary : public IMediaLibrary, public IDeviceListerCb
void migrateModel8to9();
void migrateModel9to10();
void migrateModel10to11();
void migrateModel12to13();
void createAllTables();
void createAllTriggers();
void registerEntityHooks();
......
......@@ -32,7 +32,7 @@
namespace medialibrary
{
const uint32_t Settings::DbModelVersion = 12u;
const uint32_t Settings::DbModelVersion = 13u;
Settings::Settings( MediaLibrary* ml )
: m_ml( ml )
......
"CREATE TEMPORARY TABLE " + MediaTable::Name + "_backup("
"id_media INTEGER PRIMARY KEY AUTOINCREMENT,"
"type INTEGER,"
"subtype INTEGER,"
"duration INTEGER DEFAULT -1,"
"play_count UNSIGNED INTEGER,"
"last_played_date UNSIGNED INTEGER,"
"insertion_date UNSIGNED INTEGER,"
"release_date UNSIGNED INTEGER,"
"thumbnail TEXT,"
"title TEXT COLLATE NOCASE,"
"filename TEXT,"
"is_favorite BOOLEAN NOT NULL DEFAULT 0,"
"is_present BOOLEAN NOT NULL DEFAULT 1"
")",
"INSERT INTO " + MediaTable::Name + "_backup SELECT * FROM " + MediaTable::Name,
"INSERT INTO " + ThumbnailTable::Name + "(id_thumbnail, mrl, origin) "
"SELECT id_media, thumbnail, " +
std::to_string( static_cast<typename std::underlying_type<Thumbnail::Origin>::type>(
Thumbnail::Origin::UserProvided ) ) +
" FROM " + MediaTable::Name + " WHERE thumbnail IS NOT NULL AND thumbnail != ''",
"DROP TABLE " + MediaTable::Name,
"CREATE TABLE " + MediaTable::Name + "("
"id_media INTEGER PRIMARY KEY AUTOINCREMENT,"
"type INTEGER,"
"subtype INTEGER,"
"duration INTEGER DEFAULT -1,"
"play_count UNSIGNED INTEGER,"
"last_played_date UNSIGNED INTEGER,"
"insertion_date UNSIGNED INTEGER,"
"release_date UNSIGNED INTEGER,"
"thumbnail_id INTEGER,"
"thumbnail_generated BOOLEAN NOT NULL DEFAULT 0,"
"title TEXT COLLATE NOCASE,"
"filename TEXT,"
"is_favorite BOOLEAN NOT NULL DEFAULT 0,"
"is_present BOOLEAN NOT NULL DEFAULT 1,"
"FOREIGN KEY(thumbnail_id) REFERENCES " + ThumbnailTable::Name
+ "(id_thumbnail)"
")",
"INSERT INTO " + MediaTable::Name + "("
"id_media, type, subtype, duration, play_count, last_played_date, insertion_date,"
"release_date, thumbnail_id, thumbnail_generated, title, filename, is_favorite,"
"is_present) "
"SELECT id_media, type, subtype, duration, play_count, last_played_date,"
"insertion_date, release_date, "
"CASE thumbnail WHEN NULL THEN 0 WHEN '' THEN 0 ELSE id_media END,"
"CASE thumbnail WHEN NULL THEN 0 WHEN '' THEN 0 ELSE 1 END,"
"title, filename, is_favorite, is_present FROM " + MediaTable::Name + "_backup",
......@@ -377,7 +377,7 @@ bool MetadataParser::parseAudioFile( parser::Task& task )
auto artworkMrl = task.vlcMedia.meta( libvlc_meta_ArtworkURL );
if ( artworkMrl.empty() == false )
{
task.media->setThumbnailCached( artworkMrl );
task.media->setThumbnail( artworkMrl, Thumbnail::Origin::Media );
// Don't use an attachment as default artwork for album/artists
if ( utils::file::schemeIs( "attachment", artworkMrl ) )
artworkMrl.clear();
......
......@@ -31,6 +31,7 @@
#include "database/SqliteConnection.h"
#include "Artist.h"
#include "Media.h"
class Misc : public Tests
{
......@@ -151,3 +152,19 @@ TEST_F( DbModel, Upgrade8to9 )
auto media = ml->files();
ASSERT_EQ( 1u, media.size() );
}
TEST_F( DbModel, Upgrade12to13 )
{
LoadFakeDB( SRC_DIR "/test/unittest/db_v12.sql" );
auto res = ml->initialize( "test.db", "/tmp", cbMock.get() );
ASSERT_EQ( InitializeResult::Success, res );
auto media = ml->files();
ASSERT_EQ( 2u, media.size() );
auto m = media[0];
ASSERT_EQ( m->thumbnail(), "/path/to/thumbnail" );
ASSERT_TRUE( m->isThumbnailGenerated() );
m = media[1];
ASSERT_EQ( m->thumbnail(), "" );
ASSERT_FALSE( m->isThumbnailGenerated() );
}
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