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

Add an artist/track relationship

This removes the old std::string artist property on AlbumTrack
parent 4c071328
......@@ -16,8 +16,8 @@ class IAlbumTrack
virtual const std::string& title() = 0;
virtual unsigned int trackNumber() = 0;
virtual std::shared_ptr<IAlbum> album() = 0;
virtual const std::string& artist() const = 0;
virtual bool setArtist( const std::string& artist ) = 0;
virtual bool addArtist( ArtistPtr artist ) = 0;
virtual std::vector<ArtistPtr> artists() const = 0;
virtual std::vector<FilePtr> files() = 0;
/**
* @brief destroy Deletes the album track and the file(s) associated
......
......@@ -14,4 +14,5 @@ public:
virtual const std::string& shortBio() const = 0;
virtual bool setShortBio( const std::string& shortBio ) = 0;
virtual std::vector<AlbumPtr> albums() const = 0;
virtual std::vector<AlbumTrackPtr> tracks() const = 0;
};
......@@ -74,6 +74,7 @@ class IMediaLibrary
virtual MoviePtr createMovie( const std::string& title ) = 0;
virtual ArtistPtr artist( const std::string& name ) = 0;
virtual ArtistPtr createArtist( const std::string& name ) = 0;
virtual std::vector<ArtistPtr> artists() const = 0;
/**
* @brief discover Launch a discovery on the provided entry point.
......
#include "AlbumTrack.h"
#include "Album.h"
#include "Artist.h"
#include "File.h"
#include "database/SqliteTools.h"
#include "logging/Logger.h"
......@@ -16,8 +17,7 @@ AlbumTrack::AlbumTrack( DBConnection dbConnection, sqlite3_stmt* stmt )
m_title = sqlite::Traits<std::string>::Load( stmt, 1 );
m_genre = sqlite::Traits<std::string>::Load( stmt, 2 );
m_trackNumber = sqlite::Traits<unsigned int>::Load( stmt, 3 );
m_artist = sqlite::Traits<std::string>::Load( stmt, 4 );
m_albumId = sqlite::Traits<unsigned int>::Load( stmt, 5 );
m_albumId = sqlite::Traits<unsigned int>::Load( stmt, 4 );
}
AlbumTrack::AlbumTrack( const std::string& title, unsigned int trackNumber, unsigned int albumId )
......@@ -36,16 +36,25 @@ unsigned int AlbumTrack::id() const
bool AlbumTrack::createTable( DBConnection dbConnection )
{
const char* req = "CREATE TABLE IF NOT EXISTS AlbumTrack ("
static const std::string req = "CREATE TABLE IF NOT EXISTS " + policy::AlbumTrackTable::Name + "("
"id_track INTEGER PRIMARY KEY AUTOINCREMENT,"
"title TEXT,"
"genre TEXT,"
"track_number UNSIGNED INTEGER,"
"artist TEXT,"
"album_id UNSIGNED INTEGER NOT NULL,"
"FOREIGN KEY (album_id) REFERENCES Album(id_album) ON DELETE CASCADE"
")";
return sqlite::Tools::executeRequest( dbConnection, req );
static const std::string reqRel = "CREATE TABLE IF NOT EXISTS TrackArtistRelation("
"id_track INTEGER,"
"id_artist INTEGER,"
"PRIMARY KEY (id_track, id_artist),"
"FOREIGN KEY(id_track) REFERENCES " + policy::AlbumTrackTable::Name + "("
+ policy::AlbumTrackTable::CacheColumn + ") ON DELETE CASCADE,"
"FOREIGN KEY(id_artist) REFERENCES " + policy::ArtistTable::Name + "("
+ policy::ArtistTable::CacheColumn + ") ON DELETE CASCADE"
")";
return sqlite::Tools::executeRequest( dbConnection, req ) &&
sqlite::Tools::executeRequest( dbConnection, reqRel );
}
AlbumTrackPtr AlbumTrack::create(DBConnection dbConnection, unsigned int albumId, const std::string& name, unsigned int trackNb)
......@@ -108,19 +117,23 @@ bool AlbumTrack::destroy()
return _Cache::destroy( m_dbConnection, this );
}
const std::string&AlbumTrack::artist() const
bool AlbumTrack::addArtist( ArtistPtr artist )
{
return m_artist;
static const std::string req = "INSERT INTO TrackArtistRelation VALUES(?, ?)";
if ( m_id == 0 || artist->id() == 0 )
{
LOG_ERROR("Both artist * album need to be inserted in database before being linked together" );
return false;
}
return sqlite::Tools::executeRequest( m_dbConnection, req, m_id, artist->id() );
}
bool AlbumTrack::setArtist(const std::string& artist)
std::vector<ArtistPtr> AlbumTrack::artists() const
{
static const std::string req = "UPDATE " + policy::AlbumTrackTable::Name +
" SET artist = ? WHERE id_track = ?";
if ( sqlite::Tools::executeUpdate( m_dbConnection, req, artist, m_id ) == false )
return false;
m_artist = artist;
return true;
static const std::string req = "SELECT art.* FROM " + policy::ArtistTable::Name + " art "
"LEFT JOIN TrackArtistRelation tar ON tar.id_artist = art.id_artist "
"WHERE tar.id_track = ?";
return sqlite::Tools::fetchAll<Artist, IArtist>( m_dbConnection, req, m_id );
}
std::vector<FilePtr> AlbumTrack::files()
......
......@@ -36,8 +36,8 @@ class AlbumTrack : public IAlbumTrack, public Cache<AlbumTrack, IAlbumTrack, pol
virtual unsigned int trackNumber();
virtual std::shared_ptr<IAlbum> album();
virtual bool destroy();
virtual const std::string& artist() const;
virtual bool setArtist( const std::string& artist );
virtual bool addArtist( ArtistPtr artist ) override;
virtual std::vector<ArtistPtr> artists() const override;
virtual std::vector<FilePtr> files();
static bool createTable( DBConnection dbConnection );
......@@ -50,7 +50,6 @@ class AlbumTrack : public IAlbumTrack, public Cache<AlbumTrack, IAlbumTrack, pol
std::string m_title;
std::string m_genre;
unsigned int m_trackNumber;
std::string m_artist;
unsigned int m_albumId;
std::shared_ptr<Album> m_album;
......
#include "Artist.h"
#include "Album.h"
#include "AlbumTrack.h"
#include "database/SqliteTools.h"
......@@ -55,6 +56,14 @@ std::vector<AlbumPtr> Artist::albums() const
return sqlite::Tools::fetchAll<Album, IAlbum>( m_dbConnection, req, m_id );
}
std::vector<AlbumTrackPtr> Artist::tracks() const
{
static const std::string req = "SELECT tra.* FROM " + policy::AlbumTrackTable::Name + " tra "
"LEFT JOIN TrackArtistRelation tar ON tar.id_track = tra.id_track "
"WHERE tar.id_artist = ?";
return sqlite::Tools::fetchAll<AlbumTrack, IAlbumTrack>( m_dbConnection, req, m_id );
}
bool Artist::createTable( DBConnection dbConnection )
{
static const std::string req = "CREATE TABLE IF NOT EXISTS " +
......
......@@ -30,6 +30,7 @@ public:
virtual const std::string& shortBio() const override;
virtual bool setShortBio( const std::string& shortBio ) override;
virtual std::vector<AlbumPtr> albums() const override;
virtual std::vector<AlbumTrackPtr> tracks() const override;
static bool createTable( DBConnection dbConnection );
static ArtistPtr create( DBConnection dbConnection, const std::string& name );
......
......@@ -149,9 +149,22 @@ bool VLCMetadataService::parseAudioFile( FilePtr file, VLC::Media& media ) const
if ( genre.length() != 0 )
track->setGenre( genre );
auto artist = media.meta( libvlc_meta_Artist );
if ( artist.length() != 0 )
track->setArtist( artist );
auto artistName = media.meta( libvlc_meta_Artist );
if ( artistName.length() != 0 )
{
auto artist = m_ml->artist( artistName );
if ( artist == nullptr )
{
artist = m_ml->createArtist( artistName );
if ( artist == nullptr )
{
LOG_ERROR( "Failed to create new artist ", artistName );
// Consider this a minor failure and go on nevertheless
return true;
}
}
track->addArtist( artist );
}
return true;
}
......
......@@ -140,22 +140,6 @@ TEST_F( Albums, SetArtworkUrl )
ASSERT_EQ( a->artworkUrl(), a2->artworkUrl() );
}
TEST_F( Albums, SetArtist )
{
auto a = ml->createAlbum( "album" );
auto t = a->addTrack("track1", 1);
t->setArtist( "The undead otters" );
ASSERT_EQ( t->artist(), "The undead otters" );
Reload();
auto a2 = ml->album( "album" );
auto tracks = a2->tracks();
auto t2 = tracks[0];
ASSERT_EQ( t->artist(), t2->artist() );
}
TEST_F( Albums, FetchAlbumFromTrack )
{
{
......
......@@ -45,6 +45,7 @@ list(APPEND TEST_SRCS
VLCMetadataServices.cpp
FsUtilsTests.cpp
ArtistTests.cpp
AlbumTrackTests.cpp
mocks/FileSystem.h
)
......
......@@ -8,6 +8,7 @@
#include "IAudioTrack.h"
#include "IAlbum.h"
#include "IAlbumTrack.h"
#include "IArtist.h"
#include "IVideoTrack.h"
class ServiceCb : public IMediaLibraryCb
......@@ -85,7 +86,9 @@ TEST_F( VLCMetadataServices, ParseAlbum )
ASSERT_NE( track, nullptr );
ASSERT_EQ( track->title(), "Mr. Zebra" );
ASSERT_EQ( track->genre(), "Rock" );
ASSERT_EQ( track->artist(), "Tori Amos" );
auto artists = track->artists();
ASSERT_EQ( artists.size(), 2u );
ASSERT_EQ( artists[0]->name(), "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