Add c++ implementations of the di.fm and sky.fm radio services
This commit is contained in:
parent
b6ee23dc43
commit
a0258a9e81
|
@ -340,5 +340,8 @@
|
||||||
<file>pythonlibs/uic/uiparser.py</file>
|
<file>pythonlibs/uic/uiparser.py</file>
|
||||||
<file>pythonlibs/clementinelogging.py</file>
|
<file>pythonlibs/clementinelogging.py</file>
|
||||||
<file>nyancat.png</file>
|
<file>nyancat.png</file>
|
||||||
|
<file>providers/digitallyimported.png</file>
|
||||||
|
<file>providers/skyfm.png</file>
|
||||||
|
<file>providers/digitallyimported-32.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 211 B |
Binary file not shown.
After Width: | Height: | Size: 864 B |
|
@ -118,6 +118,10 @@ set(SOURCES
|
||||||
engines/gstenginepipeline.cpp
|
engines/gstenginepipeline.cpp
|
||||||
engines/gstelementdeleter.cpp
|
engines/gstelementdeleter.cpp
|
||||||
|
|
||||||
|
internet/digitallyimportedconfig.cpp
|
||||||
|
internet/digitallyimportedservice.cpp
|
||||||
|
internet/digitallyimportedservicebase.cpp
|
||||||
|
internet/digitallyimportedurlhandler.cpp
|
||||||
internet/icecastbackend.cpp
|
internet/icecastbackend.cpp
|
||||||
internet/icecastfilterwidget.cpp
|
internet/icecastfilterwidget.cpp
|
||||||
internet/icecastmodel.cpp
|
internet/icecastmodel.cpp
|
||||||
|
@ -136,6 +140,7 @@ set(SOURCES
|
||||||
internet/magnatuneservice.cpp
|
internet/magnatuneservice.cpp
|
||||||
internet/magnatuneurlhandler.cpp
|
internet/magnatuneurlhandler.cpp
|
||||||
internet/savedradio.cpp
|
internet/savedradio.cpp
|
||||||
|
internet/skyfmservice.cpp
|
||||||
internet/somafmservice.cpp
|
internet/somafmservice.cpp
|
||||||
internet/somafmurlhandler.cpp
|
internet/somafmurlhandler.cpp
|
||||||
|
|
||||||
|
@ -346,6 +351,8 @@ set(HEADERS
|
||||||
engines/gstenginepipeline.h
|
engines/gstenginepipeline.h
|
||||||
engines/gstelementdeleter.h
|
engines/gstelementdeleter.h
|
||||||
|
|
||||||
|
internet/digitallyimportedconfig.h
|
||||||
|
internet/digitallyimportedservicebase.h
|
||||||
internet/icecastbackend.h
|
internet/icecastbackend.h
|
||||||
internet/icecastfilterwidget.h
|
internet/icecastfilterwidget.h
|
||||||
internet/icecastmodel.h
|
internet/icecastmodel.h
|
||||||
|
@ -361,6 +368,7 @@ set(HEADERS
|
||||||
internet/magnatunedownloaddialog.h
|
internet/magnatunedownloaddialog.h
|
||||||
internet/magnatuneservice.h
|
internet/magnatuneservice.h
|
||||||
internet/savedradio.h
|
internet/savedradio.h
|
||||||
|
internet/skyfmservice.h
|
||||||
internet/somafmservice.h
|
internet/somafmservice.h
|
||||||
internet/somafmurlhandler.h
|
internet/somafmurlhandler.h
|
||||||
|
|
||||||
|
@ -502,6 +510,7 @@ set(UI
|
||||||
|
|
||||||
devices/deviceproperties.ui
|
devices/deviceproperties.ui
|
||||||
|
|
||||||
|
internet/digitallyimportedconfig.ui
|
||||||
internet/icecastfilterwidget.ui
|
internet/icecastfilterwidget.ui
|
||||||
internet/magnatuneconfig.ui
|
internet/magnatuneconfig.ui
|
||||||
internet/magnatunedownloaddialog.ui
|
internet/magnatunedownloaddialog.ui
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* 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 "digitallyimportedconfig.h"
|
||||||
|
#include "digitallyimportedservicebase.h"
|
||||||
|
#include "ui_digitallyimportedconfig.h"
|
||||||
|
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
|
||||||
|
DigitallyImportedConfig::DigitallyImportedConfig(QWidget *parent)
|
||||||
|
: QWidget(parent),
|
||||||
|
ui_(new Ui_DigitallyImportedConfig)
|
||||||
|
{
|
||||||
|
ui_->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
DigitallyImportedConfig::~DigitallyImportedConfig() {
|
||||||
|
delete ui_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedConfig::Load() {
|
||||||
|
QSettings s;
|
||||||
|
s.beginGroup(DigitallyImportedServiceBase::kSettingsGroup);
|
||||||
|
|
||||||
|
ui_->audio_type->setCurrentIndex(s.value("audio_type", 0).toInt());
|
||||||
|
ui_->username->setText(s.value("username").toString());
|
||||||
|
ui_->password->setText(s.value("password").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedConfig::Save() {
|
||||||
|
QSettings s;
|
||||||
|
s.beginGroup(DigitallyImportedServiceBase::kSettingsGroup);
|
||||||
|
|
||||||
|
s.setValue("audio_type", ui_->audio_type->currentIndex());
|
||||||
|
s.setValue("username", ui_->username->text());
|
||||||
|
s.setValue("password", ui_->password->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* 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 DIGITALLYIMPORTEDCONFIG_H
|
||||||
|
#define DIGITALLYIMPORTEDCONFIG_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class Ui_DigitallyImportedConfig;
|
||||||
|
|
||||||
|
class DigitallyImportedConfig : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DigitallyImportedConfig(QWidget* parent = 0);
|
||||||
|
~DigitallyImportedConfig();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void Load();
|
||||||
|
void Save();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui_DigitallyImportedConfig* ui_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DIGITALLYIMPORTEDCONFIG_H
|
|
@ -0,0 +1,162 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DigitallyImportedConfig</class>
|
||||||
|
<widget class="QWidget" name="DigitallyImportedConfig">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>715</width>
|
||||||
|
<height>425</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_10">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Account details (Premium)</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_22">
|
||||||
|
<property name="text">
|
||||||
|
<string>Digitally Imported username</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="username"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_23">
|
||||||
|
<property name="text">
|
||||||
|
<string>Digitally Imported password</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="password">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_24">
|
||||||
|
<property name="text">
|
||||||
|
<string>You can <b>listen for free</b> without an account, but Premium members can listen to <b>higher quality</b> streams without advertisements.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="upgrade_link">
|
||||||
|
<property name="text">
|
||||||
|
<string><a href="http://www.di.fm/premium/">Upgrade to Premium now</a></string>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_9">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Preferences</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_21">
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="audio_type">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>MP3 96k</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>MP3 256k (Premium only)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>AAC 32k</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>AAC 64k (Premium only)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>AAC 128k (Premium only)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Windows Media 40k</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Windows Media 64k (Premium only)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Windows Media 128k (Premium only)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_7">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>166</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,64 @@
|
||||||
|
/* 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 "digitallyimportedservice.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkCookieJar>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
DigitallyImportedService::DigitallyImportedService(InternetModel* model, QObject* parent)
|
||||||
|
: DigitallyImportedServiceBase(
|
||||||
|
"DigitallyImported", "Digitally Imported", QUrl("http://www.di.fm"),
|
||||||
|
"di.fm", QUrl("http://listen.di.fm"), "digitallyimported",
|
||||||
|
QIcon(":/providers/digitallyimported.png"), model, parent)
|
||||||
|
{
|
||||||
|
playlists_ = QList<Playlist>()
|
||||||
|
<< Playlist(false, "http://listen.di.fm/public3/%1.pls")
|
||||||
|
<< Playlist(true, "http://www.di.fm/listen/%1/premium.pls")
|
||||||
|
<< Playlist(false, "http://listen.di.fm/public2/%1.pls")
|
||||||
|
<< Playlist(true, "http://www.di.fm/listen/%1/64k.pls")
|
||||||
|
<< Playlist(true, "http://www.di.fm/listen/%1/128k.pls")
|
||||||
|
<< Playlist(false, "http://listen.di.fm/public5/%1.asx")
|
||||||
|
<< Playlist(true, "http://www.di.fm/listen/%1/64k.asx")
|
||||||
|
<< Playlist(true, "http://www.di.fm/listen/%1/128k.asx");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedService::ReloadSettings() {
|
||||||
|
DigitallyImportedServiceBase::ReloadSettings();
|
||||||
|
|
||||||
|
QNetworkCookieJar* cookies = new QNetworkCookieJar;
|
||||||
|
|
||||||
|
if (is_premium_account()) {
|
||||||
|
qLog(Debug) << "Setting premium account cookies";
|
||||||
|
cookies->setCookiesFromUrl(QList<QNetworkCookie>()
|
||||||
|
<< QNetworkCookie("_amember_ru", username_.toUtf8())
|
||||||
|
<< QNetworkCookie("_amember_rp", password_.toUtf8()),
|
||||||
|
QUrl("http://www.di.fm/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
network_->setCookieJar(cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedService::LoadStation(const QString& key) {
|
||||||
|
QUrl playlist_url(playlists_[audio_type_].url_template_.arg(key));
|
||||||
|
qLog(Debug) << "Getting playlist URL" << playlist_url;
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(playlist_url));
|
||||||
|
connect(reply, SIGNAL(finished()), SLOT(LoadPlaylistFinished()));
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* 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 DIGITALLYIMPORTEDSERVICE_H
|
||||||
|
#define DIGITALLYIMPORTEDSERVICE_H
|
||||||
|
|
||||||
|
#include "digitallyimportedservicebase.h"
|
||||||
|
|
||||||
|
class DigitallyImportedService : public DigitallyImportedServiceBase {
|
||||||
|
public:
|
||||||
|
DigitallyImportedService(InternetModel* model, QObject* parent = NULL);
|
||||||
|
|
||||||
|
void ReloadSettings();
|
||||||
|
|
||||||
|
void LoadStation(const QString& key);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DIGITALLYIMPORTEDSERVICE_H
|
|
@ -0,0 +1,221 @@
|
||||||
|
/* 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 "digitallyimportedservicebase.h"
|
||||||
|
#include "digitallyimportedurlhandler.h"
|
||||||
|
#include "internetmodel.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/network.h"
|
||||||
|
#include "core/player.h"
|
||||||
|
#include "core/taskmanager.h"
|
||||||
|
#include "ui/iconloader.h"
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
const char* DigitallyImportedServiceBase::kSettingsGroup = "digitally_imported";
|
||||||
|
|
||||||
|
|
||||||
|
DigitallyImportedServiceBase::DigitallyImportedServiceBase(
|
||||||
|
const QString& name, const QString& description, const QUrl& homepage_url,
|
||||||
|
const QString& homepage_name, const QUrl& stream_list_url,
|
||||||
|
const QString& url_scheme, const QIcon& icon,
|
||||||
|
InternetModel* model, QObject* parent)
|
||||||
|
: InternetService(name, model, parent),
|
||||||
|
network_(new NetworkAccessManager(this)),
|
||||||
|
url_handler_(new DigitallyImportedUrlHandler(this)),
|
||||||
|
audio_type_(0),
|
||||||
|
task_id_(-1),
|
||||||
|
homepage_url_(homepage_url),
|
||||||
|
homepage_name_(homepage_name),
|
||||||
|
stream_list_url_(stream_list_url),
|
||||||
|
icon_(icon),
|
||||||
|
service_description_(description),
|
||||||
|
url_scheme_(url_scheme),
|
||||||
|
root_(NULL),
|
||||||
|
context_menu_(NULL),
|
||||||
|
context_item_(NULL)
|
||||||
|
{
|
||||||
|
model->player()->RegisterUrlHandler(url_handler_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DigitallyImportedServiceBase::~DigitallyImportedServiceBase() {
|
||||||
|
delete context_menu_;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItem* DigitallyImportedServiceBase::CreateRootItem() {
|
||||||
|
root_ = new QStandardItem(icon_, service_description_);
|
||||||
|
root_->setData(true, InternetModel::Role_CanLazyLoad);
|
||||||
|
return root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::LazyPopulate(QStandardItem* parent) {
|
||||||
|
if (parent == root_) {
|
||||||
|
RefreshStreams();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::RefreshStreams() {
|
||||||
|
if (task_id_ != -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qLog(Info) << "Getting stream list from" << stream_list_url_;
|
||||||
|
|
||||||
|
// Get the list of streams
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(stream_list_url_));
|
||||||
|
connect(reply, SIGNAL(finished()), SLOT(RefreshStreamsFinished()));
|
||||||
|
|
||||||
|
// Start a task to tell the user we're busy
|
||||||
|
task_id_ = model()->task_manager()->StartTask(tr("Getting streams"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::RefreshStreamsFinished() {
|
||||||
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
if (!reply) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
model()->task_manager()->SetTaskFinished(task_id_);
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
const QString data = QString::fromUtf8(reply->readAll());
|
||||||
|
|
||||||
|
// Poor man's JSON parser that's good enough for the stream lists and means
|
||||||
|
// we don't have to pull in QJSON as a dependency.
|
||||||
|
const QRegExp re("\\{"
|
||||||
|
"\"id\":(\\d+),"
|
||||||
|
"\"key\":\"([^\"]+)\","
|
||||||
|
"\"name\":\"([^\"]+)\","
|
||||||
|
"\"description\":\"([^\"]+)\"");
|
||||||
|
|
||||||
|
QList<Stream> streams;
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos >= 0) {
|
||||||
|
pos = re.indexIn(data, pos);
|
||||||
|
if (pos == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += re.matchedLength();
|
||||||
|
|
||||||
|
Stream stream;
|
||||||
|
stream.id_ = re.cap(1).toInt();
|
||||||
|
stream.key_ = re.cap(2).replace("\\/", "/");
|
||||||
|
stream.name_ = re.cap(3).replace("\\/", "/");
|
||||||
|
stream.description_ = re.cap(4).replace("\\/", "/");
|
||||||
|
streams << stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by name
|
||||||
|
qSort(streams);
|
||||||
|
|
||||||
|
// Add each stream to the model
|
||||||
|
foreach (const Stream& stream, streams) {
|
||||||
|
Song song;
|
||||||
|
song.set_title(stream.name_);
|
||||||
|
song.set_artist(service_description_);
|
||||||
|
song.set_url(QUrl(url_scheme_ + "://" + stream.key_));
|
||||||
|
|
||||||
|
QStandardItem* item = new QStandardItem(QIcon(":/last.fm/icon_radio.png"),
|
||||||
|
stream.name_);
|
||||||
|
item->setData(stream.description_, Qt::ToolTipRole);
|
||||||
|
item->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour);
|
||||||
|
item->setData(QVariant::fromValue(song), InternetModel::Role_SongMetadata);
|
||||||
|
root_->appendRow(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::Homepage() {
|
||||||
|
QDesktopServices::openUrl(homepage_url_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::ReloadSettings() {
|
||||||
|
QSettings s;
|
||||||
|
s.beginGroup(kSettingsGroup);
|
||||||
|
|
||||||
|
audio_type_ = s.value("audio_type", 0).toInt();
|
||||||
|
username_ = s.value("username").toString();
|
||||||
|
password_ = s.value("password").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::ShowContextMenu(
|
||||||
|
const QModelIndex& index, const QPoint& global_pos) {
|
||||||
|
if (!context_menu_) {
|
||||||
|
context_menu_ = new QMenu;
|
||||||
|
context_menu_->addActions(GetPlaylistActions());
|
||||||
|
context_menu_->addAction(IconLoader::Load("download"),
|
||||||
|
tr("Open %1 in browser").arg(homepage_name_),
|
||||||
|
this, SLOT(Homepage()));
|
||||||
|
context_menu_->addAction(IconLoader::Load("view-refresh"),
|
||||||
|
tr("Refresh streams"),
|
||||||
|
this, SLOT(RefreshStreams()));
|
||||||
|
context_menu_->addSeparator();
|
||||||
|
context_menu_->addAction(IconLoader::Load("configure"),
|
||||||
|
tr("Configure..."),
|
||||||
|
this, SLOT(ShowSettingsDialog()));
|
||||||
|
}
|
||||||
|
|
||||||
|
context_item_ = model()->itemFromIndex(index);
|
||||||
|
context_menu_->popup(global_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex DigitallyImportedServiceBase::GetCurrentIndex() {
|
||||||
|
return context_item_->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigitallyImportedServiceBase::is_valid_stream_selected() const {
|
||||||
|
return audio_type_ >= 0 && audio_type_ < playlists_.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigitallyImportedServiceBase::is_premium_account() const {
|
||||||
|
return !username_.isEmpty() && !password_.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DigitallyImportedServiceBase::is_premium_stream_selected() const {
|
||||||
|
if (!is_valid_stream_selected()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return playlists_[audio_type_].premium_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::LoadPlaylistFinished() {
|
||||||
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
if (!reply) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (reply->header(QNetworkRequest::ContentTypeHeader).toString() == "text/html") {
|
||||||
|
url_handler_->CancelTask();
|
||||||
|
|
||||||
|
if (is_premium_stream_selected()) {
|
||||||
|
emit StreamError(tr("Invalid di.fm username or password"));
|
||||||
|
} else {
|
||||||
|
emit StreamError(tr("Error loading di.fm playlist"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
url_handler_->LoadPlaylistFinished(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedServiceBase::ShowSettingsDialog() {
|
||||||
|
emit OpenSettingsAtPage(SettingsDialog::Page_DigitallyImported);
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* 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 DIGITALLYIMPORTEDSERVICEBASE_H
|
||||||
|
#define DIGITALLYIMPORTEDSERVICEBASE_H
|
||||||
|
|
||||||
|
#include "internetservice.h"
|
||||||
|
|
||||||
|
class DigitallyImportedUrlHandler;
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
|
||||||
|
|
||||||
|
class DigitallyImportedServiceBase : public InternetService {
|
||||||
|
Q_OBJECT
|
||||||
|
friend class DigitallyImportedUrlHandler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DigitallyImportedServiceBase(
|
||||||
|
const QString& name, const QString& description, const QUrl& homepage_url,
|
||||||
|
const QString& homepage_name, const QUrl& stream_list_url,
|
||||||
|
const QString& url_scheme, const QIcon& icon,
|
||||||
|
InternetModel* model, QObject* parent = NULL);
|
||||||
|
~DigitallyImportedServiceBase();
|
||||||
|
|
||||||
|
static const char* kSettingsGroup;
|
||||||
|
|
||||||
|
QStandardItem* CreateRootItem();
|
||||||
|
void LazyPopulate(QStandardItem* parent);
|
||||||
|
void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos);
|
||||||
|
|
||||||
|
void ReloadSettings();
|
||||||
|
|
||||||
|
bool is_valid_stream_selected() const;
|
||||||
|
bool is_premium_stream_selected() const;
|
||||||
|
bool is_premium_account() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct Playlist {
|
||||||
|
Playlist(bool premium, const QString& url_template)
|
||||||
|
: premium_(premium), url_template_(url_template) {}
|
||||||
|
|
||||||
|
bool premium_;
|
||||||
|
QString url_template_;
|
||||||
|
};
|
||||||
|
|
||||||
|
QModelIndex GetCurrentIndex();
|
||||||
|
|
||||||
|
// Called by DigitallyImportedUrlHandler, implemented by subclasses, must
|
||||||
|
// call LoadPlaylistFinished eventually.
|
||||||
|
virtual void LoadStation(const QString& key) = 0;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void LoadPlaylistFinished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void Homepage();
|
||||||
|
void RefreshStreams();
|
||||||
|
void RefreshStreamsFinished();
|
||||||
|
void ShowSettingsDialog();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QNetworkAccessManager* network_;
|
||||||
|
DigitallyImportedUrlHandler* url_handler_;
|
||||||
|
|
||||||
|
int audio_type_;
|
||||||
|
QString username_;
|
||||||
|
QString password_;
|
||||||
|
|
||||||
|
int task_id_;
|
||||||
|
|
||||||
|
QList<Playlist> playlists_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Stream {
|
||||||
|
int id_;
|
||||||
|
QString key_;
|
||||||
|
QString name_;
|
||||||
|
QString description_;
|
||||||
|
|
||||||
|
bool operator <(const Stream& other) const { return name_ < other.name_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Set by subclasses through the constructor
|
||||||
|
QUrl homepage_url_;
|
||||||
|
QString homepage_name_;
|
||||||
|
QUrl stream_list_url_;
|
||||||
|
QIcon icon_;
|
||||||
|
QString service_description_;
|
||||||
|
QString url_scheme_;
|
||||||
|
|
||||||
|
QStandardItem* root_;
|
||||||
|
|
||||||
|
QMenu* context_menu_;
|
||||||
|
QStandardItem* context_item_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DIGITALLYIMPORTEDSERVICEBASE_H
|
|
@ -0,0 +1,96 @@
|
||||||
|
/* 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 "digitallyimportedservicebase.h"
|
||||||
|
#include "digitallyimportedurlhandler.h"
|
||||||
|
#include "internetmodel.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/taskmanager.h"
|
||||||
|
#include "playlistparsers/playlistparser.h"
|
||||||
|
|
||||||
|
DigitallyImportedUrlHandler::DigitallyImportedUrlHandler(DigitallyImportedServiceBase* service)
|
||||||
|
: UrlHandler(service),
|
||||||
|
service_(service),
|
||||||
|
task_id_(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DigitallyImportedUrlHandler::scheme() const {
|
||||||
|
return service_->url_scheme_;
|
||||||
|
}
|
||||||
|
|
||||||
|
UrlHandler_LoadResult DigitallyImportedUrlHandler::StartLoading(const QUrl& url) {
|
||||||
|
UrlHandler_LoadResult ret(url);
|
||||||
|
if (task_id_ != -1) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!service_->is_valid_stream_selected()) {
|
||||||
|
service_->StreamError(tr("You have selected an invalid audio type setting"));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service_->is_premium_stream_selected() && !service_->is_premium_account()) {
|
||||||
|
service_->StreamError(tr("You have selected a Premium-only audio type but do not have any account details entered"));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start loading the station
|
||||||
|
const QString key = url.host();
|
||||||
|
qLog(Info) << "Loading station" << key;
|
||||||
|
service_->LoadStation(key);
|
||||||
|
|
||||||
|
// Save the URL so we can emit it in the finished signal later
|
||||||
|
last_original_url_ = url;
|
||||||
|
|
||||||
|
// Tell the user what's happening
|
||||||
|
task_id_ = service_->model()->task_manager()->StartTask(tr("Loading stream"));
|
||||||
|
|
||||||
|
ret.type_ = UrlHandler_LoadResult::WillLoadAsynchronously;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedUrlHandler::LoadPlaylistFinished(QIODevice* device) {
|
||||||
|
if (task_id_ == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the spinner in the status bar
|
||||||
|
CancelTask();
|
||||||
|
|
||||||
|
// Try to parse the playlist
|
||||||
|
PlaylistParser parser(NULL);
|
||||||
|
QList<Song> songs = parser.LoadFromDevice(device);
|
||||||
|
|
||||||
|
qLog(Info) << "Loading station finished, got" << songs.count() << "songs";
|
||||||
|
|
||||||
|
// Failed to get playlist?
|
||||||
|
if (songs.count() == 0) {
|
||||||
|
service_->StreamError(tr("Error loading di.fm playlist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit AsyncLoadComplete(UrlHandler_LoadResult(
|
||||||
|
last_original_url_,
|
||||||
|
UrlHandler_LoadResult::TrackAvailable,
|
||||||
|
songs[0].url()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitallyImportedUrlHandler::CancelTask() {
|
||||||
|
service_->model()->task_manager()->SetTaskFinished(task_id_);
|
||||||
|
task_id_ = -1;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* 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 DIGITALLYIMPORTEDURLHANDLER_H
|
||||||
|
#define DIGITALLYIMPORTEDURLHANDLER_H
|
||||||
|
|
||||||
|
#include "core/urlhandler.h"
|
||||||
|
|
||||||
|
class DigitallyImportedServiceBase;
|
||||||
|
|
||||||
|
|
||||||
|
class DigitallyImportedUrlHandler : public UrlHandler {
|
||||||
|
public:
|
||||||
|
DigitallyImportedUrlHandler(DigitallyImportedServiceBase* service);
|
||||||
|
|
||||||
|
QString scheme() const;
|
||||||
|
UrlHandler_LoadResult StartLoading(const QUrl& url);
|
||||||
|
|
||||||
|
void CancelTask();
|
||||||
|
void LoadPlaylistFinished(QIODevice* device);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DigitallyImportedServiceBase* service_;
|
||||||
|
int task_id_;
|
||||||
|
|
||||||
|
QUrl last_original_url_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DIGITALLYIMPORTEDURLHANDLER_H
|
|
@ -15,6 +15,7 @@
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "digitallyimportedservice.h"
|
||||||
#include "icecastservice.h"
|
#include "icecastservice.h"
|
||||||
#include "jamendoservice.h"
|
#include "jamendoservice.h"
|
||||||
#include "magnatuneservice.h"
|
#include "magnatuneservice.h"
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include "internetmodel.h"
|
#include "internetmodel.h"
|
||||||
#include "internetservice.h"
|
#include "internetservice.h"
|
||||||
#include "savedradio.h"
|
#include "savedradio.h"
|
||||||
|
#include "skyfmservice.h"
|
||||||
#include "somafmservice.h"
|
#include "somafmservice.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/mergedproxymodel.h"
|
#include "core/mergedproxymodel.h"
|
||||||
|
@ -54,17 +56,19 @@ InternetModel::InternetModel(BackgroundThread<Database>* db_thread,
|
||||||
|
|
||||||
merged_model_->setSourceModel(this);
|
merged_model_->setSourceModel(this);
|
||||||
|
|
||||||
|
AddService(new DigitallyImportedService(this));
|
||||||
|
AddService(new IcecastService(this));
|
||||||
|
AddService(new JamendoService(this));
|
||||||
#ifdef HAVE_LIBLASTFM
|
#ifdef HAVE_LIBLASTFM
|
||||||
AddService(new LastFMService(this));
|
AddService(new LastFMService(this));
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SPOTIFY
|
|
||||||
AddService(new SpotifyService(task_manager, this));
|
|
||||||
#endif
|
|
||||||
AddService(new SomaFMService(this));
|
|
||||||
AddService(new MagnatuneService(this));
|
AddService(new MagnatuneService(this));
|
||||||
AddService(new JamendoService(this));
|
|
||||||
AddService(new IcecastService(this));
|
|
||||||
AddService(new SavedRadio(this));
|
AddService(new SavedRadio(this));
|
||||||
|
AddService(new SkyFmService(this));
|
||||||
|
AddService(new SomaFMService(this));
|
||||||
|
#ifdef HAVE_SPOTIFY
|
||||||
|
AddService(new SpotifyService(this));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternetModel::AddService(InternetService *service) {
|
void InternetModel::AddService(InternetService *service) {
|
||||||
|
@ -86,6 +90,8 @@ void InternetModel::AddService(InternetService *service) {
|
||||||
connect(service, SIGNAL(OpenSettingsAtPage(SettingsDialog::Page)), SIGNAL(OpenSettingsAtPage(SettingsDialog::Page)));
|
connect(service, SIGNAL(OpenSettingsAtPage(SettingsDialog::Page)), SIGNAL(OpenSettingsAtPage(SettingsDialog::Page)));
|
||||||
connect(service, SIGNAL(AddToPlaylistSignal(QMimeData*)), SIGNAL(AddToPlaylist(QMimeData*)));
|
connect(service, SIGNAL(AddToPlaylistSignal(QMimeData*)), SIGNAL(AddToPlaylist(QMimeData*)));
|
||||||
connect(service, SIGNAL(destroyed()), SLOT(ServiceDeleted()));
|
connect(service, SIGNAL(destroyed()), SLOT(ServiceDeleted()));
|
||||||
|
|
||||||
|
service->ReloadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternetModel::RemoveService(InternetService* service) {
|
void InternetModel::RemoveService(InternetService* service) {
|
||||||
|
|
|
@ -84,7 +84,6 @@ LastFMService::LastFMService(InternetModel* parent)
|
||||||
neighbours_list_(NULL),
|
neighbours_list_(NULL),
|
||||||
connection_problems_(false)
|
connection_problems_(false)
|
||||||
{
|
{
|
||||||
ReloadSettings();
|
|
||||||
//we emit the signal the first time to be sure the buttons are in the right state
|
//we emit the signal the first time to be sure the buttons are in the right state
|
||||||
emit ScrobblingEnabledChanged(scrobbling_enabled_);
|
emit ScrobblingEnabledChanged(scrobbling_enabled_);
|
||||||
|
|
||||||
|
|
|
@ -76,8 +76,6 @@ MagnatuneService::MagnatuneService(InternetModel* parent)
|
||||||
total_song_count_(0),
|
total_song_count_(0),
|
||||||
network_(new NetworkAccessManager(this))
|
network_(new NetworkAccessManager(this))
|
||||||
{
|
{
|
||||||
ReloadSettings();
|
|
||||||
|
|
||||||
// Create the library backend in the database thread
|
// Create the library backend in the database thread
|
||||||
library_backend_ = new LibraryBackend;
|
library_backend_ = new LibraryBackend;
|
||||||
library_backend_->moveToThread(parent->db_thread());
|
library_backend_->moveToThread(parent->db_thread());
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* 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 "digitallyimportedurlhandler.h"
|
||||||
|
#include "internetmodel.h"
|
||||||
|
#include "skyfmservice.h"
|
||||||
|
#include "core/taskmanager.h"
|
||||||
|
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
SkyFmService::SkyFmService(InternetModel* model, QObject* parent)
|
||||||
|
: DigitallyImportedServiceBase(
|
||||||
|
"SKY.fm", "SKY.fm", QUrl("http://www.sky.fm"), "sky.fm",
|
||||||
|
QUrl("http://listen.sky.fm"), "skyfm", QIcon(":/providers/skyfm.png"),
|
||||||
|
model, parent)
|
||||||
|
{
|
||||||
|
playlists_ = QList<Playlist>()
|
||||||
|
<< Playlist(false, "http://listen.sky.fm/public3/%1.pls")
|
||||||
|
<< Playlist(true, "http://listen.sky.fm/premium_high/%1.pls?hash=%2")
|
||||||
|
<< Playlist(false, "http://listen.sky.fm/public1/%1.pls")
|
||||||
|
<< Playlist(true, "http://listen.sky.fm/premium_medium/%1.pls?hash=%2")
|
||||||
|
<< Playlist(true, "http://listen.sky.fm/premium/%1.pls?hash=%2")
|
||||||
|
<< Playlist(false, "http://listen.sky.fm/public5/%1.asx")
|
||||||
|
<< Playlist(true, "http://listen.sky.fm/premium_wma_low/%1.asx?hash=%2")
|
||||||
|
<< Playlist(true, "http://listen.sky.fm/premium_wma/%1.asx?hash=%2");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyFmService::LoadStation(const QString& key) {
|
||||||
|
if (!is_premium_stream_selected()) {
|
||||||
|
// Non-premium streams can just start loading straight away
|
||||||
|
LoadPlaylist(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we have to get the user's hashKey
|
||||||
|
QNetworkRequest req(QUrl("http://www.sky.fm/configure_player.php"));
|
||||||
|
QByteArray postdata = "amember_login=" + QUrl::toPercentEncoding(username_) +
|
||||||
|
"&amember_pass=" + QUrl::toPercentEncoding(password_);
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->post(req, postdata);
|
||||||
|
connect(reply, SIGNAL(finished()), SLOT(LoadHashKeyFinished()));
|
||||||
|
|
||||||
|
last_key_ = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyFmService::LoadHashKeyFinished() {
|
||||||
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
if (!reply) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString page_data = QString::fromUtf8(reply->readAll().data());
|
||||||
|
QRegExp re("hashKey\\s*=\\s*'([0-9a-f]+)'");
|
||||||
|
|
||||||
|
if (re.indexIn(page_data) == -1) {
|
||||||
|
url_handler_->CancelTask();
|
||||||
|
emit StreamError(tr("Invalid SKY.fm username or password"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadPlaylist(last_key_, re.cap(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkyFmService::LoadPlaylist(const QString& key, const QString& hash_key) {
|
||||||
|
QString url_template = playlists_[audio_type_].url_template_;
|
||||||
|
QUrl url;
|
||||||
|
|
||||||
|
if (hash_key.isEmpty()) {
|
||||||
|
url = QUrl(url_template.arg(key));
|
||||||
|
} else {
|
||||||
|
url = QUrl(url_template.arg(key, hash_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkReply* reply = network_->get(QNetworkRequest(url));
|
||||||
|
connect(reply, SIGNAL(finished()), SLOT(LoadPlaylistFinished()));
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* 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 SKYFMSERVICE_H
|
||||||
|
#define SKYFMSERVICE_H
|
||||||
|
|
||||||
|
#include "digitallyimportedservicebase.h"
|
||||||
|
|
||||||
|
class SkyFmService : public DigitallyImportedServiceBase {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SkyFmService(InternetModel* model, QObject* parent = NULL);
|
||||||
|
|
||||||
|
void LoadStation(const QString& key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void LoadPlaylist(const QString& key, const QString& hash_key = QString());
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void LoadHashKeyFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString last_key_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SKYFMSERVICE_H
|
|
@ -34,7 +34,7 @@ const char* SpotifyService::kSettingsGroup = "Spotify";
|
||||||
const char* SpotifyService::kBlobDownloadUrl = "http://spotify.clementine-player.org/";
|
const char* SpotifyService::kBlobDownloadUrl = "http://spotify.clementine-player.org/";
|
||||||
const int SpotifyService::kSearchDelayMsec = 400;
|
const int SpotifyService::kSearchDelayMsec = 400;
|
||||||
|
|
||||||
SpotifyService::SpotifyService(TaskManager* task_manager, InternetModel* parent)
|
SpotifyService::SpotifyService(InternetModel* parent)
|
||||||
: InternetService(kServiceName, parent, parent),
|
: InternetService(kServiceName, parent, parent),
|
||||||
server_(NULL),
|
server_(NULL),
|
||||||
url_handler_(new SpotifyUrlHandler(this, this)),
|
url_handler_(new SpotifyUrlHandler(this, this)),
|
||||||
|
@ -46,8 +46,7 @@ SpotifyService::SpotifyService(TaskManager* task_manager, InternetModel* parent)
|
||||||
login_task_id_(0),
|
login_task_id_(0),
|
||||||
pending_search_playlist_(NULL),
|
pending_search_playlist_(NULL),
|
||||||
context_menu_(NULL),
|
context_menu_(NULL),
|
||||||
search_delay_(new QTimer(this)),
|
search_delay_(new QTimer(this)) {
|
||||||
task_manager_(task_manager) {
|
|
||||||
// Build the search path for the binary blob.
|
// Build the search path for the binary blob.
|
||||||
// Look for one distributed alongside clementine first, then check in the
|
// Look for one distributed alongside clementine first, then check in the
|
||||||
// user's home directory for any that have been downloaded.
|
// user's home directory for any that have been downloaded.
|
||||||
|
@ -441,16 +440,16 @@ void SpotifyService::SyncPlaylist() {
|
||||||
int index = item->data(Role_UserPlaylistIndex).toInt();
|
int index = item->data(Role_UserPlaylistIndex).toInt();
|
||||||
server_->SyncUserPlaylist(index);
|
server_->SyncUserPlaylist(index);
|
||||||
playlist_sync_ids_[index] =
|
playlist_sync_ids_[index] =
|
||||||
task_manager_->StartTask(tr("Syncing Spotify playlist"));
|
model()->task_manager()->StartTask(tr("Syncing Spotify playlist"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type_InboxPlaylist:
|
case Type_InboxPlaylist:
|
||||||
server_->SyncInbox();
|
server_->SyncInbox();
|
||||||
inbox_sync_id_ = task_manager_->StartTask(tr("Syncing Spotify inbox"));
|
inbox_sync_id_ = model()->task_manager()->StartTask(tr("Syncing Spotify inbox"));
|
||||||
break;
|
break;
|
||||||
case Type_StarredPlaylist:
|
case Type_StarredPlaylist:
|
||||||
server_->SyncStarred();
|
server_->SyncStarred();
|
||||||
starred_sync_id_ = task_manager_->StartTask(tr("Syncing Spotify starred tracks"));
|
starred_sync_id_ = model()->task_manager()->StartTask(tr("Syncing Spotify starred tracks"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -582,9 +581,9 @@ void SpotifyService::SyncPlaylistProgress(
|
||||||
qLog(Warning) << "Received sync progress for unknown playlist";
|
qLog(Warning) << "Received sync progress for unknown playlist";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
task_manager_->SetTaskProgress(task_id, progress.sync_progress(), 100);
|
model()->task_manager()->SetTaskProgress(task_id, progress.sync_progress(), 100);
|
||||||
if (progress.sync_progress() == 100) {
|
if (progress.sync_progress() == 100) {
|
||||||
task_manager_->SetTaskFinished(task_id);
|
model()->task_manager()->SetTaskFinished(task_id);
|
||||||
if (progress.request().type() == protobuf::UserPlaylist) {
|
if (progress.request().type() == protobuf::UserPlaylist) {
|
||||||
playlist_sync_ids_.remove(task_id);
|
playlist_sync_ids_.remove(task_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ class SpotifyService : public InternetService {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SpotifyService(TaskManager* task_manager, InternetModel* parent);
|
SpotifyService(InternetModel* parent);
|
||||||
~SpotifyService();
|
~SpotifyService();
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -119,7 +119,6 @@ private:
|
||||||
|
|
||||||
QTimer* search_delay_;
|
QTimer* search_delay_;
|
||||||
|
|
||||||
TaskManager* task_manager_;
|
|
||||||
int inbox_sync_id_;
|
int inbox_sync_id_;
|
||||||
int starred_sync_id_;
|
int starred_sync_id_;
|
||||||
QMap<int, int> playlist_sync_ids_;
|
QMap<int, int> playlist_sync_ids_;
|
||||||
|
|
|
@ -468,6 +468,7 @@ void SettingsDialog::accept() {
|
||||||
|
|
||||||
ui_->library_config->Save();
|
ui_->library_config->Save();
|
||||||
ui_->magnatune->Save();
|
ui_->magnatune->Save();
|
||||||
|
ui_->digitally_imported->Save();
|
||||||
ui_->global_shortcuts->Save();
|
ui_->global_shortcuts->Save();
|
||||||
|
|
||||||
streams_->SaveStreams();
|
streams_->SaveStreams();
|
||||||
|
@ -558,6 +559,9 @@ void SettingsDialog::showEvent(QShowEvent*) {
|
||||||
// Magnatune
|
// Magnatune
|
||||||
ui_->magnatune->Load();
|
ui_->magnatune->Load();
|
||||||
|
|
||||||
|
// Digitally Imported
|
||||||
|
ui_->digitally_imported->Load();
|
||||||
|
|
||||||
// Global Shortcuts
|
// Global Shortcuts
|
||||||
ui_->global_shortcuts->Load();
|
ui_->global_shortcuts->Load();
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ class SettingsDialog : public QDialog {
|
||||||
Page_Spotify,
|
Page_Spotify,
|
||||||
#endif
|
#endif
|
||||||
Page_Magnatune,
|
Page_Magnatune,
|
||||||
|
Page_DigitallyImported,
|
||||||
Page_BackgroundStreams,
|
Page_BackgroundStreams,
|
||||||
Page_Proxy,
|
Page_Proxy,
|
||||||
Page_Transcoding,
|
Page_Transcoding,
|
||||||
|
|
|
@ -93,6 +93,15 @@
|
||||||
<normaloff>:/providers/magnatune.png</normaloff>:/providers/magnatune.png</iconset>
|
<normaloff>:/providers/magnatune.png</normaloff>:/providers/magnatune.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Digitally Imported</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../data/data.qrc">
|
||||||
|
<normaloff>:/providers/digitallyimported-32.png</normaloff>:/providers/digitallyimported-32.png</iconset>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Background Streams</string>
|
<string>Background Streams</string>
|
||||||
|
@ -125,7 +134,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QStackedWidget" name="stacked_widget">
|
<widget class="QStackedWidget" name="stacked_widget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>7</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="playback_page">
|
<widget class="QWidget" name="playback_page">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||||
|
@ -1095,6 +1104,19 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="digitally_imported_page">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_27">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="DigitallyImportedConfig" name="digitally_imported" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
<widget class="QWidget" name="streams_page">
|
<widget class="QWidget" name="streams_page">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||||
<item>
|
<item>
|
||||||
|
@ -1564,6 +1586,12 @@
|
||||||
<header>transcoder/transcoderoptionswma.h</header>
|
<header>transcoder/transcoderoptionswma.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>DigitallyImportedConfig</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>internet/digitallyimportedconfig.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>list</tabstop>
|
<tabstop>list</tabstop>
|
||||||
|
|
Loading…
Reference in New Issue