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 */ | 
