Fix some style issues in subsonic.

This commit is contained in:
John Maguire 2013-01-24 17:48:58 +01:00
parent fe2fb788d3
commit 0d743a2065
2 changed files with 123 additions and 141 deletions

View File

@ -1,27 +1,29 @@
#include "subsonicurlhandler.h"
#include "subsonicservice.h"
#include "internetmodel.h"
#include "core/application.h"
#include "core/logging.h"
#include "core/player.h"
#include "core/utilities.h"
#include "ui/iconloader.h"
#include "library/librarybackend.h"
#include "library/libraryfilterwidget.h"
#include "core/mergedproxymodel.h"
#include "core/database.h"
#include "core/closure.h"
#include "core/taskmanager.h"
#include "globalsearch/globalsearch.h"
#include "globalsearch/librarysearchprovider.h"
#include <QMenu>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkCookieJar>
#include <QNetworkReply>
#include <QSortFilterProxyModel>
#include <QSslConfiguration>
#include <QXmlStreamReader>
#include <QSortFilterProxyModel>
#include <QMenu>
#include "core/application.h"
#include "core/closure.h"
#include "core/database.h"
#include "core/logging.h"
#include "core/mergedproxymodel.h"
#include "core/player.h"
#include "core/taskmanager.h"
#include "core/timeconstants.h"
#include "core/utilities.h"
#include "globalsearch/globalsearch.h"
#include "globalsearch/librarysearchprovider.h"
#include "internet/internetmodel.h"
#include "internet/subsonicurlhandler.h"
#include "library/librarybackend.h"
#include "library/libraryfilterwidget.h"
#include "ui/iconloader.h"
const char* SubsonicService::kServiceName = "Subsonic";
const char* SubsonicService::kSettingsGroup = "Subsonic";
@ -31,7 +33,7 @@ const char* SubsonicService::kApiClientName = "Clementine";
const char* SubsonicService::kSongsTable = "subsonic_songs";
const char* SubsonicService::kFtsTable = "subsonic_songs_fts";
SubsonicService::SubsonicService(Application* app, InternetModel *parent)
SubsonicService::SubsonicService(Application* app, InternetModel* parent)
: InternetService(kServiceName, app, parent, parent),
network_(new QNetworkAccessManager(this)),
url_handler_(new SubsonicUrlHandler(this, this)),
@ -44,8 +46,7 @@ SubsonicService::SubsonicService(Application* app, InternetModel *parent)
library_filter_(NULL),
library_sort_model_(new QSortFilterProxyModel(this)),
total_song_count_(0),
login_state_(LoginState_OtherError)
{
login_state_(LoginState_OtherError) {
app_->player()->RegisterUrlHandler(url_handler_);
connect(scanner_, SIGNAL(ScanFinished()),
@ -77,14 +78,19 @@ SubsonicService::SubsonicService(Application* app, InternetModel *parent)
library_sort_model_->sort(0);
connect(this, SIGNAL(LoginStateChanged(SubsonicService::LoginState)),
SLOT(onLoginStateChanged(SubsonicService::LoginState)));
SLOT(OnLoginStateChanged(SubsonicService::LoginState)));
context_menu_ = new QMenu;
context_menu_->addActions(GetPlaylistActions());
context_menu_->addSeparator();
context_menu_->addAction(IconLoader::Load("view-refresh"), tr("Refresh catalogue"), this, SLOT(ReloadDatabase()));
QAction* config_action = context_menu_->addAction(IconLoader::Load("configure"),
tr("Configure Subsonic..."), this, SLOT(ShowConfig()));
context_menu_->addAction(
IconLoader::Load("view-refresh"),
tr("Refresh catalogue"),
this, SLOT(ReloadDatabase()));
QAction* config_action = context_menu_->addAction(
IconLoader::Load("configure"),
tr("Configure Subsonic..."),
this, SLOT(ShowConfig()));
context_menu_->addSeparator();
context_menu_->addMenu(library_filter_->menu());
@ -98,38 +104,33 @@ SubsonicService::SubsonicService(Application* app, InternetModel *parent)
true, app_, this));
}
SubsonicService::~SubsonicService()
{
SubsonicService::~SubsonicService() {
}
QStandardItem* SubsonicService::CreateRootItem()
{
QStandardItem* SubsonicService::CreateRootItem() {
root_ = new QStandardItem(QIcon(":providers/subsonic.png"), kServiceName);
root_->setData(true, InternetModel::Role_CanLazyLoad);
return root_;
}
void SubsonicService::LazyPopulate(QStandardItem *item)
{
switch (item->data(InternetModel::Role_Type).toInt())
{
case InternetModel::Type_Service:
library_model_->Init();
if (login_state() != LoginState_Loggedin) {
ShowConfig();
} else if (total_song_count_ == 0 && !load_database_task_id_) {
ReloadDatabase();
}
model()->merged_model()->AddSubModel(item->index(), library_sort_model_);
break;
void SubsonicService::LazyPopulate(QStandardItem* item) {
switch (item->data(InternetModel::Role_Type).toInt()) {
case InternetModel::Type_Service:
library_model_->Init();
if (login_state() != LoginState_Loggedin) {
ShowConfig();
} else if (total_song_count_ == 0 && !load_database_task_id_) {
ReloadDatabase();
}
model()->merged_model()->AddSubModel(item->index(), library_sort_model_);
break;
default:
break;
default:
break;
}
}
void SubsonicService::ShowContextMenu(const QPoint &global_pos)
{
void SubsonicService::ShowContextMenu(const QPoint& global_pos) {
const bool is_valid = model()->current_index().model() == library_sort_model_;
GetAppendToPlaylistAction()->setEnabled(is_valid);
@ -138,13 +139,11 @@ void SubsonicService::ShowContextMenu(const QPoint &global_pos)
context_menu_->popup(global_pos);
}
QWidget* SubsonicService::HeaderWidget() const
{
QWidget* SubsonicService::HeaderWidget() const {
return library_filter_;
}
void SubsonicService::ReloadSettings()
{
void SubsonicService::ReloadSettings() {
QSettings s;
s.beginGroup(kSettingsGroup);
@ -155,8 +154,7 @@ void SubsonicService::ReloadSettings()
Login();
}
void SubsonicService::Login()
{
void SubsonicService::Login() {
// Forget session ID
network_->setCookieJar(new QNetworkCookieJar(network_));
// Forget login state whilst waiting
@ -165,24 +163,22 @@ void SubsonicService::Login()
Ping();
}
void SubsonicService::Login(const QString &server, const QString &username, const QString &password)
{
server_ = QString(server);
username_ = QString(username);
password_ = QString(password);
void SubsonicService::Login(
const QString& server, const QString& username, const QString& password) {
server_ = server;
username_ = username;
password_ = password;
Login();
}
void SubsonicService::Ping()
{
void SubsonicService::Ping() {
QNetworkReply* reply = Send(BuildRequestUrl("ping"));
NewClosure(reply, SIGNAL(finished()),
this, SLOT(onPingFinished(QNetworkReply*)),
this, SLOT(OnPingFinished(QNetworkReply*)),
reply);
}
QUrl SubsonicService::BuildRequestUrl(const QString &view)
{
QUrl SubsonicService::BuildRequestUrl(const QString& view) const {
QUrl url(server_ + "rest/" + view + ".view");
url.addQueryItem("v", kApiVersion);
url.addQueryItem("c", kApiClientName);
@ -191,8 +187,7 @@ QUrl SubsonicService::BuildRequestUrl(const QString &view)
return url;
}
QNetworkReply* SubsonicService::Send(const QUrl &url)
{
QNetworkReply* SubsonicService::Send(const QUrl& url) {
QNetworkRequest request(url);
// Don't try and check the authenticity of the SSL certificate - it'll almost
// certainly be self-signed.
@ -203,20 +198,19 @@ QNetworkReply* SubsonicService::Send(const QUrl &url)
return reply;
}
void SubsonicService::UpdateTotalSongCount(int count)
{
void SubsonicService::UpdateTotalSongCount(int count) {
total_song_count_ = count;
}
void SubsonicService::ReloadDatabase()
{
if (!load_database_task_id_)
load_database_task_id_ = app_->task_manager()->StartTask(tr("Fetching Subsonic library"));
void SubsonicService::ReloadDatabase() {
if (!load_database_task_id_) {
load_database_task_id_ = app_->task_manager()->StartTask(
tr("Fetching Subsonic library"));
}
scanner_->Scan();
}
void SubsonicService::ReloadDatabaseFinished()
{
void SubsonicService::ReloadDatabaseFinished() {
app_->task_manager()->SetTaskFinished(load_database_task_id_);
load_database_task_id_ = 0;
@ -225,57 +219,48 @@ void SubsonicService::ReloadDatabaseFinished()
library_model_->Reset();
}
void SubsonicService::onLoginStateChanged(SubsonicService::LoginState newstate)
{
void SubsonicService::OnLoginStateChanged(SubsonicService::LoginState newstate) {
// TODO: library refresh logic?
}
void SubsonicService::onPingFinished(QNetworkReply *reply)
{
void SubsonicService::OnPingFinished(QNetworkReply* reply) {
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError)
{
if (reply->error() != QNetworkReply::NoError) {
login_state_ = LoginState_BadServer;
qLog(Error) << "Failed to connect ("
<< Utilities::EnumToString(QNetworkReply::staticMetaObject, "NetworkError", reply->error())
<< "):" << reply->errorString();
}
else
{
} else {
QXmlStreamReader reader(reply);
reader.readNextStartElement();
QStringRef status = reader.attributes().value("status");
if (status == "ok")
{
if (status == "ok") {
login_state_ = LoginState_Loggedin;
}
else
{
} else {
reader.readNextStartElement();
int error = reader.attributes().value("code").toString().toInt();
qLog(Error) << "Subsonic error ("
<< Utilities::EnumToString(SubsonicService::staticMetaObject, "ApiError", error)
<< "):" << reader.attributes().value("message").toString();
switch (error)
{
// "Parameter missing" for "ping" is always blank username or password
case ApiError_ParameterMissing:
case ApiError_BadCredentials:
login_state_ = LoginState_BadCredentials;
break;
case ApiError_OutdatedClient:
login_state_ = LoginState_OutdatedClient;
break;
case ApiError_OutdatedServer:
login_state_ = LoginState_OutdatedServer;
break;
case ApiError_Unlicensed:
login_state_ = LoginState_Unlicensed;
break;
default:
login_state_ = LoginState_OtherError;
break;
switch (error) {
// "Parameter missing" for "ping" is always blank username or password
case ApiError_ParameterMissing:
case ApiError_BadCredentials:
login_state_ = LoginState_BadCredentials;
break;
case ApiError_OutdatedClient:
login_state_ = LoginState_OutdatedClient;
break;
case ApiError_OutdatedServer:
login_state_ = LoginState_OutdatedServer;
break;
case ApiError_Unlicensed:
login_state_ = LoginState_Unlicensed;
break;
default:
login_state_ = LoginState_OtherError;
break;
}
}
}
@ -284,8 +269,7 @@ void SubsonicService::onPingFinished(QNetworkReply *reply)
emit LoginStateChanged(login_state_);
}
void SubsonicService::ShowConfig()
{
void SubsonicService::ShowConfig() {
app_->OpenSettingsDialogAtPage(SettingsDialog::Page_Subsonic);
}
@ -293,21 +277,20 @@ void SubsonicService::ShowConfig()
const int SubsonicLibraryScanner::kAlbumChunkSize = 500;
const int SubsonicLibraryScanner::kConcurrentRequests = 8;
SubsonicLibraryScanner::SubsonicLibraryScanner(SubsonicService* service, QObject* parent)
SubsonicLibraryScanner::SubsonicLibraryScanner(
SubsonicService* service, QObject* parent)
: QObject(parent),
service_(service),
scanning_(false)
{
scanning_(false) {
}
SubsonicLibraryScanner::~SubsonicLibraryScanner()
{
SubsonicLibraryScanner::~SubsonicLibraryScanner() {
}
void SubsonicLibraryScanner::Scan()
{
if (scanning_)
void SubsonicLibraryScanner::Scan() {
if (scanning_) {
return;
}
album_queue_.clear();
pending_requests_.clear();
@ -316,8 +299,8 @@ void SubsonicLibraryScanner::Scan()
GetAlbumList(0);
}
void SubsonicLibraryScanner::onGetAlbumListFinished(QNetworkReply *reply, int offset)
{
void SubsonicLibraryScanner::OnGetAlbumListFinished(
QNetworkReply* reply, int offset) {
reply->deleteLater();
QXmlStreamReader reader(reply);
@ -353,8 +336,7 @@ void SubsonicLibraryScanner::onGetAlbumListFinished(QNetworkReply *reply, int of
}
}
void SubsonicLibraryScanner::onGetAlbumFinished(QNetworkReply *reply)
{
void SubsonicLibraryScanner::OnGetAlbumFinished(QNetworkReply* reply) {
reply->deleteLater();
pending_requests_.remove(reply);
@ -385,7 +367,7 @@ void SubsonicLibraryScanner::onGetAlbumFinished(QNetworkReply *reply)
song.set_year(reader.attributes().value("year").toString().toInt());
song.set_genre(reader.attributes().value("genre").toString());
qint64 length = reader.attributes().value("duration").toString().toInt();
length *= 1000000000;
length *= kNsecPerSec;
song.set_length_nanosec(length);
QUrl url = QUrl(QString("subsonic://%1").arg(id));
song.set_url(url);
@ -399,8 +381,9 @@ void SubsonicLibraryScanner::onGetAlbumFinished(QNetworkReply *reply)
}
// Start the next request if albums remain
if (!album_queue_.empty())
if (!album_queue_.empty()) {
GetAlbum(album_queue_.dequeue());
}
// If this was the last response, we're done!
if (album_queue_.empty() && pending_requests_.empty()) {
@ -409,25 +392,23 @@ void SubsonicLibraryScanner::onGetAlbumFinished(QNetworkReply *reply)
}
}
void SubsonicLibraryScanner::GetAlbumList(int offset)
{
void SubsonicLibraryScanner::GetAlbumList(int offset) {
QUrl url = service_->BuildRequestUrl("getAlbumList2");
url.addQueryItem("type", "alphabeticalByName");
url.addQueryItem("size", QString::number(kAlbumChunkSize));
url.addQueryItem("offset", QString::number(offset));
QNetworkReply* reply = service_->Send(url);
NewClosure(reply, SIGNAL(finished()),
this, SLOT(onGetAlbumListFinished(QNetworkReply*,int)),
this, SLOT(OnGetAlbumListFinished(QNetworkReply*,int)),
reply, offset);
}
void SubsonicLibraryScanner::GetAlbum(QString id)
{
void SubsonicLibraryScanner::GetAlbum(const QString& id) {
QUrl url = service_->BuildRequestUrl("getAlbum");
url.addQueryItem("id", id);
QNetworkReply* reply = service_->Send(url);
NewClosure(reply, SIGNAL(finished()),
this, SLOT(onGetAlbumFinished(QNetworkReply*)),
this, SLOT(OnGetAlbumFinished(QNetworkReply*)),
reply);
pending_requests_.insert(reply);
}

View File

@ -1,15 +1,15 @@
#ifndef SUBSONICSERVICE_H
#define SUBSONICSERVICE_H
#include "internetmodel.h"
#include "internetservice.h"
#include <QQueue>
#include "internet/internetmodel.h"
#include "internet/internetservice.h"
class QNetworkAccessManager;
class QXmlStreamReader;
class QSortFilterProxyModel;
class QNetworkReply;
class QSortFilterProxyModel;
class QXmlStreamReader;
class SubsonicUrlHandler;
class SubsonicLibraryScanner;
@ -65,15 +65,16 @@ class SubsonicService : public InternetService
void ReloadSettings();
void Login();
void Login(const QString &server, const QString &username, const QString &password);
void Login(
const QString &server, const QString &username, const QString &password);
LoginState login_state() const { return login_state_; }
// Subsonic API methods
void Ping();
QUrl BuildRequestUrl(const QString &view);
QUrl BuildRequestUrl(const QString& view) const;
// Convenience function to reduce QNetworkRequest/QSslConfiguration boilerplate
QNetworkReply* Send(const QUrl &url);
QNetworkReply* Send(const QUrl& url);
static const char* kServiceName;
static const char* kSettingsGroup;
@ -115,8 +116,8 @@ class SubsonicService : public InternetService
void UpdateTotalSongCount(int count);
void ReloadDatabase();
void ReloadDatabaseFinished();
void onLoginStateChanged(SubsonicService::LoginState newstate);
void onPingFinished(QNetworkReply* reply);
void OnLoginStateChanged(SubsonicService::LoginState newstate);
void OnPingFinished(QNetworkReply* reply);
void ShowConfig();
};
@ -125,7 +126,7 @@ class SubsonicLibraryScanner : public QObject {
Q_OBJECT
public:
SubsonicLibraryScanner(SubsonicService* service, QObject* parent=0);
SubsonicLibraryScanner(SubsonicService* service, QObject* parent = 0);
~SubsonicLibraryScanner();
void Scan();
@ -139,13 +140,13 @@ class SubsonicLibraryScanner : public QObject {
private slots:
// Step 1: use getAlbumList2 type=alphabeticalByName to list all albums
void onGetAlbumListFinished(QNetworkReply* reply, int offset);
void OnGetAlbumListFinished(QNetworkReply* reply, int offset);
// Step 2: use getAlbum id=? to list all songs for each album
void onGetAlbumFinished(QNetworkReply* reply);
void OnGetAlbumFinished(QNetworkReply* reply);
private:
void GetAlbumList(int offset);
void GetAlbum(QString id);
void GetAlbum(const QString& id);
SubsonicService* service_;
bool scanning_;