summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am4
-rw-r--r--src/main.c679
-rw-r--r--src/player.c2
-rw-r--r--src/player.h4
-rw-r--r--src/settings.c100
-rw-r--r--src/settings.h15
-rw-r--r--src/ui.c362
-rw-r--r--src/ui.h36
-rw-r--r--src/ui_act.c288
-rw-r--r--src/ui_act.h47
10 files changed, 906 insertions, 631 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 06c8e59..a796499 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
bin_PROGRAMS = pianobar
-pianobar_SOURCES = main.c terminal.c terminal.h settings.c settings.h \
- player.c player.h
+pianobar_SOURCES = main.c main.h terminal.c terminal.h settings.c settings.h \
+ player.c player.h ui.c ui.h ui_act.c ui_act.h
pianobar_CPPFLAGS = ${LIBCURL_CFLAGS} ${LIBAO_CFLAGS} ${LIBXML_CFLAGS} \
-I../libpiano/src -I../libwardrobe/src
pianobar_LDADD = ${LIBCURL_LIBS} ${LIBAO_LIBS} ${LIBFAAD_LIBS} \
diff --git a/src/main.c b/src/main.c
index 6814f79..00e94ca 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,7 +20,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-#include <piano.h>
+/* main loop, helper functions */
+
#include <wardrobe.h>
#include <curl/curl.h>
#include <libxml/parser.h>
@@ -34,400 +35,76 @@ THE SOFTWARE.
#include <readline/readline.h>
#include <time.h>
#include <ctype.h>
+#include <piano.h>
-#include "terminal.h"
+#include "player.h"
#include "settings.h"
+#include "main.h"
+#include "terminal.h"
#include "config.h"
-#include "player.h"
-
-/* output message and flush stdout
- * @param message
- */
-inline void BarUiMsg (const char *msg) {
- printf ("%s", msg);
- fflush (stdout);
-}
-
-inline PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret) {
- if (ret != PIANO_RET_OK) {
- printf ("Error: %s\n", PianoErrorToStr (ret));
- } else {
- printf ("Ok.\n");
- }
- return ret;
-}
-
-/* check whether complete string is numeric
- * @param the string
- * @return 1 = yes, 0 = not numeric
- */
-char BarIsNumericStr (const char *str) {
- while (*str != '\0') {
- if (isdigit (*str) == 0) {
- return 0;
- }
- str++;
- }
- return 1;
-}
-
-/* use readline to get integer value
- * @param prompt or NULL
- * @param returns integer
- * @return 1 = success, 0 = failure (not an integer, ...)
- */
-char BarReadlineInt (const char *prompt, int *retVal) {
- char *buf;
- char ret = 0;
-
- if ((buf = readline (prompt)) != NULL && strlen (buf) > 0 &&
- BarIsNumericStr (buf)) {
- *retVal = atoi (buf);
- ret = 1;
- }
- if (buf != NULL) {
- free (buf);
- }
- return ret;
-}
-
-/* sort linked list (station); attention: this is a
- * "i-had-no-clue-what-to-do-algo", but it works.
- * @param stations
- * @return NULL-terminated array with sorted stations
- */
-PianoStation_t **BarSortedStations (PianoStation_t *unsortedStations) {
- PianoStation_t *currStation, **sortedStations, **currSortedStation;
- PianoStation_t *oldStation, *veryOldStation;
- size_t unsortedStationsN = 0;
- char inserted;
-
- /* get size */
- currStation = unsortedStations;
- while (currStation != NULL) {
- unsortedStationsN++;
- currStation = currStation->next;
- }
- sortedStations = calloc (unsortedStationsN+1, sizeof (*sortedStations));
-
- currStation = unsortedStations;
- while (currStation != NULL) {
- currSortedStation = sortedStations;
- inserted = 0;
- while (*currSortedStation != NULL && !inserted) {
- /* item has to be inserted _before_ current item? */
- /* FIXME: this doesn't handle multibyte chars correctly */
- if (strcasecmp (currStation->name,
- (*currSortedStation)->name) < 0) {
- oldStation = *currSortedStation;
- *currSortedStation = currStation;
- currSortedStation++;
- /* move items */
- while (*currSortedStation != NULL) {
- veryOldStation = *currSortedStation;
- *currSortedStation = oldStation;
- oldStation = veryOldStation;
- currSortedStation++;
- }
- /* append last item */
- if (oldStation != NULL) {
- *currSortedStation = oldStation;
- }
- inserted = 1;
- }
- currSortedStation++;
- }
- /* item could not be inserted: append */
- if (!inserted) {
- *currSortedStation = currStation;
- }
- currStation = currStation->next;
- }
- return sortedStations;
-}
-
-/* let user pick one station
- * @param piano handle
- * @return pointer to selected station or NULL
- */
-PianoStation_t *BarUiSelectStation (PianoHandle_t *ph,
- const char *prompt) {
- PianoStation_t **ss = NULL, **ssCurr = NULL, *retStation;
- int i = 0;
-
- ss = BarSortedStations (ph->stations);
- ssCurr = ss;
- while (*ssCurr != NULL) {
- printf ("%2i) %c%c%c %s\n", i,
- (*ssCurr)->useQuickMix ? 'q' : ' ',
- (*ssCurr)->isQuickMix ? 'Q' : ' ',
- !(*ssCurr)->isCreator ? 'S' : ' ',
- (*ssCurr)->name);
- ssCurr++;
- i++;
- }
-
- if (!BarReadlineInt (prompt, &i)) {
- return NULL;
- }
- ssCurr = ss;
- while (*ssCurr != NULL && i > 0) {
- ssCurr++;
- i--;
- }
- retStation = *ssCurr;
- free (ss);
- return retStation;
-}
-
-/* let user pick one song
- * @param song list
- * @return pointer to selected item in song list or NULL
- */
-PianoSong_t *BarUiSelectSong (PianoSong_t *startSong) {
- PianoSong_t *tmpSong = NULL;
- int i = 0;
-
- tmpSong = startSong;
- while (tmpSong != NULL) {
- printf ("%2u) %s - %s\n", i, tmpSong->artist, tmpSong->title);
- i++;
- tmpSong = tmpSong->next;
- }
- if (!BarReadlineInt ("Select song: ", &i)) {
- return NULL;
- }
- tmpSong = startSong;
- while (tmpSong != NULL && i > 0) {
- tmpSong = tmpSong->next;
- i--;
- }
- return tmpSong;
-}
-
-/* let user pick one artist
- * @param artists (linked list)
- * @return pointer to selected artist or NULL on abort
- */
-PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist) {
- PianoArtist_t *tmpArtist = NULL;
- int i = 0;
-
- tmpArtist = startArtist;
- while (tmpArtist != NULL) {
- printf ("%2u) %s\n", i, tmpArtist->name);
- i++;
- tmpArtist = tmpArtist->next;
- }
- if (!BarReadlineInt ("Select artist: ", &i)) {
- return NULL;
- }
- tmpArtist = startArtist;
- while (tmpArtist != NULL && i > 0) {
- tmpArtist = tmpArtist->next;
- i--;
- }
- return tmpArtist;
-}
-
-/* search music: query, search request, return music id
- * @param piano handle
- * @return musicId or NULL on abort/error
- */
-char *BarUiSelectMusicId (const PianoHandle_t *ph) {
- char *musicId = NULL, *lineBuf;
- char yesnoBuf;
- PianoSearchResult_t searchResult;
- PianoArtist_t *tmpArtist;
- PianoSong_t *tmpSong;
-
- lineBuf = readline ("Search for artist/title: ");
- if (lineBuf != NULL && strlen (lineBuf) > 0) {
- BarUiMsg ("Searching... ");
- if (BarUiPrintPianoStatus (PianoSearchMusic (ph, lineBuf,
- &searchResult)) != PIANO_RET_OK) {
- free (lineBuf);
- return NULL;
- }
- BarUiMsg ("\r");
- if (searchResult.songs != NULL && searchResult.artists != NULL) {
- BarUiMsg ("Is this an [a]rtist or [t]rack name? Press c to abort.\n");
- read (fileno (stdin), &yesnoBuf, sizeof (yesnoBuf));
- if (yesnoBuf == 'a') {
- tmpArtist = BarUiSelectArtist (searchResult.artists);
- if (tmpArtist != NULL) {
- musicId = strdup (tmpArtist->musicId);
- }
- } else if (yesnoBuf == 't') {
- tmpSong = BarUiSelectSong (searchResult.songs);
- if (tmpSong != NULL) {
- musicId = strdup (tmpSong->musicId);
- }
- } else {
- BarUiMsg ("Aborted.\n");
- }
- } else if (searchResult.songs != NULL) {
- tmpSong = BarUiSelectSong (searchResult.songs);
- if (tmpSong != NULL) {
- musicId = strdup (tmpSong->musicId);
- } else {
- BarUiMsg ("Aborted.\n");
- }
- } else if (searchResult.artists != NULL) {
- tmpArtist = BarUiSelectArtist (searchResult.artists);
- if (tmpArtist != NULL) {
- musicId = strdup (tmpArtist->musicId);
- } else {
- BarUiMsg ("Aborted.\n");
- }
- } else {
- BarUiMsg ("Nothing found...\n");
- }
- PianoDestroySearchResult (&searchResult);
- } else {
- BarUiMsg ("Aborted.\n");
- }
- if (lineBuf != NULL) {
- free (lineBuf);
- }
-
- return musicId;
-}
+#include "ui.h"
inline float BarSamplesToSeconds (float samplerate, float channels,
float samples) {
return channels * 1000.0 * samples / samplerate;
}
-/* browse genre stations and create shared station
- * @param piano handle
- */
-void BarStationFromGenre (PianoHandle_t *ph) {
- int i;
- PianoGenreCategory_t *curCat;
- PianoStation_t *curStation;
-
- /* receive genre stations list if not yet available */
- if (ph->genreStations == NULL) {
- BarUiMsg ("Receiving genre stations... ");
- if (BarUiPrintPianoStatus (PianoGetGenreStations (ph)) !=
- PIANO_RET_OK) {
- return;
- }
- }
-
- /* print all available categories */
- curCat = ph->genreStations;
- i = 0;
- while (curCat != NULL) {
- printf ("%2i) %s\n", i, curCat->name);
- i++;
- curCat = curCat->next;
- }
- /* select category or exit */
- if (!BarReadlineInt (NULL, &i)) {
- BarUiMsg ("Aborted.\n");
- return;
- }
- curCat = ph->genreStations;
- while (curCat != NULL && i > 0) {
- curCat = curCat->next;
- i--;
- }
-
- /* print all available stations */
- curStation = curCat->stations;
- i = 0;
- while (curStation != NULL) {
- printf ("%2i) %s\n", i, curStation->name);
- i++;
- curStation = curStation->next;
- }
- if (!BarReadlineInt (NULL, &i)) {
- BarUiMsg ("Aborted.\n");
- return;
- }
- curStation = curCat->stations;
- while (curStation != NULL && i > 0) {
- curStation = curStation->next;
- i--;
- }
- /* create station */
- printf ("Adding shared station \"%s\"... ", curStation->name);
- fflush (stdout);
- BarUiPrintPianoStatus (PianoCreateStation (ph, "sh", curStation->id));
-}
-
-/* transform station if necessary to allow changes like rename, rate, ...
- * @param piano handle
- * @param transform this station
- * @return 0 = error, 1 = everything went well
- */
-int BarTransformIfShared (PianoHandle_t *ph, PianoStation_t *station) {
- /* shared stations must be transformed */
- if (!station->isCreator) {
- BarUiMsg ("Transforming station... ");
- if (BarUiPrintPianoStatus (PianoTransformShared (ph, station)) !=
- PIANO_RET_OK) {
- return 0;
- }
- }
- return 1;
-}
-
int main (int argc, char **argv) {
PianoHandle_t ph;
struct aacPlayer player;
- char doQuit = 0;
+ BarSettings_t settings;
PianoSong_t *curSong = NULL;
PianoStation_t *curStation = NULL;
- BarSettings_t bsettings;
+ char doQuit = 0;
pthread_t playerThread;
- WardrobeSong_t scrobbleSong;
WardrobeHandle_t wh;
+ WardrobeSong_t scrobbleSong;
+ /* needed in main loop */
+ struct pollfd polls = {fileno (stdin), POLLIN, POLLIN};
+ char buf = '\0';
+ BarKeyShortcut_t *curShortcut;
- BarUiMsg ("Welcome to " PACKAGE_STRING "! Press ? for help.\n");
+ BarUiMsg ("Welcome to " PACKAGE_STRING " (built on " __DATE__ ")\n");
/* init some things */
curl_global_init (CURL_GLOBAL_SSL);
xmlInitParser ();
- ao_initialize();
+ ao_initialize ();
+ PianoInit (&ph);
+ WardrobeInit (&wh);
+ BarSettingsInit (&settings);
- BarSettingsInit (&bsettings);
- BarSettingsRead (&bsettings);
+ BarSettingsRead (&settings);
- if (bsettings.username == NULL) {
- bsettings.username = readline ("Username: ");
+ if (settings.username == NULL) {
+ settings.username = readline ("Username: ");
}
- if (bsettings.password == NULL) {
+ if (settings.password == NULL) {
BarTermSetEcho (0);
- bsettings.password = readline ("Password: ");
+ settings.password = readline ("Password: ");
BarTermSetEcho (1);
}
- PianoInit (&ph);
- WardrobeInit (&wh);
-
- if (bsettings.enableScrobbling) {
- wh.user = strdup (bsettings.lastfmUser);
- wh.password = strdup (bsettings.lastfmPassword);
+ if (settings.enableScrobbling) {
+ wh.user = strdup (settings.lastfmUser);
+ wh.password = strdup (settings.lastfmPassword);
}
/* setup control connection */
- if (bsettings.controlProxy != NULL &&
- bsettings.controlProxyType != -1) {
+ if (settings.controlProxy != NULL &&
+ settings.controlProxyType != -1) {
curl_easy_setopt (ph.curlHandle, CURLOPT_PROXY,
- bsettings.controlProxy);
+ settings.controlProxy);
curl_easy_setopt (ph.curlHandle, CURLOPT_PROXYTYPE,
- bsettings.controlProxyType);
+ settings.controlProxyType);
}
curl_easy_setopt (ph.curlHandle, CURLOPT_CONNECTTIMEOUT, 60);
BarTermSetBuffer (0);
BarUiMsg ("Login... ");
- if (BarUiPrintPianoStatus (PianoConnect (&ph, bsettings.username,
- bsettings.password, !bsettings.disableSecureLogin)) !=
+ if (BarUiPrintPianoStatus (PianoConnect (&ph, settings.username,
+ settings.password, !settings.disableSecureLogin)) !=
PIANO_RET_OK) {
return 0;
}
@@ -455,8 +132,8 @@ int main (int argc, char **argv) {
if (BarSamplesToSeconds (player.samplerate,
player.channels, player.sampleSizeCurr) * 100 /
scrobbleSong.length >=
- bsettings.lastfmScrobblePercent &&
- bsettings.enableScrobbling) {
+ settings.lastfmScrobblePercent &&
+ settings.enableScrobbling) {
WardrobeReturn_t wRet;
BarUiMsg ("Scrobbling song... ");
@@ -501,8 +178,8 @@ int main (int argc, char **argv) {
PianoFindStationById (ph.stations,
curSong->stationId);
printf ("\"%s\" by \"%s\" on \"%s\"%s%s%s\n",
- curSong->title, curSong->artist, curSong->album,
- (curSong->rating ==
+ curSong->title, curSong->artist,
+ curSong->album, (curSong->rating ==
PIANO_RATE_LOVE) ? " (Loved)" : "",
curStation->isQuickMix ? " @ ": "",
curStation->isQuickMix ? realStation->name :
@@ -523,278 +200,22 @@ int main (int argc, char **argv) {
pthread_create (&playerThread, NULL, BarPlayerThread,
&player);
}
- }
+ } /* end if curStation != NULL */
}
/* in the meantime: wait for user actions */
- struct pollfd polls = {fileno (stdin), POLLIN, POLLIN};
- char buf, yesnoBuf;
- char *lineBuf, *musicId, *explanation;
- PianoStation_t *moveStation;
-
if (poll (&polls, 1, 1000) > 0) {
read (fileno (stdin), &buf, sizeof (buf));
- switch (buf) {
- case '?':
- printf ("\na\tadd music to current station\n"
- "b\tban current song\n"
- "c\tcreate new station\n"
- "d\tdelete current station\n"
- "e\texplain why this song is played\n"
- "g\tadd genre station\n"
- "l\tlove current song\n"
- "n\tnext song\n"
- "p\tpause/continue\n"
- "q\tquit\n"
- "r\trename current station\n"
- "s\tchange station\n"
- "t\ttired (ban song for 1 month)\n"
- "u\tupcoming songs\n"
- "x\tselect quickmix stations\n");
- break;
-
- case 'a':
- if (curStation == NULL) {
- BarUiMsg ("No station selected.\n");
- break;
- }
- musicId = BarUiSelectMusicId (&ph);
- if (musicId == NULL) {
- if (!BarTransformIfShared (&ph, curStation)) {
- break;
- }
- BarUiMsg ("Adding music to station... ");
- BarUiPrintPianoStatus (PianoStationAddMusic (&ph,
- curStation, musicId));
- free (musicId);
- }
- break;
-
- case 'b':
- if (curStation == NULL || curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- if (!BarTransformIfShared (&ph, curStation)) {
- break;
- }
- BarUiMsg ("Banning song... ");
- if (BarUiPrintPianoStatus (PianoRateTrack (&ph, curSong,
- PIANO_RATE_BAN)) == PIANO_RET_OK) {
- player.doQuit = 1;
- }
- break;
-
- case 'c':
- musicId = BarUiSelectMusicId (&ph);
- if (musicId != NULL) {
- BarUiMsg ("Creating station... ");
- BarUiPrintPianoStatus (PianoCreateStation (&ph,
- "mi", musicId));
- free (musicId);
- }
- break;
-
- case 'd':
- if (curStation == NULL) {
- BarUiMsg ("No station selected.\n");
- break;
- }
- printf ("Really delete \"%s\"? [yn]\n",
- curStation->name);
- read (fileno (stdin), &yesnoBuf, sizeof (yesnoBuf));
- if (yesnoBuf == 'y') {
- BarUiMsg ("Deleting station... ");
- if (BarUiPrintPianoStatus (PianoDeleteStation (&ph,
- curStation)) == PIANO_RET_OK) {
- player.doQuit = 1;
- PianoDestroyPlaylist (&ph);
- curSong = NULL;
- curStation = NULL;
- }
- }
- break;
-
- case 'e':
- if (curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- BarUiMsg ("Receiving explanation... ");
- if (BarUiPrintPianoStatus (PianoExplain (&ph, curSong,
- &explanation)) == PIANO_RET_OK) {
- printf ("%s\n", explanation);
- free (explanation);
- }
- break;
-
- case 'g':
- /* use genre station */
- BarStationFromGenre (&ph);
- break;
-
- case 'i':
- if (curStation == NULL || curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- /* print debug-alike infos */
- printf ("Song infos:\n"
- "album:\t%s\n"
- "artist:\t%s\n"
- "audioUrl:\t%s\n"
- "fileGain:\t%f\n"
- "focusTraitId:\t%s\n"
- "identity:\t%s\n"
- "matchingSeed:\t%s\n"
- "musicId:\t%s\n"
- "rating:\t%i\n"
- "stationId:\t%s\n"
- "title:\t%s\n"
- "userSeed:\t%s\n",
- curSong->album, curSong->artist, curSong->audioUrl,
- curSong->fileGain, curSong->focusTraitId,
- curSong->identity, curSong->matchingSeed,
- curSong->musicId, curSong->rating,
- curSong->stationId, curSong->title,
- curSong->userSeed);
- break;
-
- case 'l':
- if (curStation == NULL || curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- if (curSong->rating == PIANO_RATE_LOVE) {
- BarUiMsg ("Already loved. No need to do this twice.\n");
- break;
- }
- if (!BarTransformIfShared (&ph, curStation)) {
- break;
- }
- BarUiMsg ("Loving song... ");
- BarUiPrintPianoStatus (PianoRateTrack (&ph, curSong,
- PIANO_RATE_LOVE));
+ curShortcut = settings.keys;
+ while (curShortcut != NULL) {
+ if (curShortcut->key == buf) {
+ curShortcut->cmd (&ph, &player, &settings, &curSong,
+ &curStation, &doQuit);
break;
-
- case 'n':
- player.doQuit = 1;
- break;
-
- case 'm':
- if (curStation == NULL || curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- moveStation = BarUiSelectStation (&ph, "Move song to station: ");
- if (moveStation != NULL) {
- if (!BarTransformIfShared (&ph, curStation) ||
- !BarTransformIfShared (&ph, moveStation)) {
- break;
- }
- printf ("Moving song to \"%s\"... ", moveStation->name);
- fflush (stdout);
- if (BarUiPrintPianoStatus (PianoMoveSong (&ph,
- curStation, moveStation, curSong)) ==
- PIANO_RET_OK) {
- player.doQuit = 1;
- }
- }
- break;
-
- case 'p':
- player.doPause = !player.doPause;
- break;
-
- case 'q':
- doQuit = 1;
- player.doQuit = 1;
- break;
-
- case 'r':
- if (curStation == NULL) {
- BarUiMsg ("No station selected.\n");
- break;
- }
- lineBuf = readline ("New name?\n");
- if (lineBuf != NULL && strlen (lineBuf) > 0) {
- if (!BarTransformIfShared (&ph, curStation)) {
- break;
- }
- BarUiMsg ("Renaming station... ");
- BarUiPrintPianoStatus (PianoRenameStation (&ph,
- curStation, lineBuf));
- }
- if (lineBuf != NULL) {
- free (lineBuf);
- }
- break;
-
- case 's':
- player.doQuit = 1;
- PianoDestroyPlaylist (&ph);
- curSong = NULL;
- curStation = BarUiSelectStation (&ph, "Select station: ");
- if (curStation != NULL) {
- printf ("Changed station to %s\n", curStation->name);
- }
- break;
-
- case 't':
- if (curStation == NULL || curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- if (!BarTransformIfShared (&ph, curStation)) {
- break;
- }
- BarUiMsg ("Putting song on shelf... ");
- if (BarUiPrintPianoStatus (PianoSongTired (&ph,
- curSong)) == PIANO_RET_OK) {
- player.doQuit = 1;
- }
- break;
-
- case 'u':
- if (curStation == NULL || curSong == NULL) {
- BarUiMsg ("No song playing.\n");
- break;
- }
- PianoSong_t *nextSong = curSong->next;
- if (nextSong != NULL) {
- int i = 0;
- BarUiMsg ("Next songs:\n");
- while (nextSong != NULL) {
- printf ("%2i) \"%s\" by \"%s\"\n", i,
- nextSong->title, nextSong->artist);
- nextSong = nextSong->next;
- i++;
- }
- } else {
- BarUiMsg ("No songs in queue.\n");
- }
- break;
-
- case 'x':
- if (curStation == NULL) {
- BarUiMsg ("No station selected.\n");
- break;
- }
- if (curStation->isQuickMix) {
- PianoStation_t *selStation;
- while ((selStation = BarUiSelectStation (&ph,
- "Toggle quickmix for station: ")) != NULL) {
- selStation->useQuickMix = !selStation->useQuickMix;
- }
- BarUiMsg ("Setting quickmix stations... ");
- BarUiPrintPianoStatus (PianoSetQuickmix (&ph));
- } else {
- BarUiMsg ("Not a QuickMix station.\n");
- }
- break;
-
- } /* end case */
- } /* end poll */
+ }
+ curShortcut = curShortcut->next;
+ }
+ }
/* show time */
if (player.mode >= PLAYER_SAMPLESIZE_INITIALIZED &&
@@ -802,8 +223,8 @@ int main (int argc, char **argv) {
float songLength = BarSamplesToSeconds (player.samplerate,
player.channels, player.sampleSizeN);
float songRemaining = songLength -
- BarSamplesToSeconds (player.samplerate, player.channels,
- player.sampleSizeCurr);
+ BarSamplesToSeconds (player.samplerate,
+ player.channels, player.sampleSizeCurr);
printf ("-%02i:%02i/%02i:%02i\r", (int) songRemaining/60,
(int) songRemaining%60, (int) songLength/60,
(int) songLength%60);
@@ -821,7 +242,7 @@ int main (int argc, char **argv) {
curl_global_cleanup ();
ao_shutdown();
xmlCleanupParser ();
- BarSettingsDestroy (&bsettings);
+ BarSettingsDestroy (&settings);
return 0;
}
diff --git a/src/player.c b/src/player.c
index f2403bc..e49e5bb 100644
--- a/src/player.c
+++ b/src/player.c
@@ -20,6 +20,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
+/* receive/play audio stream */
+
#include <unistd.h>
#include <string.h>
#include <math.h>
diff --git a/src/player.h b/src/player.h
index 94be1a4..e542d4d 100644
--- a/src/player.h
+++ b/src/player.h
@@ -20,6 +20,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
+#ifndef _PLAYER_H
+#define _PLAYER_H
+
#include <curl/curl.h>
#include <neaacdec.h>
#include <ao/ao.h>
@@ -53,3 +56,4 @@ struct aacPlayer {
void *BarPlayerThread (void *data);
+#endif /* _PLAYER_H */
diff --git a/src/settings.c b/src/settings.c
index ae34078..e756364 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -20,12 +20,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
+/* application settings */
+
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "settings.h"
#include "config.h"
+#include "ui_act.h"
/* tries to guess your config dir; somehow conforming to
* http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
@@ -60,6 +63,15 @@ void BarSettingsInit (BarSettings_t *settings) {
}
void BarSettingsDestroy (BarSettings_t *settings) {
+ BarKeyShortcut_t *curShortcut, *lastShortcut;
+
+ while (curShortcut != NULL) {
+ lastShortcut = curShortcut;
+ curShortcut = curShortcut->next;
+ free (lastShortcut->description);
+ free (lastShortcut->configKey);
+ free (lastShortcut);
+ }
free (settings->controlProxy);
free (settings->username);
free (settings->password);
@@ -68,17 +80,79 @@ void BarSettingsDestroy (BarSettings_t *settings) {
memset (settings, 0, sizeof (*settings));
}
+void BarSettingsAppendKey (BarKeyShortcut_t *shortcut,
+ BarSettings_t *settings) {
+ BarKeyShortcut_t *tmp = calloc (1, sizeof (*tmp));
+
+ /* copy shortcut */
+ memcpy (tmp, shortcut, sizeof (*tmp));
+ if (shortcut->description != NULL) {
+ tmp->description = strdup (shortcut->description);
+ }
+ if (shortcut->configKey != NULL) {
+ tmp->configKey = strdup (shortcut->configKey);
+ }
+
+ if (settings->keys == NULL) {
+ settings->keys = tmp;
+ } else {
+ BarKeyShortcut_t *curShortcut = settings->keys;
+ while (curShortcut->next != NULL) {
+ curShortcut = curShortcut->next;
+ }
+ curShortcut->next = tmp;
+ }
+}
+
/* read app settings from file; format is: key = value\n
* @param where to save these settings
* @return nothing yet
*/
void BarSettingsRead (BarSettings_t *settings) {
+ /* FIXME: what is the max length of a path? */
char configfile[1024], key[256], val[256];
FILE *configfd;
+ BarKeyShortcut_t defaultKeys[] = {
+ {'?', BarUiActHelp, NULL, "act_help", NULL},
+ {'+', BarUiActLoveSong, "love current song", "act_songlove",
+ NULL},
+ {'-', BarUiActBanSong, "ban current song", "act_songban", NULL},
+ {'a', BarUiActAddMusic, "add music to current station",
+ "act_stationaddmusic", NULL},
+ {'c', BarUiActCreateStation, "create new station",
+ "act_stationcreate", NULL},
+ {'d', BarUiActDeleteStation, "delete current station",
+ "act_stationdelete", NULL},
+ {'e', BarUiActExplain, "explain why this song is played",
+ "act_songexplain", NULL},
+ {'g', BarUiActStationFromGenre, "add genre station",
+ "act_stationaddbygenre", NULL},
+ {'i', BarUiActSongInfo,
+ "print verbose information about current song",
+ "act_songinfo", NULL},
+ {'m', BarUiActMoveSong, "move song to different station",
+ "act_songmove", NULL},
+ {'n', BarUiActSkipSong, "next song", "act_songnext", NULL},
+ {'p', BarUiActPause, "pause/continue", "act_songpause", NULL},
+ {'q', BarUiActQuit, "quit", "act_quit", NULL},
+ {'r', BarUiActRenameStation, "rename current station",
+ "act_stationrename", NULL},
+ {'s', BarUiActSelectStation, "change station",
+ "act_stationchange", NULL},
+ {'t', BarUiActTempBanSong, "tired (ban song for 1 month)",
+ "act_songtired", NULL},
+ {'u', BarUiActPrintUpcoming, "upcoming songs", "act_upcoming",
+ NULL},
+ {'x', BarUiActSelectQuickMix, "select quickmix stations",
+ "act_stationselectquickmix", NULL},
+ };
+ BarKeyShortcut_t *curShortcut;
+ size_t i;
BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile));
if ((configfd = fopen (configfile, "r")) == NULL) {
printf ("config file at %s not found\n", configfile);
+ /* FIXME: what about setting default values? */
return;
}
@@ -120,6 +194,15 @@ void BarSettingsRead (BarSettings_t *settings) {
} else {
settings->disableSecureLogin = 0;
}
+ } else if (memcmp ("act_", key, 4) == 0) {
+ /* keyboard shortcuts */
+ for (i = 0; i < sizeof (defaultKeys) / sizeof (*defaultKeys);
+ i++) {
+ if (strcmp (defaultKeys[i].configKey, key) == 0) {
+ defaultKeys[i].key = val[0];
+ BarSettingsAppendKey (&defaultKeys[i], settings);
+ }
+ }
}
}
@@ -129,10 +212,27 @@ void BarSettingsRead (BarSettings_t *settings) {
settings->lastfmScrobblePercent > 100) {
settings->lastfmScrobblePercent = 50;
}
+
/* only scrobble tracks if username and password are set */
if (settings->lastfmUser != NULL && settings->lastfmPassword != NULL) {
settings->enableScrobbling = 1;
}
+ /* all actions available? append default actions if necessary */
+ for (i = 0; i < sizeof (defaultKeys) / sizeof (*defaultKeys); i++) {
+ char shortcutAvailable = 0;
+ curShortcut = settings->keys;
+ while (curShortcut != NULL) {
+ if (curShortcut->cmd == defaultKeys[i].cmd) {
+ shortcutAvailable = 1;
+ break;
+ }
+ curShortcut = curShortcut->next;
+ }
+ if (!shortcutAvailable) {
+ BarSettingsAppendKey (&defaultKeys[i], settings);
+ }
+ }
+
fclose (configfd);
}
diff --git a/src/settings.h b/src/settings.h
index b9617c4..954e102 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -24,6 +24,13 @@ THE SOFTWARE.
#define _SETTINGS_H
#include <curl/curl.h>
+#include <piano.h>
+
+#include "player.h"
+
+#define BAR_KS_ARGS PianoHandle_t *ph, struct aacPlayer *player, \
+ struct BarSettings *settings, PianoSong_t **curSong, \
+ PianoStation_t **curStation, char *doQuit
struct BarSettings {
char *username;
@@ -35,9 +42,17 @@ struct BarSettings {
unsigned char lastfmScrobblePercent;
char enableScrobbling;
char disableSecureLogin;
+ struct BarKeyShortcut {
+ char key;
+ void (*cmd) (BAR_KS_ARGS);
+ char *description;
+ char *configKey;
+ struct BarKeyShortcut *next;
+ } *keys;
};
typedef struct BarSettings BarSettings_t;
+typedef struct BarKeyShortcut BarKeyShortcut_t;
void BarSettingsInit (BarSettings_t *settings);
void BarSettingsDestroy (BarSettings_t *settings);
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..a56fd06
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,362 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* everything that interacts with the user */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <readline/readline.h>
+
+#include "ui.h"
+
+/* output message and flush stdout
+ * @param message
+ */
+inline void BarUiMsg (const char *msg) {
+ printf ("%s", msg);
+ fflush (stdout);
+}
+
+/* prints human readable status message based on return value
+ * @param piano return value
+ */
+inline PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret) {
+ if (ret != PIANO_RET_OK) {
+ printf ("Error: %s\n", PianoErrorToStr (ret));
+ } else {
+ printf ("Ok.\n");
+ }
+ return ret;
+}
+
+/* check whether complete string is numeric
+ * @param the string
+ * @return 1 = yes, 0 = not numeric
+ */
+char BarIsNumericStr (const char *str) {
+ while (*str != '\0') {
+ if (isdigit (*str) == 0) {
+ return 0;
+ }
+ str++;
+ }
+ return 1;
+}
+
+/* use readline to get integer value
+ * @param prompt or NULL
+ * @param returns integer
+ * @return 1 = success, 0 = failure (not an integer, ...)
+ */
+char BarReadlineInt (const char *prompt, int *retVal) {
+ char *buf;
+ char ret = 0;
+
+ if ((buf = readline (prompt)) != NULL && strlen (buf) > 0 &&
+ BarIsNumericStr (buf)) {
+ *retVal = atoi (buf);
+ ret = 1;
+ }
+ if (buf != NULL) {
+ free (buf);
+ }
+ return ret;
+}
+
+/* sort linked list (station); attention: this is a
+ * "i-had-no-clue-what-to-do-algo", but it works.
+ * @param stations
+ * @return NULL-terminated array with sorted stations
+ */
+PianoStation_t **BarSortedStations (PianoStation_t *unsortedStations) {
+ PianoStation_t *currStation, **sortedStations, **currSortedStation;
+ PianoStation_t *oldStation, *veryOldStation;
+ size_t unsortedStationsN = 0;
+ char inserted;
+
+ /* get size */
+ currStation = unsortedStations;
+ while (currStation != NULL) {
+ unsortedStationsN++;
+ currStation = currStation->next;
+ }
+ sortedStations = calloc (unsortedStationsN+1, sizeof (*sortedStations));
+
+ currStation = unsortedStations;
+ while (currStation != NULL) {
+ currSortedStation = sortedStations;
+ inserted = 0;
+ while (*currSortedStation != NULL && !inserted) {
+ /* item has to be inserted _before_ current item? */
+ /* FIXME: this doesn't handle multibyte chars correctly */
+ if (strcasecmp (currStation->name,
+ (*currSortedStation)->name) < 0) {
+ oldStation = *currSortedStation;
+ *currSortedStation = currStation;
+ currSortedStation++;
+ /* move items */
+ while (*currSortedStation != NULL) {
+ veryOldStation = *currSortedStation;
+ *currSortedStation = oldStation;
+ oldStation = veryOldStation;
+ currSortedStation++;
+ }
+ /* append last item */
+ if (oldStation != NULL) {
+ *currSortedStation = oldStation;
+ }
+ inserted = 1;
+ }
+ currSortedStation++;
+ }
+ /* item could not be inserted: append */
+ if (!inserted) {
+ *currSortedStation = currStation;
+ }
+ currStation = currStation->next;
+ }
+ return sortedStations;
+}
+
+/* let user pick one station
+ * @param piano handle
+ * @return pointer to selected station or NULL
+ */
+PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt) {
+ PianoStation_t **ss = NULL, **ssCurr = NULL, *retStation;
+ int i = 0;
+
+ ss = BarSortedStations (ph->stations);
+ ssCurr = ss;
+ while (*ssCurr != NULL) {
+ printf ("%2i) %c%c%c %s\n", i,
+ (*ssCurr)->useQuickMix ? 'q' : ' ',
+ (*ssCurr)->isQuickMix ? 'Q' : ' ',
+ !(*ssCurr)->isCreator ? 'S' : ' ',
+ (*ssCurr)->name);
+ ssCurr++;
+ i++;
+ }
+
+ if (!BarReadlineInt (prompt, &i)) {
+ return NULL;
+ }
+ ssCurr = ss;
+ while (*ssCurr != NULL && i > 0) {
+ ssCurr++;
+ i--;
+ }
+ retStation = *ssCurr;
+ free (ss);
+ return retStation;
+}
+
+/* let user pick one song
+ * @param song list
+ * @return pointer to selected item in song list or NULL
+ */
+PianoSong_t *BarUiSelectSong (PianoSong_t *startSong) {
+ PianoSong_t *tmpSong = NULL;
+ int i = 0;
+
+ tmpSong = startSong;
+ while (tmpSong != NULL) {
+ printf ("%2u) %s - %s\n", i, tmpSong->artist, tmpSong->title);
+ i++;
+ tmpSong = tmpSong->next;
+ }
+ if (!BarReadlineInt ("Select song: ", &i)) {
+ return NULL;
+ }
+ tmpSong = startSong;
+ while (tmpSong != NULL && i > 0) {
+ tmpSong = tmpSong->next;
+ i--;
+ }
+ return tmpSong;
+}
+
+/* let user pick one artist
+ * @param artists (linked list)
+ * @return pointer to selected artist or NULL on abort
+ */
+PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist) {
+ PianoArtist_t *tmpArtist = NULL;
+ int i = 0;
+
+ tmpArtist = startArtist;
+ while (tmpArtist != NULL) {
+ printf ("%2u) %s\n", i, tmpArtist->name);
+ i++;
+ tmpArtist = tmpArtist->next;
+ }
+ if (!BarReadlineInt ("Select artist: ", &i)) {
+ return NULL;
+ }
+ tmpArtist = startArtist;
+ while (tmpArtist != NULL && i > 0) {
+ tmpArtist = tmpArtist->next;
+ i--;
+ }
+ return tmpArtist;
+}
+
+/* search music: query, search request, return music id
+ * @param piano handle
+ * @return musicId or NULL on abort/error
+ */
+char *BarUiSelectMusicId (const PianoHandle_t *ph) {
+ char *musicId = NULL, *lineBuf;
+ char yesnoBuf;
+ PianoSearchResult_t searchResult;
+ PianoArtist_t *tmpArtist;
+ PianoSong_t *tmpSong;
+
+ lineBuf = readline ("Search for artist/title: ");
+ if (lineBuf != NULL && strlen (lineBuf) > 0) {
+ BarUiMsg ("Searching... ");
+ if (BarUiPrintPianoStatus (PianoSearchMusic (ph, lineBuf,
+ &searchResult)) != PIANO_RET_OK) {
+ free (lineBuf);
+ return NULL;
+ }
+ BarUiMsg ("\r");
+ if (searchResult.songs != NULL && searchResult.artists != NULL) {
+ BarUiMsg ("Is this an [a]rtist or [t]rack name? Press c to abort.\n");
+ read (fileno (stdin), &yesnoBuf, sizeof (yesnoBuf));
+ if (yesnoBuf == 'a') {
+ tmpArtist = BarUiSelectArtist (searchResult.artists);
+ if (tmpArtist != NULL) {
+ musicId = strdup (tmpArtist->musicId);
+ }
+ } else if (yesnoBuf == 't') {
+ tmpSong = BarUiSelectSong (searchResult.songs);
+ if (tmpSong != NULL) {
+ musicId = strdup (tmpSong->musicId);
+ }
+ } else {
+ BarUiMsg ("Aborted.\n");
+ }
+ } else if (searchResult.songs != NULL) {
+ tmpSong = BarUiSelectSong (searchResult.songs);
+ if (tmpSong != NULL) {
+ musicId = strdup (tmpSong->musicId);
+ } else {
+ BarUiMsg ("Aborted.\n");
+ }
+ } else if (searchResult.artists != NULL) {
+ tmpArtist = BarUiSelectArtist (searchResult.artists);
+ if (tmpArtist != NULL) {
+ musicId = strdup (tmpArtist->musicId);
+ } else {
+ BarUiMsg ("Aborted.\n");
+ }
+ } else {
+ BarUiMsg ("Nothing found...\n");
+ }
+ PianoDestroySearchResult (&searchResult);
+ } else {
+ BarUiMsg ("Aborted.\n");
+ }
+ if (lineBuf != NULL) {
+ free (lineBuf);
+ }
+
+ return musicId;
+}
+
+/* browse genre stations and create shared station
+ * @param piano handle
+ */
+void BarStationFromGenre (PianoHandle_t *ph) {
+ int i;
+ PianoGenreCategory_t *curCat;
+ PianoStation_t *curStation;
+
+ /* receive genre stations list if not yet available */
+ if (ph->genreStations == NULL) {
+ BarUiMsg ("Receiving genre stations... ");
+ if (BarUiPrintPianoStatus (PianoGetGenreStations (ph)) !=
+ PIANO_RET_OK) {
+ return;
+ }
+ }
+
+ /* print all available categories */
+ curCat = ph->genreStations;
+ i = 0;
+ while (curCat != NULL) {
+ printf ("%2i) %s\n", i, curCat->name);
+ i++;
+ curCat = curCat->next;
+ }
+ /* select category or exit */
+ if (!BarReadlineInt (NULL, &i)) {
+ BarUiMsg ("Aborted.\n");
+ return;
+ }
+ curCat = ph->genreStations;
+ while (curCat != NULL && i > 0) {
+ curCat = curCat->next;
+ i--;
+ }
+
+ /* print all available stations */
+ curStation = curCat->stations;
+ i = 0;
+ while (curStation != NULL) {
+ printf ("%2i) %s\n", i, curStation->name);
+ i++;
+ curStation = curStation->next;
+ }
+ if (!BarReadlineInt (NULL, &i)) {
+ BarUiMsg ("Aborted.\n");
+ return;
+ }
+ curStation = curCat->stations;
+ while (curStation != NULL && i > 0) {
+ curStation = curStation->next;
+ i--;
+ }
+ /* create station */
+ printf ("Adding shared station \"%s\"... ", curStation->name);
+ fflush (stdout);
+ BarUiPrintPianoStatus (PianoCreateStation (ph, "sh", curStation->id));
+}
+
+/* transform station if necessary to allow changes like rename, rate, ...
+ * @param piano handle
+ * @param transform this station
+ * @return 0 = error, 1 = everything went well
+ */
+int BarTransformIfShared (PianoHandle_t *ph, PianoStation_t *station) {
+ /* shared stations must be transformed */
+ if (!station->isCreator) {
+ BarUiMsg ("Transforming station... ");
+ if (BarUiPrintPianoStatus (PianoTransformShared (ph, station)) !=
+ PIANO_RET_OK) {
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..91617bd
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _UI_H
+#define _UI_H
+
+#include <piano.h>
+
+inline void BarUiMsg (const char *msg);
+inline PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret);
+PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt);
+PianoSong_t *BarUiSelectSong (PianoSong_t *startSong);
+PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist);
+char *BarUiSelectMusicId (const PianoHandle_t *ph);
+void BarStationFromGenre (PianoHandle_t *ph);
+
+#endif /* _UI_H */
diff --git a/src/ui_act.c b/src/ui_act.c
new file mode 100644
index 0000000..57ac9af
--- /dev/null
+++ b/src/ui_act.c
@@ -0,0 +1,288 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* functions responding to user's keystrokes */
+
+#include <string.h>
+/* needed by readline */
+#include <stdio.h>
+#include <readline/readline.h>
+
+#include "ui.h"
+#include "ui_act.h"
+
+void BarUiActHelp (BAR_KS_ARGS) {
+ BarKeyShortcut_t *curShortcut = settings->keys;
+
+ printf ("\r");
+ while (curShortcut != NULL) {
+ if (curShortcut->description != NULL) {
+ printf ("%c\t%s\n", curShortcut->key, curShortcut->description);
+ }
+ curShortcut = curShortcut->next;
+ }
+}
+
+void BarUiActAddMusic (BAR_KS_ARGS) {
+ char *musicId;
+ if (*curStation == NULL) {
+ BarUiMsg ("No station selected.\n");
+ return;
+ }
+ musicId = BarUiSelectMusicId (ph);
+ if (musicId == NULL) {
+ if (!BarTransformIfShared (ph, *curStation)) {
+ return;
+ }
+ BarUiMsg ("Adding music to station... ");
+ BarUiPrintPianoStatus (PianoStationAddMusic (ph,
+ *curStation, musicId));
+ free (musicId);
+ }
+}
+
+void BarUiActBanSong (BAR_KS_ARGS) {
+ if (*curStation == NULL || *curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ if (!BarTransformIfShared (ph, *curStation)) {
+ return;
+ }
+ BarUiMsg ("Banning song... ");
+ if (BarUiPrintPianoStatus (PianoRateTrack (ph, *curSong,
+ PIANO_RATE_BAN)) == PIANO_RET_OK) {
+ player->doQuit = 1;
+ }
+}
+
+void BarUiActCreateStation (BAR_KS_ARGS) {
+ char *musicId;
+ musicId = BarUiSelectMusicId (ph);
+ if (musicId != NULL) {
+ BarUiMsg ("Creating station... ");
+ BarUiPrintPianoStatus (PianoCreateStation (ph, "mi", musicId));
+ free (musicId);
+ }
+}
+
+void BarUiActDeleteStation (BAR_KS_ARGS) {
+ char yesNoBuf;
+
+ if (*curStation == NULL) {
+ BarUiMsg ("No station selected.\n");
+ return;
+ }
+ printf ("Really delete \"%s\"? [yn]\n", (*curStation)->name);
+ read (fileno (stdin), &yesNoBuf, sizeof (yesNoBuf));
+ if (yesNoBuf == 'y') {
+ BarUiMsg ("Deleting station... ");
+ if (BarUiPrintPianoStatus (PianoDeleteStation (ph,
+ *curStation)) == PIANO_RET_OK) {
+ player->doQuit = 1;
+ PianoDestroyPlaylist (ph);
+ *curSong = NULL;
+ *curStation = NULL;
+ }
+ }
+}
+
+void BarUiActExplain (BAR_KS_ARGS) {
+ char *explanation;
+
+ if (*curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ BarUiMsg ("Receiving explanation... ");
+ if (BarUiPrintPianoStatus (PianoExplain (ph, *curSong,
+ &explanation)) == PIANO_RET_OK) {
+ printf ("%s\n", explanation);
+ free (explanation);
+ }
+}
+
+void BarUiActStationFromGenre (BAR_KS_ARGS) {
+ /* use genre station */
+ BarStationFromGenre (ph);
+}
+
+void BarUiActSongInfo (BAR_KS_ARGS) {
+ if (*curStation == NULL || *curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ /* print debug-alike infos */
+ printf ("Song infos:\n"
+ "album:\t%s\n"
+ "artist:\t%s\n"
+ "audioUrl:\t%s\n"
+ "fileGain:\t%f\n"
+ "focusTraitId:\t%s\n"
+ "identity:\t%s\n"
+ "matchingSeed:\t%s\n"
+ "musicId:\t%s\n"
+ "rating:\t%i\n"
+ "stationId:\t%s\n"
+ "title:\t%s\n"
+ "userSeed:\t%s\n",
+ (*curSong)->album, (*curSong)->artist, (*curSong)->audioUrl,
+ (*curSong)->fileGain, (*curSong)->focusTraitId,
+ (*curSong)->identity, (*curSong)->matchingSeed,
+ (*curSong)->musicId, (*curSong)->rating,
+ (*curSong)->stationId, (*curSong)->title,
+ (*curSong)->userSeed);
+}
+
+void BarUiActLoveSong (BAR_KS_ARGS) {
+ if (*curStation == NULL || *curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ if ((*curSong)->rating == PIANO_RATE_LOVE) {
+ BarUiMsg ("Already loved. No need to do this twice.\n");
+ return;
+ }
+ if (!BarTransformIfShared (ph, *curStation)) {
+ return;
+ }
+ BarUiMsg ("Loving song... ");
+ BarUiPrintPianoStatus (PianoRateTrack (ph, *curSong, PIANO_RATE_LOVE));
+}
+
+void BarUiActSkipSong (BAR_KS_ARGS) {
+ player->doQuit = 1;
+}
+
+void BarUiActMoveSong (BAR_KS_ARGS) {
+ PianoStation_t *moveStation;
+
+ if (*curStation == NULL || *curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ moveStation = BarUiSelectStation (ph, "Move song to station: ");
+ if (moveStation != NULL) {
+ if (!BarTransformIfShared (ph, *curStation) ||
+ !BarTransformIfShared (ph, moveStation)) {
+ return;
+ }
+ printf ("Moving song to \"%s\"... ", moveStation->name);
+ fflush (stdout);
+ if (BarUiPrintPianoStatus (PianoMoveSong (ph, *curStation,
+ moveStation, *curSong)) == PIANO_RET_OK) {
+ player->doQuit = 1;
+ }
+ }
+}
+
+void BarUiActPause (BAR_KS_ARGS) {
+ player->doPause = !player->doPause;
+}
+
+void BarUiActRenameStation (BAR_KS_ARGS) {
+ char *lineBuf;
+
+ if (*curStation == NULL) {
+ BarUiMsg ("No station selected.\n");
+ return;
+ }
+ lineBuf = readline ("New name?\n");
+ if (lineBuf != NULL && strlen (lineBuf) > 0) {
+ if (!BarTransformIfShared (ph, *curStation)) {
+ return;
+ }
+ BarUiMsg ("Renaming station... ");
+ BarUiPrintPianoStatus (PianoRenameStation (ph, *curStation, lineBuf));
+ }
+ if (lineBuf != NULL) {
+ free (lineBuf);
+ }
+}
+
+void BarUiActSelectStation (BAR_KS_ARGS) {
+ player->doQuit = 1;
+ PianoDestroyPlaylist (ph);
+ *curSong = NULL;
+ *curStation = BarUiSelectStation (ph, "Select station: ");
+ if (*curStation != NULL) {
+ printf ("Changed station to %s\n", (*curStation)->name);
+ }
+}
+
+void BarUiActTempBanSong (BAR_KS_ARGS) {
+ if (*curStation == NULL || *curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ if (!BarTransformIfShared (ph, *curStation)) {
+ return;
+ }
+ BarUiMsg ("Putting song on shelf... ");
+ if (BarUiPrintPianoStatus (PianoSongTired (ph, *curSong)) ==
+ PIANO_RET_OK) {
+ player->doQuit = 1;
+ }
+}
+
+void BarUiActPrintUpcoming (BAR_KS_ARGS) {
+ if (*curStation == NULL || *curSong == NULL) {
+ BarUiMsg ("No song playing.\n");
+ return;
+ }
+ PianoSong_t *nextSong = (*curSong)->next;
+ if (nextSong != NULL) {
+ int i = 0;
+ BarUiMsg ("Next songs:\n");
+ while (nextSong != NULL) {
+ printf ("%2i) \"%s\" by \"%s\"\n", i, nextSong->title,
+ nextSong->artist);
+ nextSong = nextSong->next;
+ i++;
+ }
+ } else {
+ BarUiMsg ("No songs in queue.\n");
+ }
+}
+
+void BarUiActSelectQuickMix (BAR_KS_ARGS) {
+ if (*curStation == NULL) {
+ BarUiMsg ("No station selected.\n");
+ return;
+ }
+ if ((*curStation)->isQuickMix) {
+ PianoStation_t *selStation;
+ while ((selStation = BarUiSelectStation (ph,
+ "Toggle quickmix for station: ")) != NULL) {
+ selStation->useQuickMix = !selStation->useQuickMix;
+ }
+ BarUiMsg ("Setting quickmix stations... ");
+ BarUiPrintPianoStatus (PianoSetQuickmix (ph));
+ } else {
+ BarUiMsg ("Not a QuickMix station.\n");
+ }
+}
+
+void BarUiActQuit (BAR_KS_ARGS) {
+ *doQuit = 1;
+ player->doQuit = 1;
+}
diff --git a/src/ui_act.h b/src/ui_act.h
new file mode 100644
index 0000000..fdcce8c
--- /dev/null
+++ b/src/ui_act.h
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _UI_ACT_H
+#define _UI_ACT_H
+
+#include "settings.h"
+
+void BarUiActHelp (BAR_KS_ARGS);
+void BarUiActAddMusic (BAR_KS_ARGS);
+void BarUiActBanSong (BAR_KS_ARGS);
+void BarUiActCreateStation (BAR_KS_ARGS);
+void BarUiActDeleteStation (BAR_KS_ARGS);
+void BarUiActExplain (BAR_KS_ARGS);
+void BarUiActStationFromGenre (BAR_KS_ARGS);
+void BarUiActSongInfo (BAR_KS_ARGS);
+void BarUiActLoveSong (BAR_KS_ARGS);
+void BarUiActSkipSong (BAR_KS_ARGS);
+void BarUiActMoveSong (BAR_KS_ARGS);
+void BarUiActPause (BAR_KS_ARGS);
+void BarUiActRenameStation (BAR_KS_ARGS);
+void BarUiActSelectStation (BAR_KS_ARGS);
+void BarUiActTempBanSong (BAR_KS_ARGS);
+void BarUiActPrintUpcoming (BAR_KS_ARGS);
+void BarUiActSelectQuickMix (BAR_KS_ARGS);
+void BarUiActQuit (BAR_KS_ARGS);
+
+#endif /* _UI_ACT_H */