summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpiano/src/main.c12
-rw-r--r--libpiano/src/piano.h5
-rw-r--r--libpiano/src/xml.c10
-rw-r--r--libpiano/src/xml.h3
-rw-r--r--src/main.c87
-rw-r--r--src/pianobar.18
-rw-r--r--src/settings.c6
-rw-r--r--src/settings.h4
-rw-r--r--src/ui_act.c61
-rw-r--r--src/ui_act.h1
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);
diff --git a/src/main.c b/src/main.c
index 190a148..bfe4965 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 */