Handle statistics tags apart, and write them to file when they change.
Next step: add a preference to activate this (should be deactivated by default IMO).
This commit is contained in:
parent
39e1275980
commit
08d40f5fca
|
@ -48,6 +48,11 @@ void TagReaderWorker::MessageArrived(const pb::tagreader::Message& message) {
|
|||
reply.mutable_save_file_response()->set_success(
|
||||
tag_reader_.SaveFile(QStringFromStdString(message.save_file_request().filename()),
|
||||
message.save_file_request().metadata()));
|
||||
} else if (message.has_save_song_statistics_to_file_request()) {
|
||||
reply.mutable_save_song_statistics_to_file_response()->set_success(
|
||||
tag_reader_.SaveSongStatisticsToFile(
|
||||
QStringFromStdString(message.save_song_statistics_to_file_request().filename()),
|
||||
message.save_song_statistics_to_file_request().metadata()));
|
||||
} else if (message.has_is_media_file_request()) {
|
||||
reply.mutable_is_media_file_response()->set_success(
|
||||
tag_reader_.IsMediaFile(QStringFromStdString(message.is_media_file_request().filename())));
|
||||
|
|
|
@ -428,8 +428,6 @@ bool TagReader::SaveFile(const QString& filename,
|
|||
SetTextFrame("TCOM", song.composer(), tag);
|
||||
SetTextFrame("TPE2", song.albumartist(), tag);
|
||||
SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag);
|
||||
SetUserTextFrame("FMPS_Rating", QString::number(song.rating()), tag);
|
||||
SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag);
|
||||
}
|
||||
else if (TagLib::Ogg::Vorbis::File* file = dynamic_cast<TagLib::Ogg::Vorbis::File*>(fileref->file())) {
|
||||
TagLib::Ogg::XiphComment* tag = file->tag();
|
||||
|
@ -474,10 +472,43 @@ bool TagReader::SaveFile(const QString& filename,
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool TagReader::SaveSongStatisticsToFile(const QString& filename,
|
||||
const pb::tagreader::SongMetadata& song) const {
|
||||
if (filename.isNull())
|
||||
return false;
|
||||
|
||||
qLog(Debug) << "Saving song statistics tags to" << filename;
|
||||
|
||||
scoped_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
|
||||
|
||||
if (!fileref || fileref->isNull()) // The file probably doesn't exist
|
||||
return false;
|
||||
|
||||
if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
|
||||
TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true);
|
||||
SetUserTextFrame("FMPS_Rating", QString::number(song.rating()), tag);
|
||||
SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag);
|
||||
} else {
|
||||
// Nothing to save: stop now
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ret = fileref->save();
|
||||
#ifdef Q_OS_LINUX
|
||||
if (ret) {
|
||||
// Linux: inotify doesn't seem to notice the change to the file unless we
|
||||
// change the timestamps as well. (this is what touch does)
|
||||
utimensat(0, QFile::encodeName(filename).constData(), NULL, 0);
|
||||
}
|
||||
#endif // Q_OS_LINUX
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TagReader::SetUserTextFrame(const QString& description, const QString& value,
|
||||
TagLib::ID3v2::Tag* tag) const {
|
||||
const QByteArray descr_utf8(description.toUtf8());
|
||||
const QByteArray value_utf8(value.toUtf8());
|
||||
qLog(Debug) << "Setting FMPSFrame:" << description << ", " << value;
|
||||
SetUserTextFrame(std::string(descr_utf8.constData(), descr_utf8.length()),
|
||||
std::string(value_utf8.constData(), value_utf8.length()),
|
||||
tag);
|
||||
|
|
|
@ -53,6 +53,10 @@ class TagReader {
|
|||
|
||||
void ReadFile(const QString& filename, pb::tagreader::SongMetadata* song) const;
|
||||
bool SaveFile(const QString& filename, const pb::tagreader::SongMetadata& song) const;
|
||||
// Returns false if something went wrong; returns true otherwise (might
|
||||
// returns true if the file exists but nothing has been written inside because
|
||||
// statistics tag format is not supported for this kind of file)
|
||||
bool SaveSongStatisticsToFile(const QString& filename, const pb::tagreader::SongMetadata& song) const;
|
||||
bool IsMediaFile(const QString& filename) const;
|
||||
QByteArray LoadEmbeddedArt(const QString& filename) const;
|
||||
|
||||
|
|
|
@ -96,6 +96,16 @@ message ReadCloudFileResponse {
|
|||
optional SongMetadata metadata = 1;
|
||||
}
|
||||
|
||||
|
||||
message SaveSongStatisticsToFileRequest {
|
||||
optional string filename = 1;
|
||||
optional SongMetadata metadata = 2;
|
||||
}
|
||||
|
||||
message SaveSongStatisticsToFileResponse {
|
||||
optional bool success = 1;
|
||||
}
|
||||
|
||||
message Message {
|
||||
optional int32 id = 1;
|
||||
|
||||
|
@ -113,4 +123,8 @@ message Message {
|
|||
|
||||
optional ReadCloudFileRequest read_cloud_file_request = 10;
|
||||
optional ReadCloudFileResponse read_cloud_file_response = 11;
|
||||
|
||||
optional SaveSongStatisticsToFileRequest save_song_statistics_to_file_request = 12;
|
||||
optional SaveSongStatisticsToFileResponse save_song_statistics_to_file_response = 13;
|
||||
|
||||
}
|
||||
|
|
|
@ -68,6 +68,24 @@ TagReaderReply* TagReaderClient::SaveFile(const QString& filename, const Song& m
|
|||
return worker_pool_->SendMessageWithReply(&message);
|
||||
}
|
||||
|
||||
TagReaderReply* TagReaderClient::UpdateSongStatistics(const Song& metadata) {
|
||||
pb::tagreader::Message message;
|
||||
pb::tagreader::SaveSongStatisticsToFileRequest* req =
|
||||
message.mutable_save_song_statistics_to_file_request();
|
||||
|
||||
req->set_filename(DataCommaSizeFromQString(metadata.url().toLocalFile()));
|
||||
metadata.ToProtobuf(req->mutable_metadata());
|
||||
|
||||
return worker_pool_->SendMessageWithReply(&message);
|
||||
}
|
||||
|
||||
void TagReaderClient::UpdateSongsStatistics(const SongList& songs) {
|
||||
for (const Song& song : songs) {
|
||||
TagReaderReply* reply = UpdateSongStatistics(song);
|
||||
connect(reply, SIGNAL(Finished(bool)), reply, SLOT(deleteLater()));
|
||||
}
|
||||
}
|
||||
|
||||
TagReaderReply* TagReaderClient::IsMediaFile(const QString& filename) {
|
||||
pb::tagreader::Message message;
|
||||
pb::tagreader::IsMediaFileRequest* req = message.mutable_is_media_file_request();
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
|
||||
ReplyType* ReadFile(const QString& filename);
|
||||
ReplyType* SaveFile(const QString& filename, const Song& metadata);
|
||||
ReplyType* UpdateSongStatistics(const Song& metadata);
|
||||
ReplyType* IsMediaFile(const QString& filename);
|
||||
ReplyType* LoadEmbeddedArt(const QString& filename);
|
||||
ReplyType* ReadCloudFile(const QUrl& download_url,
|
||||
|
@ -62,6 +63,9 @@ public:
|
|||
// TODO: Make this not a singleton
|
||||
static TagReaderClient* Instance() { return sInstance; }
|
||||
|
||||
public slots:
|
||||
void UpdateSongsStatistics(const SongList& songs);
|
||||
|
||||
private slots:
|
||||
void WorkerFailedToStart();
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "sqlrow.h"
|
||||
#include "core/database.h"
|
||||
#include "core/scopedtransaction.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "smartplaylists/search.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
@ -48,6 +49,8 @@ void LibraryBackend::Init(Database* db, const QString& songs_table,
|
|||
dirs_table_ = dirs_table;
|
||||
subdirs_table_ = subdirs_table;
|
||||
fts_table_ = fts_table;
|
||||
connect(this, SIGNAL(SongsStatisticsChanged(SongList)),
|
||||
TagReaderClient::Instance(), SLOT(UpdateSongsStatistics(SongList)));
|
||||
}
|
||||
|
||||
void LibraryBackend::LoadDirectoriesAsync() {
|
||||
|
|
Loading…
Reference in New Issue