From 53f8c8166b234ba5354c2aebfb9433cbb52f9175 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Sat, 2 Apr 2005 09:27:53 +0000 Subject: [PATCH] add dmap methods to remotely add a playlist --- src/db-generic.c | 24 +++++++++++++++++++++ src/db-generic.h | 10 +++++++++ src/dbs-sqlite.c | 52 +++++++++++++++++++++++++++++++++++++------- src/dbs-sqlite.h | 1 + src/dispatch.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 134 insertions(+), 9 deletions(-) diff --git a/src/db-generic.c b/src/db-generic.c index 219a12a8..392099d1 100644 --- a/src/db-generic.c +++ b/src/db-generic.c @@ -46,6 +46,7 @@ typedef struct tag_db_functions { int(*dbs_init)(int); int(*dbs_deinit)(void); int(*dbs_add)(MP3FILE*); + int(*dbs_add_playlist)(char *, int, char *, int *); int(*dbs_enum_start)(DBQUERYINFO *); int(*dbs_enum_size)(DBQUERYINFO *, int *); int(*dbs_enum_fetch)(DBQUERYINFO *, unsigned char **); @@ -68,6 +69,7 @@ DB_FUNCTIONS db_functions[] = { db_sqlite_init, db_sqlite_deinit, db_sqlite_add, + db_sqlite_add_playlist, db_sqlite_enum_start, db_sqlite_enum_size, db_sqlite_enum_fetch, @@ -185,6 +187,7 @@ DAAP_ITEMS taglist[] = { /* mt-daapd specific */ { 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" }, { 0x01, "MPTY", "org.mt-daapd.playlist-type" }, + { 0x0C, "MAPR", "org.mt-daapd.addplaylistresponse" }, { 0x00, NULL, NULL } }; @@ -454,6 +457,27 @@ int db_add(MP3FILE *pmp3) { return retval; } +/** + * add a playlist + * + * \param name name of playlist to add + * \param type type of playlist to add: 0 - static, 1 - smart, 2 - m3u + * \param clause where clause (if type 1) + * \param playlistid returns the id of the playlist created + * \returns 0 on success, error code otherwise + */ +int db_add_playlist(char *name, int type, char *clause, int *playlistid) { + int retval; + + db_writelock(); + retval=db_current->dbs_add_playlist(name,type,clause,playlistid); + if(retval == DB_E_SUCCESS) + db_revision_no++; + db_unlock(); + + return retval; +} + /** * start a db enumeration, based info in the DBQUERYINFO struct * diff --git a/src/db-generic.h b/src/db-generic.h index 233af3ee..c603282b 100644 --- a/src/db-generic.h +++ b/src/db-generic.h @@ -155,6 +155,8 @@ extern int db_end_scan(void); extern int db_exists(char *path); extern int db_scanning(void); +extern int db_add_playlist(char *name, int type, char *clause, int *playlistid); + extern MP3FILE *db_fetch_item(int id); extern MP3FILE *db_fetch_path(char *path); @@ -177,4 +179,12 @@ extern int db_get_song_count(void); extern int db_get_playlist_count(void); extern void db_dispose_item(MP3FILE *pmp3); + +#define DB_E_SUCCESS 0 +#define DB_E_SQL_ERROR 1 /**< some kind of sql error - typically bad syntax */ +#define DB_E_DUPLICATE_PLAYLIST 2 /**< playlist already exists when adding */ +#define DB_E_NOCLAUSE 3 /**< adding smart playlist with no clause */ + + + #endif /* _DB_GENERIC_H_ */ diff --git a/src/dbs-sqlite.c b/src/dbs-sqlite.c index 455229b5..0038914f 100644 --- a/src/dbs-sqlite.c +++ b/src/dbs-sqlite.c @@ -53,7 +53,7 @@ void db_sqlite_build_mp3file(char **valarray, MP3FILE *pmp3); int db_sqlite_exec(int fatal, char *fmt, ...); int db_sqlite_get_table(int fatal, char ***resarray, int *rows, int *cols, char *fmt, ...); int db_sqlite_free_table(char **resarray); -int db_sqlite_get_int(int loglevel, char *fmt, ...); +int db_sqlite_get_int(int loglevel, int *result, char *fmt, ...); int db_sqlite_update(MP3FILE *pmp3); int db_sqlite_update_version(int from_version); int db_sqlite_get_version(void); @@ -160,14 +160,13 @@ int db_sqlite_free_table(char **resarray) { /** * db_sqlite_get_int */ -int db_sqlite_get_int(int loglevel, char *fmt, ...) { +int db_sqlite_get_int(int loglevel, int *result, char *fmt, ...) { int rows, cols; char **resarray; va_list ap; char *query; int err; char *perr; - int retval; va_start(ap,fmt); query=sqlite_vmprintf(fmt,ap); @@ -187,13 +186,13 @@ int db_sqlite_get_int(int loglevel, char *fmt, ...) { db_sqlite_lock(); sqlite_freemem(query); db_sqlite_unlock(); - return 0; + return DB_E_SQL_ERROR; } - retval=atoi(resarray[cols]); + *result=atoi(resarray[cols]); sqlite_free_table(resarray); - return retval; + return DB_E_SUCCESS; } @@ -224,10 +223,10 @@ int db_sqlite_open(char *parameters) { */ int db_sqlite_init(int reload) { int items; - int rescan; + int rescan=0; db_sqlite_update_version(db_sqlite_get_version()); - rescan=db_sqlite_get_int(E_DBG,"SELECT value FROM config WHERE term='rescan'"); + db_sqlite_get_int(E_DBG,&rescan,"SELECT value FROM config WHERE term='rescan'"); if(rescan) reload=1; @@ -298,6 +297,43 @@ int db_sqlite_end_scan(void) { } +/** + * add a playlist + * + * \param name name of the playlist + * \param type playlist type: 0 - static, 1 - smart, 2 - m3u + * \param clause: "where" clause for smart playlist + */ +int db_sqlite_add_playlist(char *name, int type, char *clause, int *playlistid) { + int cnt=0; + int result; + + db_sqlite_get_int(E_DBG,&cnt,"select count(*) from playlists where " + "upper(title)=upper('%q')",name); + + if(cnt) return DB_E_DUPLICATE_PLAYLIST; + if((type == 1) && (!clause)) return DB_E_NOCLAUSE; + + /* Let's throw it in */ + if(type == 1) { + result=db_sqlite_get_int(E_DBG,&cnt,"select count (*) from songs where %s",clause); + if(result != DB_E_SUCCESS) return result; + result = db_sqlite_exec(E_LOG,"insert into playlists (title,smart,items,query) " + "values ('%q',1,%d,'%q')",name,cnt,clause); + } else { + result = db_sqlite_exec(E_LOG,"insert into playlists (title,smart,items,query) " + "values ('%q',0,0,NULL)",name); + } + + if(result) + return result; + + result = db_sqlite_get_int(E_LOG,playlistid, + "select id from playlists where title='%q'", name); + + return result; +} + /** * add a database item * diff --git a/src/dbs-sqlite.h b/src/dbs-sqlite.h index cabb4523..117f4408 100644 --- a/src/dbs-sqlite.h +++ b/src/dbs-sqlite.h @@ -37,5 +37,6 @@ extern int db_sqlite_get_count(CountType_t type); extern MP3FILE *db_sqlite_fetch_item(int id); extern MP3FILE *db_sqlite_fetch_path(char *path); extern void db_sqlite_dispose_item(MP3FILE *pmp3); +extern int db_sqlite_add_playlist(char *name, int type, char *clause, int *playlistid); #endif /* _DBS_SQLITE_H_ */ diff --git a/src/dispatch.c b/src/dispatch.c index 2b21397b..74fee3cc 100644 --- a/src/dispatch.c +++ b/src/dispatch.c @@ -52,6 +52,7 @@ static void dispatch_playlistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi); static void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi); static void dispatch_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi); static void dispatch_playlists(WS_CONNINFO *pqsc, DBQUERYINFO *pqi); +static void dispatch_addplaylist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi); static void dispatch_items(WS_CONNINFO *pwsc, DBQUERYINFO *pqi); static void dispatch_logout(WS_CONNINFO *pwsc, DBQUERYINFO *pqi); @@ -177,9 +178,11 @@ void daap_handler(WS_CONNINFO *pwsc) { } pqi->db_id=atoi(pqi->uri_sections[1]); if(pqi->uri_count == 3) { - if(!strcasecmp(pqi->uri_sections[2],"items")) + if(!strcasecmp(pqi->uri_sections[2],"items")) + /* /databases/id/items */ return dispatch_items(pwsc,pqi); if(!strcasecmp(pqi->uri_sections[2],"containers")) + /* /databases/id/containers */ return dispatch_playlists(pwsc,pqi); pwsc->close=1; @@ -189,9 +192,15 @@ void daap_handler(WS_CONNINFO *pwsc) { } if(pqi->uri_count == 4) { if(!strcasecmp(pqi->uri_sections[2],"browse")) + /* /databases/id/browse/something */ return dispatch_browse(pwsc,pqi); if(!strcasecmp(pqi->uri_sections[2],"items")) + /* /databases/id/items/id.mp3 */ return dispatch_stream(pwsc,pqi); + if((!strcasecmp(pqi->uri_sections[2],"containers")) && + (!strcasecmp(pqi->uri_sections[3],"add"))) + /* /databases/id/containers/add */ + return dispatch_addplaylist(pwsc,pqi); pwsc->close=1; free(pqi); @@ -753,6 +762,51 @@ void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) { free(pqi); } +/** + * add a playlist + */ +void dispatch_addplaylist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) { + char playlist_response[32]; + char *current=playlist_response; + char *name, *query; + int type; + int retval, playlistid; + + if((!ws_getvar(pwsc,"org.mt-daapd.playlist-type")) || + (!ws_getvar(pwsc,"dmap.itemname"))) { + DPRINTF(E_LOG,L_DAAP,"attempt to add playlist with invalid type\n"); + ws_returnerror(pwsc,500,"bad playlist info specified"); + return; + } + + type=atoi(ws_getvar(pwsc,"org.mt-daapd.playlist-type")); + name=ws_getvar(pwsc,"dmap.itemname"); + query=ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec"); + + retval=db_add_playlist(name,type,query,&playlistid); + if(retval != DB_E_SUCCESS) { + DPRINTF(E_LOG,L_DAAP,"error adding playlist. aborting\n"); + ws_returnerror(pwsc,500,"error adding playlist"); + return; + } + + /* success... spool out a dmap block */ + current += db_dmap_add_container(current,"MAPR",24); + current += db_dmap_add_int(current,"mstt",200); /* 12 */ + current += db_dmap_add_int(current,"miid",playlistid); /* 12 */ + + dispatch_output_start(pwsc,pqi,32); + dispatch_output_write(pwsc,pqi,playlist_response,32); + dispatch_output_end(pwsc,pqi); + + pwsc->close=1; + + return; +} + +/** + * enumerate and return playlistitems + */ void dispatch_playlistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) { char items_response[61]; char *current=items_response;