summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2015-08-10 10:36:03 +0200
committerLars-Dominik Braun <lars@6xq.net>2015-08-10 10:40:50 +0200
commit3a196f51581ffca2d2a902e83a9b69ac4702316c (patch)
treee19c3474e46ab4da4c9f08a24f0082cc3290c7e8
parentbf814cabd1e9913d6153b65f97ad851be3da9b29 (diff)
downloadpianobar-3a196f51581ffca2d2a902e83a9b69ac4702316c.tar.gz
pianobar-3a196f51581ffca2d2a902e83a9b69ac4702316c.tar.bz2
pianobar-3a196f51581ffca2d2a902e83a9b69ac4702316c.zip
Add feature to change Pandora settings
Currently exposed settings: Username, password and explicit content filter. New key for settings is ‘!’, changeable with “act_settings”. Fixes issues #524 and #506.
-rw-r--r--contrib/pianobar.14
-rw-r--r--src/libpiano/piano.h19
-rw-r--r--src/libpiano/request.c41
-rw-r--r--src/libpiano/response.c12
-rw-r--r--src/main.c1
-rw-r--r--src/settings.h3
-rw-r--r--src/ui_act.c103
-rw-r--r--src/ui_act.h1
-rw-r--r--src/ui_dispatch.h2
9 files changed, 185 insertions, 1 deletions
diff --git a/contrib/pianobar.1 b/contrib/pianobar.1
index e337ea2..ee09c41 100644
--- a/contrib/pianobar.1
+++ b/contrib/pianobar.1
@@ -170,6 +170,10 @@ Reset volume.
Increase volume.
.TP
+.B act_settings = !
+Change Pandora settings.
+
+.TP
.B at_icon = @
Replacement for %@ in station format string. It's " @ " by default.
diff --git a/src/libpiano/piano.h b/src/libpiano/piano.h
index 28a2b45..f0ba4cf 100644
--- a/src/libpiano/piano.h
+++ b/src/libpiano/piano.h
@@ -148,6 +148,11 @@ typedef struct {
PianoSong_t *feedback;
} PianoStationInfo_t;
+typedef struct {
+ char *username;
+ bool explicitContentFilter;
+} PianoSettings_t;
+
typedef enum {
/* 0 is reserved: memset (x, 0, sizeof (x)) */
PIANO_REQUEST_LOGIN = 1,
@@ -170,6 +175,8 @@ typedef enum {
PIANO_REQUEST_GET_STATION_INFO = 20,
PIANO_REQUEST_DELETE_FEEDBACK = 21,
PIANO_REQUEST_DELETE_SEED = 22,
+ PIANO_REQUEST_GET_SETTINGS = 23,
+ PIANO_REQUEST_CHANGE_SETTINGS = 24,
} PianoRequestType_t;
typedef struct PianoRequest {
@@ -245,6 +252,18 @@ typedef struct {
PianoStation_t *station;
} PianoRequestDataDeleteSeed_t;
+typedef enum {
+ PIANO_UNDEFINED = 0,
+ PIANO_FALSE = 1,
+ PIANO_TRUE = 2,
+} PianoTristate_t;
+
+typedef struct {
+ char *currentUsername, *newUsername;
+ char *currentPassword, *newPassword;
+ PianoTristate_t explicitContentFilter;
+} PianoRequestDataChangeSettings_t;
+
/* pandora error code offset */
#define PIANO_RET_OFFSET 1024
typedef enum {
diff --git a/src/libpiano/request.c b/src/libpiano/request.c
index cad0907..95ac2d0 100644
--- a/src/libpiano/request.c
+++ b/src/libpiano/request.c
@@ -402,6 +402,47 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req,
break;
}
+ case PIANO_REQUEST_GET_SETTINGS: {
+ method = "user.getSettings";
+ break;
+ }
+
+ case PIANO_REQUEST_CHANGE_SETTINGS: {
+ PianoRequestDataChangeSettings_t *reqData = req->data;
+ assert (reqData != NULL);
+ assert (reqData->currentPassword != NULL);
+ assert (reqData->currentUsername != NULL);
+
+ json_object_object_add (j, "userInitiatedChange",
+ json_object_new_boolean (true));
+ json_object_object_add (j, "currentUsername",
+ json_object_new_string (reqData->currentUsername));
+ json_object_object_add (j, "currentPassword",
+ json_object_new_string (reqData->currentPassword));
+
+ if (reqData->explicitContentFilter != PIANO_UNDEFINED) {
+ json_object_object_add (j, "isExplicitContentFilterEnabled",
+ json_object_new_boolean (
+ reqData->explicitContentFilter == PIANO_TRUE));
+ }
+
+#define changeIfSet(field) \
+ if (reqData->field != NULL) { \
+ json_object_object_add (j, #field, \
+ json_object_new_string (reqData->field)); \
+ }
+
+ changeIfSet (newUsername);
+ changeIfSet (newPassword);
+
+#undef changeIfSet
+
+ req->secure = true;
+
+ method = "user.changeSettings";
+ break;
+ }
+
/* "high-level" wrapper */
case PIANO_REQUEST_RATE_SONG: {
/* love/ban song */
diff --git a/src/libpiano/response.c b/src/libpiano/response.c
index b530f3a..542ef00 100644
--- a/src/libpiano/response.c
+++ b/src/libpiano/response.c
@@ -411,6 +411,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
case PIANO_REQUEST_BOOKMARK_ARTIST:
case PIANO_REQUEST_DELETE_FEEDBACK:
case PIANO_REQUEST_DELETE_SEED:
+ case PIANO_REQUEST_CHANGE_SETTINGS:
/* response unused */
break;
@@ -508,6 +509,17 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
break;
}
+ case PIANO_REQUEST_GET_SETTINGS: {
+ PianoSettings_t * const settings = req->data;
+
+ assert (settings != NULL);
+
+ settings->explicitContentFilter = json_object_get_boolean (
+ json_object_object_get (result, "isExplicitContentFilterEnabled"));
+ settings->username = PianoJsonStrdup (result, "username");
+ break;
+ }
+
case PIANO_REQUEST_GET_STATION_INFO: {
/* get station information (seeds and feedback) */
PianoRequestDataGetStationInfo_t *reqData = req->data;
diff --git a/src/main.c b/src/main.c
index dcf5eaf..59230e0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -77,6 +77,7 @@ static bool BarMainLoginUser (BarApp_t *app) {
ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet, &wRet);
BarUiStartEventCmd (&app->settings, "userlogin", NULL, NULL, &app->player,
NULL, pRet, wRet);
+
return ret;
}
diff --git a/src/settings.h b/src/settings.h
index 0ce5611..d35a64c 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -59,8 +59,9 @@ typedef enum {
BAR_KS_PLAY = 26,
BAR_KS_PAUSE = 27,
BAR_KS_VOLRESET = 28,
+ BAR_KS_SETTINGS = 29,
/* insert new shortcuts _before_ this element and increase its value */
- BAR_KS_COUNT = 29,
+ BAR_KS_COUNT = 30,
} BarKeyShortcutId_t;
#define BAR_KS_DISABLED '\x00'
diff --git a/src/ui_act.c b/src/ui_act.c
index adb2f87..2555367 100644
--- a/src/ui_act.c
+++ b/src/ui_act.c
@@ -23,10 +23,13 @@ THE SOFTWARE.
/* functions responding to user's keystrokes */
+#define _BSD_SOURCE
+
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
+#include <string.h>
#include "ui.h"
#include "ui_readline.h"
@@ -656,6 +659,106 @@ BarUiActCallback(BarUiActVolReset) {
BarPlayerSetVolume (&app->player);
}
+static const char *boolToYesNo (const bool value) {
+ return value ? "yes" : "no";
+}
+
+/* change pandora settings
+ */
+BarUiActCallback(BarUiActSettings) {
+ PianoReturn_t pRet;
+ CURLcode wRet;
+ PianoSettings_t settings;
+ PianoRequestDataChangeSettings_t reqData;
+ bool modified = false;
+
+ memset (&settings, 0, sizeof (settings));
+ memset (&reqData, 0, sizeof (reqData));
+
+ BarUiMsg (&app->settings, MSG_INFO, "Retrieving settings... ");
+ bool bret = BarUiActDefaultPianoCall (PIANO_REQUEST_GET_SETTINGS, &settings);
+ BarUiActDefaultEventcmd ("settingsget");
+ if (!bret) {
+ return;
+ }
+
+ BarUiMsg (&app->settings, MSG_LIST, " 0) Username (%s)\n", settings.username);
+ BarUiMsg (&app->settings, MSG_LIST, " 1) Password (*****)\n");
+ BarUiMsg (&app->settings, MSG_LIST, " 2) Explicit content filter (%s)\n",
+ boolToYesNo (settings.explicitContentFilter));
+
+ while (true) {
+ int val;
+
+ BarUiMsg (&app->settings, MSG_QUESTION, "Change setting: ");
+ if (BarReadlineInt (&val, &app->input) == 0) {
+ break;
+ }
+
+ switch (val) {
+ case 0: {
+ /* username */
+ char buf[80];
+ BarUiMsg (&app->settings, MSG_QUESTION, "New username: ");
+ if (BarReadlineStr (buf, sizeof (buf), &app->input,
+ BAR_RL_DEFAULT) > 0) {
+ reqData.newUsername = strdup (buf);
+ modified = true;
+ }
+ break;
+ }
+
+ case 1: {
+ /* password */
+ char buf[80];
+ BarUiMsg (&app->settings, MSG_QUESTION, "New password: ");
+ if (BarReadlineStr (buf, sizeof (buf), &app->input,
+ BAR_RL_NOECHO) > 0) {
+ reqData.newPassword = strdup (buf);
+ modified = true;
+ }
+ /* write missing newline */
+ puts ("");
+ break;
+ }
+
+ case 2: {
+ /* explicit content filter */
+ BarUiMsg (&app->settings, MSG_QUESTION,
+ "Enable explicit content filter? [yn] ");
+ reqData.explicitContentFilter =
+ BarReadlineYesNo (settings.explicitContentFilter,
+ &app->input) ? PIANO_TRUE : PIANO_FALSE;
+ modified = true;
+ break;
+ }
+
+ default:
+ /* continue */
+ break;
+ }
+ }
+
+ if (modified) {
+ reqData.currentUsername = app->settings.username;
+ reqData.currentPassword = app->settings.password;
+ BarUiMsg (&app->settings, MSG_INFO, "Changing settings... ");
+ BarUiActDefaultPianoCall (PIANO_REQUEST_CHANGE_SETTINGS, &reqData);
+ BarUiActDefaultEventcmd ("settingschange");
+ /* we want to be able to change settings after a username/password
+ * change, so update our internal structs too. the user will have to
+ * update his config file by himself though */
+ if (reqData.newUsername != NULL) {
+ free (app->settings.username);
+ app->settings.username = reqData.newUsername;
+ }
+ if (reqData.newPassword != NULL) {
+ free (app->settings.password);
+ app->settings.password = reqData.newPassword;
+ }
+ }
+}
+
/* manage station (remove seeds or feedback)
*/
BarUiActCallback(BarUiActManageStation) {
diff --git a/src/ui_act.h b/src/ui_act.h
index a9ce4ee..676fbb4 100644
--- a/src/ui_act.h
+++ b/src/ui_act.h
@@ -61,5 +61,6 @@ BarUiActCallback(BarUiActVolDown);
BarUiActCallback(BarUiActVolUp);
BarUiActCallback(BarUiActManageStation);
BarUiActCallback(BarUiActVolReset);
+BarUiActCallback(BarUiActSettings);
#endif /* SRC_UI_ACT_H_1FEFTC06 */
diff --git a/src/ui_dispatch.h b/src/ui_dispatch.h
index df64997..24b68bb 100644
--- a/src/ui_dispatch.h
+++ b/src/ui_dispatch.h
@@ -103,6 +103,8 @@ static const BarUiDispatchAction_t dispatchActions[BAR_KS_COUNT] = {
"act_songpause"},
{'^', BAR_DC_GLOBAL, BarUiActVolReset, "reset volume",
"act_volreset"},
+ {'!', BAR_DC_GLOBAL, BarUiActSettings, "change settings",
+ "act_settings"},
};
#include <piano.h>