More various cleanup, epsecially to some nasty Indexer.cpp stuff.

This commit is contained in:
casey 2016-05-05 00:20:22 -07:00
parent 95a1803ba0
commit a3a19aaf07
9 changed files with 157 additions and 174 deletions

View File

@ -62,7 +62,7 @@
#include <core/sdk/IMetadataReader.h>
#include <core/support/Common.h>
class TagReaderTaglib : public musik::core::Plugin::IMetadataReader {
class TagReaderTaglib : public musik::core::metadata::IMetadataReader {
public:
TagReaderTaglib();
virtual ~TagReaderTaglib();

View File

@ -50,32 +50,15 @@
#define DLLEXPORT
#endif
//////////////////////////////////////////
///\brief
///Class for fixing leaking TagLib::ID3v2::FrameFactory without changing TagLib code.
//////////////////////////////////////////
class TaglibBugFix : TagLib::ID3v2::FrameFactory{
public:
~TaglibBugFix(){
};
};
#ifdef WIN32
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){
if(ul_reason_for_call==DLL_PROCESS_DETACH){
TaglibBugFix *ff = (TaglibBugFix*)TagLib::ID3v2::FrameFactory::instance();
delete ff;
}
return TRUE;
}
#endif //WIN32
#endif
//TagReaderTaglib tagreader;
class TaglibPlugin : public musik::core::IPlugin
{
class TaglibPlugin : public musik::core::IPlugin {
void Destroy() { delete this; };
const char* Name(){
@ -92,12 +75,12 @@ class TaglibPlugin : public musik::core::IPlugin
};
extern "C"{
DLLEXPORT musik::core::Plugin::IMetadataReader* GetMetaDataReader(){
extern "C" {
DLLEXPORT musik::core::metadata::IMetadataReader* GetMetadataReader() {
return new TagReaderTaglib();
}
DLLEXPORT musik::core::IPlugin* GetPlugin(){
DLLEXPORT musik::core::IPlugin* GetPlugin() {
return new TaglibPlugin();
}
}

View File

@ -55,14 +55,13 @@ using namespace musik::core;
Indexer::Indexer()
: thread(NULL)
, progress(0)
, progress2(0)
, overallProgress(0)
, currentProgress(0)
, status(0)
, restart(false)
, nofFiles(0)
, filesIndexed(0)
, filesSaved(0)
{
, filesSaved(0) {
}
//////////////////////////////////////////
@ -90,13 +89,13 @@ std::string Indexer::GetStatus() {
std::string status;
switch(this->status) {
case 1: return boost::str(boost::format("Counting files: %1%")%this->nofFiles );
case 2: return boost::str(boost::format("Indexing: %.2f") % (this->progress*100)) + "%";
case 3: return boost::str(boost::format("Removing old files: %.2f") % (this->progress*100)) + "%";
case 2: return boost::str(boost::format("Indexing: %.2f") % (this->overallProgress*100)) + "%";
case 3: return boost::str(boost::format("Removing old files: %.2f") % (this->overallProgress*100)) + "%";
case 4: return "Cleaning up.";
case 5: return "Optimizing.";
case 6: return boost::str(boost::format("Analyzing: %.2f%% (current %.1f%%)")
% (100.0 * this->progress / (double) this->nofFiles)
% (this->progress2*100.0));
% (100.0 * this->overallProgress / (double) this->nofFiles)
% (this->currentProgress * 100.0));
}
return status;
@ -144,7 +143,7 @@ void Indexer::AddPath(std::string path) {
boost::filesystem::path fsPath(path);
path = fsPath.string(); /* canonicalize */
if (path.substr(path.size() -1 , 1) != "/") {
if (path.substr(path.size() -1, 1) != "/") {
path += "/";
}
@ -187,11 +186,11 @@ void Indexer::RemovePath(std::string path) {
//////////////////////////////////////////
void Indexer::Synchronize() {
/* load all of the metadata (tag) reader plugins */
typedef Plugin::IMetadataReader PluginType;
typedef metadata::IMetadataReader PluginType;
typedef PluginFactory::DestroyDeleter<PluginType> Deleter;
this->metadataReaders = PluginFactory::Instance()
.QueryInterface<PluginType, Deleter>("GetMetaDataReader");
.QueryInterface<PluginType, Deleter>("GetMetadataReader");
{
boost::mutex::scoped_lock lock(this->progressMutex);
@ -230,7 +229,7 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->status = 1;
this->progress = 0.0;
this->overallProgress = 0.0;
}
for(std::size_t i = 0; i < paths.size(); ++i){
@ -243,7 +242,7 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->status = 2;
this->progress = 0.0;
this->overallProgress = 0.0;
this->filesSaved = 0;
}
@ -257,7 +256,7 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->status = 3;
this->progress = 0.0;
this->overallProgress = 0.0;
}
if (!this->Restarted() && !this->Exited()) {
@ -268,7 +267,7 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress = 0.0;
this->overallProgress = 0.0;
this->status = 4;
}
@ -281,7 +280,7 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress = 0.0;
this->overallProgress = 0.0;
this->status = 5;
}
@ -362,7 +361,7 @@ void Indexer::SyncDirectory(
std::string leaf(path.leaf().string());
DBID dirId = 0;
/* get folder id */
/* get relative folder id */
{
db::CachedStatement stmt("SELECT id FROM folders WHERE name=? AND path_id=? AND parent_id=?", this->dbConnection);
@ -410,11 +409,11 @@ void Indexer::SyncDirectory(
else {
++this->filesIndexed;
/* update progress every so often... */
/* update overallProgress every so often... */
if (this->filesIndexed % 25 == 0) {
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress = (double) this->filesIndexed / (double)this->nofFiles;
this->overallProgress = (double) this->filesIndexed / (double)this->nofFiles;
}
musik::core::IndexerTrack track(0);
@ -451,7 +450,7 @@ void Indexer::SyncDirectory(
boost::thread::yield();
}
}
catch(...){
catch(...) {
}
}
@ -521,7 +520,8 @@ void Indexer::ThreadLoop(){
bool Indexer::Startup(std::string setLibraryPath) {
this->libraryPath = setLibraryPath;
// Create thumbnail cache directory
/* ensure image artwork directory exists */
boost::filesystem::path thumbPath(this->libraryPath + "thumbs/");
if (!boost::filesystem::exists(thumbPath)) {
@ -559,14 +559,16 @@ void Indexer::SyncDelete(const std::vector<DBID>& paths) {
db::Statement stmtSyncPath("SELECT p.path FROM paths p WHERE p.id=?", this->dbConnection);
{
// Remove non existing folders
db::Statement stmt("SELECT f.id,p.path||f.relative_path FROM folders f,paths p WHERE f.path_id=p.id AND p.id=?",this->dbConnection);
db::Statement stmt(
"SELECT f.id, p.path || f.relative_path "
"FROM folders f, paths p "
"WHERE f.path_id=p.id AND p.id=?", this->dbConnection);
db::Statement stmtRemove("DELETE FROM folders WHERE id=?",this->dbConnection);
for (std::size_t i = 0; i < paths.size(); ++i) {
stmt.BindInt(0, paths[i]);
// Get the syncpath
stmtSyncPath.BindInt(0, paths[i]);
stmtSyncPath.Step();
std::string syncPathString(stmtSyncPath.ColumnText(0));
@ -604,13 +606,10 @@ void Indexer::SyncDelete(const std::vector<DBID>& paths) {
}
}
boost::thread::yield(); /* so much yielding */
/* we deleted folders above. remove all tracks that were in those dirs*/
// Remove songs with no folder
this->dbConnection.Execute("DELETE FROM tracks WHERE folder_id NOT IN (SELECT id FROM folders)");
boost::thread::yield();
// Remove tracks
db::Statement stmtCount("SELECT count(*) FROM tracks", this->dbConnection);
DBID songs = 0, count = 0;
@ -620,10 +619,9 @@ void Indexer::SyncDelete(const std::vector<DBID>& paths) {
}
db::Statement stmt(
"SELECT t.id, p.path || f.relative_path || '/' || t.filename "\
"FROM tracks t, folders f, paths p " \
"WHERE t.folder_id=f.id AND f.path_id=p.id AND p.id=?",
this->dbConnection);
"SELECT t.id, p.path || f.relative_path || '/' || t.filename "
"FROM tracks t, folders f, paths p "
"WHERE t.folder_id=f.id AND f.path_id=p.id AND p.id=?", this->dbConnection);
db::Statement stmtRemove("DELETE FROM tracks WHERE id=?", this->dbConnection);
@ -641,7 +639,7 @@ void Indexer::SyncDelete(const std::vector<DBID>& paths) {
{
boost::mutex::scoped_lock lock(this->progressMutex);
if (songs > 0) {
this->progress = 0.2+0.8*(double)count/(double)(songs);
this->overallProgress = 0.2+0.8*(double)count/(double)(songs);
}
}
@ -797,11 +795,9 @@ void Indexer::SyncOptimize() {
{
db::ScopedTransaction transaction(this->dbConnection);
// Fix sort order on tracks
/************************************
The sort order of a track is by default in the following order
genre, artist, album, track number, path, filename
************************************/
/* the sort order of a track is by default in the following order
genre, artist, album, track number, path, filename */
db::Statement outer("SELECT t.id FROM tracks t " \
"LEFT OUTER JOIN artists ar ON ar.id=t.visual_artist_id " \
@ -813,7 +809,8 @@ void Indexer::SyncOptimize() {
db::Statement inner("UPDATE tracks SET sort_order1=? WHERE id=?",this->dbConnection);
count = 0;
while(outer.Step() == db::Row) {
while (outer.Step() == db::Row) {
inner.BindInt(0,count);
inner.BindInt(1, outer.ColumnInt(0));
inner.Step();
@ -839,7 +836,7 @@ void Indexer::ProcessAddRemoveQueue() {
while (!this->addRemoveQueue.empty()) {
AddRemoveContext context = this->addRemoveQueue.front();
if (context.add){
if (context.add) { /* insert new paths */
db::Statement stmt("SELECT id FROM paths WHERE path=?", this->dbConnection);
stmt.BindText(0, context.path);
@ -849,7 +846,7 @@ void Indexer::ProcessAddRemoveQueue() {
insertPath.Step();
}
}
else {
else { /* remove old ones */
db::Statement stmt("DELETE FROM paths WHERE path=?", this->dbConnection);
stmt.BindText(0, context.path);
stmt.Step();
@ -864,123 +861,133 @@ void Indexer::ProcessAddRemoveQueue() {
}
void Indexer::RunAnalyzers(){
void Indexer::RunAnalyzers() {
typedef audio::IAnalyzer PluginType;
typedef PluginFactory::DestroyDeleter<PluginType> Deleter;
typedef boost::shared_ptr<PluginType> PluginPtr;
typedef std::vector<PluginPtr> PluginVector;
// start by checking if there are any analyzers at all
{
PluginVector analyzers =
PluginFactory::Instance().QueryInterface<PluginType, Deleter>("GetAudioAnalyzer");
if(analyzers.empty()){
/* short circuit if there aren't any analyzers */
PluginVector analyzers = PluginFactory::Instance()
.QueryInterface<PluginType, Deleter>("GetAudioAnalyzer");
if (analyzers.empty()) {
return;
}
}
/* initialize status */
{
// Cleanup status
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress = 0;
this->progress2 = 0;
this->overallProgress = 0;
this->currentProgress = 0;
this->nofFiles = 0;
this->status = 6;
}
// Get the number of tracks to be able to show percentage status.
db::Statement totalTracks("SELECT count(*) FROM tracks",this->dbConnection);
if(totalTracks.Step()==db::Row){
/* figure out how many files we need to process */
db::Statement totalTracks("SELECT count(*) FROM tracks", this->dbConnection);
if (totalTracks.Step() == db::Row){
this->nofFiles = totalTracks.ColumnInt(0);
}
// Loop through all tracks
DBID trackId(0);
DBID folderId(0);
db::Statement getNextTrack("SELECT id,folder_id FROM tracks WHERE id>? ORDER BY id LIMIT 1",this->dbConnection);
getNextTrack.BindInt(0,trackId);
/* for each track... */
while( getNextTrack.Step()==db::Row ){
DBID trackId = 0;
DBID folderId = 0;
db::Statement getNextTrack(
"SELECT id, folder_id FROM tracks WHERE id>? ORDER BY id LIMIT 1",
this->dbConnection);
getNextTrack.BindInt(0, trackId);
while(getNextTrack.Step() == db::Row ) {
trackId = getNextTrack.ColumnInt(0);
folderId = getNextTrack.ColumnInt(1);
getNextTrack.Reset();
getNextTrack.UnBindAll();
boost::thread::yield();
IndexerTrack track(trackId);
if (track.Reload(this->dbConnection)) {
// lets see if we should analyze the track
PluginVector analyzers =
PluginFactory::Instance().QueryInterface<PluginType, Deleter>("GetAudioAnalyzer");
PluginVector runningAnalyzers;
// lets see what plugins that need to analyze the track audio
for(PluginVector::iterator plugin=analyzers.begin();plugin!=analyzers.end();){
if( (*plugin)->Start(&track) ){
++plugin;
}else{
plugin = analyzers.erase(plugin);
PluginVector::iterator plugin = analyzers.begin();
for ( ; plugin != analyzers.end(); ++plugin) {
if ((*plugin)->Start(&track)) {
runningAnalyzers.push_back(*plugin);
}
}
PluginVector runningAnalyzers(analyzers);
if(!runningAnalyzers.empty()){
// lets start a stream
if(!runningAnalyzers.empty()) {
audio::StreamPtr stream = audio::Stream::Create(audio::Stream::NoDSP);
if(stream){
if(stream->OpenStream(track.URL())){
// loop through the stream buffers, sending the buffers to the analyzers
if (stream) {
if (stream->OpenStream(track.URL())) {
/* decode the stream quickly, passing to all analyzers*/
audio::BufferPtr buffer;
while((buffer=stream->GetNextProcessedOutputBuffer()) && !runningAnalyzers.empty()){
while ((buffer = stream->GetNextProcessedOutputBuffer()) && !runningAnalyzers.empty()) {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress2 = stream->DecoderProgress();
this->currentProgress = stream->DecoderProgress();
}
PluginVector::iterator plugin=runningAnalyzers.begin();
while(plugin!=runningAnalyzers.end()){
// analyze the audio, and remove plugin if it returns false
if( (*plugin)->Analyze(&track,buffer.get()) ){
PluginVector::iterator plugin = runningAnalyzers.begin();
while(plugin != runningAnalyzers.end()) {
if ((*plugin)->Analyze(&track, buffer.get())) {
++plugin;
}else{
}
else {
/* TODO: dangerous? should we be removing elements from
this vector as we're iterating over it? */
plugin = runningAnalyzers.erase(plugin);
}
boost::thread::yield();
if(this->Exited() || this->Restarted()){
return;
}
}
}
// everything is analyzed, lets send the End
int successPlugins(0);
for(PluginVector::iterator plugin=analyzers.begin();plugin!=analyzers.end();++plugin){
/* done with track decoding and analysis, let the plugins know */
int successPlugins = 0;
PluginVector::iterator plugin = analyzers.begin();
for( ; plugin != analyzers.end(); ++plugin){
if((*plugin)->End(&track)){
successPlugins++;
}
}
// finally save the track
if(successPlugins>0){
track.Save(this->dbConnection,this->libraryPath,folderId);
}
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress2 = 0;
}
}
}
/* the analyzers can write metadata back to the DB, so if any of them
completed successfully, then save the track. */
if(successPlugins>0) {
track.Save(this->dbConnection, this->libraryPath,folderId);
}
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->currentProgress = 0;
}
}
}
}
}
if(this->Exited() || this->Restarted()){
return;
}
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->progress++;
this->overallProgress++;
}
getNextTrack.BindInt(0,trackId);
getNextTrack.BindInt(0, trackId);
}
}

View File

@ -36,8 +36,6 @@
#pragma once
//#include <core/config.h>
#include <core/support/ThreadHelper.h>
#include <core/db/Connection.h>
#include <core/sdk/IMetadataReader.h>
@ -45,18 +43,12 @@
#include <sigslot/sigslot.h>
#include <boost/thread/thread.hpp>
//#include <boost/thread/condition.hpp>
//#include <boost/thread/mutex.hpp>
#include <deque>
#include <vector>
//////////////////////////////////////////////////////////////////////////////
namespace musik { namespace core {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////
///\brief
///The Indexer is the class that syncronizes musik tracks with the database
@ -99,8 +91,8 @@ namespace musik { namespace core {
boost::thread *thread;
boost::mutex progressMutex;
double progress;
double progress2;
double overallProgress;
double currentProgress;
int nofFiles;
int filesIndexed;
int filesSaved;
@ -121,7 +113,7 @@ namespace musik { namespace core {
std::string path;
};
typedef std::vector<boost::shared_ptr<Plugin::IMetadataReader> > MetadataReaderList;
typedef std::vector<boost::shared_ptr<metadata::IMetadataReader> > MetadataReaderList;
std::deque<AddRemoveContext> addRemoveQueue;
@ -130,8 +122,4 @@ namespace musik { namespace core {
typedef boost::shared_ptr<Indexer> IndexerPtr;
//////////////////////////////////////////////////////////////////////////////
} } // musik::core
//////////////////////////////////////////////////////////////////////////////
} }

View File

@ -39,14 +39,16 @@
using namespace musik::core;
MetadataValue::MetadataValue(void){
}
MetadataValue::MetadataValue(const DBID newId,const char *value):id(newId){
if(value){
MetadataValue::MetadataValue(const DBID newId, const char *value)
: id(newId)
{
if(value) {
this->value = value;
}
}
MetadataValue::~MetadataValue(void){
MetadataValue::MetadataValue() {
}
MetadataValue::~MetadataValue() {
}

View File

@ -44,6 +44,7 @@
#include <vector>
namespace musik { namespace core {
class MetadataValue{
public:
MetadataValue(void);
@ -52,7 +53,6 @@ namespace musik { namespace core {
DBID id;
std::string value;
};
typedef boost::shared_ptr<MetadataValue> MetadataValuePtr;

View File

@ -73,7 +73,7 @@ IndexerTrack::~IndexerTrack() {
std::string IndexerTrack::GetValue(const char* metakey) {
if (metakey && this->internalMetadata) {
MetadataMap::iterator metavalue = this->internalMetadata->metadata.find(metakey);
if(metavalue != this->internalMetadata->metadata.end()) {
if (metavalue != this->internalMetadata->metadata.end()) {
return metavalue->second;
}
}
@ -83,7 +83,8 @@ std::string IndexerTrack::GetValue(const char* metakey) {
void IndexerTrack::SetValue(const char* metakey, const char* value) {
if (metakey && value) {
this->internalMetadata->metadata.insert(std::pair<std::string, std::string>(metakey,value));
this->internalMetadata->metadata.insert(
std::pair<std::string, std::string>(metakey,value));
}
}
@ -122,7 +123,9 @@ Track::MetadataIteratorRange IndexerTrack::GetValues(const char* metakey) {
Track::MetadataIteratorRange IndexerTrack::GetAllValues() {
if (this->internalMetadata) {
return Track::MetadataIteratorRange(this->internalMetadata->metadata.begin(), this->internalMetadata->metadata.end());
return Track::MetadataIteratorRange(
this->internalMetadata->metadata.begin(),
this->internalMetadata->metadata.end());
}
return Track::MetadataIteratorRange();
@ -305,13 +308,13 @@ void IndexerTrack::ProcessNonStandardMetadata(db::Connection& connection) {
selectMetaKey.BindText(0, it->first);
if (selectMetaKey.Step()==db::Row) {
if (selectMetaKey.Step() == db::Row) {
keyId = selectMetaKey.ColumnInt(0);
}
else {
insertMetaKey.BindText(0, it->first);
if (insertMetaKey.Step()==db::Done) {
if (insertMetaKey.Step() == db::Done) {
keyId = connection.LastInsertedId();
}
}

View File

@ -77,13 +77,13 @@ void NonLibraryTrackHelper::ReadTrack(musik::core::TrackPtr track) {
}
void NonLibraryTrackHelper::ThreadLoop() {
/* load all IMetadataReaer plugins */
typedef Plugin::IMetadataReader PluginType;
/* load all IMetadataReader plugins */
typedef metadata::IMetadataReader PluginType;
typedef PluginFactory::DestroyDeleter<PluginType> Deleter;
typedef std::vector<boost::shared_ptr<Plugin::IMetadataReader>> MetadataReaderList;
typedef std::vector<boost::shared_ptr<metadata::IMetadataReader>> MetadataReaderList;
MetadataReaderList metadataReaders = PluginFactory::Instance()
.QueryInterface<PluginType, Deleter>("GetMetaDataReader");
MetadataReaderList metadataReaders =
PluginFactory::Instance() .QueryInterface<PluginType, Deleter>("GetMetadataReader");
bool moreTracks = true;

View File

@ -39,7 +39,7 @@
#include "config.h"
#include "ITrack.h"
namespace musik { namespace core { namespace Plugin {
namespace musik { namespace core { namespace metadata {
class IMetadataReader {
public: