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

Rework artist management

Media now always have a single artist
Artist are being added media
The album artist meta is used to generate the list of artists
The artist meta isn't used for artists list
parent f8e902d9
......@@ -57,7 +57,7 @@ class IMedia
virtual bool addLabel( LabelPtr label ) = 0;
virtual bool removeLabel( LabelPtr label ) = 0;
virtual MoviePtr movie() = 0;
virtual std::vector<ArtistPtr> artists() const = 0;
virtual const std::string& artist() const = 0;
virtual std::vector<std::shared_ptr<ILabel> > labels() = 0;
virtual std::vector<VideoTrackPtr> videoTracks() = 0;
virtual std::vector<AudioTrackPtr> audioTracks() = 0;
......
......@@ -100,7 +100,6 @@ class IMediaLibrary
virtual ArtistPtr artist( const std::string& name ) = 0;
/**
* @brief unknownArtist returns a representation of a virtual "unknown" artist.
* If all tracks have an associated artist, this returns nullptr.
*/
virtual ArtistPtr unknownArtist() = 0;
virtual std::vector<ArtistPtr> artists() const = 0;
......
......@@ -107,6 +107,14 @@ std::vector<MediaPtr> Artist::media() const
}
}
bool Artist::addMedia(Media* media)
{
static const std::string req = "INSERT INTO MediaArtistRelation VALUES(?, ?)";
// If track's ID is 0, the request will fail due to table constraints
sqlite::ForeignKey artistForeignKey( m_id );
return sqlite::Tools::executeRequest( m_dbConnection, req, media->id(), artistForeignKey );
}
bool Artist::createTable( DBConnection dbConnection )
{
static const std::string req = "CREATE TABLE IF NOT EXISTS " +
......
......@@ -27,6 +27,7 @@
#include "IMediaLibrary.h"
class Artist;
class Media;
namespace policy
{
......@@ -58,6 +59,7 @@ public:
bool setShortBio( const std::string& shortBio );
virtual std::vector<AlbumPtr> albums() const override;
virtual std::vector<MediaPtr> media() const override;
bool addMedia( Media* media );
static bool createTable( DBConnection dbConnection );
static std::shared_ptr<Artist> create( DBConnection dbConnection, const std::string& name );
......
......@@ -52,6 +52,7 @@ Media::Media( DBConnection dbConnection, sqlite::Row& row )
>> m_playCount
>> m_showEpisodeId
>> m_mrl
>> m_artist
>> m_movieId
>> m_folderId
>> m_lastModificationDate
......@@ -105,20 +106,21 @@ bool Media::setAlbumTrack( AlbumTrackPtr albumTrack )
return true;
}
bool Media::addArtist( ArtistPtr artist )
const std::string& Media::artist() const
{
static const std::string req = "INSERT INTO MediaArtistRelation VALUES(?, ?)";
// If track's ID is 0, the request will fail due to table constraints
sqlite::ForeignKey artistForeignKey( artist != nullptr ? artist->id() : 0 );
return sqlite::Tools::executeRequest( m_dbConnection, req, m_id, artistForeignKey );
return m_artist;
}
std::vector<ArtistPtr> Media::artists() const
bool Media::setArtist(const std::string& artist)
{
static const std::string req = "SELECT art.* FROM " + policy::ArtistTable::Name + " art "
"LEFT JOIN MediaArtistRelation mar ON mar.id_artist = art.id_artist "
"WHERE mar.id_media = ?";
return Artist::fetchAll( m_dbConnection, req, m_id );
if ( m_artist == artist )
return true;
static const std::string req = "UPDATE " + policy::MediaTable::Name + " SET artist = ? "
"WHERE id_media = ?";
if ( sqlite::Tools::executeUpdate( m_dbConnection, req, artist, m_id ) == false )
return false;
m_artist = artist;
return true;
}
int64_t Media::duration() const
......@@ -326,6 +328,7 @@ bool Media::createTable( DBConnection connection )
"play_count UNSIGNED INTEGER,"
"show_episode_id UNSIGNED INTEGER,"
"mrl TEXT UNIQUE ON CONFLICT FAIL,"
"artist TEXT,"
"movie_id UNSIGNED INTEGER,"
"folder_id UNSIGNED INTEGER,"
"last_modification_date UNSIGNED INTEGER,"
......
......@@ -80,8 +80,8 @@ class Media : public IMedia, public Cache<Media, IMedia, policy::MediaTable, pol
bool setTitle( const std::string& title );
virtual AlbumTrackPtr albumTrack() override;
bool setAlbumTrack( AlbumTrackPtr albumTrack );
bool addArtist( ArtistPtr artist );
virtual std::vector<ArtistPtr> artists() const override;
virtual const std::string& artist() const override;
bool setArtist( const std::string& artist );
virtual int64_t duration() const override;
bool setDuration( int64_t duration);
virtual std::shared_ptr<IShowEpisode> showEpisode() override;
......@@ -120,6 +120,7 @@ class Media : public IMedia, public Cache<Media, IMedia, policy::MediaTable, pol
unsigned int m_playCount;
unsigned int m_showEpisodeId;
std::string m_mrl;
std::string m_artist;
unsigned int m_movieId;
unsigned int m_folderId;
unsigned int m_lastModificationDate;
......
......@@ -309,14 +309,8 @@ ArtistPtr MediaLibrary::artist(const std::string &name)
ArtistPtr MediaLibrary::unknownArtist()
{
if ( m_unknownArtist != nullptr )
return m_unknownArtist;
static const std::string req = "SELECT id_media FROM MediaArtistRelation "
"WHERE id_artist IS NULL LIMIT 1";
if ( sqlite::Tools::hasResults( m_dbConnection.get(), req ) == true )
{
if ( m_unknownArtist == nullptr )
m_unknownArtist = std::make_shared<Artist>( m_dbConnection.get() );
}
return m_unknownArtist;
}
......
......@@ -154,7 +154,7 @@ bool VLCMetadataService::parseAudioFile( std::shared_ptr<Media> media, VLC::Medi
}
}
return handleArtist( album, track, media, vlcMedia, newAlbum );
return handleArtist( album, media, vlcMedia, newAlbum );
}
bool VLCMetadataService::parseVideoFile( std::shared_ptr<Media> file, VLC::Media& media ) const
......@@ -195,7 +195,7 @@ bool VLCMetadataService::parseVideoFile( std::shared_ptr<Media> file, VLC::Media
return true;
}
bool VLCMetadataService::handleArtist( std::shared_ptr<Album> album, std::shared_ptr<AlbumTrack> track, std::shared_ptr<Media> media, VLC::Media& vlcMedia, bool newAlbum ) const
bool VLCMetadataService::handleArtist( std::shared_ptr<Album> album, std::shared_ptr<Media> media, VLC::Media& vlcMedia, bool newAlbum ) const
{
assert(media != nullptr);
......@@ -215,7 +215,7 @@ bool VLCMetadataService::handleArtist( std::shared_ptr<Album> album, std::shared
}
newArtist = true;
}
media->addArtist( artist );
artist->addMedia( media.get() );
// If this is either a new album or a new artist, we need to add the relationship between the two.
if ( album != nullptr && ( newAlbum == true || newArtist == true ) )
{
......@@ -224,19 +224,16 @@ bool VLCMetadataService::handleArtist( std::shared_ptr<Album> album, std::shared
}
}
else
media->addArtist( nullptr );
// We don't care about the Artist if we have no track to tag it with.
if ( track != nullptr )
std::static_pointer_cast<Artist>( m_ml->unknownArtist() )->addMedia( media.get() );
auto artistName = vlcMedia.meta( libvlc_meta_Artist );
if ( artistName.length() > 0 )
media->setArtist( artistName );
else if ( albumArtistName.length() > 0 )
{
auto artistName = vlcMedia.meta( libvlc_meta_Artist );
if ( artistName.length() > 0 )
track->setArtist( artistName );
else if ( albumArtistName.length() > 0 )
{
// Always provide an artist, to avoid the user from having to fallback
// to the album artist by himself
track->setArtist( albumArtistName );
}
// Always provide an artist, to avoid the user from having to fallback
// to the album artist by himself
media->setArtist( albumArtistName );
}
return true;
}
......
......@@ -54,7 +54,7 @@ class VLCMetadataService : public IMetadataService
Status handleMediaMeta( std::shared_ptr<Media> media , VLC::Media &vlcMedia ) const;
bool parseAudioFile( std::shared_ptr<Media> media, VLC::Media &vlcMedia ) const;
bool parseVideoFile( std::shared_ptr<Media> file, VLC::Media &media ) const;
bool handleArtist( std::shared_ptr<Album> album, std::shared_ptr<AlbumTrack> track, std::shared_ptr<Media> media, VLC::Media& vlcMedia, bool newAlbum ) const;
bool handleArtist( std::shared_ptr<Album> album, std::shared_ptr<Media> media, VLC::Media& vlcMedia, bool newAlbum ) const;
std::shared_ptr<AlbumTrack> handleTrack( std::shared_ptr<Album> album, std::shared_ptr<Media> media, VLC::Media& vlcMedia ) const;
VLC::Instance m_instance;
......
......@@ -92,7 +92,7 @@ TEST_F( Artists, AllSongs )
for (auto i = 1; i <= 3; ++i)
{
auto f = ml->addFile( "song" + std::to_string(i) + ".mp3", nullptr );
auto res = f->addArtist( artist );
auto res = artist->addMedia( f.get() );
ASSERT_TRUE( res );
}
......
......@@ -119,6 +119,23 @@ TEST_F( Files, Duration )
ASSERT_EQ( f2->duration(), d );
}
TEST_F( Files, Artist )
{
auto f = std::static_pointer_cast<Media>( ml->addFile( "media.avi", nullptr ) );
ASSERT_EQ( f->artist(), "" );
std::string newArtist( "Rage Against The Otters" );
f->setArtist( newArtist );
ASSERT_EQ( f->artist(), newArtist );
Reload();
auto f2 = ml->file( "media.avi" );
ASSERT_EQ( f2->artist(), newArtist );
}
TEST_F( Files, Snapshot )
{
auto f = ml->addFile( "media.avi", nullptr );
......@@ -137,19 +154,19 @@ TEST_F( Files, Snapshot )
TEST_F( Files, UnknownArtist )
{
// If no song has been added, unknown artist should be null.
auto a = ml->unknownArtist();
ASSERT_EQ( a, nullptr );
auto a = std::static_pointer_cast<Artist>( ml->unknownArtist() );
ASSERT_NE( a, nullptr );
auto tracks = a->media();
ASSERT_EQ( tracks.size(), 0u );
auto f = ml->addFile( "file.mp3", nullptr );
// explicitely set the artist to nullptr (aka "unknown artist")
auto res = f->addArtist( nullptr );
auto res = a->addMedia( f.get() );
ASSERT_EQ( res, true );
// Now, querying unknownArtist should give out some results.
a = ml->unknownArtist();
ASSERT_NE( a, nullptr );
auto tracks = a->media();
tracks = a->media();
ASSERT_EQ( tracks.size(), 1u );
Reload();
......@@ -160,60 +177,3 @@ TEST_F( Files, UnknownArtist )
auto tracks2 = a2->media();
ASSERT_EQ( tracks2.size(), 1u );
}
TEST_F( Files, Artists )
{
auto artist1 = ml->createArtist( "artist 1" );
auto artist2 = ml->createArtist( "artist 2" );
auto album = ml->createAlbum( "album" );
ASSERT_NE( artist1, nullptr );
ASSERT_NE( artist2, nullptr );
for ( auto i = 1; i <= 3; i++ )
{
std::string name = "track" + std::to_string(i) + ".mp3";
auto f = ml->addFile( name, nullptr );
ASSERT_NE( f, nullptr );
auto t = album->addTrack( f, i );
ASSERT_NE( t, nullptr );
}
auto tracks = album->tracks();
ASSERT_NE( tracks.size(), 0u );
for ( auto& it : tracks )
{
//FIXME: This should return a std::vector<IMedia>
auto f = std::static_pointer_cast<Media>( it );
auto res = f->addArtist( artist1 );
ASSERT_EQ( res, true );
res = f->addArtist( artist2 );
ASSERT_EQ( res, true );
auto artists = f->artists();
ASSERT_EQ( artists.size(), 2u );
}
auto artists = ml->artists();
for ( auto& a : artists )
{
auto media = a->media();
ASSERT_EQ( media.size(), 3u );
}
Reload();
auto album2 = ml->album( "album" );
auto tracks2 = album2->tracks();
for ( auto& f : tracks2 )
{
auto artists = f->artists();
ASSERT_EQ( artists.size(), 2u );
}
auto artists2 = ml->artists();
for ( auto& a : artists2 )
{
auto tracks = a->media();
ASSERT_EQ( tracks.size(), 3u );
}
}
......@@ -111,9 +111,8 @@ TEST_F( VLCMetadataServices, ParseAlbum )
ASSERT_NE( track, nullptr );
ASSERT_EQ( file->title(), "Mr. Zebra" );
ASSERT_EQ( track->genre(), "Rock" );
auto artists = file->artists();
ASSERT_EQ( artists.size(), 1u );
ASSERT_EQ( artists[0]->name(), "Tori Amos" );
auto artist = file->artist();
ASSERT_EQ( artist, "Tori Amos" );
auto album = track->album();
ASSERT_NE( album, nullptr );
......
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