mirror of
https://github.com/clementine-player/Clementine
synced 2025-02-01 11:56:45 +01:00
Last.fm global search provider
This commit is contained in:
parent
d83736acc0
commit
cc20d90a7a
@ -659,6 +659,7 @@ endif(ENABLE_VISUALISATIONS)
|
||||
if(HAVE_LIBLASTFM)
|
||||
list(APPEND SOURCES
|
||||
covers/lastfmcoverprovider.cpp
|
||||
globalsearch/lastfmsearchprovider.cpp
|
||||
internet/fixlastfm.cpp
|
||||
internet/lastfmservice.cpp
|
||||
internet/lastfmsettingspage.cpp
|
||||
@ -672,6 +673,7 @@ if(HAVE_LIBLASTFM)
|
||||
)
|
||||
list(APPEND HEADERS
|
||||
covers/lastfmcoverprovider.h
|
||||
globalsearch/lastfmsearchprovider.h
|
||||
internet/lastfmservice.h
|
||||
internet/lastfmsettingspage.h
|
||||
internet/lastfmstationdialog.h
|
||||
|
@ -91,6 +91,10 @@ void GlobalSearchItemDelegate::paint(QPainter* p,
|
||||
case SearchProvider::Result::Type_Track:
|
||||
break;
|
||||
|
||||
case SearchProvider::Result::Type_Stream:
|
||||
count = QString::fromUtf8("∞");
|
||||
break;
|
||||
|
||||
case SearchProvider::Result::Type_Album:
|
||||
if (result.album_size_ <= 0)
|
||||
count = "-";
|
||||
@ -126,7 +130,8 @@ void GlobalSearchItemDelegate::paint(QPainter* p,
|
||||
|
||||
// The text we draw depends on the type of result.
|
||||
switch (result.type_) {
|
||||
case SearchProvider::Result::Type_Track: {
|
||||
case SearchProvider::Result::Type_Track:
|
||||
case SearchProvider::Result::Type_Stream: {
|
||||
// Title
|
||||
line_1 += m.title() + " ";
|
||||
|
||||
|
@ -50,6 +50,7 @@ bool GlobalSearchSortModel::lessThan(const QModelIndex& left, const QModelIndex&
|
||||
// Then compare title, artist and album
|
||||
switch (r1.type_) {
|
||||
case SearchProvider::Result::Type_Track:
|
||||
case SearchProvider::Result::Type_Stream:
|
||||
CompareString(title);
|
||||
// fallthrough
|
||||
case SearchProvider::Result::Type_Album:
|
||||
|
@ -112,8 +112,12 @@ GlobalSearchWidget::~GlobalSearchWidget() {
|
||||
|
||||
void GlobalSearchWidget::Init(GlobalSearch* engine) {
|
||||
engine_ = engine;
|
||||
|
||||
// These have to be queued connections because they may get emitted before
|
||||
// our call to Search() (or whatever) returns and we add the ID to the map.
|
||||
connect(engine_, SIGNAL(ResultsAvailable(int,SearchProvider::ResultList)),
|
||||
SLOT(AddResults(int,SearchProvider::ResultList)));
|
||||
SLOT(AddResults(int,SearchProvider::ResultList)),
|
||||
Qt::QueuedConnection);
|
||||
connect(engine_, SIGNAL(SearchFinished(int)), SLOT(SearchFinished(int)),
|
||||
Qt::QueuedConnection);
|
||||
connect(engine_, SIGNAL(ArtLoaded(int,QPixmap)), SLOT(ArtLoaded(int,QPixmap)),
|
||||
@ -555,6 +559,10 @@ GlobalSearchWidget::CombineAction GlobalSearchWidget::CanCombineResults(
|
||||
if (StringsDiffer(album) || StringsDiffer(artist))
|
||||
return CannotCombine;
|
||||
break;
|
||||
case SearchProvider::Result::Type_Stream:
|
||||
if (StringsDiffer(url().toString))
|
||||
return CannotCombine;
|
||||
break;
|
||||
}
|
||||
|
||||
#undef StringsDiffer
|
||||
|
148
src/globalsearch/lastfmsearchprovider.cpp
Normal file
148
src/globalsearch/lastfmsearchprovider.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
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 "lastfmsearchprovider.h"
|
||||
#include "core/logging.h"
|
||||
#include "internet/lastfmservice.h"
|
||||
#include "playlist/songmimedata.h"
|
||||
|
||||
const int LastFMSearchProvider::kResultLimit = 6;
|
||||
|
||||
|
||||
LastFMSearchProvider::LastFMSearchProvider(LastFMService* service, QObject* parent)
|
||||
: BlockingSearchProvider(parent),
|
||||
service_(service) {
|
||||
Init("Last.fm", "lastfm", QIcon(":last.fm/as.png"), false, true);
|
||||
icon_ = ScaleAndPad(QImage(":last.fm/as.png"));
|
||||
|
||||
connect(service, SIGNAL(SavedItemsChanged()), SLOT(RecreateItems()));
|
||||
RecreateItems();
|
||||
}
|
||||
|
||||
SearchProvider::ResultList LastFMSearchProvider::Search(int id, const QString& query) {
|
||||
ResultList ret;
|
||||
const QStringList tokens = TokenizeQuery(query);
|
||||
|
||||
QMutexLocker l(&items_mutex_);
|
||||
foreach (const Item& item, items_) {
|
||||
Result result(this);
|
||||
result.type_ = Result::Type_Stream;
|
||||
result.match_quality_ = Result::Quality_None;
|
||||
|
||||
foreach (const QString& token, tokens) {
|
||||
if (item.keyword_.startsWith(token, Qt::CaseInsensitive)) {
|
||||
result.match_quality_ = Result::Quality_AtStart;
|
||||
result.metadata_ = item.metadata_;
|
||||
break; // Next item
|
||||
}
|
||||
|
||||
Result::MatchQuality quality = MatchQuality(tokens, item.metadata_.title());
|
||||
if (quality == Result::Quality_None)
|
||||
continue;
|
||||
|
||||
result.match_quality_ = qMin(quality, result.match_quality_);
|
||||
result.metadata_ = item.metadata_;
|
||||
}
|
||||
|
||||
if (result.match_quality_ != Result::Quality_None) {
|
||||
ret << result;
|
||||
}
|
||||
|
||||
if (ret.count() >= kResultLimit)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LastFMSearchProvider::LoadArtAsync(int id, const Result& result) {
|
||||
// TODO: Maybe we should try to get user pictures for friends?
|
||||
|
||||
emit ArtLoaded(id, icon_);
|
||||
}
|
||||
|
||||
void LastFMSearchProvider::LoadTracksAsync(int id, const Result& result) {
|
||||
Song metadata = result.metadata_;
|
||||
metadata.set_filetype(Song::Type_Stream);
|
||||
|
||||
SongMimeData* mime_data = new SongMimeData;
|
||||
mime_data->songs = SongList() << metadata;
|
||||
|
||||
emit TracksLoaded(id, mime_data);
|
||||
}
|
||||
|
||||
void LastFMSearchProvider::RecreateItems() {
|
||||
QList<Item> items;
|
||||
Item item;
|
||||
|
||||
item.keyword_ = "recommended";
|
||||
item.metadata_.set_title(tr("My Last.fm Recommended Radio"));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/USERNAME/recommended"));
|
||||
items << item;
|
||||
|
||||
item.keyword_ = "radio";
|
||||
item.metadata_.set_title(tr("My Last.fm Library"));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/USERNAME/library"));
|
||||
items << item;
|
||||
|
||||
item.keyword_ = "mix";
|
||||
item.metadata_.set_title(tr("My Last.fm Mix Radio"));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/USERNAME/mix"));
|
||||
items << item;
|
||||
|
||||
item.keyword_ = "neighborhood";
|
||||
item.metadata_.set_title(tr("My Last.fm Neighborhood"));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/USERNAME/neighbours"));
|
||||
items << item;
|
||||
|
||||
const QStringList artists = service_->SavedArtistRadioNames();
|
||||
const QStringList tags = service_->SavedTagRadioNames();
|
||||
const QStringList friends = service_->FriendNames();
|
||||
|
||||
foreach (const QString& name, artists) {
|
||||
item.keyword_ = name;
|
||||
item.metadata_.set_title(tr(LastFMService::kTitleArtist).arg(name));
|
||||
item.metadata_.set_url(QUrl(QString(LastFMService::kUrlArtist).arg(name)));
|
||||
items << item;
|
||||
}
|
||||
|
||||
foreach (const QString& name, tags) {
|
||||
item.keyword_ = name;
|
||||
item.metadata_.set_title(tr(LastFMService::kTitleTag).arg(name));
|
||||
item.metadata_.set_url(QUrl(QString(LastFMService::kUrlTag).arg(name)));
|
||||
items << item;
|
||||
}
|
||||
|
||||
foreach (const QString& name, friends) {
|
||||
item.keyword_ = name;
|
||||
|
||||
item.metadata_.set_title(tr("Last.fm Radio Station - %1").arg(name));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/" + name + "/library"));
|
||||
items << item;
|
||||
|
||||
item.metadata_.set_title(tr("Last.fm Mix Radio - %1").arg(name));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/" + name + "/mix"));
|
||||
items << item;
|
||||
|
||||
item.metadata_.set_title(tr("Last.fm Neighbor Radio - %1").arg(name));
|
||||
item.metadata_.set_url(QUrl("lastfm://user/" + name + "/neighbours"));
|
||||
items << item;
|
||||
}
|
||||
|
||||
QMutexLocker l(&items_mutex_);
|
||||
items_ = items;
|
||||
}
|
56
src/globalsearch/lastfmsearchprovider.h
Normal file
56
src/globalsearch/lastfmsearchprovider.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
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 LASTFMSEARCHPROVIDER_H
|
||||
#define LASTFMSEARCHPROVIDER_H
|
||||
|
||||
#include "searchprovider.h"
|
||||
|
||||
class LastFMService;
|
||||
|
||||
class LastFMSearchProvider : public BlockingSearchProvider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LastFMSearchProvider(LastFMService* service, QObject* parent);
|
||||
|
||||
static const int kResultLimit;
|
||||
|
||||
void LoadArtAsync(int id, const Result& result);
|
||||
void LoadTracksAsync(int id, const Result& result);
|
||||
|
||||
protected:
|
||||
ResultList Search(int id, const QString& query);
|
||||
|
||||
private slots:
|
||||
void RecreateItems();
|
||||
|
||||
private:
|
||||
LastFMService* service_;
|
||||
|
||||
QImage icon_;
|
||||
|
||||
struct Item {
|
||||
QString keyword_;
|
||||
Song metadata_;
|
||||
};
|
||||
|
||||
QMutex items_mutex_;
|
||||
QList<Item> items_;
|
||||
};
|
||||
|
||||
#endif // LASTFMSEARCHPROVIDER_H
|
@ -136,7 +136,7 @@ void LibrarySearchProvider::LoadTracksAsync(int id, const Result& result) {
|
||||
ret << result.metadata_;
|
||||
break;
|
||||
|
||||
case Result::Type_Album: {
|
||||
case Result::Type_Album: {
|
||||
// Find all the songs in this album.
|
||||
LibraryQuery query;
|
||||
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
|
||||
@ -156,6 +156,9 @@ void LibrarySearchProvider::LoadTracksAsync(int id, const Result& result) {
|
||||
ret << song;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SortSongs(&ret);
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
// The order of types here is the order they'll appear in the UI.
|
||||
enum Type {
|
||||
Type_Track = 0,
|
||||
Type_Stream,
|
||||
Type_Album
|
||||
};
|
||||
|
||||
@ -113,7 +114,7 @@ protected:
|
||||
// Sorts a list of songs by disc, then by track.
|
||||
static void SortSongs(SongList* list);
|
||||
|
||||
// Subclasses must call this from their constructor
|
||||
// Subclasses must call this from their constructors.
|
||||
void Init(const QString& name, const QString& id, const QIcon& icon,
|
||||
bool delay_searches, bool serialised_art);
|
||||
|
||||
|
@ -166,6 +166,9 @@ void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) {
|
||||
s->AlbumBrowse(uri);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ QSize TooltipResultWidget::CalculateSizeHint() const {
|
||||
|
||||
switch (result_.type_) {
|
||||
case SearchProvider::Result::Type_Track:
|
||||
case SearchProvider::Result::Type_Stream:
|
||||
break;
|
||||
|
||||
case SearchProvider::Result::Type_Album:
|
||||
@ -119,6 +120,7 @@ void TooltipResultWidget::paintEvent(QPaintEvent*) {
|
||||
|
||||
switch (result_.type_) {
|
||||
case SearchProvider::Result::Type_Track:
|
||||
case SearchProvider::Result::Type_Stream:
|
||||
break;
|
||||
|
||||
case SearchProvider::Result::Type_Album:
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "lastfmurlhandler.h"
|
||||
#include "internetmodel.h"
|
||||
#include "internetplaylistitem.h"
|
||||
#include "globalsearch/globalsearch.h"
|
||||
#include "globalsearch/lastfmsearchprovider.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/song.h"
|
||||
@ -79,6 +81,7 @@ LastFMService::LastFMService(InternetModel* parent)
|
||||
initial_tune_(false),
|
||||
tune_task_id_(0),
|
||||
scrobbling_enabled_(false),
|
||||
root_item_(NULL),
|
||||
artist_list_(NULL),
|
||||
tag_list_(NULL),
|
||||
custom_list_(NULL),
|
||||
@ -111,6 +114,8 @@ LastFMService::LastFMService(InternetModel* parent)
|
||||
|
||||
model()->player()->RegisterUrlHandler(url_handler_);
|
||||
model()->cover_providers()->AddProvider(new LastFmCoverProvider(this));
|
||||
|
||||
model()->global_search()->AddProvider(new LastFMSearchProvider(this, this));
|
||||
}
|
||||
|
||||
LastFMService::~LastFMService() {
|
||||
@ -126,8 +131,8 @@ void LastFMService::ReloadSettings() {
|
||||
buttons_visible_ = settings.value("ShowLoveBanButtons", true).toBool();
|
||||
scrobble_button_visible_ = settings.value("ShowScrobbleButton", true).toBool();
|
||||
|
||||
friend_names_ = settings.value("FriendNames").toStringList();
|
||||
last_refreshed_friends_ = settings.value("LastRefreshedFriends").toDateTime();
|
||||
friend_names_ = settings.value("FriendNames").toStringList();
|
||||
|
||||
//avoid emitting signal if it's not changed
|
||||
if(scrobbling_enabled_old != scrobbling_enabled_)
|
||||
@ -151,9 +156,9 @@ bool LastFMService::IsSubscriber() const {
|
||||
}
|
||||
|
||||
QStandardItem* LastFMService::CreateRootItem() {
|
||||
QStandardItem* item = new QStandardItem(QIcon(":last.fm/as.png"), kServiceName);
|
||||
item->setData(true, InternetModel::Role_CanLazyLoad);
|
||||
return item;
|
||||
root_item_ = new QStandardItem(QIcon(":last.fm/as.png"), kServiceName);
|
||||
root_item_->setData(true, InternetModel::Role_CanLazyLoad);
|
||||
return root_item_;
|
||||
}
|
||||
|
||||
void LastFMService::LazyPopulate(QStandardItem* parent) {
|
||||
@ -281,6 +286,7 @@ void LastFMService::SignOut() {
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup(kSettingsGroup);
|
||||
|
||||
settings.setValue("Username", QString());
|
||||
settings.setValue("Session", QString());
|
||||
settings.setValue("FriendNames", friend_names_);
|
||||
@ -589,13 +595,55 @@ bool LastFMService::IsFriendsListStale() const {
|
||||
kFriendsCacheDurationSecs;
|
||||
}
|
||||
|
||||
QStringList LastFMService::FriendNames() {
|
||||
// Update the list for next time, in the main thread.
|
||||
if (IsFriendsListStale())
|
||||
metaObject()->invokeMethod(this, "RefreshFriends", Qt::QueuedConnection);
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(LastFMService::kSettingsGroup);
|
||||
return s.value("FriendNames").toStringList();
|
||||
}
|
||||
|
||||
static QStringList SavedArtistOrTagRadioNames(const QString& name) {
|
||||
QStringList ret;
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(LastFMService::kSettingsGroup);
|
||||
int count = s.beginReadArray(name);
|
||||
for (int i=0 ; i<count ; ++i) {
|
||||
ret << s.value("key").toString();
|
||||
}
|
||||
s.endArray();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList LastFMService::SavedArtistRadioNames() const {
|
||||
return SavedArtistOrTagRadioNames("artists");
|
||||
}
|
||||
|
||||
QStringList LastFMService::SavedTagRadioNames() const {
|
||||
return SavedArtistOrTagRadioNames("tags");
|
||||
}
|
||||
|
||||
void LastFMService::RefreshFriends() {
|
||||
RefreshFriends(false);
|
||||
}
|
||||
|
||||
void LastFMService::ForceRefreshFriends() {
|
||||
RefreshFriends(true);
|
||||
}
|
||||
|
||||
void LastFMService::RefreshFriends(bool force) {
|
||||
if (!friends_list_ || !IsAuthenticated())
|
||||
if (!IsAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!friends_list_) {
|
||||
root_item_->setData(false, InternetModel::Role_CanLazyLoad);
|
||||
LazyPopulate(root_item_);
|
||||
}
|
||||
|
||||
if (!force && !IsFriendsListStale()) {
|
||||
PopulateFriendsList();
|
||||
@ -635,6 +683,7 @@ void LastFMService::RefreshFriendsFinished() {
|
||||
}
|
||||
|
||||
last_refreshed_friends_ = QDateTime::currentDateTime();
|
||||
|
||||
friend_names_ = QStringList();
|
||||
foreach (const lastfm::User& f, friends) {
|
||||
friend_names_ << f.name();
|
||||
@ -646,6 +695,8 @@ void LastFMService::RefreshFriendsFinished() {
|
||||
s.setValue("LastRefreshedFriends", last_refreshed_friends_);
|
||||
|
||||
PopulateFriendsList();
|
||||
|
||||
emit SavedItemsChanged();
|
||||
}
|
||||
|
||||
void LastFMService::PopulateFriendsList() {
|
||||
@ -756,6 +807,8 @@ void LastFMService::AddArtistOrTag(const QString& name,
|
||||
emit AddItemToPlaylist(item->index(), AddMode_Append);
|
||||
|
||||
SaveList(name, list);
|
||||
|
||||
emit SavedItemsChanged();
|
||||
}
|
||||
|
||||
void LastFMService::SaveList(const QString& name, QStandardItem* list) const {
|
||||
@ -774,35 +827,30 @@ void LastFMService::RestoreList(const QString& name,
|
||||
const QString& url_pattern,
|
||||
const QString& title_pattern,
|
||||
const QIcon& icon, QStandardItem* parent) {
|
||||
QSettings settings;
|
||||
settings.beginGroup(kSettingsGroup);
|
||||
|
||||
if (parent->hasChildren())
|
||||
parent->removeRows(0, parent->rowCount());
|
||||
|
||||
int count = settings.beginReadArray(name);
|
||||
for (int i=0 ; i<count ; ++i) {
|
||||
settings.setArrayIndex(i);
|
||||
QString content = settings.value("key").toString();
|
||||
const QStringList keys = SavedArtistOrTagRadioNames(name);
|
||||
|
||||
foreach (const QString& key, keys) {
|
||||
QString url;
|
||||
if (name == "custom" && content.startsWith("lastfm://")) {
|
||||
url = content;
|
||||
if (name == "custom" && key.startsWith("lastfm://")) {
|
||||
url = key;
|
||||
} else if (name == "custom") {
|
||||
url = url_pattern.arg(QString(content.toUtf8().toBase64()));
|
||||
url = url_pattern.arg(QString(key.toUtf8().toBase64()));
|
||||
} else {
|
||||
url = url_pattern.arg(content);
|
||||
url = url_pattern.arg(key);
|
||||
}
|
||||
|
||||
Song song;
|
||||
song.set_url(QUrl(url));
|
||||
song.set_title(title_pattern.arg(content));
|
||||
song.set_title(title_pattern.arg(key));
|
||||
|
||||
QStandardItem* item = new QStandardItem(icon, content);
|
||||
QStandardItem* item = new QStandardItem(icon, key);
|
||||
item->setData(QVariant::fromValue(song), InternetModel::Role_SongMetadata);
|
||||
item->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour);
|
||||
parent->appendRow(item);
|
||||
}
|
||||
settings.endArray();
|
||||
}
|
||||
|
||||
void LastFMService::Remove() {
|
||||
|
@ -113,6 +113,11 @@ class LastFMService : public InternetService {
|
||||
|
||||
bool IsFriendsListStale() const;
|
||||
|
||||
// Thread safe
|
||||
QStringList FriendNames();
|
||||
QStringList SavedArtistRadioNames() const;
|
||||
QStringList SavedTagRadioNames() const;
|
||||
|
||||
public slots:
|
||||
void NowPlaying(const Song& song);
|
||||
void Scrobble();
|
||||
@ -130,6 +135,8 @@ class LastFMService : public InternetService {
|
||||
void UpdatedSubscriberStatus(bool is_subscriber);
|
||||
void ScrobbledRadioStream();
|
||||
|
||||
void SavedItemsChanged();
|
||||
|
||||
protected:
|
||||
QModelIndex GetCurrentIndex();
|
||||
|
||||
@ -146,6 +153,7 @@ class LastFMService : public InternetService {
|
||||
void AddTagRadio();
|
||||
void AddCustomRadio();
|
||||
void ForceRefreshFriends();
|
||||
void RefreshFriends();
|
||||
void Remove();
|
||||
|
||||
// Radio tuner.
|
||||
@ -208,6 +216,7 @@ class LastFMService : public InternetService {
|
||||
bool buttons_visible_;
|
||||
bool scrobble_button_visible_;
|
||||
|
||||
QStandardItem* root_item_;
|
||||
QStandardItem* artist_list_;
|
||||
QStandardItem* tag_list_;
|
||||
QStandardItem* custom_list_;
|
||||
|
@ -220,6 +220,7 @@ int main(int argc, char *argv[]) {
|
||||
qRegisterMetaTypeStreamOperators<QMap<int, int> >("ColumnAlignmentMap");
|
||||
qRegisterMetaType<QNetworkCookie>("QNetworkCookie");
|
||||
qRegisterMetaType<QList<QNetworkCookie> >("QList<QNetworkCookie>");
|
||||
qRegisterMetaType<SearchProvider::ResultList>("SearchProvider::ResultList");
|
||||
|
||||
qRegisterMetaType<GstBuffer*>("GstBuffer*");
|
||||
qRegisterMetaType<GstElement*>("GstElement*");
|
||||
|
Loading…
x
Reference in New Issue
Block a user