[spotify] Introduce own spotifyc as replacement for libspotify

This commit is contained in:
ejurgensen 2021-03-28 20:00:15 +02:00
parent d3cc8a52f8
commit a67c74ba6c
54 changed files with 18680 additions and 104 deletions

View File

@ -286,19 +286,22 @@ AS_IF([[test "x$with_avahi" = "xno"]],
[AC_MSG_ERROR([[Avahi client or Bonjour DNS_SD required, please install one.]])])]) [AC_MSG_ERROR([[Avahi client or Bonjour DNS_SD required, please install one.]])])])
AM_CONDITIONAL([COND_AVAHI], [[test "x$with_avahi" = "xyes"]]) AM_CONDITIONAL([COND_AVAHI], [[test "x$with_avahi" = "xyes"]])
dnl Spotify with dynamic linking to libspotify dnl Spotify support
OWNTONE_ARG_ENABLE([Spotify support], [spotify], [SPOTIFY], OWNTONE_ARG_ENABLE([Spotify support], [spotify], [SPOTIFY],
[AS_IF([[test "x$with_libevent_pthreads" = "xno"]], [AS_IF([[test "x$with_libevent_pthreads" = "xno"]],
[AC_MSG_ERROR([[Spotify support requires libevent_pthreads]])]) [AC_MSG_ERROR([[Spotify support requires libevent_pthreads]])])
OWNTONE_MODULES_CHECK([SPOTIFY], [LIBSPOTIFY], [libspotify], OWNTONE_MODULES_CHECK([OWNTONE_OPTS], [LIBPROTOBUF_C],
[], [libspotify/api.h]) [libprotobuf-c >= 1.0.0], [protobuf_c_message_pack],
AC_DEFINE([HAVE_SPOTIFY_H], 1, [protobuf-c/protobuf-c.h], [],
[Define to 1 if you have the <libspotify/api.h> header file.]) [OWNTONE_FUNC_REQUIRE([OWNTONE_OPTS], [v0 libprotobuf-c],
dnl Don't link with libspotify, use dynamic linking [LIBPROTOBUF_OLD], [protobuf-c],
AC_SEARCH_LIBS([dlopen], [dl], [], [protobuf_c_message_pack],
[AC_MSG_ERROR([[Spotify support requires dlopen]])]) [google/protobuf-c/protobuf-c.h],
OWNTONE_VAR_PREPEND([OWNTONE_OPTS_CPPFLAGS], [$SPOTIFY_CPPFLAGS]) [AC_DEFINE([HAVE_PROTOBUF_OLD], 1,
OWNTONE_VAR_PREPEND([OWNTONE_OPTS_LIBS], [-rdynamic]) [Define to 1 if you have libprotobuf < 1.0.0])
[protobuf_old=yes]],
[AC_MSG_ERROR([[Spotify support requires protobuf-c]])])
])
]) ])
AM_CONDITIONAL([COND_SPOTIFY], [[test "x$enable_spotify" = "xyes"]]) AM_CONDITIONAL([COND_SPOTIFY], [[test "x$enable_spotify" = "xyes"]])

View File

@ -2,7 +2,16 @@
sbin_PROGRAMS = owntone sbin_PROGRAMS = owntone
if COND_SPOTIFY if COND_SPOTIFY
SPOTIFY_SRC=spotify.c spotify.h spotify_webapi.c spotify_webapi.h inputs/spotify.c SPOTIFY_SRC = \
library/spotify_webapi.c library/spotify_webapi.h \
inputs/spotify.c inputs/spotify.h \
inputs/spotifyc/spotifyc.c inputs/spotifyc/spotifyc.h \
inputs/spotifyc/shannon/ShannonFast.c \
inputs/spotifyc/shannon/ShannonInternal.h inputs/spotifyc/shannon/Shannon.h \
inputs/spotifyc/proto/keyexchange.pb-c.c inputs/spotifyc/proto/keyexchange.pb-c.h \
inputs/spotifyc/proto/authentication.pb-c.c inputs/spotifyc/proto/authentication.pb-c.h \
inputs/spotifyc/proto/mercury.pb-c.c inputs/spotifyc/proto/mercury.pb-c.h \
inputs/spotifyc/proto/metadata.pb-c.c inputs/spotifyc/proto/metadata.pb-c.h
endif endif
if COND_LASTFM if COND_LASTFM

View File

@ -45,8 +45,8 @@
#include "artwork.h" #include "artwork.h"
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
# include "spotify_webapi.h" # include "library/spotify_webapi.h"
#endif #endif
/* This artwork module will look for artwork by consulting a set of sources one /* This artwork module will look for artwork by consulting a set of sources one
@ -1608,7 +1608,7 @@ source_item_coverartarchive_get(struct artwork_ctx *ctx)
return ret; return ret;
} }
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
static int static int
source_item_spotifywebapi_track_get(struct artwork_ctx *ctx) source_item_spotifywebapi_track_get(struct artwork_ctx *ctx)
{ {

View File

@ -55,9 +55,9 @@
#include "remote_pairing.h" #include "remote_pairing.h"
#include "settings.h" #include "settings.h"
#include "smartpl_query.h" #include "smartpl_query.h"
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
# include "spotify_webapi.h" # include "library/spotify_webapi.h"
# include "spotify.h" # include "inputs/spotify.h"
#endif #endif
@ -1201,11 +1201,11 @@ jsonapi_reply_spotify(struct httpd_request *hreq)
CHECK_NULL(L_WEB, jreply = json_object_new_object()); CHECK_NULL(L_WEB, jreply = json_object_new_object());
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
int httpd_port; int httpd_port;
char redirect_uri[256]; char redirect_uri[256];
char *oauth_uri; char *oauth_uri;
struct spotify_status_info info; struct spotify_status sp_status;
struct spotifywebapi_status_info webapi_info; struct spotifywebapi_status_info webapi_info;
struct spotifywebapi_access_token webapi_token; struct spotifywebapi_access_token webapi_token;
@ -1225,10 +1225,10 @@ jsonapi_reply_spotify(struct httpd_request *hreq)
json_object_object_add(jreply, "oauth_uri", json_object_new_string(oauth_uri)); json_object_object_add(jreply, "oauth_uri", json_object_new_string(oauth_uri));
free(oauth_uri); free(oauth_uri);
spotify_status_info_get(&info); spotify_status_get(&sp_status);
json_object_object_add(jreply, "libspotify_installed", json_object_new_boolean(info.libspotify_installed)); json_object_object_add(jreply, "libspotify_installed", json_object_new_boolean(sp_status.installed));
json_object_object_add(jreply, "libspotify_logged_in", json_object_new_boolean(info.libspotify_logged_in)); json_object_object_add(jreply, "libspotify_logged_in", json_object_new_boolean(sp_status.logged_in));
safe_json_add_string(jreply, "libspotify_user", info.libspotify_user); safe_json_add_string(jreply, "libspotify_user", sp_status.username);
spotifywebapi_status_info_get(&webapi_info); spotifywebapi_status_info_get(&webapi_info);
json_object_object_add(jreply, "webapi_token_valid", json_object_new_boolean(webapi_info.token_valid)); json_object_object_add(jreply, "webapi_token_valid", json_object_new_boolean(webapi_info.token_valid));
@ -1255,12 +1255,12 @@ jsonapi_reply_spotify(struct httpd_request *hreq)
static int static int
jsonapi_reply_spotify_login(struct httpd_request *hreq) jsonapi_reply_spotify_login(struct httpd_request *hreq)
{ {
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
struct evbuffer *in_evbuf; struct evbuffer *in_evbuf;
json_object* request; json_object* request;
const char *user; const char *user;
const char *password; const char *password;
char *errmsg = NULL; const char *errmsg;
json_object* jreply; json_object* jreply;
json_object* errors; json_object* errors;
int ret; int ret;
@ -1294,7 +1294,6 @@ jsonapi_reply_spotify_login(struct httpd_request *hreq)
{ {
json_object_object_add(jreply, "success", json_object_new_boolean(true)); json_object_object_add(jreply, "success", json_object_new_boolean(true));
} }
free(errmsg);
} }
else else
{ {
@ -1323,7 +1322,7 @@ jsonapi_reply_spotify_login(struct httpd_request *hreq)
static int static int
jsonapi_reply_spotify_logout(struct httpd_request *hreq) jsonapi_reply_spotify_logout(struct httpd_request *hreq)
{ {
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
spotify_logout(); spotify_logout();
#endif #endif
return HTTP_NOCONTENT; return HTTP_NOCONTENT;

View File

@ -32,14 +32,14 @@
#include "logger.h" #include "logger.h"
#include "misc.h" #include "misc.h"
#include "conffile.h" #include "conffile.h"
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
# include "spotify_webapi.h" # include "library/spotify_webapi.h"
#endif #endif
/* --------------------------- REPLY HANDLERS ------------------------------- */ /* --------------------------- REPLY HANDLERS ------------------------------- */
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
static int static int
oauth_reply_spotify(struct httpd_request *hreq) oauth_reply_spotify(struct httpd_request *hreq)
{ {

View File

@ -58,7 +58,7 @@ extern struct input_definition input_file;
extern struct input_definition input_http; extern struct input_definition input_http;
extern struct input_definition input_pipe; extern struct input_definition input_pipe;
extern struct input_definition input_timer; extern struct input_definition input_timer;
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
extern struct input_definition input_spotify; extern struct input_definition input_spotify;
#endif #endif
@ -68,7 +68,7 @@ static struct input_definition *inputs[] = {
&input_http, &input_http,
&input_pipe, &input_pipe,
&input_timer, &input_timer,
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
&input_spotify, &input_spotify,
#endif #endif
NULL NULL
@ -171,7 +171,7 @@ map_data_kind(int data_kind)
case DATA_KIND_PIPE: case DATA_KIND_PIPE:
return INPUT_TYPE_PIPE; return INPUT_TYPE_PIPE;
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
case DATA_KIND_SPOTIFY: case DATA_KIND_SPOTIFY:
return INPUT_TYPE_SPOTIFY; return INPUT_TYPE_SPOTIFY;
#endif #endif
@ -420,6 +420,7 @@ setup(struct input_source *source, struct db_queue_item *queue_item, int seek_ms
source->id = queue_item->file_id; source->id = queue_item->file_id;
source->len_ms = queue_item->song_length; source->len_ms = queue_item->song_length;
source->path = safe_strdup(queue_item->path); source->path = safe_strdup(queue_item->path);
source->evbase = evbase_input;
DPRINTF(E_DBG, L_PLAYER, "Setting up input item '%s' (item id %" PRIu32 ")\n", source->path, source->item_id); DPRINTF(E_DBG, L_PLAYER, "Setting up input item '%s' (item id %" PRIu32 ")\n", source->path, source->item_id);

View File

@ -16,7 +16,7 @@ enum input_types
INPUT_TYPE_HTTP, INPUT_TYPE_HTTP,
INPUT_TYPE_PIPE, INPUT_TYPE_PIPE,
INPUT_TYPE_TIMER, INPUT_TYPE_TIMER,
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
INPUT_TYPE_SPOTIFY, INPUT_TYPE_SPOTIFY,
#endif #endif
}; };
@ -62,6 +62,10 @@ struct input_source
// Opaque pointer to data that the input backend sets up when start() is // Opaque pointer to data that the input backend sets up when start() is
// called, and that is cleaned up by the backend when stop() is called // called, and that is cleaned up by the backend when stop() is called
void *input_ctx; void *input_ctx;
// The input's event base that the input backend can use for own events
struct event_base *evbase;
// Private evbuf. Alloc'ed by backend at start() and free'd at stop() // Private evbuf. Alloc'ed by backend at start() and free'd at stop()
struct evbuffer *evbuf; struct evbuffer *evbuf;
// Private source quality storage // Private source quality storage
@ -128,7 +132,7 @@ struct input_definition
/* ---------------------- Interface towards input backends ------------------ */ /* ---------------------- Interface towards input backends ------------------ */
/* Thread: input and spotify */ /* Thread: input */
/* /*
* Transfer stream data to the player's input buffer. Data must be PCM-LE * Transfer stream data to the player's input buffer. Data must be PCM-LE

View File

@ -1,6 +1,4 @@
/* /*
* Copyright (C) 2017 Espen Jurgensen
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -21,63 +19,512 @@
#include <unistd.h> #include <unistd.h>
#include <stdint.h> #include <stdint.h>
#include <event2/event.h>
#include "input.h" #include "input.h"
#include "misc.h"
#include "logger.h" #include "logger.h"
#include "http.h"
#include "db.h"
#include "transcode.h"
#include "spotify.h" #include "spotify.h"
#include "spotifyc/spotifyc.h"
// How many retries to start playback if resource is still loading #define SPOTIFY_PROBE_SIZE_MIN 65536
#define SPOTIFY_SETUP_RETRIES 5
// How long to wait between retries in microseconds (500000 = 0.5 seconds)
#define SPOTIFY_SETUP_RETRY_WAIT 500000
static int struct global_ctx
setup(struct input_source *source)
{ {
int i = 0; pthread_mutex_t lock;
int ret; pthread_cond_t cond;
while((ret = spotify_playback_setup(source->path)) == SPOTIFY_SETUP_ERROR_IS_LOADING) struct sp_session *session;
bool response_pending; // waiting for a response from spotifyc
struct spotify_status status;
};
struct playback_ctx
{
struct transcode_ctx *xcode;
int read_fd;
struct evbuffer *read_buf;
size_t read_bytes;
uint32_t len_ms;
};
static struct global_ctx spotify_ctx;
static bool db_is_initialized;
static struct media_quality spotify_quality = { 44100, 16, 2, 0 };
/* ------------------------------ Utility funcs ----------------------------- */
static void
hextobin(uint8_t *data, size_t data_len, const char *hexstr, size_t hexstr_len)
{
char hex[] = { 0, 0, 0 };
const char *ptr;
int i;
if (2 * data_len < hexstr_len)
{ {
if (i >= SPOTIFY_SETUP_RETRIES) memset(data, 0, data_len);
break; return;
DPRINTF(E_DBG, L_SPOTIFY, "Resource still loading (%d)\n", i);
usleep(SPOTIFY_SETUP_RETRY_WAIT);
i++;
} }
if (ret < 0) ptr = hexstr;
return -1; for (i = 0; i < data_len; i++, ptr+=2)
{
memcpy(hex, ptr, 2);
data[i] = strtol(hex, NULL, 16);
}
}
ret = spotify_playback_play();
if (ret < 0) /* -------------------- Callbacks from spotifyc thread ---------------------- */
return -1;
static void
got_reply(struct global_ctx *ctx)
{
pthread_mutex_lock(&ctx->lock);
ctx->response_pending = false;
pthread_cond_signal(&ctx->cond);
pthread_mutex_unlock(&ctx->lock);
}
static void
error_cb(void *cb_arg, int err, const char *errmsg)
{
struct global_ctx *ctx = cb_arg;
got_reply(ctx);
DPRINTF(E_LOG, L_SPOTIFY, "%s (error code %d)\n", errmsg, err);
}
static void
logged_in_cb(struct sp_session *session, void *cb_arg, struct sp_credentials *credentials)
{
struct global_ctx *ctx = cb_arg;
char *db_stored_cred;
char *ptr;
int ret;
int i;
if (!db_is_initialized)
{
ret = db_perthread_init();
if (ret < 0)
{
DPRINTF(E_LOG, L_SPOTIFY, "Error: DB init failed (spotify thread)\n");
return;
}
db_is_initialized = true;
}
DPRINTF(E_LOG, L_SPOTIFY, "Logged into Spotify succesfully\n");
if (!credentials->username || !credentials->stored_cred)
{
DPRINTF(E_LOG, L_SPOTIFY, "No credentials returned by Spotify, automatic login will not be possible\n");
return;
}
db_stored_cred = malloc(2 * credentials->stored_cred_len +1);
for (i = 0, ptr = db_stored_cred; i < credentials->stored_cred_len; i++)
ptr += sprintf(ptr, "%02x", credentials->stored_cred[i]);
db_admin_set("spotify_username", credentials->username);
db_admin_set("spotify_stored_cred", db_stored_cred);
free(db_stored_cred);
pthread_mutex_lock(&ctx->lock);
ctx->response_pending = false;
ctx->status.logged_in = true;
snprintf(ctx->status.username, sizeof(ctx->status.username), "%s", credentials->username);
pthread_cond_signal(&ctx->cond);
pthread_mutex_unlock(&ctx->lock);
}
static void
logged_out_cb(void *cb_arg)
{
db_admin_delete("spotify_username");
db_admin_delete("spotify_stored_cred");
if (db_is_initialized)
db_perthread_deinit();
db_is_initialized = false;
}
static void
track_opened_cb(struct sp_session *session, void *cb_arg, int fd)
{
struct global_ctx *ctx = cb_arg;
DPRINTF(E_DBG, L_SPOTIFY, "track_opened_cb()\n");
pthread_mutex_lock(&ctx->lock);
ctx->response_pending = false;
ctx->status.track_opened = true;
pthread_cond_signal(&ctx->cond);
pthread_mutex_unlock(&ctx->lock);
}
static void
track_closed_cb(struct sp_session *session, void *cb_arg, int fd)
{
struct global_ctx *ctx = cb_arg;
DPRINTF(E_DBG, L_SPOTIFY, "track_closed_cb()\n");
pthread_mutex_lock(&ctx->lock);
ctx->response_pending = false;
ctx->status.track_opened = false;
pthread_cond_signal(&ctx->cond);
pthread_mutex_unlock(&ctx->lock);
}
static int
https_get_cb(char **out, const char *url)
{
struct http_client_ctx ctx = { 0 };
char *body;
size_t len;
int ret;
ctx.url = url;
ctx.input_body = evbuffer_new();
ret = http_client_request(&ctx);
if (ret < 0 || ctx.response_code != HTTP_OK)
{
DPRINTF(E_LOG, L_SPOTIFY, "Failed to AP list from '%s' (return %d, error code %d)\n", ctx.url, ret, ctx.response_code);
goto error;
}
len = evbuffer_get_length(ctx.input_body);
body = malloc(len + 1);
evbuffer_remove(ctx.input_body, body, len);
body[len] = '\0'; // For safety
*out = body;
evbuffer_free(ctx.input_body);
return 0;
error:
evbuffer_free(ctx.input_body);
return -1;
}
static int
tcp_connect(const char *address, unsigned short port)
{
return net_connect(address, port, SOCK_STREAM, "spotify");
}
static void
tcp_disconnect(int fd)
{
close(fd);
}
static void
logmsg_cb(const char *fmt, ...)
{
/*
va_list ap;
va_start(ap, fmt);
DVPRINTF(E_DBG, L_SPOTIFY, fmt, ap);
va_end(ap);
*/
}
static void
hexdump_cb(const char *msg, uint8_t *data, size_t data_len)
{
// DHEXDUMP(E_DBG, L_SPOTIFY, data, data_len, msg);
}
/* --------------------- Implementation (input thread) ---------------------- */
struct sp_callbacks callbacks = {
.error = error_cb,
.logged_in = logged_in_cb,
.logged_out = logged_out_cb,
.track_opened = track_opened_cb,
.track_closed = track_closed_cb,
.https_get = https_get_cb,
.tcp_connect = tcp_connect,
.tcp_disconnect = tcp_disconnect,
.hexdump = hexdump_cb,
.logmsg = logmsg_cb,
};
// Has to be called after we have started receiving data, since ffmpeg needs to
// probe the data to find the audio streams
static int
playback_xcode_setup(struct playback_ctx *playback)
{
struct transcode_ctx *xcode;
CHECK_NULL(L_SPOTIFY, xcode = malloc(sizeof(struct transcode_ctx)));
xcode->decode_ctx = transcode_decode_setup(XCODE_OGG, NULL, DATA_KIND_SPOTIFY, NULL, playback->read_buf, playback->len_ms);
if (!xcode->decode_ctx)
goto error;
xcode->encode_ctx = transcode_encode_setup(XCODE_PCM16, NULL, xcode->decode_ctx, NULL, 0, 0);
if (!xcode->encode_ctx)
goto error;
playback->xcode = xcode;
return 0; return 0;
error:
transcode_cleanup(&xcode);
return -1;
}
static void
playback_free(struct playback_ctx *playback)
{
if (!playback)
return;
if (playback->read_buf)
evbuffer_free(playback->read_buf);
if (playback->read_fd >= 0)
close(playback->read_fd);
transcode_cleanup(&playback->xcode);
free(playback);
}
static struct playback_ctx *
playback_new(struct input_source *source, int fd)
{
struct playback_ctx *playback;
CHECK_NULL(L_SPOTIFY, playback = calloc(1, sizeof(struct playback_ctx)));
CHECK_NULL(L_SPOTIFY, playback->read_buf = evbuffer_new());
playback->read_fd = fd;
playback->len_ms = source->len_ms;
return playback;
} }
static int static int
stop(struct input_source *source) stop(struct input_source *source)
{ {
int ret; struct global_ctx *ctx = &spotify_ctx;
struct playback_ctx *playback = source->input_ctx;
ret = spotify_playback_stop(); pthread_mutex_lock(&ctx->lock);
if (ret < 0)
return -1; if (playback)
{
// Only need to request stop if spotifyc still has the track open
if (ctx->status.track_opened)
spotifyc_stop(playback->read_fd);
playback_free(playback);
}
if (source->evbuf)
evbuffer_free(source->evbuf);
source->input_ctx = NULL;
source->evbuf = NULL;
ctx->status.track_opened = false;
pthread_mutex_unlock(&ctx->lock);
return 0; return 0;
} }
static int static int
seek(struct input_source *source, int seek_ms) setup(struct input_source *source)
{ {
struct global_ctx *ctx = &spotify_ctx;
int ret;
int fd;
pthread_mutex_lock(&ctx->lock);
fd = spotifyc_open(source->path, ctx->session);
if (fd < 0)
{
DPRINTF(E_LOG, L_SPOTIFY, "Could not create fd for Spotify playback\n");
goto error;
}
ctx->response_pending = true;
while (ctx->response_pending)
pthread_cond_wait(&ctx->cond, &ctx->lock);
if (!ctx->status.track_opened)
{
close(fd);
goto error;
}
// Seems we have a valid source, now setup a read + decoding context. The
// closing of the fd is from now on part of closing the playback_ctx, which is
// done in stop().
source->evbuf = evbuffer_new();
source->input_ctx = playback_new(source, fd);
if (!source->evbuf || !source->input_ctx)
goto error;
source->quality = spotify_quality;
// FIXME This makes sure we get the beginning of the file for ffmpeg to probe,
// but it doesn't work well if the player seeks after setup()
ret = spotifyc_play(fd);
if (ret < 0)
goto error;
pthread_mutex_unlock(&ctx->lock);
return 0;
error:
pthread_mutex_unlock(&ctx->lock);
stop(source);
return -1;
}
static int
play(struct input_source *source)
{
struct playback_ctx *playback = source->input_ctx;
int got;
int ret; int ret;
ret = spotify_playback_seek(seek_ms); got = evbuffer_read(playback->read_buf, playback->read_fd, -1);
if (ret < 0) if (got < 0)
return -1; goto error;
return ret; // ffmpeg requires enough data to be able to probe the Ogg
playback->read_bytes += got;
if (playback->read_bytes < SPOTIFY_PROBE_SIZE_MIN)
{
input_wait();
return 0;
}
if (!playback->xcode)
{
ret = playback_xcode_setup(playback);
if (ret < 0)
goto error;
}
// Decode the Ogg Vorbis to PCM in chunks of 16 packets, which seems to keep
// the input buffer nice and full
ret = transcode(source->evbuf, NULL, playback->xcode, 16);
if (ret == 0)
{
input_write(source->evbuf, &source->quality, INPUT_FLAG_EOF);
stop(source);
return -1;
}
else if (ret < 0)
goto error;
// debug_count++;
// if (debug_count % 100 == 0)
// DPRINTF(E_DBG, L_SPOTIFY, "source->evbuf is %zu, playback->read_buf %zu, got is %d\n",
// evbuffer_get_length(source->evbuf), evbuffer_get_length(playback->read_buf), got);
input_write(source->evbuf, &source->quality, 0);
return 0;
error:
input_write(NULL, NULL, INPUT_FLAG_ERROR);
stop(source);
return -1;
}
static int
seek(struct input_source *source, int seek_ms)
{
return -1;
}
static int
init(void)
{
char *username = NULL;
char *db_stored_cred = NULL;
size_t db_stored_cred_len;
uint8_t *stored_cred = NULL;
size_t stored_cred_len;
int ret;
CHECK_ERR(L_SPOTIFY, mutex_init(&spotify_ctx.lock));
CHECK_ERR(L_SPOTIFY, pthread_cond_init(&spotify_ctx.cond, NULL));
ret = spotifyc_init(&callbacks, &spotify_ctx);
if (ret < 0)
goto error;
if ( db_admin_get(&username, "spotify_username") < 0 ||
db_admin_get(&db_stored_cred, "spotify_stored_cred") < 0 ||
!username || !db_stored_cred )
goto end; // User not logged in yet
db_stored_cred_len = strlen(db_stored_cred);
stored_cred_len = db_stored_cred_len / 2;
CHECK_NULL(L_SPOTIFY, stored_cred = malloc(stored_cred_len));
hextobin(stored_cred, stored_cred_len, db_stored_cred, db_stored_cred_len);
spotify_ctx.session = spotifyc_login_stored_cred(username, stored_cred, stored_cred_len);
if (!spotify_ctx.session)
goto error;
end:
free(username);
free(db_stored_cred);
free(stored_cred);
return 0;
error:
free(username);
free(db_stored_cred);
free(stored_cred);
return -1;
}
static void
deinit(void)
{
spotifyc_deinit();
} }
struct input_definition input_spotify = struct input_definition input_spotify =
@ -87,6 +534,67 @@ struct input_definition input_spotify =
.disabled = 0, .disabled = 0,
.setup = setup, .setup = setup,
.stop = stop, .stop = stop,
.play = play,
.seek = seek, .seek = seek,
.init = init,
.deinit = deinit,
}; };
/* ------------ Functions exposed via spotify.h (foreign threads) ----------- */
int
spotify_login_user(const char *user, const char *password, const char **errmsg)
{
struct global_ctx *ctx = &spotify_ctx;
int ret;
pthread_mutex_lock(&ctx->lock);
ctx->response_pending = true;
ctx->session = spotifyc_login_password(user, password);
if (!ctx->session)
{
pthread_mutex_unlock(&ctx->lock);
*errmsg = "Error creating Spotify session";
return -1;
}
while (ctx->response_pending)
pthread_cond_wait(&ctx->cond, &ctx->lock);
ret = ctx->status.logged_in ? 0 : -1;
if (ret < 0)
*errmsg = spotifyc_last_errmsg();
pthread_mutex_unlock(&ctx->lock);
return ret;
}
void
spotify_login(char **arglist)
{
return;
}
void
spotify_logout(void)
{
return;
}
void
spotify_status_get(struct spotify_status *status)
{
struct global_ctx *ctx = &spotify_ctx;
pthread_mutex_lock(&ctx->lock);
memcpy(status->username, ctx->status.username, sizeof(status->username));
status->logged_in = ctx->status.logged_in;
status->installed = true;
pthread_mutex_unlock(&ctx->lock);
}

26
src/inputs/spotify.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __SPOTIFY_H__
#define __SPOTIFY_H__
#include <stdbool.h>
struct spotify_status
{
bool installed;
bool logged_in;
bool track_opened;
char username[100];
};
int
spotify_login_user(const char *user, const char *password, const char **errmsg);
void
spotify_login(char **arglist);
void
spotify_logout(void);
void
spotify_status_get(struct spotify_status *status);
#endif /* !__SPOTIFY_H__ */

View File

@ -0,0 +1,51 @@
syntax = "proto2";
message Rule {
optional string type = 0x1;
optional uint32 times = 0x2;
optional uint64 interval = 0x3;
}
message AdRequest {
optional string client_language = 0x1;
optional string product = 0x2;
optional uint32 version = 0x3;
optional string type = 0x4;
repeated string avoidAds = 0x5;
}
message AdQueueResponse {
repeated AdQueueEntry adQueueEntry = 0x1;
}
message AdFile {
optional string id = 0x1;
optional string format = 0x2;
}
message AdQueueEntry {
optional uint64 start_time = 0x1;
optional uint64 end_time = 0x2;
optional double priority = 0x3;
optional string token = 0x4;
optional uint32 ad_version = 0x5;
optional string id = 0x6;
optional string type = 0x7;
optional string campaign = 0x8;
optional string advertiser = 0x9;
optional string url = 0xa;
optional uint64 duration = 0xb;
optional uint64 expiry = 0xc;
optional string tracking_url = 0xd;
optional string banner_type = 0xe;
optional string html = 0xf;
optional string image = 0x10;
optional string background_image = 0x11;
optional string background_url = 0x12;
optional string background_color = 0x13;
optional string title = 0x14;
optional string caption = 0x15;
repeated AdFile file = 0x16;
repeated Rule rule = 0x17;
}

View File

@ -0,0 +1,95 @@
syntax = "proto2";
message AppInfo {
optional string identifier = 0x1;
optional int32 version_int = 0x2;
}
message AppInfoList {
repeated AppInfo items = 0x1;
}
message SemanticVersion {
optional int32 major = 0x1;
optional int32 minor = 0x2;
optional int32 patch = 0x3;
}
message RequestHeader {
optional string market = 0x1;
optional Platform platform = 0x2;
enum Platform {
WIN32_X86 = 0x0;
OSX_X86 = 0x1;
LINUX_X86 = 0x2;
IPHONE_ARM = 0x3;
SYMBIANS60_ARM = 0x4;
OSX_POWERPC = 0x5;
ANDROID_ARM = 0x6;
WINCE_ARM = 0x7;
LINUX_X86_64 = 0x8;
OSX_X86_64 = 0x9;
PALM_ARM = 0xa;
LINUX_SH = 0xb;
FREEBSD_X86 = 0xc;
FREEBSD_X86_64 = 0xd;
BLACKBERRY_ARM = 0xe;
SONOS_UNKNOWN = 0xf;
LINUX_MIPS = 0x10;
LINUX_ARM = 0x11;
LOGITECH_ARM = 0x12;
LINUX_BLACKFIN = 0x13;
ONKYO_ARM = 0x15;
QNXNTO_ARM = 0x16;
BADPLATFORM = 0xff;
}
optional AppInfoList app_infos = 0x6;
optional string bridge_identifier = 0x7;
optional SemanticVersion bridge_version = 0x8;
optional DeviceClass device_class = 0x9;
enum DeviceClass {
DESKTOP = 0x1;
TABLET = 0x2;
MOBILE = 0x3;
WEB = 0x4;
TV = 0x5;
}
}
message AppItem {
optional string identifier = 0x1;
optional Requirement requirement = 0x2;
enum Requirement {
REQUIRED_INSTALL = 0x1;
LAZYLOAD = 0x2;
OPTIONAL_INSTALL = 0x3;
}
optional string manifest = 0x4;
optional string checksum = 0x5;
optional string bundle_uri = 0x6;
optional string small_icon_uri = 0x7;
optional string large_icon_uri = 0x8;
optional string medium_icon_uri = 0x9;
optional Type bundle_type = 0xa;
enum Type {
APPLICATION = 0x0;
FRAMEWORK = 0x1;
BRIDGE = 0x2;
}
optional SemanticVersion version = 0xb;
optional uint32 ttl_in_seconds = 0xc;
optional IdentifierList categories = 0xd;
}
message AppList {
repeated AppItem items = 0x1;
}
message IdentifierList {
repeated string identifiers = 0x1;
}
message BannerConfig {
optional string json = 0x1;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,697 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: proto/authentication.proto */
#ifndef PROTOBUF_C_proto_2fauthentication_2eproto__INCLUDED
#define PROTOBUF_C_proto_2fauthentication_2eproto__INCLUDED
#include <protobuf-c/protobuf-c.h>
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
typedef struct _ClientResponseEncrypted ClientResponseEncrypted;
typedef struct _LoginCredentials LoginCredentials;
typedef struct _FingerprintResponseUnion FingerprintResponseUnion;
typedef struct _FingerprintGrainResponse FingerprintGrainResponse;
typedef struct _FingerprintHmacRipemdResponse FingerprintHmacRipemdResponse;
typedef struct _PeerTicketUnion PeerTicketUnion;
typedef struct _PeerTicketPublicKey PeerTicketPublicKey;
typedef struct _PeerTicketOld PeerTicketOld;
typedef struct _SystemInfo SystemInfo;
typedef struct _LibspotifyAppKey LibspotifyAppKey;
typedef struct _ClientInfo ClientInfo;
typedef struct _ClientInfoFacebook ClientInfoFacebook;
typedef struct _APWelcome APWelcome;
typedef struct _AccountInfo AccountInfo;
typedef struct _AccountInfoSpotify AccountInfoSpotify;
typedef struct _AccountInfoFacebook AccountInfoFacebook;
/* --- enums --- */
typedef enum _AuthenticationType {
AUTHENTICATION_TYPE__AUTHENTICATION_USER_PASS = 0,
AUTHENTICATION_TYPE__AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 1,
AUTHENTICATION_TYPE__AUTHENTICATION_STORED_FACEBOOK_CREDENTIALS = 2,
AUTHENTICATION_TYPE__AUTHENTICATION_SPOTIFY_TOKEN = 3,
AUTHENTICATION_TYPE__AUTHENTICATION_FACEBOOK_TOKEN = 4
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(AUTHENTICATION_TYPE)
} AuthenticationType;
typedef enum _AccountCreation {
ACCOUNT_CREATION__ACCOUNT_CREATION_ALWAYS_PROMPT = 1,
ACCOUNT_CREATION__ACCOUNT_CREATION_ALWAYS_CREATE = 3
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(ACCOUNT_CREATION)
} AccountCreation;
typedef enum _CpuFamily {
CPU_FAMILY__CPU_UNKNOWN = 0,
CPU_FAMILY__CPU_X86 = 1,
CPU_FAMILY__CPU_X86_64 = 2,
CPU_FAMILY__CPU_PPC = 3,
CPU_FAMILY__CPU_PPC_64 = 4,
CPU_FAMILY__CPU_ARM = 5,
CPU_FAMILY__CPU_IA64 = 6,
CPU_FAMILY__CPU_SH = 7,
CPU_FAMILY__CPU_MIPS = 8,
CPU_FAMILY__CPU_BLACKFIN = 9
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(CPU_FAMILY)
} CpuFamily;
typedef enum _Brand {
BRAND__BRAND_UNBRANDED = 0,
BRAND__BRAND_INQ = 1,
BRAND__BRAND_HTC = 2,
BRAND__BRAND_NOKIA = 3
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(BRAND)
} Brand;
typedef enum _Os {
OS__OS_UNKNOWN = 0,
OS__OS_WINDOWS = 1,
OS__OS_OSX = 2,
OS__OS_IPHONE = 3,
OS__OS_S60 = 4,
OS__OS_LINUX = 5,
OS__OS_WINDOWS_CE = 6,
OS__OS_ANDROID = 7,
OS__OS_PALM = 8,
OS__OS_FREEBSD = 9,
OS__OS_BLACKBERRY = 10,
OS__OS_SONOS = 11,
OS__OS_LOGITECH = 12,
OS__OS_WP7 = 13,
OS__OS_ONKYO = 14,
OS__OS_PHILIPS = 15,
OS__OS_WD = 16,
OS__OS_VOLVO = 17,
OS__OS_TIVO = 18,
OS__OS_AWOX = 19,
OS__OS_MEEGO = 20,
OS__OS_QNXNTO = 21,
OS__OS_BCO = 22
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(OS)
} Os;
typedef enum _AccountType {
ACCOUNT_TYPE__Spotify = 0,
ACCOUNT_TYPE__Facebook = 1
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(ACCOUNT_TYPE)
} AccountType;
/* --- messages --- */
struct _ClientResponseEncrypted
{
ProtobufCMessage base;
LoginCredentials *login_credentials;
protobuf_c_boolean has_account_creation;
AccountCreation account_creation;
FingerprintResponseUnion *fingerprint_response;
PeerTicketUnion *peer_ticket;
SystemInfo *system_info;
char *platform_model;
char *version_string;
LibspotifyAppKey *appkey;
ClientInfo *client_info;
};
#define CLIENT_RESPONSE_ENCRYPTED__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&client_response_encrypted__descriptor) \
, NULL, 0, ACCOUNT_CREATION__ACCOUNT_CREATION_ALWAYS_PROMPT, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
struct _LoginCredentials
{
ProtobufCMessage base;
char *username;
AuthenticationType typ;
protobuf_c_boolean has_auth_data;
ProtobufCBinaryData auth_data;
};
#define LOGIN_CREDENTIALS__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&login_credentials__descriptor) \
, NULL, AUTHENTICATION_TYPE__AUTHENTICATION_USER_PASS, 0, {0,NULL} }
struct _FingerprintResponseUnion
{
ProtobufCMessage base;
FingerprintGrainResponse *grain;
FingerprintHmacRipemdResponse *hmac_ripemd;
};
#define FINGERPRINT_RESPONSE_UNION__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&fingerprint_response_union__descriptor) \
, NULL, NULL }
struct _FingerprintGrainResponse
{
ProtobufCMessage base;
ProtobufCBinaryData encrypted_key;
};
#define FINGERPRINT_GRAIN_RESPONSE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&fingerprint_grain_response__descriptor) \
, {0,NULL} }
struct _FingerprintHmacRipemdResponse
{
ProtobufCMessage base;
ProtobufCBinaryData hmac;
};
#define FINGERPRINT_HMAC_RIPEMD_RESPONSE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&fingerprint_hmac_ripemd_response__descriptor) \
, {0,NULL} }
struct _PeerTicketUnion
{
ProtobufCMessage base;
PeerTicketPublicKey *public_key;
PeerTicketOld *old_ticket;
};
#define PEER_TICKET_UNION__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&peer_ticket_union__descriptor) \
, NULL, NULL }
struct _PeerTicketPublicKey
{
ProtobufCMessage base;
ProtobufCBinaryData public_key;
};
#define PEER_TICKET_PUBLIC_KEY__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&peer_ticket_public_key__descriptor) \
, {0,NULL} }
struct _PeerTicketOld
{
ProtobufCMessage base;
ProtobufCBinaryData peer_ticket;
ProtobufCBinaryData peer_ticket_signature;
};
#define PEER_TICKET_OLD__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&peer_ticket_old__descriptor) \
, {0,NULL}, {0,NULL} }
struct _SystemInfo
{
ProtobufCMessage base;
CpuFamily cpu_family;
protobuf_c_boolean has_cpu_subtype;
uint32_t cpu_subtype;
protobuf_c_boolean has_cpu_ext;
uint32_t cpu_ext;
protobuf_c_boolean has_brand;
Brand brand;
protobuf_c_boolean has_brand_flags;
uint32_t brand_flags;
Os os;
protobuf_c_boolean has_os_version;
uint32_t os_version;
protobuf_c_boolean has_os_ext;
uint32_t os_ext;
char *system_information_string;
char *device_id;
};
#define SYSTEM_INFO__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&system_info__descriptor) \
, CPU_FAMILY__CPU_UNKNOWN, 0, 0, 0, 0, 0, BRAND__BRAND_UNBRANDED, 0, 0, OS__OS_UNKNOWN, 0, 0, 0, 0, NULL, NULL }
struct _LibspotifyAppKey
{
ProtobufCMessage base;
uint32_t version;
ProtobufCBinaryData devkey;
ProtobufCBinaryData signature;
char *useragent;
ProtobufCBinaryData callback_hash;
};
#define LIBSPOTIFY_APP_KEY__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&libspotify_app_key__descriptor) \
, 0, {0,NULL}, {0,NULL}, NULL, {0,NULL} }
struct _ClientInfo
{
ProtobufCMessage base;
protobuf_c_boolean has_limited;
protobuf_c_boolean limited;
ClientInfoFacebook *fb;
char *language;
};
#define CLIENT_INFO__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&client_info__descriptor) \
, 0, 0, NULL, NULL }
struct _ClientInfoFacebook
{
ProtobufCMessage base;
char *machine_id;
};
#define CLIENT_INFO_FACEBOOK__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&client_info_facebook__descriptor) \
, NULL }
struct _APWelcome
{
ProtobufCMessage base;
char *canonical_username;
AccountType account_type_logged_in;
AccountType credentials_type_logged_in;
AuthenticationType reusable_auth_credentials_type;
ProtobufCBinaryData reusable_auth_credentials;
protobuf_c_boolean has_lfs_secret;
ProtobufCBinaryData lfs_secret;
AccountInfo *account_info;
AccountInfoFacebook *fb;
};
#define APWELCOME__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&apwelcome__descriptor) \
, NULL, ACCOUNT_TYPE__Spotify, ACCOUNT_TYPE__Spotify, AUTHENTICATION_TYPE__AUTHENTICATION_USER_PASS, {0,NULL}, 0, {0,NULL}, NULL, NULL }
struct _AccountInfo
{
ProtobufCMessage base;
AccountInfoSpotify *spotify;
AccountInfoFacebook *facebook;
};
#define ACCOUNT_INFO__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&account_info__descriptor) \
, NULL, NULL }
struct _AccountInfoSpotify
{
ProtobufCMessage base;
};
#define ACCOUNT_INFO_SPOTIFY__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&account_info_spotify__descriptor) \
}
struct _AccountInfoFacebook
{
ProtobufCMessage base;
char *access_token;
char *machine_id;
};
#define ACCOUNT_INFO_FACEBOOK__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&account_info_facebook__descriptor) \
, NULL, NULL }
/* ClientResponseEncrypted methods */
void client_response_encrypted__init
(ClientResponseEncrypted *message);
size_t client_response_encrypted__get_packed_size
(const ClientResponseEncrypted *message);
size_t client_response_encrypted__pack
(const ClientResponseEncrypted *message,
uint8_t *out);
size_t client_response_encrypted__pack_to_buffer
(const ClientResponseEncrypted *message,
ProtobufCBuffer *buffer);
ClientResponseEncrypted *
client_response_encrypted__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void client_response_encrypted__free_unpacked
(ClientResponseEncrypted *message,
ProtobufCAllocator *allocator);
/* LoginCredentials methods */
void login_credentials__init
(LoginCredentials *message);
size_t login_credentials__get_packed_size
(const LoginCredentials *message);
size_t login_credentials__pack
(const LoginCredentials *message,
uint8_t *out);
size_t login_credentials__pack_to_buffer
(const LoginCredentials *message,
ProtobufCBuffer *buffer);
LoginCredentials *
login_credentials__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void login_credentials__free_unpacked
(LoginCredentials *message,
ProtobufCAllocator *allocator);
/* FingerprintResponseUnion methods */
void fingerprint_response_union__init
(FingerprintResponseUnion *message);
size_t fingerprint_response_union__get_packed_size
(const FingerprintResponseUnion *message);
size_t fingerprint_response_union__pack
(const FingerprintResponseUnion *message,
uint8_t *out);
size_t fingerprint_response_union__pack_to_buffer
(const FingerprintResponseUnion *message,
ProtobufCBuffer *buffer);
FingerprintResponseUnion *
fingerprint_response_union__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void fingerprint_response_union__free_unpacked
(FingerprintResponseUnion *message,
ProtobufCAllocator *allocator);
/* FingerprintGrainResponse methods */
void fingerprint_grain_response__init
(FingerprintGrainResponse *message);
size_t fingerprint_grain_response__get_packed_size
(const FingerprintGrainResponse *message);
size_t fingerprint_grain_response__pack
(const FingerprintGrainResponse *message,
uint8_t *out);
size_t fingerprint_grain_response__pack_to_buffer
(const FingerprintGrainResponse *message,
ProtobufCBuffer *buffer);
FingerprintGrainResponse *
fingerprint_grain_response__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void fingerprint_grain_response__free_unpacked
(FingerprintGrainResponse *message,
ProtobufCAllocator *allocator);
/* FingerprintHmacRipemdResponse methods */
void fingerprint_hmac_ripemd_response__init
(FingerprintHmacRipemdResponse *message);
size_t fingerprint_hmac_ripemd_response__get_packed_size
(const FingerprintHmacRipemdResponse *message);
size_t fingerprint_hmac_ripemd_response__pack
(const FingerprintHmacRipemdResponse *message,
uint8_t *out);
size_t fingerprint_hmac_ripemd_response__pack_to_buffer
(const FingerprintHmacRipemdResponse *message,
ProtobufCBuffer *buffer);
FingerprintHmacRipemdResponse *
fingerprint_hmac_ripemd_response__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void fingerprint_hmac_ripemd_response__free_unpacked
(FingerprintHmacRipemdResponse *message,
ProtobufCAllocator *allocator);
/* PeerTicketUnion methods */
void peer_ticket_union__init
(PeerTicketUnion *message);
size_t peer_ticket_union__get_packed_size
(const PeerTicketUnion *message);
size_t peer_ticket_union__pack
(const PeerTicketUnion *message,
uint8_t *out);
size_t peer_ticket_union__pack_to_buffer
(const PeerTicketUnion *message,
ProtobufCBuffer *buffer);
PeerTicketUnion *
peer_ticket_union__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void peer_ticket_union__free_unpacked
(PeerTicketUnion *message,
ProtobufCAllocator *allocator);
/* PeerTicketPublicKey methods */
void peer_ticket_public_key__init
(PeerTicketPublicKey *message);
size_t peer_ticket_public_key__get_packed_size
(const PeerTicketPublicKey *message);
size_t peer_ticket_public_key__pack
(const PeerTicketPublicKey *message,
uint8_t *out);
size_t peer_ticket_public_key__pack_to_buffer
(const PeerTicketPublicKey *message,
ProtobufCBuffer *buffer);
PeerTicketPublicKey *
peer_ticket_public_key__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void peer_ticket_public_key__free_unpacked
(PeerTicketPublicKey *message,
ProtobufCAllocator *allocator);
/* PeerTicketOld methods */
void peer_ticket_old__init
(PeerTicketOld *message);
size_t peer_ticket_old__get_packed_size
(const PeerTicketOld *message);
size_t peer_ticket_old__pack
(const PeerTicketOld *message,
uint8_t *out);
size_t peer_ticket_old__pack_to_buffer
(const PeerTicketOld *message,
ProtobufCBuffer *buffer);
PeerTicketOld *
peer_ticket_old__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void peer_ticket_old__free_unpacked
(PeerTicketOld *message,
ProtobufCAllocator *allocator);
/* SystemInfo methods */
void system_info__init
(SystemInfo *message);
size_t system_info__get_packed_size
(const SystemInfo *message);
size_t system_info__pack
(const SystemInfo *message,
uint8_t *out);
size_t system_info__pack_to_buffer
(const SystemInfo *message,
ProtobufCBuffer *buffer);
SystemInfo *
system_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void system_info__free_unpacked
(SystemInfo *message,
ProtobufCAllocator *allocator);
/* LibspotifyAppKey methods */
void libspotify_app_key__init
(LibspotifyAppKey *message);
size_t libspotify_app_key__get_packed_size
(const LibspotifyAppKey *message);
size_t libspotify_app_key__pack
(const LibspotifyAppKey *message,
uint8_t *out);
size_t libspotify_app_key__pack_to_buffer
(const LibspotifyAppKey *message,
ProtobufCBuffer *buffer);
LibspotifyAppKey *
libspotify_app_key__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void libspotify_app_key__free_unpacked
(LibspotifyAppKey *message,
ProtobufCAllocator *allocator);
/* ClientInfo methods */
void client_info__init
(ClientInfo *message);
size_t client_info__get_packed_size
(const ClientInfo *message);
size_t client_info__pack
(const ClientInfo *message,
uint8_t *out);
size_t client_info__pack_to_buffer
(const ClientInfo *message,
ProtobufCBuffer *buffer);
ClientInfo *
client_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void client_info__free_unpacked
(ClientInfo *message,
ProtobufCAllocator *allocator);
/* ClientInfoFacebook methods */
void client_info_facebook__init
(ClientInfoFacebook *message);
size_t client_info_facebook__get_packed_size
(const ClientInfoFacebook *message);
size_t client_info_facebook__pack
(const ClientInfoFacebook *message,
uint8_t *out);
size_t client_info_facebook__pack_to_buffer
(const ClientInfoFacebook *message,
ProtobufCBuffer *buffer);
ClientInfoFacebook *
client_info_facebook__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void client_info_facebook__free_unpacked
(ClientInfoFacebook *message,
ProtobufCAllocator *allocator);
/* APWelcome methods */
void apwelcome__init
(APWelcome *message);
size_t apwelcome__get_packed_size
(const APWelcome *message);
size_t apwelcome__pack
(const APWelcome *message,
uint8_t *out);
size_t apwelcome__pack_to_buffer
(const APWelcome *message,
ProtobufCBuffer *buffer);
APWelcome *
apwelcome__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void apwelcome__free_unpacked
(APWelcome *message,
ProtobufCAllocator *allocator);
/* AccountInfo methods */
void account_info__init
(AccountInfo *message);
size_t account_info__get_packed_size
(const AccountInfo *message);
size_t account_info__pack
(const AccountInfo *message,
uint8_t *out);
size_t account_info__pack_to_buffer
(const AccountInfo *message,
ProtobufCBuffer *buffer);
AccountInfo *
account_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void account_info__free_unpacked
(AccountInfo *message,
ProtobufCAllocator *allocator);
/* AccountInfoSpotify methods */
void account_info_spotify__init
(AccountInfoSpotify *message);
size_t account_info_spotify__get_packed_size
(const AccountInfoSpotify *message);
size_t account_info_spotify__pack
(const AccountInfoSpotify *message,
uint8_t *out);
size_t account_info_spotify__pack_to_buffer
(const AccountInfoSpotify *message,
ProtobufCBuffer *buffer);
AccountInfoSpotify *
account_info_spotify__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void account_info_spotify__free_unpacked
(AccountInfoSpotify *message,
ProtobufCAllocator *allocator);
/* AccountInfoFacebook methods */
void account_info_facebook__init
(AccountInfoFacebook *message);
size_t account_info_facebook__get_packed_size
(const AccountInfoFacebook *message);
size_t account_info_facebook__pack
(const AccountInfoFacebook *message,
uint8_t *out);
size_t account_info_facebook__pack_to_buffer
(const AccountInfoFacebook *message,
ProtobufCBuffer *buffer);
AccountInfoFacebook *
account_info_facebook__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void account_info_facebook__free_unpacked
(AccountInfoFacebook *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*ClientResponseEncrypted_Closure)
(const ClientResponseEncrypted *message,
void *closure_data);
typedef void (*LoginCredentials_Closure)
(const LoginCredentials *message,
void *closure_data);
typedef void (*FingerprintResponseUnion_Closure)
(const FingerprintResponseUnion *message,
void *closure_data);
typedef void (*FingerprintGrainResponse_Closure)
(const FingerprintGrainResponse *message,
void *closure_data);
typedef void (*FingerprintHmacRipemdResponse_Closure)
(const FingerprintHmacRipemdResponse *message,
void *closure_data);
typedef void (*PeerTicketUnion_Closure)
(const PeerTicketUnion *message,
void *closure_data);
typedef void (*PeerTicketPublicKey_Closure)
(const PeerTicketPublicKey *message,
void *closure_data);
typedef void (*PeerTicketOld_Closure)
(const PeerTicketOld *message,
void *closure_data);
typedef void (*SystemInfo_Closure)
(const SystemInfo *message,
void *closure_data);
typedef void (*LibspotifyAppKey_Closure)
(const LibspotifyAppKey *message,
void *closure_data);
typedef void (*ClientInfo_Closure)
(const ClientInfo *message,
void *closure_data);
typedef void (*ClientInfoFacebook_Closure)
(const ClientInfoFacebook *message,
void *closure_data);
typedef void (*APWelcome_Closure)
(const APWelcome *message,
void *closure_data);
typedef void (*AccountInfo_Closure)
(const AccountInfo *message,
void *closure_data);
typedef void (*AccountInfoSpotify_Closure)
(const AccountInfoSpotify *message,
void *closure_data);
typedef void (*AccountInfoFacebook_Closure)
(const AccountInfoFacebook *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCEnumDescriptor authentication_type__descriptor;
extern const ProtobufCEnumDescriptor account_creation__descriptor;
extern const ProtobufCEnumDescriptor cpu_family__descriptor;
extern const ProtobufCEnumDescriptor brand__descriptor;
extern const ProtobufCEnumDescriptor os__descriptor;
extern const ProtobufCEnumDescriptor account_type__descriptor;
extern const ProtobufCMessageDescriptor client_response_encrypted__descriptor;
extern const ProtobufCMessageDescriptor login_credentials__descriptor;
extern const ProtobufCMessageDescriptor fingerprint_response_union__descriptor;
extern const ProtobufCMessageDescriptor fingerprint_grain_response__descriptor;
extern const ProtobufCMessageDescriptor fingerprint_hmac_ripemd_response__descriptor;
extern const ProtobufCMessageDescriptor peer_ticket_union__descriptor;
extern const ProtobufCMessageDescriptor peer_ticket_public_key__descriptor;
extern const ProtobufCMessageDescriptor peer_ticket_old__descriptor;
extern const ProtobufCMessageDescriptor system_info__descriptor;
extern const ProtobufCMessageDescriptor libspotify_app_key__descriptor;
extern const ProtobufCMessageDescriptor client_info__descriptor;
extern const ProtobufCMessageDescriptor client_info_facebook__descriptor;
extern const ProtobufCMessageDescriptor apwelcome__descriptor;
extern const ProtobufCMessageDescriptor account_info__descriptor;
extern const ProtobufCMessageDescriptor account_info_spotify__descriptor;
extern const ProtobufCMessageDescriptor account_info_facebook__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_proto_2fauthentication_2eproto__INCLUDED */

View File

@ -0,0 +1,165 @@
syntax = "proto2";
message ClientResponseEncrypted {
required LoginCredentials login_credentials = 0xa;
optional AccountCreation account_creation = 0x14;
optional FingerprintResponseUnion fingerprint_response = 0x1e;
optional PeerTicketUnion peer_ticket = 0x28;
required SystemInfo system_info = 0x32;
optional string platform_model = 0x3c;
optional string version_string = 0x46;
optional LibspotifyAppKey appkey = 0x50;
optional ClientInfo client_info = 0x5a;
}
message LoginCredentials {
optional string username = 0xa;
required AuthenticationType typ = 0x14;
optional bytes auth_data = 0x1e;
}
enum AuthenticationType {
AUTHENTICATION_USER_PASS = 0x0;
AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1;
AUTHENTICATION_STORED_FACEBOOK_CREDENTIALS = 0x2;
AUTHENTICATION_SPOTIFY_TOKEN = 0x3;
AUTHENTICATION_FACEBOOK_TOKEN = 0x4;
}
enum AccountCreation {
ACCOUNT_CREATION_ALWAYS_PROMPT = 0x1;
ACCOUNT_CREATION_ALWAYS_CREATE = 0x3;
}
message FingerprintResponseUnion {
optional FingerprintGrainResponse grain = 0xa;
optional FingerprintHmacRipemdResponse hmac_ripemd = 0x14;
}
message FingerprintGrainResponse {
required bytes encrypted_key = 0xa;
}
message FingerprintHmacRipemdResponse {
required bytes hmac = 0xa;
}
message PeerTicketUnion {
optional PeerTicketPublicKey public_key = 0xa;
optional PeerTicketOld old_ticket = 0x14;
}
message PeerTicketPublicKey {
required bytes public_key = 0xa;
}
message PeerTicketOld {
required bytes peer_ticket = 0xa;
required bytes peer_ticket_signature = 0x14;
}
message SystemInfo {
required CpuFamily cpu_family = 0xa;
optional uint32 cpu_subtype = 0x14;
optional uint32 cpu_ext = 0x1e;
optional Brand brand = 0x28;
optional uint32 brand_flags = 0x32;
required Os os = 0x3c;
optional uint32 os_version = 0x46;
optional uint32 os_ext = 0x50;
optional string system_information_string = 0x5a;
optional string device_id = 0x64;
}
enum CpuFamily {
CPU_UNKNOWN = 0x0;
CPU_X86 = 0x1;
CPU_X86_64 = 0x2;
CPU_PPC = 0x3;
CPU_PPC_64 = 0x4;
CPU_ARM = 0x5;
CPU_IA64 = 0x6;
CPU_SH = 0x7;
CPU_MIPS = 0x8;
CPU_BLACKFIN = 0x9;
}
enum Brand {
BRAND_UNBRANDED = 0x0;
BRAND_INQ = 0x1;
BRAND_HTC = 0x2;
BRAND_NOKIA = 0x3;
}
enum Os {
OS_UNKNOWN = 0x0;
OS_WINDOWS = 0x1;
OS_OSX = 0x2;
OS_IPHONE = 0x3;
OS_S60 = 0x4;
OS_LINUX = 0x5;
OS_WINDOWS_CE = 0x6;
OS_ANDROID = 0x7;
OS_PALM = 0x8;
OS_FREEBSD = 0x9;
OS_BLACKBERRY = 0xa;
OS_SONOS = 0xb;
OS_LOGITECH = 0xc;
OS_WP7 = 0xd;
OS_ONKYO = 0xe;
OS_PHILIPS = 0xf;
OS_WD = 0x10;
OS_VOLVO = 0x11;
OS_TIVO = 0x12;
OS_AWOX = 0x13;
OS_MEEGO = 0x14;
OS_QNXNTO = 0x15;
OS_BCO = 0x16;
}
message LibspotifyAppKey {
required uint32 version = 0x1;
required bytes devkey = 0x2;
required bytes signature = 0x3;
required string useragent = 0x4;
required bytes callback_hash = 0x5;
}
message ClientInfo {
optional bool limited = 0x1;
optional ClientInfoFacebook fb = 0x2;
optional string language = 0x3;
}
message ClientInfoFacebook {
optional string machine_id = 0x1;
}
message APWelcome {
required string canonical_username = 0xa;
required AccountType account_type_logged_in = 0x14;
required AccountType credentials_type_logged_in = 0x19;
required AuthenticationType reusable_auth_credentials_type = 0x1e;
required bytes reusable_auth_credentials = 0x28;
optional bytes lfs_secret = 0x32;
optional AccountInfo account_info = 0x3c;
optional AccountInfoFacebook fb = 0x46;
}
enum AccountType {
Spotify = 0x0;
Facebook = 0x1;
}
message AccountInfo {
optional AccountInfoSpotify spotify = 0x1;
optional AccountInfoFacebook facebook = 0x2;
}
message AccountInfoSpotify {
}
message AccountInfoFacebook {
optional string access_token = 0x1;
optional string machine_id = 0x2;
}

View File

@ -0,0 +1,51 @@
syntax = "proto2";
message EventReply {
optional int32 queued = 0x1;
optional RetryInfo retry = 0x2;
}
message RetryInfo {
optional int32 retry_delay = 0x1;
optional int32 max_retry = 0x2;
}
message Id {
optional string uri = 0x1;
optional int64 start_time = 0x2;
}
message Start {
optional int32 length = 0x1;
optional string context_uri = 0x2;
optional int64 end_time = 0x3;
}
message Seek {
optional int64 end_time = 0x1;
}
message Pause {
optional int32 seconds_played = 0x1;
optional int64 end_time = 0x2;
}
message Resume {
optional int32 seconds_played = 0x1;
optional int64 end_time = 0x2;
}
message End {
optional int32 seconds_played = 0x1;
optional int64 end_time = 0x2;
}
message Event {
optional Id id = 0x1;
optional Start start = 0x2;
optional Seek seek = 0x3;
optional Pause pause = 0x4;
optional Resume resume = 0x5;
optional End end = 0x6;
}

View File

@ -0,0 +1,183 @@
syntax = "proto2";
message Credential {
optional string facebook_uid = 0x1;
optional string access_token = 0x2;
}
message EnableRequest {
optional Credential credential = 0x1;
}
message EnableReply {
optional Credential credential = 0x1;
}
message DisableRequest {
optional Credential credential = 0x1;
}
message RevokeRequest {
optional Credential credential = 0x1;
}
message InspectCredentialRequest {
optional Credential credential = 0x1;
}
message InspectCredentialReply {
optional Credential alternative_credential = 0x1;
optional bool app_user = 0x2;
optional bool permanent_error = 0x3;
optional bool transient_error = 0x4;
}
message UserState {
optional Credential credential = 0x1;
}
message UpdateUserStateRequest {
optional Credential credential = 0x1;
}
message OpenGraphError {
repeated string permanent = 0x1;
repeated string invalid_token = 0x2;
repeated string retries = 0x3;
}
message OpenGraphScrobble {
optional int32 create_delay = 0x1;
}
message OpenGraphConfig {
optional OpenGraphError error = 0x1;
optional OpenGraphScrobble scrobble = 0x2;
}
message AuthConfig {
optional string url = 0x1;
repeated string permissions = 0x2;
repeated string blacklist = 0x3;
repeated string whitelist = 0x4;
repeated string cancel = 0x5;
}
message ConfigReply {
optional string domain = 0x1;
optional string app_id = 0x2;
optional string app_namespace = 0x3;
optional AuthConfig auth = 0x4;
optional OpenGraphConfig og = 0x5;
}
message UserFields {
optional bool app_user = 0x1;
optional bool display_name = 0x2;
optional bool first_name = 0x3;
optional bool middle_name = 0x4;
optional bool last_name = 0x5;
optional bool picture_large = 0x6;
optional bool picture_square = 0x7;
optional bool gender = 0x8;
optional bool email = 0x9;
}
message UserOptions {
optional bool cache_is_king = 0x1;
}
message UserRequest {
optional UserOptions options = 0x1;
optional UserFields fields = 0x2;
}
message User {
optional string spotify_username = 0x1;
optional string facebook_uid = 0x2;
optional bool app_user = 0x3;
optional string display_name = 0x4;
optional string first_name = 0x5;
optional string middle_name = 0x6;
optional string last_name = 0x7;
optional string picture_large = 0x8;
optional string picture_square = 0x9;
optional string gender = 0xa;
optional string email = 0xb;
}
message FriendsFields {
optional bool app_user = 0x1;
optional bool display_name = 0x2;
optional bool picture_large = 0x6;
}
message FriendsOptions {
optional int32 limit = 0x1;
optional int32 offset = 0x2;
optional bool cache_is_king = 0x3;
optional bool app_friends = 0x4;
optional bool non_app_friends = 0x5;
}
message FriendsRequest {
optional FriendsOptions options = 0x1;
optional FriendsFields fields = 0x2;
}
message FriendsReply {
repeated User friends = 0x1;
optional bool more = 0x2;
}
message ShareRequest {
optional Credential credential = 0x1;
optional string uri = 0x2;
optional string message_text = 0x3;
}
message ShareReply {
optional string post_id = 0x1;
}
message InboxRequest {
optional Credential credential = 0x1;
repeated string facebook_uids = 0x3;
optional string message_text = 0x4;
optional string message_link = 0x5;
}
message InboxReply {
optional string message_id = 0x1;
optional string thread_id = 0x2;
}
message PermissionsOptions {
optional bool cache_is_king = 0x1;
}
message PermissionsRequest {
optional Credential credential = 0x1;
optional PermissionsOptions options = 0x2;
}
message PermissionsReply {
repeated string permissions = 0x1;
}
message GrantPermissionsRequest {
optional Credential credential = 0x1;
repeated string permissions = 0x2;
}
message GrantPermissionsReply {
repeated string granted = 0x1;
repeated string failed = 0x2;
}
message TransferRequest {
optional Credential credential = 0x1;
optional string source_username = 0x2;
optional string target_username = 0x3;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
syntax = "proto2";
message ClientHello {
required BuildInfo build_info = 0xa;
repeated Fingerprint fingerprints_supported = 0x14;
repeated Cryptosuite cryptosuites_supported = 0x1e;
repeated Powscheme powschemes_supported = 0x28;
required LoginCryptoHelloUnion login_crypto_hello = 0x32;
required bytes client_nonce = 0x3c;
optional bytes padding = 0x46;
optional FeatureSet feature_set = 0x50;
}
message BuildInfo {
required Product product = 0xa;
repeated ProductFlags product_flags = 0x14;
required Platform platform = 0x1e;
required uint64 version = 0x28;
}
enum Product {
PRODUCT_CLIENT = 0x0;
PRODUCT_LIBSPOTIFY= 0x1;
PRODUCT_MOBILE = 0x2;
PRODUCT_PARTNER = 0x3;
PRODUCT_LIBSPOTIFY_EMBEDDED = 0x5;
}
enum ProductFlags {
PRODUCT_FLAG_NONE = 0x0;
PRODUCT_FLAG_DEV_BUILD = 0x1;
}
enum Platform {
PLATFORM_WIN32_X86 = 0x0;
PLATFORM_OSX_X86 = 0x1;
PLATFORM_LINUX_X86 = 0x2;
PLATFORM_IPHONE_ARM = 0x3;
PLATFORM_S60_ARM = 0x4;
PLATFORM_OSX_PPC = 0x5;
PLATFORM_ANDROID_ARM = 0x6;
PLATFORM_WINDOWS_CE_ARM = 0x7;
PLATFORM_LINUX_X86_64 = 0x8;
PLATFORM_OSX_X86_64 = 0x9;
PLATFORM_PALM_ARM = 0xa;
PLATFORM_LINUX_SH = 0xb;
PLATFORM_FREEBSD_X86 = 0xc;
PLATFORM_FREEBSD_X86_64 = 0xd;
PLATFORM_BLACKBERRY_ARM = 0xe;
PLATFORM_SONOS = 0xf;
PLATFORM_LINUX_MIPS = 0x10;
PLATFORM_LINUX_ARM = 0x11;
PLATFORM_LOGITECH_ARM = 0x12;
PLATFORM_LINUX_BLACKFIN = 0x13;
PLATFORM_WP7_ARM = 0x14;
PLATFORM_ONKYO_ARM = 0x15;
PLATFORM_QNXNTO_ARM = 0x16;
PLATFORM_BCO_ARM = 0x17;
}
enum Fingerprint {
FINGERPRINT_GRAIN = 0x0;
FINGERPRINT_HMAC_RIPEMD = 0x1;
}
enum Cryptosuite {
CRYPTO_SUITE_SHANNON = 0x0;
CRYPTO_SUITE_RC4_SHA1_HMAC = 0x1;
}
enum Powscheme {
POW_HASH_CASH = 0x0;
}
message LoginCryptoHelloUnion {
optional LoginCryptoDiffieHellmanHello diffie_hellman = 0xa;
}
message LoginCryptoDiffieHellmanHello {
required bytes gc = 0xa;
required uint32 server_keys_known = 0x14;
}
message FeatureSet {
optional bool autoupdate2 = 0x1;
optional bool current_location = 0x2;
}
message APResponseMessage {
optional APChallenge challenge = 0xa;
optional UpgradeRequiredMessage upgrade = 0x14;
optional APLoginFailed login_failed = 0x1e;
}
message APChallenge {
required LoginCryptoChallengeUnion login_crypto_challenge = 0xa;
required FingerprintChallengeUnion fingerprint_challenge = 0x14;
required PoWChallengeUnion pow_challenge = 0x1e;
required CryptoChallengeUnion crypto_challenge = 0x28;
required bytes server_nonce = 0x32;
optional bytes padding = 0x3c;
}
message LoginCryptoChallengeUnion {
optional LoginCryptoDiffieHellmanChallenge diffie_hellman = 0xa;
}
message LoginCryptoDiffieHellmanChallenge {
required bytes gs = 0xa;
required int32 server_signature_key = 0x14;
required bytes gs_signature = 0x1e;
}
message FingerprintChallengeUnion {
optional FingerprintGrainChallenge grain = 0xa;
optional FingerprintHmacRipemdChallenge hmac_ripemd = 0x14;
}
message FingerprintGrainChallenge {
required bytes kek = 0xa;
}
message FingerprintHmacRipemdChallenge {
required bytes challenge = 0xa;
}
message PoWChallengeUnion {
optional PoWHashCashChallenge hash_cash = 0xa;
}
message PoWHashCashChallenge {
optional bytes prefix = 0xa;
optional int32 length = 0x14;
optional int32 target = 0x1e;
}
message CryptoChallengeUnion {
optional CryptoShannonChallenge shannon = 0xa;
optional CryptoRc4Sha1HmacChallenge rc4_sha1_hmac = 0x14;
}
message CryptoShannonChallenge {
}
message CryptoRc4Sha1HmacChallenge {
}
message UpgradeRequiredMessage {
required bytes upgrade_signed_part = 0xa;
required bytes signature = 0x14;
optional string http_suffix = 0x1e;
}
message APLoginFailed {
required ErrorCode error_code = 0xa;
optional int32 retry_delay = 0x14;
optional int32 expiry = 0x1e;
optional string error_description = 0x28;
}
enum ErrorCode {
ProtocolError = 0x0;
TryAnotherAP = 0x2;
BadConnectionId = 0x5;
TravelRestriction = 0x9;
PremiumAccountRequired = 0xb;
BadCredentials = 0xc;
CouldNotValidateCredentials = 0xd;
AccountExists = 0xe;
ExtraVerificationRequired = 0xf;
InvalidAppKey = 0x10;
ApplicationBanned = 0x11;
}
message ClientResponsePlaintext {
required LoginCryptoResponseUnion login_crypto_response = 0xa;
required PoWResponseUnion pow_response = 0x14;
required CryptoResponseUnion crypto_response = 0x1e;
}
message LoginCryptoResponseUnion {
optional LoginCryptoDiffieHellmanResponse diffie_hellman = 0xa;
}
message LoginCryptoDiffieHellmanResponse {
required bytes hmac = 0xa;
}
message PoWResponseUnion {
optional PoWHashCashResponse hash_cash = 0xa;
}
message PoWHashCashResponse {
required bytes hash_suffix = 0xa;
}
message CryptoResponseUnion {
optional CryptoShannonResponse shannon = 0xa;
optional CryptoRc4Sha1HmacResponse rc4_sha1_hmac = 0x14;
}
message CryptoShannonResponse {
optional int32 dummy = 0x1;
}
message CryptoRc4Sha1HmacResponse {
optional int32 dummy = 0x1;
}

View File

@ -0,0 +1,720 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: proto/mercury.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "mercury.pb-c.h"
void mercury_multi_get_request__init
(MercuryMultiGetRequest *message)
{
static const MercuryMultiGetRequest init_value = MERCURY_MULTI_GET_REQUEST__INIT;
*message = init_value;
}
size_t mercury_multi_get_request__get_packed_size
(const MercuryMultiGetRequest *message)
{
assert(message->base.descriptor == &mercury_multi_get_request__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t mercury_multi_get_request__pack
(const MercuryMultiGetRequest *message,
uint8_t *out)
{
assert(message->base.descriptor == &mercury_multi_get_request__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t mercury_multi_get_request__pack_to_buffer
(const MercuryMultiGetRequest *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &mercury_multi_get_request__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
MercuryMultiGetRequest *
mercury_multi_get_request__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (MercuryMultiGetRequest *)
protobuf_c_message_unpack (&mercury_multi_get_request__descriptor,
allocator, len, data);
}
void mercury_multi_get_request__free_unpacked
(MercuryMultiGetRequest *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &mercury_multi_get_request__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void mercury_multi_get_reply__init
(MercuryMultiGetReply *message)
{
static const MercuryMultiGetReply init_value = MERCURY_MULTI_GET_REPLY__INIT;
*message = init_value;
}
size_t mercury_multi_get_reply__get_packed_size
(const MercuryMultiGetReply *message)
{
assert(message->base.descriptor == &mercury_multi_get_reply__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t mercury_multi_get_reply__pack
(const MercuryMultiGetReply *message,
uint8_t *out)
{
assert(message->base.descriptor == &mercury_multi_get_reply__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t mercury_multi_get_reply__pack_to_buffer
(const MercuryMultiGetReply *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &mercury_multi_get_reply__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
MercuryMultiGetReply *
mercury_multi_get_reply__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (MercuryMultiGetReply *)
protobuf_c_message_unpack (&mercury_multi_get_reply__descriptor,
allocator, len, data);
}
void mercury_multi_get_reply__free_unpacked
(MercuryMultiGetReply *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &mercury_multi_get_reply__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void mercury_request__init
(MercuryRequest *message)
{
static const MercuryRequest init_value = MERCURY_REQUEST__INIT;
*message = init_value;
}
size_t mercury_request__get_packed_size
(const MercuryRequest *message)
{
assert(message->base.descriptor == &mercury_request__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t mercury_request__pack
(const MercuryRequest *message,
uint8_t *out)
{
assert(message->base.descriptor == &mercury_request__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t mercury_request__pack_to_buffer
(const MercuryRequest *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &mercury_request__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
MercuryRequest *
mercury_request__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (MercuryRequest *)
protobuf_c_message_unpack (&mercury_request__descriptor,
allocator, len, data);
}
void mercury_request__free_unpacked
(MercuryRequest *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &mercury_request__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void mercury_reply__init
(MercuryReply *message)
{
static const MercuryReply init_value = MERCURY_REPLY__INIT;
*message = init_value;
}
size_t mercury_reply__get_packed_size
(const MercuryReply *message)
{
assert(message->base.descriptor == &mercury_reply__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t mercury_reply__pack
(const MercuryReply *message,
uint8_t *out)
{
assert(message->base.descriptor == &mercury_reply__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t mercury_reply__pack_to_buffer
(const MercuryReply *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &mercury_reply__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
MercuryReply *
mercury_reply__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (MercuryReply *)
protobuf_c_message_unpack (&mercury_reply__descriptor,
allocator, len, data);
}
void mercury_reply__free_unpacked
(MercuryReply *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &mercury_reply__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void header__init
(Header *message)
{
static const Header init_value = HEADER__INIT;
*message = init_value;
}
size_t header__get_packed_size
(const Header *message)
{
assert(message->base.descriptor == &header__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t header__pack
(const Header *message,
uint8_t *out)
{
assert(message->base.descriptor == &header__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t header__pack_to_buffer
(const Header *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &header__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
Header *
header__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Header *)
protobuf_c_message_unpack (&header__descriptor,
allocator, len, data);
}
void header__free_unpacked
(Header *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &header__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void user_field__init
(UserField *message)
{
static const UserField init_value = USER_FIELD__INIT;
*message = init_value;
}
size_t user_field__get_packed_size
(const UserField *message)
{
assert(message->base.descriptor == &user_field__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t user_field__pack
(const UserField *message,
uint8_t *out)
{
assert(message->base.descriptor == &user_field__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t user_field__pack_to_buffer
(const UserField *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &user_field__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
UserField *
user_field__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (UserField *)
protobuf_c_message_unpack (&user_field__descriptor,
allocator, len, data);
}
void user_field__free_unpacked
(UserField *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &user_field__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor mercury_multi_get_request__field_descriptors[1] =
{
{
"request",
1,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(MercuryMultiGetRequest, n_request),
offsetof(MercuryMultiGetRequest, request),
&mercury_request__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned mercury_multi_get_request__field_indices_by_name[] = {
0, /* field[0] = request */
};
static const ProtobufCIntRange mercury_multi_get_request__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor mercury_multi_get_request__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"MercuryMultiGetRequest",
"MercuryMultiGetRequest",
"MercuryMultiGetRequest",
"",
sizeof(MercuryMultiGetRequest),
1,
mercury_multi_get_request__field_descriptors,
mercury_multi_get_request__field_indices_by_name,
1, mercury_multi_get_request__number_ranges,
(ProtobufCMessageInit) mercury_multi_get_request__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor mercury_multi_get_reply__field_descriptors[1] =
{
{
"reply",
1,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(MercuryMultiGetReply, n_reply),
offsetof(MercuryMultiGetReply, reply),
&mercury_reply__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned mercury_multi_get_reply__field_indices_by_name[] = {
0, /* field[0] = reply */
};
static const ProtobufCIntRange mercury_multi_get_reply__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor mercury_multi_get_reply__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"MercuryMultiGetReply",
"MercuryMultiGetReply",
"MercuryMultiGetReply",
"",
sizeof(MercuryMultiGetReply),
1,
mercury_multi_get_reply__field_descriptors,
mercury_multi_get_reply__field_indices_by_name,
1, mercury_multi_get_reply__number_ranges,
(ProtobufCMessageInit) mercury_multi_get_reply__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor mercury_request__field_descriptors[4] =
{
{
"uri",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(MercuryRequest, uri),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"content_type",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(MercuryRequest, content_type),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"body",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(MercuryRequest, has_body),
offsetof(MercuryRequest, body),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"etag",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(MercuryRequest, has_etag),
offsetof(MercuryRequest, etag),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned mercury_request__field_indices_by_name[] = {
2, /* field[2] = body */
1, /* field[1] = content_type */
3, /* field[3] = etag */
0, /* field[0] = uri */
};
static const ProtobufCIntRange mercury_request__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 4 }
};
const ProtobufCMessageDescriptor mercury_request__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"MercuryRequest",
"MercuryRequest",
"MercuryRequest",
"",
sizeof(MercuryRequest),
4,
mercury_request__field_descriptors,
mercury_request__field_indices_by_name,
1, mercury_request__number_ranges,
(ProtobufCMessageInit) mercury_request__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCEnumValue mercury_reply__cache_policy__enum_values_by_number[3] =
{
{ "CACHE_NO", "MERCURY_REPLY__CACHE_POLICY__CACHE_NO", 1 },
{ "CACHE_PRIVATE", "MERCURY_REPLY__CACHE_POLICY__CACHE_PRIVATE", 2 },
{ "CACHE_PUBLIC", "MERCURY_REPLY__CACHE_POLICY__CACHE_PUBLIC", 3 },
};
static const ProtobufCIntRange mercury_reply__cache_policy__value_ranges[] = {
{1, 0},{0, 3}
};
static const ProtobufCEnumValueIndex mercury_reply__cache_policy__enum_values_by_name[3] =
{
{ "CACHE_NO", 0 },
{ "CACHE_PRIVATE", 1 },
{ "CACHE_PUBLIC", 2 },
};
const ProtobufCEnumDescriptor mercury_reply__cache_policy__descriptor =
{
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
"MercuryReply.CachePolicy",
"CachePolicy",
"MercuryReply__CachePolicy",
"",
3,
mercury_reply__cache_policy__enum_values_by_number,
3,
mercury_reply__cache_policy__enum_values_by_name,
1,
mercury_reply__cache_policy__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};
static const ProtobufCFieldDescriptor mercury_reply__field_descriptors[7] =
{
{
"status_code",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_SINT32,
offsetof(MercuryReply, has_status_code),
offsetof(MercuryReply, status_code),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"status_message",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(MercuryReply, status_message),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cache_policy",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_ENUM,
offsetof(MercuryReply, has_cache_policy),
offsetof(MercuryReply, cache_policy),
&mercury_reply__cache_policy__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"ttl",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_SINT32,
offsetof(MercuryReply, has_ttl),
offsetof(MercuryReply, ttl),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"etag",
5,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(MercuryReply, has_etag),
offsetof(MercuryReply, etag),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"content_type",
6,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(MercuryReply, content_type),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"body",
7,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(MercuryReply, has_body),
offsetof(MercuryReply, body),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned mercury_reply__field_indices_by_name[] = {
6, /* field[6] = body */
2, /* field[2] = cache_policy */
5, /* field[5] = content_type */
4, /* field[4] = etag */
0, /* field[0] = status_code */
1, /* field[1] = status_message */
3, /* field[3] = ttl */
};
static const ProtobufCIntRange mercury_reply__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 7 }
};
const ProtobufCMessageDescriptor mercury_reply__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"MercuryReply",
"MercuryReply",
"MercuryReply",
"",
sizeof(MercuryReply),
7,
mercury_reply__field_descriptors,
mercury_reply__field_indices_by_name,
1, mercury_reply__number_ranges,
(ProtobufCMessageInit) mercury_reply__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor header__field_descriptors[5] =
{
{
"uri",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(Header, uri),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"content_type",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(Header, content_type),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"method",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(Header, method),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"status_code",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_SINT32,
offsetof(Header, has_status_code),
offsetof(Header, status_code),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"user_fields",
6,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(Header, n_user_fields),
offsetof(Header, user_fields),
&user_field__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned header__field_indices_by_name[] = {
1, /* field[1] = content_type */
2, /* field[2] = method */
3, /* field[3] = status_code */
0, /* field[0] = uri */
4, /* field[4] = user_fields */
};
static const ProtobufCIntRange header__number_ranges[2 + 1] =
{
{ 1, 0 },
{ 6, 4 },
{ 0, 5 }
};
const ProtobufCMessageDescriptor header__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"Header",
"Header",
"Header",
"",
sizeof(Header),
5,
header__field_descriptors,
header__field_indices_by_name,
2, header__number_ranges,
(ProtobufCMessageInit) header__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor user_field__field_descriptors[2] =
{
{
"key",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(UserField, key),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"value",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(UserField, has_value),
offsetof(UserField, value),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned user_field__field_indices_by_name[] = {
0, /* field[0] = key */
1, /* field[1] = value */
};
static const ProtobufCIntRange user_field__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor user_field__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"UserField",
"UserField",
"UserField",
"",
sizeof(UserField),
2,
user_field__field_descriptors,
user_field__field_indices_by_name,
1, user_field__number_ranges,
(ProtobufCMessageInit) user_field__init,
NULL,NULL,NULL /* reserved[123] */
};

View File

@ -0,0 +1,274 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: proto/mercury.proto */
#ifndef PROTOBUF_C_proto_2fmercury_2eproto__INCLUDED
#define PROTOBUF_C_proto_2fmercury_2eproto__INCLUDED
#include <protobuf-c/protobuf-c.h>
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
typedef struct _MercuryMultiGetRequest MercuryMultiGetRequest;
typedef struct _MercuryMultiGetReply MercuryMultiGetReply;
typedef struct _MercuryRequest MercuryRequest;
typedef struct _MercuryReply MercuryReply;
typedef struct _Header Header;
typedef struct _UserField UserField;
/* --- enums --- */
typedef enum _MercuryReply__CachePolicy {
MERCURY_REPLY__CACHE_POLICY__CACHE_NO = 1,
MERCURY_REPLY__CACHE_POLICY__CACHE_PRIVATE = 2,
MERCURY_REPLY__CACHE_POLICY__CACHE_PUBLIC = 3
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(MERCURY_REPLY__CACHE_POLICY)
} MercuryReply__CachePolicy;
/* --- messages --- */
struct _MercuryMultiGetRequest
{
ProtobufCMessage base;
size_t n_request;
MercuryRequest **request;
};
#define MERCURY_MULTI_GET_REQUEST__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&mercury_multi_get_request__descriptor) \
, 0,NULL }
struct _MercuryMultiGetReply
{
ProtobufCMessage base;
size_t n_reply;
MercuryReply **reply;
};
#define MERCURY_MULTI_GET_REPLY__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&mercury_multi_get_reply__descriptor) \
, 0,NULL }
struct _MercuryRequest
{
ProtobufCMessage base;
char *uri;
char *content_type;
protobuf_c_boolean has_body;
ProtobufCBinaryData body;
protobuf_c_boolean has_etag;
ProtobufCBinaryData etag;
};
#define MERCURY_REQUEST__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&mercury_request__descriptor) \
, NULL, NULL, 0, {0,NULL}, 0, {0,NULL} }
struct _MercuryReply
{
ProtobufCMessage base;
protobuf_c_boolean has_status_code;
int32_t status_code;
char *status_message;
protobuf_c_boolean has_cache_policy;
MercuryReply__CachePolicy cache_policy;
protobuf_c_boolean has_ttl;
int32_t ttl;
protobuf_c_boolean has_etag;
ProtobufCBinaryData etag;
char *content_type;
protobuf_c_boolean has_body;
ProtobufCBinaryData body;
};
#define MERCURY_REPLY__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&mercury_reply__descriptor) \
, 0, 0, NULL, 0, MERCURY_REPLY__CACHE_POLICY__CACHE_NO, 0, 0, 0, {0,NULL}, NULL, 0, {0,NULL} }
struct _Header
{
ProtobufCMessage base;
char *uri;
char *content_type;
char *method;
protobuf_c_boolean has_status_code;
int32_t status_code;
size_t n_user_fields;
UserField **user_fields;
};
#define HEADER__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&header__descriptor) \
, NULL, NULL, NULL, 0, 0, 0,NULL }
struct _UserField
{
ProtobufCMessage base;
char *key;
protobuf_c_boolean has_value;
ProtobufCBinaryData value;
};
#define USER_FIELD__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&user_field__descriptor) \
, NULL, 0, {0,NULL} }
/* MercuryMultiGetRequest methods */
void mercury_multi_get_request__init
(MercuryMultiGetRequest *message);
size_t mercury_multi_get_request__get_packed_size
(const MercuryMultiGetRequest *message);
size_t mercury_multi_get_request__pack
(const MercuryMultiGetRequest *message,
uint8_t *out);
size_t mercury_multi_get_request__pack_to_buffer
(const MercuryMultiGetRequest *message,
ProtobufCBuffer *buffer);
MercuryMultiGetRequest *
mercury_multi_get_request__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void mercury_multi_get_request__free_unpacked
(MercuryMultiGetRequest *message,
ProtobufCAllocator *allocator);
/* MercuryMultiGetReply methods */
void mercury_multi_get_reply__init
(MercuryMultiGetReply *message);
size_t mercury_multi_get_reply__get_packed_size
(const MercuryMultiGetReply *message);
size_t mercury_multi_get_reply__pack
(const MercuryMultiGetReply *message,
uint8_t *out);
size_t mercury_multi_get_reply__pack_to_buffer
(const MercuryMultiGetReply *message,
ProtobufCBuffer *buffer);
MercuryMultiGetReply *
mercury_multi_get_reply__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void mercury_multi_get_reply__free_unpacked
(MercuryMultiGetReply *message,
ProtobufCAllocator *allocator);
/* MercuryRequest methods */
void mercury_request__init
(MercuryRequest *message);
size_t mercury_request__get_packed_size
(const MercuryRequest *message);
size_t mercury_request__pack
(const MercuryRequest *message,
uint8_t *out);
size_t mercury_request__pack_to_buffer
(const MercuryRequest *message,
ProtobufCBuffer *buffer);
MercuryRequest *
mercury_request__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void mercury_request__free_unpacked
(MercuryRequest *message,
ProtobufCAllocator *allocator);
/* MercuryReply methods */
void mercury_reply__init
(MercuryReply *message);
size_t mercury_reply__get_packed_size
(const MercuryReply *message);
size_t mercury_reply__pack
(const MercuryReply *message,
uint8_t *out);
size_t mercury_reply__pack_to_buffer
(const MercuryReply *message,
ProtobufCBuffer *buffer);
MercuryReply *
mercury_reply__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void mercury_reply__free_unpacked
(MercuryReply *message,
ProtobufCAllocator *allocator);
/* Header methods */
void header__init
(Header *message);
size_t header__get_packed_size
(const Header *message);
size_t header__pack
(const Header *message,
uint8_t *out);
size_t header__pack_to_buffer
(const Header *message,
ProtobufCBuffer *buffer);
Header *
header__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void header__free_unpacked
(Header *message,
ProtobufCAllocator *allocator);
/* UserField methods */
void user_field__init
(UserField *message);
size_t user_field__get_packed_size
(const UserField *message);
size_t user_field__pack
(const UserField *message,
uint8_t *out);
size_t user_field__pack_to_buffer
(const UserField *message,
ProtobufCBuffer *buffer);
UserField *
user_field__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void user_field__free_unpacked
(UserField *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*MercuryMultiGetRequest_Closure)
(const MercuryMultiGetRequest *message,
void *closure_data);
typedef void (*MercuryMultiGetReply_Closure)
(const MercuryMultiGetReply *message,
void *closure_data);
typedef void (*MercuryRequest_Closure)
(const MercuryRequest *message,
void *closure_data);
typedef void (*MercuryReply_Closure)
(const MercuryReply *message,
void *closure_data);
typedef void (*Header_Closure)
(const Header *message,
void *closure_data);
typedef void (*UserField_Closure)
(const UserField *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCMessageDescriptor mercury_multi_get_request__descriptor;
extern const ProtobufCMessageDescriptor mercury_multi_get_reply__descriptor;
extern const ProtobufCMessageDescriptor mercury_request__descriptor;
extern const ProtobufCMessageDescriptor mercury_reply__descriptor;
extern const ProtobufCEnumDescriptor mercury_reply__cache_policy__descriptor;
extern const ProtobufCMessageDescriptor header__descriptor;
extern const ProtobufCMessageDescriptor user_field__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_proto_2fmercury_2eproto__INCLUDED */

View File

@ -0,0 +1,46 @@
syntax = "proto2";
message MercuryMultiGetRequest {
repeated MercuryRequest request = 0x1;
}
message MercuryMultiGetReply {
repeated MercuryReply reply = 0x1;
}
message MercuryRequest {
optional string uri = 0x1;
optional string content_type = 0x2;
optional bytes body = 0x3;
optional bytes etag = 0x4;
}
message MercuryReply {
optional sint32 status_code = 0x1;
optional string status_message = 0x2;
optional CachePolicy cache_policy = 0x3;
enum CachePolicy {
CACHE_NO = 0x1;
CACHE_PRIVATE = 0x2;
CACHE_PUBLIC = 0x3;
}
optional sint32 ttl = 0x4;
optional bytes etag = 0x5;
optional string content_type = 0x6;
optional bytes body = 0x7;
}
message Header {
optional string uri = 0x01;
optional string content_type = 0x02;
optional string method = 0x03;
optional sint32 status_code = 0x04;
repeated UserField user_fields = 0x06;
}
message UserField {
optional string key = 0x01;
optional bytes value = 0x02;
}

View File

@ -0,0 +1,10 @@
syntax = "proto2";
message MergedProfileRequest {
}
message MergedProfileReply {
optional string username = 0x1;
optional string artistid = 0x2;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,266 @@
syntax = "proto2";
message TopTracks {
optional string country = 0x1;
repeated Track track = 0x2;
}
message ActivityPeriod {
optional sint32 start_year = 0x1;
optional sint32 end_year = 0x2;
optional sint32 decade = 0x3;
}
message Artist {
optional bytes gid = 0x1;
optional string name = 0x2;
optional sint32 popularity = 0x3;
repeated TopTracks top_track = 0x4;
repeated AlbumGroup album_group = 0x5;
repeated AlbumGroup single_group = 0x6;
repeated AlbumGroup compilation_group = 0x7;
repeated AlbumGroup appears_on_group = 0x8;
repeated string genre = 0x9;
repeated ExternalId external_id = 0xa;
repeated Image portrait = 0xb;
repeated Biography biography = 0xc;
repeated ActivityPeriod activity_period = 0xd;
repeated Restriction restriction = 0xe;
repeated Artist related = 0xf;
optional bool is_portrait_album_cover = 0x10;
optional ImageGroup portrait_group = 0x11;
}
message AlbumGroup {
repeated Album album = 0x1;
}
message Date {
optional sint32 year = 0x1;
optional sint32 month = 0x2;
optional sint32 day = 0x3;
optional sint32 hour = 0x4;
optional sint32 minute = 0x5;
}
message Album {
optional bytes gid = 0x1;
optional string name = 0x2;
repeated Artist artist = 0x3;
optional Type typ = 0x4;
enum Type {
ALBUM = 0x1;
SINGLE = 0x2;
COMPILATION = 0x3;
EP = 0x4;
}
optional string label = 0x5;
optional Date date = 0x6;
optional sint32 popularity = 0x7;
repeated string genre = 0x8;
repeated Image cover = 0x9;
repeated ExternalId external_id = 0xa;
repeated Disc disc = 0xb;
repeated string review = 0xc;
repeated Copyright copyright = 0xd;
repeated Restriction restriction = 0xe;
repeated Album related = 0xf;
repeated SalePeriod sale_period = 0x10;
optional ImageGroup cover_group = 0x11;
}
message Track {
optional bytes gid = 0x1;
optional string name = 0x2;
optional Album album = 0x3;
repeated Artist artist = 0x4;
optional sint32 number = 0x5;
optional sint32 disc_number = 0x6;
optional sint32 duration = 0x7;
optional sint32 popularity = 0x8;
optional bool explicit = 0x9;
repeated ExternalId external_id = 0xa;
repeated Restriction restriction = 0xb;
repeated AudioFile file = 0xc;
repeated Track alternative = 0xd;
repeated SalePeriod sale_period = 0xe;
repeated AudioFile preview = 0xf;
}
message Image {
optional bytes file_id = 0x1;
optional Size size = 0x2;
enum Size {
DEFAULT = 0x0;
SMALL = 0x1;
LARGE = 0x2;
XLARGE = 0x3;
}
optional sint32 width = 0x3;
optional sint32 height = 0x4;
}
message ImageGroup {
repeated Image image = 0x1;
}
message Biography {
optional string text = 0x1;
repeated Image portrait = 0x2;
repeated ImageGroup portrait_group = 0x3;
}
message Disc {
optional sint32 number = 0x1;
optional string name = 0x2;
repeated Track track = 0x3;
}
message Copyright {
optional Type typ = 0x1;
enum Type {
P = 0x0;
C = 0x1;
}
optional string text = 0x2;
}
message Restriction {
enum Catalogue {
AD = 0;
SUBSCRIPTION = 1;
CATALOGUE_ALL = 2;
SHUFFLE = 3;
COMMERCIAL = 4;
}
enum Type {
STREAMING = 0x0;
}
repeated Catalogue catalogue = 0x1;
optional string countries_allowed = 0x2;
optional string countries_forbidden = 0x3;
optional Type typ = 0x4;
repeated string catalogue_str = 0x5;
}
message Availability {
repeated string catalogue_str = 0x1;
optional Date start = 0x2;
}
message SalePeriod {
repeated Restriction restriction = 0x1;
optional Date start = 0x2;
optional Date end = 0x3;
}
message ExternalId {
optional string typ = 0x1;
optional string id = 0x2;
}
message AudioFile {
optional bytes file_id = 0x1;
optional Format format = 0x2;
enum Format {
OGG_VORBIS_96 = 0x0;
OGG_VORBIS_160 = 0x1;
OGG_VORBIS_320 = 0x2;
MP3_256 = 0x3;
MP3_320 = 0x4;
MP3_160 = 0x5;
MP3_96 = 0x6;
MP3_160_ENC = 0x7;
// v4
// AAC_24 = 0x8;
// AAC_48 = 0x9;
MP4_128_DUAL = 0x8;
OTHER3 = 0x9;
AAC_160 = 0xa;
AAC_320 = 0xb;
MP4_128 = 0xc;
OTHER5 = 0xd;
}
}
message VideoFile {
optional bytes file_id = 1;
}
// Podcast Protos
message Show {
enum MediaType {
MIXED = 0;
AUDIO = 1;
VIDEO = 2;
}
enum ConsumptionOrder {
SEQUENTIAL = 1;
EPISODIC = 2;
RECENT = 3;
}
enum PassthroughEnum {
UNKNOWN = 0;
NONE = 1;
ALLOWED = 2;
}
optional bytes gid = 0x1;
optional string name = 0x2;
optional string description = 0x40;
optional sint32 deprecated_popularity = 0x41;
optional string publisher = 0x42;
optional string language = 0x43;
optional bool explicit = 0x44;
optional ImageGroup covers = 0x45;
repeated Episode episode = 0x46;
repeated Copyright copyright = 0x47;
repeated Restriction restriction = 0x48;
repeated string keyword = 0x49;
optional MediaType media_type = 0x4A;
optional ConsumptionOrder consumption_order = 0x4B;
optional bool interpret_restriction_using_geoip = 0x4C;
repeated Availability availability = 0x4E;
optional string country_of_origin = 0x4F;
repeated Category categories = 0x50;
optional PassthroughEnum passthrough = 0x51;
}
message Episode {
optional bytes gid = 0x1;
optional string name = 0x2;
optional sint32 duration = 0x7;
optional sint32 popularity = 0x8;
repeated AudioFile file = 0xc;
optional string description = 0x40;
optional sint32 number = 0x41;
optional Date publish_time = 0x42;
optional sint32 deprecated_popularity = 0x43;
optional ImageGroup covers = 0x44;
optional string language = 0x45;
optional bool explicit = 0x46;
optional Show show = 0x47;
repeated VideoFile video = 0x48;
repeated VideoFile video_preview = 0x49;
repeated AudioFile audio_preview = 0x4A;
repeated Restriction restriction = 0x4B;
optional ImageGroup freeze_frame = 0x4C;
repeated string keyword = 0x4D;
// Order of these two flags might be wrong!
optional bool suppress_monetization = 0x4E;
optional bool interpret_restriction_using_geoip = 0x4F;
optional bool allow_background_playback = 0x51;
repeated Availability availability = 0x52;
optional string external_url = 0x53;
optional OriginalAudio original_audio = 0x54;
}
message Category {
optional string name = 0x1;
repeated Category subcategories = 0x2;
}
message OriginalAudio {
optional bytes uuid = 0x1;
}

View File

@ -0,0 +1,87 @@
syntax = "proto2";
import "playlist4ops.proto";
import "playlist4meta.proto";
import "playlist4content.proto";
import "playlist4issues.proto";
message ChangeInfo {
optional string user = 0x1;
optional int32 timestamp = 0x2;
optional bool admin = 0x3;
optional bool undo = 0x4;
optional bool redo = 0x5;
optional bool merge = 0x6;
optional bool compressed = 0x7;
optional bool migration = 0x8;
}
message Delta {
optional bytes base_version = 0x1;
repeated Op ops = 0x2;
optional ChangeInfo info = 0x4;
}
message Merge {
optional bytes base_version = 0x1;
optional bytes merge_version = 0x2;
optional ChangeInfo info = 0x4;
}
message ChangeSet {
optional Kind kind = 0x1;
enum Kind {
KIND_UNKNOWN = 0x0;
DELTA = 0x2;
MERGE = 0x3;
}
optional Delta delta = 0x2;
optional Merge merge = 0x3;
}
message RevisionTaggedChangeSet {
optional bytes revision = 0x1;
optional ChangeSet change_set = 0x2;
}
message Diff {
optional bytes from_revision = 0x1;
repeated Op ops = 0x2;
optional bytes to_revision = 0x3;
}
message ListDump {
optional bytes latestRevision = 0x1;
optional int32 length = 0x2;
optional ListAttributes attributes = 0x3;
optional ListChecksum checksum = 0x4;
optional ListItems contents = 0x5;
repeated Delta pendingDeltas = 0x7;
}
message ListChanges {
optional bytes baseRevision = 0x1;
repeated Delta deltas = 0x2;
optional bool wantResultingRevisions = 0x3;
optional bool wantSyncResult = 0x4;
optional ListDump dump = 0x5;
repeated int32 nonces = 0x6;
}
message SelectedListContent {
optional bytes revision = 0x1;
optional int32 length = 0x2;
optional ListAttributes attributes = 0x3;
optional ListChecksum checksum = 0x4;
optional ListItems contents = 0x5;
optional Diff diff = 0x6;
optional Diff syncResult = 0x7;
repeated bytes resultingRevisions = 0x8;
optional bool multipleHeads = 0x9;
optional bool upToDate = 0xa;
repeated ClientResolveAction resolveAction = 0xc;
repeated ClientIssue issues = 0xd;
repeated int32 nonces = 0xe;
optional string owner_username =0x10;
}

View File

@ -0,0 +1,37 @@
syntax = "proto2";
import "playlist4meta.proto";
import "playlist4issues.proto";
message Item {
optional string uri = 0x1;
optional ItemAttributes attributes = 0x2;
}
message ListItems {
optional int32 pos = 0x1;
optional bool truncated = 0x2;
repeated Item items = 0x3;
}
message ContentRange {
optional int32 pos = 0x1;
optional int32 length = 0x2;
}
message ListContentSelection {
optional bool wantRevision = 0x1;
optional bool wantLength = 0x2;
optional bool wantAttributes = 0x3;
optional bool wantChecksum = 0x4;
optional bool wantContent = 0x5;
optional ContentRange contentRange = 0x6;
optional bool wantDiff = 0x7;
optional bytes baseRevision = 0x8;
optional bytes hintRevision = 0x9;
optional bool wantNothingIfUpToDate = 0xa;
optional bool wantResolveAction = 0xc;
repeated ClientIssue issues = 0xd;
repeated ClientResolveAction resolveAction = 0xe;
}

View File

@ -0,0 +1,43 @@
syntax = "proto2";
message ClientIssue {
optional Level level = 0x1;
enum Level {
LEVEL_UNKNOWN = 0x0;
LEVEL_DEBUG = 0x1;
LEVEL_INFO = 0x2;
LEVEL_NOTICE = 0x3;
LEVEL_WARNING = 0x4;
LEVEL_ERROR = 0x5;
}
optional Code code = 0x2;
enum Code {
CODE_UNKNOWN = 0x0;
CODE_INDEX_OUT_OF_BOUNDS = 0x1;
CODE_VERSION_MISMATCH = 0x2;
CODE_CACHED_CHANGE = 0x3;
CODE_OFFLINE_CHANGE = 0x4;
CODE_CONCURRENT_CHANGE = 0x5;
}
optional int32 repeatCount = 0x3;
}
message ClientResolveAction {
optional Code code = 0x1;
enum Code {
CODE_UNKNOWN = 0x0;
CODE_NO_ACTION = 0x1;
CODE_RETRY = 0x2;
CODE_RELOAD = 0x3;
CODE_DISCARD_LOCAL_CHANGES = 0x4;
CODE_SEND_DUMP = 0x5;
CODE_DISPLAY_ERROR_MESSAGE = 0x6;
}
optional Initiator initiator = 0x2;
enum Initiator {
INITIATOR_UNKNOWN = 0x0;
INITIATOR_SERVER = 0x1;
INITIATOR_CLIENT = 0x2;
}
}

View File

@ -0,0 +1,52 @@
syntax = "proto2";
message ListChecksum {
optional int32 version = 0x1;
optional bytes sha1 = 0x4;
}
message DownloadFormat {
optional Codec codec = 0x1;
enum Codec {
CODEC_UNKNOWN = 0x0;
OGG_VORBIS = 0x1;
FLAC = 0x2;
MPEG_1_LAYER_3 = 0x3;
}
}
message ListAttributes {
optional string name = 0x1;
optional string description = 0x2;
optional bytes picture = 0x3;
optional bool collaborative = 0x4;
optional string pl3_version = 0x5;
optional bool deleted_by_owner = 0x6;
optional bool restricted_collaborative = 0x7;
optional int64 deprecated_client_id = 0x8;
optional bool public_starred = 0x9;
optional string client_id = 0xa;
}
message ItemAttributes {
optional string added_by = 0x1;
optional int64 timestamp = 0x2;
optional string message = 0x3;
optional bool seen = 0x4;
optional int64 download_count = 0x5;
optional DownloadFormat download_format = 0x6;
optional string sevendigital_id = 0x7;
optional int64 sevendigital_left = 0x8;
optional int64 seen_at = 0x9;
optional bool public = 0xa;
}
message StringAttribute {
optional string key = 0x1;
optional string value = 0x2;
}
message StringAttributes {
repeated StringAttribute attribute = 0x1;
}

View File

@ -0,0 +1,103 @@
syntax = "proto2";
import "playlist4meta.proto";
import "playlist4content.proto";
message Add {
optional int32 fromIndex = 0x1;
repeated Item items = 0x2;
optional ListChecksum list_checksum = 0x3;
optional bool addLast = 0x4;
optional bool addFirst = 0x5;
}
message Rem {
optional int32 fromIndex = 0x1;
optional int32 length = 0x2;
repeated Item items = 0x3;
optional ListChecksum list_checksum = 0x4;
optional ListChecksum items_checksum = 0x5;
optional ListChecksum uris_checksum = 0x6;
optional bool itemsAsKey = 0x7;
}
message Mov {
optional int32 fromIndex = 0x1;
optional int32 length = 0x2;
optional int32 toIndex = 0x3;
optional ListChecksum list_checksum = 0x4;
optional ListChecksum items_checksum = 0x5;
optional ListChecksum uris_checksum = 0x6;
}
message ItemAttributesPartialState {
optional ItemAttributes values = 0x1;
repeated ItemAttributeKind no_value = 0x2;
enum ItemAttributeKind {
ITEM_UNKNOWN = 0x0;
ITEM_ADDED_BY = 0x1;
ITEM_TIMESTAMP = 0x2;
ITEM_MESSAGE = 0x3;
ITEM_SEEN = 0x4;
ITEM_DOWNLOAD_COUNT = 0x5;
ITEM_DOWNLOAD_FORMAT = 0x6;
ITEM_SEVENDIGITAL_ID = 0x7;
ITEM_SEVENDIGITAL_LEFT = 0x8;
ITEM_SEEN_AT = 0x9;
ITEM_PUBLIC = 0xa;
}
}
message ListAttributesPartialState {
optional ListAttributes values = 0x1;
repeated ListAttributeKind no_value = 0x2;
enum ListAttributeKind {
LIST_UNKNOWN = 0x0;
LIST_NAME = 0x1;
LIST_DESCRIPTION = 0x2;
LIST_PICTURE = 0x3;
LIST_COLLABORATIVE = 0x4;
LIST_PL3_VERSION = 0x5;
LIST_DELETED_BY_OWNER = 0x6;
LIST_RESTRICTED_COLLABORATIVE = 0x7;
}
}
message UpdateItemAttributes {
optional int32 index = 0x1;
optional ItemAttributesPartialState new_attributes = 0x2;
optional ItemAttributesPartialState old_attributes = 0x3;
optional ListChecksum list_checksum = 0x4;
optional ListChecksum old_attributes_checksum = 0x5;
}
message UpdateListAttributes {
optional ListAttributesPartialState new_attributes = 0x1;
optional ListAttributesPartialState old_attributes = 0x2;
optional ListChecksum list_checksum = 0x3;
optional ListChecksum old_attributes_checksum = 0x4;
}
message Op {
optional Kind kind = 0x1;
enum Kind {
KIND_UNKNOWN = 0x0;
ADD = 0x2;
REM = 0x3;
MOV = 0x4;
UPDATE_ITEM_ATTRIBUTES = 0x5;
UPDATE_LIST_ATTRIBUTES = 0x6;
}
optional Add add = 0x2;
optional Rem rem = 0x3;
optional Mov mov = 0x4;
optional UpdateItemAttributes update_item_attributes = 0x5;
optional UpdateListAttributes update_list_attributes = 0x6;
}
message OpList {
repeated Op ops = 0x1;
}

View File

@ -0,0 +1,13 @@
syntax = "proto2";
message PopcountRequest {
}
message PopcountResult {
optional sint64 count = 0x1;
optional bool truncated = 0x2;
repeated string user = 0x3;
repeated sint64 subscriptionTimestamps = 0x4;
repeated sint64 insertionTimestamps = 0x5;
}

View File

@ -0,0 +1,94 @@
syntax = "proto2";
message PlaylistPublishedState {
optional string uri = 0x1;
optional int64 timestamp = 0x2;
}
message PlaylistTrackAddedState {
optional string playlist_uri = 0x1;
optional string track_uri = 0x2;
optional int64 timestamp = 0x3;
}
message TrackFinishedPlayingState {
optional string uri = 0x1;
optional string context_uri = 0x2;
optional int64 timestamp = 0x3;
optional string referrer_uri = 0x4;
}
message FavoriteAppAddedState {
optional string app_uri = 0x1;
optional int64 timestamp = 0x2;
}
message TrackStartedPlayingState {
optional string uri = 0x1;
optional string context_uri = 0x2;
optional int64 timestamp = 0x3;
optional string referrer_uri = 0x4;
}
message UriSharedState {
optional string uri = 0x1;
optional string message = 0x2;
optional int64 timestamp = 0x3;
}
message ArtistFollowedState {
optional string uri = 0x1;
optional string artist_name = 0x2;
optional string artist_cover_uri = 0x3;
optional int64 timestamp = 0x4;
}
message DeviceInformation {
optional string os = 0x1;
optional string type = 0x2;
}
message GenericPresenceState {
optional int32 type = 0x1;
optional int64 timestamp = 0x2;
optional string item_uri = 0x3;
optional string item_name = 0x4;
optional string item_image = 0x5;
optional string context_uri = 0x6;
optional string context_name = 0x7;
optional string context_image = 0x8;
optional string referrer_uri = 0x9;
optional string referrer_name = 0xa;
optional string referrer_image = 0xb;
optional string message = 0xc;
optional DeviceInformation device_information = 0xd;
}
message State {
optional int64 timestamp = 0x1;
optional Type type = 0x2;
enum Type {
PLAYLIST_PUBLISHED = 0x1;
PLAYLIST_TRACK_ADDED = 0x2;
TRACK_FINISHED_PLAYING = 0x3;
FAVORITE_APP_ADDED = 0x4;
TRACK_STARTED_PLAYING = 0x5;
URI_SHARED = 0x6;
ARTIST_FOLLOWED = 0x7;
GENERIC = 0xb;
}
optional string uri = 0x3;
optional PlaylistPublishedState playlist_published = 0x4;
optional PlaylistTrackAddedState playlist_track_added = 0x5;
optional TrackFinishedPlayingState track_finished_playing = 0x6;
optional FavoriteAppAddedState favorite_app_added = 0x7;
optional TrackStartedPlayingState track_started_playing = 0x8;
optional UriSharedState uri_shared = 0x9;
optional ArtistFollowedState artist_followed = 0xa;
optional GenericPresenceState generic = 0xb;
}
message StateList {
repeated State states = 0x1;
}

View File

@ -0,0 +1,8 @@
syntax = "proto2";
message Subscription {
optional string uri = 0x1;
optional int32 expiry = 0x2;
optional int32 status_code = 0x3;
}

View File

@ -0,0 +1,58 @@
syntax = "proto2";
message RadioRequest {
repeated string uris = 0x1;
optional int32 salt = 0x2;
optional int32 length = 0x4;
optional string stationId = 0x5;
repeated string lastTracks = 0x6;
}
message MultiSeedRequest {
repeated string uris = 0x1;
}
message Feedback {
optional string uri = 0x1;
optional string type = 0x2;
optional double timestamp = 0x3;
}
message Tracks {
repeated string gids = 0x1;
optional string source = 0x2;
optional string identity = 0x3;
repeated string tokens = 0x4;
repeated Feedback feedback = 0x5;
}
message Station {
optional string id = 0x1;
optional string title = 0x2;
optional string titleUri = 0x3;
optional string subtitle = 0x4;
optional string subtitleUri = 0x5;
optional string imageUri = 0x6;
optional double lastListen = 0x7;
repeated string seeds = 0x8;
optional int32 thumbsUp = 0x9;
optional int32 thumbsDown = 0xa;
}
message Rules {
optional string js = 0x1;
}
message StationResponse {
optional Station station = 0x1;
repeated Feedback feedback = 0x2;
}
message StationList {
repeated Station stations = 0x1;
}
message LikedPlaylist {
optional string uri = 0x1;
}

View File

@ -0,0 +1,44 @@
syntax = "proto2";
message SearchRequest {
optional string query = 0x1;
optional Type type = 0x2;
enum Type {
TRACK = 0x0;
ALBUM = 0x1;
ARTIST = 0x2;
PLAYLIST = 0x3;
USER = 0x4;
}
optional int32 limit = 0x3;
optional int32 offset = 0x4;
optional bool did_you_mean = 0x5;
optional string spotify_uri = 0x2;
repeated bytes file_id = 0x3;
optional string url = 0x4;
optional string slask_id = 0x5;
}
message Playlist {
optional string uri = 0x1;
optional string name = 0x2;
repeated Image image = 0x3;
}
message User {
optional string username = 0x1;
optional string full_name = 0x2;
repeated Image image = 0x3;
optional sint32 followers = 0x4;
}
message SearchReply {
optional sint32 hits = 0x1;
repeated Track track = 0x2;
repeated Album album = 0x3;
repeated Artist artist = 0x4;
repeated Playlist playlist = 0x5;
optional string did_you_mean = 0x6;
repeated User user = 0x7;
}

View File

@ -0,0 +1,12 @@
syntax = "proto2";
message DecorationData {
optional string username = 0x1;
optional string full_name = 0x2;
optional string image_url = 0x3;
optional string large_image_url = 0x5;
optional string first_name = 0x6;
optional string last_name = 0x7;
optional string facebook_uid = 0x8;
}

View File

@ -0,0 +1,49 @@
syntax = "proto2";
message CountReply {
repeated int32 counts = 0x1;
}
message UserListRequest {
optional string last_result = 0x1;
optional int32 count = 0x2;
optional bool include_length = 0x3;
}
message UserListReply {
repeated User users = 0x1;
optional int32 length = 0x2;
}
message User {
optional string username = 0x1;
optional int32 subscriber_count = 0x2;
optional int32 subscription_count = 0x3;
}
message ArtistListReply {
repeated Artist artists = 0x1;
}
message Artist {
optional string artistid = 0x1;
optional int32 subscriber_count = 0x2;
}
message StringListRequest {
repeated string args = 0x1;
}
message StringListReply {
repeated string reply = 0x1;
}
message TopPlaylistsRequest {
optional string username = 0x1;
optional int32 count = 0x2;
}
message TopPlaylistsReply {
repeated string uris = 0x1;
}

View File

@ -0,0 +1,133 @@
syntax = "proto2";
message Frame {
optional uint32 version = 0x1;
optional string ident = 0x2;
optional string protocol_version = 0x3;
optional uint32 seq_nr = 0x4;
optional MessageType typ = 0x5;
optional DeviceState device_state = 0x7;
optional Goodbye goodbye = 0xb;
optional State state = 0xc;
optional uint32 position = 0xd;
optional uint32 volume = 0xe;
optional int64 state_update_id = 0x11;
repeated string recipient = 0x12;
optional bytes context_player_state = 0x13;
optional string new_name = 0x14;
optional Metadata metadata = 0x19;
}
enum MessageType {
kMessageTypeHello = 0x1;
kMessageTypeGoodbye = 0x2;
kMessageTypeProbe = 0x3;
kMessageTypeNotify = 0xa;
kMessageTypeLoad = 0x14;
kMessageTypePlay = 0x15;
kMessageTypePause = 0x16;
kMessageTypePlayPause = 0x17;
kMessageTypeSeek = 0x18;
kMessageTypePrev = 0x19;
kMessageTypeNext = 0x1a;
kMessageTypeVolume = 0x1b;
kMessageTypeShuffle = 0x1c;
kMessageTypeRepeat = 0x1d;
kMessageTypeVolumeDown = 0x1f;
kMessageTypeVolumeUp = 0x20;
kMessageTypeReplace = 0x21;
kMessageTypeLogout = 0x22;
kMessageTypeAction = 0x23;
kMessageTypeRename = 0x24;
kMessageTypeUpdateMetadata = 0x80;
}
message DeviceState {
optional string sw_version = 0x1;
optional bool is_active = 0xa;
optional bool can_play = 0xb;
optional uint32 volume = 0xc;
optional string name = 0xd;
optional uint32 error_code = 0xe;
optional int64 became_active_at = 0xf;
optional string error_message = 0x10;
repeated Capability capabilities = 0x11;
optional string context_player_error = 0x14;
repeated Metadata metadata = 0x19;
}
message Capability {
optional CapabilityType typ = 0x1;
repeated int64 intValue = 0x2;
repeated string stringValue = 0x3;
}
enum CapabilityType {
kSupportedContexts = 0x1;
kCanBePlayer = 0x2;
kRestrictToLocal = 0x3;
kDeviceType = 0x4;
kGaiaEqConnectId = 0x5;
kSupportsLogout = 0x6;
kIsObservable = 0x7;
kVolumeSteps = 0x8;
kSupportedTypes = 0x9;
kCommandAcks = 0xa;
kSupportsRename = 0xb;
kHidden = 0xc;
kSupportsPlaylistV2 = 0xd;
kSupportsExternalEpisodes = 0xe;
}
message Goodbye {
optional string reason = 0x1;
}
message State {
optional string context_uri = 0x2;
optional uint32 index = 0x3;
optional uint32 position_ms = 0x4;
optional PlayStatus status = 0x5;
optional uint64 position_measured_at = 0x7;
optional string context_description = 0x8;
optional bool shuffle = 0xd;
optional bool repeat = 0xe;
optional string last_command_ident = 0x14;
optional uint32 last_command_msgid = 0x15;
optional bool playing_from_fallback = 0x18;
optional uint32 row = 0x19;
optional uint32 playing_track_index = 0x1a;
repeated TrackRef track = 0x1b;
optional Ad ad = 0x1c;
}
enum PlayStatus {
kPlayStatusStop = 0x0;
kPlayStatusPlay = 0x1;
kPlayStatusPause = 0x2;
kPlayStatusLoading = 0x3;
}
message TrackRef {
optional bytes gid = 0x1;
optional string uri = 0x2;
optional bool queued = 0x3;
optional string context = 0x4;
}
message Ad {
optional int32 next = 0x1;
optional bytes ogg_fid = 0x2;
optional bytes image_fid = 0x3;
optional int32 duration = 0x4;
optional string click_url = 0x5;
optional string impression_url = 0x6;
optional string product = 0x7;
optional string advertiser = 0x8;
optional bytes gid = 0x9;
}
message Metadata {
optional string type = 0x1;
optional string metadata = 0x2;
}

View File

@ -0,0 +1,43 @@
syntax = "proto2";
message Track {
optional bytes gid = 0x1;
optional string name = 0x2;
optional bytes image = 0x3;
repeated string artist_name = 0x4;
repeated bytes artist_gid = 0x5;
optional uint32 rank = 0x6;
}
message Artist {
optional bytes gid = 0x1;
optional string name = 0x2;
optional bytes image = 0x3;
optional uint32 rank = 0x6;
}
message Album {
optional bytes gid = 0x1;
optional string name = 0x2;
optional bytes image = 0x3;
repeated string artist_name = 0x4;
repeated bytes artist_gid = 0x5;
optional uint32 rank = 0x6;
}
message Playlist {
optional string uri = 0x1;
optional string name = 0x2;
optional string image_uri = 0x3;
optional string owner_name = 0x4;
optional string owner_uri = 0x5;
optional uint32 rank = 0x6;
}
message Suggestions {
repeated Track track = 0x1;
repeated Album album = 0x2;
repeated Artist artist = 0x3;
repeated Playlist playlist = 0x4;
}

View File

@ -0,0 +1,6 @@
syntax = "proto2";
message Toplist {
repeated string items = 0x1;
}

View File

@ -0,0 +1,52 @@
/* $Id: $ */
/* Shannon: Shannon stream cipher and MAC header files */
/*
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND AGAINST
INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SHN_DEFINED
#define _SHN_DEFINED 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define SHANNON_N 16
typedef struct {
uint32_t R[SHANNON_N]; /* Working storage for the shift register */
uint32_t CRC[SHANNON_N]; /* Working storage for CRC accumulation */
uint32_t initR[SHANNON_N]; /* saved register contents */
uint32_t konst; /* key dependent semi-constant */
uint32_t sbuf; /* encryption buffer */
uint32_t mbuf; /* partial word MAC buffer */
int nbuf; /* number of part-word stream bits buffered */
} shn_ctx;
/* interface definitions */
void shn_key(shn_ctx *c, const uint8_t key[], int keylen); /* set key */
void shn_nonce(shn_ctx *c, const uint8_t nonce[], int nlen); /* set Init Vector */
void shn_stream(shn_ctx *c, uint8_t *buf, int nbytes); /* stream cipher */
void shn_maconly(shn_ctx *c, uint8_t *buf, int nbytes); /* accumulate MAC */
void shn_encrypt(shn_ctx *c, uint8_t *buf, int nbytes); /* encrypt + MAC */
void shn_decrypt(shn_ctx *c, uint8_t *buf, int nbytes); /* decrypt + MAC */
void shn_finish(shn_ctx *c, uint8_t *buf, int nbytes); /* finalise MAC */
#ifdef __cplusplus
}
#endif
#endif /* _SHN_DEFINED */

View File

@ -0,0 +1,626 @@
/* $Id: shnfast.c 442 2006-05-12 23:22:21Z ggr $ */
/* ShannonFast: Shannon stream cipher and MAC -- fast implementation */
/*
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND AGAINST
INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* interface, multiplication table and SBox */
#include <stdlib.h>
#include <string.h>
#include "ShannonInternal.h"
/*
* FOLD is how many register cycles need to be performed after combining the
* last byte of key and non-linear feedback, before every byte depends on every
* byte of the key. This depends on the feedback and nonlinear functions, and
* on where they are combined into the register. Making it same as the
* register length is a safe and conservative choice.
*/
#define FOLD N /* how many iterations of folding to do */
#define INITKONST 0x6996c53a /* value of KONST to use during key loading */
#define KEYP 13 /* where to insert key/MAC words */
#define Byte(x,i) ((UCHAR)(((x) >> (8*i)) & 0xFF))
/* define IS_LITTLE_ENDIAN for faster operation when appropriate */
#ifdef IS_LITTLE_ENDIAN
/* Useful macros -- little endian words on a little endian machine */
#define BYTE2WORD(b) (*(WORD *)(b))
#define WORD2BYTE(w, b) ((*(WORD *)(b)) = w)
#define XORWORD(w, b) ((*(WORD *)(b)) ^= w)
#else
/* Useful macros -- machine independent little-endian version */
#define BYTE2WORD(b) ( \
(((WORD)(b)[3] & 0xFF)<<24) | \
(((WORD)(b)[2] & 0xFF)<<16) | \
(((WORD)(b)[1] & 0xFF)<<8) | \
(((WORD)(b)[0] & 0xFF)) \
)
#define WORD2BYTE(w, b) { \
(b)[3] = Byte(w,3); \
(b)[2] = Byte(w,2); \
(b)[1] = Byte(w,1); \
(b)[0] = Byte(w,0); \
}
#define XORWORD(w, b) { \
(b)[3] ^= Byte(w,3); \
(b)[2] ^= Byte(w,2); \
(b)[1] ^= Byte(w,1); \
(b)[0] ^= Byte(w,0); \
}
#endif
/* give correct offset for the current position of the register,
* where logically R[0] is at position "zero". Note that this works for
* both the stream register and the CRC register.
*/
#define OFF(zero, i) (((zero)+(i)) % N)
/* step the shift register */
/* After stepping, "zero" moves right one place */
#define STEP(c,z) \
{ \
t = c->R[OFF(z,12)] ^ c->R[OFF(z,13)] ^ c->konst; \
/* Sbox 1 */ \
t ^= ROTL(t, 5) | ROTL(t, 7); \
t ^= ROTL(t, 19) | ROTL(t, 22); \
c->R[OFF(z,0)] = t ^ ROTL(c->R[OFF(z,0)],1); \
t = c->R[OFF((z+1),2)] ^ c->R[OFF((z+1),15)]; \
/* Sbox 2 */ \
t ^= ROTL(t, 7) | ROTL(t, 22); \
t ^= ROTL(t, 5) | ROTL(t, 19); \
c->R[OFF((z+1),0)] ^= t; \
c->sbuf = t ^ c->R[OFF((z+1),8)] ^ c->R[OFF((z+1),12)]; \
}
static void
cycle(shn_ctx *c)
{
WORD t;
int i;
/* nonlinear feedback function */
STEP(c,0);
/* shift register */
t = c->R[0];
for (i = 1; i < N; ++i)
c->R[i-1] = c->R[i];
c->R[N-1] = t;
}
/* The Shannon MAC function is modelled after the concepts of Phelix and SHA.
* Basically, words to be accumulated in the MAC are incorporated in two
* different ways:
* 1. They are incorporated into the stream cipher register at a place
* where they will immediately have a nonlinear effect on the state
* 2. They are incorporated into bit-parallel CRC-16 registers; the
* contents of these registers will be used in MAC finalization.
*/
/* Accumulate a CRC of input words, later to be fed into MAC.
* This is actually 32 parallel CRC-16s, using the IBM CRC-16
* polynomial x^16 + x^15 + x^2 + 1.
*/
#define CRCFUNC(c,i,z) \
{ \
c->CRC[OFF(z,0)] ^= c->CRC[OFF(z,2)] ^ c->CRC[OFF(z,15)] ^ i; \
}
static void
crcfunc(shn_ctx *c, WORD i)
{
WORD t;
CRCFUNC(c, i, 0);
/* now correct alignment of CRC accumulator */
t = c->CRC[0];
for (i = 1; i < N; ++i)
c->CRC[i-1] = c->CRC[i];
c->CRC[N-1] = t;
}
/* Normal MAC word processing: do both SHA and CRC.
*/
static void
macfunc(shn_ctx *c, WORD i)
{
crcfunc(c, i);
c->R[KEYP] ^= i;
}
/* initialise to known state
*/
static void
shn_initstate(shn_ctx *c)
{
int i;
/* Register initialised to Fibonacci numbers; Counter zeroed. */
c->R[0] = 1;
c->R[1] = 1;
for (i = 2; i < N; ++i)
c->R[i] = c->R[i-1] + c->R[i-2];
c->konst = INITKONST;
}
/* Save the current register state
*/
static void
shn_savestate(shn_ctx *c)
{
int i;
for (i = 0; i < N; ++i)
c->initR[i] = c->R[i];
}
/* initialise to previously saved register state
*/
static void
shn_reloadstate(shn_ctx *c)
{
int i;
for (i = 0; i < N; ++i)
c->R[i] = c->initR[i];
}
/* Initialise "konst"
*/
static void
shn_genkonst(shn_ctx *c)
{
c->konst = c->R[0];
}
/* Load key material into the register
*/
#define ADDKEY(k) \
c->R[KEYP] ^= (k);
/* nonlinear diffusion of register for key and MAC */
#define DROUND(z) { register WORD t; STEP(c,z); }
static void
shn_diffuse(shn_ctx *c)
{
/* relies on FOLD == N! */
DROUND(0);
DROUND(1);
DROUND(2);
DROUND(3);
DROUND(4);
DROUND(5);
DROUND(6);
DROUND(7);
DROUND(8);
DROUND(9);
DROUND(10);
DROUND(11);
DROUND(12);
DROUND(13);
DROUND(14);
DROUND(15);
}
/* common actions for loading key material
* Allow non-word-multiple key and nonce materianl
* Note also initializes the CRC register as a side effect.
*/
static void
shn_loadkey(shn_ctx *c, const uint8_t key[], int keylen)
{
int i, j;
WORD k;
uint8_t xtra[4];
/* start folding in key */
for (i = 0; i < (keylen & ~0x3); i += 4)
{
k = BYTE2WORD(&key[i]);
ADDKEY(k);
cycle(c);
}
/* if there were any extra key bytes, zero pad to a word */
if (i < keylen) {
for (j = 0 /* i unchanged */; i < keylen; ++i)
xtra[j++] = key[i];
for (/* j unchanged */; j < 4; ++j)
xtra[j] = 0;
k = BYTE2WORD(xtra);
ADDKEY(k);
cycle(c);
}
/* also fold in the length of the key */
ADDKEY(keylen);
cycle(c);
/* save a copy of the register */
for (i = 0; i < N; ++i)
c->CRC[i] = c->R[i];
/* now diffuse */
shn_diffuse(c);
/* now xor the copy back -- makes key loading irreversible */
for (i = 0; i < N; ++i)
c->R[i] ^= c->CRC[i];
}
/* Published "key" interface
*/
void
shn_key(shn_ctx *c, const uint8_t key[], int keylen)
{
shn_initstate(c);
shn_loadkey(c, key, keylen);
shn_genkonst(c);
shn_savestate(c);
c->nbuf = 0;
}
/* Published "nonce" interface
*/
void
shn_nonce(shn_ctx *c, const uint8_t nonce[], int noncelen)
{
shn_reloadstate(c);
c->konst = INITKONST;
shn_loadkey(c, nonce, noncelen);
shn_genkonst(c);
c->nbuf = 0;
}
/* XOR pseudo-random bytes into buffer
* Note: doesn't play well with MAC functions.
*/
#define SROUND(z) \
{ register WORD t; \
STEP(c,z); \
XORWORD(c->sbuf, buf+(z*4)); \
}
void
shn_stream(shn_ctx *c, uint8_t *buf, int nbytes)
{
/* handle any previously buffered bytes */
while (c->nbuf != 0 && nbytes != 0) {
*buf++ ^= c->sbuf & 0xFF;
c->sbuf >>= 8;
c->nbuf -= 8;
--nbytes;
}
/* do lots at a time, if there's enough to do */
while (nbytes >= N*4)
{
SROUND(0);
SROUND(1);
SROUND(2);
SROUND(3);
SROUND(4);
SROUND(5);
SROUND(6);
SROUND(7);
SROUND(8);
SROUND(9);
SROUND(10);
SROUND(11);
SROUND(12);
SROUND(13);
SROUND(14);
SROUND(15);
buf += 4*N;
nbytes -= N*4;
}
/* do small or odd size buffers the slow way */
while (4 <= nbytes) {
cycle(c);
XORWORD(c->sbuf, buf);
buf += 4;
nbytes -= 4;
}
/* handle any trailing bytes */
if (nbytes != 0) {
cycle(c);
c->nbuf = 32;
while (c->nbuf != 0 && nbytes != 0) {
*buf++ ^= c->sbuf & 0xFF;
c->sbuf >>= 8;
c->nbuf -= 8;
--nbytes;
}
}
}
/* accumulate words into MAC without encryption
* Note that plaintext is accumulated for MAC.
*/
#define MROUND(z) \
{ register WORD t, t1; \
t1 = BYTE2WORD(buf+(z*4)); \
STEP(c,z); \
CRCFUNC(c,t1,z); \
c->R[OFF(z+1,KEYP)] ^= t1; \
}
void
shn_maconly(shn_ctx *c, uint8_t *buf, int nbytes)
{
/* handle any previously buffered bytes */
if (c->nbuf != 0) {
while (c->nbuf != 0 && nbytes != 0) {
c->mbuf ^= (*buf++) << (32 - c->nbuf);
c->nbuf -= 8;
--nbytes;
}
if (c->nbuf != 0) /* not a whole word yet */
return;
/* LFSR already cycled */
macfunc(c, c->mbuf);
}
/* do lots at a time, if there's enough to do */
while (4*N <= nbytes)
{
MROUND( 0);
MROUND( 1);
MROUND( 2);
MROUND( 3);
MROUND( 4);
MROUND( 5);
MROUND( 6);
MROUND( 7);
MROUND( 8);
MROUND( 9);
MROUND(10);
MROUND(11);
MROUND(12);
MROUND(13);
MROUND(14);
MROUND(15);
buf += 4*N;
nbytes -= 4*N;
}
/* do small or odd size buffers the slow way */
while (4 <= nbytes) {
cycle(c);
macfunc(c, BYTE2WORD(buf));
buf += 4;
nbytes -= 4;
}
/* handle any trailing bytes */
if (nbytes != 0) {
cycle(c);
c->mbuf = 0;
c->nbuf = 32;
while (nbytes != 0) {
c->mbuf ^= (*buf++) << (32 - c->nbuf);
c->nbuf -= 8;
--nbytes;
}
}
}
/* Combined MAC and encryption.
* Note that plaintext is accumulated for MAC.
*/
#define EROUND(z) \
{ register WORD t, t3; \
STEP(c,z); \
t3 = BYTE2WORD(buf+(z*4)); \
CRCFUNC(c,t3,z); \
c->R[OFF((z+1),KEYP)] ^= t3; \
t3 ^= c->sbuf; \
WORD2BYTE(t3,buf+(z*4)); \
}
void
shn_encrypt(shn_ctx *c, uint8_t *buf, int nbytes)
{
WORD t3 = 0;
/* handle any previously buffered bytes */
if (c->nbuf != 0) {
while (c->nbuf != 0 && nbytes != 0) {
c->mbuf ^= *buf << (32 - c->nbuf);
*buf ^= (c->sbuf >> (32 - c->nbuf)) & 0xFF;
++buf;
c->nbuf -= 8;
--nbytes;
}
if (c->nbuf != 0) /* not a whole word yet */
return;
/* LFSR already cycled */
macfunc(c, c->mbuf);
}
/* do lots at a time, if there's enough to do */
while (4*N <= nbytes)
{
EROUND( 0);
EROUND( 1);
EROUND( 2);
EROUND( 3);
EROUND( 4);
EROUND( 5);
EROUND( 6);
EROUND( 7);
EROUND( 8);
EROUND( 9);
EROUND(10);
EROUND(11);
EROUND(12);
EROUND(13);
EROUND(14);
EROUND(15);
buf += 4*N;
nbytes -= 4*N;
}
/* do small or odd size buffers the slow way */
while (4 <= nbytes) {
cycle(c);
t3 = BYTE2WORD(buf);
macfunc(c, t3);
t3 ^= c->sbuf;
WORD2BYTE(t3, buf);
nbytes -= 4;
buf += 4;
}
/* handle any trailing bytes */
if (nbytes != 0) {
cycle(c);
c->mbuf = 0;
c->nbuf = 32;
while (c->nbuf != 0 && nbytes != 0) {
c->mbuf ^= *buf << (32 - c->nbuf);
*buf ^= (c->sbuf >> (32 - c->nbuf)) & 0xFF;
++buf;
c->nbuf -= 8;
--nbytes;
}
}
}
/* Combined MAC and decryption.
* Note that plaintext is accumulated for MAC.
*/
#undef DROUND
#define DROUND(z) \
{ register WORD t, t3; \
STEP(c,z); \
t3 = BYTE2WORD(buf+(z*4)); \
t3 ^= c->sbuf; \
CRCFUNC(c,t3,z); \
c->R[OFF((z+1),KEYP)] ^= t3; \
WORD2BYTE(t3, buf+(z*4)); \
}
void
shn_decrypt(shn_ctx *c, uint8_t *buf, int nbytes)
{
WORD t3 = 0;
/* handle any previously buffered bytes */
if (c->nbuf != 0) {
while (c->nbuf != 0 && nbytes != 0) {
*buf ^= (c->sbuf >> (32 - c->nbuf)) & 0xFF;
c->mbuf ^= *buf << (32 - c->nbuf);
++buf;
c->nbuf -= 8;
--nbytes;
}
if (c->nbuf != 0) /* not a whole word yet */
return;
/* LFSR already cycled */
macfunc(c, c->mbuf);
}
/* now do lots at a time, if there's enough */
while (4*N <= nbytes)
{
DROUND( 0);
DROUND( 1);
DROUND( 2);
DROUND( 3);
DROUND( 4);
DROUND( 5);
DROUND( 6);
DROUND( 7);
DROUND( 8);
DROUND( 9);
DROUND(10);
DROUND(11);
DROUND(12);
DROUND(13);
DROUND(14);
DROUND(15);
buf += 4*N;
nbytes -= 4*N;
}
/* do small or odd size buffers the slow way */
while (4 <= nbytes) {
cycle(c);
t3 = BYTE2WORD(buf);
t3 ^= c->sbuf;
macfunc(c, t3);
WORD2BYTE(t3, buf);
nbytes -= 4;
buf += 4;
}
/* handle any trailing bytes */
if (nbytes != 0) {
cycle(c);
c->mbuf = 0;
c->nbuf = 32;
while (c->nbuf != 0 && nbytes != 0) {
*buf ^= (c->sbuf >> (32 - c->nbuf)) & 0xFF;
c->mbuf ^= *buf << (32 - c->nbuf);
++buf;
c->nbuf -= 8;
--nbytes;
}
}
}
/* Having accumulated a MAC, finish processing and return it.
* Note that any unprocessed bytes are treated as if
* they were encrypted zero bytes, so plaintext (zero) is accumulated.
*/
void
shn_finish(shn_ctx *c, uint8_t *buf, int nbytes)
{
int i;
/* handle any previously buffered bytes */
if (c->nbuf != 0) {
/* LFSR already cycled */
macfunc(c, c->mbuf);
}
/* perturb the MAC to mark end of input.
* Note that only the stream register is updated, not the CRC. This is an
* action that can't be duplicated by passing in plaintext, hence
* defeating any kind of extension attack.
*/
cycle(c);
ADDKEY(INITKONST ^ (c->nbuf << 3));
c->nbuf = 0;
/* now add the CRC to the stream register and diffuse it */
for (i = 0; i < N; ++i)
c->R[i] ^= c->CRC[i];
shn_diffuse(c);
/* produce output from the stream buffer */
while (nbytes > 0) {
cycle(c);
if (nbytes >= 4) {
WORD2BYTE(c->sbuf, buf);
nbytes -= 4;
buf += 4;
}
else {
for (i = 0; i < nbytes; ++i)
buf[i] = Byte(c->sbuf, i);
break;
}
}
}

View File

@ -0,0 +1,23 @@
#ifndef SHANNONINTERNAL_H
#define SHANNONINTERNAL_H
#include "Shannon.h"
#include <limits.h>
#define N SHANNON_N
#define WORDSIZE 32
#define UCHAR unsigned char
#define WORD uint32_t
#define WORD_MAX UINT32_MAX
#if WORD_MAX == 0xffffffff
#define ROTL(w,x) (((w) << (x))|((w) >> (32 - (x))))
#define ROTR(w,x) (((w) >> (x))|((w) << (32 - (x))))
#else
#define ROTL(w,x) (((w) << (x))|(((w) & 0xffffffff) >> (32 - (x))))
#define ROTR(w,x) ((((w) & 0xffffffff) >> (x))|((w) << (32 - (x))))
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
#ifndef __SPOTIFYC_H__
#define __SPOTIFYC_H__
#include <inttypes.h>
struct sp_session;
enum sp_bitrates
{
SP_BITRATE_96,
SP_BITRATE_160,
SP_BITRATE_320,
};
struct sp_credentials
{
char *username;
char *password;
uint8_t stored_cred[256]; // Actual size is 146, but leave room for some more
size_t stored_cred_len;
uint8_t token[256]; // Actual size is 190, but leave room for some more
size_t token_len;
};
struct sp_callbacks
{
void (*logged_in)(struct sp_session *session, void *cb_arg, struct sp_credentials *credentials);
void (*logged_out)(void *cb_arg);
void (*track_opened)(struct sp_session *session, void *cb_arg, int fd);
void (*track_closed)(struct sp_session *session, void *cb_arg, int fd);
void (*track_seeked)(struct sp_session *session, void *cb_arg, int fd);
void (*error)(void *cb_arg, int err, const char *errmsg);
// Bring your own https client and tcp connector
int (*https_get)(char **body, const char *url);
int (*tcp_connect)(const char *address, unsigned short port);
void (*tcp_disconnect)(int fd);
// Debugging
void (*hexdump)(const char *msg, uint8_t *data, size_t data_len);
void (*logmsg)(const char *fmt, ...);
};
// Async interface
struct sp_session *
spotifyc_login_password(const char *username, const char *password);
struct sp_session *
spotifyc_login_stored_cred(const char *username, uint8_t *stored_cred, size_t stored_cred_len);
struct sp_session *
spotifyc_login_token(const char *username, uint8_t *token, size_t token_len);
void
spotifyc_logout(struct sp_session *session);
int
spotifyc_open(const char *path, struct sp_session *session);
void
spotifyc_bitrate_set(enum sp_bitrates bitrate, struct sp_session *session);
// Starts writing audio to the file descriptor
int
spotifyc_play(int fd);
int
spotifyc_seek(int seek_ms, int fd);
int
spotifyc_stop(int fd);
// Sync interface
const char *
spotifyc_last_errmsg(void);
// This Spotify implementation is entirely async, so first the caller must set
// up callbacks
int
spotifyc_init(struct sp_callbacks *callbacks, void *cb_arg);
void
spotifyc_deinit(void);
#endif /* !__SPOTIFYC_H__ */

View File

@ -79,14 +79,14 @@ static pthread_t tid_library;
struct event_base *evbase_lib; struct event_base *evbase_lib;
extern struct library_source filescanner; extern struct library_source filescanner;
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
extern struct library_source spotifyscanner; extern struct library_source spotifyscanner;
#endif #endif
extern struct library_source rssscanner; extern struct library_source rssscanner;
static struct library_source *sources[] = { static struct library_source *sources[] = {
&filescanner, &filescanner,
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
&spotifyscanner, &spotifyscanner,
#endif #endif
&rssscanner, &rssscanner,

View File

@ -67,7 +67,7 @@
#ifdef LASTFM #ifdef LASTFM
# include "lastfm.h" # include "lastfm.h"
#endif #endif
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
# include "spotify.h" # include "spotify.h"
#endif #endif
@ -701,7 +701,7 @@ process_file(char *file, struct stat *sb, enum file_type file_type, int scan_typ
break; break;
case FILE_CTRL_SPOTIFY: case FILE_CTRL_SPOTIFY:
#ifdef HAVE_SPOTIFY_H #ifdef SPOTIFY
if (flags & F_SCAN_BULK) if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file); DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
else else

View File

@ -35,7 +35,6 @@
#include "listener.h" #include "listener.h"
#include "logger.h" #include "logger.h"
#include "misc_json.h" #include "misc_json.h"
#include "spotify.h"
enum spotify_request_type { enum spotify_request_type {
@ -1471,8 +1470,6 @@ track_add(struct spotify_track *track, struct spotify_album *album, const char *
free_mfi(&mfi, 1); free_mfi(&mfi, 1);
} }
spotify_uri_register(track->uri);
if (album && album->uri) if (album && album->uri)
cache_artwork_ping(track->uri, album->mtime, 0); cache_artwork_ping(track->uri, album->mtime, 0);
else else
@ -1814,21 +1811,6 @@ initscan()
spotify_saved_plid = 0; spotify_saved_plid = 0;
/*
* Login to spotify needs to be done before scanning tracks from the web api.
* (Scanned tracks need to be registered with libspotify for playback)
*/
ret = spotify_relogin();
if (ret < 0)
{
DPRINTF(E_LOG, L_SPOTIFY, "libspotify-login failed. In order to use Spotify, "
"provide valid credentials for libspotify by visiting http://owntone.local:3689\n");
db_spotify_purge();
return 0;
}
/* /*
* Scan saved tracks from the web api * Scan saved tracks from the web api
*/ */
@ -2066,12 +2048,9 @@ spotifywebapi_access_token_get(struct spotifywebapi_access_token *info)
static int static int
spotifywebapi_init() spotifywebapi_init()
{ {
int ret;
CHECK_ERR(L_SPOTIFY, mutex_init(&token_lck)); CHECK_ERR(L_SPOTIFY, mutex_init(&token_lck));
ret = spotify_init();
return ret; return 0;
} }
static void static void
@ -2079,8 +2058,6 @@ spotifywebapi_deinit()
{ {
CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&token_lck)); CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&token_lck));
spotify_deinit();
free_credentials(); free_credentials();
} }

View File

@ -86,6 +86,9 @@ struct artwork_get_param
int is_loaded; int is_loaded;
}; };
static void
spotify_playback_stop_nonblock(void);
/* --- Globals --- */ /* --- Globals --- */
// Spotify thread // Spotify thread
static pthread_t tid_spotify; static pthread_t tid_spotify;

View File

@ -26,20 +26,20 @@ spotify_playback_play();
int int
spotify_playback_pause(); spotify_playback_pause();
void //void
spotify_playback_pause_nonblock(void); //spotify_playback_pause_nonblock(void);
int int
spotify_playback_stop(void); spotify_playback_stop(void);
void //void
spotify_playback_stop_nonblock(void); //spotify_playback_stop_nonblock(void);
int int
spotify_playback_seek(int ms); spotify_playback_seek(int ms);
int //int
spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h); //spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h);
int int
spotify_relogin(); spotify_relogin();

View File

@ -242,6 +242,11 @@ init_settings(struct settings_ctx *settings, enum transcode_profile profile, str
settings->sample_format = AV_SAMPLE_FMT_S16P; settings->sample_format = AV_SAMPLE_FMT_S16P;
break; break;
case XCODE_OGG:
settings->encode_audio = 1;
settings->in_format = "ogg";
break;
case XCODE_JPEG: case XCODE_JPEG:
settings->encode_video = 1; settings->encode_video = 1;
settings->silent = 1; settings->silent = 1;

View File

@ -19,13 +19,15 @@ enum transcode_profile
XCODE_PCM16, XCODE_PCM16,
XCODE_PCM24, XCODE_PCM24,
XCODE_PCM32, XCODE_PCM32,
// Transcodes the best audio stream into MP3 // Transcodes the best audio stream to MP3
XCODE_MP3, XCODE_MP3,
// Transcodes the best audio stream into OPUS // Transcodes the best audio stream to OPUS
XCODE_OPUS, XCODE_OPUS,
// Transcodes the best audio stream into ALAC // Transcodes the best audio stream to ALAC
XCODE_ALAC, XCODE_ALAC,
// Transcodes the best video stream into JPEG/PNG/VP8 // Transcodes the best audio stream from OGG
XCODE_OGG,
// Transcodes the best video stream to JPEG/PNG/VP8
XCODE_JPEG, XCODE_JPEG,
XCODE_PNG, XCODE_PNG,
XCODE_VP8, XCODE_VP8,