Improve handling of song source

This commit is contained in:
Jonas Kvinge
2019-04-08 23:00:07 +02:00
parent 9be161d165
commit 77903a5ecd
13 changed files with 67 additions and 61 deletions

View File

@@ -32,6 +32,7 @@
#include "core/tagreaderclient.h" #include "core/tagreaderclient.h"
#include "core/thread.h" #include "core/thread.h"
#include "core/utilities.h" #include "core/utilities.h"
#include "core/song.h"
#include "collection.h" #include "collection.h"
#include "collectionwatcher.h" #include "collectionwatcher.h"
#include "collectionbackend.h" #include "collectionbackend.h"
@@ -51,7 +52,7 @@ SCollection::SCollection(Application *app, QObject *parent)
watcher_(nullptr), watcher_(nullptr),
watcher_thread_(nullptr) { watcher_thread_(nullptr) {
backend_ = new CollectionBackend; backend_ = new CollectionBackend();
backend()->moveToThread(app->database()->thread()); backend()->moveToThread(app->database()->thread());
backend_->Init(app->database(), kSongsTable, kDirsTable, kSubdirsTable, kFtsTable); backend_->Init(app->database(), kSongsTable, kDirsTable, kSubdirsTable, kFtsTable);
@@ -71,7 +72,7 @@ SCollection::~SCollection() {
void SCollection::Init() { void SCollection::Init() {
watcher_ = new CollectionWatcher; watcher_ = new CollectionWatcher(Song::Source_Collection);
watcher_thread_ = new Thread(this); watcher_thread_ = new Thread(this);
watcher_thread_->SetIoPriority(Utilities::IOPRIO_CLASS_IDLE); watcher_thread_->SetIoPriority(Utilities::IOPRIO_CLASS_IDLE);

View File

@@ -29,11 +29,11 @@
class SqlRow; class SqlRow;
CollectionPlaylistItem::CollectionPlaylistItem(const Song::Source &source) CollectionPlaylistItem::CollectionPlaylistItem() : PlaylistItem(Song::Source_Collection) {
: PlaylistItem(source) {} song_.set_source(Song::Source_Collection);
}
CollectionPlaylistItem::CollectionPlaylistItem(const Song &song) CollectionPlaylistItem::CollectionPlaylistItem(const Song &song) : PlaylistItem(Song::Source_Collection), song_(song) {
: PlaylistItem(Song::Source_Collection), song_(song) {
song_.set_source(Song::Source_Collection); song_.set_source(Song::Source_Collection);
} }
@@ -46,6 +46,7 @@ void CollectionPlaylistItem::Reload() {
bool CollectionPlaylistItem::InitFromQuery(const SqlRow &query) { bool CollectionPlaylistItem::InitFromQuery(const SqlRow &query) {
// Rows from the songs tables come first // Rows from the songs tables come first
song_.InitFromQuery(query, true); song_.InitFromQuery(query, true);
song_.set_source(Song::Source_Collection);
return song_.is_valid(); return song_.is_valid();
} }

View File

@@ -36,7 +36,7 @@ class SqlRow;
class CollectionPlaylistItem : public PlaylistItem { class CollectionPlaylistItem : public PlaylistItem {
public: public:
CollectionPlaylistItem(const Song::Source &source); CollectionPlaylistItem();
CollectionPlaylistItem(const Song &song); CollectionPlaylistItem(const Song &song);
bool InitFromQuery(const SqlRow &query); bool InitFromQuery(const SqlRow &query);
@@ -51,6 +51,7 @@ class CollectionPlaylistItem : public PlaylistItem {
protected: protected:
QVariant DatabaseValue(DatabaseColumn column) const; QVariant DatabaseValue(DatabaseColumn column) const;
Song DatabaseSongMetadata() const { return Song(Song::Source_Collection); }
protected: protected:
Song song_; Song song_;

View File

@@ -59,13 +59,14 @@
namespace { namespace {
static const char *kNoMediaFile = ".nomedia"; static const char *kNoMediaFile = ".nomedia";
static const char *kNoMusicFile = ".nomusic"; static const char *kNoMusicFile = ".nomusic";
} }
QStringList CollectionWatcher::sValidImages; QStringList CollectionWatcher::sValidImages;
CollectionWatcher::CollectionWatcher(QObject *parent) CollectionWatcher::CollectionWatcher(Song::Source source, QObject *parent)
: QObject(parent), : QObject(parent),
source_(source),
backend_(nullptr), backend_(nullptr),
task_manager_(nullptr), task_manager_(nullptr),
fs_watcher_(FileSystemWatcherInterface::Create(this)), fs_watcher_(FileSystemWatcherInterface::Create(this)),
@@ -387,7 +388,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory
QString image = ImageForSong(file, album_art); QString image = ImageForSong(file, album_art);
for (Song song : song_list) { for (Song song : song_list) {
song.set_source(Song::Source_Collection); song.set_source(source_);
song.set_directory_id(t->dir()); song.set_directory_id(t->dir());
if (song.art_automatic().isEmpty()) song.set_art_automatic(image); if (song.art_automatic().isEmpty()) song.set_art_automatic(image);
t->new_songs << song; t->new_songs << song;
@@ -441,7 +442,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, const QStr
// Update every song that's in the cue and collection // Update every song that's in the cue and collection
for (Song cue_song : cue_parser_->Load(&cue, matching_cue, path)) { for (Song cue_song : cue_parser_->Load(&cue, matching_cue, path)) {
cue_song.set_source(Song::Source_Collection); cue_song.set_source(source_);
cue_song.set_directory_id(t->dir()); cue_song.set_directory_id(t->dir());
Song matching = sections_map[cue_song.beginning_nanosec()]; Song matching = sections_map[cue_song.beginning_nanosec()];
@@ -477,7 +478,7 @@ void CollectionWatcher::UpdateNonCueAssociatedSong(const QString &file, const So
} }
Song song_on_disk; Song song_on_disk;
song_on_disk.set_source(Song::Source_Collection); song_on_disk.set_source(source_);
song_on_disk.set_directory_id(t->dir()); song_on_disk.set_directory_id(t->dir());
TagReaderClient::Instance()->ReadFileBlocking(file, &song_on_disk); TagReaderClient::Instance()->ReadFileBlocking(file, &song_on_disk);

View File

@@ -46,7 +46,7 @@ class CollectionWatcher : public QObject {
Q_OBJECT Q_OBJECT
public: public:
CollectionWatcher(QObject *parent = nullptr); CollectionWatcher(Song::Source source, QObject *parent = nullptr);
void set_backend(CollectionBackend *backend) { backend_ = backend; } void set_backend(CollectionBackend *backend) { backend_ = backend; }
void set_task_manager(TaskManager *task_manager) { task_manager_ = task_manager; } void set_task_manager(TaskManager *task_manager) { task_manager_ = task_manager; }
@@ -162,6 +162,7 @@ signals:
SongList ScanNewFile(const QString &file, const QString &path, const QString &matching_cue, QSet<QString> *cues_processed); SongList ScanNewFile(const QString &file, const QString &path, const QString &matching_cue, QSet<QString> *cues_processed);
private: private:
Song::Source source_;
CollectionBackend *backend_; CollectionBackend *backend_;
TaskManager *task_manager_; TaskManager *task_manager_;
QString device_name_; QString device_name_;

View File

@@ -148,7 +148,7 @@ const QRegExp Song::kTitleRemoveMisc(" ?-? ((\\(|\\[)?)(Remastered|Live|Remaster
struct Song::Private : public QSharedData { struct Song::Private : public QSharedData {
Private(); Private(Source source = Source_Unknown);
bool valid_; bool valid_;
int id_; int id_;
@@ -207,7 +207,7 @@ struct Song::Private : public QSharedData {
}; };
Song::Private::Private() Song::Private::Private(Song::Source source)
: valid_(false), : valid_(false),
id_(-1), id_(-1),
album_id_(-1), album_id_(-1),
@@ -223,7 +223,7 @@ Song::Private::Private()
samplerate_(-1), samplerate_(-1),
bitdepth_(-1), bitdepth_(-1),
source_(Source_Unknown), source_(source),
directory_id_(-1), directory_id_(-1),
filetype_(FileType_Unknown), filetype_(FileType_Unknown),
filesize_(-1), filesize_(-1),
@@ -244,10 +244,8 @@ Song::Private::Private()
{} {}
Song::Song() : d(new Private) {} Song::Song(Song::Source source) : d(new Private(source)) {}
Song::Song(const Song &other) : d(other.d) {} Song::Song(const Song &other) : d(other.d) {}
Song::~Song() {} Song::~Song() {}
Song &Song::operator=(const Song &other) { Song &Song::operator=(const Song &other) {
@@ -590,6 +588,8 @@ QString Song::Decode(const QString &tag, const QTextCodec *codec) {
void Song::InitFromProtobuf(const pb::tagreader::SongMetadata &pb) { void Song::InitFromProtobuf(const pb::tagreader::SongMetadata &pb) {
if (d->source_ == Source_Unknown) d->source_ = Source_LocalFile;
d->init_from_file_ = true; d->init_from_file_ = true;
d->valid_ = pb.valid(); d->valid_ = pb.valid();
d->title_ = QStringFromStdString(pb.title()); d->title_ = QStringFromStdString(pb.title());
@@ -611,7 +611,6 @@ void Song::InitFromProtobuf(const pb::tagreader::SongMetadata &pb) {
d->bitrate_ = pb.bitrate(); d->bitrate_ = pb.bitrate();
d->samplerate_ = pb.samplerate(); d->samplerate_ = pb.samplerate();
d->bitdepth_ = pb.bitdepth(); d->bitdepth_ = pb.bitdepth();
d->source_ = Source_LocalFile;
set_url(QUrl::fromEncoded(QByteArray(pb.url().data(), pb.url().size()))); set_url(QUrl::fromEncoded(QByteArray(pb.url().data(), pb.url().size())));
d->basefilename_ = QStringFromStdString(pb.basefilename()); d->basefilename_ = QStringFromStdString(pb.basefilename());
d->filetype_ = static_cast<FileType>(pb.filetype()); d->filetype_ = static_cast<FileType>(pb.filetype());
@@ -678,7 +677,6 @@ void Song::ToProtobuf(pb::tagreader::SongMetadata *pb) const {
void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) { void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
//qLog(Debug) << __PRETTY_FUNCTION__;
//qLog(Debug) << "Song::kColumns.size():" << Song::kColumns.size() << "q.columns_.size():" << q.columns_.size() << "col:" << col; //qLog(Debug) << "Song::kColumns.size():" << Song::kColumns.size() << "q.columns_.size():" << q.columns_.size() << "col:" << col;
int x = col; int x = col;
@@ -691,6 +689,7 @@ void Song::InitFromQuery(const SqlRow &q, bool reliable_metadata, int col) {
qLog(Error) << "Skipping" << Song::kColumns.value(i); qLog(Error) << "Skipping" << Song::kColumns.value(i);
break; break;
} }
//qLog(Debug) << "Index:" << i << x << Song::kColumns.value(i) << q.value(x).toString(); //qLog(Debug) << "Index:" << i << x << Song::kColumns.value(i) << q.value(x).toString();
if (Song::kColumns.value(i) == "title") { if (Song::kColumns.value(i) == "title") {

View File

@@ -66,33 +66,6 @@ class Song {
public: public:
Song();
Song(const Song &other);
~Song();
static const QStringList kColumns;
static const QString kColumnSpec;
static const QString kBindSpec;
static const QString kUpdateSpec;
static const QStringList kFtsColumns;
static const QString kFtsColumnSpec;
static const QString kFtsBindSpec;
static const QString kFtsUpdateSpec;
static const QString kManuallyUnsetCover;
static const QString kEmbeddedCover;
static const QRegExp kAlbumRemoveDisc;
static const QRegExp kAlbumRemoveMisc;
static const QRegExp kTitleRemoveMisc;
static const QRegExp kFilenameRemoveNonFatChars;
static QString JoinSpec(const QString &table);
// Don't change these values - they're stored in the database, and defined in the tag reader protobuf.
// If a new lossless file is added, also add it to IsFileLossless().
enum Source { enum Source {
Source_Unknown = 0, Source_Unknown = 0,
Source_LocalFile = 1, Source_LocalFile = 1,
@@ -103,6 +76,9 @@ class Song {
Source_Tidal = 6, Source_Tidal = 6,
}; };
// Don't change these values - they're stored in the database, and defined in the tag reader protobuf.
// If a new lossless file is added, also add it to IsFileLossless().
enum FileType { enum FileType {
FileType_Unknown = 0, FileType_Unknown = 0,
FileType_WAV = 1, FileType_WAV = 1,
@@ -126,6 +102,30 @@ class Song {
FileType_Stream = 91, FileType_Stream = 91,
}; };
Song(Song::Source source = Song::Source_Unknown);
Song(const Song &other);
~Song();
static const QStringList kColumns;
static const QString kColumnSpec;
static const QString kBindSpec;
static const QString kUpdateSpec;
static const QStringList kFtsColumns;
static const QString kFtsColumnSpec;
static const QString kFtsBindSpec;
static const QString kFtsUpdateSpec;
static const QString kManuallyUnsetCover;
static const QString kEmbeddedCover;
static const QRegExp kAlbumRemoveDisc;
static const QRegExp kAlbumRemoveMisc;
static const QRegExp kTitleRemoveMisc;
static const QRegExp kFilenameRemoveNonFatChars;
static QString JoinSpec(const QString &table);
static Source SourceFromURL(const QUrl &url); static Source SourceFromURL(const QUrl &url);
static QString TextForSource(Source source); static QString TextForSource(Source source);
static QIcon IconForSource(Source source); static QIcon IconForSource(Source source);

View File

@@ -213,7 +213,8 @@ SongLoader::Result SongLoader::LoadLocal(const QString &filename) {
if (song.is_valid()) { if (song.is_valid()) {
songs_ << song; songs_ << song;
} }
} while (query.Next()); }
while (query.Next());
return Success; return Success;
} }
@@ -337,7 +338,7 @@ void SongLoader::LoadLocalDirectory(const QString &filename) {
} }
void SongLoader::AddAsRawStream() { void SongLoader::AddAsRawStream() {
Song song; Song song(Song::Source_Stream);
song.set_valid(true); song.set_valid(true);
song.set_filetype(Song::FileType_Stream); song.set_filetype(Song::FileType_Stream);
song.set_url(url_); song.set_url(url_);

View File

@@ -27,6 +27,7 @@
#include "core/application.h" #include "core/application.h"
#include "core/logging.h" #include "core/logging.h"
#include "core/song.h"
#include "collection/collectionbackend.h" #include "collection/collectionbackend.h"
#include "collection/collectionmodel.h" #include "collection/collectionmodel.h"
@@ -38,8 +39,10 @@
class DeviceLister; class DeviceLister;
FilesystemDevice::FilesystemDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time) FilesystemDevice::FilesystemDevice(const QUrl &url, DeviceLister *lister, const QString &unique_id, DeviceManager *manager, Application *app, int database_id, bool first_time)
: FilesystemMusicStorage(url.toLocalFile()), ConnectedDevice(url, lister, unique_id, manager, app, database_id, first_time), watcher_(new CollectionWatcher), watcher_thread_(new QThread(this)) : FilesystemMusicStorage(url.toLocalFile()),
{ ConnectedDevice(url, lister, unique_id, manager, app, database_id, first_time),
watcher_(new CollectionWatcher(Song::Source_Device)), watcher_thread_(new QThread(this))
{
watcher_->moveToThread(watcher_thread_); watcher_->moveToThread(watcher_thread_);
watcher_thread_->start(QThread::IdlePriority); watcher_thread_->start(QThread::IdlePriority);

View File

@@ -245,12 +245,13 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, std::share
song_list = cue_parser.Load(&cue, cue_path, QDir(cue_path.section('/', 0, -2))); song_list = cue_parser.Load(&cue, cue_path, QDir(cue_path.section('/', 0, -2)));
state->cached_cues_[cue_path] = song_list; state->cached_cues_[cue_path] = song_list;
} else { }
else {
song_list = state->cached_cues_[cue_path]; song_list = state->cached_cues_[cue_path];
} }
} }
for (const Song& from_list : song_list) { for (const Song &from_list : song_list) {
if (from_list.url().toEncoded() == song.url().toEncoded() && from_list.beginning_nanosec() == song.beginning_nanosec()) { if (from_list.url().toEncoded() == song.url().toEncoded() && from_list.beginning_nanosec() == song.beginning_nanosec()) {
// we found a matching section; replace the input item with a new one containing CUE metadata // we found a matching section; replace the input item with a new one containing CUE metadata
return PlaylistItemPtr(new SongPlaylistItem(from_list)); return PlaylistItemPtr(new SongPlaylistItem(from_list));

View File

@@ -45,7 +45,7 @@ PlaylistItem::~PlaylistItem() {}
PlaylistItem *PlaylistItem::NewFromSource(const Song::Source &source) { PlaylistItem *PlaylistItem::NewFromSource(const Song::Source &source) {
switch (source) { switch (source) {
case Song::Source_Collection: return new CollectionPlaylistItem(source); case Song::Source_Collection: return new CollectionPlaylistItem();
case Song::Source_Tidal: case Song::Source_Tidal:
case Song::Source_Stream: return new InternetPlaylistItem(source); case Song::Source_Stream: return new InternetPlaylistItem(source);
default: return new SongPlaylistItem(source); default: return new SongPlaylistItem(source);
@@ -65,7 +65,7 @@ PlaylistItem *PlaylistItem::NewFromSongsTable(const QString &table, const Song &
void PlaylistItem::BindToQuery(QSqlQuery *query) const { void PlaylistItem::BindToQuery(QSqlQuery *query) const {
query->bindValue(":type", source()); query->bindValue(":type", source_);
query->bindValue(":collection_id", DatabaseValue(Column_CollectionId)); query->bindValue(":collection_id", DatabaseValue(Column_CollectionId));
DatabaseSongMetadata().BindToQuery(query); DatabaseSongMetadata().BindToQuery(query);

View File

@@ -30,9 +30,7 @@
#include "songplaylistitem.h" #include "songplaylistitem.h"
SongPlaylistItem::SongPlaylistItem(const Song::Source &source) : PlaylistItem(source) {} SongPlaylistItem::SongPlaylistItem(const Song::Source &source) : PlaylistItem(source) {}
SongPlaylistItem::SongPlaylistItem(const Song &song) : PlaylistItem(song.source()), song_(song) {}
SongPlaylistItem::SongPlaylistItem(const Song &song)
: PlaylistItem(Song::Source_LocalFile), song_(song) {}
bool SongPlaylistItem::InitFromQuery(const SqlRow &query) { bool SongPlaylistItem::InitFromQuery(const SqlRow &query) {
song_.InitFromQuery(query, false, (Song::kColumns.count()+1)); song_.InitFromQuery(query, false, (Song::kColumns.count()+1));

View File

@@ -76,8 +76,7 @@ void ParserBase::LoadSong(const QString &filename_or_url, qint64 beginning, cons
const QUrl url = QUrl::fromLocalFile(filename); const QUrl url = QUrl::fromLocalFile(filename);
// Search in the collection // Search in the collection
Song collection_song; Song collection_song(Song::Source_Collection);
collection_song.set_source(Song::Source_Collection);
if (collection_) { if (collection_) {
collection_song = collection_->GetSongByUrl(url, beginning); collection_song = collection_->GetSongByUrl(url, beginning);
} }