Exemplo n.º 1
0
/*	authenticate user
 */
static bool BarMainLoginUser (BarApp_t *app) {
	PianoReturn_t pRet;
	WaitressReturn_t wRet;
	PianoRequestDataLogin_t reqData;
	bool ret;

	reqData.user = app->settings.username;
	reqData.password = app->settings.password;
	reqData.step = 0;

	BarUiMsg (&app->settings, MSG_INFO, "Login... ");
	ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet, &wRet);
	BarUiStartEventCmd (&app->settings, "userlogin", NULL, NULL, &app->player,
			NULL, pRet, wRet);
	return ret;
}
Exemplo n.º 2
0
/*	transform station if necessary to allow changes like rename, rate, ...
 *	@param piano handle
 *	@param transform this station
 *	@return 0 = error, 1 = everything went well
 */
static int BarTransformIfShared (BarApp_t *app, PianoStation_t *station) {
	PianoReturn_t pRet;
	CURLcode wRet;

	assert (station != NULL);

	/* shared stations must be transformed */
	if (!station->isCreator) {
		BarUiMsg (&app->settings, MSG_INFO, "Transforming station... ");
		if (!BarUiPianoCall (app, PIANO_REQUEST_TRANSFORM_STATION, station,
				&pRet, &wRet)) {
			return 0;
		}
	}
	return 1;
}
Exemplo n.º 3
0
/*	authenticate user
 */
static bool BarMainLoginUser (BarApp_t *app) {
	PianoReturn_t pRet;
	WaitressReturn_t wRet;
	PianoRequestDataLogin_t reqData;
	bool ret;
#if 0
	WaitressHandle_t waithSync;
	char *syncTime;
	unsigned long int syncTimeInt;

	/* skip sync step by fetching time from somewhere else */
	WaitressInit (&waithSync);
	WaitressSetUrl (&waithSync, "http://ridetheclown.com/s2/synctime.php");
	if (app->settings.proxy != NULL && strlen (app->settings.proxy) > 0) {
		WaitressSetProxy (&waithSync, app->settings.proxy);
	}
	wRet = WaitressFetchBuf (&waithSync, &syncTime);
	WaitressFree (&waithSync);
	if (wRet != WAITRESS_RET_OK) {
		BarUiMsg (&app->settings, MSG_ERR, "Unable to sync: %s\n",
				WaitressErrorToStr (wRet));
		return false;
	}

	syncTimeInt = strtoul (syncTime, NULL, 0);
	app->ph.timeOffset = time (NULL) - syncTimeInt;
	free (syncTime);
#endif
	app->ph.timeOffset = -30239998; /* woo! magic number */

	reqData.user = app->settings.username;
	reqData.password = app->settings.password;
	reqData.step = 0;

	BarUiMsg (&app->settings, MSG_INFO, "Login... ");
	ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet, &wRet);
	BarUiStartEventCmd (&app->settings, "userlogin", NULL, NULL, &app->player,
			NULL, pRet, wRet);
	return ret;
}
Exemplo n.º 4
0
/*	fetch new playlist
 */
static void BarMainGetPlaylist (BarApp_t *app) {
	PianoReturn_t pRet;
	CURLcode wRet;
	PianoRequestDataGetPlaylist_t reqData;
	reqData.station = app->curStation;
	reqData.quality = app->settings.audioQuality;

	BarUiMsg (&app->settings, MSG_INFO, "Receiving new playlist... ");
	if (!BarUiPianoCall (app, PIANO_REQUEST_GET_PLAYLIST,
			&reqData, &pRet, &wRet)) {
		app->curStation = NULL;
	} else {
		app->playlist = reqData.retPlaylist;
		if (app->playlist == NULL) {
			BarUiMsg (&app->settings, MSG_INFO, "No tracks left.\n");
			app->curStation = NULL;
		}
	}
	BarUiStartEventCmd (&app->settings, "stationfetchplaylist",
			app->curStation, app->playlist, &app->player, app->ph.stations,
			pRet, wRet);
}
Exemplo n.º 5
0
/*	browse genre stations and create shared station
 *	@param app handle
 */
void BarStationFromGenre (BarApp_t *app) {
	PianoReturn_t pRet;
	WaitressReturn_t wRet;
	PianoGenreCategory_t *curCat;
	PianoGenre_t *curGenre;
	int i;

	/* receive genre stations list if not yet available */
	if (app->ph.genreStations == NULL) {
		BarUiMsg (&app->settings, MSG_INFO, "Receiving genre stations... ");
		if (!BarUiPianoCall (app, PIANO_REQUEST_GET_GENRE_STATIONS, NULL,
				&pRet, &wRet)) {
			return;
		}
	}

	/* print all available categories */
	curCat = app->ph.genreStations;
	i = 0;
	while (curCat != NULL) {
		BarUiMsg (&app->settings, MSG_LIST, "%2i) %s\n", i, curCat->name);
		i++;
		curCat = curCat->next;
	}

	do {
		/* select category or exit */
		BarUiMsg (&app->settings, MSG_QUESTION, "Select category: ");
		if (BarReadlineInt (&i, &app->input) == 0) {
			return;
		}
		curCat = app->ph.genreStations;
		while (curCat != NULL && i > 0) {
			curCat = curCat->next;
			i--;
		}
	} while (curCat == NULL);
	
	/* print all available stations */
	curGenre = curCat->genres;
	i = 0;
	while (curGenre != NULL) {
		BarUiMsg (&app->settings, MSG_LIST, "%2i) %s\n", i, curGenre->name);
		i++;
		curGenre = curGenre->next;
	}

	do {
		BarUiMsg (&app->settings, MSG_QUESTION, "Select genre: ");
		if (BarReadlineInt (&i, &app->input) == 0) {
			return;
		}
		curGenre = curCat->genres;
		while (curGenre != NULL && i > 0) {
			curGenre = curGenre->next;
			i--;
		}
	} while (curGenre == NULL);

	/* create station */
	PianoRequestDataCreateStation_t reqData;
	reqData.token = curGenre->musicId;
	reqData.type = PIANO_MUSICTYPE_INVALID;
	BarUiMsg (&app->settings, MSG_INFO, "Adding shared station \"%s\"... ", curGenre->name);
	BarUiPianoCall (app, PIANO_REQUEST_CREATE_STATION, &reqData, &pRet, &wRet);
}
Exemplo n.º 6
0
/*	search music: query, search request, return music id
 *	@param app handle
 *	@param seed suggestion station
 *	@param seed suggestion musicid
 *	@param prompt string
 *	@return musicId or NULL on abort/error
 */
char *BarUiSelectMusicId (BarApp_t *app, PianoStation_t *station,
		const char *msg) {
	char *musicId = NULL;
	char lineBuf[100], selectBuf[2];
	PianoSearchResult_t searchResult;
	PianoArtist_t *tmpArtist;
	PianoSong_t *tmpSong;

	BarUiMsg (&app->settings, MSG_QUESTION, msg);
	if (BarReadlineStr (lineBuf, sizeof (lineBuf), &app->input,
			BAR_RL_DEFAULT) > 0) {
		PianoReturn_t pRet;
		WaitressReturn_t wRet;
		PianoRequestDataSearch_t reqData;

		reqData.searchStr = lineBuf;

		BarUiMsg (&app->settings, MSG_INFO, "Searching... ");
		if (!BarUiPianoCall (app, PIANO_REQUEST_SEARCH, &reqData, &pRet,
				&wRet)) {
			return NULL;
		}
		memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult));

		BarUiMsg (&app->settings, MSG_NONE, "\r");
		if (searchResult.songs != NULL &&
				searchResult.artists != NULL) {
			/* songs and artists found */
			BarUiMsg (&app->settings, MSG_QUESTION, "Is this an [a]rtist or [t]rack name? ");
			BarReadline (selectBuf, sizeof (selectBuf), "at", &app->input,
					BAR_RL_FULLRETURN, -1);
			if (*selectBuf == 'a') {
				tmpArtist = BarUiSelectArtist (app, searchResult.artists);
				if (tmpArtist != NULL) {
					musicId = strdup (tmpArtist->musicId);
				}
			} else if (*selectBuf == 't') {
				tmpSong = BarUiSelectSong (&app->settings, searchResult.songs,
						&app->input);
				if (tmpSong != NULL) {
					musicId = strdup (tmpSong->musicId);
				}
			}
		} else if (searchResult.songs != NULL) {
			/* songs found */
			tmpSong = BarUiSelectSong (&app->settings, searchResult.songs,
					&app->input);
			if (tmpSong != NULL) {
				musicId = strdup (tmpSong->musicId);
			}
		} else if (searchResult.artists != NULL) {
			/* artists found */
			tmpArtist = BarUiSelectArtist (app, searchResult.artists);
			if (tmpArtist != NULL) {
				musicId = strdup (tmpArtist->musicId);
			}
		} else {
			BarUiMsg (&app->settings, MSG_INFO, "Nothing found...\n");
		}
		PianoDestroySearchResult (&searchResult);
	}

	return musicId;
}
Exemplo n.º 7
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano (updates data structures)
 *	@param app handle
 *	@param request type
 *	@param request data
 *	@param stores piano return code
 *	@param stores waitress return code
 *	@return 1 on success, 0 otherwise
 */
int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type,
		void *data, PianoReturn_t *pRet, WaitressReturn_t *wRet) {
	PianoRequest_t req;

	memset (&req, 0, sizeof (req));

	/* repeat as long as there are http requests to do */
	do {
		req.data = data;

		*pRet = PianoRequest (&app->ph, &req, type);
		if (*pRet != PIANO_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
			PianoDestroyRequest (&req);
			return 0;
		}

		*wRet = BarPianoHttpRequest (&app->waith, &req);
		if (*wRet != WAITRESS_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n", WaitressErrorToStr (*wRet));
			if (req.responseData != NULL) {
				free (req.responseData);
			}
			PianoDestroyRequest (&req);
			return 0;
		}

		*pRet = PianoResponse (&app->ph, &req);
		if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
			/* checking for request type avoids infinite loops */
			if (*pRet == PIANO_RET_P_INVALID_AUTH_TOKEN &&
					type != PIANO_REQUEST_LOGIN) {
				/* reauthenticate */
				PianoReturn_t authpRet;
				WaitressReturn_t authwRet;
				PianoRequestDataLogin_t reqData;
				reqData.user = app->settings.username;
				reqData.password = app->settings.password;
				reqData.step = 0;

				BarUiMsg (&app->settings, MSG_NONE, "Reauthentication required... ");
				if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet,
						&authwRet)) {
					*pRet = authpRet;
					*wRet = authwRet;
					if (req.responseData != NULL) {
						free (req.responseData);
					}
					PianoDestroyRequest (&req);
					return 0;
				} else {
					/* try again */
					*pRet = PIANO_RET_CONTINUE_REQUEST;
					BarUiMsg (&app->settings, MSG_INFO, "Trying again... ");
				}
			} else if (*pRet != PIANO_RET_OK) {
				BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
				if (req.responseData != NULL) {
					free (req.responseData);
				}
				PianoDestroyRequest (&req);
				return 0;
			} else {
				BarUiMsg (&app->settings, MSG_NONE, "Ok.\n");
			}
		}
		/* we can destroy the request at this point, even when this call needs
		 * more than one http request. persistent data (step counter, e.g.) is
		 * stored in req.data */
		if (req.responseData != NULL) {
			free (req.responseData);
		}
		PianoDestroyRequest (&req);
	} while (*pRet == PIANO_RET_CONTINUE_REQUEST);

	return 1;
}
Exemplo n.º 8
0
int main (int argc, char **argv) {
	static BarApp_t app;
	pthread_t playerThread;
	/* FIXME: max path length? */
	char ctlPath[1024];
	FILE *ctlFd = NULL;
	struct timeval selectTimeout;
	int maxFd, selectFds[2];
	fd_set readSet, readSetCopy;
	char buf = '\0';
	/* terminal attributes _before_ we started messing around with ~ECHO */
	struct termios termOrig;

	memset (&app, 0, sizeof (app));

	/* save terminal attributes, before disabling echoing */
	BarTermSave (&termOrig);

	BarTermSetEcho (0);
	BarTermSetBuffer (0);
	/* init some things */
	ao_initialize ();
	PianoInit (&app.ph);

	WaitressInit (&app.waith);
	strncpy (app.waith.host, PIANO_RPC_HOST, sizeof (app.waith.host)-1);
	strncpy (app.waith.port, PIANO_RPC_PORT, sizeof (app.waith.port)-1);

	BarSettingsInit (&app.settings);
	BarSettingsRead (&app.settings);

	BarUiMsg (MSG_NONE, "Welcome to " PACKAGE "! Press %c for a list of commands.\n",
			app.settings.keys[BAR_KS_HELP]);

	/* init fds */
	FD_ZERO(&readSet);
	selectFds[0] = fileno (stdin);
	FD_SET(selectFds[0], &readSet);
	maxFd = selectFds[0] + 1;

	BarGetXdgConfigDir (PACKAGE "/ctl", ctlPath, sizeof (ctlPath));
	/* FIXME: why is r_+_ required? */
	ctlFd = fopen (ctlPath, "r+");
	if (ctlFd != NULL) {
		selectFds[1] = fileno (ctlFd);
		FD_SET(selectFds[1], &readSet);
		/* assuming ctlFd is always > stdin */
		maxFd = selectFds[1] + 1;
		BarUiMsg (MSG_INFO, "Control fifo at %s opened\n", ctlPath);
	}

	if (app.settings.username == NULL) {
		char nameBuf[100];
		BarUiMsg (MSG_QUESTION, "Username: "******"Password: "******"Login... ");
		if (!BarUiPianoCall (&app.ph, PIANO_REQUEST_LOGIN, &app.waith,
				&reqData, &pRet, &wRet)) {
			BarTermRestore (&termOrig);
			return 0;
		}
	}

	{
		PianoReturn_t pRet;
		WaitressReturn_t wRet;

		BarUiMsg (MSG_INFO, "Get stations... ");
		if (!BarUiPianoCall (&app.ph, PIANO_REQUEST_GET_STATIONS, &app.waith,
				NULL, &pRet, &wRet)) {
			BarTermRestore (&termOrig);
			return 0;
		}
	}

	/* try to get autostart station */
	if (app.settings.autostartStation != NULL) {
		app.curStation = PianoFindStationById (app.ph.stations,
				app.settings.autostartStation);
		if (app.curStation == NULL) {
			BarUiMsg (MSG_ERR, "Error: Autostart station not found.\n");
		}
	}
	/* no autostart? ask the user */
	if (app.curStation == NULL) {
		app.curStation = BarUiSelectStation (&app.ph, "Select station: ",
				app.settings.sortOrder, stdin);
	}
	if (app.curStation != NULL) {
		BarUiPrintStation (app.curStation);
	}

	/* little hack, needed to signal: hey! we need a playlist, but don't
	 * free anything (there is nothing to be freed yet) */
	memset (&app.player, 0, sizeof (app.player));

	while (!app.doQuit) {
		/* song finished playing, clean up things/scrobble song */
		if (app.player.mode == PLAYER_FINISHED_PLAYBACK) {
			BarUiStartEventCmd (&app.settings, "songfinish", app.curStation,
					app.playlist, &app.player, PIANO_RET_OK, WAITRESS_RET_OK);
			/* FIXME: pthread_join blocks everything if network connection
			 * is hung up e.g. */
			void *threadRet;
			pthread_join (playerThread, &threadRet);
			/* don't continue playback if thread reports error */
			if (threadRet != (void *) PLAYER_RET_OK) {
				app.curStation = NULL;
			}
			memset (&app.player, 0, sizeof (app.player));
		}

		/* check whether player finished playing and start playing new
		 * song */
		if (app.player.mode >= PLAYER_FINISHED_PLAYBACK ||
				app.player.mode == PLAYER_FREED) {
			if (app.curStation != NULL) {
				/* what's next? */
				if (app.playlist != NULL) {
					if (app.settings.history != 0) {
						/* prepend song to history list */
						PianoSong_t *tmpSong = app.songHistory;
						app.songHistory = app.playlist;
						/* select next song */
						app.playlist = app.playlist->next;
						app.songHistory->next = tmpSong;

						/* limit history's length */
						/* start with 1, so we're stopping at n-1 and have the
						 * chance to set ->next = NULL */
						unsigned int i = 1;
						tmpSong = app.songHistory;
						while (i < app.settings.history && tmpSong != NULL) {
							tmpSong = tmpSong->next;
							++i;
						}
						/* if too many songs in history... */
						if (tmpSong != NULL) {
							PianoSong_t *delSong = tmpSong->next;
							tmpSong->next = NULL;
							if (delSong != NULL) {
								PianoDestroyPlaylist (delSong);
							}
						}
					} else {
						/* don't keep history */
						app.playlist = app.playlist->next;
					}
				}
				if (app.playlist == NULL) {
					PianoReturn_t pRet;
					WaitressReturn_t wRet;
					PianoRequestDataGetPlaylist_t reqData;
					reqData.station = app.curStation;
					reqData.format = app.settings.audioFormat;

					BarUiMsg (MSG_INFO, "Receiving new playlist... ");
					if (!BarUiPianoCall (&app.ph, PIANO_REQUEST_GET_PLAYLIST,
							&app.waith, &reqData, &pRet, &wRet)) {
						app.curStation = NULL;
					} else {
						app.playlist = reqData.retPlaylist;
						if (app.playlist == NULL) {
							BarUiMsg (MSG_INFO, "No tracks left.\n");
							app.curStation = NULL;
						}
					}
					BarUiStartEventCmd (&app.settings, "stationfetchplaylist",
							app.curStation, app.playlist, &app.player, pRet,
							wRet);
				}
				/* song ready to play */
				if (app.playlist != NULL) {
					BarUiPrintSong (app.playlist, app.curStation->isQuickMix ?
							PianoFindStationById (app.ph.stations,
							app.playlist->stationId) : NULL);

					if (app.playlist->audioUrl == NULL) {
						BarUiMsg (MSG_ERR, "Invalid song url.\n");
					} else {
						/* setup player */
						memset (&app.player, 0, sizeof (app.player));

						WaitressInit (&app.player.waith);
						WaitressSetUrl (&app.player.waith, app.playlist->audioUrl);

						/* set up global proxy, player is NULLed on songfinish */
						if (app.settings.proxy != NULL) {
							char tmpPath[2];
							WaitressSplitUrl (app.settings.proxy,
									app.player.waith.proxyHost,
									sizeof (app.player.waith.proxyHost),
									app.player.waith.proxyPort,
									sizeof (app.player.waith.proxyPort), tmpPath,
									sizeof (tmpPath));
						}

						app.player.gain = app.playlist->fileGain;
						app.player.audioFormat = app.playlist->audioFormat;
			
						/* throw event */
						BarUiStartEventCmd (&app.settings, "songstart",
								app.curStation, app.playlist, &app.player,
								PIANO_RET_OK, WAITRESS_RET_OK);

						/* prevent race condition, mode must _not_ be FREED if
						 * thread has been started */
						app.player.mode = PLAYER_STARTING;
						/* start player */
						pthread_create (&playerThread, NULL, BarPlayerThread,
								&app.player);
					} /* end if audioUrl == NULL */
				} /* end if playlist != NULL */
			} /* end if curStation != NULL */
		}

		/* select modifies its arguments => copy the set */
		memcpy (&readSetCopy, &readSet, sizeof (readSet));
		selectTimeout.tv_sec = 1;
		selectTimeout.tv_usec = 0;

		/* in the meantime: wait for user actions */
		if (select (maxFd, &readSetCopy, NULL, NULL, &selectTimeout) > 0) {
			FILE *curFd = NULL;

			if (FD_ISSET(selectFds[0], &readSetCopy)) {
				curFd = stdin;
			} else if (FD_ISSET(selectFds[1], &readSetCopy)) {
				curFd = ctlFd;
			}
			buf = fgetc (curFd);

			size_t i;
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (app.settings.keys[i] == buf) {
					static const BarKeyShortcutFunc_t idToF[] = {BarUiActHelp,
							BarUiActLoveSong, BarUiActBanSong,
							BarUiActAddMusic, BarUiActCreateStation,
							BarUiActDeleteStation, BarUiActExplain,
							BarUiActStationFromGenre, BarUiActHistory,
							BarUiActSongInfo, BarUiActAddSharedStation,
							BarUiActMoveSong, BarUiActSkipSong, BarUiActPause,
							BarUiActQuit, BarUiActRenameStation,
							BarUiActSelectStation, BarUiActTempBanSong,
							BarUiActPrintUpcoming, BarUiActSelectQuickMix,
							BarUiActDebug, BarUiActBookmark};
					idToF[i] (&app, curFd);
					break;
				}
			}
		}

		/* show time */
		if (app.player.mode >= PLAYER_SAMPLESIZE_INITIALIZED &&
				app.player.mode < PLAYER_FINISHED_PLAYBACK) {
			/* Ugly: songDuration is unsigned _long_ int! Lets hope this won't
			 * overflow */
			int songRemaining = (signed long int) (app.player.songDuration -
					app.player.songPlayed) / BAR_PLAYER_MS_TO_S_FACTOR;
			char pos = 0;
			if (songRemaining < 0) {
				/* Use plus sign if song is longer than expected */
				pos = 1;
				songRemaining = -songRemaining;
			}
			BarUiMsg (MSG_TIME, "%c%02i:%02i/%02i:%02i\r", (pos ? '+' : '-'),
					songRemaining / 60, songRemaining % 60,
					app.player.songDuration / BAR_PLAYER_MS_TO_S_FACTOR / 60,
					app.player.songDuration / BAR_PLAYER_MS_TO_S_FACTOR % 60);
		}
	}

	/* destroy everything (including the world...) */
	if (app.player.mode != PLAYER_FREED) {
		pthread_join (playerThread, NULL);
	}
	if (ctlFd != NULL) {
		fclose (ctlFd);
	}
	PianoDestroy (&app.ph);
	PianoDestroyPlaylist (app.songHistory);
	PianoDestroyPlaylist (app.playlist);
	ao_shutdown();
	BarSettingsDestroy (&app.settings);

	/* restore terminal attributes, zsh doesn't need this, bash does... */
	BarTermRestore (&termOrig);

	return 0;
}
Exemplo n.º 9
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano
 */
bool BarUiPianoCall (BarApp_t * const app, const PianoRequestType_t type,
		void * const data, PianoReturn_t * const pRet, CURLcode * const wRet) {
	PianoReturn_t pRetLocal = PIANO_RET_OK;
	CURLcode wRetLocal = CURLE_OK;
	bool ret = false;

	/* repeat as long as there are http requests to do */
	do {
		PianoRequest_t req = { .data = data, .responseData = NULL };

		pRetLocal = PianoRequest (&app->ph, &req, type);
		if (pRetLocal != PIANO_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n",
					PianoErrorToStr (pRetLocal));
			goto cleanup;
		}

		wRetLocal = BarPianoHttpRequest (app->http, &app->settings, &req);
		if (wRetLocal == CURLE_ABORTED_BY_CALLBACK) {
			BarUiMsg (&app->settings, MSG_NONE, "Interrupted.\n");
			goto cleanup;
		} else if (wRetLocal != CURLE_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n",
					curl_easy_strerror (wRetLocal));
			goto cleanup;
		}

		pRetLocal = PianoResponse (&app->ph, &req);
		if (pRetLocal != PIANO_RET_CONTINUE_REQUEST) {
			/* checking for request type avoids infinite loops */
			if (pRetLocal == PIANO_RET_P_INVALID_AUTH_TOKEN &&
					type != PIANO_REQUEST_LOGIN) {
				/* reauthenticate */
				PianoRequestDataLogin_t reqData;
				reqData.user = app->settings.username;
				reqData.password = app->settings.password;
				reqData.step = 0;

				BarUiMsg (&app->settings, MSG_NONE,
						"Reauthentication required... ");
				if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData,
						&pRetLocal, &wRetLocal)) {
					goto cleanup;
				} else {
					/* try again */
					pRetLocal = PIANO_RET_CONTINUE_REQUEST;
					BarUiMsg (&app->settings, MSG_INFO, "Trying again... ");
				}
			} else if (pRetLocal != PIANO_RET_OK) {
				BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n",
						PianoErrorToStr (pRetLocal));
				goto cleanup;
			} else {
				BarUiMsg (&app->settings, MSG_NONE, "Ok.\n");
				ret = true;
			}
		}

cleanup:
		/* persistent data is stored in req.data */
		free (req.responseData);
		PianoDestroyRequest (&req);
	} while (pRetLocal == PIANO_RET_CONTINUE_REQUEST);

	*pRet = pRetLocal;
	*wRet = wRetLocal;

	return ret;
}
Exemplo n.º 10
0
/*	start new player thread
 */
static void BarMainStartPlayback (BarApp_t *app, pthread_t *playerThread) {
	PianoReturn_t pRet;
	WaitressReturn_t wRet;

	/* is this an advertising track? */
	if (app->playlist->adToken != NULL) {
		PianoRequestDataGetAdMetadata_t adReqData;

		adReqData.token = app->playlist->adToken;
		adReqData.quality = app->settings.audioQuality;

		BarUiMsg (&app->settings, MSG_INFO, "Fetching ads with token %s... ",
				adReqData.token);
		BarUiPianoCall (app, PIANO_REQUEST_GET_AD_METADATA,
				&adReqData, &pRet, &wRet);

		/* got token? */
		if (adReqData.retTokenCount > 0) {
			PianoRequestDataRegisterAd_t regReqData;

			regReqData.token = adReqData.retToken;
			regReqData.tokenCount = adReqData.retTokenCount;
			regReqData.station = app->curStation;

			BarUiMsg (&app->settings, MSG_INFO, "Registering ad... ");
			BarUiPianoCall (app, PIANO_REQUEST_REGISTER_AD, &regReqData, &pRet,
					&wRet);

			// change the current song to the actual audio ad url
			app->playlist->audioUrl = adReqData.audioUrl;
			// you can configure to get silence instead of ads or you can choose
			// to hear the ads. The default is silence
			if (app->settings.silenceAds) {
				app->playlist->fileGain = -999;
				app->playlist->title = strdup("Audio Ad (Silenced)");
			} else {
				app->playlist->fileGain = adReqData.fileGain;
				app->playlist->title = strdup("Audio Ad");
			}
			app->playlist->audioFormat = adReqData.audioFormat;
			app->playlist->artist = strdup("advertiser");
			app->playlist->album = strdup("pianobar");

			/* delete */
			for (size_t i = 0; i < adReqData.retTokenCount; i++) {
				free (adReqData.retToken[i]);
			}
			free (adReqData.retToken);
		}
	}

	BarUiPrintSong (&app->settings, app->playlist, app->curStation->isQuickMix ?
			PianoFindStationById (app->ph.stations,
			app->playlist->stationId) : NULL);

	if (app->playlist->audioUrl == NULL) {
		BarUiMsg (&app->settings, MSG_ERR, "Invalid song url.\n");
	} else {
		/* setup player */
		memset (&app->player, 0, sizeof (app->player));

		WaitressInit (&app->player.waith);
		WaitressSetUrl (&app->player.waith, app->playlist->audioUrl);

		/* set up global proxy, player is NULLed on songfinish */
		if (app->settings.proxy != NULL) {
			WaitressSetProxy (&app->player.waith, app->settings.proxy);
		}

		app->player.gain = app->playlist->fileGain;
		app->player.scale = BarPlayerCalcScale (app->player.gain + app->settings.volume);
		app->player.audioFormat = app->playlist->audioFormat;
		app->player.settings = &app->settings;
		pthread_mutex_init (&app->player.pauseMutex, NULL);
		pthread_cond_init (&app->player.pauseCond, NULL);

		/* throw event */
		BarUiStartEventCmd (&app->settings, "songstart",
				app->curStation, app->playlist, &app->player, app->ph.stations,
				PIANO_RET_OK, WAITRESS_RET_OK);

		/* prevent race condition, mode must _not_ be FREED if
		 * thread has been started */
		app->player.mode = PLAYER_STARTING;
		/* start player */
		pthread_create (playerThread, NULL, BarPlayerThread,
				&app->player);
	}
}
Exemplo n.º 11
0
/*	browse genre stations and create shared station
 *	@param piano handle
 */
void BarStationFromGenre (PianoHandle_t *ph, WaitressHandle_t *waith, FILE *curFd) {
	PianoReturn_t pRet;
	WaitressReturn_t wRet;
	PianoGenreCategory_t *curCat;
	PianoGenre_t *curGenre;
	PianoRequestDataCreateStation_t reqData;
	int i;

	/* receive genre stations list if not yet available */
	if (ph->genreStations == NULL) {
		PianoReturn_t pRet;
		WaitressReturn_t wRet;

		BarUiMsg (MSG_INFO, "Receiving genre stations... ");
		if (!BarUiPianoCall (ph, PIANO_REQUEST_GET_GENRE_STATIONS, waith, NULL,
				&pRet, &wRet)) {
			return;
		}
	}

	/* print all available categories */
	curCat = ph->genreStations;
	i = 0;
	while (curCat != NULL) {
		BarUiMsg (MSG_LIST, "%2i) %s\n", i, curCat->name);
		i++;
		curCat = curCat->next;
	}
	/* select category or exit */
	BarUiMsg (MSG_QUESTION, "Select category: ");
	if (BarReadlineInt (&i, curFd) == 0) {
		return;
	}
	curCat = ph->genreStations;
	while (curCat != NULL && i > 0) {
		curCat = curCat->next;
		i--;
	}
	
	/* print all available stations */
	curGenre = curCat->genres;
	i = 0;
	while (curGenre != NULL) {
		BarUiMsg (MSG_LIST, "%2i) %s\n", i, curGenre->name);
		i++;
		curGenre = curGenre->next;
	}
	BarUiMsg (MSG_QUESTION, "Select genre: ");
	if (BarReadlineInt (&i, curFd) == 0) {
		return;
	}
	curGenre = curCat->genres;
	while (curGenre != NULL && i > 0) {
		curGenre = curGenre->next;
		i--;
	}
	/* create station */
	BarUiMsg (MSG_INFO, "Adding shared station \"%s\"... ", curGenre->name);
	reqData.id = curGenre->musicId;
	reqData.type = "mi";
	BarUiPianoCall (ph, PIANO_REQUEST_CREATE_STATION, waith, &reqData, &pRet,
			&wRet);
}
Exemplo n.º 12
0
/*	search music: query, search request, return music id
 *	@param piano handle
 *	@param read data from fd
 *	@param allow seed suggestions if != NULL
 *	@return musicId or NULL on abort/error
 */
char *BarUiSelectMusicId (PianoHandle_t *ph, WaitressHandle_t *waith,
		FILE *curFd, char *similarToId) {
	char *musicId = NULL;
	char lineBuf[100], selectBuf[2];
	PianoSearchResult_t searchResult;
	PianoArtist_t *tmpArtist;
	PianoSong_t *tmpSong;

	BarUiMsg (MSG_QUESTION, "Search for artist/title: ");
	if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0, curFd) > 0) {
		if (strcmp ("?", lineBuf) == 0 && similarToId != NULL) {
			PianoReturn_t pRet;
			WaitressReturn_t wRet;
			PianoRequestDataGetSeedSuggestions_t reqData;

			reqData.musicId = similarToId;
			reqData.max = 20;

			BarUiMsg (MSG_INFO, "Receiving suggestions... ");
			if (!BarUiPianoCall (ph, PIANO_REQUEST_GET_SEED_SUGGESTIONS,
					waith, &reqData, &pRet, &wRet)) {
				return NULL;
			}
			memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult));
		} else {
			PianoReturn_t pRet;
			WaitressReturn_t wRet;
			PianoRequestDataSearch_t reqData;

			reqData.searchStr = lineBuf;

			BarUiMsg (MSG_INFO, "Searching... ");
			if (!BarUiPianoCall (ph, PIANO_REQUEST_SEARCH, waith, &reqData,
					&pRet, &wRet)) {
				return NULL;
			}
			memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult));
		}
		BarUiMsg (MSG_NONE, "\r");
		if (searchResult.songs != NULL &&
				searchResult.artists != NULL) {
			/* songs and artists found */
			BarUiMsg (MSG_QUESTION, "Is this an [a]rtist or [t]rack name? ");
			BarReadline (selectBuf, sizeof (selectBuf), "at", 1, 0, curFd);
			if (*selectBuf == 'a') {
				tmpArtist = BarUiSelectArtist (searchResult.artists, curFd);
				if (tmpArtist != NULL) {
					musicId = strdup (tmpArtist->musicId);
				}
			} else if (*selectBuf == 't') {
				tmpSong = BarUiSelectSong (searchResult.songs, curFd);
				if (tmpSong != NULL) {
					musicId = strdup (tmpSong->musicId);
				}
			}
		} else if (searchResult.songs != NULL) {
			/* songs found */
			tmpSong = BarUiSelectSong (searchResult.songs, curFd);
			if (tmpSong != NULL) {
				musicId = strdup (tmpSong->musicId);
			}
		} else if (searchResult.artists != NULL) {
			/* artists found */
			tmpArtist = BarUiSelectArtist (searchResult.artists, curFd);
			if (tmpArtist != NULL) {
				musicId = strdup (tmpArtist->musicId);
			}
		} else {
			BarUiMsg (MSG_INFO, "Nothing found...\n");
		}
		PianoDestroySearchResult (&searchResult);
	}

	return musicId;
}