mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-26 22:23:17 -05:00
abstract the plugin interface to the db to prepare for db plugins and making daap a plugin
This commit is contained in:
parent
9e547e6c16
commit
b3fbb9bbd5
@ -354,7 +354,8 @@ char *db_error_list[] = {
|
|||||||
"Could not initialize thread pool",
|
"Could not initialize thread pool",
|
||||||
"Passed buffer too small for result",
|
"Passed buffer too small for result",
|
||||||
"Wrong db schema. Use mtd-update to upgrade the db.",
|
"Wrong db schema. Use mtd-update to upgrade the db.",
|
||||||
"Database error: %s"
|
"Database error: %s",
|
||||||
|
"Malloc error"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
|
@ -216,6 +216,7 @@ extern void db_dispose_playlist(M3UFILE *pm3u);
|
|||||||
#define DB_E_SIZE 0x0B /**< passed buffer too small */
|
#define DB_E_SIZE 0x0B /**< passed buffer too small */
|
||||||
#define DB_E_WRONGVERSION 0x0C /**< must upgrade db */
|
#define DB_E_WRONGVERSION 0x0C /**< must upgrade db */
|
||||||
#define DB_E_DB_ERROR 0x0D /**< gdbm error */
|
#define DB_E_DB_ERROR 0x0D /**< gdbm error */
|
||||||
|
#define DB_E_MALLOC 0x0E /**< malloc error */
|
||||||
|
|
||||||
/* describes the individual database handlers */
|
/* describes the individual database handlers */
|
||||||
typedef struct tag_dbinfo {
|
typedef struct tag_dbinfo {
|
||||||
|
@ -737,7 +737,7 @@ char *dispatch_xml_encode(char *original, int len) {
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
void dispatch_stream_id(WS_CONNINFO *pwsc, int session, char *id) {
|
||||||
MP3FILE *pmp3;
|
MP3FILE *pmp3;
|
||||||
FILE *file_ptr;
|
FILE *file_ptr;
|
||||||
int file_fd;
|
int file_fd;
|
||||||
@ -763,7 +763,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
pmp3=db_fetch_item(NULL,item);
|
pmp3=db_fetch_item(NULL,item);
|
||||||
if(!pmp3) {
|
if(!pmp3) {
|
||||||
DPRINTF(E_LOG,L_DAAP|L_WS|L_DB,"Could not find requested item %lu\n",item);
|
DPRINTF(E_LOG,L_DAAP|L_WS|L_DB,"Could not find requested item %lu\n",item);
|
||||||
config_set_status(pwsc,pqi->session_id,NULL);
|
config_set_status(pwsc,session,NULL);
|
||||||
ws_returnerror(pwsc,404,"File Not Found");
|
ws_returnerror(pwsc,404,"File Not Found");
|
||||||
} else if (server_side_convert(pmp3->codectype)) {
|
} else if (server_side_convert(pmp3->codectype)) {
|
||||||
/************************
|
/************************
|
||||||
@ -820,12 +820,12 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
|
|
||||||
ws_emitheaders(pwsc);
|
ws_emitheaders(pwsc);
|
||||||
|
|
||||||
config_set_status(pwsc,pqi->session_id,
|
config_set_status(pwsc,session,
|
||||||
"Transcoding '%s' (id %d)",
|
"Transcoding '%s' (id %d)",
|
||||||
pmp3->title,pmp3->id);
|
pmp3->title,pmp3->id);
|
||||||
DPRINTF(E_LOG,L_WS,
|
DPRINTF(E_LOG,L_WS,
|
||||||
"Session %d: Streaming file '%s' to %s (offset %ld)\n",
|
"Session %d: Streaming file '%s' to %s (offset %ld)\n",
|
||||||
pqi->session_id,pmp3->fname, pwsc->hostname,(long)offset);
|
session,pmp3->fname, pwsc->hostname,(long)offset);
|
||||||
|
|
||||||
if(!offset)
|
if(!offset)
|
||||||
config.stats.songs_served++; /* FIXME: remove stat races */
|
config.stats.songs_served++; /* FIXME: remove stat races */
|
||||||
@ -840,7 +840,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
server_side_convert_close(file_ptr);
|
server_side_convert_close(file_ptr);
|
||||||
config_set_status(pwsc,pqi->session_id,NULL);
|
config_set_status(pwsc,session,NULL);
|
||||||
db_dispose_item(pmp3);
|
db_dispose_item(pmp3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -853,7 +853,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
DPRINTF(E_WARN,L_WS,"Thread %d: Error opening %s: %s\n",
|
DPRINTF(E_WARN,L_WS,"Thread %d: Error opening %s: %s\n",
|
||||||
pwsc->threadno,pmp3->path,strerror(errno));
|
pwsc->threadno,pmp3->path,strerror(errno));
|
||||||
ws_returnerror(pwsc,404,"Not found");
|
ws_returnerror(pwsc,404,"Not found");
|
||||||
config_set_status(pwsc,pqi->session_id,NULL);
|
config_set_status(pwsc,session,NULL);
|
||||||
db_dispose_item(pmp3);
|
db_dispose_item(pmp3);
|
||||||
} else {
|
} else {
|
||||||
real_len=lseek(file_fd,0,SEEK_END);
|
real_len=lseek(file_fd,0,SEEK_END);
|
||||||
@ -903,10 +903,10 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
|
|
||||||
ws_emitheaders(pwsc);
|
ws_emitheaders(pwsc);
|
||||||
|
|
||||||
config_set_status(pwsc,pqi->session_id,"Streaming '%s' (id %d)",
|
config_set_status(pwsc,session,"Streaming '%s' (id %d)",
|
||||||
pmp3->title, pmp3->id);
|
pmp3->title, pmp3->id);
|
||||||
DPRINTF(E_LOG,L_WS,"Session %d: Streaming file '%s' to %s (offset %d)\n",
|
DPRINTF(E_LOG,L_WS,"Session %d: Streaming file '%s' to %s (offset %d)\n",
|
||||||
pqi->session_id,pmp3->fname, pwsc->hostname,(long)offset);
|
session,pmp3->fname, pwsc->hostname,(long)offset);
|
||||||
|
|
||||||
if(!offset)
|
if(!offset)
|
||||||
config.stats.songs_served++; /* FIXME: remove stat races */
|
config.stats.songs_served++; /* FIXME: remove stat races */
|
||||||
@ -940,7 +940,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config_set_status(pwsc,pqi->session_id,NULL);
|
config_set_status(pwsc,session,NULL);
|
||||||
r_close(file_fd);
|
r_close(file_fd);
|
||||||
db_dispose_item(pmp3);
|
db_dispose_item(pmp3);
|
||||||
}
|
}
|
||||||
@ -950,7 +950,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||||
dispatch_stream_id(pwsc, pqi, pqi->uri_sections[3]);
|
dispatch_stream_id(pwsc, pqi->session_id, pqi->uri_sections[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
|
|
||||||
extern void daap_handler(WS_CONNINFO *pwsc);
|
extern void daap_handler(WS_CONNINFO *pwsc);
|
||||||
extern int daap_auth(WS_CONNINFO *pwsc, char *username, char *password);
|
extern int daap_auth(WS_CONNINFO *pwsc, char *username, char *password);
|
||||||
extern void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id);
|
extern void dispatch_stream_id(WS_CONNINFO *pwsc, int session, char *id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
106
src/plugin.c
106
src/plugin.c
@ -43,6 +43,7 @@
|
|||||||
#include "smart-parser.h"
|
#include "smart-parser.h"
|
||||||
#include "xml-rpc.h"
|
#include "xml-rpc.h"
|
||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
|
#include "ff-plugins.h"
|
||||||
|
|
||||||
typedef struct tag_pluginentry {
|
typedef struct tag_pluginentry {
|
||||||
void *phandle;
|
void *phandle;
|
||||||
@ -87,12 +88,13 @@ void pi_log(int, char *, ...);
|
|||||||
|
|
||||||
/* db helpers */
|
/* db helpers */
|
||||||
int pi_db_count(void);
|
int pi_db_count(void);
|
||||||
int pi_db_enum_start(char **pe, DBQUERYINFO *pinfo);
|
int pi_db_enum_start(char **pe, DB_QUERY *pinfo);
|
||||||
int pi_db_enum_fetch_row(char **pe, char ***row, DBQUERYINFO *pinfo);
|
int pi_db_enum_fetch_row(char **pe, char ***row, DB_QUERY *pinfo);
|
||||||
int pi_db_enum_end(char **pe);
|
int pi_db_enum_end(char **pe);
|
||||||
void pi_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id);
|
void pi_db_enum_dispose(char **pe, DB_QUERY *pinfo);
|
||||||
|
void pi_stream(WS_CONNINFO *pwsc, char *id);
|
||||||
|
|
||||||
void pi_conf_dispose_string(char *str);
|
void pi_conf_dispose_string(char *str);
|
||||||
int pi_sp_parse(PARSETREE tree, char *term);
|
|
||||||
|
|
||||||
PLUGIN_INPUT_FN pi = {
|
PLUGIN_INPUT_FN pi = {
|
||||||
pi_ws_uri,
|
pi_ws_uri,
|
||||||
@ -114,13 +116,9 @@ PLUGIN_INPUT_FN pi = {
|
|||||||
pi_db_enum_start,
|
pi_db_enum_start,
|
||||||
pi_db_enum_fetch_row,
|
pi_db_enum_fetch_row,
|
||||||
pi_db_enum_end,
|
pi_db_enum_end,
|
||||||
|
pi_db_enum_dispose,
|
||||||
pi_stream,
|
pi_stream,
|
||||||
|
|
||||||
sp_init,
|
|
||||||
pi_sp_parse,
|
|
||||||
sp_dispose,
|
|
||||||
sp_get_error,
|
|
||||||
|
|
||||||
conf_alloc_string,
|
conf_alloc_string,
|
||||||
pi_conf_dispose_string
|
pi_conf_dispose_string
|
||||||
};
|
};
|
||||||
@ -577,25 +575,99 @@ int pi_db_count(void) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pi_db_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
int pi_db_enum_start(char **pe, DB_QUERY *pinfo) {
|
||||||
return db_enum_start(pe, pinfo);
|
DBQUERYINFO *pqi;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
pqi = (DBQUERYINFO*)malloc(sizeof(DBQUERYINFO));
|
||||||
|
if(!pqi) {
|
||||||
|
if(pe) *pe = strdup("Malloc error");
|
||||||
|
return DB_E_MALLOC;
|
||||||
|
}
|
||||||
|
memset(pqi,0,sizeof(DBQUERYINFO));
|
||||||
|
pinfo->private = (void*)pqi;
|
||||||
|
|
||||||
|
if(pinfo->filter) {
|
||||||
|
pqi->pt = sp_init();
|
||||||
|
if(!sp_parse(pqi->pt,pinfo->filter,pinfo->filter_type)) {
|
||||||
|
DPRINTF(E_LOG,L_PLUG,"Ignoring bad query (%s): %s\n",
|
||||||
|
pinfo->filter,sp_get_error(pqi->pt));
|
||||||
|
sp_dispose(pqi->pt);
|
||||||
|
pqi->pt = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((pinfo->limit) || (pinfo->offset)) {
|
||||||
|
pqi->index_low = pinfo->offset;
|
||||||
|
pqi->index_high = pinfo->offset + pinfo->limit - 1;
|
||||||
|
if(pqi->index_high < pqi->index_low)
|
||||||
|
pqi->index_high = 9999999;
|
||||||
|
|
||||||
|
pqi->index_type = indexTypeSub;
|
||||||
|
} else {
|
||||||
|
pqi->index_type = indexTypeNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
pqi->want_count = 1;
|
||||||
|
|
||||||
|
switch(pinfo->query_type) {
|
||||||
|
case QUERY_TYPE_PLAYLISTS:
|
||||||
|
pqi->query_type = queryTypePlaylists;
|
||||||
|
break;
|
||||||
|
case QUERY_TYPE_DISTINCT:
|
||||||
|
if((strcmp(pinfo->distinct_field,"artist") == 0)) {
|
||||||
|
pqi->query_type = queryTypeBrowseArtists;
|
||||||
|
} else if((strcmp(pinfo->distinct_field,"genre") == 0)) {
|
||||||
|
pqi->query_type = queryTypeBrowseGenres;
|
||||||
|
} else if((strcmp(pinfo->distinct_field,"album") == 0)) {
|
||||||
|
pqi->query_type = queryTypeBrowseAlbums;
|
||||||
|
} else if((strcmp(pinfo->distinct_field,"composer") == 0)) {
|
||||||
|
pqi->query_type = queryTypeBrowseComposers;
|
||||||
|
} else {
|
||||||
|
if(pe) *pe = strdup("Unsupported browse type");
|
||||||
|
sp_dispose(pqi->pt);
|
||||||
|
pqi->pt = NULL;
|
||||||
|
return -1; /* not really a db error for this */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QUERY_TYPE_ITEMS:
|
||||||
|
default:
|
||||||
|
pqi->query_type = queryTypePlaylistItems;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pqi->playlist_id = pinfo->playlist_id;
|
||||||
|
result = db_enum_start(pe, pqi);
|
||||||
|
pinfo->totalcount = pqi->specifiedtotalcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pi_db_enum_fetch_row(char **pe, char ***row, DBQUERYINFO *pinfo) {
|
int pi_db_enum_fetch_row(char **pe, char ***row, DB_QUERY *pinfo) {
|
||||||
return db_enum_fetch_row(pe, (PACKED_MP3FILE*)row, pinfo);
|
return db_enum_fetch_row(pe, (PACKED_MP3FILE*)row,
|
||||||
|
(DBQUERYINFO*)pinfo->private);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pi_db_enum_end(char **pe) {
|
int pi_db_enum_end(char **pe) {
|
||||||
return db_enum_end(pe);
|
return db_enum_end(pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pi_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
|
void pi_stream(WS_CONNINFO *pwsc, char *id) {
|
||||||
dispatch_stream_id(pwsc, pqi,id);
|
dispatch_stream_id(pwsc, 0, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pi_sp_parse(PARSETREE tree, char *term) {
|
void pi_db_enum_dispose(char **pe, DB_QUERY *pinfo) {
|
||||||
return sp_parse(tree, term, 0);
|
DBQUERYINFO *pqi;
|
||||||
|
|
||||||
|
if(!pinfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(pinfo->private) {
|
||||||
|
pqi = (DBQUERYINFO *)pinfo->private;
|
||||||
|
if(pqi->pt) {
|
||||||
|
sp_dispose(pqi->pt);
|
||||||
|
pqi->pt = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pi_conf_dispose_string(char *str) {
|
void pi_conf_dispose_string(char *str) {
|
||||||
|
79
src/plugin.h
79
src/plugin.h
@ -37,87 +37,10 @@ extern int plugin_auth_handle(WS_CONNINFO *pwsc, char *username, char *pw);
|
|||||||
extern int plugin_rend_register(char *name, int port, char *iface, char *txt);
|
extern int plugin_rend_register(char *name, int port, char *iface, char *txt);
|
||||||
extern void plugin_event_dispatch(int event_id, int intval, void *vp, int len);
|
extern void plugin_event_dispatch(int event_id, int intval, void *vp, int len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define PLUGIN_E_SUCCESS 0
|
#define PLUGIN_E_SUCCESS 0
|
||||||
#define PLUGIN_E_NOLOAD 1
|
#define PLUGIN_E_NOLOAD 1
|
||||||
#define PLUGIN_E_BADFUNCS 2
|
#define PLUGIN_E_BADFUNCS 2
|
||||||
|
|
||||||
#define PLUGIN_OUTPUT 1
|
#include "ff-plugins.h"
|
||||||
#define PLUGIN_SCANNER 2
|
|
||||||
#define PLUGIN_DATABASE 4
|
|
||||||
#define PLUGIN_EVENT 8
|
|
||||||
|
|
||||||
#define PLUGIN_EVENT_LOG 0
|
|
||||||
#define PLUGIN_EVENT_FULLSCAN_START 1
|
|
||||||
#define PLUGIN_EVENT_FULLSCAN_END 2
|
|
||||||
#define PLUGIN_EVENT_STARTING 3
|
|
||||||
#define PLUGIN_EVENT_SHUTDOWN 4
|
|
||||||
#define PLUGIN_EVENT_STARTSTREAM 5
|
|
||||||
#define PLUGIN_EVENT_ABORTSTREAM 6
|
|
||||||
#define PLUGIN_EVENT_ENDSTREAM 7
|
|
||||||
|
|
||||||
#define PLUGIN_VERSION 1
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct tag_plugin_output_fn {
|
|
||||||
void(*handler)(WS_CONNINFO *pwsc);
|
|
||||||
int(*auth)(WS_CONNINFO *pwsc, char *username, char *pw);
|
|
||||||
} PLUGIN_OUTPUT_FN;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_event_fn {
|
|
||||||
void(*handler)(int event_id, int intval, void *vp, int len);
|
|
||||||
} PLUGIN_EVENT_FN;
|
|
||||||
|
|
||||||
/* version 1 plugin info */
|
|
||||||
typedef struct tag_plugin_rend_info {
|
|
||||||
char *type;
|
|
||||||
char *txt;
|
|
||||||
} PLUGIN_REND_INFO;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_info {
|
|
||||||
int version;
|
|
||||||
int type;
|
|
||||||
char *server;
|
|
||||||
char *url; /* for output plugins */
|
|
||||||
PLUGIN_OUTPUT_FN *output_fns;
|
|
||||||
PLUGIN_EVENT_FN *event_fns;
|
|
||||||
void *pi; /* exported functions */
|
|
||||||
PLUGIN_REND_INFO *rend_info;
|
|
||||||
} PLUGIN_INFO;
|
|
||||||
|
|
||||||
/* version 1 plugin imports */
|
|
||||||
typedef struct tag_plugin_input_fn {
|
|
||||||
/* webserver helpers */
|
|
||||||
char* (*ws_uri)(WS_CONNINFO *);
|
|
||||||
void (*ws_close)(WS_CONNINFO *);
|
|
||||||
int (*ws_returnerror)(WS_CONNINFO *, int, char *);
|
|
||||||
char* (*ws_getvar)(WS_CONNINFO *, char *);
|
|
||||||
int (*ws_writefd)(WS_CONNINFO *, char *, ...);
|
|
||||||
int (*ws_addresponseheader)(WS_CONNINFO *, char *, char *, ...);
|
|
||||||
void (*ws_emitheaders)(WS_CONNINFO *);
|
|
||||||
int (*ws_fd)(WS_CONNINFO *);
|
|
||||||
char* (*ws_getrequestheader)(WS_CONNINFO *, char *);
|
|
||||||
int (*ws_writebinary)(WS_CONNINFO *, char *, int);
|
|
||||||
|
|
||||||
/* misc helpers */
|
|
||||||
char* (*server_ver)(void);
|
|
||||||
int (*server_name)(char *, int *);
|
|
||||||
void (*log)(int, char *, ...);
|
|
||||||
|
|
||||||
int (*db_count)(void);
|
|
||||||
int (*db_enum_start)(char **, DBQUERYINFO *);
|
|
||||||
int (*db_enum_fetch_row)(char **, char ***, DBQUERYINFO *);
|
|
||||||
int (*db_enum_end)(char **);
|
|
||||||
void (*stream)(WS_CONNINFO *, DBQUERYINFO *, char *);
|
|
||||||
|
|
||||||
PARSETREE (*sp_init)(void);
|
|
||||||
int (*sp_parse)(PARSETREE tree, char *term);
|
|
||||||
int (*sp_dispose)(PARSETREE tree);
|
|
||||||
char* (*sp_get_error)(PARSETREE tree);
|
|
||||||
|
|
||||||
char *(*conf_alloc_string)(char *section, char *key, char *dflt);
|
|
||||||
void (*conf_dispose_string)(char *str);
|
|
||||||
} PLUGIN_INPUT_FN;
|
|
||||||
|
|
||||||
#endif /* _PLUGIN_H_ */
|
#endif /* _PLUGIN_H_ */
|
||||||
|
@ -6,4 +6,7 @@ rsp_LTLIBRARIES=rsp.la
|
|||||||
rsp_la_LDFLAGS=-module -avoid-version
|
rsp_la_LDFLAGS=-module -avoid-version
|
||||||
rsp_la_SOURCES = compat.c rsp.c xml-rpc.c
|
rsp_la_SOURCES = compat.c rsp.c xml-rpc.c
|
||||||
|
|
||||||
EXTRA_DIST = compat.h rsp.h mtd-plugins.h xml-rpc.h
|
EXTRA_DIST = compat.h rsp.h mtd-plugins.h xml-rpc.h
|
||||||
|
|
||||||
|
AM_CFLAGS = -I..
|
||||||
|
|
||||||
|
@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* $Id: $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _MTD_PLUGINS_H_
|
|
||||||
#define _MTD_PLUGINS_H_
|
|
||||||
|
|
||||||
#define PLUGIN_OUTPUT 1
|
|
||||||
#define PLUGIN_SCANNER 2
|
|
||||||
#define PLUGIN_DATABASE 4
|
|
||||||
#define PLUGIN_EVENT 8
|
|
||||||
|
|
||||||
#define PLUGIN_VERSION 1
|
|
||||||
|
|
||||||
#define PLUGIN_EVENT_LOG 0
|
|
||||||
#define PLUGIN_EVENT_FULLSCAN_START 1
|
|
||||||
#define PLUGIN_EVENT_FULLSCAN_END 2
|
|
||||||
#define PLUGIN_EVENT_STARTING 3
|
|
||||||
#define PLUGIN_EVENT_SHUTDOWN 4
|
|
||||||
#define PLUGIN_EVENT_STARTSTREAM 5
|
|
||||||
#define PLUGIN_EVENT_ABORTSTREAM 6
|
|
||||||
#define PLUGIN_EVENT_ENDSTREAM 7
|
|
||||||
|
|
||||||
typedef void* PARSETREE;
|
|
||||||
|
|
||||||
struct tag_ws_conninfo;
|
|
||||||
typedef struct tag_ws_conninfo WS_CONNINFO;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_output_fn {
|
|
||||||
void(*handler)(WS_CONNINFO *pwsc);
|
|
||||||
int(*auth)(WS_CONNINFO *pwsc, char *username, char *pw);
|
|
||||||
} PLUGIN_OUTPUT_FN;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_event_fn {
|
|
||||||
void(*handler)(int event_id, int intval, void *vp, int len);
|
|
||||||
} PLUGIN_EVENT_FN;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_rend_info {
|
|
||||||
char *type;
|
|
||||||
char *txt;
|
|
||||||
} PLUGIN_REND_INFO;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_info {
|
|
||||||
int version;
|
|
||||||
int type;
|
|
||||||
char *server;
|
|
||||||
char *url; /* regex of namespace to handle if OUTPUT type */
|
|
||||||
PLUGIN_OUTPUT_FN *output_fns;
|
|
||||||
PLUGIN_EVENT_FN *event_fns;
|
|
||||||
void *pi; /* exported functions */
|
|
||||||
PLUGIN_REND_INFO *rend_info;
|
|
||||||
} PLUGIN_INFO;
|
|
||||||
|
|
||||||
/* xml helpers for output plugins */
|
|
||||||
|
|
||||||
/* logging */
|
|
||||||
#define E_FATAL 0
|
|
||||||
#define E_LOG 1
|
|
||||||
#define E_INF 5
|
|
||||||
#define E_DBG 9
|
|
||||||
|
|
||||||
/* db stuff */
|
|
||||||
typedef enum {
|
|
||||||
queryTypeItems,
|
|
||||||
queryTypePlaylists,
|
|
||||||
queryTypePlaylistItems,
|
|
||||||
queryTypeBrowseArtists,
|
|
||||||
queryTypeBrowseAlbums,
|
|
||||||
queryTypeBrowseGenres,
|
|
||||||
queryTypeBrowseComposers
|
|
||||||
} QueryType_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
indexTypeNone,
|
|
||||||
indexTypeFirst,
|
|
||||||
indexTypeLast,
|
|
||||||
indexTypeSub
|
|
||||||
} IndexType_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
// generic meta data
|
|
||||||
metaItemId,
|
|
||||||
metaItemName,
|
|
||||||
metaItemKind,
|
|
||||||
metaPersistentId,
|
|
||||||
metaContainerItemId,
|
|
||||||
metaParentContainerId,
|
|
||||||
|
|
||||||
firstTypeSpecificMetaId,
|
|
||||||
|
|
||||||
// song meta data
|
|
||||||
metaSongAlbum = firstTypeSpecificMetaId,
|
|
||||||
metaSongArtist,
|
|
||||||
metaSongBPM,
|
|
||||||
metaSongBitRate,
|
|
||||||
metaSongComment,
|
|
||||||
metaSongCompilation,
|
|
||||||
metaSongComposer,
|
|
||||||
metaSongDataKind,
|
|
||||||
metaSongDataURL,
|
|
||||||
metaSongDateAdded,
|
|
||||||
metaSongDateModified,
|
|
||||||
metaSongDescription,
|
|
||||||
metaSongDisabled,
|
|
||||||
metaSongDiscCount,
|
|
||||||
metaSongDiscNumber,
|
|
||||||
metaSongEqPreset,
|
|
||||||
metaSongFormat,
|
|
||||||
metaSongGenre,
|
|
||||||
metaSongGrouping,
|
|
||||||
metaSongRelativeVolume,
|
|
||||||
metaSongSampleRate,
|
|
||||||
metaSongSize,
|
|
||||||
metaSongStartTime,
|
|
||||||
metaSongStopTime,
|
|
||||||
metaSongTime,
|
|
||||||
metaSongTrackCount,
|
|
||||||
metaSongTrackNumber,
|
|
||||||
metaSongUserRating,
|
|
||||||
metaSongYear,
|
|
||||||
|
|
||||||
/* iTunes 4.5 + */
|
|
||||||
metaSongCodecType,
|
|
||||||
metaSongCodecSubType,
|
|
||||||
metaItunesNormVolume,
|
|
||||||
metaItmsSongId,
|
|
||||||
metaItmsArtistId,
|
|
||||||
metaItmsPlaylistId,
|
|
||||||
metaItmsComposerId,
|
|
||||||
metaItmsGenreId,
|
|
||||||
metaItmsStorefrontId,
|
|
||||||
metaItunesSmartPlaylist,
|
|
||||||
|
|
||||||
/* iTunes 5.0 + */
|
|
||||||
metaSongContentRating,
|
|
||||||
metaHasChildContainers,
|
|
||||||
|
|
||||||
/* iTunes 6.0.2+ */
|
|
||||||
metaItunesHasVideo,
|
|
||||||
|
|
||||||
/* mt-daapd specific */
|
|
||||||
metaMPlaylistSpec,
|
|
||||||
metaMPlaylistType
|
|
||||||
} MetaFieldName_t;
|
|
||||||
|
|
||||||
typedef unsigned long long MetaField_t;
|
|
||||||
|
|
||||||
typedef struct tag_dbqueryinfo {
|
|
||||||
QueryType_t query_type;
|
|
||||||
IndexType_t index_type;
|
|
||||||
MetaField_t meta;
|
|
||||||
int zero_length; /* emit zero-length strings? */
|
|
||||||
int index_low;
|
|
||||||
int index_high;
|
|
||||||
int playlist_id;
|
|
||||||
int db_id;
|
|
||||||
int session_id;
|
|
||||||
int want_count;
|
|
||||||
int specifiedtotalcount;
|
|
||||||
int uri_count;
|
|
||||||
char *uri_sections[10];
|
|
||||||
PARSETREE pt;
|
|
||||||
void *output_info;
|
|
||||||
} DBQUERYINFO;
|
|
||||||
|
|
||||||
typedef struct tag_plugin_input_fn {
|
|
||||||
/* webserver helpers */
|
|
||||||
char* (*ws_uri)(WS_CONNINFO *);
|
|
||||||
void (*ws_close)(WS_CONNINFO *);
|
|
||||||
int (*ws_returnerror)(WS_CONNINFO *, int, char *);
|
|
||||||
char* (*ws_getvar)(WS_CONNINFO *, char *);
|
|
||||||
int (*ws_writefd)(WS_CONNINFO *, char *, ...);
|
|
||||||
int (*ws_addresponseheader)(WS_CONNINFO *, char *, char *, ...);
|
|
||||||
void (*ws_emitheaders)(WS_CONNINFO *);
|
|
||||||
int (*ws_fd)(WS_CONNINFO *);
|
|
||||||
char* (*ws_getrequestheader)(WS_CONNINFO *, char *);
|
|
||||||
int (*ws_writebinary)(WS_CONNINFO *, char *, int);
|
|
||||||
|
|
||||||
/* misc helpers */
|
|
||||||
char* (*server_ver)(void);
|
|
||||||
int (*server_name)(char *, int *);
|
|
||||||
void (*log)(int, char *, ...);
|
|
||||||
|
|
||||||
int (*db_count)(void);
|
|
||||||
int (*db_enum_start)(char **, DBQUERYINFO *);
|
|
||||||
int (*db_enum_fetch_row)(char **, char ***, DBQUERYINFO *);
|
|
||||||
int (*db_enum_end)(char **);
|
|
||||||
void (*stream)(WS_CONNINFO *, DBQUERYINFO *, char *);
|
|
||||||
|
|
||||||
PARSETREE (*sp_init)(void);
|
|
||||||
int (*sp_parse)(PARSETREE tree, char *term);
|
|
||||||
int (*sp_dispose)(PARSETREE tree);
|
|
||||||
char* (*sp_get_error)(PARSETREE tree);
|
|
||||||
|
|
||||||
char *(*conf_alloc_string)(char *, char *, char *);
|
|
||||||
void (*conf_dispose_string)(char *);
|
|
||||||
} PLUGIN_INPUT_FN;
|
|
||||||
|
|
||||||
|
|
||||||
/* these are the functions that must be exported by the plugin */
|
|
||||||
PLUGIN_INFO *plugin_info(void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _MTD_PLUGINS_H_ */
|
|
@ -11,20 +11,26 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "mtd-plugins.h"
|
#include "ff-plugins.h"
|
||||||
#include "rsp.h"
|
#include "rsp.h"
|
||||||
#include "xml-rpc.h"
|
#include "xml-rpc.h"
|
||||||
|
|
||||||
|
typedef struct tag_rsp_privinfo {
|
||||||
|
DB_QUERY dq;
|
||||||
|
int uri_count;
|
||||||
|
char *uri_sections[10];
|
||||||
|
} PRIVINFO;
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
PLUGIN_INFO *plugin_info(void);
|
PLUGIN_INFO *plugin_info(void);
|
||||||
void plugin_handler(WS_CONNINFO *pwsc);
|
void plugin_handler(WS_CONNINFO *pwsc);
|
||||||
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw);
|
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw);
|
||||||
void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||||
void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||||
void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||||
void rsp_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||||
void rsp_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||||
void rsp_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, int eno, char *estr);
|
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr);
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
PLUGIN_OUTPUT_FN _pofn = { plugin_handler, plugin_auth };
|
PLUGIN_OUTPUT_FN _pofn = { plugin_handler, plugin_auth };
|
||||||
@ -34,19 +40,21 @@ PLUGIN_REND_INFO _pri[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INFO _pi = {
|
PLUGIN_INFO _pi = {
|
||||||
PLUGIN_VERSION,
|
PLUGIN_VERSION, /* version */
|
||||||
PLUGIN_OUTPUT,
|
PLUGIN_OUTPUT, /* type */
|
||||||
"rsp/" RSP_VERSION,
|
"rsp/" RSP_VERSION, /* server */
|
||||||
"/rsp/.*",
|
"/rsp/.*", /* url */
|
||||||
&_pofn,
|
&_pofn, /* output fns */
|
||||||
NULL,
|
NULL, /* event fns */
|
||||||
NULL,
|
NULL, /* transcode fns */
|
||||||
_pri
|
NULL, /* ff functions */
|
||||||
|
_pri, /* rend info */
|
||||||
|
NULL /* transcode info */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct tag_response {
|
typedef struct tag_response {
|
||||||
char *uri[10];
|
char *uri[10];
|
||||||
void (*dispatch)(WS_CONNINFO *, DBQUERYINFO *);
|
void (*dispatch)(WS_CONNINFO *, PRIVINFO *);
|
||||||
} PLUGIN_RESPONSE;
|
} PLUGIN_RESPONSE;
|
||||||
|
|
||||||
|
|
||||||
@ -155,26 +163,30 @@ int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw) {
|
|||||||
*/
|
*/
|
||||||
void plugin_handler(WS_CONNINFO *pwsc) {
|
void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
char *string, *save, *token;
|
char *string, *save, *token;
|
||||||
DBQUERYINFO *pqi;
|
PRIVINFO *ppi;
|
||||||
int elements;
|
int elements;
|
||||||
int index, part;
|
int index, part;
|
||||||
int found;
|
int found;
|
||||||
|
|
||||||
|
|
||||||
string = infn->ws_uri(pwsc);
|
string = infn->ws_uri(pwsc);
|
||||||
string++;
|
string++;
|
||||||
|
|
||||||
|
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
|
||||||
|
if(ppi) {
|
||||||
|
memset(ppi,0,sizeof(PRIVINFO));
|
||||||
|
}
|
||||||
|
|
||||||
pqi = (DBQUERYINFO *)malloc(sizeof(DBQUERYINFO));
|
if(!ppi) {
|
||||||
if(!pqi) {
|
|
||||||
infn->ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
infn->ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memset(pqi,0,sizeof(DBQUERYINFO));
|
|
||||||
|
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
|
||||||
|
|
||||||
infn->log(E_DBG,"Tokenizing url\n");
|
infn->log(E_DBG,"Tokenizing url\n");
|
||||||
while((pqi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
||||||
string=NULL;
|
string=NULL;
|
||||||
pqi->uri_sections[pqi->uri_count++] = token;
|
ppi->uri_sections[ppi->uri_count++] = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
|
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
|
||||||
@ -188,15 +200,15 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
|||||||
infn->log(E_DBG,"Checking reponse %d\n",index);
|
infn->log(E_DBG,"Checking reponse %d\n",index);
|
||||||
part=0;
|
part=0;
|
||||||
while(part < 10) {
|
while(part < 10) {
|
||||||
if((rsp_uri_map[index].uri[part]) && (!pqi->uri_sections[part]))
|
if((rsp_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
|
||||||
break;
|
break;
|
||||||
if((pqi->uri_sections[part]) && (!rsp_uri_map[index].uri[part]))
|
if((ppi->uri_sections[part]) && (!rsp_uri_map[index].uri[part]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if((rsp_uri_map[index].uri[part]) &&
|
if((rsp_uri_map[index].uri[part]) &&
|
||||||
(strcmp(rsp_uri_map[index].uri[part],"*") != 0)) {
|
(strcmp(rsp_uri_map[index].uri[part],"*") != 0)) {
|
||||||
if(strcmp(rsp_uri_map[index].uri[part],
|
if(strcmp(rsp_uri_map[index].uri[part],
|
||||||
pqi->uri_sections[part])!= 0)
|
ppi->uri_sections[part])!= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
part++;
|
part++;
|
||||||
@ -211,20 +223,22 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(found) {
|
if(found) {
|
||||||
rsp_uri_map[index].dispatch(pwsc, pqi);
|
rsp_uri_map[index].dispatch(pwsc, ppi);
|
||||||
infn->ws_close(pwsc);
|
infn->ws_close(pwsc);
|
||||||
|
free(ppi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp_error(pwsc, pqi, 1, "Bad path");
|
rsp_error(pwsc, ppi, 1, "Bad path");
|
||||||
infn->ws_close(pwsc);
|
infn->ws_close(pwsc);
|
||||||
|
free(ppi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get server info
|
* get server info
|
||||||
*/
|
*/
|
||||||
void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
XMLSTRUCT *pxml;
|
XMLSTRUCT *pxml;
|
||||||
char servername[256];
|
char servername[256];
|
||||||
int size;
|
int size;
|
||||||
@ -262,17 +276,18 @@ void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
*
|
*
|
||||||
* dump details about all playlists
|
* dump details about all playlists
|
||||||
*/
|
*/
|
||||||
void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
XMLSTRUCT *pxml;
|
XMLSTRUCT *pxml;
|
||||||
char *pe;
|
char *pe;
|
||||||
int err;
|
int err;
|
||||||
char **row;
|
char **row;
|
||||||
int rowindex;
|
int rowindex;
|
||||||
|
|
||||||
pqi->want_count = 1;
|
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
|
||||||
pqi->query_type = queryTypePlaylists;
|
|
||||||
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
|
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||||
rsp_error(pwsc, pqi, err | E_DB, pe);
|
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||||
|
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,13 +297,13 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
xml_push(pxml,"status");
|
xml_push(pxml,"status");
|
||||||
xml_output(pxml,"errorcode","0");
|
xml_output(pxml,"errorcode","0");
|
||||||
xml_output(pxml,"errorstring","");
|
xml_output(pxml,"errorstring","");
|
||||||
xml_output(pxml,"records","%d",pqi->specifiedtotalcount);
|
xml_output(pxml,"records","%d",ppi->dq.totalcount);
|
||||||
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
|
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
|
||||||
xml_pop(pxml); /* status */
|
xml_pop(pxml); /* status */
|
||||||
|
|
||||||
xml_push(pxml,"playlists");
|
xml_push(pxml,"playlists");
|
||||||
|
|
||||||
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
|
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||||
xml_push(pxml,"playlist");
|
xml_push(pxml,"playlist");
|
||||||
rowindex=0;
|
rowindex=0;
|
||||||
while(rsp_playlist_fields[rowindex].name) {
|
while(rsp_playlist_fields[rowindex].name) {
|
||||||
@ -302,6 +317,7 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
infn->db_enum_end(NULL);
|
infn->db_enum_end(NULL);
|
||||||
|
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
xml_pop(pxml); /* playlists */
|
xml_pop(pxml); /* playlists */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
@ -312,7 +328,7 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
/**
|
/**
|
||||||
* get all items under the playlist
|
* get all items under the playlist
|
||||||
*/
|
*/
|
||||||
void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
XMLSTRUCT *pxml;
|
XMLSTRUCT *pxml;
|
||||||
char *pe;
|
char *pe;
|
||||||
int err;
|
int err;
|
||||||
@ -321,8 +337,6 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
int returned;
|
int returned;
|
||||||
char *browse_type;
|
char *browse_type;
|
||||||
int type;
|
int type;
|
||||||
char *query;
|
|
||||||
char *estr = NULL;
|
|
||||||
char *transcode_codecs;
|
char *transcode_codecs;
|
||||||
int transcode;
|
int transcode;
|
||||||
int samplerate;
|
int samplerate;
|
||||||
@ -341,30 +355,15 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
query = infn->ws_getvar(pwsc,"query");
|
ppi->dq.filter = infn->ws_getvar(pwsc,"query");
|
||||||
if(query) {
|
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
||||||
pqi->pt = infn->sp_init();
|
|
||||||
if(!infn->sp_parse(pqi->pt,query)) {
|
|
||||||
estr = strdup(infn->sp_get_error(pqi->pt));
|
|
||||||
infn->log(E_LOG,"Ignoring bad query (%s): %s\n",query,estr);
|
|
||||||
infn->sp_dispose(pqi->pt);
|
|
||||||
pqi->pt = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pqi->index_type = indexTypeNone;
|
|
||||||
if(infn->ws_getvar(pwsc,"offset")) {
|
if(infn->ws_getvar(pwsc,"offset")) {
|
||||||
pqi->index_low = atoi(infn->ws_getvar(pwsc,"offset"));
|
ppi->dq.offset = atoi(infn->ws_getvar(pwsc,"offset"));
|
||||||
}
|
}
|
||||||
if(infn->ws_getvar(pwsc,"limit")) {
|
if(infn->ws_getvar(pwsc,"limit")) {
|
||||||
pqi->index_high = pqi->index_low + atoi(infn->ws_getvar(pwsc,"limit")) -1;
|
ppi->dq.limit = atoi(infn->ws_getvar(pwsc,"limit"));
|
||||||
if(pqi->index_high < pqi->index_low) {
|
|
||||||
pqi->index_high = 999999;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pqi->index_high = 999999; /* FIXME */
|
|
||||||
}
|
}
|
||||||
pqi->index_type = indexTypeSub;
|
|
||||||
|
|
||||||
browse_type = infn->ws_getvar(pwsc,"type");
|
browse_type = infn->ws_getvar(pwsc,"type");
|
||||||
type = F_FULL;
|
type = F_FULL;
|
||||||
@ -376,26 +375,24 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
type = F_ID;
|
type = F_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
||||||
|
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
||||||
|
|
||||||
pqi->want_count = 1;
|
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||||
pqi->query_type = queryTypePlaylistItems;
|
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||||
pqi->playlist_id = atoi(pqi->uri_sections[2]);
|
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
free(pe);
|
||||||
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
|
|
||||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
|
||||||
if(estr) free(estr);
|
|
||||||
rsp_error(pwsc, pqi, err | E_DB, pe);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxml = xml_init(pwsc,1);
|
pxml = xml_init(pwsc,1);
|
||||||
|
|
||||||
if(pqi->index_low > pqi->specifiedtotalcount) {
|
if(ppi->dq.offset > ppi->dq.totalcount) {
|
||||||
returned = 0;
|
returned = 0;
|
||||||
} else {
|
} else {
|
||||||
returned = pqi->index_high - pqi->index_low + 1;
|
returned = ppi->dq.limit;
|
||||||
if(returned > (pqi->specifiedtotalcount - pqi->index_low))
|
if(returned > (ppi->dq.totalcount - ppi->dq.offset))
|
||||||
returned = pqi->specifiedtotalcount - pqi->index_low;
|
returned = ppi->dq.totalcount - ppi->dq.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
transcode_codecs = infn->conf_alloc_string("general","ssc_codectypes","");
|
transcode_codecs = infn->conf_alloc_string("general","ssc_codectypes","");
|
||||||
@ -403,14 +400,14 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
xml_push(pxml,"response");
|
xml_push(pxml,"response");
|
||||||
xml_push(pxml,"status");
|
xml_push(pxml,"status");
|
||||||
xml_output(pxml,"errorcode","0");
|
xml_output(pxml,"errorcode","0");
|
||||||
xml_output(pxml,"errorstring",estr ? estr : "");
|
xml_output(pxml,"errorstring","");
|
||||||
xml_output(pxml,"records","%d",returned);
|
xml_output(pxml,"records","%d",returned);
|
||||||
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
|
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
|
||||||
xml_pop(pxml); /* status */
|
xml_pop(pxml); /* status */
|
||||||
|
|
||||||
xml_push(pxml,"items");
|
xml_push(pxml,"items");
|
||||||
|
|
||||||
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
|
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||||
xml_push(pxml,"item");
|
xml_push(pxml,"item");
|
||||||
rowindex=0;
|
rowindex=0;
|
||||||
transcode = 0;
|
transcode = 0;
|
||||||
@ -462,108 +459,75 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
|||||||
xml_pop(pxml); /* items */
|
xml_pop(pxml); /* items */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
xml_deinit(pxml);
|
xml_deinit(pxml);
|
||||||
|
|
||||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
|
||||||
if(estr) free(estr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rsp_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
XMLSTRUCT *pxml;
|
XMLSTRUCT *pxml;
|
||||||
char *pe;
|
char *pe;
|
||||||
int err;
|
int err;
|
||||||
char **row;
|
char **row;
|
||||||
int returned;
|
int returned;
|
||||||
char *query;
|
|
||||||
char *estr = NULL;
|
|
||||||
|
|
||||||
/* FIXME */
|
/* this might fail if an unsupported browse type */
|
||||||
if(!strcmp(pqi->uri_sections[3],"artist")) {
|
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
|
||||||
pqi->query_type = queryTypeBrowseArtists;
|
ppi->dq.distinct_field = ppi->uri_sections[3];
|
||||||
} else if(!strcmp(pqi->uri_sections[3],"genre")) {
|
ppi->dq.filter = infn->ws_getvar(pwsc,"query");
|
||||||
pqi->query_type = queryTypeBrowseGenres;
|
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
||||||
} else if(!strcmp(pqi->uri_sections[3],"album")) {
|
|
||||||
pqi->query_type = queryTypeBrowseAlbums;
|
if(infn->ws_getvar(pwsc,"offset")) {
|
||||||
} else if(!strcmp(pqi->uri_sections[3],"composer")) {
|
ppi->dq.offset = atoi(infn->ws_getvar(pwsc,"offset"));
|
||||||
pqi->query_type = queryTypeBrowseComposers;
|
|
||||||
} else {
|
|
||||||
rsp_error(pwsc, pqi, 0 | E_RSP, "Unsupported browse type");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query = infn->ws_getvar(pwsc,"query");
|
|
||||||
if(query) {
|
|
||||||
pqi->pt = infn->sp_init();
|
|
||||||
if(!infn->sp_parse(pqi->pt,query)) {
|
|
||||||
estr = strdup(infn->sp_get_error(pqi->pt));
|
|
||||||
infn->log(E_LOG,"Ignoring bad query (%s): %s\n",query,estr);
|
|
||||||
infn->sp_dispose(pqi->pt);
|
|
||||||
pqi->pt = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pqi->index_type = indexTypeNone;
|
|
||||||
if(infn->ws_getvar(pwsc,"offset")) {
|
|
||||||
pqi->index_low = atoi(infn->ws_getvar(pwsc,"offset"));
|
|
||||||
}
|
|
||||||
if(infn->ws_getvar(pwsc,"limit")) {
|
if(infn->ws_getvar(pwsc,"limit")) {
|
||||||
pqi->index_high = pqi->index_low + atoi(infn->ws_getvar(pwsc,"limit")) -1;
|
ppi->dq.limit = atoi(infn->ws_getvar(pwsc,"limit"));
|
||||||
if(pqi->index_high < pqi->index_low) {
|
|
||||||
pqi->index_high = 999999;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pqi->index_high = 999999; /* FIXME */
|
|
||||||
}
|
}
|
||||||
pqi->index_type = indexTypeSub;
|
|
||||||
pqi->want_count = 1;
|
|
||||||
pqi->playlist_id = atoi(pqi->uri_sections[2]);
|
|
||||||
|
|
||||||
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
|
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
||||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
|
||||||
if(estr) free(estr);
|
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||||
rsp_error(pwsc, pqi, err | E_DB, pe);
|
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||||
|
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxml = xml_init(pwsc,1);
|
pxml = xml_init(pwsc,1);
|
||||||
|
|
||||||
if(pqi->index_low > pqi->specifiedtotalcount) {
|
if(ppi->dq.offset > ppi->dq.totalcount) {
|
||||||
returned = 0;
|
returned = 0;
|
||||||
} else {
|
} else {
|
||||||
returned = pqi->index_high - pqi->index_low + 1;
|
returned = ppi->dq.limit;
|
||||||
if(returned > (pqi->specifiedtotalcount - pqi->index_low))
|
if(returned > (ppi->dq.totalcount - ppi->dq.offset))
|
||||||
returned = pqi->specifiedtotalcount - pqi->index_low;
|
returned = ppi->dq.totalcount - ppi->dq.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml_push(pxml,"response");
|
xml_push(pxml,"response");
|
||||||
xml_push(pxml,"status");
|
xml_push(pxml,"status");
|
||||||
xml_output(pxml,"errorcode","0");
|
xml_output(pxml,"errorcode","0");
|
||||||
xml_output(pxml,"errorstring",estr ? estr : "");
|
xml_output(pxml,"errorstring","");
|
||||||
xml_output(pxml,"records","%d",returned);
|
xml_output(pxml,"records","%d",returned);
|
||||||
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
|
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
|
||||||
xml_pop(pxml); /* status */
|
xml_pop(pxml); /* status */
|
||||||
|
|
||||||
xml_push(pxml,"items");
|
xml_push(pxml,"items");
|
||||||
|
|
||||||
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
|
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||||
xml_output(pxml,"item",row[0]);
|
xml_output(pxml,"item",row[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
infn->db_enum_end(NULL);
|
infn->db_enum_end(NULL);
|
||||||
|
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
xml_pop(pxml); /* items */
|
xml_pop(pxml); /* items */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
xml_deinit(pxml);
|
xml_deinit(pxml);
|
||||||
|
|
||||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
|
||||||
if(estr) free(estr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rsp_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
infn->stream(pwsc, pqi, pqi->uri_sections[2]);
|
infn->stream(pwsc, ppi->uri_sections[2]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rsp_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, int eno, char *estr) {
|
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr) {
|
||||||
XMLSTRUCT *pxml;
|
XMLSTRUCT *pxml;
|
||||||
|
|
||||||
pxml = xml_init(pwsc, 1);
|
pxml = xml_init(pwsc, 1);
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "mtd-plugins.h"
|
#include "ff-plugins.h"
|
||||||
#include "rsp.h"
|
#include "rsp.h"
|
||||||
#include "xml-rpc.h"
|
#include "xml-rpc.h"
|
||||||
|
|
||||||
|
|
||||||
/* typedefs */
|
/* typedefs */
|
||||||
typedef struct tag_xmlstack {
|
typedef struct tag_xmlstack {
|
||||||
char *tag;
|
char *tag;
|
||||||
@ -135,7 +136,8 @@ int xml_stream_write(XMLSTRUCT *pxml, char *out) {
|
|||||||
if(result != Z_OK) {
|
if(result != Z_OK) {
|
||||||
infn->log(E_FATAL,"Error in zlib: %d\n",result);
|
infn->log(E_FATAL,"Error in zlib: %d\n",result);
|
||||||
}
|
}
|
||||||
infn->ws_writebinary(pxml->pwsc,psb->out_buffer,XML_STREAM_BLOCK-psb->strm.avail_out);
|
infn->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
||||||
|
XML_STREAM_BLOCK-psb->strm.avail_out);
|
||||||
if(psb->strm.avail_out != 0) {
|
if(psb->strm.avail_out != 0) {
|
||||||
done=1;
|
done=1;
|
||||||
} else {
|
} else {
|
||||||
@ -161,7 +163,8 @@ int xml_stream_close(XMLSTRUCT *pxml) {
|
|||||||
psb->strm.next_in = psb->in_buffer;
|
psb->strm.next_in = psb->in_buffer;
|
||||||
|
|
||||||
deflate(&psb->strm,Z_FINISH);
|
deflate(&psb->strm,Z_FINISH);
|
||||||
infn->ws_writebinary(pxml->pwsc,psb->out_buffer,XML_STREAM_BLOCK - psb->strm.avail_out);
|
infn->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
||||||
|
XML_STREAM_BLOCK - psb->strm.avail_out);
|
||||||
|
|
||||||
if(psb->strm.avail_out != 0)
|
if(psb->strm.avail_out != 0)
|
||||||
done=1;
|
done=1;
|
||||||
|
@ -5,10 +5,11 @@
|
|||||||
#ifndef _XMLRPC_H_
|
#ifndef _XMLRPC_H_
|
||||||
#define _XMLRPC_H_
|
#define _XMLRPC_H_
|
||||||
|
|
||||||
#include "mtd-plugins.h"
|
#include "ff-plugins.h"
|
||||||
|
|
||||||
struct tag_xmlstruct;
|
struct tag_xmlstruct;
|
||||||
typedef struct tag_xmlstruct XMLSTRUCT;
|
typedef struct tag_xmlstruct XMLSTRUCT;
|
||||||
|
typedef struct tag_ws_conninfo WS_CONNINFO;
|
||||||
|
|
||||||
extern XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header);
|
extern XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header);
|
||||||
extern void xml_push(XMLSTRUCT *pxml, char *term);
|
extern void xml_push(XMLSTRUCT *pxml, char *term);
|
||||||
|
@ -717,9 +717,9 @@ int sp_parse(PARSETREE tree, char *term, int type) {
|
|||||||
tree->tree = sp_parse_phrase(tree);
|
tree->tree = sp_parse_phrase(tree);
|
||||||
|
|
||||||
if(tree->tree) {
|
if(tree->tree) {
|
||||||
DPRINTF(E_SPAM,L_PARSE,"Parsed successfully\n");
|
DPRINTF(E_SPAM,L_PARSE,"Parsed successfully (type %d)\n",type);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(E_SPAM,L_PARSE,"Parsing error\n");
|
DPRINTF(E_SPAM,L_PARSE,"Parsing error (type %d)\n",type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tree->tree ? 1 : 0;
|
return tree->tree ? 1 : 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user