diff --git a/mpd-interface/mpdparseutils.cpp b/mpd-interface/mpdparseutils.cpp index 6f0977ad9..c2b0c2451 100644 --- a/mpd-interface/mpdparseutils.cpp +++ b/mpd-interface/mpdparseutils.cpp @@ -825,57 +825,39 @@ QList MPDParseUtils::parseStickers(const QByteArray &dat return stickers; } -static const QString constStreamNameHash("#StreamName:"); -static const QString constStreamNameAmpersand("&StreamName:"); +static const QString constStreamName("StreamName"); + QString MPDParseUtils::addStreamName(const QString &url, const QString &name, bool singleHash) { - if (name.isEmpty()) { - return url; - } - - if (url.contains('#')) { - return url+(singleHash ? QLatin1String("&") : constStreamNameAmpersand)+name; - } - return url+(QUrl(url).path().isEmpty() ? "/" : "")+(singleHash ? QLatin1String("#") : constStreamNameHash)+name; + return Utils::addHashParam(url, singleHash ? QString() : constStreamName, name); } -// Previous versions replaced '#' in a stream's name with ${hash}. -// This no longer occurs, but we need to do the replacement here, -// just in case the stream name was saved this way. -static const QString constHashReplacement=QLatin1String("${hash}"); - QString MPDParseUtils::getStreamName(const QString &url) { - int idx=url.indexOf(constStreamNameHash); - if (-1==idx) { - url.indexOf(constStreamNameAmpersand); + DBUG << url; + QMap kv = Utils::hashParams(url); + QMap::ConstIterator name = kv.constFind(constStreamName); + if (kv.constEnd()!=name) { + DBUG << "name" << name.value(); + return name.value(); } - QString name=-1==idx ? QString() : url.mid(idx+constStreamNameHash.length()); - while (name.contains(constHashReplacement)) { - name.replace(constHashReplacement, "#"); - } - return name; + return QString(); } QString MPDParseUtils::getAndRemoveStreamName(QString &url, bool checkSingleHash) { - int idx=url.indexOf(constStreamNameHash); - int len=constStreamNameHash.length(); - if (-1==idx) { - idx=url.indexOf(constStreamNameAmpersand); + DBUG << url; + QMap kv = Utils::hashParams(url); + QMap::ConstIterator name = kv.constFind(constStreamName); + if (kv.constEnd()==name && checkSingleHash) { + DBUG << "check single"; + name = kv.find("-"); } - if (-1==idx && checkSingleHash) { - idx=url.lastIndexOf('#'); - len=1; - } - if (-1==idx) { + if (kv.constEnd()==name) { + DBUG << "no name found"; return QString(); } - - QString name=url.mid(idx+len); - while (name.contains(constHashReplacement)) { - name.replace(constHashReplacement, "#"); - } - url=url.left(idx); - return name; + url=Utils::removeHash(url); + DBUG << "name" << name.value(); + return name.value(); } diff --git a/online/onlineservice.cpp b/online/onlineservice.cpp index e6261f671..f6a35e7c6 100644 --- a/online/onlineservice.cpp +++ b/online/onlineservice.cpp @@ -26,14 +26,9 @@ #include #include #include +#include -static const QString constUrlGuard=QLatin1String("#{SONG_DETAILS}"); -static const QString constDeliminator=QLatin1String("<@>"); - -static inline QString fixString(QString str) -{ - return str.replace(constDeliminator, " ").replace("\n", ""); -} +static const QString constSongDetails=QLatin1String("SongDetails"); static inline void add(QJsonObject &json, const QString &key, const QString &val) { @@ -62,7 +57,7 @@ Song & OnlineService::encode(Song &song) add(json, "track", song.track); add(json, "disc", song.disc); add(json, "service", song.onlineService()); - song.file=QUrl(song.file).toEncoded()+"#"+QJsonDocument(json).toJson(QJsonDocument::Compact); + song.file=Utils::addHashParam(QUrl(song.file).toEncoded(), constSongDetails, QJsonDocument(json).toJson(QJsonDocument::Compact)); return song; } @@ -72,46 +67,27 @@ bool OnlineService::decode(Song &song) return false; } - int pos=song.file.indexOf(constUrlGuard); + QMap kv = Utils::hashParams(song.file); + QMap::ConstIterator details = kv.constFind(constSongDetails); - if (pos>0) { // Old (pre 2.3.1) style - QStringList parts=song.file.mid(pos+constUrlGuard.length()).split(constDeliminator); - if (parts.length()>=10) { - song.artist=parts.at(0); - song.albumartist=parts.at(1); - song.album=parts.at(2); - song.title=parts.at(3); - song.genres[0]=parts.at(4); - song.time=parts.at(5).toUInt(); - song.year=parts.at(6).toUInt(); - song.track=parts.at(7).toUInt(); - song.disc=parts.at(8).toUInt(); + if (kv.constEnd()!=details) { + QJsonDocument doc = QJsonDocument::fromJson(details.value().toUtf8()); + if (!doc.isNull()) { + QJsonObject obj = doc.object(); + song.artist=obj["artist"].toString(); + song.albumartist=obj["albumartist"].toString(); + song.album=obj["album"].toString(); + song.title=obj["title"].toString(); + song.genres[0]=obj["genre"].toString(); + if (obj.contains("time")) song.track=obj["time"].toInt(); + if (obj.contains("year")) song.track=obj["year"].toInt(); + if (obj.contains("track")) song.track=obj["track"].toInt(); + if (obj.contains("disc")) song.track=obj["disc"].toInt(); + song.setIsFromOnlineService(obj["service"].toString()); song.type=Song::OnlineSvrTrack; - song.setIsFromOnlineService(parts.at(9)); - song.file=song.file.left(pos); + song.file=Utils::removeHash(song.file); return true; } - } else { - pos = song.file.indexOf("#{"); - if (pos>0) { - QJsonDocument doc = QJsonDocument::fromJson(song.file.mid(pos+1).toUtf8()); - if (!doc.isNull()) { - QJsonObject obj = doc.object(); - song.artist=obj["artist"].toString(); - song.albumartist=obj["albumartist"].toString(); - song.album=obj["album"].toString(); - song.title=obj["title"].toString(); - song.genres[0]=obj["genre"].toString(); - if (obj.contains("time")) song.track=obj["time"].toInt(); - if (obj.contains("year")) song.track=obj["year"].toInt(); - if (obj.contains("track")) song.track=obj["track"].toInt(); - if (obj.contains("disc")) song.track=obj["disc"].toInt(); - song.setIsFromOnlineService(obj["service"].toString()); - song.type=Song::OnlineSvrTrack; - song.file=song.file.left(pos); - return true; - } - } } return false; } diff --git a/streams/streamfetcher.cpp b/streams/streamfetcher.cpp index 7c6d7b3b3..ac8617bf6 100644 --- a/streams/streamfetcher.cpp +++ b/streams/streamfetcher.cpp @@ -239,9 +239,7 @@ void StreamFetcher::doNext() } } emit status(tr("Loading %1").arg(report)); - if (!currentName.isEmpty()) { - current=current.left(current.length()-(currentName.length()+1)); - } + current=Utils::removeHash(current); // MPD 0.19.2 can handle m3u8 if (u.path().endsWith(QLatin1String(".m3u8"))) { DBUG << "use orig (m3u8)" << current; diff --git a/support/utils.cpp b/support/utils.cpp index 6e9c3f3f5..dbc2cada1 100644 --- a/support/utils.cpp +++ b/support/utils.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #ifndef _MSC_VER #include #include @@ -230,6 +231,41 @@ QString Utils::stripAcceleratorMarkers(QString label) return label; } +QMap Utils::hashParams(const QString &url) +{ + QMap map; + int start=url.indexOf("#"); + if (start>0) { + QStringList parts = url.mid(start+1).split("&"); + for (const QString &p: parts) { + QStringList kv = p.split("="); + if (kv.length()>=2) { + QString key = kv[0]; + kv.removeAt(0); + map.insert(key, QUrl::fromPercentEncoding(kv.join("=").toLatin1())); + } else { + map.insert(QString("-"), QUrl::fromPercentEncoding(p.toLatin1())); + } + } + } + return map; +} + +QString Utils::addHashParam(const QString &url, const QString &key, const QString &val) +{ + if (val.isEmpty()) { + return url; + } + + return url+(url.contains('#') ? "&" : "#")+(key.isEmpty() ? "" : (key+"="))+QUrl::toPercentEncoding(val); +} + +QString Utils::removeHash(const QString &url) +{ + int hash=url.indexOf('#'); + return hash<0 ? url : url.left(hash); +} + QString Utils::convertPathForDisplay(const QString &path, bool isFolder) { if (path.isEmpty() || path.startsWith(constHttp) || path.startsWith(constHttps)) { diff --git a/support/utils.h b/support/utils.h index 10db1c748..368301b60 100644 --- a/support/utils.h +++ b/support/utils.h @@ -74,6 +74,9 @@ namespace Utils extern QString strippedText(QString s); extern QString stripAcceleratorMarkers(QString label); + extern QMap hashParams(const QString &url); + extern QString addHashParam(const QString &url, const QString &key, const QString &val); + extern QString removeHash(const QString &url); // Convert path to a format suitable fo rUI - e.g. use native separators, and remove any trailing separator extern QString convertPathForDisplay(const QString &dir, bool isFolder=true);