parent
f48d1a8017
commit
e1fbe9ae54
|
@ -1210,6 +1210,36 @@ Song CollectionBackend::GetSongByUrl(const QUrl &url, const qint64 beginning) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Song CollectionBackend::GetSongByUrlAndTrack(const QUrl &url, const int track) {
|
||||||
|
|
||||||
|
QMutexLocker l(db_->Mutex());
|
||||||
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
|
SqlQuery q(db);
|
||||||
|
q.prepare(QString("SELECT ROWID, %1 FROM %2 WHERE (url = :url1 OR url = :url2 OR url = :url3 OR url = :url4) AND track = :track AND unavailable = 0").arg(Song::kColumnSpec, songs_table_));
|
||||||
|
|
||||||
|
q.BindValue(":url1", url);
|
||||||
|
q.BindValue(":url2", url.toString());
|
||||||
|
q.BindValue(":url3", url.toString(QUrl::FullyEncoded));
|
||||||
|
q.BindValue(":url4", url.toEncoded());
|
||||||
|
q.BindValue(":track", track);
|
||||||
|
|
||||||
|
if (!q.Exec()) {
|
||||||
|
db_->ReportErrors(q);
|
||||||
|
return Song();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!q.next()) {
|
||||||
|
return Song();
|
||||||
|
}
|
||||||
|
|
||||||
|
Song song(source_);
|
||||||
|
song.InitFromQuery(q, true);
|
||||||
|
|
||||||
|
return song;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
SongList CollectionBackend::GetSongsByUrl(const QUrl &url, const bool unavailable) {
|
SongList CollectionBackend::GetSongsByUrl(const QUrl &url, const bool unavailable) {
|
||||||
|
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
|
|
|
@ -130,6 +130,7 @@ class CollectionBackendInterface : public QObject {
|
||||||
// Returns a section of a song with the given filename and beginning. If the section is not present in collection, returns invalid song.
|
// Returns a section of a song with the given filename and beginning. If the section is not present in collection, returns invalid song.
|
||||||
// Using default beginning value is suitable when searching for single-section songs.
|
// Using default beginning value is suitable when searching for single-section songs.
|
||||||
virtual Song GetSongByUrl(const QUrl &url, const qint64 beginning = 0) = 0;
|
virtual Song GetSongByUrl(const QUrl &url, const qint64 beginning = 0) = 0;
|
||||||
|
virtual Song GetSongByUrlAndTrack(const QUrl &url, const int track) = 0;
|
||||||
|
|
||||||
virtual void AddDirectory(const QString &path) = 0;
|
virtual void AddDirectory(const QString &path) = 0;
|
||||||
virtual void RemoveDirectory(const CollectionDirectory &dir) = 0;
|
virtual void RemoveDirectory(const CollectionDirectory &dir) = 0;
|
||||||
|
@ -203,6 +204,7 @@ class CollectionBackend : public CollectionBackendInterface {
|
||||||
|
|
||||||
SongList GetSongsByUrl(const QUrl &url, const bool unavailable = false) override;
|
SongList GetSongsByUrl(const QUrl &url, const bool unavailable = false) override;
|
||||||
Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) override;
|
Song GetSongByUrl(const QUrl &url, qint64 beginning = 0) override;
|
||||||
|
Song GetSongByUrlAndTrack(const QUrl &url, const int track) override;
|
||||||
|
|
||||||
void AddDirectory(const QString &path) override;
|
void AddDirectory(const QString &path) override;
|
||||||
void RemoveDirectory(const CollectionDirectory &dir) override;
|
void RemoveDirectory(const CollectionDirectory &dir) override;
|
||||||
|
|
|
@ -59,7 +59,7 @@ SongList AsxIniParser::Load(QIODevice *device, const QString &playlist_path, con
|
||||||
QString value = line.mid(equals + 1);
|
QString value = line.mid(equals + 1);
|
||||||
|
|
||||||
if (key.startsWith("ref")) {
|
if (key.startsWith("ref")) {
|
||||||
Song song = LoadSong(value, 0, dir, collection_search);
|
Song song = LoadSong(value, 0, 0, dir, collection_search);
|
||||||
if (song.is_valid()) {
|
if (song.is_valid()) {
|
||||||
ret << song;
|
ret << song;
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ Song ASXParser::ParseTrack(QXmlStreamReader *reader, const QDir &dir, const bool
|
||||||
}
|
}
|
||||||
|
|
||||||
return_song:
|
return_song:
|
||||||
Song song = LoadSong(ref, 0, dir, collection_search);
|
Song song = LoadSong(ref, 0, 0, dir, collection_search);
|
||||||
|
|
||||||
// Override metadata with what was in the playlist
|
// Override metadata with what was in the playlist
|
||||||
if (song.source() != Song::Source::Collection) {
|
if (song.source() != Song::Source::Collection) {
|
||||||
|
|
|
@ -246,7 +246,7 @@ SongList CueParser::Load(QIODevice *device, const QString &playlist_path, const
|
||||||
for (int i = 0; i < entries.length(); i++) {
|
for (int i = 0; i < entries.length(); i++) {
|
||||||
CueEntry entry = entries.at(i);
|
CueEntry entry = entries.at(i);
|
||||||
|
|
||||||
Song song = LoadSong(entry.file, IndexToMarker(entry.index), dir, collection_search);
|
Song song = LoadSong(entry.file, IndexToMarker(entry.index), 0, dir, collection_search);
|
||||||
|
|
||||||
// Cue song has mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
|
// Cue song has mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
|
||||||
if (cue_mtime.isValid()) {
|
if (cue_mtime.isValid()) {
|
||||||
|
|
|
@ -71,7 +71,7 @@ SongList M3UParser::Load(QIODevice *device, const QString &playlist_path, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!line.isEmpty()) {
|
else if (!line.isEmpty()) {
|
||||||
Song song = LoadSong(line, 0, dir, collection_search);
|
Song song = LoadSong(line, 0, 0, dir, collection_search);
|
||||||
if (!current_metadata.title.isEmpty()) {
|
if (!current_metadata.title.isEmpty()) {
|
||||||
song.set_title(current_metadata.title);
|
song.set_title(current_metadata.title);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
ParserBase::ParserBase(SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
ParserBase::ParserBase(SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
||||||
: QObject(parent), collection_backend_(collection_backend) {}
|
: QObject(parent), collection_backend_(collection_backend) {}
|
||||||
|
|
||||||
void ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning, const QDir &dir, Song *song, const bool collection_search) const {
|
void ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning, const int track, const QDir &dir, Song *song, const bool collection_search) const {
|
||||||
|
|
||||||
if (filename_or_url.isEmpty()) {
|
if (filename_or_url.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -81,7 +81,13 @@ void ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning
|
||||||
|
|
||||||
// Search in the collection
|
// Search in the collection
|
||||||
if (collection_backend_ && collection_search) {
|
if (collection_backend_ && collection_search) {
|
||||||
Song collection_song = collection_backend_->GetSongByUrl(url, beginning);
|
Song collection_song;
|
||||||
|
if (track > 0) {
|
||||||
|
collection_song = collection_backend_->GetSongByUrlAndTrack(url, track);
|
||||||
|
}
|
||||||
|
if (!collection_song.is_valid()) {
|
||||||
|
collection_song = collection_backend_->GetSongByUrl(url, beginning);
|
||||||
|
}
|
||||||
// If it was found in the collection then use it, otherwise load metadata from disk.
|
// If it was found in the collection then use it, otherwise load metadata from disk.
|
||||||
if (collection_song.is_valid()) {
|
if (collection_song.is_valid()) {
|
||||||
*song = collection_song;
|
*song = collection_song;
|
||||||
|
@ -89,14 +95,16 @@ void ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!song->has_cue()) {
|
||||||
TagReaderClient::Instance()->ReadFileBlocking(filename, song);
|
TagReaderClient::Instance()->ReadFileBlocking(filename, song);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Song ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning, const QDir &dir, const bool collection_search) const {
|
Song ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning, const int track, const QDir &dir, const bool collection_search) const {
|
||||||
|
|
||||||
Song song(Song::Source::LocalFile);
|
Song song(Song::Source::LocalFile);
|
||||||
LoadSong(filename_or_url, beginning, dir, &song, collection_search);
|
LoadSong(filename_or_url, beginning, track, dir, &song, collection_search);
|
||||||
|
|
||||||
return song;
|
return song;
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,8 @@ class ParserBase : public QObject {
|
||||||
// If it is a filename or a file:// URL then it is made absolute and canonical and set as a file:// url on the song.
|
// If it is a filename or a file:// URL then it is made absolute and canonical and set as a file:// url on the song.
|
||||||
// Also sets the song's metadata by searching in the Collection, or loading from the file as a fallback.
|
// Also sets the song's metadata by searching in the Collection, or loading from the file as a fallback.
|
||||||
// This function should always be used when loading a playlist.
|
// This function should always be used when loading a playlist.
|
||||||
Song LoadSong(const QString &filename_or_url, const qint64 beginning, const QDir &dir, const bool collection_search) const;
|
Song LoadSong(const QString &filename_or_url, const qint64 beginning, const int track, const QDir &dir, const bool collection_search) const;
|
||||||
void LoadSong(const QString &filename_or_url, const qint64 beginning, const QDir &dir, Song *song, const bool collection_search) const;
|
void LoadSong(const QString &filename_or_url, const qint64 beginning, const int track, const QDir &dir, Song *song, const bool collection_search) const;
|
||||||
|
|
||||||
// If the URL is a file:// URL then returns its path, absolute or relative to the directory depending on the path_type option.
|
// If the URL is a file:// URL then returns its path, absolute or relative to the directory depending on the path_type option.
|
||||||
// Otherwise, returns the URL as is. This function should always be used when saving a playlist.
|
// Otherwise, returns the URL as is. This function should always be used when saving a playlist.
|
||||||
|
|
|
@ -62,7 +62,7 @@ SongList PLSParser::Load(QIODevice *device, const QString &playlist_path, const
|
||||||
int n = re_match.captured(0).toInt();
|
int n = re_match.captured(0).toInt();
|
||||||
|
|
||||||
if (key.startsWith("file")) {
|
if (key.startsWith("file")) {
|
||||||
Song song = LoadSong(value, 0, dir, collection_search);
|
Song song = LoadSong(value, 0, 0, dir, collection_search);
|
||||||
|
|
||||||
// Use the title and length we've already loaded if any
|
// Use the title and length we've already loaded if any
|
||||||
if (!songs[n].title().isEmpty()) song.set_title(songs[n].title());
|
if (!songs[n].title().isEmpty()) song.set_title(songs[n].title());
|
||||||
|
|
|
@ -72,7 +72,7 @@ void WplParser::ParseSeq(const QDir &dir, QXmlStreamReader *reader, SongList *so
|
||||||
if (name == "media") {
|
if (name == "media") {
|
||||||
QString src = reader->attributes().value("src").toString();
|
QString src = reader->attributes().value("src").toString();
|
||||||
if (!src.isEmpty()) {
|
if (!src.isEmpty()) {
|
||||||
Song song = LoadSong(src, 0, dir, collection_search);
|
Song song = LoadSong(src, 0, 0, dir, collection_search);
|
||||||
if (song.is_valid()) {
|
if (song.is_valid()) {
|
||||||
songs->append(song);
|
songs->append(song);
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ Song XSPFParser::ParseTrack(QXmlStreamReader *reader, const QDir &dir, const boo
|
||||||
}
|
}
|
||||||
|
|
||||||
return_song:
|
return_song:
|
||||||
Song song = LoadSong(location, 0, dir, collection_search);
|
Song song = LoadSong(location, 0, track_num, dir, collection_search);
|
||||||
|
|
||||||
// Override metadata with what was in the playlist
|
// Override metadata with what was in the playlist
|
||||||
if (song.source() != Song::Source::Collection) {
|
if (song.source() != Song::Source::Collection) {
|
||||||
|
@ -169,10 +169,13 @@ void XSPFParser::Save(const SongList &songs, QIODevice *device, const QDir &dir,
|
||||||
if (song.length_nanosec() != -1) {
|
if (song.length_nanosec() != -1) {
|
||||||
writer.writeTextElement("duration", QString::number(song.length_nanosec() / kNsecPerMsec));
|
writer.writeTextElement("duration", QString::number(song.length_nanosec() / kNsecPerMsec));
|
||||||
}
|
}
|
||||||
if (song.track() > 0) {
|
}
|
||||||
|
|
||||||
|
if ((write_metadata || song.has_cue() || (song.is_stream() && !song.is_radio())) && song.track() > 0) {
|
||||||
writer.writeTextElement("trackNum", QString::number(song.track()));
|
writer.writeTextElement("trackNum", QString::number(song.track()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (write_metadata || (song.is_stream() && !song.is_radio())) {
|
||||||
const QUrl cover_url = song.art_manual().isEmpty() || !song.art_manual().isValid() ? song.art_automatic() : song.art_manual();
|
const QUrl cover_url = song.art_manual().isEmpty() || !song.art_manual().isValid() ? song.art_automatic() : song.art_manual();
|
||||||
// Ignore images that are in our resource bundle.
|
// Ignore images that are in our resource bundle.
|
||||||
if (!cover_url.isEmpty() && cover_url.isValid()) {
|
if (!cover_url.isEmpty() && cover_url.isValid()) {
|
||||||
|
|
Loading…
Reference in New Issue