diff options
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/main.c | 679 | ||||
-rw-r--r-- | src/player.c | 2 | ||||
-rw-r--r-- | src/player.h | 4 | ||||
-rw-r--r-- | src/settings.c | 100 | ||||
-rw-r--r-- | src/settings.h | 15 | ||||
-rw-r--r-- | src/ui.c | 362 | ||||
-rw-r--r-- | src/ui.h | 36 | ||||
-rw-r--r-- | src/ui_act.c | 288 | ||||
-rw-r--r-- | src/ui_act.h | 47 |
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} \ @@ -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 */ |