Initial RadioBrowser support: implemented search, groups by category, top 100
This commit is contained in:
parent
e7768948e0
commit
3e31094227
|
@ -193,7 +193,6 @@ set(SOURCES
|
||||||
internet/intergalacticfm/intergalacticfmservice.cpp
|
internet/intergalacticfm/intergalacticfmservice.cpp
|
||||||
internet/intergalacticfm/intergalacticfmurlhandler.cpp
|
internet/intergalacticfm/intergalacticfmurlhandler.cpp
|
||||||
internet/radiobrowser/radiobrowserservice.cpp
|
internet/radiobrowser/radiobrowserservice.cpp
|
||||||
internet/radiobrowser/radiobrowserurlhandler.cpp
|
|
||||||
internet/subsonic/subsonicservice.cpp
|
internet/subsonic/subsonicservice.cpp
|
||||||
internet/subsonic/subsonicsettingspage.cpp
|
internet/subsonic/subsonicsettingspage.cpp
|
||||||
internet/subsonic/subsonicurlhandler.cpp
|
internet/subsonic/subsonicurlhandler.cpp
|
||||||
|
@ -478,6 +477,7 @@ set(HEADERS
|
||||||
globalsearch/searchprovider.h
|
globalsearch/searchprovider.h
|
||||||
globalsearch/simplesearchprovider.h
|
globalsearch/simplesearchprovider.h
|
||||||
globalsearch/suggestionwidget.h
|
globalsearch/suggestionwidget.h
|
||||||
|
globalsearch/radiobrowsersearchprovider.h
|
||||||
|
|
||||||
internet/core/cloudfileservice.h
|
internet/core/cloudfileservice.h
|
||||||
internet/digitally/digitallyimportedclient.h
|
internet/digitally/digitallyimportedclient.h
|
||||||
|
@ -510,7 +510,6 @@ set(HEADERS
|
||||||
internet/intergalacticfm/intergalacticfmservice.h
|
internet/intergalacticfm/intergalacticfmservice.h
|
||||||
internet/intergalacticfm/intergalacticfmurlhandler.h
|
internet/intergalacticfm/intergalacticfmurlhandler.h
|
||||||
internet/radiobrowser/radiobrowserservice.h
|
internet/radiobrowser/radiobrowserservice.h
|
||||||
internet/radiobrowser/radiobrowserurlhandler.h
|
|
||||||
internet/subsonic/subsonicservice.h
|
internet/subsonic/subsonicservice.h
|
||||||
internet/subsonic/subsonicsettingspage.h
|
internet/subsonic/subsonicsettingspage.h
|
||||||
internet/subsonic/subsonicurlhandler.h
|
internet/subsonic/subsonicurlhandler.h
|
||||||
|
|
|
@ -99,8 +99,7 @@ void RegisterMetaTypes() {
|
||||||
qRegisterMetaType<SomaFMService::Stream>("SomaFMService::Stream");
|
qRegisterMetaType<SomaFMService::Stream>("SomaFMService::Stream");
|
||||||
qRegisterMetaType<IntergalacticFMService::Stream>(
|
qRegisterMetaType<IntergalacticFMService::Stream>(
|
||||||
"IntergalacticFMService::Stream");
|
"IntergalacticFMService::Stream");
|
||||||
qRegisterMetaType<RadioBrowserService::Stream>(
|
qRegisterMetaType<RadioBrowserService::Stream>("RadioBrowserService::Stream");
|
||||||
"RadioBrowserService::Stream");
|
|
||||||
qRegisterMetaType<SongList>("SongList");
|
qRegisterMetaType<SongList>("SongList");
|
||||||
qRegisterMetaType<Song>("Song");
|
qRegisterMetaType<Song>("Song");
|
||||||
qRegisterMetaTypeStreamOperators<DigitallyImportedClient::Channel>(
|
qRegisterMetaTypeStreamOperators<DigitallyImportedClient::Channel>(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
Copyright 2021, Fabio Bas <ctrlaltca@gmail.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -17,36 +17,50 @@
|
||||||
|
|
||||||
#include "radiobrowsersearchprovider.h"
|
#include "radiobrowsersearchprovider.h"
|
||||||
|
|
||||||
|
#include "ui/iconloader.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const int kSearchStationLimit = 10;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
RadioBrowserSearchProvider::RadioBrowserSearchProvider(
|
RadioBrowserSearchProvider::RadioBrowserSearchProvider(
|
||||||
RadioBrowserServiceBase* service, Application* app, QObject* parent)
|
Application* app, RadioBrowserService* service, QObject* parent)
|
||||||
: SimpleSearchProvider(app, parent), service_(service) {
|
: SearchProvider(app, parent), service_(service) {
|
||||||
Init(service->name(), service->url_scheme(), service->icon(),
|
Init(RadioBrowserService::kServiceName, "radiobrowser",
|
||||||
CanGiveSuggestions);
|
IconLoader::Load("radiobrowser", IconLoader::Provider),
|
||||||
set_result_limit(3);
|
WantsDelayedQueries);
|
||||||
set_max_suggestion_count(3);
|
connect(service_,
|
||||||
icon_ = ScaleAndPad(
|
SIGNAL(SearchFinished(int, RadioBrowserService::StreamList)),
|
||||||
service->icon().pixmap(service->icon().availableSizes()[0]).toImage());
|
SLOT(SearchFinishedSlot(int, RadioBrowserService::StreamList)));
|
||||||
|
|
||||||
connect(service, SIGNAL(StreamsChanged()), SLOT(MaybeRecreateItems()));
|
|
||||||
|
|
||||||
// Load the stream list on startup only if it doesn't involve going to update
|
|
||||||
// info from the server.
|
|
||||||
if (!service_->IsStreamListStale()) RecreateItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserSearchProvider::LoadArtAsync(int id, const Result& result) {
|
void RadioBrowserSearchProvider::SearchAsync(int id, const QString& query) {
|
||||||
emit ArtLoaded(id, icon_);
|
PendingState state;
|
||||||
|
state.orig_id_ = id;
|
||||||
|
state.tokens_ = TokenizeQuery(query);
|
||||||
|
|
||||||
|
const QString query_string = state.tokens_.join(" ");
|
||||||
|
service_->Search(id, query_string, kSearchStationLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserSearchProvider::RecreateItems() {
|
void RadioBrowserSearchProvider::SearchFinishedSlot(
|
||||||
QList<Item> items;
|
int search_id, RadioBrowserService::StreamList streams) {
|
||||||
|
ResultList ret;
|
||||||
|
|
||||||
for (const RadioBrowserService::Stream& stream : service_->Streams()) {
|
for (auto stream : streams) {
|
||||||
Item item;
|
Result result(this);
|
||||||
item.metadata_ = stream.ToSong(service_->name());
|
result.group_automatically_ = false;
|
||||||
item.keyword_ = stream.name_;
|
result.metadata_ = stream.ToSong(QString());
|
||||||
items << item;
|
ret << result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetItems(items);
|
emit ResultsAvailable(search_id, ret);
|
||||||
|
emit SearchFinished(search_id);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
void RadioBrowserSearchProvider::ShowConfig() {
|
||||||
|
if (service_) {
|
||||||
|
return service_->ShowConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
Copyright 2021, Fabio Bas <ctrlaltca@gmail.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,23 +19,24 @@
|
||||||
#define RADIOBROWSERSEARCHPROVIDER_H
|
#define RADIOBROWSERSEARCHPROVIDER_H
|
||||||
|
|
||||||
#include "internet/radiobrowser/radiobrowserservice.h"
|
#include "internet/radiobrowser/radiobrowserservice.h"
|
||||||
#include "simplesearchprovider.h"
|
#include "searchprovider.h"
|
||||||
|
|
||||||
|
class RadioBrowserSearchProvider : public SearchProvider {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
class RadioBrowserSearchProvider : public SimpleSearchProvider {
|
|
||||||
public:
|
public:
|
||||||
RadioBrowserSearchProvider(RadioBrowserServiceBase* service,
|
RadioBrowserSearchProvider(Application* app, RadioBrowserService* service,
|
||||||
Application* app, QObject* parent);
|
QObject* parent = nullptr);
|
||||||
// SearchProvider
|
void SearchAsync(int id, const QString& query) override;
|
||||||
|
// void ShowConfig() override;
|
||||||
InternetService* internet_service() override { return service_; }
|
InternetService* internet_service() override { return service_; }
|
||||||
|
|
||||||
void LoadArtAsync(int id, const Result& result) override;
|
public slots:
|
||||||
|
void SearchFinishedSlot(int search_id,
|
||||||
protected:
|
RadioBrowserService::StreamList streams);
|
||||||
void RecreateItems() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RadioBrowserServiceBase* service_;
|
RadioBrowserService* service_;
|
||||||
QImage icon_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RADIOBROWSERSEARCHPROVIDER_H
|
#endif // RADIOBROWSERSEARCHPROVIDER_H
|
||||||
|
|
|
@ -332,6 +332,11 @@ QMimeData* InternetModel::mimeData(const QModelIndexList& indexes) const {
|
||||||
|
|
||||||
if (urls.isEmpty()) return nullptr;
|
if (urls.isEmpty()) return nullptr;
|
||||||
|
|
||||||
|
for (const QModelIndex& index : new_indexes) {
|
||||||
|
InternetModel::ServiceForIndex(index)
|
||||||
|
->ItemNowPlaying(itemFromIndex(index));
|
||||||
|
}
|
||||||
|
|
||||||
InternetMimeData* data = new InternetMimeData(this);
|
InternetMimeData* data = new InternetMimeData(this);
|
||||||
data->setUrls(urls);
|
data->setUrls(urls);
|
||||||
data->indexes = new_indexes;
|
data->indexes = new_indexes;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2010-2013, David Sansome <me@davidsansome.com>
|
Copyright 2021, Fabio Bas <ctrlaltca@gmail.com>
|
||||||
Copyright 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
|
|
||||||
Copyright 2011, Paweł Bara <keirangtp@gmail.com>
|
|
||||||
Copyright 2012, 2014, John Maguire <john.maguire@gmail.com>
|
|
||||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -39,63 +35,140 @@
|
||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
#include "globalsearch/globalsearch.h"
|
#include "globalsearch/globalsearch.h"
|
||||||
#include "globalsearch/radiobrowsersearchprovider.h"
|
#include "globalsearch/radiobrowsersearchprovider.h"
|
||||||
#include "radiobrowserurlhandler.h"
|
|
||||||
#include "internet/core/internetmodel.h"
|
|
||||||
#include "ui/iconloader.h"
|
#include "ui/iconloader.h"
|
||||||
|
|
||||||
const int RadioBrowserServiceBase::kStreamsCacheDurationSecs =
|
bool operator<(const RadioBrowserService::Stream& a,
|
||||||
60 * 60 * 24 * 28; // 4 weeks
|
const RadioBrowserService::Stream& b) {
|
||||||
|
|
||||||
bool operator<(const RadioBrowserServiceBase::Stream& a,
|
|
||||||
const RadioBrowserServiceBase::Stream& b) {
|
|
||||||
return a.name_.compare(b.name_, Qt::CaseInsensitive) < 0;
|
return a.name_.compare(b.name_, Qt::CaseInsensitive) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioBrowserServiceBase::RadioBrowserServiceBase(
|
const char* RadioBrowserService::kServiceName = "Radio-Browser.info";
|
||||||
Application* app, InternetModel* parent, const QString& name,
|
QString RadioBrowserService::SearchUrl =
|
||||||
const QUrl& channel_list_url, const QUrl& homepage_url,
|
"%1/json/stations/byname/%2?limit=%3";
|
||||||
const QUrl& donate_page_url, const QIcon& icon)
|
QString RadioBrowserService::PlayClickUrl = "%1/json/url/%2";
|
||||||
: InternetService(name, app, parent, parent),
|
|
||||||
url_scheme_(name.toLower().remove(' ')),
|
QList<RadioBrowserService::Branch> RadioBrowserService::BranchList = {
|
||||||
url_handler_(new RadioBrowserUrlHandler(app, this, this)),
|
{"By Country", "%1/json/countries",
|
||||||
|
"%1/json/stations/bycountryexact/%2?hidebroken=true", Type_Category},
|
||||||
|
{"By Language", "%1/json/languages",
|
||||||
|
"%1/json/stations/bylanguageexact/%2?hidebroken=true", Type_Category},
|
||||||
|
{"By Tag", "%1/json/tags", "%1/json/stations/bytagexact/%2?hidebroken=true",
|
||||||
|
Type_Category},
|
||||||
|
{"By Codec", "%1/json/codecs",
|
||||||
|
"%1/json/stations/bycodecexact/%2?hidebroken=true", Type_Category},
|
||||||
|
{"Top 100 Clicked", "",
|
||||||
|
"%1/json/stations/search?order=clickcount&reverse=true&limit=100",
|
||||||
|
Type_Top100},
|
||||||
|
{"Top 100 Voted", "",
|
||||||
|
"%1/json/stations/search?order=votes&reverse=true&limit=100", Type_Top100},
|
||||||
|
{"Top 100 Trending", "",
|
||||||
|
"%1/json/stations/search?order=clicktrend&reverse=true&limit=100",
|
||||||
|
Type_Top100}};
|
||||||
|
|
||||||
|
RadioBrowserService::RadioBrowserService(Application* app,
|
||||||
|
InternetModel* parent)
|
||||||
|
: InternetService(kServiceName, app, parent, parent),
|
||||||
root_(nullptr),
|
root_(nullptr),
|
||||||
context_menu_(nullptr),
|
context_menu_(nullptr),
|
||||||
network_(new NetworkAccessManager(this)),
|
network_(new NetworkAccessManager(this)),
|
||||||
streams_(name, "streams", kStreamsCacheDurationSecs),
|
name_(kServiceName),
|
||||||
name_(name),
|
main_server_url_(QStringLiteral("http://all.api.radio-browser.info")),
|
||||||
channel_list_url_(channel_list_url),
|
homepage_url_(QUrl("https://www.radio-browser.info")),
|
||||||
homepage_url_(homepage_url),
|
icon_(IconLoader::Load("radiobrowser", IconLoader::Provider)) {
|
||||||
donate_page_url_(donate_page_url),
|
|
||||||
icon_(icon) {
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
app_->player()->RegisterUrlHandler(url_handler_);
|
|
||||||
app_->global_search()->AddProvider(
|
app_->global_search()->AddProvider(
|
||||||
new RadioBrowserSearchProvider(this, app_, this));
|
new RadioBrowserSearchProvider(app_, this, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioBrowserServiceBase::~RadioBrowserServiceBase() {
|
RadioBrowserService::~RadioBrowserService() { delete context_menu_; }
|
||||||
delete context_menu_;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStandardItem* RadioBrowserServiceBase::CreateRootItem() {
|
QStandardItem* RadioBrowserService::CreateRootItem() {
|
||||||
root_ = new QStandardItem(icon_, name_);
|
root_ = new QStandardItem(icon_, name_);
|
||||||
root_->setData(true, InternetModel::Role_CanLazyLoad);
|
root_->setData(true, InternetModel::Role_CanLazyLoad);
|
||||||
return root_;
|
return root_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::LazyPopulate(QStandardItem* item) {
|
void RadioBrowserService::LazyPopulate(QStandardItem* item) {
|
||||||
switch (item->data(InternetModel::Role_Type).toInt()) {
|
switch (item->data(InternetModel::Role_Type).toInt()) {
|
||||||
case InternetModel::Type_Service:
|
case InternetModel::Type_Service:
|
||||||
RefreshStreams();
|
RefreshRootItem();
|
||||||
|
break;
|
||||||
|
case RadioBrowserService::Type_Category:
|
||||||
|
RefreshCategory(item);
|
||||||
|
break;
|
||||||
|
case RadioBrowserService::Type_CategoryItem:
|
||||||
|
RefreshCategoryItem(item);
|
||||||
|
break;
|
||||||
|
case RadioBrowserService::Type_Top100:
|
||||||
|
RefreshTop100(item);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::ShowContextMenu(const QPoint& global_pos) {
|
void RadioBrowserService::RefreshRootItem() {
|
||||||
|
if (root_->hasChildren()) root_->removeRows(0, root_->rowCount());
|
||||||
|
for (auto branch : RadioBrowserService::BranchList) {
|
||||||
|
QStandardItem* item = new QStandardItem(
|
||||||
|
IconLoader::Load("icon_radio", IconLoader::Lastfm), QString());
|
||||||
|
item->setText(branch.name);
|
||||||
|
item->setData(branch.type, InternetModel::Role_Type);
|
||||||
|
item->setData(branch.listUrl, RadioBrowserService::Role_ListUrl);
|
||||||
|
item->setData(branch.itemsUrl, RadioBrowserService::Role_ItemsUrl);
|
||||||
|
item->setData(true, InternetModel::Role_CanLazyLoad);
|
||||||
|
root_->appendRow(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioBrowserService::RefreshCategory(QStandardItem* item) {
|
||||||
|
QString determinedUrl = item->data(RadioBrowserService::Role_ListUrl)
|
||||||
|
.toString()
|
||||||
|
.arg(main_server_url_);
|
||||||
|
QUrl url(determinedUrl);
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(url));
|
||||||
|
int task_id = app_->task_manager()->StartTask(tr("Getting channels"));
|
||||||
|
|
||||||
|
NewClosure(reply, SIGNAL(finished()), this,
|
||||||
|
SLOT(RefreshCategoryFinished(QNetworkReply*, int, QStandardItem*)),
|
||||||
|
reply, task_id, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioBrowserService::RefreshCategoryItem(QStandardItem* item) {
|
||||||
|
QStandardItem* parent = item->parent();
|
||||||
|
QString determinedUrl = parent->data(RadioBrowserService::Role_ItemsUrl)
|
||||||
|
.toString()
|
||||||
|
.arg(main_server_url_, item->text());
|
||||||
|
QUrl url(determinedUrl);
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(url));
|
||||||
|
int task_id = app_->task_manager()->StartTask(tr("Getting channels"));
|
||||||
|
|
||||||
|
NewClosure(reply, SIGNAL(finished()), this,
|
||||||
|
SLOT(RefreshStreamsFinished(QNetworkReply*, int, QStandardItem*)),
|
||||||
|
reply, task_id, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioBrowserService::RefreshTop100(QStandardItem* item) {
|
||||||
|
QString determinedUrl = item->data(RadioBrowserService::Role_ItemsUrl)
|
||||||
|
.toString()
|
||||||
|
.arg(main_server_url_);
|
||||||
|
QUrl url(determinedUrl);
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(url));
|
||||||
|
int task_id = app_->task_manager()->StartTask(tr("Getting channels"));
|
||||||
|
|
||||||
|
NewClosure(reply, SIGNAL(finished()), this,
|
||||||
|
SLOT(RefreshStreamsFinished(QNetworkReply*, int, QStandardItem*)),
|
||||||
|
reply, task_id, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioBrowserService::ShowContextMenu(const QPoint& global_pos) {
|
||||||
|
if (!model()->current_index().isValid()) return;
|
||||||
|
QStandardItem* item = model()->itemFromIndex(model()->current_index());
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
if (!context_menu_) {
|
if (!context_menu_) {
|
||||||
context_menu_ = new QMenu;
|
context_menu_ = new QMenu;
|
||||||
context_menu_->addActions(GetPlaylistActions());
|
context_menu_->addActions(GetPlaylistActions());
|
||||||
|
@ -103,48 +176,40 @@ void RadioBrowserServiceBase::ShowContextMenu(const QPoint& global_pos) {
|
||||||
tr("Open %1 in browser").arg(homepage_url_.host()),
|
tr("Open %1 in browser").arg(homepage_url_.host()),
|
||||||
this, SLOT(Homepage()));
|
this, SLOT(Homepage()));
|
||||||
|
|
||||||
if (!donate_page_url_.isEmpty()) {
|
|
||||||
context_menu_->addAction(IconLoader::Load("download", IconLoader::Base),
|
|
||||||
tr("Donate"), this, SLOT(Donate()));
|
|
||||||
}
|
|
||||||
|
|
||||||
context_menu_->addAction(IconLoader::Load("view-refresh", IconLoader::Base),
|
context_menu_->addAction(IconLoader::Load("view-refresh", IconLoader::Base),
|
||||||
tr("Refresh channels"), this,
|
tr("Refresh channels"), this,
|
||||||
SLOT(ForceRefreshStreams()));
|
SLOT(LazyPopulate(item)));
|
||||||
}
|
}
|
||||||
|
|
||||||
context_menu_->popup(global_pos);
|
context_menu_->popup(global_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::ForceRefreshStreams() {
|
void RadioBrowserService::RefreshCategoryFinished(QNetworkReply* reply,
|
||||||
QNetworkReply* reply = network_->get(QNetworkRequest(channel_list_url_));
|
int task_id,
|
||||||
int task_id = app_->task_manager()->StartTask(tr("Getting channels"));
|
QStandardItem* item) {
|
||||||
|
|
||||||
NewClosure(reply, SIGNAL(finished()), this,
|
|
||||||
SLOT(RefreshStreamsFinished(QNetworkReply*, int)), reply, task_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioBrowserServiceBase::RefreshStreamsFinished(QNetworkReply* reply,
|
|
||||||
int task_id) {
|
|
||||||
app_->task_manager()->SetTaskFinished(task_id);
|
app_->task_manager()->SetTaskFinished(task_id);
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
QJsonDocument document = ParseJsonReply(reply);
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
QStringList list;
|
||||||
app_->AddError(
|
QJsonArray contents = document.array();
|
||||||
tr("Failed to get channel list:\n%1").arg(reply->errorString()));
|
qLog(Debug) << "RadioBrowser station list found:" << contents.size();
|
||||||
return;
|
for (const QJsonValue& c : contents) {
|
||||||
|
QJsonObject item = c.toObject();
|
||||||
|
list << item["name"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PopulateCategory(item, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioBrowserService::RefreshStreamsFinished(QNetworkReply* reply,
|
||||||
|
int task_id,
|
||||||
|
QStandardItem* item) {
|
||||||
|
app_->task_manager()->SetTaskFinished(task_id);
|
||||||
|
reply->deleteLater();
|
||||||
|
QJsonDocument document = ParseJsonReply(reply);
|
||||||
|
|
||||||
StreamList list;
|
StreamList list;
|
||||||
|
|
||||||
QJsonParseError error;
|
|
||||||
QJsonDocument document = QJsonDocument::fromJson(reply->readAll(), &error);
|
|
||||||
if (error.error != QJsonParseError::NoError) {
|
|
||||||
app_->AddError(
|
|
||||||
tr("Failed to parse channel list:\n%1").arg(error.errorString()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray contents = document.array();
|
QJsonArray contents = document.array();
|
||||||
qLog(Debug) << "RadioBrowser station list found:" << contents.size();
|
qLog(Debug) << "RadioBrowser station list found:" << contents.size();
|
||||||
for (const QJsonValue& c : contents) {
|
for (const QJsonValue& c : contents) {
|
||||||
|
@ -152,25 +217,19 @@ void RadioBrowserServiceBase::RefreshStreamsFinished(QNetworkReply* reply,
|
||||||
ReadStation(item, &list);
|
ReadStation(item, &list);
|
||||||
}
|
}
|
||||||
|
|
||||||
streams_.Update(list);
|
PopulateStreams(item, list);
|
||||||
streams_.Sort();
|
|
||||||
|
|
||||||
// Only update the item's children if it's already been populated
|
|
||||||
if (!root_->data(InternetModel::Role_CanLazyLoad).toBool()) PopulateStreams();
|
|
||||||
|
|
||||||
emit StreamsChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::ReadStation(QJsonObject& item,
|
void RadioBrowserService::ReadStation(QJsonObject& item, StreamList* ret) {
|
||||||
StreamList* ret) {
|
|
||||||
Stream stream;
|
Stream stream;
|
||||||
stream.name_ = item["name"].toString();
|
stream.name_ = item["name"].toString();
|
||||||
|
stream.uuid_ = item["stationuuid"].toString();
|
||||||
QUrl url(item["url"].toString());
|
QUrl url(item["url"].toString());
|
||||||
stream.url_ = url;
|
stream.url_ = url;
|
||||||
ret->append(stream);
|
ret->append(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
Song RadioBrowserServiceBase::Stream::ToSong(const QString& prefix) const {
|
Song RadioBrowserService::Stream::ToSong(const QString& prefix) const {
|
||||||
QString song_title = name_.trimmed();
|
QString song_title = name_.trimmed();
|
||||||
if (!song_title.startsWith(prefix)) {
|
if (!song_title.startsWith(prefix)) {
|
||||||
song_title = prefix + " " + song_title;
|
song_title = prefix + " " + song_title;
|
||||||
|
@ -184,38 +243,36 @@ Song RadioBrowserServiceBase::Stream::ToSong(const QString& prefix) const {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::Homepage() {
|
void RadioBrowserService::Homepage() {
|
||||||
QDesktopServices::openUrl(homepage_url_);
|
QDesktopServices::openUrl(homepage_url_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::Donate() {
|
PlaylistItem::Options RadioBrowserService::playlistitem_options() const {
|
||||||
QDesktopServices::openUrl(donate_page_url_);
|
return PlaylistItem::PauseDisabled | PlaylistItem::SeekDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaylistItem::Options RadioBrowserServiceBase::playlistitem_options() const {
|
void RadioBrowserService::PopulateCategory(QStandardItem* parentItem,
|
||||||
return PlaylistItem::PauseDisabled;
|
QStringList& elements) {
|
||||||
}
|
if (parentItem->hasChildren())
|
||||||
|
parentItem->removeRows(0, parentItem->rowCount());
|
||||||
|
|
||||||
RadioBrowserServiceBase::StreamList RadioBrowserServiceBase::Streams() {
|
for (const QString& element : elements) {
|
||||||
if (IsStreamListStale()) {
|
QStandardItem* item = new QStandardItem(
|
||||||
metaObject()->invokeMethod(this, "ForceRefreshStreams",
|
IconLoader::Load("icon_radio", IconLoader::Lastfm), QString());
|
||||||
Qt::QueuedConnection);
|
item->setText(element);
|
||||||
|
item->setData(RadioBrowserService::Type_CategoryItem,
|
||||||
|
InternetModel::Role_Type);
|
||||||
|
item->setData(true, InternetModel::Role_CanLazyLoad);
|
||||||
|
parentItem->appendRow(item);
|
||||||
}
|
}
|
||||||
return streams_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::RefreshStreams() {
|
void RadioBrowserService::PopulateStreams(QStandardItem* parentItem,
|
||||||
if (IsStreamListStale()) {
|
StreamList& streams) {
|
||||||
ForceRefreshStreams();
|
if (parentItem->hasChildren())
|
||||||
return;
|
parentItem->removeRows(0, parentItem->rowCount());
|
||||||
}
|
|
||||||
PopulateStreams();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioBrowserServiceBase::PopulateStreams() {
|
for (const Stream& stream : streams) {
|
||||||
if (root_->hasChildren()) root_->removeRows(0, root_->rowCount());
|
|
||||||
|
|
||||||
for (const Stream& stream : streams_) {
|
|
||||||
QStandardItem* item = new QStandardItem(
|
QStandardItem* item = new QStandardItem(
|
||||||
IconLoader::Load("icon_radio", IconLoader::Lastfm), QString());
|
IconLoader::Load("icon_radio", IconLoader::Lastfm), QString());
|
||||||
item->setText(stream.name_);
|
item->setText(stream.name_);
|
||||||
|
@ -223,32 +280,73 @@ void RadioBrowserServiceBase::PopulateStreams() {
|
||||||
InternetModel::Role_SongMetadata);
|
InternetModel::Role_SongMetadata);
|
||||||
item->setData(InternetModel::PlayBehaviour_SingleItem,
|
item->setData(InternetModel::PlayBehaviour_SingleItem,
|
||||||
InternetModel::Role_PlayBehaviour);
|
InternetModel::Role_PlayBehaviour);
|
||||||
|
item->setData(stream.uuid_,
|
||||||
|
RadioBrowserService::Role_StationUuid);
|
||||||
|
|
||||||
root_->appendRow(item);
|
parentItem->appendRow(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream& out,
|
QDataStream& operator<<(QDataStream& out,
|
||||||
const RadioBrowserServiceBase::Stream& stream) {
|
const RadioBrowserService::Stream& stream) {
|
||||||
out << stream.name_ << stream.url_;
|
out << stream.name_ << stream.url_;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator>>(QDataStream& in,
|
QDataStream& operator>>(QDataStream& in,
|
||||||
RadioBrowserServiceBase::Stream& stream) {
|
RadioBrowserService::Stream& stream) {
|
||||||
in >> stream.name_ >> stream.url_;
|
in >> stream.name_ >> stream.url_;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioBrowserServiceBase::ReloadSettings() {
|
void RadioBrowserService::ReloadSettings() {}
|
||||||
streams_.Load();
|
|
||||||
streams_.Sort();
|
void RadioBrowserService::Search(int search_id, const QString& query,
|
||||||
|
const int limit) {
|
||||||
|
QString determinedUrl =
|
||||||
|
RadioBrowserService::SearchUrl.arg(main_server_url_, query)
|
||||||
|
.arg(limit);
|
||||||
|
QUrl url(determinedUrl);
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(url));
|
||||||
|
int task_id = app_->task_manager()->StartTask(tr("Getting channels"));
|
||||||
|
|
||||||
|
NewClosure(reply, SIGNAL(finished()), this,
|
||||||
|
SLOT(SearchFinishedInternal(QNetworkReply*, int, int)), reply,
|
||||||
|
task_id, search_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioBrowserService::RadioBrowserService(Application* app,
|
void RadioBrowserService::SearchFinishedInternal(QNetworkReply* reply,
|
||||||
InternetModel* parent)
|
int task_id,
|
||||||
: RadioBrowserServiceBase(
|
int search_id) {
|
||||||
app, parent, "Radio-Browser.info",
|
app_->task_manager()->SetTaskFinished(task_id);
|
||||||
QUrl("http://all.api.radio-browser.info/json/stations"),
|
reply->deleteLater();
|
||||||
QUrl("https://www.radio-browser.info"), QUrl(),
|
QJsonDocument document = ParseJsonReply(reply);
|
||||||
IconLoader::Load("radiobrowser", IconLoader::Provider)) {}
|
|
||||||
|
StreamList list;
|
||||||
|
QJsonArray contents = document.array();
|
||||||
|
qLog(Debug) << "RadioBrowser station list found:" << contents.size();
|
||||||
|
for (const QJsonValue& c : contents) {
|
||||||
|
QJsonObject item = c.toObject();
|
||||||
|
ReadStation(item, &list);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit SearchFinished(search_id, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioBrowserService::ItemNowPlaying(QStandardItem* item) {
|
||||||
|
QString station_uuid = item->data(RadioBrowserService::Role_StationUuid).toString();
|
||||||
|
if(station_uuid.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString determinedUrl =
|
||||||
|
RadioBrowserService::PlayClickUrl.arg(main_server_url_, station_uuid);
|
||||||
|
QUrl url(determinedUrl);
|
||||||
|
|
||||||
|
qLog(Debug) << "RadioBrowser station played:" << determinedUrl;
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(url));
|
||||||
|
connect(reply, &QNetworkReply::finished, [this, reply]()
|
||||||
|
{
|
||||||
|
reply->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2010-2013, David Sansome <me@davidsansome.com>
|
Copyright 2021, Fabio Bas <ctrlaltca@gmail.com>
|
||||||
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
|
|
||||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -23,6 +21,7 @@
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include "core/cachedlist.h"
|
#include "core/cachedlist.h"
|
||||||
|
#include "internet/core/internetmodel.h"
|
||||||
#include "internet/core/internetservice.h"
|
#include "internet/core/internetservice.h"
|
||||||
|
|
||||||
class RadioBrowserUrlHandler;
|
class RadioBrowserUrlHandler;
|
||||||
|
@ -31,87 +30,103 @@ class QNetworkAccessManager;
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
|
||||||
class RadioBrowserServiceBase : public InternetService {
|
class RadioBrowserService : public InternetService {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RadioBrowserServiceBase(Application* app, InternetModel* parent,
|
RadioBrowserService(Application* app, InternetModel* parent);
|
||||||
const QString& name, const QUrl& channel_list_url,
|
~RadioBrowserService();
|
||||||
const QUrl& homepage_url,
|
|
||||||
const QUrl& donate_page_url, const QIcon& icon);
|
|
||||||
~RadioBrowserServiceBase();
|
|
||||||
|
|
||||||
enum ItemType {
|
enum ItemType {
|
||||||
Type_Stream = 2000,
|
Type_Stream = 2000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
Type_Category = InternetModel::TypeCount,
|
||||||
|
Type_CategoryItem,
|
||||||
|
Type_Top100,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Role {
|
||||||
|
Role_ListUrl = InternetModel::RoleCount,
|
||||||
|
Role_ItemsUrl,
|
||||||
|
Role_StationUuid,
|
||||||
|
};
|
||||||
|
|
||||||
struct Stream {
|
struct Stream {
|
||||||
QString name_;
|
QString name_;
|
||||||
QUrl url_;
|
QUrl url_;
|
||||||
|
QString uuid_;
|
||||||
|
|
||||||
Song ToSong(const QString& prefix) const;
|
Song ToSong(const QString& prefix) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Branch {
|
||||||
|
QString name;
|
||||||
|
QString listUrl;
|
||||||
|
QString itemsUrl;
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QList<Branch> BranchList;
|
||||||
|
static QString SearchUrl;
|
||||||
|
static QString PlayClickUrl;
|
||||||
|
|
||||||
typedef QList<Stream> StreamList;
|
typedef QList<Stream> StreamList;
|
||||||
|
|
||||||
static const int kStreamsCacheDurationSecs;
|
static const char* kServiceName;
|
||||||
|
|
||||||
const QString& url_scheme() const { return url_scheme_; }
|
|
||||||
const QIcon& icon() const { return icon_; }
|
const QIcon& icon() const { return icon_; }
|
||||||
|
|
||||||
QStandardItem* CreateRootItem();
|
QStandardItem* CreateRootItem();
|
||||||
void LazyPopulate(QStandardItem* item);
|
|
||||||
void ShowContextMenu(const QPoint& global_pos);
|
void ShowContextMenu(const QPoint& global_pos);
|
||||||
|
|
||||||
PlaylistItem::Options playlistitem_options() const;
|
PlaylistItem::Options playlistitem_options() const;
|
||||||
QNetworkAccessManager* network() const { return network_; }
|
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
void Search(int search_id, const QString& query, const int limit);
|
||||||
bool IsStreamListStale() const { return streams_.IsStale(); }
|
void ItemNowPlaying(QStandardItem* item) override;
|
||||||
StreamList Streams();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void StreamsChanged();
|
void SearchFinished(int search_id,
|
||||||
|
RadioBrowserService::StreamList streams);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ForceRefreshStreams();
|
void LazyPopulate(QStandardItem* item);
|
||||||
void RefreshStreams();
|
|
||||||
void RefreshStreamsFinished(QNetworkReply* reply, int task_id);
|
void RefreshRootItem();
|
||||||
|
void RefreshCategory(QStandardItem* item);
|
||||||
|
void RefreshCategoryItem(QStandardItem* item);
|
||||||
|
void RefreshTop100(QStandardItem* item);
|
||||||
|
|
||||||
|
void RefreshCategoryFinished(QNetworkReply* reply, int task_id,
|
||||||
|
QStandardItem* item);
|
||||||
|
void RefreshStreamsFinished(QNetworkReply* reply, int task_id,
|
||||||
|
QStandardItem* item);
|
||||||
|
void SearchFinishedInternal(QNetworkReply* reply, int task_id, int search_id);
|
||||||
|
|
||||||
void Homepage();
|
void Homepage();
|
||||||
void Donate();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ReadStation(QJsonObject& value, StreamList* ret);
|
void ReadStation(QJsonObject& value, StreamList* ret);
|
||||||
void PopulateStreams();
|
void PopulateCategory(QStandardItem* parentItem, QStringList& elements);
|
||||||
|
void PopulateStreams(QStandardItem* parentItem, StreamList& streams);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString url_scheme_;
|
|
||||||
RadioBrowserUrlHandler* url_handler_;
|
|
||||||
|
|
||||||
QStandardItem* root_;
|
QStandardItem* root_;
|
||||||
QMenu* context_menu_;
|
QMenu* context_menu_;
|
||||||
|
|
||||||
QNetworkAccessManager* network_;
|
QNetworkAccessManager* network_;
|
||||||
|
|
||||||
CachedList<Stream> streams_;
|
|
||||||
|
|
||||||
const QString name_;
|
const QString name_;
|
||||||
const QUrl channel_list_url_;
|
const QString main_server_url_;
|
||||||
const QUrl homepage_url_;
|
const QUrl homepage_url_;
|
||||||
const QUrl donate_page_url_;
|
|
||||||
const QIcon icon_;
|
const QIcon icon_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RadioBrowserService : public RadioBrowserServiceBase {
|
|
||||||
public:
|
|
||||||
RadioBrowserService(Application* app, InternetModel* parent);
|
|
||||||
};
|
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream& out,
|
QDataStream& operator<<(QDataStream& out,
|
||||||
const RadioBrowserService::Stream& stream);
|
const RadioBrowserService::Stream& stream);
|
||||||
QDataStream& operator>>(QDataStream& in,
|
QDataStream& operator>>(QDataStream& in, RadioBrowserService::Stream& stream);
|
||||||
RadioBrowserService::Stream& stream);
|
|
||||||
Q_DECLARE_METATYPE(RadioBrowserService::Stream)
|
Q_DECLARE_METATYPE(RadioBrowserService::Stream)
|
||||||
|
|
||||||
#endif // INTERNET_RADIOBROWSER_RADIOBROWSERSERVICE_H_
|
#endif // INTERNET_RADIOBROWSER_RADIOBROWSERSERVICE_H_
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2011-2013, David Sansome <me@davidsansome.com>
|
|
||||||
Copyright 2012, Olaf Christ <olafc81@gmail.com>
|
|
||||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
||||||
Copyright 2014, John Maguire <john.maguire@gmail.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 "radiobrowserurlhandler.h"
|
|
||||||
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QSettings>
|
|
||||||
#include <QTemporaryFile>
|
|
||||||
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "core/taskmanager.h"
|
|
||||||
#include "radiobrowserservice.h"
|
|
||||||
#include "internet/core/internetmodel.h"
|
|
||||||
#include "playlistparsers/playlistparser.h"
|
|
||||||
|
|
||||||
RadioBrowserUrlHandler::RadioBrowserUrlHandler(
|
|
||||||
Application* app, RadioBrowserServiceBase* service, QObject* parent)
|
|
||||||
: UrlHandler(parent), app_(app), service_(service), task_id_(0) {}
|
|
||||||
|
|
||||||
QString RadioBrowserUrlHandler::scheme() const {
|
|
||||||
return service_->url_scheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon RadioBrowserUrlHandler::icon() const { return service_->icon(); }
|
|
||||||
|
|
||||||
UrlHandler::LoadResult RadioBrowserUrlHandler::StartLoading(
|
|
||||||
const QUrl& url) {
|
|
||||||
QUrl playlist_url = url;
|
|
||||||
playlist_url.setScheme("https");
|
|
||||||
|
|
||||||
// Load the playlist
|
|
||||||
QNetworkReply* reply =
|
|
||||||
service_->network()->get(QNetworkRequest(playlist_url));
|
|
||||||
connect(reply, SIGNAL(finished()), SLOT(LoadPlaylistFinished()));
|
|
||||||
|
|
||||||
if (!task_id_)
|
|
||||||
task_id_ = app_->task_manager()->StartTask(tr("Loading stream"));
|
|
||||||
|
|
||||||
return LoadResult(url, LoadResult::WillLoadAsynchronously);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioBrowserUrlHandler::LoadPlaylistFinished() {
|
|
||||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
|
||||||
app_->task_manager()->SetTaskFinished(task_id_);
|
|
||||||
task_id_ = 0;
|
|
||||||
|
|
||||||
QUrl original_url(reply->url());
|
|
||||||
original_url.setScheme(scheme());
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
// TODO((David Sansome): Error handling
|
|
||||||
qLog(Error) << reply->errorString();
|
|
||||||
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::NoMoreTracks));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the playlist
|
|
||||||
PlaylistParser parser(nullptr);
|
|
||||||
QList<Song> songs = parser.LoadFromDevice(reply);
|
|
||||||
|
|
||||||
qLog(Info) << "Loading station finished, got" << songs.count() << "songs";
|
|
||||||
|
|
||||||
// Failed to get playlist?
|
|
||||||
if (songs.count() == 0) {
|
|
||||||
qLog(Error) << "Error loading" << scheme() << "playlist";
|
|
||||||
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::NoMoreTracks));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit AsyncLoadComplete(
|
|
||||||
LoadResult(original_url, LoadResult::TrackAvailable, songs[0].url()));
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2011-2013, David Sansome <me@davidsansome.com>
|
|
||||||
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
|
|
||||||
Copyright 2014, John Maguire <john.maguire@gmail.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 INTERNET_RADIOBROWSER_RADIOBROWSERURLHANDLER_H_
|
|
||||||
#define INTERNET_RADIOBROWSER_RADIOBROWSERURLHANDLER_H_
|
|
||||||
|
|
||||||
#include "core/urlhandler.h"
|
|
||||||
|
|
||||||
class Application;
|
|
||||||
class RadioBrowserServiceBase;
|
|
||||||
|
|
||||||
class RadioBrowserUrlHandler : public UrlHandler {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
RadioBrowserUrlHandler(Application* app,
|
|
||||||
RadioBrowserServiceBase* service,
|
|
||||||
QObject* parent);
|
|
||||||
|
|
||||||
QString scheme() const;
|
|
||||||
QIcon icon() const;
|
|
||||||
LoadResult StartLoading(const QUrl& url);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void LoadPlaylistFinished();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Application* app_;
|
|
||||||
RadioBrowserServiceBase* service_;
|
|
||||||
|
|
||||||
int task_id_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INTERNET_RADIOBROWSER_RADIOBROWSERURLHANDLER_H_
|
|
Loading…
Reference in New Issue