Add code to add track to DB and remove old ones that are gone. Added fingerprint lib to link for id-ing tracks. Make sure DB is logical after these changes. Change music path due to complaints I don't quite understand.
This commit is contained in:
@@ -9,6 +9,6 @@ find_package(Wt REQUIRED)
|
||||
find_package(Groove REQUIRED)
|
||||
|
||||
add_executable(arbitrateor src/main.cpp src/WebInterface.cpp src/GroovePlayer.cpp src/ui/LoginInterface.cpp src/ui/PlayerInterface.cpp)
|
||||
target_link_libraries(arbitrateor ${Wt_LIBRARIES} ${GROOVE_LIBRARY} pthread stdc++fs) #TODO get threading links based on platform. Remove gcc experimental fs when official c++17 exists.
|
||||
target_link_libraries(arbitrateor ${Wt_LIBRARIES} ${GROOVE_LIBRARY} ${GROOVE_FINGERPRINT_LIBRARY} pthread stdc++fs) #TODO get threading links based on platform. Remove gcc experimental fs when official c++17 exists.
|
||||
|
||||
install(TARGETS arbitrateor RUNTIME DESTINATION bin)
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
# GROOVE_FOUND
|
||||
# GROOVE_INCLUDE_DIR
|
||||
# GROOVE_LIBRARY
|
||||
# GROOVE_FINGERPRINT_LIBRARY
|
||||
|
||||
find_path(GROOVE_INCLUDE_DIR NAMES groove/groove.h)
|
||||
|
||||
find_library(GROOVE_LIBRARY NAMES groove)
|
||||
find_library(GROOVE_FINGERPRINT_LIBRARY NAMES groovefingerprinter)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GROOVE DEFAULT_MSG GROOVE_LIBRARY GROOVE_INCLUDE_DIR)
|
||||
find_package_handle_standard_args(GROOVE DEFAULT_MSG GROOVE_LIBRARY GROOVE_FINGERPRINT_LIBRARY GROOVE_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(GROOVE_INCLUDE_DIR GROOVE_LIBRARY)
|
||||
mark_as_advanced(GROOVE_INCLUDE_DIR GROOVE_LIBRARY GROOVE_FINGERPRINT_LIBRARY)
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "WebInterface.h"
|
||||
#include <locale>
|
||||
#include <Wt/WLogger>
|
||||
#include <Wt/Dbo/Transaction>
|
||||
#include <groovefingerprinter/fingerprinter.h>
|
||||
|
||||
std::filesystem::path GroovePlayer::musicScanDir = "";
|
||||
|
||||
@@ -42,6 +44,8 @@ GroovePlayer::GroovePlayer(std::string dbFile) : sqliteConnection(dbFile)
|
||||
Wt::log("info") << "Using Existing DB.";
|
||||
}
|
||||
|
||||
groove_init();
|
||||
|
||||
grooveAudioScanner = new std::thread(grooveAudioScannerLoop);
|
||||
grooveEvents = new std::thread(grooveEventLoop);
|
||||
}
|
||||
@@ -59,11 +63,85 @@ void GroovePlayer::grooveEventLoop()
|
||||
bool GroovePlayer::addFileToTrackDBIfTagged(std::filesystem::path file)
|
||||
{
|
||||
//Now check if tags exist and put into DB.
|
||||
struct GrooveFile* gfile = groove_file_open(file.c_str());
|
||||
struct GrooveTag* artist_tag = groove_file_metadata_get(gfile, "artist", nullptr, 0);
|
||||
struct GrooveTag* album_tag = groove_file_metadata_get(gfile, "album", nullptr, 0);
|
||||
struct GrooveTag* name_tag = groove_file_metadata_get(gfile, "title", nullptr, 0);
|
||||
struct GrooveTag* genre_tag = groove_file_metadata_get(gfile, "genre", nullptr, 0);
|
||||
if(artist_tag == nullptr || album_tag == nullptr || name_tag == nullptr || genre_tag == nullptr)
|
||||
{
|
||||
//Only accept song with all metadata for DB.
|
||||
groove_file_close(gfile);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Take fingerprint and compare to DB.
|
||||
struct GrooveFingerprinter* fingerprinter = groove_fingerprinter_create();
|
||||
struct GrooveFingerprinterInfo info;
|
||||
struct GroovePlaylist* playlist = groove_playlist_create();
|
||||
groove_playlist_insert(playlist,gfile,1.0,1.0,nullptr);
|
||||
groove_fingerprinter_attach(fingerprinter, playlist);
|
||||
groove_fingerprinter_info_get(fingerprinter, &info, 1);
|
||||
double trackLen = info.duration;
|
||||
char* encodedFP;
|
||||
groove_fingerprinter_encode(info.fingerprint,info.fingerprint_size,&encodedFP);
|
||||
std::string fingerprint = std::string(encodedFP);
|
||||
groove_fingerprinter_dealloc(encodedFP);
|
||||
groove_fingerprinter_free_info(&info);
|
||||
groove_fingerprinter_detach(fingerprinter);
|
||||
groove_fingerprinter_destroy(fingerprinter);
|
||||
groove_playlist_destroy(playlist);
|
||||
|
||||
Wt::Dbo::Transaction transaction(getInstance()->sqlSession);
|
||||
int existing = getInstance()->sqlSession.query<int>("select count(fingerprint) from tracks").where("fingerprint = ?").bind(fingerprint);
|
||||
if(existing >0)
|
||||
{
|
||||
//This track has a duplicate already.
|
||||
groove_file_close(gfile);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Add to DB.
|
||||
AudioTrack* newTrack = new AudioTrack();
|
||||
newTrack->trackName = groove_tag_value(name_tag);
|
||||
newTrack->trackAlbumName = groove_tag_value(album_tag);
|
||||
newTrack->trackArtistName = groove_tag_value(artist_tag);
|
||||
newTrack->trackGenre = groove_tag_value(genre_tag);
|
||||
newTrack->trackLengthSeconds = trackLen;
|
||||
newTrack->trackFingerprint = fingerprint;
|
||||
newTrack->trackPath = file.string();
|
||||
getInstance()->sqlSession.add(newTrack);
|
||||
groove_file_close(gfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GroovePlayer::removeOrphanedTracks()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(getInstance()->sqlSession);
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<AudioTrack>> tracks = getInstance()->sqlSession.find<AudioTrack>();
|
||||
for(Wt::Dbo::collection<Wt::Dbo::ptr<AudioTrack>>::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
|
||||
{
|
||||
if(!std::filesystem::exists(std::filesystem::path((*i)->trackPath)))
|
||||
{
|
||||
Wt::Dbo::ptr<AudioTrack> item = getInstance()->sqlSession.find<AudioTrack>().where("fingerprint = ?").bind((*i)->trackFingerprint);
|
||||
Wt::log("info") << (*i)->trackPath + " not found in filesystem. Removed from DB.";
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GroovePlayer::grooveAudioScannerLoop()
|
||||
{
|
||||
if(!std::filesystem::exists(musicScanDir))
|
||||
{
|
||||
std::filesystem::create_directory(musicScanDir);
|
||||
Wt::log("info") << "Directory "+std::filesystem::canonical(musicScanDir).string()+" didn't exist, so created.";
|
||||
} else
|
||||
{
|
||||
Wt::log("info") << "Directory "+std::filesystem::canonical(musicScanDir).string()+" exists.";
|
||||
}
|
||||
for(std::filesystem::directory_entry p: std::filesystem::directory_iterator(musicScanDir))
|
||||
{
|
||||
std::string extensionLowered;
|
||||
@@ -71,14 +149,20 @@ void GroovePlayer::grooveAudioScannerLoop()
|
||||
{
|
||||
extensionLowered.push_back(std::tolower(elem));
|
||||
}
|
||||
if(extensionLowered == "mp3") //TODO:think about supporting more than mp3s.
|
||||
if(extensionLowered == ".mp3") //TODO:think about supporting more than mp3s.
|
||||
{
|
||||
if(addFileToTrackDBIfTagged(p.path()))
|
||||
{
|
||||
Wt::log("info") << p.path().string() << " was added to DB";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Wt::log("info") << p.path().string() + " was not an accepted audio file.";
|
||||
}
|
||||
}
|
||||
//Now check for tracks in DB without a file.
|
||||
removeOrphanedTracks();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <thread>
|
||||
#include "db/User.h"
|
||||
#include "db/AudioTrack.h"
|
||||
#include <groove/groove.h>
|
||||
#include <experimental/filesystem> //TODO:Change to non-gcc way when officially using c++17
|
||||
namespace std {
|
||||
namespace filesystem = experimental::filesystem;
|
||||
@@ -37,7 +38,7 @@ public:
|
||||
static std::filesystem::path musicScanDir;
|
||||
static GroovePlayer* getInstance() {
|
||||
static GroovePlayer instance("music.db");
|
||||
musicScanDir = std::filesystem::current_path().string()+"/music";
|
||||
musicScanDir = std::filesystem::path("music");
|
||||
return &instance;
|
||||
};
|
||||
GroovePlayer(GroovePlayer const&) = delete;
|
||||
@@ -54,6 +55,7 @@ private:
|
||||
std::thread* grooveAudioScanner;
|
||||
static void grooveAudioScannerLoop();
|
||||
static bool addFileToTrackDBIfTagged(std::filesystem::path file);
|
||||
static void removeOrphanedTracks();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ public:
|
||||
std::string trackArtistName;
|
||||
std::string trackAlbumName;
|
||||
std::string trackGenre;
|
||||
double trackLengthSeconds;
|
||||
std::string trackFingerprint;
|
||||
std::string trackPath;
|
||||
|
||||
template<class Action>
|
||||
@@ -37,6 +39,8 @@ public:
|
||||
Wt::Dbo::field(a, trackName, "name");
|
||||
Wt::Dbo::field(a, trackArtistName, "artist");
|
||||
Wt::Dbo::field(a, trackAlbumName, "album");
|
||||
Wt::Dbo::field(a, trackLengthSeconds, "length");
|
||||
Wt::Dbo::field(a, trackFingerprint, "fingerprint");
|
||||
Wt::Dbo::field(a, trackGenre, "genre");
|
||||
Wt::Dbo::field(a, trackPath, "path");
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public:
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::belongsTo(a, user, "user");
|
||||
Wt::Dbo::belongsTo(a, user, "user", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::field(a, action, "action");
|
||||
Wt::Dbo::belongsTo(a, trackInvolved, "track");
|
||||
Wt::Dbo::belongsTo(a, trackInvolved, "track", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::field(a, datetime, "datetime");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user