From 99fc43dec0fc2132d6b3a1a2a4c4cbd771802473 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Mon, 25 Sep 2017 19:26:37 +0200 Subject: Add (optional) song duration to song list format string Closes #636. --- contrib/pianobar.1 | 3 +++ 1 file changed, 3 insertions(+) (limited to 'contrib/pianobar.1') diff --git a/contrib/pianobar.1 b/contrib/pianobar.1 index bf385f6..1fd53ae 100644 --- a/contrib/pianobar.1 +++ b/contrib/pianobar.1 @@ -255,6 +255,9 @@ Song title .B %r Rating icon +.B %d +Song duration + .TP .B format_msg_none = %s .TQ -- cgit v1.2.3 From f43a0894cb1386bbb5c0c1f068a4f60192070658 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sat, 30 Sep 2017 17:06:41 +0200 Subject: Add tired rating to song Now we can show a tired icon in the history. Closes #637. --- contrib/config-example | 6 ++++-- contrib/pianobar.1 | 10 +++++++--- src/libpiano/piano.h | 3 ++- src/libpiano/request.c | 3 ++- src/libpiano/response.c | 7 ++++++- src/settings.c | 5 +++++ src/settings.h | 3 +-- src/ui.c | 22 +++++++++++++++++++--- 8 files changed, 46 insertions(+), 13 deletions(-) (limited to 'contrib/pianobar.1') diff --git a/contrib/config-example b/contrib/config-example index 0a69526..6a40937 100644 --- a/contrib/config-example +++ b/contrib/config-example @@ -46,14 +46,16 @@ #event_command = /home/user/.config/pianobar/eventcmd #fifo = /tmp/pianobar #sort = quickmix_10_name_az -#love_icon = [+] -#ban_icon = [-] #volume = 0 #ca_bundle = /etc/ssl/certs/ca-certificates.crt #gain_mul = 1.0 # Format strings #format_nowplaying_song = %t by %a on %l%r%@%s +#format_nowplaying_song = %t by %a on %l%r%@%s +#ban_icon = trackToken != NULL); assert (reqData->stationId != NULL); - assert (reqData->rating != PIANO_RATE_NONE); + assert (reqData->rating != PIANO_RATE_NONE && + reqData->rating != PIANO_RATE_TIRED); json_object_object_add (j, "stationToken", json_object_new_string (reqData->stationId)); diff --git a/src/libpiano/response.c b/src/libpiano/response.c index e37824e..48a07db 100644 --- a/src/libpiano/response.c +++ b/src/libpiano/response.c @@ -436,8 +436,13 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) { break; } + case PIANO_REQUEST_ADD_TIRED_SONG: { + PianoSong_t * const song = req->data; + song->rating = PIANO_RATE_TIRED; + break; + } + case PIANO_REQUEST_ADD_SEED: - case PIANO_REQUEST_ADD_TIRED_SONG: case PIANO_REQUEST_SET_QUICKMIX: case PIANO_REQUEST_BOOKMARK_SONG: case PIANO_REQUEST_BOOKMARK_ARTIST: diff --git a/src/settings.c b/src/settings.c index 4f0ef8c..553c86e 100644 --- a/src/settings.c +++ b/src/settings.c @@ -129,6 +129,7 @@ void BarSettingsDestroy (BarSettings_t *settings) { free (settings->eventCmd); free (settings->loveIcon); free (settings->banIcon); + free (settings->tiredIcon); free (settings->atIcon); free (settings->npSongFormat); free (settings->npStationFormat); @@ -177,6 +178,7 @@ void BarSettingsRead (BarSettings_t *settings) { settings->sortOrder = BAR_SORT_NAME_AZ; settings->loveIcon = strdup (" <3"); settings->banIcon = strdup (" tiredIcon = strdup (" zZ"); settings->atIcon = strdup (" @ "); settings->npSongFormat = strdup ("\"%t\" by \"%a\" on \"%l\"%r%@%s"); settings->npStationFormat = strdup ("Station \"%n\" (%i)"); @@ -374,6 +376,9 @@ void BarSettingsRead (BarSettings_t *settings) { } else if (streq ("ban_icon", key)) { free (settings->banIcon); settings->banIcon = strdup (val); + } else if (streq ("tired_icon", key)) { + free (settings->tiredIcon); + settings->tiredIcon = strdup (val); } else if (streq ("at_icon", key)) { free (settings->atIcon); settings->atIcon = strdup (val); diff --git a/src/settings.h b/src/settings.h index 0edb544..8ec69ac 100644 --- a/src/settings.h +++ b/src/settings.h @@ -98,8 +98,7 @@ typedef struct { char *bindTo; char *autostartStation; char *eventCmd; - char *loveIcon; - char *banIcon; + char *loveIcon, *banIcon, *tiredIcon; char *atIcon; char *npSongFormat; char *npStationFormat; diff --git a/src/ui.c b/src/ui.c index 5f683ca..30b62f7 100644 --- a/src/ui.c +++ b/src/ui.c @@ -614,6 +614,23 @@ void BarUiPrintStation (const BarSettings_t *settings, BarUiMsg (settings, MSG_PLAYING, "%s", outstr); } +static const char *ratingToIcon (const BarSettings_t * const settings, + const PianoSong_t * const song) { + switch (song->rating) { + case PIANO_RATE_LOVE: + return settings->loveIcon; + + case PIANO_RATE_BAN: + return settings->banIcon; + + case PIANO_RATE_TIRED: + return settings->tiredIcon; + + default: + return ""; + } +} + /* Print song infos (artist, title, album, loved) * @param pianobar settings * @param the song @@ -623,7 +640,7 @@ void BarUiPrintSong (const BarSettings_t *settings, const PianoSong_t *song, const PianoStation_t *station) { char outstr[512]; const char *vals[] = {song->title, song->artist, song->album, - (song->rating == PIANO_RATE_LOVE) ? settings->loveIcon : "", + ratingToIcon (settings, song), station != NULL ? settings->atIcon : "", station != NULL ? station->name : "", song->detailUrl}; @@ -654,8 +671,7 @@ size_t BarUiListSongs (const BarSettings_t *settings, BarStrCaseStr (song->title, filter) != NULL))) { char outstr[512], digits[8], duration[8] = "??:??"; const char *vals[] = {digits, song->artist, song->title, - (song->rating == PIANO_RATE_LOVE) ? settings->loveIcon : - ((song->rating == PIANO_RATE_BAN) ? settings->banIcon : ""), + ratingToIcon (settings, song), duration}; /* pre-format a few strings */ -- cgit v1.2.3 From ed3ab2743344dfe2b38427733560b9847d259c8c Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Mon, 2 Oct 2017 12:12:01 +0200 Subject: Show station in song lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iff song’s station is not the current station. This is only the case for the song history right now. Closes #638 --- contrib/config-example | 2 +- contrib/pianobar.1 | 8 ++++++++ src/libpiano/piano.c | 6 +++++- src/ui.c | 33 +++++++++++++++++++++++++-------- src/ui.h | 7 ++++--- src/ui_act.c | 8 ++++---- 6 files changed, 47 insertions(+), 17 deletions(-) (limited to 'contrib/pianobar.1') diff --git a/contrib/config-example b/contrib/config-example index 6a40937..2986d47 100644 --- a/contrib/config-example +++ b/contrib/config-example @@ -57,7 +57,7 @@ #love_icon = <3 #tired_icon = zZ #format_nowplaying_station = Station %n -#format_list_song = %i) %a - %t%r +#format_list_song = %i) %a - %t%r (%d)%@%s # high-quality audio (192k mp3, for Pandora One subscribers only!) #audio_quality = high diff --git a/contrib/pianobar.1 b/contrib/pianobar.1 index 5394e4f..9600859 100644 --- a/contrib/pianobar.1 +++ b/contrib/pianobar.1 @@ -258,6 +258,14 @@ Rating icon .B %d Song duration +.B %@ + +The at_icon + +.B %s + +Song’s station, if not the current station. + .TP .B format_msg_none = %s .TQ diff --git a/src/libpiano/piano.c b/src/libpiano/piano.c index c496ea1..7f1eff9 100644 --- a/src/libpiano/piano.c +++ b/src/libpiano/piano.c @@ -214,7 +214,11 @@ void PianoDestroyRequest (PianoRequest_t *req) { */ PianoStation_t *PianoFindStationById (PianoStation_t * const stations, const char * const searchStation) { - assert (searchStation != NULL); + assert (stations != NULL); + + if (searchStation == NULL) { + return NULL; + } PianoStation_t *currStation = stations; PianoListForeachP (currStation) { diff --git a/src/ui.c b/src/ui.c index 30b62f7..c682ca3 100644 --- a/src/ui.c +++ b/src/ui.c @@ -388,20 +388,21 @@ PianoStation_t *BarUiSelectStation (BarApp_t *app, PianoStation_t *stations, } /* let user pick one song - * @param pianobar settings + * @param app * @param song list * @param input fds * @return pointer to selected item in song list or NULL */ -PianoSong_t *BarUiSelectSong (const BarSettings_t *settings, +PianoSong_t *BarUiSelectSong (const BarApp_t * const app, PianoSong_t *startSong, BarReadline_t rl) { + const BarSettings_t * const settings = &app->settings; PianoSong_t *tmpSong = NULL; char buf[100]; memset (buf, 0, sizeof (buf)); do { - BarUiListSongs (settings, startSong, buf); + BarUiListSongs (app, startSong, buf); BarUiMsg (settings, MSG_QUESTION, "Select song: "); if (BarReadlineStr (buf, sizeof (buf), rl, BAR_RL_DEFAULT) == 0) { @@ -498,7 +499,7 @@ char *BarUiSelectMusicId (BarApp_t *app, PianoStation_t *station, musicId = strdup (tmpArtist->musicId); } } else if (*selectBuf == 't') { - tmpSong = BarUiSelectSong (&app->settings, searchResult.songs, + tmpSong = BarUiSelectSong (app, searchResult.songs, app->rl); if (tmpSong != NULL) { musicId = strdup (tmpSong->musicId); @@ -506,7 +507,7 @@ char *BarUiSelectMusicId (BarApp_t *app, PianoStation_t *station, } } else if (searchResult.songs != NULL) { /* songs found */ - tmpSong = BarUiSelectSong (&app->settings, searchResult.songs, + tmpSong = BarUiSelectSong (app, searchResult.songs, app->rl); if (tmpSong != NULL) { musicId = strdup (tmpSong->musicId); @@ -661,18 +662,34 @@ void BarUiPrintSong (const BarSettings_t *settings, * @param artist/song filter string * @return # of songs */ -size_t BarUiListSongs (const BarSettings_t *settings, +size_t BarUiListSongs (const BarApp_t * const app, const PianoSong_t *song, const char *filter) { + const BarSettings_t * const settings = &app->settings; size_t i = 0; PianoListForeachP (song) { if (filter == NULL || (filter != NULL && (BarStrCaseStr (song->artist, filter) != NULL || BarStrCaseStr (song->title, filter) != NULL))) { + const char * const empty = ""; + const char *stationName = "(deleted)"; + const PianoStation_t * const station = + PianoFindStationById (app->ph.stations, song->stationId); + if (station != NULL) { + if (station != app->curStation) { + stationName = station->name; + } else { + stationName = empty; + } + } + char outstr[512], digits[8], duration[8] = "??:??"; const char *vals[] = {digits, song->artist, song->title, ratingToIcon (settings, song), - duration}; + duration, + stationName != empty ? settings->atIcon : "", + stationName, + }; /* pre-format a few strings */ snprintf (digits, sizeof (digits) / sizeof (*digits), "%2zu", i); @@ -683,7 +700,7 @@ size_t BarUiListSongs (const BarSettings_t *settings, } BarUiCustomFormat (outstr, sizeof (outstr), settings->listSongFormat, - "iatrd", vals); + "iatrd@s", vals); BarUiAppendNewline (outstr, sizeof (outstr)); BarUiMsg (settings, MSG_LIST, "%s", outstr); } diff --git a/src/ui.h b/src/ui.h index 126f6bb..faca48e 100644 --- a/src/ui.h +++ b/src/ui.h @@ -38,14 +38,15 @@ typedef void (*BarUiSelectStationCallback_t) (BarApp_t *app, char *buf); void BarUiMsg (const BarSettings_t *, const BarUiMsg_t, const char *, ...) __attribute__((format(printf, 3, 4))); PianoStation_t *BarUiSelectStation (BarApp_t *, PianoStation_t *, const char *, BarUiSelectStationCallback_t, bool); -PianoSong_t *BarUiSelectSong (const BarSettings_t *, PianoSong_t *, - BarReadline_t); +PianoSong_t *BarUiSelectSong (const BarApp_t * const app, + PianoSong_t *startSong, BarReadline_t rl); PianoArtist_t *BarUiSelectArtist (BarApp_t *, PianoArtist_t *); char *BarUiSelectMusicId (BarApp_t *, PianoStation_t *, const char *); void BarUiPrintStation (const BarSettings_t *, PianoStation_t *); void BarUiPrintSong (const BarSettings_t *, const PianoSong_t *, const PianoStation_t *); -size_t BarUiListSongs (const BarSettings_t *, const PianoSong_t *, const char *); +size_t BarUiListSongs (const BarApp_t * const app, + const PianoSong_t *song, const char *filter); void BarUiStartEventCmd (const BarSettings_t *, const char *, const PianoStation_t *, const PianoSong_t *, const player2_t * const, PianoStation_t *, PianoReturn_t); diff --git a/src/ui_act.c b/src/ui_act.c index a036f19..d834191 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -482,7 +482,7 @@ BarUiActCallback(BarUiActTempBanSong) { BarUiActCallback(BarUiActPrintUpcoming) { PianoSong_t * const nextSong = PianoListNextP (selSong); if (nextSong != NULL) { - BarUiListSongs (&app->settings, nextSong, NULL); + BarUiListSongs (app, nextSong, NULL); } else { BarUiMsg (&app->settings, MSG_INFO, "No songs in queue.\n"); } @@ -563,7 +563,7 @@ BarUiActCallback(BarUiActHistory) { PianoSong_t *histSong; if (app->songHistory != NULL) { - histSong = BarUiSelectSong (&app->settings, app->songHistory, + histSong = BarUiSelectSong (app, app->songHistory, app->rl); if (histSong != NULL) { BarKeyShortcutId_t action; @@ -815,7 +815,7 @@ BarUiActCallback(BarUiActManageStation) { BarUiActDefaultEventcmd ("stationdeleteartistseed"); } } else if (selectBuf[0] == 's') { - PianoSong_t *song = BarUiSelectSong (&app->settings, + PianoSong_t *song = BarUiSelectSong (app, reqData.info.songSeeds, app->rl); if (song != NULL) { PianoRequestDataDeleteSeed_t subReqData; @@ -842,7 +842,7 @@ BarUiActCallback(BarUiActManageStation) { BarUiActDefaultEventcmd ("stationdeletestationseed"); } } else if (selectBuf[0] == 'f') { - PianoSong_t *song = BarUiSelectSong (&app->settings, + PianoSong_t *song = BarUiSelectSong (app, reqData.info.feedback, app->rl); if (song != NULL) { BarUiMsg (&app->settings, MSG_INFO, "Deleting feedback... "); -- cgit v1.2.3 From a9d5d2c3eb9d29d54509936b9e45f8eb034c033f Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sat, 7 Apr 2018 20:17:23 +0200 Subject: Add network timeouts and retries All network operations can time out now. API requests are retried up to three times (default). Replaces setting max_player_errors with max_retries, which is used for player and API. Adds timeout setting. Partially reverts 436a1d4012553a2f33d0e3a5180b3b5ae0378bdd and fixes (at least) issue #657. Thanks to @exarkun for testing. --- contrib/pianobar.1 | 8 ++++++-- src/http/http.c | 16 ++++++++-------- src/http/http.h | 2 +- src/main.c | 11 ++++++----- src/main.h | 2 +- src/settings.c | 9 ++++++--- src/settings.h | 2 +- 7 files changed, 29 insertions(+), 21 deletions(-) (limited to 'contrib/pianobar.1') diff --git a/contrib/pianobar.1 b/contrib/pianobar.1 index 9600859..9219a99 100644 --- a/contrib/pianobar.1 +++ b/contrib/pianobar.1 @@ -335,8 +335,8 @@ Keep a history of the last n songs (5, by default). You can rate these songs. Icon for loved songs. .TP -.B max_player_errors = 5 -Amount of song download errors in a row after pianobar stops playback. +.B max_retry = 3 +Max failures for several actions before giving up. .TP .B partner_password = AC7IBG09A3DTSYM4R41UJWL07VLN8JI7 @@ -371,6 +371,10 @@ Sort station list by name or type (is quickmix) and name. name_az for example sorts by name from a to z, quickmix_01_name_za by type (quickmix at the bottom) and name from z to a. +.TP +.B timeout = 30 +Network operation timeout. + .TP .B tired_icon = zZ Icon for temporarily suspended songs. diff --git a/src/http/http.c b/src/http/http.c index 4576d04..9457fab 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -41,7 +41,7 @@ struct _http_t { static char* HttpToString(const wchar_t* wideString, int size); static wchar_t* HttpToWideString(const char* string, int size); -static bool HttpCreateConnection (http_t http); +static bool HttpCreateConnection (http_t http, unsigned int timeOut); static void HttpCloseConnection (http_t http); static void HttpSetLastError (http_t http, const char* message); static void HttpSetLastErrorW (http_t http, const wchar_t* message); @@ -75,7 +75,7 @@ static wchar_t* HttpToWideString(const char* string, int size) { } -static bool HttpCreateConnection (http_t http) { +static bool HttpCreateConnection (http_t http, unsigned int timeOut) { INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT; HttpCloseConnection (http); @@ -89,10 +89,10 @@ static bool HttpCreateConnection (http_t http) { WINHTTP_SAFE(http->session != NULL); WinHttpSetTimeouts(http->session, - 60 * 1000, // DNS time-out - 60 * 1000, // connect time-out - 30 * 1000, // send time-out - 30 * 1000); // receive time-out + timeOut * 1000, // DNS time-out + timeOut * 1000, // connect time-out + timeOut * 1000, // send time-out + timeOut * 1000); // receive time-out http->connection = WinHttpConnect( http->session, @@ -187,7 +187,7 @@ static char* HttpFormatWinHttpError (DWORD errorCode) { return HttpFormatWinApiError(errorCode, NULL); } -bool HttpInit(http_t* http, const char* endpoint, const char* securePort) { +bool HttpInit(http_t* http, const char* endpoint, const char* securePort, unsigned int timeOut) { http_t out = malloc(sizeof(struct _http_t)); if (!out) return false; @@ -196,7 +196,7 @@ bool HttpInit(http_t* http, const char* endpoint, const char* securePort) { out->endpoint = HttpToWideString(endpoint, -1); out->securePort = HttpToWideString(securePort, -1); - if (!HttpCreateConnection (out)) { + if (!HttpCreateConnection (out, timeOut)) { HttpDestroy (out); return false; } diff --git a/src/http/http.h b/src/http/http.h index 5ea617f..415b0d0 100644 --- a/src/http/http.h +++ b/src/http/http.h @@ -32,7 +32,7 @@ THE SOFTWARE. typedef struct _http_t *http_t; -bool HttpInit (http_t*, const char*, const char*); +bool HttpInit (http_t*, const char*, const char*, unsigned int); void HttpDestroy (http_t); bool HttpSetAutoProxy (http_t, const char*); diff --git a/src/main.c b/src/main.c index 4f4214a..a75388e 100644 --- a/src/main.c +++ b/src/main.c @@ -248,9 +248,9 @@ static void BarMainStartPlayback(BarApp_t *app) PIANO_RET_OK); if (!BarPlayer2Play(app->player)) - ++app->playerErrors; + ++app->retries; else - app->playerErrors = 0; + app->retries = 0; } } @@ -265,11 +265,11 @@ static void BarMainPlayerCleanup(BarApp_t *app) BarConsoleSetTitle(TITLE); - if (app->playerErrors >= app->settings.maxPlayerErrors) + if (app->retries >= app->settings.maxRetry) { /* don't continue playback if thread reports too many error */ app->nextStation = NULL; - app->playerErrors = 0; + app->retries = 0; } } @@ -411,7 +411,8 @@ int main(int argc, char **argv) app.settings.keys[BAR_KS_HELP]); } - HttpInit(&app.http2, app.settings.rpcHost, app.settings.rpcTlsPort); + HttpInit(&app.http2, app.settings.rpcHost, app.settings.rpcTlsPort, + app.settings.timeout); if (app.settings.controlProxy) HttpSetProxy(app.http2, app.settings.controlProxy); diff --git a/src/main.h b/src/main.h index 192ffdb..047f637 100644 --- a/src/main.h +++ b/src/main.h @@ -46,6 +46,6 @@ typedef struct { PianoStation_t *curStation, *nextStation; char doQuit; BarReadline_t rl; - unsigned int playerErrors; + unsigned int retries; } BarApp_t; diff --git a/src/settings.c b/src/settings.c index 553c86e..c8a413e 100644 --- a/src/settings.c +++ b/src/settings.c @@ -173,8 +173,9 @@ void BarSettingsRead (BarSettings_t *settings) { settings->autoselect = true; settings->history = 5; settings->volume = 0; + settings->timeout = 30; /* seconds */ settings->gainMul = 1.0; - settings->maxPlayerErrors = 5; + settings->maxRetry = 3; settings->sortOrder = BAR_SORT_NAME_AZ; settings->loveIcon = strdup (" <3"); settings->banIcon = strdup (" eventCmd = BarSettingsExpandTilde (val, userhome); } else if (streq ("history", key)) { settings->history = atoi (val); - } else if (streq ("max_player_errors", key)) { - settings->maxPlayerErrors = atoi (val); + } else if (streq ("max_retry", key)) { + settings->maxRetry = atoi (val); + } else if (streq ("timeout", key)) { + settings->timeout = atoi (val); } else if (streq ("sort", key)) { size_t i; static const char *mapping[] = {"name_az", diff --git a/src/settings.h b/src/settings.h index 8ec69ac..719c39b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -86,7 +86,7 @@ typedef struct { typedef struct { bool autoselect; - unsigned int history, maxPlayerErrors; + unsigned int history, maxRetry, timeout; int volume; float gainMul; BarStationSorting_t sortOrder; -- cgit v1.2.3