Split the echonest images and biographies into different classes, fetch tags and similar artists from echonest.

This commit is contained in:
David Sansome 2010-10-10 21:45:01 +00:00
parent 0940d88862
commit 35988411e1
49 changed files with 585 additions and 73 deletions

View File

@ -273,5 +273,6 @@
<file>providers/mog.png</file>
<file>providers/mtvmusic.png</file>
<file>providers/cdbaby.png</file>
<file>providers/echonest.png</file>
</qresource>
</RCC>

BIN
data/providers/echonest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

View File

@ -131,7 +131,10 @@ set(SOURCES
songinfo/artistinfoview.cpp
songinfo/collapsibleinfoheader.cpp
songinfo/collapsibleinfopane.cpp
songinfo/echonestartistinfo.cpp
songinfo/echonestbiographies.cpp
songinfo/echonestimages.cpp
songinfo/echonestsimilarartists.cpp
songinfo/echonesttags.cpp
songinfo/lastfmtrackinfoprovider.cpp
songinfo/lyricsettings.cpp
songinfo/songinfobase.cpp
@ -275,7 +278,10 @@ set(HEADERS
songinfo/artistinfoview.h
songinfo/collapsibleinfoheader.h
songinfo/collapsibleinfopane.h
songinfo/echonestartistinfo.h
songinfo/echonestbiographies.h
songinfo/echonestimages.h
songinfo/echonestsimilarartists.h
songinfo/echonesttags.h
songinfo/lastfmtrackinfoprovider.h
songinfo/lyricsettings.h
songinfo/songinfobase.h

View File

@ -15,14 +15,20 @@
*/
#include "artistinfoview.h"
#include "echonestartistinfo.h"
#include "echonestbiographies.h"
#include "echonestimages.h"
#include "echonestsimilarartists.h"
#include "echonesttags.h"
#include "songinfofetcher.h"
#include "widgets/prettyimageview.h"
ArtistInfoView::ArtistInfoView(NetworkAccessManager* network, QWidget *parent)
: SongInfoBase(network, parent)
{
fetcher_->AddProvider(new EchoNestArtistInfo);
fetcher_->AddProvider(new EchoNestBiographies);
fetcher_->AddProvider(new EchoNestImages);
fetcher_->AddProvider(new EchoNestSimilarArtists);
fetcher_->AddProvider(new EchoNestTags);
}
ArtistInfoView::~ArtistInfoView() {

View File

@ -34,6 +34,7 @@ public:
enum Type {
Type_PlayCounts,
Type_Tags,
Type_Similar,
Type_Biography,
Type_Lyrics,

View File

@ -14,24 +14,21 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonestartistinfo.h"
#include "echonestbiographies.h"
#include "widgets/autosizedtextedit.h"
#include <echonest/Artist.h>
#include <boost/scoped_ptr.hpp>
struct EchoNestArtistInfo::Request {
struct EchoNestBiographies::Request {
Request(int id) : id_(id), artist_(new Echonest::Artist) {}
bool is_finished() const { return pending_replies_.isEmpty(); }
int id_;
boost::scoped_ptr<Echonest::Artist> artist_;
QList<QNetworkReply*> pending_replies_;
};
EchoNestArtistInfo::EchoNestArtistInfo() {
EchoNestBiographies::EchoNestBiographies() {
site_relevance_["wikipedia"] = 100;
site_relevance_["lastfm"] = 60;
site_relevance_["amazon"] = 30;
@ -46,58 +43,28 @@ EchoNestArtistInfo::EchoNestArtistInfo() {
site_icons_["wikipedia"] = QIcon(":/providers/wikipedia.png");
}
void EchoNestArtistInfo::FetchInfo(int id, const Song& metadata) {
void EchoNestBiographies::FetchInfo(int id, const Song& metadata) {
boost::shared_ptr<Request> request(new Request(id));
request->artist_->setName(metadata.artist());
ConnectReply(request, request->artist_->fetchBiographies(), SLOT(BiographiesFinished()));
ConnectReply(request, request->artist_->fetchImages(), SLOT(ImagesFinished()));
requests_ << request;
QNetworkReply* reply = request->artist_->fetchBiographies();
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = request;
}
void EchoNestArtistInfo::ConnectReply(
boost::shared_ptr<Request> request, QNetworkReply* reply, const char* slot) {
request->pending_replies_ << reply;
connect(reply, SIGNAL(finished()), slot);
}
EchoNestArtistInfo::RequestPtr EchoNestArtistInfo::ReplyFinished(QNetworkReply* reply) {
void EchoNestBiographies::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply))
return;
reply->deleteLater();
foreach (RequestPtr request, requests_) {
if (request->pending_replies_.contains(reply)) {
try {
request->artist_->parseProfile(reply);
} catch (Echonest::ParseError e) {
qWarning() << "Error parsing echonest reply:" << e.errorType() << e.what();
}
RequestPtr request = requests_.take(reply);
request->pending_replies_.removeAll(reply);
if (request->is_finished()) {
requests_.removeAll(request);
}
return request;
}
try {
request->artist_->parseProfile(reply);
} catch (Echonest::ParseError e) {
qWarning() << "Error parsing echonest reply:" << e.errorType() << e.what();
}
return RequestPtr();
}
void EchoNestArtistInfo::ImagesFinished() {
RequestPtr request = ReplyFinished(qobject_cast<QNetworkReply*>(sender()));
foreach (const Echonest::ArtistImage& image, request->artist_->images()) {
emit ImageReady(request->id_, image.url());
}
if (request->is_finished())
emit Finished(request->id_);
}
void EchoNestArtistInfo::BiographiesFinished() {
RequestPtr request = ReplyFinished(qobject_cast<QNetworkReply*>(sender()));
QSet<QString> already_seen;
@ -125,6 +92,5 @@ void EchoNestArtistInfo::BiographiesFinished() {
emit InfoReady(request->id_, data);
}
if (request->is_finished())
emit Finished(request->id_);
emit Finished(request->id_);
}

View File

@ -14,40 +14,34 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTARTISTINFO_H
#define ECHONESTARTISTINFO_H
#ifndef ECHONESTBIOGRAPHIES_H
#define ECHONESTBIOGRAPHIES_H
#include "songinfoprovider.h"
#include <QMap>
#include <boost/shared_ptr.hpp>
class QNetworkReply;
class EchoNestArtistInfo : public SongInfoProvider {
class EchoNestBiographies : public SongInfoProvider {
Q_OBJECT
public:
EchoNestArtistInfo();
EchoNestBiographies();
void FetchInfo(int id, const Song& metadata);
private slots:
void BiographiesFinished();
void ImagesFinished();
void RequestFinished();
private:
QMap<QString, int> site_relevance_;
QMap<QString, QIcon> site_icons_;
struct Request;
typedef boost::shared_ptr<Request> RequestPtr;
void ConnectReply(RequestPtr request, QNetworkReply* reply, const char* slot);
RequestPtr ReplyFinished(QNetworkReply* reply);
private:
QList<RequestPtr> requests_;
QMap<QString, int> site_relevance_;
QMap<QString, QIcon> site_icons_;
QMap<QNetworkReply*, RequestPtr> requests_;
};
#endif // ECHONESTARTISTINFO_H
#endif // ECHONESTBIOGRAPHIES_H

View File

@ -0,0 +1,58 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonestimages.h"
#include <echonest/Artist.h>
#include <boost/scoped_ptr.hpp>
struct EchoNestImages::Request {
Request(int id) : id_(id), artist_(new Echonest::Artist) {}
int id_;
boost::scoped_ptr<Echonest::Artist> artist_;
};
void EchoNestImages::FetchInfo(int id, const Song& metadata) {
boost::shared_ptr<Request> request(new Request(id));
request->artist_->setName(metadata.artist());
QNetworkReply* reply = request->artist_->fetchImages();
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = request;
}
void EchoNestImages::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply))
return;
reply->deleteLater();
RequestPtr request = requests_.take(reply);
try {
request->artist_->parseProfile(reply);
} catch (Echonest::ParseError e) {
qWarning() << "Error parsing echonest reply:" << e.errorType() << e.what();
}
foreach (const Echonest::ArtistImage& image, request->artist_->images()) {
emit ImageReady(request->id_, image.url());
}
emit Finished(request->id_);
}

View File

@ -0,0 +1,42 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTIMAGES_H
#define ECHONESTIMAGES_H
#include "songinfoprovider.h"
#include <boost/shared_ptr.hpp>
class QNetworkReply;
class EchoNestImages : public SongInfoProvider {
Q_OBJECT
public:
void FetchInfo(int id, const Song& metadata);
private slots:
void RequestFinished();
private:
struct Request;
typedef boost::shared_ptr<Request> RequestPtr;
QMap<QNetworkReply*, RequestPtr> requests_;
};
#endif // ECHONESTIMAGES_H

View File

@ -0,0 +1,74 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonestsimilarartists.h"
#include "tagwidget.h"
#include "ui/iconloader.h"
#include <echonest/Artist.h>
Q_DECLARE_METATYPE(QVector<QString>);
void EchoNestSimilarArtists::FetchInfo(int id, const Song& metadata) {
using Echonest::Artist;
Artist::SearchParams params;
params << Artist::SearchParamEntry(Artist::Name, metadata.artist());
params << Artist::SearchParamEntry(Artist::MinHotttnesss, 0.5);
QNetworkReply* reply = Echonest::Artist::fetchSimilar(params);
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = id;
}
void EchoNestSimilarArtists::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply))
return;
reply->deleteLater();
int id = requests_.take(reply);
Echonest::Artists artists;
try {
artists = Echonest::Artist::parseSimilar(reply);
} catch (Echonest::ParseError e) {
qWarning() << "Error parsing echonest reply:" << e.errorType() << e.what();
}
if (!artists.isEmpty()) {
CollapsibleInfoPane::Data data;
data.title_ = tr("Similar artists");
data.type_ = CollapsibleInfoPane::Data::Type_Similar;
data.icon_ = QIcon(":/providers/echonest.png");
TagWidget* widget = new TagWidget;
data.contents_ = widget;
widget->SetIcon(QIcon(":/icons/22x22/x-clementine-artist.png"));
widget->SetUrlPattern("lastfm://artist/%1/similarartists");
foreach (const Echonest::Artist& artist, artists) {
widget->AddTag(artist.name());
if (widget->count() >= 10)
break;
}
emit InfoReady(id, data);
}
emit Finished(id);
}

View File

@ -0,0 +1,37 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTSIMILARARTISTS_H
#define ECHONESTSIMILARARTISTS_H
#include "songinfoprovider.h"
class QNetworkReply;
class EchoNestSimilarArtists : public SongInfoProvider {
Q_OBJECT
public:
void FetchInfo(int id, const Song& metadata);
private slots:
void RequestFinished();
private:
QMap<QNetworkReply*, int> requests_;
};
#endif // ECHONESTSIMILARARTISTS_H

View File

@ -0,0 +1,77 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonesttags.h"
#include "tagwidget.h"
#include <echonest/Artist.h>
#include <boost/scoped_ptr.hpp>
struct EchoNestTags::Request {
Request(int id) : id_(id), artist_(new Echonest::Artist) {}
int id_;
boost::scoped_ptr<Echonest::Artist> artist_;
};
void EchoNestTags::FetchInfo(int id, const Song& metadata) {
boost::shared_ptr<Request> request(new Request(id));
request->artist_->setName(metadata.artist());
QNetworkReply* reply = request->artist_->fetchTerms();
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = request;
}
void EchoNestTags::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply))
return;
reply->deleteLater();
RequestPtr request = requests_.take(reply);
try {
request->artist_->parseProfile(reply);
} catch (Echonest::ParseError e) {
qWarning() << "Error parsing echonest reply:" << e.errorType() << e.what();
}
if (!request->artist_->terms().isEmpty()) {
CollapsibleInfoPane::Data data;
data.title_ = tr("Artist tags");
data.type_ = CollapsibleInfoPane::Data::Type_Tags;
data.icon_ = QIcon(":/last.fm/icon_tag.png");
TagWidget* widget = new TagWidget;
data.contents_ = widget;
widget->SetIcon(data.icon_);
widget->SetUrlPattern("lastfm://globaltags/%1");
foreach (const Echonest::Term& term, request->artist_->terms()) {
widget->AddTag(term.name());
if (widget->count() >= 10)
break;
}
emit InfoReady(request->id_, data);
}
emit Finished(request->id_);
}

View File

@ -0,0 +1,42 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTTAGS_H
#define ECHONESTTAGS_H
#include "songinfoprovider.h"
#include <boost/shared_ptr.hpp>
class QNetworkReply;
class EchoNestTags : public SongInfoProvider {
Q_OBJECT
public:
void FetchInfo(int id, const Song& metadata);
private slots:
void RequestFinished();
private:
struct Request;
typedef boost::shared_ptr<Request> RequestPtr;
QMap<QNetworkReply*, RequestPtr> requests_;
};
#endif // ECHONESTTAGS_H

View File

@ -104,5 +104,7 @@ void TagWidget::AddTag(const QString& tag) {
if (tag.isEmpty())
return;
layout()->addWidget(new TagWidgetTag(icon_, tag, this));
TagWidgetTag* widget = new TagWidgetTag(icon_, tag, this);
layout()->addWidget(widget);
tags_ << widget;
}

View File

@ -64,10 +64,12 @@ public:
void SetIcon(const QIcon& icon) { icon_ = icon; }
void AddTag(const QString& tag);
int count() const { return tags_.count(); }
private:
QString url_pattern_;
QIcon icon_;
QStringList tags_;
QList<TagWidgetTag*> tags_;
};
#endif // TAGWIDGET_H

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1686,6 +1689,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr ""

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1687,6 +1690,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr ""

View File

@ -284,6 +284,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Radio de l'artista"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Inicials de l'artista"
@ -1716,6 +1719,9 @@ msgstr "Llista de reproducció aleatòria"
msgid "Sign out"
msgstr "Tancar la sessió"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -277,6 +277,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Rádio umělce"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1691,6 +1694,9 @@ msgstr "Zamíchat seznam skladeb"
msgid "Sign out"
msgstr "Odhlásit"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -277,6 +277,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Kunstnerradio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Kunstner's initial"
@ -1694,6 +1697,9 @@ msgstr "Bland spilleliste"
msgid "Sign out"
msgstr "Log ud"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -283,6 +283,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Interpreten-Radio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Initialen des Künstlers"
@ -1717,6 +1720,9 @@ msgstr "Wiedergabeliste mischen"
msgid "Sign out"
msgstr "Abmelden"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -284,6 +284,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Ραδιόφωνο καλλιτέχνη"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Αρχικά του καλλιτέχνη"
@ -1720,6 +1723,9 @@ msgstr "Ανακάτεμα λίστας"
msgid "Sign out"
msgstr "Αποσύνδεση"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Artist radio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1691,6 +1694,9 @@ msgstr "Shuffle playlist"
msgid "Sign out"
msgstr "Sign out"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Artist radio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1688,6 +1691,9 @@ msgstr "Shuffle playlist"
msgid "Sign out"
msgstr "Sign out"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -284,6 +284,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Radio del artista"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Iniciales del artista"
@ -1721,6 +1724,9 @@ msgstr "Mezclar lista de reproducción"
msgid "Sign out"
msgstr "Cerrar sesión"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1689,6 +1692,9 @@ msgstr ""
msgid "Sign out"
msgstr "Kirjaudu ulos"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -287,6 +287,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Radio par artiste"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Initiale de l'artiste"
@ -1725,6 +1728,9 @@ msgstr "Mélanger la liste de lecture"
msgid "Sign out"
msgstr "Se déconnecter"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Artista da rádio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Iniciáis do artista"
@ -1693,6 +1696,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -281,6 +281,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Előadó rádió"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Előadó kezdése"
@ -1715,6 +1718,9 @@ msgstr "Lejátszási lista véletlenszerűen"
msgid "Sign out"
msgstr "Kijelentkezés"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -288,6 +288,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Radio dell'artista"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Iniziale dell'artista"
@ -1725,6 +1728,9 @@ msgstr "Mescola la scaletta"
msgid "Sign out"
msgstr "Disconnetti"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1688,6 +1691,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ска"

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1687,6 +1690,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr ""

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Artistradio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1690,6 +1693,9 @@ msgstr "Bland spilleliste"
msgid "Sign out"
msgstr "Logg ut"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -284,6 +284,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Artiestradio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Artiest's initiaal"
@ -1720,6 +1723,9 @@ msgstr "Afspeellijst schudden"
msgid "Sign out"
msgstr "Afmelden"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1686,6 +1689,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -284,6 +284,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Radio wykonawcy"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Inicjał autora"
@ -1716,6 +1719,9 @@ msgstr "Zamieszaj playlistę"
msgid "Sign out"
msgstr "Wyloguj"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -283,6 +283,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Rádio do artista"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Iniciais do artista"
@ -1717,6 +1720,9 @@ msgstr "Baralhar lista de reprodução"
msgid "Sign out"
msgstr "Sair"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -281,6 +281,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Rádio do artista"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Artista inicial"
@ -1705,6 +1708,9 @@ msgstr "Misturar lista de reprodução"
msgid "Sign out"
msgstr "Sair"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1687,6 +1690,9 @@ msgstr "Amestecă lista de melodii"
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -279,6 +279,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Радио исполнителя"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Инициалы исполнителя"
@ -1709,6 +1712,9 @@ msgstr "Перемешать список воспроизведения"
msgid "Sign out"
msgstr "Выйти"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -281,6 +281,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Rádio interpréta"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Interprétov prvotný"
@ -1710,6 +1713,9 @@ msgstr "Zamiešať playlist"
msgid "Sign out"
msgstr "Odhlásiť"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -280,6 +280,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Radio izvajalca"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Začetnice izvajalca"
@ -1710,6 +1713,9 @@ msgstr "Premešaj seznam predvajanja"
msgid "Sign out"
msgstr "Odjavi se"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Иницијали извођача"
@ -1692,6 +1695,9 @@ msgstr ""
msgid "Sign out"
msgstr "Одјави се"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ска"

View File

@ -276,6 +276,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Artistradio"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Artistens initialer"
@ -1696,6 +1699,9 @@ msgstr "Slumpsportera spellista"
msgid "Sign out"
msgstr "Logga ut"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -280,6 +280,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Sanatçı radyosu"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Sanatçının kısaltması"
@ -1713,6 +1716,9 @@ msgstr "Çalma listesini karıştır"
msgid "Sign out"
msgstr "Çıkış yap"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ska"

View File

@ -266,6 +266,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1677,6 +1680,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr ""

View File

@ -280,6 +280,9 @@ msgstr ""
msgid "Artist radio"
msgstr "Радіо виконавця"
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr "Ініціали виконавця"
@ -1710,6 +1713,9 @@ msgstr "Перемішати список відтворення"
msgid "Sign out"
msgstr "Вийти"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr "Ска"

View File

@ -275,6 +275,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1686,6 +1689,9 @@ msgstr ""
msgid "Sign out"
msgstr ""
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr ""

View File

@ -280,6 +280,9 @@ msgstr ""
msgid "Artist radio"
msgstr ""
msgid "Artist tags"
msgstr ""
msgid "Artist's initial"
msgstr ""
@ -1692,6 +1695,9 @@ msgstr "隨機排列播放清單"
msgid "Sign out"
msgstr "登出"
msgid "Similar artists"
msgstr ""
msgid "Ska"
msgstr ""