31
31
#include "ui_act.h"
32
32
#include "ui_readline.h"
34
#define RETURN_IF_NO_STATION if (*curStation == NULL) { \
34
#define RETURN_IF_NO_STATION if (app->curStation == NULL) { \
35
35
BarUiMsg (MSG_ERR, "No station selected.\n"); \
38
#define RETURN_IF_NO_SONG if (*curStation == NULL || *curSong == NULL) { \
38
#define RETURN_IF_NO_SONG if (app->curStation == NULL || app->playlist == NULL) { \
39
39
BarUiMsg (MSG_ERR, "No song playing.\n"); \
42
/* standard eventcmd call
44
#define BarUiActDefaultEventcmd(name) BarUiStartEventCmd (&app->settings, \
45
name, app->curStation, app->playlist, &app->player, pRet, wRet)
47
/* standard piano call
49
#define BarUiActDefaultPianoCall(call, arg) BarUiPianoCall (&app->ph, \
50
call, &app->waith, arg, &pRet, &wRet)
42
52
/* helper to _really_ skip a song (unlock mutex, quit player)
43
53
* @param player handle
100
110
BarUiMsg (MSG_NONE, "\r");
101
111
for (i = 0; i < BAR_KS_COUNT; i++) {
102
112
if (idToDesc[i] != NULL) {
103
BarUiMsg (MSG_LIST, "%c %s\n", settings->keys[i], idToDesc[i]);
113
BarUiMsg (MSG_LIST, "%c %s\n", app->settings.keys[i], idToDesc[i]);
108
118
/* add more music to current station
110
void BarUiActAddMusic (BAR_KS_ARGS) {
120
BarUiActCallback(BarUiActAddMusic) {
111
121
PianoReturn_t pRet;
112
122
WaitressReturn_t wRet;
113
123
PianoRequestDataAddSeed_t reqData;
115
125
RETURN_IF_NO_STATION;
117
reqData.musicId = BarUiSelectMusicId (ph, waith, curFd, (*curSong)->musicId);
127
reqData.musicId = BarUiSelectMusicId (&app->ph, &app->waith, curFd,
128
app->playlist->musicId);
118
129
if (reqData.musicId != NULL) {
119
if (!BarTransformIfShared (ph, waith, *curStation)) {
130
if (!BarTransformIfShared (&app->ph, &app->waith, app->curStation)) {
122
reqData.station = *curStation;
133
reqData.station = app->curStation;
124
135
BarUiMsg (MSG_INFO, "Adding music to station... ");
125
BarUiPianoCall (ph, PIANO_REQUEST_ADD_SEED, waith, &reqData, &pRet,
136
BarUiActDefaultPianoCall (PIANO_REQUEST_ADD_SEED, &reqData);
128
138
free (reqData.musicId);
130
BarUiStartEventCmd (settings, "stationaddmusic", *curStation, *curSong,
140
BarUiActDefaultEventcmd ("stationaddmusic");
137
void BarUiActBanSong (BAR_KS_ARGS) {
146
BarUiActCallback(BarUiActBanSong) {
138
147
PianoReturn_t pRet;
139
148
WaitressReturn_t wRet;
141
150
RETURN_IF_NO_SONG;
143
if (!BarTransformIfShared (ph, waith, *curStation)) {
152
if (!BarTransformIfShared (&app->ph, &app->waith, app->curStation)) {
147
156
PianoRequestDataRateSong_t reqData;
148
reqData.song = *curSong;
157
reqData.song = app->playlist;
149
158
reqData.rating = PIANO_RATE_BAN;
151
160
BarUiMsg (MSG_INFO, "Banning song... ");
152
if (BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith, &reqData, &pRet,
154
BarUiDoSkipSong (player);
161
if (BarUiActDefaultPianoCall (PIANO_REQUEST_RATE_SONG, &reqData)) {
162
BarUiDoSkipSong (&app->player);
156
BarUiStartEventCmd (settings, "songban", *curStation, *curSong, player,
164
BarUiActDefaultEventcmd ("songban");
160
167
/* create new station
162
void BarUiActCreateStation (BAR_KS_ARGS) {
169
BarUiActCallback(BarUiActCreateStation) {
163
170
PianoReturn_t pRet;
164
171
WaitressReturn_t wRet;
165
172
PianoRequestDataCreateStation_t reqData;
167
reqData.id = BarUiSelectMusicId (ph, waith, curFd, NULL);
174
reqData.id = BarUiSelectMusicId (&app->ph, &app->waith, curFd, NULL);
168
175
if (reqData.id != NULL) {
169
176
reqData.type = "mi";
170
177
BarUiMsg (MSG_INFO, "Creating station... ");
171
BarUiPianoCall (ph, PIANO_REQUEST_CREATE_STATION, waith, &reqData,
178
BarUiActDefaultPianoCall (PIANO_REQUEST_CREATE_STATION, &reqData);
173
179
free (reqData.id);
174
BarUiStartEventCmd (settings, "stationcreate", *curStation, *curSong,
180
BarUiActDefaultEventcmd ("stationcreate");
179
184
/* add shared station by id
181
void BarUiActAddSharedStation (BAR_KS_ARGS) {
186
BarUiActCallback(BarUiActAddSharedStation) {
182
187
PianoReturn_t pRet;
183
188
WaitressReturn_t wRet;
184
189
PianoRequestDataCreateStation_t reqData;
190
195
reqData.id = stationId;
191
196
reqData.type = "sh";
192
197
BarUiMsg (MSG_INFO, "Adding shared station... ");
193
BarUiPianoCall (ph, PIANO_REQUEST_CREATE_STATION, waith, &reqData,
195
BarUiStartEventCmd (settings, "stationaddshared", *curStation,
196
*curSong, player, pRet, wRet);
198
BarUiActDefaultPianoCall (PIANO_REQUEST_CREATE_STATION, &reqData);
199
BarUiActDefaultEventcmd ("stationaddshared");
200
203
/* delete current station
202
void BarUiActDeleteStation (BAR_KS_ARGS) {
205
BarUiActCallback(BarUiActDeleteStation) {
203
206
PianoReturn_t pRet;
204
207
WaitressReturn_t wRet;
206
209
RETURN_IF_NO_STATION;
208
211
BarUiMsg (MSG_QUESTION, "Really delete \"%s\"? [yN] ",
209
(*curStation)->name);
212
app->curStation->name);
210
213
if (BarReadlineYesNo (0, curFd)) {
211
214
BarUiMsg (MSG_INFO, "Deleting station... ");
212
if (BarUiPianoCall (ph, PIANO_REQUEST_DELETE_STATION, waith,
213
*curStation, &pRet, &wRet)) {
214
BarUiDoSkipSong (player);
215
PianoDestroyPlaylist (*curSong);
215
if (BarUiActDefaultPianoCall (PIANO_REQUEST_DELETE_STATION,
217
BarUiDoSkipSong (&app->player);
218
PianoDestroyPlaylist (app->playlist);
219
app->playlist = NULL;
220
app->curStation = NULL;
219
BarUiStartEventCmd (settings, "stationdelete", *curStation, *curSong,
222
BarUiActDefaultEventcmd ("stationdelete");
224
226
/* explain pandora's song choice
226
void BarUiActExplain (BAR_KS_ARGS) {
228
BarUiActCallback(BarUiActExplain) {
227
229
PianoReturn_t pRet;
228
230
WaitressReturn_t wRet;
229
231
PianoRequestDataExplain_t reqData;
231
233
RETURN_IF_NO_STATION;
233
reqData.song = *curSong;
235
reqData.song = app->playlist;
235
237
BarUiMsg (MSG_INFO, "Receiving explanation... ");
236
if (BarUiPianoCall (ph, PIANO_REQUEST_EXPLAIN, waith, &reqData, &pRet,
238
if (BarUiActDefaultPianoCall (PIANO_REQUEST_EXPLAIN, &reqData)) {
238
239
BarUiMsg (MSG_INFO, "%s\n", reqData.retExplain);
239
240
free (reqData.retExplain);
241
BarUiStartEventCmd (settings, "songexplain", *curStation, *curSong, player,
242
BarUiActDefaultEventcmd ("songexplain");
245
245
/* choose genre station and add it as shared station
247
void BarUiActStationFromGenre (BAR_KS_ARGS) {
247
BarUiActCallback(BarUiActStationFromGenre) {
248
248
/* use genre station */
249
BarStationFromGenre (ph, waith, curFd);
249
BarStationFromGenre (&app->ph, &app->waith, curFd);
252
252
/* print verbose song information
254
void BarUiActSongInfo (BAR_KS_ARGS) {
254
BarUiActCallback(BarUiActSongInfo) {
255
255
RETURN_IF_NO_SONG;
257
BarUiPrintStation ((*curStation));
257
BarUiPrintStation (app->curStation);
258
258
/* print real station if quickmix */
259
BarUiPrintSong ((*curSong), (*curStation)->isQuickMix ?
260
PianoFindStationById (ph->stations, (*curSong)->stationId) : NULL);
259
BarUiPrintSong (app->playlist, app->curStation->isQuickMix ?
260
PianoFindStationById (app->ph.stations, app->playlist->stationId) :
263
264
/* print some debugging information
265
void BarUiActDebug (BAR_KS_ARGS) {
266
BarUiActCallback(BarUiActDebug) {
266
267
RETURN_IF_NO_SONG;
268
269
/* print debug-alike infos */
272
273
"audioFormat:\t%i\n"
273
274
"audioUrl:\t%s\n"
274
275
"fileGain:\t%f\n"
275
"focusTraitId:\t%s\n"
276
276
"identity:\t%s\n"
277
"matchingSeed:\t%s\n"
280
280
"stationId:\t%s\n"
281
"testStrategy:\t%i\n"
282
283
"userSeed:\t%s\n",
283
(*curSong)->album, (*curSong)->artist, (*curSong)->audioFormat,
284
(*curSong)->audioUrl, (*curSong)->fileGain,
285
(*curSong)->focusTraitId, (*curSong)->identity,
286
(*curSong)->matchingSeed, (*curSong)->musicId, (*curSong)->rating,
287
(*curSong)->stationId, (*curSong)->title, (*curSong)->userSeed);
284
app->playlist->album, app->playlist->artist,
285
app->playlist->audioFormat, app->playlist->audioUrl,
286
app->playlist->fileGain, app->playlist->identity,
287
app->playlist->musicId, app->playlist->rating,
288
app->playlist->songType, app->playlist->stationId,
289
app->playlist->testStrategy, app->playlist->title,
290
app->playlist->userSeed);
290
293
/* rate current song
292
void BarUiActLoveSong (BAR_KS_ARGS) {
295
BarUiActCallback(BarUiActLoveSong) {
293
296
PianoReturn_t pRet;
294
297
WaitressReturn_t wRet;
296
299
RETURN_IF_NO_SONG;
298
if (!BarTransformIfShared (ph, waith, *curStation)) {
301
if (!BarTransformIfShared (&app->ph, &app->waith, app->curStation)) {
302
305
PianoRequestDataRateSong_t reqData;
303
reqData.song = *curSong;
306
reqData.song = app->playlist;
304
307
reqData.rating = PIANO_RATE_LOVE;
306
309
BarUiMsg (MSG_INFO, "Loving song... ");
307
BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith, &reqData, &pRet,
309
BarUiStartEventCmd (settings, "songlove", *curStation, *curSong, player,
310
BarUiActDefaultPianoCall (PIANO_REQUEST_RATE_SONG, &reqData);
311
BarUiActDefaultEventcmd ("songlove");
315
void BarUiActSkipSong (BAR_KS_ARGS) {
316
BarUiDoSkipSong (player);
316
BarUiActCallback(BarUiActSkipSong) {
317
BarUiDoSkipSong (&app->player);
319
320
/* move song to different station
321
void BarUiActMoveSong (BAR_KS_ARGS) {
322
BarUiActCallback(BarUiActMoveSong) {
322
323
PianoReturn_t pRet;
323
324
WaitressReturn_t wRet;
324
325
PianoRequestDataMoveSong_t reqData;
328
329
RETURN_IF_NO_SONG;
330
reqData.to = BarUiSelectStation (ph, "Move song to station: ", curFd);
331
reqData.to = BarUiSelectStation (&app->ph, "Move song to station: ",
332
app->settings.sortOrder, curFd);
331
333
if (reqData.to != NULL) {
332
334
/* find original station (just is case we're playing a quickmix
334
reqData.from = PianoFindStationById (ph->stations, (*curSong)->stationId);
336
reqData.from = PianoFindStationById (app->ph.stations,
337
app->playlist->stationId);
335
338
if (reqData.from == NULL) {
336
339
BarUiMsg (MSG_ERR, "Station not found\n");
340
if (!BarTransformIfShared (ph, waith, reqData.from) ||
341
!BarTransformIfShared (ph, waith, reqData.to)) {
343
if (!BarTransformIfShared (&app->ph, &app->waith, reqData.from) ||
344
!BarTransformIfShared (&app->ph, &app->waith, reqData.to)) {
344
347
BarUiMsg (MSG_INFO, "Moving song to \"%s\"... ", reqData.to->name);
345
reqData.song = *curSong;
346
if (BarUiPianoCall (ph, PIANO_REQUEST_MOVE_SONG, waith, &reqData,
348
BarUiDoSkipSong (player);
348
reqData.song = app->playlist;
349
if (BarUiActDefaultPianoCall (PIANO_REQUEST_MOVE_SONG, &reqData)) {
350
BarUiDoSkipSong (&app->player);
350
BarUiStartEventCmd (settings, "songmove", *curStation, *curSong,
352
BarUiActDefaultEventcmd ("songmove");
357
void BarUiActPause (BAR_KS_ARGS) {
358
BarUiActCallback(BarUiActPause) {
358
359
/* already locked => unlock/unpause */
359
if (pthread_mutex_trylock (&player->pauseMutex) == EBUSY) {
360
pthread_mutex_unlock (&player->pauseMutex);
360
if (pthread_mutex_trylock (&app->player.pauseMutex) == EBUSY) {
361
pthread_mutex_unlock (&app->player.pauseMutex);
364
365
/* rename current station
366
void BarUiActRenameStation (BAR_KS_ARGS) {
367
BarUiActCallback(BarUiActRenameStation) {
367
368
PianoReturn_t pRet;
368
369
WaitressReturn_t wRet;
369
370
char lineBuf[100];
373
374
BarUiMsg (MSG_QUESTION, "New name: ");
374
375
if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0, curFd) > 0) {
375
376
PianoRequestDataRenameStation_t reqData;
376
if (!BarTransformIfShared (ph, waith, *curStation)) {
377
if (!BarTransformIfShared (&app->ph, &app->waith, app->curStation)) {
380
reqData.station = *curStation;
381
reqData.station = app->curStation;
381
382
reqData.newName = lineBuf;
383
384
BarUiMsg (MSG_INFO, "Renaming station... ");
384
BarUiPianoCall (ph, PIANO_REQUEST_RENAME_STATION, waith, &reqData,
386
BarUiStartEventCmd (settings, "stationrename", *curStation, *curSong,
385
BarUiActDefaultPianoCall (PIANO_REQUEST_RENAME_STATION, &reqData);
386
BarUiActDefaultEventcmd ("stationrename");
391
390
/* play another station
393
void BarUiActSelectStation (BAR_KS_ARGS) {
394
PianoStation_t *newStation = BarUiSelectStation (ph, "Select station: ",
392
BarUiActCallback(BarUiActSelectStation) {
393
PianoStation_t *newStation = BarUiSelectStation (&app->ph, "Select station: ",
394
app->settings.sortOrder, curFd);
396
395
if (newStation != NULL) {
397
*curStation = newStation;
398
BarUiPrintStation ((*curStation));
399
BarUiDoSkipSong (player);
400
PianoDestroyPlaylist (*curSong);
396
app->curStation = newStation;
397
BarUiPrintStation (app->curStation);
398
BarUiDoSkipSong (&app->player);
399
PianoDestroyPlaylist (app->playlist);
400
app->playlist = NULL;
405
404
/* ban song for 1 month
407
void BarUiActTempBanSong (BAR_KS_ARGS) {
406
BarUiActCallback(BarUiActTempBanSong) {
408
407
PianoReturn_t pRet;
409
408
WaitressReturn_t wRet;
411
410
RETURN_IF_NO_SONG;
413
412
BarUiMsg (MSG_INFO, "Putting song on shelf... ");
414
if (BarUiPianoCall (ph, PIANO_REQUEST_ADD_TIRED_SONG, waith, *curSong,
416
BarUiDoSkipSong (player);
413
if (BarUiActDefaultPianoCall (PIANO_REQUEST_ADD_TIRED_SONG, app->playlist)) {
414
BarUiDoSkipSong (&app->player);
418
BarUiStartEventCmd (settings, "songshelf", *curStation, *curSong, player,
416
BarUiActDefaultEventcmd ("songshelf");
422
419
/* print upcoming songs
424
void BarUiActPrintUpcoming (BAR_KS_ARGS) {
421
BarUiActCallback(BarUiActPrintUpcoming) {
425
422
RETURN_IF_NO_SONG;
427
PianoSong_t *nextSong = (*curSong)->next;
424
PianoSong_t *nextSong = app->playlist->next;
428
425
if (nextSong != NULL) {
430
427
while (nextSong != NULL) {
441
438
/* if current station is a quickmix: select stations that are played in
444
void BarUiActSelectQuickMix (BAR_KS_ARGS) {
441
BarUiActCallback(BarUiActSelectQuickMix) {
445
442
PianoReturn_t pRet;
446
443
WaitressReturn_t wRet;
448
445
RETURN_IF_NO_STATION;
450
if ((*curStation)->isQuickMix) {
447
if (app->curStation->isQuickMix) {
451
448
PianoStation_t *selStation;
452
while ((selStation = BarUiSelectStation (ph,
453
"Toggle quickmix for station: ", curFd)) != NULL) {
449
while ((selStation = BarUiSelectStation (&app->ph,
450
"Toggle quickmix for station: ", app->settings.sortOrder,
454
452
selStation->useQuickMix = !selStation->useQuickMix;
456
454
BarUiMsg (MSG_INFO, "Setting quickmix stations... ");
457
BarUiPianoCall (ph, PIANO_REQUEST_SET_QUICKMIX, waith, NULL, &pRet,
459
BarUiStartEventCmd (settings, "stationquickmixtoggle", *curStation,
460
*curSong, player, pRet, wRet);
455
BarUiActDefaultPianoCall (PIANO_REQUEST_SET_QUICKMIX, NULL);
456
BarUiActDefaultEventcmd ("stationquickmixtoggle");
462
458
BarUiMsg (MSG_ERR, "Not a QuickMix station.\n");
468
void BarUiActQuit (BAR_KS_ARGS) {
470
BarUiDoSkipSong (player);
464
BarUiActCallback(BarUiActQuit) {
466
BarUiDoSkipSong (&app->player);
475
void BarUiActHistory (BAR_KS_ARGS) {
471
BarUiActCallback(BarUiActHistory) {
476
472
PianoReturn_t pRet;
477
473
WaitressReturn_t wRet;
478
474
char selectBuf[2], allowedBuf[3];
479
475
PianoSong_t *selectedSong;
481
if (*songHistory != NULL) {
482
selectedSong = BarUiSelectSong (*songHistory, curFd);
477
if (app->songHistory != NULL) {
478
selectedSong = BarUiSelectSong (app->songHistory, curFd);
483
479
if (selectedSong != NULL) {
484
480
/* use user-defined keybindings */
485
allowedBuf[0] = settings->keys[BAR_KS_LOVE];
486
allowedBuf[1] = settings->keys[BAR_KS_BAN];
481
allowedBuf[0] = app->settings.keys[BAR_KS_LOVE];
482
allowedBuf[1] = app->settings.keys[BAR_KS_BAN];
487
483
allowedBuf[2] = '\0';
489
485
BarUiMsg (MSG_QUESTION, "%s - %s: love[%c] or ban[%c]? ",
490
486
selectedSong->artist, selectedSong->title,
491
settings->keys[BAR_KS_LOVE], settings->keys[BAR_KS_BAN]);
487
app->settings.keys[BAR_KS_LOVE],
488
app->settings.keys[BAR_KS_BAN]);
492
489
BarReadline (selectBuf, sizeof (selectBuf), allowedBuf, 1, 0, curFd);
494
if (selectBuf[0] == settings->keys[BAR_KS_LOVE] ||
495
selectBuf[0] == settings->keys[BAR_KS_BAN]) {
491
if (selectBuf[0] == app->settings.keys[BAR_KS_LOVE] ||
492
selectBuf[0] == app->settings.keys[BAR_KS_BAN]) {
496
493
/* make sure we're transforming the _original_ station (not
498
495
PianoStation_t *songStation =
499
PianoFindStationById (ph->stations,
496
PianoFindStationById (app->ph.stations,
500
497
selectedSong->stationId);
502
499
if (songStation == NULL) {
507
if (!BarTransformIfShared (ph, waith, songStation)) {
504
if (!BarTransformIfShared (&app->ph, &app->waith, songStation)) {
511
if (selectBuf[0] == settings->keys[BAR_KS_LOVE]) {
508
if (selectBuf[0] == app->settings.keys[BAR_KS_LOVE]) {
512
509
/* FIXME: copy&waste */
513
510
PianoRequestDataRateSong_t reqData;
514
511
reqData.song = selectedSong;
515
512
reqData.rating = PIANO_RATE_LOVE;
517
514
BarUiMsg (MSG_INFO, "Loving song... ");
518
BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith,
519
&reqData, &pRet, &wRet);
515
BarUiActDefaultPianoCall (PIANO_REQUEST_RATE_SONG,
521
BarUiStartEventCmd (settings, "songlove", songStation,
522
selectedSong, player, pRet, wRet);
523
} else if (selectBuf[0] == settings->keys[BAR_KS_BAN]) {
518
BarUiStartEventCmd (&app->settings, "songlove", songStation,
519
selectedSong, &app->player, pRet, wRet);
520
} else if (selectBuf[0] == app->settings.keys[BAR_KS_BAN]) {
524
521
PianoRequestDataRateSong_t reqData;
525
522
reqData.song = selectedSong;
526
523
reqData.rating = PIANO_RATE_BAN;
528
525
BarUiMsg (MSG_INFO, "Banning song... ");
529
BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith,
530
&reqData, &pRet, &wRet);
531
BarUiStartEventCmd (settings, "songban", songStation,
532
selectedSong, player, pRet, wRet);
526
BarUiActDefaultPianoCall (PIANO_REQUEST_RATE_SONG,
528
BarUiStartEventCmd (&app->settings, "songban", songStation,
529
selectedSong, &app->player, pRet, wRet);
534
531
} /* end if selectBuf[0] */
535
532
} /* end if selectedSong != NULL */
537
BarUiMsg (MSG_INFO, (settings->history == 0) ? "History disabled.\n" :
534
BarUiMsg (MSG_INFO, (app->settings.history == 0) ? "History disabled.\n" :
538
535
"No history yet.\n");
542
539
/* create song bookmark
544
void BarUiActBookmark (BAR_KS_ARGS) {
541
BarUiActCallback(BarUiActBookmark) {
545
542
PianoReturn_t pRet;
546
543
WaitressReturn_t wRet;
547
544
char selectBuf[2];
552
549
BarReadline (selectBuf, sizeof (selectBuf), "sa", 1, 0, curFd);
553
550
if (selectBuf[0] == 's') {
554
551
BarUiMsg (MSG_INFO, "Bookmarking song... ");
555
BarUiPianoCall (ph, PIANO_REQUEST_BOOKMARK_SONG, waith, *curSong,
557
BarUiStartEventCmd (settings, "songbookmark", *curStation, *curSong,
552
BarUiActDefaultPianoCall (PIANO_REQUEST_BOOKMARK_SONG, app->playlist);
553
BarUiActDefaultEventcmd ("songbookmark");
559
554
} else if (selectBuf[0] == 'a') {
560
555
BarUiMsg (MSG_INFO, "Bookmarking artist... ");
561
BarUiPianoCall (ph, PIANO_REQUEST_BOOKMARK_ARTIST, waith, *curSong,
563
BarUiStartEventCmd (settings, "artistbookmark", *curStation, *curSong,
556
BarUiActDefaultPianoCall (PIANO_REQUEST_BOOKMARK_ARTIST,
558
BarUiActDefaultEventcmd ("artistbookmark");