From 3a196f51581ffca2d2a902e83a9b69ac4702316c Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Mon, 10 Aug 2015 10:36:03 +0200 Subject: Add feature to change Pandora settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently exposed settings: Username, password and explicit content filter. New key for settings is ‘!’, changeable with “act_settings”. Fixes issues #524 and #506. --- contrib/pianobar.1 | 4 ++ src/libpiano/piano.h | 19 +++++++++ src/libpiano/request.c | 41 +++++++++++++++++++ src/libpiano/response.c | 12 ++++++ src/main.c | 1 + src/settings.h | 3 +- src/ui_act.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ui_act.h | 1 + src/ui_dispatch.h | 2 + 9 files changed, 185 insertions(+), 1 deletion(-) diff --git a/contrib/pianobar.1 b/contrib/pianobar.1 index e337ea2..ee09c41 100644 --- a/contrib/pianobar.1 +++ b/contrib/pianobar.1 @@ -169,6 +169,10 @@ Reset volume. .B act_volup = ) 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 #include #include #include +#include #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 -- cgit v1.2.3