diff options
| -rw-r--r-- | src/libpiano/piano.c | 69 | ||||
| -rw-r--r-- | src/libpiano/piano.h | 16 | ||||
| -rw-r--r-- | src/libpiano/xml.c | 194 | ||||
| -rw-r--r-- | src/libpiano/xml.h | 1 | 
4 files changed, 227 insertions, 53 deletions
| diff --git a/src/libpiano/piano.c b/src/libpiano/piano.c index a53c102..e475799 100644 --- a/src/libpiano/piano.c +++ b/src/libpiano/piano.c @@ -57,32 +57,29 @@ void PianoInit (PianoHandle_t *ph) {  			(unsigned long) time (NULL) % 10000000);  } -/*	free complete search result - *	@public yes - *	@param search result +/*	destroy artist linked list   */ -void PianoDestroySearchResult (PianoSearchResult_t *searchResult) { +void PianoDestroyArtists (PianoArtist_t *artists) {  	PianoArtist_t *curArtist, *lastArtist; -	PianoSong_t *curSong, *lastSong; -	curArtist = searchResult->artists; +	curArtist = artists;  	while (curArtist != NULL) {  		free (curArtist->name);  		free (curArtist->musicId); +		free (curArtist->seedId);  		lastArtist = curArtist;  		curArtist = curArtist->next;  		free (lastArtist);  	} +} -	curSong = searchResult->songs; -	while (curSong != NULL) { -		free (curSong->title); -		free (curSong->artist); -		free (curSong->musicId); -		lastSong = curSong; -		curSong = curSong->next; -		free (lastSong); -	} +/*	free complete search result + *	@public yes + *	@param search result + */ +void PianoDestroySearchResult (PianoSearchResult_t *searchResult) { +	PianoDestroyArtists (searchResult->artists); +	PianoDestroyPlaylist (searchResult->songs);  }  /*	free single station @@ -128,12 +125,20 @@ void PianoDestroyPlaylist (PianoSong_t *playlist) {  		free (curSong->stationId);  		free (curSong->album);  		free (curSong->artistMusicId); +		free (curSong->feedbackId); +		free (curSong->seedId);  		lastSong = curSong;  		curSong = curSong->next;  		free (lastSong);  	}  } +void PianoDestroyStationInfo (PianoStationInfo_t *info) { +	PianoDestroyPlaylist (info->feedback); +	PianoDestroyPlaylist (info->songSeeds); +	PianoDestroyArtists (info->artistSeeds); +} +  /*	destroy genre linked list   */  void PianoDestroyGenres (PianoGenre_t *genres) { @@ -708,6 +713,28 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req,  			break;  		} +		case PIANO_REQUEST_GET_STATION_INFO: { +			/* get station information (seeds and feedback) */ +			PianoRequestDataGetStationInfo_t *reqData = req->data; + +			assert (reqData != NULL); +			assert (reqData->station != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.getStation</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->station->id); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=getStation&arg1=%s", +					ph->routeId, ph->user.listenerId, reqData->station->id); +			break; +		} +  		/* "high-level" wrapper */  		case PIANO_REQUEST_RATE_SONG: {  			/* love/ban song */ @@ -1029,6 +1056,18 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  					&reqData->searchResult);  			break;  		} + +		case PIANO_REQUEST_GET_STATION_INFO: { +			/* get station information (seeds and feedback) */ +			PianoRequestDataGetStationInfo_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); + +			ret = PianoXmlParseGetStationInfo (req->responseData, +					&reqData->info); +			break; +		}  	}  	return ret; diff --git a/src/libpiano/piano.h b/src/libpiano/piano.h index 509be9e..c91b7e9 100644 --- a/src/libpiano/piano.h +++ b/src/libpiano/piano.h @@ -71,6 +71,8 @@ typedef struct PianoSong {  	char *coverArt;  	char *musicId;  	char *title; +	char *seedId; +	char *feedbackId;  	float fileGain;  	PianoSongRating_t rating;  	PianoAudioFormat_t audioFormat; @@ -83,6 +85,7 @@ typedef struct PianoSong {  typedef struct PianoArtist {  	char *name;  	char *musicId; +	char *seedId;  	int score;  	struct PianoArtist *next;  } PianoArtist_t; @@ -113,6 +116,12 @@ typedef struct PianoSearchResult {  	PianoArtist_t *artists;  } PianoSearchResult_t; +typedef struct { +	PianoSong_t *songSeeds; +	PianoArtist_t *artistSeeds; +	PianoSong_t *feedback; +} PianoStationInfo_t; +  typedef enum {  	/* 0 is reserved: memset (x, 0, sizeof (x)) */  	PIANO_REQUEST_LOGIN = 1, @@ -134,6 +143,7 @@ typedef enum {  	PIANO_REQUEST_GET_SEED_SUGGESTIONS = 17,  	PIANO_REQUEST_BOOKMARK_SONG = 18,  	PIANO_REQUEST_BOOKMARK_ARTIST = 19, +	PIANO_REQUEST_GET_STATION_INFO = 20,  } PianoRequestType_t;  typedef struct PianoRequest { @@ -209,6 +219,11 @@ typedef struct {  	PianoSearchResult_t searchResult;  } PianoRequestDataGetSeedSuggestions_t; +typedef struct { +	PianoStation_t *station; +	PianoStationInfo_t info; +} PianoRequestDataGetStationInfo_t; +  typedef enum {  	PIANO_RET_ERR = 0,  	PIANO_RET_OK = 1, @@ -232,6 +247,7 @@ void PianoInit (PianoHandle_t *);  void PianoDestroy (PianoHandle_t *);  void PianoDestroyPlaylist (PianoSong_t *);  void PianoDestroySearchResult (PianoSearchResult_t *); +void PianoDestroyStationInfo (PianoStationInfo_t *);  PianoReturn_t PianoRequest (PianoHandle_t *, PianoRequest_t *,  		PianoRequestType_t); diff --git a/src/libpiano/xml.c b/src/libpiano/xml.c index 158eef2..19871c1 100644 --- a/src/libpiano/xml.c +++ b/src/libpiano/xml.c @@ -27,6 +27,7 @@ THE SOFTWARE.  #include <string.h>  #include <stdlib.h>  #include <ezxml.h> +#include <assert.h>  #include "piano.h"  #include "crypt.h" @@ -275,6 +276,12 @@ static void PianoXmlParsePlaylistCb (const char *key, const ezxml_t value,  		} else {  			song->rating = PIANO_RATE_NONE;  		} +	} else if (strcmp ("isPositive", key) == 0) { +		if (strcmp (valueStr, "1") == 0) { +			song->rating = PIANO_RATE_LOVE; +		} else { +			song->rating = PIANO_RATE_BAN; +		}  	} else if (strcmp ("stationId", key) == 0) {  		song->stationId = strdup (valueStr);  	} else if (strcmp ("albumTitle", key) == 0) { @@ -295,6 +302,8 @@ static void PianoXmlParsePlaylistCb (const char *key, const ezxml_t value,  		song->testStrategy = atoi (valueStr);  	} else if (strcmp ("songType", key) == 0) {  		song->songType = atoi (valueStr); +	} else if (strcmp ("feedbackId", key) == 0) { +		song->feedbackId = strdup (valueStr);  	}  } @@ -490,6 +499,32 @@ PianoReturn_t PianoXmlParseAddSeed (PianoHandle_t *ph, char *xml,  	return PIANO_RET_OK;  } +static PianoReturn_t PianoXmlParsePlaylistStruct (ezxml_t xml, +		PianoSong_t **retSong) { +	PianoSong_t *playlist = *retSong, *tmpSong; +	 +	if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { +		return PIANO_RET_OUT_OF_MEMORY; +	} + +	PianoXmlStructParser (ezxml_child (xml, "struct"), PianoXmlParsePlaylistCb, +			tmpSong); +	/* begin linked list or append */ +	if (playlist == NULL) { +		playlist = tmpSong; +	} else { +		PianoSong_t *curSong = playlist; +		while (curSong->next != NULL) { +			curSong = curSong->next; +		} +		curSong->next = tmpSong; +	} + +	*retSong = playlist; + +	return PIANO_RET_OK; +} +  /*	parses playlist; used when searching too   *	@param piano handle   *	@param xml document @@ -498,7 +533,7 @@ PianoReturn_t PianoXmlParseAddSeed (PianoHandle_t *ph, char *xml,  PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml,  		PianoSong_t **retPlaylist) {  	ezxml_t xmlDoc, dataNode; -	PianoReturn_t ret; +	PianoReturn_t ret = PIANO_RET_OK;  	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) {  		return ret; @@ -509,30 +544,15 @@ PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml,  	for (dataNode = ezxml_child (dataNode, "value"); dataNode;  			dataNode = dataNode->next) { -		PianoSong_t *tmpSong; -		 -		if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { -			ezxml_free (xmlDoc); -			return PIANO_RET_OUT_OF_MEMORY; -		} - -		PianoXmlStructParser (ezxml_child (dataNode, "struct"), -				PianoXmlParsePlaylistCb, tmpSong); -		/* begin linked list or append */ -		if (*retPlaylist == NULL) { -			*retPlaylist = tmpSong; -		} else { -			PianoSong_t *curSong = *retPlaylist; -			while (curSong->next != NULL) { -				curSong = curSong->next; -			} -			curSong->next = tmpSong; +		if ((ret = PianoXmlParsePlaylistStruct (dataNode, retPlaylist)) != +				PIANO_RET_OK) { +			break;  		}  	}  	ezxml_free (xmlDoc); -	return PIANO_RET_OK; +	return ret;  }  /*	parse simple answers like this: <?xml version="1.0" encoding="UTF-8"?> @@ -614,26 +634,10 @@ static void PianoXmlParseSearchCb (const char *key, const ezxml_t value,  	} else if (strcmp ("songs", key) == 0) {  		for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value");  				curNode; curNode = curNode->next) { -			/* FIXME: copy & waste */ -			PianoSong_t *tmpSong; -			 -			if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { -				/* fail silently */ +			if (PianoXmlParsePlaylistStruct (curNode, &searchResult->songs) != +					PIANO_RET_OK) {  				break;  			} - -			PianoXmlStructParser (ezxml_child (curNode, "struct"), -					PianoXmlParsePlaylistCb, tmpSong); -			/* begin linked list or append */ -			if (searchResult->songs == NULL) { -				searchResult->songs = tmpSong; -			} else { -				PianoSong_t *curSong = searchResult->songs; -				while (curSong->next != NULL) { -					curSong = curSong->next; -				} -				curSong->next = tmpSong; -			}  		}  	}  } @@ -824,3 +828,117 @@ PianoReturn_t PianoXmlParseNarrative (char *xml, char **retNarrative) {  	return ret;  } +/*	seed bag, required because seedId is not part of artist/song struct in + *	pandora's xml response + */ +struct PianoXmlParseSeedBag { +	char *seedId; +	PianoSong_t *song; +	PianoArtist_t *artist; +}; + +/*	parse seed struct + */ +static void PianoXmlParseSeedCb (const char *key, const ezxml_t value, +		void *data) { +	struct PianoXmlParseSeedBag *bag = data; + +	if (strcmp ("song", key) == 0) { +		if ((bag->song = calloc (1, sizeof (*bag->song))) == NULL) { +			return; +		} + +		PianoXmlStructParser (ezxml_child (value, "struct"), +				PianoXmlParsePlaylistCb, bag->song); +	} else if (strcmp ("artist", key) == 0) { +		if ((bag->artist = calloc (1, sizeof (*bag->artist))) == NULL) { +			return; +		} + +		PianoXmlStructParser (ezxml_child (value, "struct"), +				PianoXmlParseSearchArtistCb, bag->artist); +	} else if (strcmp ("seedId", key) == 0) { +		char *valueStr = PianoXmlGetNodeText (value); +		bag->seedId = strdup (valueStr); +	} +} + +/*	parse getStation xml struct + */ +static void PianoXmlParseGetStationInfoCb (const char *key, const ezxml_t value, +		void *data) { +	PianoStationInfo_t *info = data; + +	if (strcmp ("seeds", key) == 0) { +		const ezxml_t dataNode = ezxml_get (value, "array", 0, "data", -1); +		for (ezxml_t seedNode = ezxml_child (dataNode, "value"); seedNode; +					seedNode = seedNode->next) { +			struct PianoXmlParseSeedBag bag; +			memset (&bag, 0, sizeof (bag)); + +			PianoXmlStructParser (ezxml_child (seedNode, "struct"), +					PianoXmlParseSeedCb, &bag); + +			/* FIXME: use if-clause */ +			assert (bag.seedId != NULL); +			assert (bag.song != NULL || bag.artist != NULL); + +			if (bag.song != NULL) { +				bag.song->seedId = bag.seedId; + +				if (info->songSeeds == NULL) { +					info->songSeeds = bag.song; +				} else { +					PianoSong_t *curSong = info->songSeeds; +					while (curSong->next != NULL) { +						curSong = curSong->next; +					} +					curSong->next = bag.song; +				} +			} else if (bag.artist != NULL) { +				bag.artist->seedId = bag.seedId; + +				if (info->artistSeeds == NULL) { +					info->artistSeeds = bag.artist; +				} else { +					PianoArtist_t *curSong = info->artistSeeds; +					while (curSong->next != NULL) { +						curSong = curSong->next; +					} +					curSong->next = bag.artist; +				} +			} else { +				free (bag.seedId); +			} +		} +	} else if (strcmp ("feedback", key) == 0) { +		const ezxml_t dataNode = ezxml_get (value, "array", 0, "data", -1); +		for (ezxml_t feedbackNode = ezxml_child (dataNode, "value"); feedbackNode; +					feedbackNode = feedbackNode->next) { +			if (PianoXmlParsePlaylistStruct (feedbackNode, &info->feedback) != +					PIANO_RET_OK) { +				break; +			} +		} +	} +} + +/*	parse getStation response + */ +PianoReturn_t PianoXmlParseGetStationInfo (char *xml, +		PianoStationInfo_t *stationInfo) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} +	 +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); +	PianoXmlStructParser (dataNode, PianoXmlParseGetStationInfoCb, stationInfo); + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + diff --git a/src/libpiano/xml.h b/src/libpiano/xml.h index f21c765..c5f3988 100644 --- a/src/libpiano/xml.h +++ b/src/libpiano/xml.h @@ -42,6 +42,7 @@ PianoReturn_t PianoXmlParseGenreExplorer (PianoHandle_t *ph,  PianoReturn_t PianoXmlParseTranformStation (const char *searchXml);  PianoReturn_t PianoXmlParseNarrative (const char *xml, char **retNarrative);  PianoReturn_t PianoXmlParseSeedSuggestions (char *, PianoSearchResult_t *); +PianoReturn_t PianoXmlParseGetStationInfo (char *, PianoStationInfo_t *);  char *PianoXmlEncodeString (const char *s); | 
