diff --git a/data/data.qrc b/data/data.qrc
index 30110af24..686bd8a31 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -312,5 +312,6 @@
icons/48x48/mail-message.png
schema/schema-29.sql
schema/schema-30.sql
+ schema/schema-31.sql
diff --git a/data/schema/schema-31.sql b/data/schema/schema-31.sql
new file mode 100644
index 000000000..fd1d9051e
--- /dev/null
+++ b/data/schema/schema-31.sql
@@ -0,0 +1,3 @@
+UPDATE songs SET filename = "file://" || filename;
+
+UPDATE schema_version SET version=31;
diff --git a/scripts/digitallyimported-radio/servicebase.py b/scripts/digitallyimported-radio/servicebase.py
index 246ade687..9279ef43b 100644
--- a/scripts/digitallyimported-radio/servicebase.py
+++ b/scripts/digitallyimported-radio/servicebase.py
@@ -125,7 +125,7 @@ class DigitallyImportedServiceBase(clementine.RadioService):
song = clementine.Song()
song.set_title(stream["name"])
song.set_artist(self.SERVICE_DESCRIPTION)
- song.set_filename("digitallyimported://%s" % stream["key"])
+ song.set_url(QUrl("digitallyimported://%s" % stream["key"]))
item = QStandardItem(QIcon(":last.fm/icon_radio.png"), stream["name"])
item.setData(stream["description"], PyQt4.QtCore.Qt.ToolTipRole)
@@ -192,6 +192,6 @@ class DigitallyImportedServiceBase(clementine.RadioService):
# Take the first track in the playlist
result.type_ = clementine.PlaylistItem.SpecialLoadResult.TrackAvailable
- result.media_url_ = QUrl(songs[0].filename())
+ result.media_url_ = songs[0].url()
self.AsyncLoadFinished.emit(result)
diff --git a/src/core/database.cpp b/src/core/database.cpp
index e9e3ab62c..b89b99185 100644
--- a/src/core/database.cpp
+++ b/src/core/database.cpp
@@ -32,7 +32,7 @@
#include
const char* Database::kDatabaseFilename = "clementine.db";
-const int Database::kSchemaVersion = 30;
+const int Database::kSchemaVersion = 31;
const char* Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;
diff --git a/src/core/deletefiles.cpp b/src/core/deletefiles.cpp
index d915014a2..6ff03e595 100644
--- a/src/core/deletefiles.cpp
+++ b/src/core/deletefiles.cpp
@@ -60,7 +60,7 @@ void DeleteFiles::Start(const QStringList& filenames) {
SongList songs;
foreach (const QString& filename, filenames) {
Song song;
- song.set_filename(filename);
+ song.set_url(QUrl::fromLocalFile(filename));
songs << song;
}
diff --git a/src/core/filesystemmusicstorage.cpp b/src/core/filesystemmusicstorage.cpp
index ba7405495..cb04f089a 100644
--- a/src/core/filesystemmusicstorage.cpp
+++ b/src/core/filesystemmusicstorage.cpp
@@ -66,14 +66,14 @@ bool FilesystemMusicStorage::CopyToStorage(const CopyJob& job) {
bool FilesystemMusicStorage::DeleteFromStorage(const DeleteJob& job) {
#ifdef HAVE_GIO
//convert QString to char
- QByteArray ba = job.metadata_.filename().toLocal8Bit();
+ QByteArray ba = job.metadata_.url().toLocalFile().toLocal8Bit();
const char *filepathChar = ba.data();
GFile *file = g_file_new_for_path (filepathChar);
bool success = g_file_trash(file, NULL, NULL);
g_object_unref(file);
return success;
#else
- return QFile::remove(job.metadata_.filename());
+ return QFile::remove(job.metadata_.url().toLocalFile());
#endif
}
diff --git a/src/core/mpris1.cpp b/src/core/mpris1.cpp
index 26ed74c03..c11935a63 100644
--- a/src/core/mpris1.cpp
+++ b/src/core/mpris1.cpp
@@ -321,7 +321,7 @@ void Mpris1TrackList::PlayTrack(int index) {
QVariantMap Mpris1::GetMetadata(const Song& song) {
QVariantMap ret;
- AddMetadata("location", song.filename(), &ret);
+ AddMetadata("location", song.url().toString(), &ret);
AddMetadata("title", song.PrettyTitle(), &ret);
AddMetadata("artist", song.artist(), &ret);
AddMetadata("album", song.album(), &ret);
diff --git a/src/core/mpris2.cpp b/src/core/mpris2.cpp
index a93d86f1c..6154de3e9 100644
--- a/src/core/mpris2.cpp
+++ b/src/core/mpris2.cpp
@@ -308,7 +308,7 @@ void Mpris2::ArtLoaded(const Song& song, const QString& art_uri) {
using mpris::AddMetadata;
AddMetadata("mpris:trackid", current_track_id(), &last_metadata_);
- AddMetadata("xesam:url", song.filename(), &last_metadata_);
+ AddMetadata("xesam:url", song.url().toString(), &last_metadata_);
AddMetadata("xesam:title", song.PrettyTitle(), &last_metadata_);
AddMetadataAsList("xesam:artist", song.artist(), &last_metadata_);
AddMetadata("xesam:album", song.album(), &last_metadata_);
diff --git a/src/core/organise.cpp b/src/core/organise.cpp
index 98c631ef4..431b94768 100644
--- a/src/core/organise.cpp
+++ b/src/core/organise.cpp
@@ -148,7 +148,7 @@ void Organise::ProcessSomeFiles() {
song.set_filetype(task.new_filetype_);
// Fiddle the filename extension as well to match the new type
- song.set_filename(FiddleFileExtension(song.filename(), task.new_extension_));
+ song.set_url(QUrl::fromLocalFile(FiddleFileExtension(song.url().toLocalFile(), task.new_extension_)));
song.set_basefilename(FiddleFileExtension(song.basefilename(), task.new_extension_));
// Have to set this to the size of the new file or else funny stuff happens
diff --git a/src/core/organiseformat.cpp b/src/core/organiseformat.cpp
index 2b4d350fa..50cd8230b 100644
--- a/src/core/organiseformat.cpp
+++ b/src/core/organiseformat.cpp
@@ -139,7 +139,7 @@ QString OrganiseFormat::TagValue(const QString &tag, const Song &song) const {
else if (tag == "length") value = QString::number(song.length_nanosec() / kNsecPerSec);
else if (tag == "bitrate") value = QString::number(song.bitrate());
else if (tag == "samplerate") value = QString::number(song.samplerate());
- else if (tag == "extension") value = song.filename().section('.', -1, -1);
+ else if (tag == "extension") value = song.url().toLocalFile().section('.', -1, -1);
else if (tag == "artistinitial") {
value = song.albumartist().trimmed();
if (value.isEmpty()) value = song.artist().trimmed();
diff --git a/src/core/song.cpp b/src/core/song.cpp
index a98662743..2e46aa0c1 100644
--- a/src/core/song.cpp
+++ b/src/core/song.cpp
@@ -253,7 +253,7 @@ bool Song::HasProperMediaFile() const {
#endif
QMutexLocker l(&taglib_mutex_);
- scoped_ptr fileref(factory_->GetFileRef(d->filename_));
+ scoped_ptr fileref(factory_->GetFileRef(d->url_.toLocalFile()));
return !fileref->isNull() && fileref->tag();
}
@@ -266,7 +266,7 @@ void Song::InitFromFile(const QString& filename, int directory_id) {
d->init_from_file_ = true;
- d->filename_ = filename;
+ d->url_ = QUrl::fromLocalFile(filename);
d->directory_id_ = directory_id;
QFileInfo info(filename);
@@ -502,6 +502,7 @@ void Song::InitFromQuery(const SqlRow& q, int col) {
d->init_from_file_ = true;
#define tostr(n) (q.value(n).isNull() ? QString::null : q.value(n).toString())
+ #define tobytearray(n)(q.value(n).isNull() ? QByteArray() : q.value(n).toByteArray())
#define toint(n) (q.value(n).isNull() ? -1 : q.value(n).toInt())
#define tolonglong(n) (q.value(n).isNull() ? -1 : q.value(n).toLongLong())
#define tofloat(n) (q.value(n).isNull() ? -1 : q.value(n).toDouble())
@@ -524,8 +525,8 @@ void Song::InitFromQuery(const SqlRow& q, int col) {
d->samplerate_ = toint(col + 14);
d->directory_id_ = toint(col + 15);
- d->filename_ = tostr(col + 16);
- d->basefilename_ = QFileInfo(d->filename_).fileName();
+ d->url_ = QUrl::fromEncoded(tobytearray(col + 16));
+ d->basefilename_ = QFileInfo(d->url_.toLocalFile()).fileName();
d->mtime_ = toint(col + 17);
d->ctime_ = toint(col + 18);
d->filesize_ = toint(col + 19);
@@ -562,7 +563,7 @@ void Song::InitFromQuery(const SqlRow& q, int col) {
}
void Song::InitFromFilePartial(const QString& filename) {
- d->filename_ = filename;
+ d->url_ = QUrl::fromLocalFile(filename);
// We currently rely on filename suffix to know if it's a music file or not.
// TODO: I know this is not satisfying, but currently, we rely on TagLib
// which seems to have the behavior (filename checks). Someday, it would be
@@ -594,7 +595,7 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
#endif // HAVE_LIBLASTFM
#ifdef HAVE_LIBGPOD
- void Song::InitFromItdb(const Itdb_Track* track) {
+ void Song::InitFromItdb(const Itdb_Track* track, const QString& prefix) {
d->valid_ = true;
d->title_ = QString::fromUtf8(track->title);
@@ -621,9 +622,11 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
d->skipcount_ = track->skipcount;
d->lastplayed_ = track->time_played;
- d->filename_ = QString::fromLocal8Bit(track->ipod_path);
- d->filename_.replace(':', '/');
- d->basefilename_ = QFileInfo(d->filename_).fileName();
+ QString filename = QString::fromLocal8Bit(track->ipod_path);
+ filename.replace(':', '/');
+
+ d->url_ = QUrl::fromLocalFile(prefix + filename);
+ d->basefilename_ = QFileInfo(filename).fileName();
}
void Song::ToItdb(Itdb_Track *track) const {
@@ -656,7 +659,7 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
#endif
#ifdef HAVE_LIBMTP
- void Song::InitFromMTP(const LIBMTP_track_t* track) {
+ void Song::InitFromMTP(const LIBMTP_track_t* track, const QString& host) {
d->valid_ = true;
d->title_ = QString::fromUtf8(track->title);
@@ -664,8 +667,8 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
d->album_ = QString::fromUtf8(track->album);
d->composer_ = QString::fromUtf8(track->composer);
d->genre_ = QString::fromUtf8(track->genre);
- d->filename_ = QString::number(track->item_id);
- d->basefilename_ = d->filename_;
+ d->url_ = QUrl(QString("mtp://%1/%2").arg(host, track->item_id));
+ d->basefilename_ = QString::number(track->item_id);
d->track_ = track->tracknumber;
set_length_nanosec(track->duration * kNsecPerMsec);
@@ -839,7 +842,7 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
d->bitrate_ = item_value.toInt();
else if (wcscmp(name, g_wszWMDMFileName) == 0)
- d->filename_ = item_value.toString();
+ d->url_ = QUrl::fromLocalFile(item_value.toString());
else if (wcscmp(name, g_wszWMDMDuration) == 0)
set_length_nanosec(item_value.toULongLong() * 1e2);
@@ -913,7 +916,7 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
// Make a final guess based on the file extension
{
- QString ext = d->filename_.section('.', -1, -1).toLower();
+ QString ext = d->url_.path().section('.', -1, -1).toLower();
if (ext == "mp3" || ext == "wma" || ext == "flac" || ext == "ogg" ||
ext == "spx" || ext == "mp4" || ext == "aac" || ext == "m4a")
break;
@@ -1007,7 +1010,7 @@ void Song::BindToQuery(QSqlQuery *query) const {
query->bindValue(":samplerate", intval(d->samplerate_));
query->bindValue(":directory", notnullintval(d->directory_id_));
- query->bindValue(":filename", d->filename_);
+ query->bindValue(":filename", d->url_.toEncoded());
query->bindValue(":mtime", notnullintval(d->mtime_));
query->bindValue(":ctime", notnullintval(d->ctime_));
query->bindValue(":filesize", notnullintval(d->filesize_));
@@ -1066,12 +1069,6 @@ void Song::ToLastFM(lastfm::Track* track) const {
}
#endif // HAVE_LIBLASTFM
-QUrl Song::url() const {
- return QFile::exists(filename())
- ? QUrl::fromLocalFile(filename())
- : filename();
-}
-
QString Song::PrettyTitle() const {
QString title(d->title_);
@@ -1164,16 +1161,17 @@ TagLib::String QStringToTaglibString(const QString& s) {
}
bool Song::IsEditable() const {
- return d->valid_ && !d->filename_.isNull() && !is_stream() &&
+ return d->valid_ && !d->url_.isEmpty() && !is_stream() &&
d->filetype_ != Type_Unknown && !has_cue();
}
bool Song::Save() const {
- if (d->filename_.isNull())
+ const QString filename = d->url_.toLocalFile();
+ if (filename.isNull())
return false;
QMutexLocker l(&taglib_mutex_);
- scoped_ptr fileref(factory_->GetFileRef(d->filename_));
+ scoped_ptr fileref(factory_->GetFileRef(filename));
if (!fileref || fileref->isNull()) // The file probably doesn't exist
return false;
@@ -1214,7 +1212,7 @@ bool Song::Save() const {
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(d->filename_).constData(), NULL, 0);
+ utimensat(0, QFile::encodeName(filename).constData(), NULL, 0);
}
#endif // Q_OS_LINUX
@@ -1232,7 +1230,7 @@ QFuture Song::BackgroundSave() const {
bool Song::operator==(const Song& other) const {
// TODO: this isn't working for radios
- return filename() == other.filename() &&
+ return url() == other.url() &&
beginning_nanosec() == other.beginning_nanosec();
}
diff --git a/src/core/song.h b/src/core/song.h
index 98487e6c6..3d808e000 100644
--- a/src/core/song.h
+++ b/src/core/song.h
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
@@ -136,12 +137,12 @@ class Song {
void MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle& bundle);
#ifdef HAVE_LIBGPOD
- void InitFromItdb(const Itdb_Track* track);
+ void InitFromItdb(const Itdb_Track* track, const QString& prefix);
void ToItdb(Itdb_Track* track) const;
#endif
#ifdef HAVE_LIBMTP
- void InitFromMTP(const LIBMTP_track_t* track);
+ void InitFromMTP(const LIBMTP_track_t* track, const QString& host);
void ToMTP(LIBMTP_track_t* track) const;
#endif
@@ -197,10 +198,7 @@ class Song {
int samplerate() const { return d->samplerate_; }
int directory_id() const { return d->directory_id_; }
- const QString& filename() const { return d->filename_; }
- // Returns this Song's URL which may point either to a file or to another type
- // of stream.
- QUrl url() const;
+ const QUrl& url() const { return d->url_; }
const QString& basefilename() const { return d->basefilename_; }
uint mtime() const { return d->mtime_; }
uint ctime() const { return d->ctime_; }
@@ -277,7 +275,7 @@ class Song {
void set_cue_path(const QString& v) { d->cue_path_ = v; }
// Setters that should only be used by tests
- void set_filename(const QString& v) { d->filename_ = v; }
+ void set_url(const QUrl& v) { d->url_ = v; }
void set_basefilename(const QString& v) { d->basefilename_ = v; }
void set_directory_id(int v) { d->directory_id_ = v; }
@@ -342,7 +340,7 @@ class Song {
int samplerate_;
int directory_id_;
- QString filename_;
+ QUrl url_;
QString basefilename_;
int mtime_;
int ctime_;
diff --git a/src/core/songloader.cpp b/src/core/songloader.cpp
index 8c33771c6..7793ca9fd 100644
--- a/src/core/songloader.cpp
+++ b/src/core/songloader.cpp
@@ -193,7 +193,7 @@ SongLoader::Result SongLoader::LoadLocal(const QString& filename, bool block,
void SongLoader::EffectiveSongsLoad() {
for (int i = 0; i < songs_.size(); i++) {
Song& song = songs_[i];
- QString filename = song.filename();
+ QString filename = song.url().toLocalFile();
QFileInfo info(filename);
LibraryQuery query;
@@ -233,7 +233,7 @@ static bool CompareSongs(const Song& left, const Song& right) {
if (left.disc() > right.disc()) return false;
if (left.track() < right.track()) return true;
if (left.track() > right.track()) return false;
- return left.filename() < right.filename();
+ return left.url() < right.url();
}
void SongLoader::LoadLocalDirectoryAndEmit(const QString& filename) {
@@ -256,7 +256,7 @@ void SongLoader::AddAsRawStream() {
Song song;
song.set_valid(true);
song.set_filetype(Song::Type_Stream);
- song.set_filename(url_.toString());
+ song.set_url(url_);
song.set_title(url_.toString());
songs_ << song;
}
diff --git a/src/covers/albumcoverloader.cpp b/src/covers/albumcoverloader.cpp
index 4f8814979..381435bb9 100644
--- a/src/covers/albumcoverloader.cpp
+++ b/src/covers/albumcoverloader.cpp
@@ -233,5 +233,5 @@ void AlbumCoverLoader::SetDefaultOutputImage(const QImage &image) {
quint64 AlbumCoverLoader::LoadImageAsync(const Song &song) {
return LoadImageAsync(song.art_automatic(), song.art_manual(),
- song.filename(), song.image());
+ song.url().toLocalFile(), song.image());
}
diff --git a/src/devices/afcdevice.cpp b/src/devices/afcdevice.cpp
index d0a9bc667..9c4c6300a 100644
--- a/src/devices/afcdevice.cpp
+++ b/src/devices/afcdevice.cpp
@@ -159,7 +159,7 @@ void AfcDevice::FinaliseDatabase() {
}
bool AfcDevice::DeleteFromStorage(const DeleteJob& job) {
- const QString path = QUrl(job.metadata_.filename()).path();
+ const QString path = job.metadata_.url().toLocalFile();
if (!RemoveTrackFromITunesDb(path))
return false;
diff --git a/src/devices/connecteddevice.cpp b/src/devices/connecteddevice.cpp
index a90842784..59fc8f38b 100644
--- a/src/devices/connecteddevice.cpp
+++ b/src/devices/connecteddevice.cpp
@@ -79,7 +79,7 @@ void ConnectedDevice::InitBackendDirectory(
if (dir.path != mount_point) {
// The directory is different, commence the munging.
qLog(Info) << "Changing path from" << dir.path << "to" << mount_point;
- backend_->ChangeDirPath(dir.id, mount_point);
+ backend_->ChangeDirPath(dir.id, dir.path, mount_point);
}
}
diff --git a/src/devices/deviceview.cpp b/src/devices/deviceview.cpp
index f51177791..6603782e3 100644
--- a/src/devices/deviceview.cpp
+++ b/src/devices/deviceview.cpp
@@ -402,7 +402,7 @@ void DeviceView::Organise() {
SongList songs = GetSelectedSongs();
QStringList filenames;
foreach (const Song& song, songs) {
- filenames << song.filename();
+ filenames << song.url().toLocalFile();
}
organise_dialog_->SetCopy(true);
diff --git a/src/devices/gpoddevice.cpp b/src/devices/gpoddevice.cpp
index b7f41c42f..a8e57d776 100644
--- a/src/devices/gpoddevice.cpp
+++ b/src/devices/gpoddevice.cpp
@@ -99,9 +99,8 @@ Itdb_Track* GPodDevice::AddTrackToITunesDb(const Song& metadata) {
void GPodDevice::AddTrackToModel(Itdb_Track* track, const QString& prefix) {
// Add it to our LibraryModel
Song metadata_on_device;
- metadata_on_device.InitFromItdb(track);
+ metadata_on_device.InitFromItdb(track, prefix);
metadata_on_device.set_directory_id(1);
- metadata_on_device.set_filename(prefix + metadata_on_device.filename());
songs_to_add_ << metadata_on_device;
}
@@ -209,11 +208,11 @@ bool GPodDevice::RemoveTrackFromITunesDb(const QString& path, const QString& rel
bool GPodDevice::DeleteFromStorage(const DeleteJob& job) {
Q_ASSERT(db_);
- if (!RemoveTrackFromITunesDb(job.metadata_.filename(), url_.path()))
+ if (!RemoveTrackFromITunesDb(job.metadata_.url().toLocalFile(), url_.path()))
return false;
// Remove the file
- if (!QFile::remove(job.metadata_.filename()))
+ if (!QFile::remove(job.metadata_.url().toLocalFile()))
return false;
// Remove it from our library model
diff --git a/src/devices/gpodloader.cpp b/src/devices/gpodloader.cpp
index 4db90beed..730cff5b8 100644
--- a/src/devices/gpodloader.cpp
+++ b/src/devices/gpodloader.cpp
@@ -66,20 +66,17 @@ void GPodLoader::LoadDatabase() {
}
// Convert all the tracks from libgpod structs into Song classes
+ const QString prefix = path_prefix_.isEmpty()
+ ? QDir::fromNativeSeparators(mount_point_) : path_prefix_;
+
SongList songs;
for (GList* tracks = db->tracks ; tracks != NULL ; tracks = tracks->next) {
Itdb_Track* track = static_cast(tracks->data);
Song song;
- song.InitFromItdb(track);
+ song.InitFromItdb(track, prefix);
song.set_directory_id(1);
- QString filename = (path_prefix_.isEmpty() ? mount_point_ : path_prefix_) +
- song.filename();
- if (path_prefix_.isEmpty())
- filename = QDir::cleanPath(QDir::fromNativeSeparators(filename));
- song.set_filename(filename);
-
if (type_ != Song::Type_Unknown)
song.set_filetype(type_);
songs << song;
diff --git a/src/devices/imobiledeviceconnection.cpp b/src/devices/imobiledeviceconnection.cpp
index 8a5c221b9..d98c908ea 100644
--- a/src/devices/imobiledeviceconnection.cpp
+++ b/src/devices/imobiledeviceconnection.cpp
@@ -215,7 +215,7 @@ QString iMobileDeviceConnection::GetUnusedFilename(
}
// Use the same file extension as the original file, default to mp3.
- QString extension = metadata.filename().section('.', -1, -1).toLower();
+ QString extension = metadata.url().path().section('.', -1, -1).toLower();
if (extension.isEmpty())
extension = "mp3";
diff --git a/src/devices/mtpdevice.cpp b/src/devices/mtpdevice.cpp
index 1a06f957b..571655920 100644
--- a/src/devices/mtpdevice.cpp
+++ b/src/devices/mtpdevice.cpp
@@ -112,9 +112,8 @@ bool MtpDevice::CopyToStorage(const CopyJob& job) {
// Add it to our LibraryModel
Song metadata_on_device;
- metadata_on_device.InitFromMTP(&track);
+ metadata_on_device.InitFromMTP(&track, url_.host());
metadata_on_device.set_directory_id(1);
- metadata_on_device.set_filename("mtp://" + url_.host() + "/" + metadata_on_device.filename());
songs_to_add_ << metadata_on_device;
// Remove the original if requested
@@ -150,8 +149,7 @@ void MtpDevice::StartDelete() {
bool MtpDevice::DeleteFromStorage(const DeleteJob& job) {
// Extract the ID from the song's URL
- QUrl url(job.metadata_.filename());
- QString filename = url.path();
+ QString filename = job.metadata_.url().path();
filename.remove('/');
bool ok = false;
diff --git a/src/devices/mtploader.cpp b/src/devices/mtploader.cpp
index 07a467ff7..17015f18a 100644
--- a/src/devices/mtploader.cpp
+++ b/src/devices/mtploader.cpp
@@ -64,9 +64,8 @@ bool MtpLoader::TryLoad() {
LIBMTP_track_t* track = tracks;
Song song;
- song.InitFromMTP(track);
+ song.InitFromMTP(track, url_.host());
song.set_directory_id(1);
- song.set_filename("mtp://" + url_.host() + "/" + song.filename());
songs << song;
tracks = tracks->next;
diff --git a/src/library/librarybackend.cpp b/src/library/librarybackend.cpp
index 8c80b06ef..7439769e7 100644
--- a/src/library/librarybackend.cpp
+++ b/src/library/librarybackend.cpp
@@ -89,7 +89,8 @@ void LibraryBackend::LoadDirectories() {
}
}
-void LibraryBackend::ChangeDirPath(int id, const QString &new_path) {
+void LibraryBackend::ChangeDirPath(int id, const QString& old_path,
+ const QString& new_path) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
ScopedTransaction t(&db);
@@ -101,12 +102,15 @@ void LibraryBackend::ChangeDirPath(int id, const QString &new_path) {
q.exec();
if (db_->CheckErrors(q)) return;
- const int path_len = new_path.length();
+ const QByteArray old_url = QUrl::fromLocalFile(old_path).toEncoded();
+ const QByteArray new_url = QUrl::fromLocalFile(new_path).toEncoded();
+
+ const int path_len = old_url.length();
// Do the subdirs table
q = QSqlQuery(QString("UPDATE %1 SET path=:path || substr(path, %2)"
" WHERE directory=:id").arg(subdirs_table_).arg(path_len), db);
- q.bindValue(":path", new_path);
+ q.bindValue(":path", new_url);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
@@ -114,7 +118,7 @@ void LibraryBackend::ChangeDirPath(int id, const QString &new_path) {
// Do the songs table
q = QSqlQuery(QString("UPDATE %1 SET filename=:path || substr(filename, %2)"
" WHERE directory=:id").arg(songs_table_).arg(path_len), db);
- q.bindValue(":path", new_path);
+ q.bindValue(":path", new_url);
q.bindValue(":id", id);
q.exec();
if (db_->CheckErrors(q)) return;
@@ -564,10 +568,10 @@ SongList LibraryBackend::GetSongsById(const QStringList& ids, QSqlDatabase& db)
return ret;
}
-Song LibraryBackend::GetSongByFilename(const QString& filename, qint64 beginning) {
+Song LibraryBackend::GetSongByUrl(const QUrl& url, qint64 beginning) {
LibraryQuery query;
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
- query.AddWhere("filename", filename);
+ query.AddWhere("filename", url.toEncoded());
query.AddWhere("beginning", beginning);
Song song;
@@ -577,10 +581,10 @@ Song LibraryBackend::GetSongByFilename(const QString& filename, qint64 beginning
return song;
}
-SongList LibraryBackend::GetSongsByFilename(const QString& filename) {
+SongList LibraryBackend::GetSongsByUrl(const QUrl& url) {
LibraryQuery query;
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
- query.AddWhere("filename", filename);
+ query.AddWhere("filename", url.toEncoded());
SongList songlist;
if (ExecQuery(&query)) {
@@ -754,7 +758,7 @@ LibraryBackend::AlbumList LibraryBackend::GetAlbums(const QString& artist,
info.album_name = query.Value(0).toString();
info.art_automatic = query.Value(4).toString();
info.art_manual = query.Value(5).toString();
- info.first_filename = query.Value(6).toString();
+ info.first_url = QUrl::fromEncoded(query.Value(6).toByteArray());
if (info.artist == last_artist && info.album_name == last_album)
continue;
@@ -784,7 +788,7 @@ LibraryBackend::Album LibraryBackend::GetAlbumArt(const QString& artist, const Q
if (query.Next()) {
ret.art_automatic = query.Value(0).toString();
ret.art_manual = query.Value(1).toString();
- ret.first_filename = query.Value(2).toString();
+ ret.first_url = QUrl::fromEncoded(query.Value(2).toByteArray());
}
return ret;
diff --git a/src/library/librarybackend.h b/src/library/librarybackend.h
index 52c33cec0..90a562dd5 100644
--- a/src/library/librarybackend.h
+++ b/src/library/librarybackend.h
@@ -40,17 +40,17 @@ class LibraryBackendInterface : public QObject {
Album() {}
Album(const QString& _artist, const QString& _album_name,
const QString& _art_automatic, const QString& _art_manual,
- const QString& _first_filename)
+ const QUrl& _first_url)
: artist(_artist), album_name(_album_name),
art_automatic(_art_automatic), art_manual(_art_manual),
- first_filename(_first_filename) {}
+ first_url(_first_url) {}
QString artist;
QString album_name;
QString art_automatic;
QString art_manual;
- QString first_filename;
+ QUrl first_url;
};
typedef QList AlbumList;
@@ -63,7 +63,7 @@ class LibraryBackendInterface : public QObject {
virtual SongList FindSongsInDirectory(int id) = 0;
virtual SubdirectoryList SubdirsInDirectory(int id) = 0;
virtual DirectoryList GetAllDirectories() = 0;
- virtual void ChangeDirPath(int id, const QString& new_path) = 0;
+ virtual void ChangeDirPath(int id, const QString& old_path, const QString& new_path) = 0;
virtual QStringList GetAllArtists(const QueryOptions& opt = QueryOptions()) = 0;
virtual QStringList GetAllArtistsWithAlbums(const QueryOptions& opt = QueryOptions()) = 0;
@@ -84,11 +84,11 @@ class LibraryBackendInterface : public QObject {
// Returns all sections of a song with the given filename. If there's just one section
// the resulting list will have it's size equal to 1.
- virtual SongList GetSongsByFilename(const QString& filename) = 0;
+ virtual SongList GetSongsByUrl(const QUrl& url) = 0;
// Returns a section of a song with the given filename and beginning. If the section
// is not present in library, returns invalid song.
// Using default beginning value is suitable when searching for single-section songs.
- virtual Song GetSongByFilename(const QString& filename, qint64 beginning = 0) = 0;
+ virtual Song GetSongByUrl(const QUrl& url, qint64 beginning = 0) = 0;
virtual void AddDirectory(const QString& path) = 0;
virtual void RemoveDirectory(const Directory& dir) = 0;
@@ -120,7 +120,7 @@ class LibraryBackend : public LibraryBackendInterface {
SongList FindSongsInDirectory(int id);
SubdirectoryList SubdirsInDirectory(int id);
DirectoryList GetAllDirectories();
- void ChangeDirPath(int id, const QString& new_path);
+ void ChangeDirPath(int id, const QString& old_path, const QString& new_path);
QStringList GetAll(const QString& column, const QueryOptions& opt = QueryOptions());
QStringList GetAllArtists(const QueryOptions& opt = QueryOptions());
@@ -143,8 +143,8 @@ class LibraryBackend : public LibraryBackendInterface {
SongList GetSongsByForeignId(const QStringList& ids, const QString& table,
const QString& column);
- SongList GetSongsByFilename(const QString& filename);
- Song GetSongByFilename(const QString& filename, qint64 beginning = 0);
+ SongList GetSongsByUrl(const QUrl& url);
+ Song GetSongByUrl(const QUrl& url, qint64 beginning = 0);
void AddDirectory(const QString& path);
void RemoveDirectory(const Directory& dir);
diff --git a/src/library/librarymodel.cpp b/src/library/librarymodel.cpp
index ba87f6d08..aebdaf809 100644
--- a/src/library/librarymodel.cpp
+++ b/src/library/librarymodel.cpp
@@ -392,7 +392,7 @@ QVariant LibraryModel::AlbumIcon(const QModelIndex& index, int role) const {
if (!songs.isEmpty()) {
const Song& s = songs.first();
QPixmap pixmap = AlbumCoverLoader::TryLoadPixmap(
- s.art_automatic(), s.art_manual(), s.filename());
+ s.art_automatic(), s.art_manual(), s.url().toLocalFile());
if (!pixmap.isNull()) {
QImage image = pixmap.toImage().scaled(
@@ -931,7 +931,7 @@ QString LibraryModel::SortTextForYear(int year) const {
QString LibraryModel::SortTextForSong(const Song& song) const {
QString ret = QString::number(qMax(0, song.disc()) * 1000 + qMax(0, song.track()));
ret.prepend(QString("0").repeated(6 - ret.length()));
- ret.append(song.filename());
+ ret.append(song.url().toString());
return ret;
}
@@ -1012,7 +1012,7 @@ void LibraryModel::GetChildSongs(LibraryItem* item, QList* urls,
}
case LibraryItem::Type_Song:
- urls->append(QUrl::fromLocalFile(item->metadata.filename()));
+ urls->append(item->metadata.url());
if (!song_ids->contains(item->metadata.id())) {
songs->append(item->metadata);
song_ids->insert(item->metadata.id());
diff --git a/src/library/libraryplaylistitem.cpp b/src/library/libraryplaylistitem.cpp
index e166114a4..d478d229e 100644
--- a/src/library/libraryplaylistitem.cpp
+++ b/src/library/libraryplaylistitem.cpp
@@ -32,11 +32,11 @@ LibraryPlaylistItem::LibraryPlaylistItem(const Song& song)
QUrl LibraryPlaylistItem::Url() const {
- return QUrl::fromLocalFile(song_.filename());
+ return song_.url();
}
void LibraryPlaylistItem::Reload() {
- song_.InitFromFile(song_.filename(), song_.directory_id());
+ song_.InitFromFile(song_.url().toLocalFile(), song_.directory_id());
}
bool LibraryPlaylistItem::InitFromQuery(const SqlRow& query) {
diff --git a/src/library/libraryview.cpp b/src/library/libraryview.cpp
index 80fdf6169..c395873cc 100644
--- a/src/library/libraryview.cpp
+++ b/src/library/libraryview.cpp
@@ -550,7 +550,7 @@ void LibraryView::EditSmartPlaylistFinished() {
void LibraryView::ShowInBrowser() {
QStringList filenames;
foreach (const Song& song, GetSelectedSongs()) {
- filenames << song.filename();
+ filenames << song.url().toLocalFile();
}
Utilities::OpenInFileBrowser(filenames);
diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp
index 0ac6c0c57..4bd505df9 100644
--- a/src/library/librarywatcher.cpp
+++ b/src/library/librarywatcher.cpp
@@ -132,7 +132,7 @@ SongList LibraryWatcher::ScanTransaction::FindSongsInSubdirectory(const QString
// TODO: Make this faster
SongList ret;
foreach (const Song& song, cached_songs_) {
- if (song.filename().section('/', 0, -2) == path)
+ if (song.url().toLocalFile().section('/', 0, -2) == path)
ret << song;
}
return ret;
@@ -363,8 +363,8 @@ void LibraryWatcher::ScanSubdirectory(
// Look for deleted songs
foreach (const Song& song, songs_in_db) {
- if (!files_on_disk.contains(song.filename())) {
- qLog(Debug) << "Song deleted from disk:" << song.filename();
+ if (!files_on_disk.contains(song.url().toLocalFile())) {
+ qLog(Debug) << "Song deleted from disk:" << song.url().toLocalFile();
t->deleted_songs << song;
}
}
@@ -397,7 +397,7 @@ void LibraryWatcher::UpdateCueAssociatedSongs(const QString& file, const QString
QFile cue(matching_cue);
cue.open(QIODevice::ReadOnly);
- SongList old_sections = backend_->GetSongsByFilename(file);
+ SongList old_sections = backend_->GetSongsByUrl(QUrl::fromLocalFile(file));
QHash sections_map;
foreach(const Song& song, old_sections) {
@@ -437,7 +437,7 @@ void LibraryWatcher::UpdateNonCueAssociatedSong(const QString& file, const Song&
// 'raw' (cueless) song and we just remove the rest of the sections
// from the library
if(cue_deleted) {
- foreach(const Song& song, backend_->GetSongsByFilename(file)) {
+ foreach(const Song& song, backend_->GetSongsByUrl(QUrl::fromLocalFile(file))) {
if(!song.IsMetadataEqual(matching_song)) {
t->deleted_songs << song;
}
@@ -470,7 +470,7 @@ SongList LibraryWatcher::ScanNewFile(const QString& file, const QString& path,
// media files. Playlist parser for CUEs considers every entry in sheet
// valid and we don't want invalid media getting into library!
foreach(const Song& cue_song, cue_parser_->Load(&cue, matching_cue, path)) {
- if(cue_song.filename() == file && cue_song.HasProperMediaFile()) {
+ if(cue_song.url().toLocalFile() == file && cue_song.HasProperMediaFile()) {
song_list << cue_song;
}
}
@@ -553,7 +553,7 @@ void LibraryWatcher::RemoveDirectory(const Directory& dir) {
bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, Song* out) {
// TODO: Make this faster
foreach (const Song& song, list) {
- if (song.filename() == path) {
+ if (song.url().toLocalFile() == path) {
*out = song;
return true;
}
diff --git a/src/musicbrainz/tagfetcher.cpp b/src/musicbrainz/tagfetcher.cpp
index dd50b2fc2..ece742c3b 100644
--- a/src/musicbrainz/tagfetcher.cpp
+++ b/src/musicbrainz/tagfetcher.cpp
@@ -35,7 +35,7 @@ TagFetcher::TagFetcher(QObject* parent)
}
QString TagFetcher::GetFingerprint(const Song& song) {
- return Fingerprinter(song.filename()).CreateFingerprint();
+ return Fingerprinter(song.url().toLocalFile()).CreateFingerprint();
}
void TagFetcher::StartFetch(const SongList& songs) {
diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp
index 67b762ad5..69dd79eae 100644
--- a/src/playlist/playlist.cpp
+++ b/src/playlist/playlist.cpp
@@ -274,7 +274,7 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
case Column_BPM: return song.bpm();
case Column_Bitrate: return song.bitrate();
case Column_Samplerate: return song.samplerate();
- case Column_Filename: return song.filename();
+ case Column_Filename: return song.url();
case Column_BaseFilename: return song.basefilename();
case Column_Filesize: return song.filesize();
case Column_Filetype: return song.filetype();
@@ -958,7 +958,7 @@ void Playlist::UpdateItems(const SongList& songs) {
// Update current items list
for (int i=0; iMetadata().filename() == song.filename()) {
+ if (item->Metadata().url() == song.url()) {
PlaylistItemPtr new_item;
if (song.id() == -1) {
new_item = PlaylistItemPtr(new SongPlaylistItem(song));
@@ -1041,7 +1041,7 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order,
case Column_BPM: cmp(bpm);
case Column_Bitrate: cmp(bitrate);
case Column_Samplerate: cmp(samplerate);
- case Column_Filename: cmp(filename);
+ case Column_Filename: cmp(url);
case Column_BaseFilename: cmp(basefilename);
case Column_Filesize: cmp(filesize);
case Column_Filetype: cmp(filetype);
@@ -1186,7 +1186,7 @@ void Playlist::ItemsLoaded() {
while (it.hasNext()) {
PlaylistItemPtr item = it.next();
- if (item->IsLocalLibraryItem() && item->Metadata().filename().isEmpty()) {
+ if (item->IsLocalLibraryItem() && item->Metadata().url().isEmpty()) {
it.remove();
}
}
@@ -1684,7 +1684,7 @@ void Playlist::InvalidateDeletedSongs() {
Song song = item->Metadata();
if(!song.is_stream()) {
- bool exists = QFile::exists(song.filename());
+ bool exists = QFile::exists(song.url().toLocalFile());
if(!exists && !item->HasForegroundColor(kInvalidSongPriority)) {
// gray out the song if it's not there
@@ -1707,7 +1707,7 @@ void Playlist::RemoveDeletedSongs() {
PlaylistItemPtr item = items_[row];
Song song = item->Metadata();
- if(!song.is_stream() && !QFile::exists(song.filename())) {
+ if(!song.is_stream() && !QFile::exists(song.url().toLocalFile())) {
rows_to_remove.append(row);
}
}
@@ -1723,8 +1723,8 @@ bool Playlist::ApplyValidityOnCurrentSong(const QUrl& url, bool valid) {
// if validity has changed, reload the item
if(!current_song.is_stream() &&
- current_song.filename() == url.toLocalFile() &&
- current_song.is_valid() != QFile::exists(current_song.filename())) {
+ current_song.url() == url &&
+ current_song.is_valid() != QFile::exists(current_song.url().toLocalFile())) {
ReloadItems(QList() << current_row());
}
diff --git a/src/playlist/playlistbackend.cpp b/src/playlist/playlistbackend.cpp
index cfc0082c5..1da313dda 100644
--- a/src/playlist/playlistbackend.cpp
+++ b/src/playlist/playlistbackend.cpp
@@ -192,7 +192,7 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, boost::sha
}
foreach(const Song& from_list, song_list) {
- if(from_list.filename() == song.filename() &&
+ if(from_list.url() == song.url() &&
from_list.beginning_nanosec() == song.beginning_nanosec()) {
// we found a matching section; replace the input
// item with a new one containing CUE metadata
diff --git a/src/playlist/playlistundocommands.cpp b/src/playlist/playlistundocommands.cpp
index f0efc11f9..828b5ad59 100644
--- a/src/playlist/playlistundocommands.cpp
+++ b/src/playlist/playlistundocommands.cpp
@@ -50,7 +50,7 @@ void InsertItems::undo() {
bool InsertItems::UpdateItem(const PlaylistItemPtr& updated_item) {
for (int i=0; iMetadata().filename() == updated_item->Metadata().filename()) {
+ if (item->Metadata().url() == updated_item->Metadata().url()) {
items_[i] = updated_item;
return true;
}
diff --git a/src/playlist/songplaylistitem.cpp b/src/playlist/songplaylistitem.cpp
index e230b4642..f3c446f51 100644
--- a/src/playlist/songplaylistitem.cpp
+++ b/src/playlist/songplaylistitem.cpp
@@ -52,7 +52,7 @@ QUrl SongPlaylistItem::Url() const {
}
void SongPlaylistItem::Reload() {
- QString old_filename = song_.filename();
+ QString old_filename = song_.url().toLocalFile();
int old_directory_id = song_.directory_id();
song_ = Song();
diff --git a/src/playlistparsers/asxiniparser.cpp b/src/playlistparsers/asxiniparser.cpp
index bbf93ed1a..79e5a155c 100644
--- a/src/playlistparsers/asxiniparser.cpp
+++ b/src/playlistparsers/asxiniparser.cpp
@@ -40,16 +40,8 @@ SongList AsxIniParser::Load(QIODevice *device, const QString& playlist_path, con
QString value = line.mid(equals + 1);
if (key.startsWith("ref")) {
- Song song;
- if (!ParseTrackLocation(value, dir, &song))
- qLog(Warning) << "Failed to parse location: " << value;
-
- // Load the song from the library if it's there.
- Song library_song = LoadLibrarySong(song.filename());
- if (library_song.is_valid()) {
- ret << library_song;
- } else {
- song.InitFromFile(song.filename(), -1);
+ Song song = LoadSong(value, 0, dir);
+ if (song.is_valid()) {
ret << song;
}
}
@@ -64,7 +56,7 @@ void AsxIniParser::Save(const SongList &songs, QIODevice *device, const QDir &di
int n = 1;
foreach (const Song& song, songs) {
- s << "Ref" << n << "=" << MakeRelativeTo(song.filename(), dir) << endl;
+ s << "Ref" << n << "=" << URLOrRelativeFilename(song.url(), dir) << endl;
++n;
}
}
diff --git a/src/playlistparsers/asxparser.cpp b/src/playlistparsers/asxparser.cpp
index fad080324..eb819cdcd 100644
--- a/src/playlistparsers/asxparser.cpp
+++ b/src/playlistparsers/asxparser.cpp
@@ -31,7 +31,8 @@ ASXParser::ASXParser(LibraryBackendInterface* library, QObject* parent)
{
}
-SongList ASXParser::Load(QIODevice *device, const QString& playlist_path, const QDir&) const {
+SongList ASXParser::Load(QIODevice *device, const QString& playlist_path,
+ const QDir& dir) const {
// We have to load everything first so we can munge the "XML".
QByteArray data = device->readAll();
@@ -70,7 +71,7 @@ SongList ASXParser::Load(QIODevice *device, const QString& playlist_path, const
}
while (!reader.atEnd() && ParseUntilElement(&reader, "entry")) {
- Song song = ParseTrack(&reader);
+ Song song = ParseTrack(&reader, dir);
if (song.is_valid()) {
ret << song;
}
@@ -79,9 +80,9 @@ SongList ASXParser::Load(QIODevice *device, const QString& playlist_path, const
}
-Song ASXParser::ParseTrack(QXmlStreamReader* reader) const {
- Song song;
- QString title, artist, album;
+Song ASXParser::ParseTrack(QXmlStreamReader* reader, const QDir& dir) const {
+ QString title, artist, album, ref;
+
while (!reader->atEnd()) {
QXmlStreamReader::TokenType type = reader->readNext();
@@ -89,24 +90,7 @@ Song ASXParser::ParseTrack(QXmlStreamReader* reader) const {
case QXmlStreamReader::StartElement: {
QStringRef name = reader->name();
if (name == "ref") {
- QUrl url(reader->attributes().value("href").toString());
- if (url.scheme() == "file") {
- QString filename = url.toLocalFile();
- if (!QFile::exists(filename)) {
- return Song();
- }
-
- // Load the song from the library if it's there.
- Song library_song = LoadLibrarySong(filename);
- if (library_song.is_valid())
- return library_song;
-
- song.InitFromFile(filename, -1);
- return song;
- } else {
- song.set_filename(url.toString());
- song.set_filetype(Song::Type_Stream);
- }
+ ref = reader->attributes().value("href").toString();
} else if (name == "title") {
title = reader->readElementText();
} else if (name == "author") {
@@ -116,8 +100,7 @@ Song ASXParser::ParseTrack(QXmlStreamReader* reader) const {
}
case QXmlStreamReader::EndElement: {
if (reader->name() == "entry") {
- song.Init(title, artist, album, -1);
- return song;
+ goto return_song;
}
break;
}
@@ -125,8 +108,14 @@ Song ASXParser::ParseTrack(QXmlStreamReader* reader) const {
break;
}
}
- // At least make an effort if we never find a .
- song.Init(title, artist, album, -1);
+
+return_song:
+ Song song = LoadSong(ref, 0, dir);
+
+ // Override metadata with what was in the playlist
+ song.set_title(title);
+ song.set_artist(artist);
+ song.set_album(album);
return song;
}
@@ -142,7 +131,7 @@ void ASXParser::Save(const SongList& songs, QIODevice* device, const QDir&) cons
writer.writeTextElement("title", song.title());
{
StreamElement ref("ref", &writer);
- writer.writeAttribute("href", MakeUrl(song.filename()));
+ writer.writeAttribute("href", song.url().toString());
}
if (!song.artist().isEmpty()) {
writer.writeTextElement("author", song.artist());
diff --git a/src/playlistparsers/asxparser.h b/src/playlistparsers/asxparser.h
index a151c4833..0d295dfa7 100644
--- a/src/playlistparsers/asxparser.h
+++ b/src/playlistparsers/asxparser.h
@@ -31,11 +31,12 @@ class ASXParser : public XMLParser {
bool TryMagic(const QByteArray &data) const;
- SongList Load(QIODevice *device, const QString& playlist_path = "", const QDir &dir = QDir()) const;
+ SongList Load(QIODevice *device, const QString& playlist_path = "",
+ const QDir& dir = QDir()) const;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir()) const;
private:
- Song ParseTrack(QXmlStreamReader* reader) const;
+ Song ParseTrack(QXmlStreamReader* reader, const QDir& dir) const;
};
#endif
diff --git a/src/playlistparsers/cueparser.cpp b/src/playlistparsers/cueparser.cpp
index 7acd72d1d..91c21e297 100644
--- a/src/playlistparsers/cueparser.cpp
+++ b/src/playlistparsers/cueparser.cpp
@@ -207,46 +207,37 @@ SongList CueParser::Load(QIODevice* device, const QString& playlist_path, const
for(int i = 0; i < entries.length(); i++) {
CueEntry entry = entries.at(i);
- Song current;
- if (!ParseTrackLocation(entry.file, dir, ¤t)) {
- qLog(Warning) << "failed to parse location in .cue file from " << dir_path;
- } else {
- // look for the section in library
- Song song = LoadLibrarySong(current.filename(), IndexToMarker(entry.index));
- if (!song.is_valid()) {
- song.InitFromFile(current.filename(), -1);
- }
+ Song song = LoadSong(entry.file, IndexToMarker(entry.index), dir);
- // cue song has mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
- if(cue_mtime.isValid()) {
- song.set_mtime(qMax(cue_mtime.toTime_t(), song.mtime()));
- }
- song.set_cue_path(playlist_path);
-
- // overwrite the stuff, we may have read from the file or library, using
- // the current .cue metadata
-
- // set track number only in single-file mode
- if(files == 1) {
- song.set_track(i + 1);
- }
-
- // the last TRACK for every FILE gets it's 'end' marker from the media file's
- // length
- if(i + 1 < entries.size() && entries.at(i).file == entries.at(i + 1).file) {
- // incorrect indices?
- if(!UpdateSong(entry, entries.at(i + 1).index, &song)) {
- continue;
- }
- } else {
- // incorrect index?
- if(!UpdateLastSong(entry, &song)) {
- continue;
- }
- }
-
- ret << song;
+ // cue song has mtime equal to qMax(media_file_mtime, cue_sheet_mtime)
+ if(cue_mtime.isValid()) {
+ song.set_mtime(qMax(cue_mtime.toTime_t(), song.mtime()));
}
+ song.set_cue_path(playlist_path);
+
+ // overwrite the stuff, we may have read from the file or library, using
+ // the current .cue metadata
+
+ // set track number only in single-file mode
+ if(files == 1) {
+ song.set_track(i + 1);
+ }
+
+ // the last TRACK for every FILE gets it's 'end' marker from the media file's
+ // length
+ if(i + 1 < entries.size() && entries.at(i).file == entries.at(i + 1).file) {
+ // incorrect indices?
+ if(!UpdateSong(entry, entries.at(i + 1).index, &song)) {
+ continue;
+ }
+ } else {
+ // incorrect index?
+ if(!UpdateLastSong(entry, &song)) {
+ continue;
+ }
+ }
+
+ ret << song;
}
return ret;
diff --git a/src/playlistparsers/m3uparser.cpp b/src/playlistparsers/m3uparser.cpp
index 859a98f59..47cc9beb7 100644
--- a/src/playlistparsers/m3uparser.cpp
+++ b/src/playlistparsers/m3uparser.cpp
@@ -56,29 +56,13 @@ SongList M3UParser::Load(QIODevice* device, const QString& playlist_path, const
}
}
} else if (!line.isEmpty()) {
- Song song;
+ Song song = LoadSong(line, 0, dir);
+ song.set_title(current_metadata.title);
+ song.set_artist(current_metadata.artist);
+ song.set_length_nanosec(current_metadata.length);
+ ret << song;
- // Track location.
- if (!ParseTrackLocation(line, dir, &song)) {
- qLog(Warning) << "Failed to parse location: " << line;
- } else {
- // Load the song from the library if it's there.
- Song library_song = LoadLibrarySong(song.filename());
- if (library_song.is_valid()) {
- ret << library_song;
- } else {
- song.Init(current_metadata.title,
- current_metadata.artist,
- QString(), // Unknown album.
- current_metadata.length);
- song.InitFromFile(song.filename(), -1);
- ret << song;
- }
-
- current_metadata.artist.clear();
- current_metadata.title.clear();
- current_metadata.length = -1;
- }
+ current_metadata = Metadata();
}
if (buffer.atEnd()) {
break;
@@ -115,14 +99,14 @@ bool M3UParser::ParseMetadata(const QString& line, M3UParser::Metadata* metadata
void M3UParser::Save(const SongList &songs, QIODevice *device, const QDir &dir) const {
device->write("#EXTM3U\n");
foreach (const Song& song, songs) {
- if (song.filename().isEmpty()) {
+ if (song.url().isEmpty()) {
continue;
}
QString meta = QString("#EXTINF:%1,%2 - %3\n")
.arg(song.length_nanosec() / kNsecPerSec)
.arg(song.artist()).arg(song.title());
device->write(meta.toUtf8());
- device->write(MakeRelativeTo(song.filename(), dir).toUtf8());
+ device->write(URLOrRelativeFilename(song.url(), dir).toUtf8());
device->write("\n");
}
}
diff --git a/src/playlistparsers/parserbase.cpp b/src/playlistparsers/parserbase.cpp
index b5671e564..613e6be57 100644
--- a/src/playlistparsers/parserbase.cpp
+++ b/src/playlistparsers/parserbase.cpp
@@ -28,67 +28,72 @@ ParserBase::ParserBase(LibraryBackendInterface* library, QObject *parent)
{
}
-bool ParserBase::ParseTrackLocation(const QString& filename_or_url,
- const QDir& dir, Song* song) const {
+void ParserBase::LoadSong(const QString& filename_or_url, qint64 beginning,
+ const QDir& dir, Song* song) const {
+ if (filename_or_url.isEmpty()) {
+ return;
+ }
+
+ QString filename = filename_or_url;
+
if (filename_or_url.contains(QRegExp("^[a-z]+://"))) {
- // Looks like a url.
- QUrl temp(filename_or_url);
- if (temp.isValid()) {
- song->set_filename(temp.toString());
+ QUrl url(filename_or_url);
+ if (url.scheme() == "file") {
+ filename = url.toLocalFile();
+ } else {
+ song->set_url(QUrl(filename_or_url));
song->set_filetype(Song::Type_Stream);
song->set_valid(true);
- return true;
- } else {
- return false;
+ return;
}
}
- // Should be a local path.
- if (QDir::isAbsolutePath(filename_or_url)) {
- // Absolute path.
- // Fix windows \, eg. C:\foo -> C:/foo.
- song->set_filename(QDir::fromNativeSeparators(filename_or_url));
- } else {
- // Relative path.
- QString proper_path = QDir::fromNativeSeparators(filename_or_url);
- QString absolute_path = dir.absoluteFilePath(proper_path);
- song->set_filename(absolute_path);
+ // Convert native separators for Windows paths
+ filename = QDir::fromNativeSeparators(filename);
+
+ // Make the path absolute
+ if (!QDir::isAbsolutePath(filename)) {
+ filename = dir.absoluteFilePath(filename);
+ }
+
+ // Use the canonical path
+ if (QFile::exists(filename)) {
+ filename = QFileInfo(filename).canonicalFilePath();
+ }
+
+ const QUrl url = QUrl::fromLocalFile(filename);
+
+ // Search in the library
+ Song library_song;
+ if (library_) {
+ library_song = library_->GetSongByUrl(url, beginning);
+ }
+
+ // If it was found in the library then use it, otherwise load metadata from
+ // disk.
+ if (library_song.is_valid()) {
+ *song = library_song;
+ } else {
+ song->InitFromFile(filename, -1);
}
- return true;
}
-QString ParserBase::MakeRelativeTo(const QString& filename_or_url,
- const QDir& dir) const {
- if (filename_or_url.contains(QRegExp("^[a-z]+://")))
- return filename_or_url;
+Song ParserBase::LoadSong(const QString& filename_or_url, qint64 beginning, const QDir& dir) const {
+ Song song;
+ LoadSong(filename_or_url, beginning, dir, &song);
+ return song;
+}
- if (QDir::isAbsolutePath(filename_or_url)) {
- QString relative = dir.relativeFilePath(filename_or_url);
+QString ParserBase::URLOrRelativeFilename(const QUrl& url, const QDir& dir) const {
+ if (url.scheme() != "file")
+ return url.toString();
+
+ const QString filename = url.toLocalFile();
+ if (QDir::isAbsolutePath(filename)) {
+ const QString relative = dir.relativeFilePath(filename);
if (!relative.contains(".."))
return relative;
}
- return filename_or_url;
-}
-
-QString ParserBase::MakeUrl(const QString& filename_or_url) const {
- if (filename_or_url.contains(QRegExp("^[a-z]+://"))) {
- return filename_or_url;
- }
-
- return QUrl::fromLocalFile(filename_or_url).toString();
-}
-
-Song ParserBase::LoadLibrarySong(const QString& filename_or_url, qint64 beginning) const {
- if (!library_)
- return Song();
-
- QFileInfo info;
-
- if (filename_or_url.contains("://"))
- info.setFile(QUrl(filename_or_url).path());
- else
- info.setFile(filename_or_url);
-
- return library_->GetSongByFilename(info.canonicalFilePath(), beginning);
+ return filename;
}
diff --git a/src/playlistparsers/parserbase.h b/src/playlistparsers/parserbase.h
index 8c6f67443..793a42951 100644
--- a/src/playlistparsers/parserbase.h
+++ b/src/playlistparsers/parserbase.h
@@ -48,22 +48,19 @@ public:
virtual void Save(const SongList& songs, QIODevice* device, const QDir& dir = QDir()) const = 0;
protected:
- // Takes a URL, relative path or absolute path, and returns an absolute path.
- // Resolves relative paths to "dir".
- bool ParseTrackLocation(const QString& filename_or_url, const QDir& dir,
- Song* song) const;
+ // Loads a song. If filename_or_url is a URL (with a scheme other than
+ // "file") then it is set on the song and the song marked as a stream.
+ // 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 Library, or loading from the file as a fallback.
+ // This function should always be used when loading a playlist.
+ Song LoadSong(const QString& filename_or_url, qint64 beginning, const QDir& dir) const;
+ void LoadSong(const QString& filename_or_url, qint64 beginning, const QDir& dir, Song* song) const;
- // Takes a URL, relative path or absolute path, and in the case of absolute
- // paths makes them relative to dir if they are subdirectories.
- QString MakeRelativeTo(const QString& filename_or_url, const QDir& dir) const;
-
- // Takes a URL or absolute path and returns a URL
- QString MakeUrl(const QString& filename_or_url) const;
-
- // Converts the URL or path to a canonical path and searches the library for
- // a section of a song with that path and the given beginning. If one is found,
- // returns it, otherwise returns an invalid song.
- Song LoadLibrarySong(const QString& filename_or_url, qint64 beginning = 0) const;
+ // If the URL is a file:// URL then returns its path relative to the
+ // directory. Otherwise returns the URL as is.
+ // This function should always be used when saving a playlist.
+ QString URLOrRelativeFilename(const QUrl& url, const QDir& dir) const;
private:
LibraryBackendInterface* library_;
diff --git a/src/playlistparsers/plsparser.cpp b/src/playlistparsers/plsparser.cpp
index 1685a7e1a..ef94ef38e 100644
--- a/src/playlistparsers/plsparser.cpp
+++ b/src/playlistparsers/plsparser.cpp
@@ -40,16 +40,15 @@ SongList PLSParser::Load(QIODevice *device, const QString& playlist_path, const
int n = n_re.cap(0).toInt();
if (key.startsWith("file")) {
- if (!ParseTrackLocation(value, dir, &songs[n]))
- qLog(Warning) << "Failed to parse location: " << value;
+ Song song = LoadSong(value, 0, dir);
- // Load the song from the library if it's there.
- Song library_song = LoadLibrarySong(songs[n].filename());
- if (library_song.is_valid()) {
- songs[n] = library_song;
- } else {
- songs[n].InitFromFile(songs[n].filename(), -1);
- }
+ // 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].length_nanosec() != -1)
+ song.set_length_nanosec(songs[n].length_nanosec());
+
+ songs[n] = song;
} else if (key.startsWith("title")) {
songs[n].set_title(value);
} else if (key.startsWith("length")) {
@@ -71,7 +70,7 @@ void PLSParser::Save(const SongList &songs, QIODevice *device, const QDir &dir)
int n = 1;
foreach (const Song& song, songs) {
- s << "File" << n << "=" << MakeRelativeTo(song.filename(), dir) << endl;
+ s << "File" << n << "=" << URLOrRelativeFilename(song.url(), dir) << endl;
s << "Title" << n << "=" << song.title() << endl;
s << "Length" << n << "=" << song.length_nanosec() / kNsecPerSec << endl;
++n;
diff --git a/src/playlistparsers/xspfparser.cpp b/src/playlistparsers/xspfparser.cpp
index 9f9f3257e..468fff829 100644
--- a/src/playlistparsers/xspfparser.cpp
+++ b/src/playlistparsers/xspfparser.cpp
@@ -29,7 +29,8 @@ XSPFParser::XSPFParser(LibraryBackendInterface* library, QObject* parent)
{
}
-SongList XSPFParser::Load(QIODevice *device, const QString& playlist_path, const QDir&) const {
+SongList XSPFParser::Load(QIODevice *device, const QString& playlist_path,
+ const QDir& dir) const {
SongList ret;
QXmlStreamReader reader(device);
@@ -39,7 +40,7 @@ SongList XSPFParser::Load(QIODevice *device, const QString& playlist_path, const
}
while (!reader.atEnd() && ParseUntilElement(&reader, "track")) {
- Song song = ParseTrack(&reader);
+ Song song = ParseTrack(&reader, dir);
if (song.is_valid()) {
ret << song;
}
@@ -47,34 +48,17 @@ SongList XSPFParser::Load(QIODevice *device, const QString& playlist_path, const
return ret;
}
-Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
- Song song;
- QString title, artist, album;
+Song XSPFParser::ParseTrack(QXmlStreamReader* reader, const QDir& dir) const {
+ QString title, artist, album, location;
qint64 nanosec = -1;
+
while (!reader->atEnd()) {
QXmlStreamReader::TokenType type = reader->readNext();
switch (type) {
case QXmlStreamReader::StartElement: {
QStringRef name = reader->name();
if (name == "location") {
- QUrl url(reader->readElementText());
- if (url.scheme() == "file") {
- QString filename = url.toLocalFile();
- if (!QFile::exists(filename)) {
- return Song();
- }
-
- // Load the song from the library if it's there.
- Song library_song = LoadLibrarySong(filename);
- if (library_song.is_valid())
- return library_song;
-
- song.InitFromFile(filename, -1);
- return song;
- } else {
- song.set_filename(url.toString());
- song.set_filetype(Song::Type_Stream);
- }
+ location = reader->readElementText();
} else if (name == "title") {
title = reader->readElementText();
} else if (name == "creator") {
@@ -82,7 +66,7 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
} else if (name == "album") {
album = reader->readElementText();
} else if (name == "duration") { // in milliseconds.
- const QString& duration = reader->readElementText();
+ const QString duration = reader->readElementText();
bool ok = false;
nanosec = duration.toInt(&ok) * kNsecPerMsec;
if (!ok) {
@@ -97,16 +81,22 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
}
case QXmlStreamReader::EndElement: {
if (reader->name() == "track") {
- song.Init(title, artist, album, nanosec);
- return song;
+ goto return_song;
}
}
default:
break;
}
}
- // At least make an effort if we never find a .
- song.Init(title, artist, album, nanosec);
+
+return_song:
+ Song song = LoadSong(location, 0, dir);
+
+ // Override metadata with what was in the playlist
+ song.set_title(title);
+ song.set_artist(artist);
+ song.set_album(album);
+ song.set_length_nanosec(nanosec);
return song;
}
@@ -120,7 +110,7 @@ void XSPFParser::Save(const SongList& songs, QIODevice* device, const QDir&) con
StreamElement tracklist("trackList", &writer);
foreach (const Song& song, songs) {
StreamElement track("track", &writer);
- writer.writeTextElement("location", MakeUrl(song.filename()));
+ writer.writeTextElement("location", song.url().toString());
writer.writeTextElement("title", song.title());
if (!song.artist().isEmpty()) {
writer.writeTextElement("creator", song.artist());
@@ -136,7 +126,9 @@ void XSPFParser::Save(const SongList& songs, QIODevice* device, const QDir&) con
// Ignore images that are in our resource bundle.
if (!art.startsWith(":") && !art.isEmpty()) {
// Convert local files to URLs.
- art = MakeUrl(art);
+ if (!art.contains("://")) {
+ art = QUrl::fromLocalFile(art).toString();
+ }
writer.writeTextElement("image", art);
}
}
diff --git a/src/playlistparsers/xspfparser.h b/src/playlistparsers/xspfparser.h
index 29f465fd4..14ea42446 100644
--- a/src/playlistparsers/xspfparser.h
+++ b/src/playlistparsers/xspfparser.h
@@ -36,11 +36,12 @@ class XSPFParser : public XMLParser {
bool TryMagic(const QByteArray &data) const;
- SongList Load(QIODevice *device, const QString& playlist_path = "", const QDir &dir = QDir()) const;
+ SongList Load(QIODevice *device, const QString& playlist_path = "",
+ const QDir& dir = QDir()) const;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir()) const;
private:
- Song ParseTrack(QXmlStreamReader* reader) const;
+ Song ParseTrack(QXmlStreamReader* reader, const QDir& dir) const;
};
#endif
diff --git a/src/radio/icecastbackend.cpp b/src/radio/icecastbackend.cpp
index d546604ce..4707484af 100644
--- a/src/radio/icecastbackend.cpp
+++ b/src/radio/icecastbackend.cpp
@@ -177,7 +177,7 @@ Song IcecastBackend::Station::ToSong() const {
Song ret;
ret.set_valid(true);
ret.set_title(name);
- ret.set_filename(url.toEncoded());
+ ret.set_url(url);
ret.set_bitrate(bitrate);
ret.set_samplerate(samplerate);
ret.set_genre(genre);
diff --git a/src/radio/jamendoplaylistitem.cpp b/src/radio/jamendoplaylistitem.cpp
index 8f8da9c66..01755e7e7 100644
--- a/src/radio/jamendoplaylistitem.cpp
+++ b/src/radio/jamendoplaylistitem.cpp
@@ -36,5 +36,5 @@ bool JamendoPlaylistItem::InitFromQuery(const SqlRow& query) {
}
QUrl JamendoPlaylistItem::Url() const {
- return QUrl::fromEncoded(song_.filename().toAscii());
+ return song_.url();
}
diff --git a/src/radio/jamendoservice.cpp b/src/radio/jamendoservice.cpp
index 5fcfc3ec8..bdacef636 100644
--- a/src/radio/jamendoservice.cpp
+++ b/src/radio/jamendoservice.cpp
@@ -364,7 +364,7 @@ Song JamendoService::ReadTrack(const QString& artist,
continue;
QString ogg_url = QString(kOggStreamUrl).arg(id_text);
- song.set_filename(ogg_url);
+ song.set_url(QUrl(ogg_url));
song.set_art_automatic(album_cover);
song.set_valid(true);
diff --git a/src/radio/lastfmservice.cpp b/src/radio/lastfmservice.cpp
index 29ac2ef49..f71cfa1aa 100644
--- a/src/radio/lastfmservice.cpp
+++ b/src/radio/lastfmservice.cpp
@@ -148,22 +148,22 @@ void LastFMService::LazyPopulate(QStandardItem* parent) {
CreateStationItem(parent,
tr("My Recommendations"),
":last.fm/recommended_radio.png",
- "lastfm://user/USERNAME/recommended",
+ QUrl("lastfm://user/USERNAME/recommended"),
tr("My Last.fm Recommended Radio"));
CreateStationItem(parent,
tr("My Radio Station"),
":last.fm/personal_radio.png",
- "lastfm://user/USERNAME/library",
+ QUrl("lastfm://user/USERNAME/library"),
tr("My Last.fm Library"));
CreateStationItem(parent,
tr("My Mix Radio"),
":last.fm/loved_radio.png",
- "lastfm://user/USERNAME/mix",
+ QUrl("lastfm://user/USERNAME/mix"),
tr("My Last.fm Mix Radio"));
CreateStationItem(parent,
tr("My Neighborhood"),
":last.fm/neighbour_radio.png",
- "lastfm://user/USERNAME/neighbours",
+ QUrl("lastfm://user/USERNAME/neighbours"),
tr("My Last.fm Neighborhood"));
// Types that have children
@@ -213,17 +213,17 @@ void LastFMService::LazyPopulate(QStandardItem* parent) {
CreateStationItem(parent,
tr("Last.fm Radio Station - %1").arg(parent->text()),
":last.fm/personal_radio.png",
- "lastfm://user/" + parent->text() + "/library",
+ QUrl("lastfm://user/" + parent->text() + "/library"),
tr("Last.fm Library - %1").arg(parent->text()));
CreateStationItem(parent,
tr("Last.fm Mix Radio - %1").arg(parent->text()),
":last.fm/loved_radio.png",
- "lastfm://user/" + parent->text() + "/mix",
+ QUrl("lastfm://user/" + parent->text() + "/mix"),
tr("Last.fm Mix Radio - %1").arg(parent->text()));
CreateStationItem(parent,
tr("Last.fm Neighbor Radio - %1").arg(parent->text()),
":last.fm/neighbour_radio.png",
- "lastfm://user/" + parent->text() + "/neighbours",
+ QUrl("lastfm://user/" + parent->text() + "/neighbours"),
tr("Last.fm Neighbor Radio - %1").arg(parent->text()));
break;
@@ -234,9 +234,9 @@ void LastFMService::LazyPopulate(QStandardItem* parent) {
QStandardItem* LastFMService::CreateStationItem(
QStandardItem* parent, const QString& name, const QString& icon,
- const QString& url, const QString& title) {
+ const QUrl& url, const QString& title) {
Song song;
- song.set_filename(url);
+ song.set_url(url);
song.set_title(title);
QStandardItem* ret = new QStandardItem(QIcon(icon), name);
@@ -625,7 +625,7 @@ void LastFMService::RefreshFriendsFinished() {
foreach (const lastfm::User& f, friends) {
Song song;
- song.set_filename("lastfm://user/" + f.name() + "/library");
+ song.set_url(QUrl("lastfm://user/" + f.name() + "/library"));
song.set_title(tr("Last.fm Library - %1").arg(f.name()));
QStandardItem* item = new QStandardItem(QIcon(":last.fm/icon_user.png"), f.name());
@@ -657,7 +657,7 @@ void LastFMService::RefreshNeighboursFinished() {
foreach (const lastfm::User& n, neighbours) {
Song song;
- song.set_filename("lastfm://user/" + n.name() + "/library");
+ song.set_url(QUrl("lastfm://user/" + n.name() + "/library"));
song.set_title(tr("Last.fm Library - %1").arg(n.name()));
QStandardItem* item = new QStandardItem(QIcon(":last.fm/user_purple.png"), n.name());
@@ -711,7 +711,7 @@ void LastFMService::AddArtistOrTag(const QString& name,
url_content = content;
Song song;
- song.set_filename(url_pattern.arg(url_content));
+ song.set_url(QUrl(url_pattern.arg(url_content)));
song.set_title(title_pattern.arg(content));
QStandardItem* item = new QStandardItem(QIcon(icon), content);
@@ -756,7 +756,7 @@ void LastFMService::RestoreList(const QString& name,
url_content = content;
Song song;
- song.set_filename(url_pattern.arg(url_content));
+ song.set_url(QUrl(url_pattern.arg(url_content)));
song.set_title(title_pattern.arg(content));
QStandardItem* item = new QStandardItem(icon, content);
@@ -881,7 +881,7 @@ PlaylistItemPtr LastFMService::PlaylistItemForUrl(const QUrl& url) {
QStringList sections(url.path().split("/", QString::SkipEmptyParts));
Song song;
- song.set_filename(url.toString());
+ song.set_url(url);
if (sections.count() == 2 && url.host() == "artist" && sections[1] == "similarartists") {
song.set_title(tr(kTitleArtist).arg(sections[0]));
diff --git a/src/radio/lastfmservice.h b/src/radio/lastfmservice.h
index d5a4b373e..f45b595e1 100644
--- a/src/radio/lastfmservice.h
+++ b/src/radio/lastfmservice.h
@@ -150,7 +150,7 @@ class LastFMService : public RadioService {
private:
QStandardItem* CreateStationItem(QStandardItem* parent,
- const QString& name, const QString& icon, const QString& url,
+ const QString& name, const QString& icon, const QUrl& url,
const QString& title);
QString ErrorString(lastfm::ws::Error error) const;
bool InitScrobbler();
diff --git a/src/radio/magnatuneplaylistitem.cpp b/src/radio/magnatuneplaylistitem.cpp
index 8a434e3ce..e7a8ccfe8 100644
--- a/src/radio/magnatuneplaylistitem.cpp
+++ b/src/radio/magnatuneplaylistitem.cpp
@@ -42,7 +42,7 @@ PlaylistItem::Options MagnatunePlaylistItem::options() const {
}
QUrl MagnatunePlaylistItem::Url() const {
- return QUrl::fromEncoded(song_.filename().toAscii());
+ return song_.url();
}
PlaylistItem::SpecialLoadResult MagnatunePlaylistItem::StartLoading() {
diff --git a/src/radio/magnatuneservice.cpp b/src/radio/magnatuneservice.cpp
index 240fc3503..c07fc87c9 100644
--- a/src/radio/magnatuneservice.cpp
+++ b/src/radio/magnatuneservice.cpp
@@ -205,7 +205,7 @@ Song MagnatuneService::ReadTrack(QXmlStreamReader& reader) {
if (name == "year") song.set_year(value.toInt());
if (name == "magnatunegenres") song.set_genre(value.section(',', 0, 0));
if (name == "seconds") song.set_length_nanosec(value.toInt() * kNsecPerSec);
- if (name == "url") song.set_filename(value);
+ if (name == "url") song.set_url(QUrl(value));
if (name == "cover_small") song.set_art_automatic(value);
if (name == "albumsku") song.set_comment(value);
}
diff --git a/src/radio/radioplaylistitem.cpp b/src/radio/radioplaylistitem.cpp
index 2c52c8338..5670549c0 100644
--- a/src/radio/radioplaylistitem.cpp
+++ b/src/radio/radioplaylistitem.cpp
@@ -77,7 +77,7 @@ QVariant RadioPlaylistItem::DatabaseValue(DatabaseColumn column) const {
void RadioPlaylistItem::InitMetadata() {
if (metadata_.title().isEmpty())
- metadata_.set_title(metadata_.filename());
+ metadata_.set_title(metadata_.url().toString());
metadata_.set_filetype(Song::Type_Stream);
metadata_.set_valid(true);
}
@@ -108,7 +108,7 @@ PlaylistItem::SpecialLoadResult RadioPlaylistItem::LoadNext() {
}
QUrl RadioPlaylistItem::Url() const {
- return QUrl(metadata_.filename());
+ return metadata_.url();
}
PlaylistItem::Options RadioPlaylistItem::options() const {
diff --git a/src/radio/somafmservice.cpp b/src/radio/somafmservice.cpp
index 79bcdb407..c2ad1ada8 100644
--- a/src/radio/somafmservice.cpp
+++ b/src/radio/somafmservice.cpp
@@ -181,7 +181,7 @@ void SomaFMService::ReadChannel(QXmlStreamReader& reader) {
} else if (reader.name() == "dj") {
song.set_artist(reader.readElementText());
} else if (reader.name() == "fastpls" && reader.attributes().value("format") == "mp3") {
- song.set_filename(reader.readElementText());
+ song.set_url(QUrl(reader.readElementText()));
} else {
ConsumeElement(reader);
}
diff --git a/src/radio/spotifyservice.cpp b/src/radio/spotifyservice.cpp
index b1eeb7556..267f9a3bb 100644
--- a/src/radio/spotifyservice.cpp
+++ b/src/radio/spotifyservice.cpp
@@ -278,7 +278,7 @@ void SpotifyService::FillPlaylist(QStandardItem* item, const protobuf::LoadPlayl
child->setData(Type_Track, RadioModel::Role_Type);
child->setData(QVariant::fromValue(song), RadioModel::Role_SongMetadata);
child->setData(RadioModel::PlayBehaviour_SingleItem, RadioModel::Role_PlayBehaviour);
- child->setData(QUrl(song.filename()), RadioModel::Role_Url);
+ child->setData(song.url(), RadioModel::Role_Url);
item->appendRow(child);
}
@@ -293,7 +293,7 @@ void SpotifyService::SongFromProtobuf(const protobuf::Track& track, Song* song)
song->set_disc(track.disc());
song->set_track(track.track());
song->set_year(track.year());
- song->set_filename(QStringFromStdString(track.uri()));
+ song->set_url(QUrl(QStringFromStdString(track.uri())));
QStringList artists;
for (int i=0 ; i AlbumList;
@@ -33,7 +33,7 @@ public:
SongList FindSongsInDirectory(int id);
SubdirectoryList SubdirsInDirectory(int id);
DirectoryList GetAllDirectories();
- void ChangeDirPath(int id, const QString& new_path);
+ void ChangeDirPath(int id, const QString& old_path, const QString& new_path);
QStringList GetAll(const QString& column, const QueryOptions& opt = QueryOptions());
QStringList GetAllArtists(const QueryOptions& opt = QueryOptions());
@@ -56,8 +56,8 @@ public:
SongList GetSongsByForeignId(const QStringList& ids, const QString& table,
const QString& column);
- SongList GetSongsByFilename(const QString& filename);
- Song GetSongByFilename(const QString& filename, int beginning);
+ SongList GetSongsByUrl(const QUrl& url);
+ Song GetSongByUrl(const QUrl& url, int beginning);
void AddDirectory(const QString& path);
void RemoveDirectory(const Directory& dir);
diff --git a/src/scripting/python/song.sip b/src/scripting/python/song.sip
index d54548d3a..530a29cca 100644
--- a/src/scripting/python/song.sip
+++ b/src/scripting/python/song.sip
@@ -308,22 +308,16 @@ The ID in the L{LibraryBackend} of the directory containing this song, or -1 if
the song is not from the library.
%End
- const QString& filename() const;
+ const QUrl& url() const;
%Docstring
-filename() -> str
-The filename I{or URL} of this song.
+url() -> L{PyQt4.QtCore.QUrl}
+The URL of this song.
%End
const QString& basefilename() const;
%Docstring
basefilename() -> str
The filename of this song without any directory component.
-%End
-
- QUrl url() const;
-%Docstring
-url() -> L{PyQt4.QtCore.QUrl}
-URL for this song which may point either to a file or to another type of stream.
%End
uint mtime() const;
@@ -658,9 +652,9 @@ set_lastplayed(lastplayed)
set_score(score)
%End
- void set_filename(const QString& v);
+ void set_url(const QUrl& v);
%Docstring
-set_filename(filename)
+set_url(url)
%End
void set_basefilename(const QString& v);
diff --git a/src/ui/albumcoverchoicecontroller.cpp b/src/ui/albumcoverchoicecontroller.cpp
index 98608a8d0..d9c88fbc9 100644
--- a/src/ui/albumcoverchoicecontroller.cpp
+++ b/src/ui/albumcoverchoicecontroller.cpp
@@ -130,8 +130,8 @@ QString AlbumCoverChoiceController::GetInitialPathForFileDialog(const Song& song
return song.art_automatic();
// if no automatic art, start in the song's folder
- } else if (!song.filename().isEmpty() && song.filename().contains('/')) {
- return song.filename().section('/', 0, -2) + filename;
+ } else if (!song.url().isEmpty() && song.url().toLocalFile().contains('/')) {
+ return song.url().toLocalFile().section('/', 0, -2) + filename;
// fallback - start in home
} else {
@@ -189,7 +189,7 @@ void AlbumCoverChoiceController::ShowCover(const Song& song) {
QLabel* label = new QLabel(dialog);
label->setPixmap(AlbumCoverLoader::TryLoadPixmap(
- song.art_automatic(), song.art_manual(), song.filename()));
+ song.art_automatic(), song.art_manual(), song.url().toLocalFile()));
dialog->resize(label->pixmap()->size());
dialog->show();
diff --git a/src/ui/albumcovermanager.cpp b/src/ui/albumcovermanager.cpp
index edc839678..d7b5a802b 100644
--- a/src/ui/albumcovermanager.cpp
+++ b/src/ui/albumcovermanager.cpp
@@ -293,14 +293,14 @@ void AlbumCoverManager::ArtistChanged(QListWidgetItem* current) {
QListWidgetItem* item = new QListWidgetItem(no_cover_icon_, info.album_name, ui_->albums);
item->setData(Role_ArtistName, info.artist);
item->setData(Role_AlbumName, info.album_name);
- item->setData(Role_FirstFilename, info.first_filename);
+ item->setData(Role_FirstUrl, info.first_url);
item->setData(Qt::TextAlignmentRole, QVariant(Qt::AlignTop | Qt::AlignHCenter));
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
item->setToolTip(info.artist + " - " + info.album_name);
if (!info.art_automatic.isEmpty() || !info.art_manual.isEmpty()) {
quint64 id = cover_loader_->Worker()->LoadImageAsync(
- info.art_automatic, info.art_manual, info.first_filename);
+ info.art_automatic, info.art_manual, info.first_url.toLocalFile());
item->setData(Role_PathAutomatic, info.art_automatic);
item->setData(Role_PathManual, info.art_manual);
cover_loading_tasks_[id] = item;
@@ -487,7 +487,7 @@ Song AlbumCoverManager::ItemAsSong(QListWidgetItem* item) {
result.set_artist(item->data(Role_ArtistName).toString());
result.set_album(item->data(Role_AlbumName).toString());
- result.set_filename(item->data(Role_FirstFilename).toString());
+ result.set_url(item->data(Role_FirstUrl).toUrl());
result.set_art_automatic(item->data(Role_PathAutomatic).toString());
result.set_art_manual(item->data(Role_PathManual).toString());
diff --git a/src/ui/albumcovermanager.h b/src/ui/albumcovermanager.h
index c8a321de2..c4c1c3170 100644
--- a/src/ui/albumcovermanager.h
+++ b/src/ui/albumcovermanager.h
@@ -110,7 +110,7 @@ class AlbumCoverManager : public QMainWindow {
Role_AlbumName,
Role_PathAutomatic,
Role_PathManual,
- Role_FirstFilename,
+ Role_FirstUrl,
};
enum HideCovers {
diff --git a/src/ui/albumcovermanagerlist.cpp b/src/ui/albumcovermanagerlist.cpp
index 4314f1a67..0d54b58b8 100644
--- a/src/ui/albumcovermanagerlist.cpp
+++ b/src/ui/albumcovermanagerlist.cpp
@@ -43,7 +43,7 @@ QMimeData* AlbumCoverManagerList::mimeData(const QList items)
// Get URLs from the songs
QList urls;
foreach (const Song& song, songs) {
- urls << QUrl::fromLocalFile(song.filename());
+ urls << song.url();
}
// Get the QAbstractItemModel data so the picture works
diff --git a/src/ui/edittagdialog.cpp b/src/ui/edittagdialog.cpp
index 3223f4f6d..75075fe4d 100644
--- a/src/ui/edittagdialog.cpp
+++ b/src/ui/edittagdialog.cpp
@@ -191,7 +191,7 @@ QList EditTagDialog::LoadData(const SongList& songs) const
if (song.IsEditable()) {
// Try reloading the tags from file
Song copy(song);
- copy.InitFromFile(copy.filename(), copy.directory_id());
+ copy.InitFromFile(copy.url().toLocalFile(), copy.directory_id());
if (copy.is_valid())
ret << Data(copy);
@@ -424,7 +424,11 @@ void EditTagDialog::UpdateSummaryTab(const Song& song) {
QLocale::system().dateTimeFormat(QLocale::LongFormat)));
ui_->filesize->setText(Utilities::PrettySize(song.filesize()));
ui_->filetype->setText(song.TextForFiletype());
- ui_->filename->setText(QDir::toNativeSeparators(song.filename()));
+
+ if (song.url().scheme() == "file")
+ ui_->filename->setText(QDir::toNativeSeparators(song.url().toLocalFile()));
+ else
+ ui_->filename->setText(song.url().toString());
album_cover_choice_controller_->search_for_cover_action()->setEnabled(CoverProviders::instance().HasAnyProviders());
}
@@ -602,7 +606,7 @@ void EditTagDialog::SaveData(const QList& data) {
continue;
if (!ref.current_.Save()) {
- emit Error(tr("An error occurred writing metadata to '%1'").arg(ref.current_.filename()));
+ emit Error(tr("An error occurred writing metadata to '%1'").arg(ref.current_.url().toLocalFile()));
}
}
}
@@ -736,12 +740,12 @@ void EditTagDialog::FetchTag() {
}
void EditTagDialog::FetchTagSongChosen(const Song& original_song, const Song& new_metadata) {
- const QString filename = original_song.filename();
+ const QString filename = original_song.url().toLocalFile();
// Find the song with this filename
for (int i=0 ; ioriginal_.filename() != filename)
+ if (data->original_.url().toLocalFile() != filename)
continue;
// Is it currently being displayed in the UI?
diff --git a/src/ui/organisedialog.cpp b/src/ui/organisedialog.cpp
index 7bff6fa26..ea0324166 100644
--- a/src/ui/organisedialog.cpp
+++ b/src/ui/organisedialog.cpp
@@ -106,19 +106,13 @@ int OrganiseDialog::SetSongs(const SongList& songs) {
preview_songs_.clear();
foreach (const Song& song, songs) {
- const QString filename = song.filename();
-
- if (filename.isEmpty())
+ if (song.url().scheme() != "file") {
continue;
- if (filename.contains("://")) {
- QUrl url(song.filename());
- if (!url.scheme().isEmpty() && url.scheme() != "file")
- continue;
- }
+ };
if (song.filesize() > 0)
total_size_ += song.filesize();
- filenames_ << filename;
+ filenames_ << song.url().toLocalFile();
if (preview_songs_.count() < kNumberOfPreviews)
preview_songs_ << song;
diff --git a/src/ui/organiseerrordialog.cpp b/src/ui/organiseerrordialog.cpp
index ccf12c02b..b67ee4d29 100644
--- a/src/ui/organiseerrordialog.cpp
+++ b/src/ui/organiseerrordialog.cpp
@@ -38,7 +38,7 @@ void OrganiseErrorDialog::Show(
OperationType type, const SongList& songs_with_errors) {
QStringList files;
foreach (const Song& song, songs_with_errors) {
- files << song.filename();
+ files << song.url().toLocalFile();
}
Show(type, files);
}
diff --git a/src/ui/trackselectiondialog.cpp b/src/ui/trackselectiondialog.cpp
index 80d7e4b29..1222c4112 100644
--- a/src/ui/trackselectiondialog.cpp
+++ b/src/ui/trackselectiondialog.cpp
@@ -77,7 +77,7 @@ void TrackSelectionDialog::Init(const SongList& songs) {
data_ << data;
QListWidgetItem* item = new QListWidgetItem(ui_->song_list);
- item->setText(QFileInfo(song.filename()).fileName());
+ item->setText(QFileInfo(song.url().toLocalFile()).fileName());
item->setForeground(palette().color(QPalette::Disabled, QPalette::Text));
}
@@ -94,7 +94,7 @@ void TrackSelectionDialog::FetchTagProgress(const Song& original_song,
// Find the item with this filename
int row = -1;
for (int i=0 ; iAddOrUpdateSongs(SongList() << s);
ASSERT_EQ(1, spy.count()); spy.takeFirst();
- s.set_filename("foo");
+ s.set_url(QUrl::fromLocalFile("foo"));
backend_->AddOrUpdateSongs(SongList() << s);
ASSERT_EQ(1, spy.count()); spy.takeFirst();
diff --git a/tests/librarymodel_test.cpp b/tests/librarymodel_test.cpp
index 3f6388193..bd7bb2441 100644
--- a/tests/librarymodel_test.cpp
+++ b/tests/librarymodel_test.cpp
@@ -52,7 +52,7 @@ class LibraryModelTest : public ::testing::Test {
song.set_directory_id(1);
if (song.mtime() == -1) song.set_mtime(1);
if (song.ctime() == -1) song.set_ctime(1);
- if (song.filename().isNull()) song.set_filename("/tmp/foo");
+ if (song.url().isEmpty()) song.set_url(QUrl("file:///tmp/foo"));
if (song.filesize() == -1) song.set_filesize(1);
if (!added_dir_) {
diff --git a/tests/m3uparser_test.cpp b/tests/m3uparser_test.cpp
index 0d71549ae..d6020647f 100644
--- a/tests/m3uparser_test.cpp
+++ b/tests/m3uparser_test.cpp
@@ -56,10 +56,10 @@ TEST_F(M3UParserTest, ParsesTrackLocation) {
taglib_.ExpectCall(temp.fileName(), "foo", "bar", "baz");
Song song(&taglib_);
QString line(temp.fileName());
- ASSERT_TRUE(parser_.ParseTrackLocation(line, QDir(), &song));
- ASSERT_EQ(temp.fileName(), song.filename());
+ parser_.LoadSong(line, 0, QDir(), &song);
+ ASSERT_EQ(QUrl::fromLocalFile(temp.fileName()), song.url());
- song.InitFromFile(song.filename(), -1);
+ song.InitFromFile(song.url().toLocalFile(), -1);
EXPECT_EQ("foo", song.title());
EXPECT_EQ("bar", song.artist());
@@ -74,10 +74,10 @@ TEST_F(M3UParserTest, ParsesTrackLocationRelative) {
M3UParser parser(NULL);
QString line(info.fileName());
Song song(&taglib_);
- ASSERT_TRUE(parser.ParseTrackLocation(line, info.dir(), &song));
- ASSERT_EQ(temp.fileName(), song.filename());
+ parser.LoadSong(line, 0, info.dir(), &song);
+ ASSERT_EQ(QUrl::fromLocalFile(temp.fileName()), song.url());
- song.InitFromFile(song.filename(), -1);
+ song.InitFromFile(song.url().toLocalFile(), -1);
EXPECT_EQ("foo", song.title());
}
@@ -85,8 +85,8 @@ TEST_F(M3UParserTest, ParsesTrackLocationRelative) {
TEST_F(M3UParserTest, ParsesTrackLocationHttp) {
QString line("http://example.com/foo/bar.mp3");
Song song;
- ASSERT_TRUE(parser_.ParseTrackLocation(line, QDir(), &song));
- EXPECT_EQ("http://example.com/foo/bar.mp3", song.filename());
+ parser_.LoadSong(line, 0, QDir(), &song);
+ EXPECT_EQ(QUrl("http://example.com/foo/bar.mp3"), song.url());
}
TEST_F(M3UParserTest, ParsesSongsFromDevice) {
@@ -102,8 +102,7 @@ TEST_F(M3UParserTest, ParsesSongsFromDevice) {
EXPECT_EQ("Some Artist", s.artist());
EXPECT_EQ("Some Title", s.title());
EXPECT_EQ(123 * kNsecPerSec, s.length_nanosec());
- EXPECT_PRED_FORMAT2(::testing::IsSubstring,
- "http://foo.com/bar/somefile.mp3", s.filename().toStdString());
+ EXPECT_EQ(QUrl("http://foo.com/bar/somefile.mp3"), s.url());
}
TEST_F(M3UParserTest, ParsesNonExtendedM3U) {
@@ -114,10 +113,8 @@ TEST_F(M3UParserTest, ParsesNonExtendedM3U) {
M3UParser parser(NULL);
SongList songs = parser.Load(&buffer, "", QDir("somedir"));
ASSERT_EQ(2, songs.size());
- EXPECT_PRED_FORMAT2(::testing::IsSubstring,
- "http://foo.com/bar/somefile.mp3", songs[0].filename().toStdString());
- EXPECT_PRED_FORMAT2(::testing::IsSubstring,
- "http://baz.com/thing.mp3", songs[1].filename().toStdString());
+ EXPECT_EQ(QUrl("http://foo.com/bar/somefile.mp3"), songs[0].url());
+ EXPECT_EQ(QUrl("http://baz.com/thing.mp3"), songs[1].url());
EXPECT_EQ(-1, songs[0].length_nanosec());
EXPECT_EQ(-1, songs[1].length_nanosec());
EXPECT_TRUE(songs[0].artist().isEmpty());
@@ -144,7 +141,7 @@ TEST_F(M3UParserTest, SavesSong) {
one.set_title("foo");
one.set_artist("bar");
one.set_length_nanosec(123 * kNsecPerSec);
- one.set_filename("http://www.example.com/foo.mp3");
+ one.set_url(QUrl("http://www.example.com/foo.mp3"));
SongList songs;
songs << one;
M3UParser parser(NULL);
@@ -167,5 +164,6 @@ TEST_F(M3UParserTest, ParsesUTF8) {
EXPECT_EQ(11, songs[0].title().length());
EXPECT_EQ(QString::fromUtf8("Разные"), songs[0].artist());
EXPECT_EQ(QString::fromUtf8("исполнители"), songs[0].title());
- EXPECT_EQ(QString::fromUtf8("/foo/Разные/исполнители.mp3"), songs[0].filename());
+ EXPECT_EQ(QUrl::fromLocalFile(QString::fromUtf8("/foo/Разные/исполнители.mp3")),
+ songs[0].url());
}
diff --git a/tests/mock_librarybackend.h b/tests/mock_librarybackend.h
index 9141af834..314f74c9a 100644
--- a/tests/mock_librarybackend.h
+++ b/tests/mock_librarybackend.h
@@ -33,7 +33,7 @@ class MockLibraryBackend : public LibraryBackendInterface {
MOCK_METHOD1(FindSongsInDirectory, SongList(int));
MOCK_METHOD1(SubdirsInDirectory, SubdirectoryList(int));
MOCK_METHOD0(GetAllDirectories, DirectoryList());
- MOCK_METHOD2(ChangeDirPath, void(int, const QString&));
+ MOCK_METHOD3(ChangeDirPath, void(int, const QString&, const QString&));
MOCK_METHOD1(GetAllArtists, QStringList(const QueryOptions&));
MOCK_METHOD1(GetAllArtistsWithAlbums, QStringList(const QueryOptions&));
@@ -51,8 +51,8 @@ class MockLibraryBackend : public LibraryBackendInterface {
MOCK_METHOD1(GetSongById, Song(int));
- MOCK_METHOD1(GetSongsByFilename, SongList(const QString&));
- MOCK_METHOD2(GetSongByFilename, Song(const QString&, qint64));
+ MOCK_METHOD1(GetSongsByUrl, SongList(const QUrl&));
+ MOCK_METHOD2(GetSongByUrl, Song(const QUrl&, qint64));
MOCK_METHOD1(AddDirectory, void(const QString&));
MOCK_METHOD1(RemoveDirectory, void(const Directory&));
diff --git a/tests/organiseformat_test.cpp b/tests/organiseformat_test.cpp
index 1e01c9ff9..8d7d58c0e 100644
--- a/tests/organiseformat_test.cpp
+++ b/tests/organiseformat_test.cpp
@@ -52,7 +52,7 @@ TEST_F(OrganiseFormatTest, BasicReplace) {
}
TEST_F(OrganiseFormatTest, Extension) {
- song_.set_filename("/some/path/filename.mp3");
+ song_.set_url(QUrl("file:///some/path/filename.mp3"));
format_.set_format("%extension");
ASSERT_TRUE(format_.IsValid());
diff --git a/tests/plsparser_test.cpp b/tests/plsparser_test.cpp
index 1815b1497..4d56211ae 100644
--- a/tests/plsparser_test.cpp
+++ b/tests/plsparser_test.cpp
@@ -48,7 +48,7 @@ TEST_F(PLSParserTest, ParseOneTrack) {
SongList songs = parser_.Load(file.get(), "", QDir("/relative/to/"));
ASSERT_EQ(1, songs.length());
- EXPECT_EQ("/relative/to/filename with spaces.mp3", songs[0].filename());
+ EXPECT_EQ(QUrl("file:///relative/to/filename with spaces.mp3"), songs[0].url());
EXPECT_EQ("Title", songs[0].title());
EXPECT_EQ(123 * kNsecPerSec, songs[0].length_nanosec());
}
@@ -58,10 +58,10 @@ TEST_F(PLSParserTest, ParseSomaFM) {
SongList songs = parser_.Load(file.get());
ASSERT_EQ(4, songs.length());
- EXPECT_EQ("http://streamer-dtc-aa05.somafm.com:80/stream/1018", songs[0].filename());
- EXPECT_EQ("http://streamer-mtc-aa03.somafm.com:80/stream/1018", songs[1].filename());
- EXPECT_EQ("http://streamer-ntc-aa04.somafm.com:80/stream/1018", songs[2].filename());
- EXPECT_EQ("http://ice.somafm.com/groovesalad", songs[3].filename());
+ EXPECT_EQ(QUrl("http://streamer-dtc-aa05.somafm.com:80/stream/1018"), songs[0].url());
+ EXPECT_EQ(QUrl("http://streamer-mtc-aa03.somafm.com:80/stream/1018"), songs[1].url());
+ EXPECT_EQ(QUrl("http://streamer-ntc-aa04.somafm.com:80/stream/1018"), songs[2].url());
+ EXPECT_EQ(QUrl("http://ice.somafm.com/groovesalad"), songs[3].url());
EXPECT_EQ("SomaFM: Groove Salad (#1 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[0].title());
EXPECT_EQ("SomaFM: Groove Salad (#2 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[1].title());
EXPECT_EQ("SomaFM: Groove Salad (#3 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[2].title());
@@ -74,10 +74,10 @@ TEST_F(PLSParserTest, ParseSomaFM2) {
SongList songs = parser_.Load(file.get());
ASSERT_EQ(4, songs.length());
- EXPECT_EQ("http://streamer-ntc-aa03.somafm.com:80/stream/1021", songs[0].filename());
- EXPECT_EQ("http://streamer-mtc-aa04.somafm.com:80/stream/1021", songs[1].filename());
- EXPECT_EQ("http://streamer-dtc-aa05.somafm.com:80/stream/1021", songs[2].filename());
- EXPECT_EQ("http://ice.somafm.com/secretagent", songs[3].filename());
+ EXPECT_EQ(QUrl("http://streamer-ntc-aa03.somafm.com:80/stream/1021"), songs[0].url());
+ EXPECT_EQ(QUrl("http://streamer-mtc-aa04.somafm.com:80/stream/1021"), songs[1].url());
+ EXPECT_EQ(QUrl("http://streamer-dtc-aa05.somafm.com:80/stream/1021"), songs[2].url());
+ EXPECT_EQ(QUrl("http://ice.somafm.com/secretagent"), songs[3].url());
EXPECT_EQ("SomaFM: Secret Agent (#1 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[0].title());
EXPECT_EQ("SomaFM: Secret Agent (#2 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[1].title());
EXPECT_EQ("SomaFM: Secret Agent (#3 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[2].title());
@@ -87,11 +87,11 @@ TEST_F(PLSParserTest, ParseSomaFM2) {
TEST_F(PLSParserTest, SaveAndLoad) {
Song one;
- one.set_filename("http://www.example.com/foo.mp3");
+ one.set_url(QUrl("http://www.example.com/foo.mp3"));
one.set_title("Foo, with, some, commas");
Song two;
- two.set_filename("relative/bar.mp3");
+ two.set_url(QUrl("relative/bar.mp3"));
two.set_title("Bar");
two.set_length_nanosec(123 * kNsecPerSec);
@@ -106,8 +106,8 @@ TEST_F(PLSParserTest, SaveAndLoad) {
songs = parser_.Load(&temp, "", QDir("/meep"));
ASSERT_EQ(2, songs.count());
- EXPECT_EQ(one.filename(), songs[0].filename());
- EXPECT_EQ("/meep/relative/bar.mp3", songs[1].filename());
+ EXPECT_EQ(one.url(), songs[0].url());
+ EXPECT_EQ(QUrl("file:///meep/relative/bar.mp3"), songs[1].url());
EXPECT_EQ(one.title(), songs[0].title());
EXPECT_EQ(two.title(), songs[1].title());
EXPECT_EQ(one.length_nanosec(), songs[0].length_nanosec());
diff --git a/tests/songloader_test.cpp b/tests/songloader_test.cpp
index eeada3a95..44913376b 100644
--- a/tests/songloader_test.cpp
+++ b/tests/songloader_test.cpp
@@ -55,7 +55,7 @@ protected:
loader_->set_timeout(20000);
// the thing we return is not really important
- EXPECT_CALL(*library_.get(), GetSongByFilename(_, _)).WillRepeatedly(Return(Song()));
+ EXPECT_CALL(*library_.get(), GetSongByUrl(_, _)).WillRepeatedly(Return(Song()));
}
void LoadLocalDirectory(const QString& dir);
@@ -191,7 +191,7 @@ TEST_F(SongLoaderTest, LoadRemoteMp3) {
// Check the song got loaded
ASSERT_EQ(1, loader_->songs().count());
- EXPECT_EQ(QString(kRemoteUrl) + "/beep.mp3", loader_->songs()[0].filename());
+ EXPECT_EQ(QUrl(QString(kRemoteUrl) + "/beep.mp3"), loader_->songs()[0].url());
}
TEST_F(SongLoaderTest, LoadRemote404) {
@@ -231,7 +231,7 @@ TEST_F(SongLoaderTest, LoadRemotePls) {
ASSERT_EQ(4, loader_->songs().count());
EXPECT_EQ("SomaFM: Groove Salad (#3 128k mp3): A nicely chilled plate of ambient beats and grooves.",
loader_->songs()[2].title());
- EXPECT_EQ("http://ice.somafm.com/groovesalad", loader_->songs()[3].filename());
+ EXPECT_EQ(QUrl("http://ice.somafm.com/groovesalad"), loader_->songs()[3].url());
}
TEST_F(SongLoaderTest, LoadRemotePlainText) {
@@ -268,8 +268,8 @@ TEST_F(SongLoaderTest, LoadRemotePlainM3U) {
EXPECT_EQ(true, spy[0][0].toBool());
ASSERT_EQ(2, loader_->songs().count());
- EXPECT_EQ("http://www.example.com/one.mp3", loader_->songs()[0].filename());
- EXPECT_EQ("http://www.example.com/two.mp3", loader_->songs()[1].filename());
+ EXPECT_EQ(QUrl("http://www.example.com/one.mp3"), loader_->songs()[0].url());
+ EXPECT_EQ(QUrl("http://www.example.com/two.mp3"), loader_->songs()[1].url());
}
TEST_F(SongLoaderTest, LoadLocalDirectory) {
diff --git a/tests/songplaylistitem_test.cpp b/tests/songplaylistitem_test.cpp
index 38daa5842..7dee583f7 100644
--- a/tests/songplaylistitem_test.cpp
+++ b/tests/songplaylistitem_test.cpp
@@ -38,7 +38,7 @@ class SongPlaylistItemTest : public ::testing::TestWithParam {
absolute_file_name_ = QFileInfo(temp_file_.fileName()).absoluteFilePath();
song_.Init("Title", "Artist", "Album", 123);
- song_.set_filename(absolute_file_name_);
+ song_.set_url(QUrl::fromLocalFile(absolute_file_name_));
item_.reset(new SongPlaylistItem(song_));
diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp
index 9b0088b29..5a9610174 100644
--- a/tests/test_utils.cpp
+++ b/tests/test_utils.cpp
@@ -50,6 +50,10 @@ void PrintTo(const ::QVariant& var, std::ostream& os) {
os << var.toString().toStdString();
}
+void PrintTo(const ::QUrl& url, std::ostream& os) {
+ os << url.toString().toStdString();
+}
+
TemporaryResource::TemporaryResource(const QString& filename) {
setFileTemplate(QDir::tempPath() + "/clementine_test-XXXXXX." +
filename.section('.', -1, -1));
diff --git a/tests/test_utils.h b/tests/test_utils.h
index a60a95b95..26cbab828 100644
--- a/tests/test_utils.h
+++ b/tests/test_utils.h
@@ -46,6 +46,7 @@ std::ostream& operator <<(std::ostream& stream, const QList& list) {
void PrintTo(const ::QString& str, std::ostream& os);
void PrintTo(const ::QVariant& var, std::ostream& os);
+void PrintTo(const ::QUrl& url, std::ostream& os);
#define EXPOSE_SIGNAL0(n) \
void Emit##n() { emit n(); }
diff --git a/tests/xspfparser_test.cpp b/tests/xspfparser_test.cpp
index d2e8dc623..8fe233ffa 100644
--- a/tests/xspfparser_test.cpp
+++ b/tests/xspfparser_test.cpp
@@ -49,7 +49,7 @@ TEST_F(XSPFParserTest, ParsesOneTrackFromXML) {
EXPECT_EQ("Foo", song.title());
EXPECT_EQ("Bar", song.artist());
EXPECT_EQ("Baz", song.album());
- EXPECT_EQ("http://example.com/foo.mp3", song.filename());
+ EXPECT_EQ(QUrl("http://example.com/foo.mp3"), song.url());
EXPECT_EQ(60 * kNsecPerSec, song.length_nanosec());
EXPECT_TRUE(song.is_valid());
}
@@ -69,8 +69,8 @@ TEST_F(XSPFParserTest, ParsesMoreThanOneTrackFromXML) {
XSPFParser parser(NULL);
SongList songs = parser.Load(&buffer);
ASSERT_EQ(2, songs.length());
- EXPECT_EQ("http://example.com/foo.mp3", songs[0].filename());
- EXPECT_EQ("http://example.com/bar.mp3", songs[1].filename());
+ EXPECT_EQ(QUrl("http://example.com/foo.mp3"), songs[0].url());
+ EXPECT_EQ(QUrl("http://example.com/bar.mp3"), songs[1].url());
EXPECT_TRUE(songs[0].is_stream());
EXPECT_TRUE(songs[1].is_stream());
}
@@ -100,7 +100,7 @@ TEST_F(XSPFParserTest, SavesSong) {
buffer.open(QIODevice::WriteOnly);
XSPFParser parser(NULL);
Song one;
- one.set_filename("http://www.example.com/foo.mp3");
+ one.set_url(QUrl("http://www.example.com/foo.mp3"));
one.set_filetype(Song::Type_Stream);
one.set_title("foo");
one.set_length_nanosec(123 * kNsecPerSec);
@@ -121,7 +121,7 @@ TEST_F(XSPFParserTest, SavesLocalFile) {
buffer.open(QIODevice::WriteOnly);
XSPFParser parser(NULL);
Song one;
- one.set_filename("/bar/foo.mp3");
+ one.set_url(QUrl("file:///bar/foo.mp3"));
one.set_filetype(Song::Type_Mpeg);
one.set_title("foo");
one.set_length_nanosec(123 * kNsecPerSec);