summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c679
1 files changed, 50 insertions, 629 deletions
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;
}