Skip to content
28 changes: 23 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ LIBDIR:=${PREFIX}/lib
INCDIR:=${PREFIX}/include
MANDIR:=${PREFIX}/share/man
DYNLINK:=0
CFLAGS?=-O2 -DNDEBUG

ifeq ($(MAKECMDGOALS),debug)
CFLAGS?=-O0 -g -DDEBUG
else
CFLAGS?=-O2 -DNDEBUG
endif

ifeq (${CC},cc)
OS := $(shell uname)
Expand Down Expand Up @@ -41,13 +46,18 @@ LIBPIANO_SRC:=\
${LIBPIANO_DIR}/piano.c \
${LIBPIANO_DIR}/request.c \
${LIBPIANO_DIR}/response.c \
${LIBPIANO_DIR}/list.c
${LIBPIANO_DIR}/list.c \
${LIBPIANO_DIR}/debug_log.c
LIBPIANO_OBJ:=${LIBPIANO_SRC:.c=.o}
LIBPIANO_RELOBJ:=${LIBPIANO_SRC:.c=.lo}
LIBPIANO_INCLUDE:=${LIBPIANO_DIR}

LIBAV_CFLAGS:=$(shell $(PKG_CONFIG) --cflags libavcodec libavformat libavutil libavfilter)
LIBAV_LDFLAGS:=$(shell $(PKG_CONFIG) --libs libavcodec libavformat libavutil libavfilter)
ifneq (${LIBAV},)
PKG_CONFIG_LIBDIR=PKG_CONFIG_LIBDIR=${LIBAV}/lib/pkgconfig
endif

LIBAV_CFLAGS:=$(shell ${PKG_CONFIG_LIBDIR} $(PKG_CONFIG) --cflags libavcodec libavformat libavutil libavfilter)
LIBAV_LDFLAGS:=$(shell ${PKG_CONFIG_LIBDIR} $(PKG_CONFIG) --libs libavcodec libavformat libavutil libavfilter)

LIBCURL_CFLAGS:=$(shell $(PKG_CONFIG) --cflags libcurl)
LIBCURL_LDFLAGS:=$(shell $(PKG_CONFIG) --libs libcurl)
Expand Down Expand Up @@ -122,6 +132,8 @@ clean:

all: pianobar

debug: pianobar

ifeq (${DYNLINK},1)
install: pianobar install-libpiano
else
Expand Down Expand Up @@ -150,4 +162,10 @@ uninstall:
${DESTDIR}/${LIBDIR}/libpiano.a \
${DESTDIR}/${INCDIR}/piano.h

.PHONY: install install-libpiano uninstall test debug all
.PHONY: install install-libpiano uninstall test debug all make_debug

make_debug:
@echo "LIBAV: '${LIBAV}'"
@echo "PKG_CONFIG_LIBDIR: '${PKG_CONFIG_LIBDIR}'"
@echo "LIBAV_CFLAGS: '${LIBAV_CFLAGS}'"
@echo "LIBAV_LDFLAGS: '${LIBAV_LDFLAGS}'"
1 change: 1 addition & 0 deletions src/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ THE SOFTWARE.

#include "config.h"
#include <stdbool.h>
#include "debug_log.h"

#ifdef HAVE_DEBUGLOG
#include <stdio.h>
Expand Down
30 changes: 30 additions & 0 deletions src/libpiano/debug_log.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <stdio.h>
#include <ctype.h>
#include <assert.h>

#include "debug_log.h"

static ErrMsgCallback_t gPianoPrintErrMsgCB;

void PianoRegisterErrMsgCallback(ErrMsgCallback_t Arg)
{
gPianoPrintErrMsgCB = Arg;
}

void PianoPrintErrMsg(const char *format, ...)
{
va_list fmtargs;

assert (format != NULL);
va_start (fmtargs, format);

if(gPianoPrintErrMsgCB != NULL) {
gPianoPrintErrMsgCB(format,fmtargs);
}
else {
va_start (fmtargs, format);
vprintf (format, fmtargs);
va_end (fmtargs);
}
}

21 changes: 21 additions & 0 deletions src/libpiano/debug_log.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _DEBUG_LOG_H_
#define _DEBUG_LOG_H_
#include <stdarg.h>

typedef void (*ErrMsgCallback_t) (const char *fmt,va_list fmtargs);
// typedef void (ErrMsgCallback_t) (const char *format);

void PianoRegisterErrMsgCallback(ErrMsgCallback_t);
void PianoPrintErrMsg(const char *format,...) __attribute__((format(printf, 1, 2)));

#define ELOG(format, ... ) PianoPrintErrMsg("%s#%d: " format, __FUNCTION__,__LINE__,## __VA_ARGS__)
#ifdef DEBUG
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
#else
#define LOG(format, ... )
#define LOG_RAW(format, ... )
#endif

#endif

60 changes: 51 additions & 9 deletions src/libpiano/piano.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,32 @@ typedef struct PianoListHead {
typedef struct PianoUserInfo {
char *listenerId;
char *authToken;
bool IsSubscriber;
bool IsPremiumUser;
int PlayListCount;
int StationCount;
int AlbumCount;
int TrackCount;
int PodcastCount;
} PianoUserInfo_t;

typedef struct PianoStation {
PianoListHead_t head;
char isCreator;
char isQuickMix;
char useQuickMix; /* station will be included in quickmix */
char *name;
char *id;
char *seedId;
} PianoStation_t;
typedef enum {
PIANO_TYPE_NONE = 0,
PIANO_TYPE_STATION = 1,
PIANO_TYPE_PODCAST = 2,
PIANO_TYPE_PLAYLIST = 3,
PIANO_TYPE_ALBUM = 4,
PIANO_TYPE_TRACK = 5,
PIANO_TYPE_LAST
} PianoStationType_t;

typedef enum {
PIANO_MODE_STATION = 0,
PIANO_MODE_PODCAST = 1,
PIANO_MODE_PLAYLIST = 2,
PIANO_MODE_ALBUM = 3,
PIANO_MODE_ALL = 4
} PianoMode_t;

typedef enum {
PIANO_RATE_NONE = 0,
Expand Down Expand Up @@ -100,8 +115,27 @@ typedef struct PianoSong {
unsigned int length; /* song length in seconds */
PianoSongRating_t rating;
PianoAudioFormat_t audioFormat;
unsigned int releaseDate;
} PianoSong_t;

typedef struct PianoStation {
PianoListHead_t head;
char isCreator;
char isQuickMix;
char useQuickMix; /* station will be included in quickmix */
char *name;
char *id;
char *seedId;
PianoStationType_t stationType;
PianoSong_t *theSong;
} PianoStation_t;

typedef struct {
PianoStation_t *station;
PianoSong_t *playList;
bool bGetAll;
} PianoRequestDataGetEpisodes_t;

/* currently only used for search results */
typedef struct PianoArtist {
PianoListHead_t head;
Expand Down Expand Up @@ -188,6 +222,14 @@ typedef enum {
PIANO_REQUEST_CHANGE_SETTINGS = 24,
PIANO_REQUEST_GET_STATION_MODES = 25,
PIANO_REQUEST_SET_STATION_MODE = 26,
PIANO_REQUEST_GET_PLAYLISTS = 27,
PIANO_REQUEST_GET_TRACKS = 28,
PIANO_REQUEST_GET_PLAYBACK_INFO = 29,
PIANO_REQUEST_GET_ITEMS = 30,
PIANO_REQUEST_GET_USER_PROFILE = 31,
PIANO_REQUEST_ANNOTATE_OBJECTS = 32,
PIANO_REQUEST_REMOVE_ITEM = 33,
PIANO_REQUEST_GET_EPISODES = 34,
} PianoRequestType_t;

typedef struct PianoRequest {
Expand Down
8 changes: 8 additions & 0 deletions src/libpiano/piano_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ THE SOFTWARE.

#include "piano.h"

#ifdef DEBUG
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
#else
#define LOG(format, ... )
#define LOG_RAW(format, ... )
#endif

void PianoDestroyStation (PianoStation_t *station);
void PianoDestroyUserInfo (PianoUserInfo_t *user);

153 changes: 152 additions & 1 deletion src/libpiano/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ THE SOFTWARE.
#include <string.h>

#include "piano.h"
#include "piano_private.h"
#include "crypt.h"
#include "debug.h"

/* prepare piano request (initializes request type, urlpath and postData)
* @param piano handle
Expand Down Expand Up @@ -95,6 +97,8 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req,
json_object_new_string (ph->partner.authToken));
json_object_object_add (j, "syncTime",
json_object_new_int (timestamp));
json_object_object_add (j, "returnIsSubscriber",
json_object_new_boolean (true));

CURL * const curl = curl_easy_init ();
urlencAuthToken = curl_easy_escape (curl,
Expand Down Expand Up @@ -501,8 +505,155 @@ PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req,
goto cleanup;
break;
}
}
case PIANO_REQUEST_GET_PLAYLISTS: {
/* get stations, user must be authenticated */
assert (ph->user.listenerId != NULL);
req->secure = true;
json_object *a = json_object_new_object ();
json_object_object_add(a,"listenerId",json_object_new_string(ph->user.listenerId));
json_object_object_add(a,"offset",json_object_new_int(0));
json_object_object_add(a,"limit",json_object_new_int(100));
json_object_object_add(a,"annotationLimit",json_object_new_int(100));
json_object_object_add(j,"request",a);
method = "collections.v7.getSortedPlaylists";
break;
}

case PIANO_REQUEST_GET_TRACKS: {
assert (ph->user.listenerId != NULL);
PianoRequestDataGetPlaylist_t *reqData = req->data;

assert (reqData != NULL);
assert (reqData->station != NULL);
assert (reqData->station->id != NULL);

req->secure = true;
switch(reqData->station->stationType) {
case PIANO_TYPE_PLAYLIST: {
json_object *a = json_object_new_object ();
json_object_object_add(a,"pandoraId",json_object_new_string(reqData->station->id));
json_object_object_add(a,"limit",json_object_new_int(100));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We’d probably need a very large number here or some kind of pagingation aka PIANO_RET_CONTINUE_REQUEST.

json_object_object_add(a,"annotationLimit",json_object_new_int(100));
json_object_object_add(a,"bypassPrivacyRu1les",json_object_new_boolean(true));
json_object_object_add(j,"request",a);
method = "playlists.v7.getTracks";
break;
}

case PIANO_TYPE_ALBUM: {
json_object *a = json_object_new_array();
json_object_array_add(a,json_object_new_string(reqData->station->id));
json_object_object_add(j,"pandoraIds",a);
json_object_object_add(j,"annotateAlbumTracks",json_object_new_boolean(true));
method = "catalog.v4.annotateObjects";
break;
}

default:
LOG("Invalid stationType 0x%x\n",ph->stations->stationType);
break;
}
break;
}

case PIANO_REQUEST_GET_PLAYBACK_INFO: {
PianoRequestDataGetPlaylist_t *reqData = req->data;

assert (reqData != NULL);
assert (reqData->station != NULL);
assert (reqData->station->id != NULL);
assert (reqData->station->stationType != PIANO_TYPE_STATION);

req->secure = true;
json_object_object_add (j, "pandoraId",
json_object_new_string (reqData->retPlaylist->trackToken));
json_object_object_add (j, "sourcePandoraId",
json_object_new_string (reqData->retPlaylist->seedId));
json_object_object_add (j, "includeAudioToken",
json_object_new_boolean (true));
json_object_object_add (j, "deviceCode",json_object_new_string (""));
method = "onDemand.getAudioPlaybackInfo";
break;
}

case PIANO_REQUEST_GET_USER_PROFILE: {
req->secure = true;
json_object *a = json_object_new_object ();
json_object_object_add(a,"limit",json_object_new_int(10));
json_object_object_add(a,"annotationLimit",json_object_new_int(10));
json_object_object_add(a,"profileOwner",
json_object_new_string(ph->user.listenerId));
json_object_object_add(j,"request",a);
method = "profile.v1.getFullProfile";
break;
}

case PIANO_REQUEST_GET_ITEMS: {
req->secure = true;

json_object *a = json_object_new_object ();
json_object_object_add(j,"request",a);
#if 0
// test ability to continue after hitting limit
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we also need a continue return value here?

json_object_object_add(a,"limit",json_object_new_int(4));
json_object_object_add(a,"cursor",json_object_new_string("g6FjzwAFdTr1OqMYoXbAoXSWokFSolRSolBMolBDokFMolBF"));
#endif
method = "collections.v7.getItems";
break;
}

case PIANO_REQUEST_ANNOTATE_OBJECTS: {
json_object *a = json_object_new_array();
PianoStation_t *station = ph->stations;
req->secure = true;

while(station != NULL) {
assert(station->id != NULL);
if(station->name == NULL) {
switch(station->stationType) {
case PIANO_TYPE_PODCAST:
case PIANO_TYPE_ALBUM:
case PIANO_TYPE_TRACK:
json_object_array_add(a,json_object_new_string(station->id));
break;
}
}
station = (PianoStation_t *) station->head.next;
}
json_object_object_add(j,"pandoraIds",a);
json_object_object_add(j,"annotateAlbumTracks",
json_object_new_boolean(false));
method = "catalog.v4.annotateObjects";
break;
}

case PIANO_REQUEST_REMOVE_ITEM: {
/* delete item */
PianoStation_t *station = req->data;
assert (station != NULL);

req->secure = true;
json_object *a = json_object_new_object ();
json_object_object_add(a,"pandoraId",json_object_new_string(station->id));
json_object_object_add(j,"request",a);
method = "collections.v7.removeItem";
break;
}

case PIANO_REQUEST_GET_EPISODES: {
PianoRequestDataGetEpisodes_t *reqData = req->data;
PianoStation_t *station = reqData->station;
assert (station != NULL);

req->secure = true;
json_object_object_add(j,"annotationLimit",json_object_new_int(20));
json_object_object_add(j,"catalogVersion",json_object_new_int(4));
json_object_object_add(j,"pandoraId",json_object_new_string(station->id));
json_object_object_add(j,"sortingOrder",json_object_new_string(""));
method = "aesop.v1.getDetails";
break;
}
}
/* standard parameter */
if (method != NULL) {
char *urlencAuthToken;
Expand Down
Loading