diff options
-rw-r--r-- | libpiano/src/main.c | 12 | ||||
-rw-r--r-- | libpiano/src/piano.h | 5 | ||||
-rw-r--r-- | libpiano/src/xml.c | 10 | ||||
-rw-r--r-- | libpiano/src/xml.h | 3 | ||||
-rw-r--r-- | src/main.c | 87 | ||||
-rw-r--r-- | src/pianobar.1 | 8 | ||||
-rw-r--r-- | src/settings.c | 6 | ||||
-rw-r--r-- | src/settings.h | 4 | ||||
-rw-r--r-- | src/ui_act.c | 61 | ||||
-rw-r--r-- | src/ui_act.h | 1 |
10 files changed, 151 insertions, 46 deletions
diff --git a/libpiano/src/main.c b/libpiano/src/main.c index 16d30d7..2bf8426 100644 --- a/libpiano/src/main.c +++ b/libpiano/src/main.c @@ -133,10 +133,10 @@ void PianoDestroyStations (PianoStation_t *stations) { * @param piano handle * @return nothing */ -void PianoDestroyPlaylist (PianoHandle_t *ph) { +void PianoDestroyPlaylist (PianoSong_t *playlist) { PianoSong_t *curSong, *lastSong; - curSong = ph->playlist; + curSong = playlist; while (curSong != NULL) { PianoFree (curSong->audioUrl, 0); PianoFree (curSong->artist, 0); @@ -152,7 +152,6 @@ void PianoDestroyPlaylist (PianoHandle_t *ph) { curSong = curSong->next; PianoFree (lastSong, sizeof (*lastSong)); } - ph->playlist = NULL; } /* frees the whole piano handle structure @@ -176,7 +175,6 @@ void PianoDestroy (PianoHandle_t *ph) { curGenreCat = curGenreCat->next; PianoFree (lastGenreCat, sizeof (*lastGenreCat)); } - PianoDestroyPlaylist (ph); memset (ph, 0, sizeof (*ph)); } @@ -255,9 +253,11 @@ PianoReturn_t PianoGetStations (PianoHandle_t *ph) { /* get next songs for station (usually four tracks) * @param piano handle * @param station id + * @param audio format + * @param return value: playlist */ PianoReturn_t PianoGetPlaylist (PianoHandle_t *ph, const char *stationId, - PianoAudioFormat_t format) { + PianoAudioFormat_t format, PianoSong_t **retPlaylist) { char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr; PianoReturn_t ret; @@ -283,7 +283,7 @@ PianoReturn_t PianoGetPlaylist (PianoHandle_t *ph, const char *stationId, if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) == PIANO_RET_OK) { - ret = PianoXmlParsePlaylist (ph, retStr); + ret = PianoXmlParsePlaylist (ph, retStr, retPlaylist); PianoFree (retStr, 0); } diff --git a/libpiano/src/piano.h b/libpiano/src/piano.h index 3bb9108..cd3e8ca 100644 --- a/libpiano/src/piano.h +++ b/libpiano/src/piano.h @@ -90,7 +90,6 @@ typedef struct PianoHandle { PianoUserInfo_t user; /* linked lists */ PianoStation_t *stations; - PianoSong_t *playlist; PianoGenreCategory_t *genreStations; } PianoHandle_t; @@ -109,13 +108,13 @@ typedef enum {PIANO_RET_OK, PIANO_RET_ERR, PIANO_RET_XML_INVALID, void PianoInit (PianoHandle_t *); void PianoDestroy (PianoHandle_t *); -void PianoDestroyPlaylist (PianoHandle_t *); +void PianoDestroyPlaylist (PianoSong_t *); void PianoDestroySearchResult (PianoSearchResult_t *); PianoReturn_t PianoConnect (PianoHandle_t *, const char *, const char *); PianoReturn_t PianoGetStations (PianoHandle_t *); PianoReturn_t PianoGetPlaylist (PianoHandle_t *, const char *, - PianoAudioFormat_t); + PianoAudioFormat_t, PianoSong_t **); PianoReturn_t PianoRateTrack (PianoHandle_t *, PianoSong_t *, PianoSongRating_t); diff --git a/libpiano/src/xml.c b/libpiano/src/xml.c index 185002d..ad0cf7d 100644 --- a/libpiano/src/xml.c +++ b/libpiano/src/xml.c @@ -487,8 +487,10 @@ PianoReturn_t PianoXmlParseAddSeed (PianoHandle_t *ph, char *xml, /* parses playlist; used when searching too * @param piano handle * @param xml document + * @param return: playlist */ -PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { +PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml, + PianoSong_t **retPlaylist) { ezxml_t xmlDoc, dataNode; PianoReturn_t ret; @@ -511,10 +513,10 @@ PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { PianoXmlStructParser (ezxml_child (dataNode, "struct"), PianoXmlParsePlaylistCb, tmpSong); /* begin linked list or append */ - if (ph->playlist == NULL) { - ph->playlist = tmpSong; + if (*retPlaylist == NULL) { + *retPlaylist = tmpSong; } else { - PianoSong_t *curSong = ph->playlist; + PianoSong_t *curSong = *retPlaylist; while (curSong->next != NULL) { curSong = curSong->next; } diff --git a/libpiano/src/xml.h b/libpiano/src/xml.h index 5c0e5c2..7d1f1b2 100644 --- a/libpiano/src/xml.h +++ b/libpiano/src/xml.h @@ -28,7 +28,8 @@ THE SOFTWARE. PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, const char *xml); PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, const char *xml); -PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, const char *xml); +PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, const char *xml, + PianoSong_t **); PianoReturn_t PianoXmlParseSearch (const char *searchXml, PianoSearchResult_t *searchResult); PianoReturn_t PianoXmlParseSimple (const char *xml); @@ -62,8 +62,9 @@ int main (int argc, char **argv) { BarSettings_t settings; pthread_t playerThread; WardrobeHandle_t wh; - /* currently playing */ - PianoSong_t *curSong = NULL; + /* playlist; first item is current song */ + PianoSong_t *playlist = NULL; + PianoSong_t *songHistory = NULL; PianoStation_t *curStation = NULL; WardrobeSong_t scrobbleSong; char doQuit = 0; @@ -204,63 +205,89 @@ int main (int argc, char **argv) { player.mode == PLAYER_FREED) { if (curStation != NULL) { /* what's next? */ - if (curSong != NULL) { - curSong = curSong->next; + if (playlist != NULL) { + if (settings.history != 0) { + /* prepend song to history list */ + PianoSong_t *tmpSong = songHistory; + songHistory = playlist; + /* select next song */ + playlist = playlist->next; + songHistory->next = tmpSong; + + /* limit history's length */ + /* start with 1, so we're stopping at n-1 and have the + * chance to set ->next = NULL */ + unsigned int i = 1; + tmpSong = songHistory; + while (i < settings.history && tmpSong != NULL) { + tmpSong = tmpSong->next; + ++i; + } + /* if too many songs in history... */ + if (tmpSong != NULL) { + PianoSong_t *delSong = tmpSong->next; + tmpSong->next = NULL; + if (delSong != NULL) { + PianoDestroyPlaylist (delSong); + } + } + } else { + /* don't keep history */ + playlist = playlist->next; + } } - if (curSong == NULL) { + if (playlist == NULL) { PianoReturn_t pRet = PIANO_RET_ERR; BarUiMsg (MSG_INFO, "Receiving new playlist... "); - PianoDestroyPlaylist (&ph); if ((pRet = BarUiPrintPianoStatus (PianoGetPlaylist (&ph, - curStation->id, settings.audioFormat))) != - PIANO_RET_OK) { + curStation->id, settings.audioFormat, + &playlist))) != PIANO_RET_OK) { curStation = NULL; } else { - curSong = ph.playlist; - if (curSong == NULL) { + if (playlist == NULL) { BarUiMsg (MSG_INFO, "No tracks left.\n"); curStation = NULL; } } BarUiStartEventCmd (&settings, "stationfetchplaylist", - curStation, curSong, pRet); + curStation, playlist, pRet); } /* song ready to play */ - if (curSong != NULL) { - BarUiPrintSong (curSong, curStation->isQuickMix ? + if (playlist != NULL) { + BarUiPrintSong (playlist, curStation->isQuickMix ? PianoFindStationById (ph.stations, - curSong->stationId) : NULL); + playlist->stationId) : NULL); - if (curSong->audioUrl == NULL) { - BarUiMsg (MSG_ERR, "Invalid song url\n"); + if (playlist->audioUrl == NULL) { + BarUiMsg (MSG_ERR, "Invalid song url.\n"); } else { - /* setup artist and song name for scrobbling (curSong + /* setup artist and song name for scrobbling (playlist * may be NULL later) */ WardrobeSongInit (&scrobbleSong); - scrobbleSong.artist = strdup (curSong->artist); - scrobbleSong.title = strdup (curSong->title); - scrobbleSong.album = strdup (curSong->album); + scrobbleSong.artist = strdup (playlist->artist); + scrobbleSong.title = strdup (playlist->title); + scrobbleSong.album = strdup (playlist->album); scrobbleSong.started = time (NULL); /* setup player */ memset (&player, 0, sizeof (player)); WaitressInit (&player.waith); - WaitressSetUrl (&player.waith, curSong->audioUrl); - - player.gain = curSong->fileGain; - player.audioFormat = curSong->audioFormat; + WaitressSetUrl (&player.waith, playlist->audioUrl); + player.gain = playlist->fileGain; + player.audioFormat = playlist->audioFormat; + /* throw event */ BarUiStartEventCmd (&settings, "songstart", curStation, - curSong, PIANO_RET_OK); + playlist, PIANO_RET_OK); /* start player */ pthread_create (&playerThread, NULL, BarPlayerThread, &player); - } - } + } /* end if audioUrl == NULL */ + } /* end if playlist != NULL */ } /* end if curStation != NULL */ } @@ -279,8 +306,8 @@ int main (int argc, char **argv) { while (curShortcut != NULL) { if (curShortcut->key == buf) { - curShortcut->cmd (&ph, &player, &settings, &curSong, - &curStation, &doQuit, curFd); + curShortcut->cmd (&ph, &player, &settings, &playlist, + &curStation, &songHistory, &doQuit, curFd); break; } curShortcut = curShortcut->next; @@ -315,6 +342,8 @@ int main (int argc, char **argv) { fclose (ctlFd); } PianoDestroy (&ph); + PianoDestroyPlaylist (songHistory); + PianoDestroyPlaylist (playlist); WardrobeDestroy (&wh); ao_shutdown(); BarSettingsDestroy (&settings); diff --git a/src/pianobar.1 b/src/pianobar.1 index 87eabda..b8f5446 100644 --- a/src/pianobar.1 +++ b/src/pianobar.1 @@ -63,6 +63,10 @@ Explain why this song is played. Add genre station provided by pandora. .TP +.B act_history = h +Show history. + +.TP .B act_songinfo = i Print information about currently played song/station. @@ -133,6 +137,10 @@ File that is executed when event occurs. The file is called with the event type as it's first argument. More information is supplied through stdin. .TP +.B history = 5 +Keep a history of the last n songs (5, by default). You can rate these songs. + +.TP .B lastfm_user = your_username If you want to send your played songs to last.fm set this to your last.fm username. diff --git a/src/settings.c b/src/settings.c index a7d6f61..1726a78 100644 --- a/src/settings.c +++ b/src/settings.c @@ -149,6 +149,8 @@ void BarSettingsRead (BarSettings_t *settings) { "act_songexplain", NULL}, {'g', BarUiActStationFromGenre, "add genre station", "act_stationaddbygenre", NULL}, + {'h', BarUiActHistory, "song history", + "act_history", NULL}, {'i', BarUiActSongInfo, "print information about current song/station", "act_songinfo", NULL}, @@ -181,6 +183,7 @@ void BarSettingsRead (BarSettings_t *settings) { settings->audioFormat = PIANO_AF_MP3; #endif #endif + settings->history = 5; BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile)); if ((configfd = fopen (configfile, "r")) == NULL) { @@ -192,6 +195,7 @@ void BarSettingsRead (BarSettings_t *settings) { return; } + /* read config file */ while (!feof (configfd)) { memset (val, 0, sizeof (*val)); memset (key, 0, sizeof (*key)); @@ -233,6 +237,8 @@ void BarSettingsRead (BarSettings_t *settings) { settings->autostartStation = strdup (val); } else if (strcmp ("event_command", key) == 0) { settings->eventCmd = strdup (val); + } else if (strcmp ("history", key) == 0) { + settings->history = atoi (val); } } diff --git a/src/settings.h b/src/settings.h index b3811a6..3d98ec6 100644 --- a/src/settings.h +++ b/src/settings.h @@ -30,7 +30,8 @@ THE SOFTWARE. #define BAR_KS_ARGS PianoHandle_t *ph, struct audioPlayer *player, \ struct BarSettings *settings, PianoSong_t **curSong, \ - PianoStation_t **curStation, char *doQuit, FILE *curFd + PianoStation_t **curStation, PianoSong_t **songHistory, char *doQuit, \ + FILE *curFd struct BarSettings { char *username; @@ -50,6 +51,7 @@ struct BarSettings { PianoAudioFormat_t audioFormat; char *autostartStation; char *eventCmd; + unsigned int history; }; typedef struct BarSettings BarSettings_t; diff --git a/src/ui_act.c b/src/ui_act.c index a3d33ed..5510b2f 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -163,7 +163,7 @@ void BarUiActDeleteStation (BAR_KS_ARGS) { if ((pRet = BarUiPrintPianoStatus (PianoDeleteStation (ph, *curStation))) == PIANO_RET_OK) { BarUiDoSkipSong (player); - PianoDestroyPlaylist (ph); + PianoDestroyPlaylist (*curSong); *curSong = NULL; *curStation = NULL; } @@ -315,7 +315,7 @@ void BarUiActRenameStation (BAR_KS_ARGS) { */ void BarUiActSelectStation (BAR_KS_ARGS) { BarUiDoSkipSong (player); - PianoDestroyPlaylist (ph); + PianoDestroyPlaylist (*curSong); *curSong = NULL; *curStation = BarUiSelectStation (ph, "Select station: ", curFd); if (*curStation != NULL) { @@ -386,3 +386,60 @@ void BarUiActQuit (BAR_KS_ARGS) { *doQuit = 1; BarUiDoSkipSong (player); } + +/* song history + */ +void BarUiActHistory (BAR_KS_ARGS) { + char selectBuf[2]; + PianoSong_t *selectedSong; + + if (*songHistory != NULL) { + selectedSong = BarUiSelectSong (*songHistory, curFd); + if (selectedSong != NULL) { + BarUiMsg (MSG_QUESTION, "%s - %s: [l]ove or [b]an? ", + selectedSong->artist, selectedSong->title); + BarReadline (selectBuf, sizeof (selectBuf), "lbs", 1, 0, curFd); + if (selectBuf[0] == 'l' || selectBuf[0] == 'b') { + PianoReturn_t pRet = PIANO_RET_ERR; + /* make sure we're transforming the _original_ station (not + * curStation) */ + PianoStation_t *songStation = + PianoFindStationById (ph->stations, + selectedSong->stationId); + + if (songStation == NULL) { + BarUiMsg (MSG_ERR, "Station does not exist any more.\n"); + return; + } + + if (!BarTransformIfShared (ph, songStation)) { + return; + } + + switch (selectBuf[0]) { + case 'l': + /* love */ + /* FIXME: copy&waste */ + BarUiMsg (MSG_INFO, "Loving song... "); + pRet = BarUiPrintPianoStatus (PianoRateTrack (ph, + selectedSong, PIANO_RATE_LOVE)); + BarUiStartEventCmd (settings, "songlove", songStation, + selectedSong, pRet); + break; + + case 'b': + /* ban */ + BarUiMsg (MSG_INFO, "Banning song... "); + pRet = BarUiPrintPianoStatus (PianoRateTrack (ph, + selectedSong, PIANO_RATE_BAN)); + BarUiStartEventCmd (settings, "songban", songStation, + selectedSong, pRet); + break; + } /* end switch */ + } /* end if selectBuf[0] */ + } /* end if selectedSong != NULL */ + } else { + BarUiMsg (MSG_INFO, (settings->history == 0) ? "History disabled.\n" : + "No history yet.\n"); + } +} diff --git a/src/ui_act.h b/src/ui_act.h index bbb5904..f6c3285 100644 --- a/src/ui_act.h +++ b/src/ui_act.h @@ -46,5 +46,6 @@ void BarUiActPrintUpcoming (BAR_KS_ARGS); void BarUiActSelectQuickMix (BAR_KS_ARGS); void BarUiActQuit (BAR_KS_ARGS); void BarUiActDebug (BAR_KS_ARGS); +void BarUiActHistory (BAR_KS_ARGS); #endif /* _UI_ACT_H */ |