summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libpiano/piano.c12
-rw-r--r--src/libpiano/piano.h20
-rw-r--r--src/libpiano/request.c30
-rw-r--r--src/libpiano/response.c60
-rw-r--r--src/ui_act.c82
-rw-r--r--src/ui_dispatch.h2
6 files changed, 183 insertions, 23 deletions
diff --git a/src/libpiano/piano.c b/src/libpiano/piano.c
index a189f34..fde8789 100644
--- a/src/libpiano/piano.c
+++ b/src/libpiano/piano.c
@@ -183,6 +183,18 @@ static void PianoDestroyPartner (PianoPartner_t *partner) {
memset (partner, 0, sizeof (*partner));
}
+void PianoDestroyStationMode (PianoStationMode_t * const modes) {
+ PianoStationMode_t *curMode = modes;
+
+ while (curMode != NULL) {
+ free (curMode->name);
+ free (curMode->description);
+ PianoStationMode_t * const lastMode = curMode;
+ curMode = (PianoStationMode_t *) curMode->head.next;
+ free (lastMode);
+ }
+}
+
/* frees the whole piano handle structure
* @param piano handle
* @return nothing
diff --git a/src/libpiano/piano.h b/src/libpiano/piano.h
index 0ec6c49..f7360aa 100644
--- a/src/libpiano/piano.h
+++ b/src/libpiano/piano.h
@@ -155,6 +155,13 @@ typedef struct {
bool explicitContentFilter;
} PianoSettings_t;
+typedef struct {
+ PianoListHead_t head;
+ char *name, *description;
+ bool isAlgorithmic, isTakeover, active;
+ int id;
+} PianoStationMode_t;
+
typedef enum {
/* 0 is reserved: memset (x, 0, sizeof (x)) */
PIANO_REQUEST_LOGIN = 1,
@@ -179,6 +186,8 @@ typedef enum {
PIANO_REQUEST_DELETE_SEED = 22,
PIANO_REQUEST_GET_SETTINGS = 23,
PIANO_REQUEST_CHANGE_SETTINGS = 24,
+ PIANO_REQUEST_GET_STATION_MODES = 25,
+ PIANO_REQUEST_SET_STATION_MODE = 26,
} PianoRequestType_t;
typedef struct PianoRequest {
@@ -266,6 +275,16 @@ typedef struct {
PianoTristate_t explicitContentFilter;
} PianoRequestDataChangeSettings_t;
+typedef struct {
+ PianoStation_t *station;
+ PianoStationMode_t *retModes;
+} PianoRequestDataGetStationModes_t;
+
+typedef struct {
+ PianoStation_t *station;
+ unsigned int id;
+} PianoRequestDataSetStationMode_t;
+
/* pandora error code offset */
#define PIANO_RET_OFFSET 1024
typedef enum {
@@ -355,6 +374,7 @@ void PianoDestroy (PianoHandle_t *);
void PianoDestroyPlaylist (PianoSong_t *);
void PianoDestroySearchResult (PianoSearchResult_t *);
void PianoDestroyStationInfo (PianoStationInfo_t *);
+void PianoDestroyStationMode (PianoStationMode_t * const);
/* pandora rpc */
PianoReturn_t PianoRequest (PianoHandle_t *, PianoRequest_t *,
diff --git a/src/libpiano/request.c b/src/libpiano/request.c
index 35feda9..69e49a1 100644
--- a/src/libpiano/request.c
+++ b/src/libpiano/request.c
@@ -369,6 +369,36 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req,
break;
}
+ case PIANO_REQUEST_GET_STATION_MODES: {
+ PianoRequestDataGetStationModes_t *reqData = req->data;
+ assert (reqData != NULL);
+ PianoStation_t * const station = reqData->station;
+ assert (station != NULL);
+
+ json_object_object_add (j, "stationId",
+ json_object_new_string (station->id));
+
+ method = "interactiveradio.v1.getAvailableModesSimple";
+ req->secure = true;
+ break;
+ }
+
+ case PIANO_REQUEST_SET_STATION_MODE: {
+ PianoRequestDataSetStationMode_t *reqData = req->data;
+ assert (reqData != NULL);
+ PianoStation_t * const station = reqData->station;
+ assert (station != NULL);
+
+ json_object_object_add (j, "stationId",
+ json_object_new_string (station->id));
+ json_object_object_add (j, "modeId",
+ json_object_new_int (reqData->id));
+
+ method = "interactiveradio.v1.setAndGetAvailableModes";
+ req->secure = true;
+ break;
+ }
+
case PIANO_REQUEST_DELETE_FEEDBACK: {
PianoSong_t *song = req->data;
diff --git a/src/libpiano/response.c b/src/libpiano/response.c
index 4b706e2..1a0f2d5 100644
--- a/src/libpiano/response.c
+++ b/src/libpiano/response.c
@@ -651,6 +651,66 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {
}
break;
}
+
+ case PIANO_REQUEST_GET_STATION_MODES: {
+ PianoRequestDataGetStationModes_t *reqData = req->data;
+ assert (reqData != NULL);
+
+ int active = -1;
+
+ json_object *activeMode;
+ if (json_object_object_get_ex (result, "currentModeId", &activeMode)) {
+ active = json_object_get_int (activeMode);
+ }
+
+ json_object *availableModes;
+ if (json_object_object_get_ex (result, "availableModes", &availableModes)) {
+ for (int i = 0; i < json_object_array_length (availableModes); i++) {
+ json_object *val = json_object_array_get_idx (availableModes, i);
+
+ assert (json_object_is_type (val, json_type_object));
+
+ PianoStationMode_t *mode;
+ if ((mode = calloc (1, sizeof (*mode))) == NULL) {
+ return PIANO_RET_OUT_OF_MEMORY;
+ }
+
+ json_object *modeId;
+ if (json_object_object_get_ex (val, "modeId", &modeId)) {
+ mode->id = json_object_get_int (modeId);
+ mode->name = PianoJsonStrdup (val, "modeName");
+ mode->description = PianoJsonStrdup (val, "modeDescription");
+ mode->isAlgorithmic = getBoolDefault (val, "isAlgorithmicMode",
+ false);
+ mode->isTakeover = getBoolDefault (val, "isTakeoverMode",
+ false);
+ mode->active = active == mode->id;
+ }
+
+ reqData->retModes = PianoListAppendP (reqData->retModes,
+ mode);
+ }
+ }
+ break;
+ }
+
+ case PIANO_REQUEST_SET_STATION_MODE: {
+ PianoRequestDataSetStationMode_t *reqData = req->data;
+ assert (reqData != NULL);
+
+ int active = -1;
+
+ json_object *activeMode;
+ if (json_object_object_get_ex (result, "currentModeId", &activeMode)) {
+ active = json_object_get_int (activeMode);
+ }
+
+ if (active != reqData->id) {
+ /* this did not work */
+ return PIANO_RET_ERR;
+ }
+ break;
+ }
}
cleanup:
diff --git a/src/ui_act.c b/src/ui_act.c
index ba340c1..43d5b6e 100644
--- a/src/ui_act.c
+++ b/src/ui_act.c
@@ -224,6 +224,15 @@ BarUiActCallback(BarUiActAddSharedStation) {
}
}
+static void drainPlaylist (BarApp_t * const app) {
+ BarUiDoSkipSong (&app->player);
+ if (app->playlist != NULL) {
+ /* drain playlist */
+ PianoDestroyPlaylist (PianoListNextP (app->playlist));
+ app->playlist->head.next = NULL;
+ }
+}
+
/* delete current station
*/
BarUiActCallback(BarUiActDeleteStation) {
@@ -238,13 +247,7 @@ BarUiActCallback(BarUiActDeleteStation) {
BarUiMsg (&app->settings, MSG_INFO, "Deleting station... ");
if (BarUiActDefaultPianoCall (PIANO_REQUEST_DELETE_STATION,
selStation) && selStation == app->curStation) {
- BarUiDoSkipSong (&app->player);
- if (app->playlist != NULL) {
- /* drain playlist */
- PianoDestroyPlaylist (PianoListNextP (app->playlist));
- app->playlist->head.next = NULL;
- selSong = NULL;
- }
+ drainPlaylist (app);
app->nextStation = NULL;
/* XXX: usually we shoudn’t touch cur*, but DELETE_STATION destroys
* station struct */
@@ -478,12 +481,7 @@ BarUiActCallback(BarUiActSelectStation) {
"Select station: ", NULL, app->settings.autoselect);
if (newStation != NULL) {
app->nextStation = newStation;
- BarUiDoSkipSong (&app->player);
- if (app->playlist != NULL) {
- /* drain playlist */
- PianoDestroyPlaylist (PianoListNextP (app->playlist));
- app->playlist->head.next = NULL;
- }
+ drainPlaylist (app);
}
}
@@ -773,7 +771,7 @@ BarUiActCallback(BarUiActManageStation) {
CURLcode wRet;
PianoRequestDataGetStationInfo_t reqData;
char selectBuf[2], allowedActions[6], *allowedPos = allowedActions;
- char question[64];
+ char question[128];
memset (&reqData, 0, sizeof (reqData));
reqData.station = selStation;
@@ -816,18 +814,17 @@ BarUiActCallback(BarUiActManageStation) {
strcat (question, "[f]eedback");
*allowedPos++ = 'f';
}
+ /* station mode is always available */
+ if (allowedPos != allowedActions) {
+ strcat (question, "? ");
+ }
+ strcat (question, "Manage [m]ode? ");
+ *allowedPos++ = 'm';
+
*allowedPos = '\0';
- strcat (question, "? ");
assert (strlen (question) < sizeof (question) / sizeof (*question));
- /* nothing to see? */
- if (allowedPos == allowedActions) {
- BarUiMsg (&app->settings, MSG_ERR, "No seeds or feedback available yet.\n");
- PianoDestroyStationInfo (&reqData.info);
- return;
- }
-
BarUiMsg (&app->settings, MSG_QUESTION, "%s", question);
if (BarReadline (selectBuf, sizeof (selectBuf), allowedActions, &app->input,
BAR_RL_FULLRETURN, -1)) {
@@ -879,6 +876,47 @@ BarUiActCallback(BarUiActManageStation) {
BarUiActDefaultPianoCall (PIANO_REQUEST_DELETE_FEEDBACK, song);
BarUiActDefaultEventcmd ("stationdeletefeedback");
}
+ } else if (selectBuf[0] == 'm') {
+ PianoRequestDataGetStationModes_t subReqData =
+ { .station = selStation };
+ BarUiMsg (&app->settings, MSG_INFO, "Fetching modes... ");
+ BarUiActDefaultPianoCall (PIANO_REQUEST_GET_STATION_MODES,
+ &subReqData);
+ BarUiActDefaultEventcmd ("stationgetmodes");
+
+ const PianoStationMode_t *curMode = subReqData.retModes;
+ unsigned int i = 0;
+ PianoListForeachP (curMode) {
+ BarUiMsg (&app->settings, MSG_LIST, "%2i) %s: %s%s\n", i,
+ curMode->name, curMode->description,
+ curMode->active ? " (active)" : "");
+ i++;
+ }
+
+ BarUiMsg (&app->settings, MSG_QUESTION, "Pick a new mode: ");
+ int selected;
+ while (true) {
+ if (BarReadlineInt (&selected, &app->input) == 0) {
+ break;
+ }
+
+ const PianoStationMode_t * const selMode =
+ PianoListGetP (subReqData.retModes, selected);
+ if (selMode != NULL) {
+ PianoRequestDataSetStationMode_t subReqDataSet =
+ {.station = selStation, .id = selected};
+ BarUiMsg (&app->settings, MSG_INFO,
+ "Selecting mode \"%s\"... ", selMode->name);
+ if (BarUiActDefaultPianoCall (
+ PIANO_REQUEST_SET_STATION_MODE, &subReqDataSet)) {
+ drainPlaylist (app);
+ }
+ BarUiActDefaultEventcmd ("stationsetmode");
+ break;
+ }
+ }
+
+ PianoDestroyStationMode (subReqData.retModes);
}
}
diff --git a/src/ui_dispatch.h b/src/ui_dispatch.h
index 7e34393..72de887 100644
--- a/src/ui_dispatch.h
+++ b/src/ui_dispatch.h
@@ -90,7 +90,7 @@ static const BarUiDispatchAction_t dispatchActions[BAR_KS_COUNT] = {
"act_voldown"},
{')', BAR_DC_GLOBAL, BarUiActVolUp, "increase volume",
"act_volup"},
- {'=', BAR_DC_STATION, BarUiActManageStation, "delete seeds/feedback",
+ {'=', BAR_DC_STATION, BarUiActManageStation, "manage station seeds/feedback/mode",
"act_managestation"},
{' ', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActTogglePause, NULL,
"act_songpausetoggle2"},