mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-27 13:54:49 -04:00
abstract database somewhat, improve error handling
This commit is contained in:
parent
24f40d7956
commit
86b45a028e
@ -30,7 +30,7 @@ MUSEPACKSRC=scan-mpc.c
|
||||
endif
|
||||
|
||||
if COND_SQLITE
|
||||
SQLITEDB=dbs-sqlite.c dbs-sqlite.h
|
||||
SQLITEDB=db-sql.c db-sql.h db-sql-sqlite2.c db-sql-sqlite2.h
|
||||
endif
|
||||
|
||||
wavstreamer_SOURCES = wavstreamer.c
|
||||
|
@ -868,6 +868,7 @@ void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
char buf[256];
|
||||
int r_days, r_hours, r_mins, r_secs;
|
||||
int scanning;
|
||||
int song_count;
|
||||
|
||||
ws_writefd(pwsc,"<table><tr><th align=\"left\">Service</th>");
|
||||
ws_writefd(pwsc,"<th align=\"left\">Status</th><th align=\"left\">Control</th></tr>\n");
|
||||
@ -945,7 +946,8 @@ void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||
|
||||
ws_writefd(pwsc,"<tr>\n");
|
||||
ws_writefd(pwsc," <th>Songs</th>\n");
|
||||
ws_writefd(pwsc," <td>%d</td>\n",db_get_song_count());
|
||||
db_get_song_count(NULL,&song_count);
|
||||
ws_writefd(pwsc," <td>%d</td>\n",song_count);
|
||||
ws_writefd(pwsc,"</tr>\n");
|
||||
|
||||
ws_writefd(pwsc,"<tr>\n");
|
||||
|
186
src/db-generic.c
186
src/db-generic.c
@ -27,6 +27,7 @@
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -34,7 +35,7 @@
|
||||
#include "err.h"
|
||||
#include "mp3-scanner.h"
|
||||
|
||||
#include "dbs-sqlite.h"
|
||||
#include "db-sql.h"
|
||||
|
||||
#define DB_VERSION 1
|
||||
#define MAYBEFREE(a) { if((a)) free((a)); };
|
||||
@ -42,61 +43,59 @@
|
||||
/** pointers to database-specific functions */
|
||||
typedef struct tag_db_functions {
|
||||
char *name;
|
||||
int(*dbs_open)(char *);
|
||||
int(*dbs_open)(char **, char *);
|
||||
int(*dbs_init)(int);
|
||||
int(*dbs_deinit)(void);
|
||||
int(*dbs_add)(MP3FILE*);
|
||||
int(*dbs_add_playlist)(char *, int, char *,char *, int, int *);
|
||||
int(*dbs_add_playlist_item)(int, int);
|
||||
int(*dbs_delete_playlist)(int);
|
||||
int(*dbs_delete_playlist_item)(int, int);
|
||||
int(*dbs_edit_playlist)(int, char*, char*);
|
||||
int(*dbs_enum_start)(DBQUERYINFO *);
|
||||
int(*dbs_enum_size)(DBQUERYINFO *, int *);
|
||||
int(*dbs_enum_fetch)(DBQUERYINFO *, unsigned char **);
|
||||
int(*dbs_enum_reset)(DBQUERYINFO *);
|
||||
int(*dbs_enum_end)(void);
|
||||
int(*dbs_add)(char **, MP3FILE*);
|
||||
int(*dbs_add_playlist)(char **, char *, int, char *,char *, int, int *);
|
||||
int(*dbs_add_playlist_item)(char **, int, int);
|
||||
int(*dbs_delete_playlist)(char **, int);
|
||||
int(*dbs_delete_playlist_item)(char **, int, int);
|
||||
int(*dbs_edit_playlist)(char **, int, char*, char*);
|
||||
int(*dbs_enum_start)(char **, DBQUERYINFO *);
|
||||
int(*dbs_enum_size)(char **, DBQUERYINFO *, int *, int *);
|
||||
int(*dbs_enum_fetch)(char **, DBQUERYINFO *, int *, unsigned char **);
|
||||
int(*dbs_enum_reset)(char **, DBQUERYINFO *);
|
||||
int(*dbs_enum_end)(char **);
|
||||
int(*dbs_start_scan)(void);
|
||||
int(*dbs_end_song_scan)(void);
|
||||
int(*dbs_end_scan)(void);
|
||||
int(*dbs_get_count)(CountType_t);
|
||||
MP3FILE*(*dbs_fetch_item)(int);
|
||||
MP3FILE*(*dbs_fetch_path)(char *,int);
|
||||
M3UFILE*(*dbs_fetch_playlist)(char *, int);
|
||||
int(*dbs_get_count)(char **, int *, CountType_t);
|
||||
MP3FILE*(*dbs_fetch_item)(char **, int);
|
||||
MP3FILE*(*dbs_fetch_path)(char **, char *,int);
|
||||
M3UFILE*(*dbs_fetch_playlist)(char **, char *, int);
|
||||
void(*dbs_dispose_item)(MP3FILE*);
|
||||
void(*dbs_dispose_playlist)(M3UFILE*);
|
||||
}DB_FUNCTIONS;
|
||||
|
||||
/** All supported backend databases, and pointers to the db specific implementations */
|
||||
DB_FUNCTIONS db_functions[] = {
|
||||
#ifdef HAVE_LIBSQLITE
|
||||
{
|
||||
"sqlite",
|
||||
db_sqlite_open,
|
||||
db_sqlite_init,
|
||||
db_sqlite_deinit,
|
||||
db_sqlite_add,
|
||||
db_sqlite_add_playlist,
|
||||
db_sqlite_add_playlist_item,
|
||||
db_sqlite_delete_playlist,
|
||||
db_sqlite_delete_playlist_item,
|
||||
db_sqlite_edit_playlist,
|
||||
db_sqlite_enum_start,
|
||||
db_sqlite_enum_size,
|
||||
db_sqlite_enum_fetch,
|
||||
db_sqlite_enum_reset,
|
||||
db_sqlite_enum_end,
|
||||
db_sqlite_start_scan,
|
||||
db_sqlite_end_song_scan,
|
||||
db_sqlite_end_scan,
|
||||
db_sqlite_get_count,
|
||||
db_sqlite_fetch_item,
|
||||
db_sqlite_fetch_path,
|
||||
db_sqlite_fetch_playlist,
|
||||
db_sqlite_dispose_item,
|
||||
db_sqlite_dispose_playlist
|
||||
"sql",
|
||||
db_sql_open,
|
||||
db_sql_init,
|
||||
db_sql_deinit,
|
||||
db_sql_add,
|
||||
db_sql_add_playlist,
|
||||
db_sql_add_playlist_item,
|
||||
db_sql_delete_playlist,
|
||||
db_sql_delete_playlist_item,
|
||||
db_sql_edit_playlist,
|
||||
db_sql_enum_start,
|
||||
db_sql_enum_size,
|
||||
db_sql_enum_fetch,
|
||||
db_sql_enum_reset,
|
||||
db_sql_enum_end,
|
||||
db_sql_start_scan,
|
||||
db_sql_end_song_scan,
|
||||
db_sql_end_scan,
|
||||
db_sql_get_count,
|
||||
db_sql_fetch_item,
|
||||
db_sql_fetch_path,
|
||||
db_sql_fetch_playlist,
|
||||
db_sql_dispose_item,
|
||||
db_sql_dispose_playlist
|
||||
},
|
||||
#endif
|
||||
{ NULL,NULL }
|
||||
};
|
||||
|
||||
@ -264,6 +263,17 @@ static METAMAP db_metamap[] = {
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
char *db_error_list[] = {
|
||||
"Success",
|
||||
"Misc SQL Error: %s",
|
||||
"Duplicate Playlist: %s",
|
||||
"Missing playlist spec",
|
||||
"Cannot add playlist items to a playlist of that type",
|
||||
"No rows returned",
|
||||
"Invalid playlist id: %d",
|
||||
"Invalid song id: %d",
|
||||
"Parse error"
|
||||
};
|
||||
|
||||
/* Globals */
|
||||
static DB_FUNCTIONS *db_current=&db_functions[0]; /**< current database backend */
|
||||
@ -365,6 +375,22 @@ int db_unlock(void) {
|
||||
return pthread_rwlock_unlock(&db_rwlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an error string
|
||||
*/
|
||||
void db_get_error(char **pe, int error, ...) {
|
||||
va_list ap;
|
||||
char errbuf[1024];
|
||||
|
||||
if(!pe)
|
||||
return;
|
||||
|
||||
va_start(ap, error);
|
||||
vsnprintf(errbuf, sizeof(errbuf), db_error_list[error], ap);
|
||||
va_end(ap);
|
||||
|
||||
*pe = strdup(errbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must dynamically initialize the rwlock, as Mac OSX 10.3 (at least)
|
||||
@ -409,7 +435,7 @@ extern int db_set_backend(char *type) {
|
||||
*
|
||||
* \param parameters This is backend-specific (mysql, sqlite, etc)
|
||||
*/
|
||||
int db_open(char *parameters) {
|
||||
int db_open(char **pe, char *parameters) {
|
||||
int result;
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Opening database\n");
|
||||
@ -417,7 +443,7 @@ int db_open(char *parameters) {
|
||||
if(pthread_once(&db_initlock,db_init_once))
|
||||
return -1;
|
||||
|
||||
result=db_current->dbs_open(parameters);
|
||||
result=db_current->dbs_open(pe, parameters);
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Results: %d\n",result);
|
||||
return result;
|
||||
@ -463,13 +489,13 @@ int db_scanning(void) {
|
||||
/**
|
||||
* add (or update) a file
|
||||
*/
|
||||
int db_add(MP3FILE *pmp3) {
|
||||
int db_add(char **pe, MP3FILE *pmp3) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
db_utf8_validate(pmp3);
|
||||
db_trim_strings(pmp3);
|
||||
retval=db_current->dbs_add(pmp3);
|
||||
retval=db_current->dbs_add(pe,pmp3);
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
|
||||
@ -485,11 +511,11 @@ int db_add(MP3FILE *pmp3) {
|
||||
* \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, char *path, int index, int *playlistid) {
|
||||
int db_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_add_playlist(name,type,clause,path,index,playlistid);
|
||||
retval=db_current->dbs_add_playlist(pe,name,type,clause,path,index,playlistid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
@ -504,11 +530,11 @@ int db_add_playlist(char *name, int type, char *clause, char *path, int index, i
|
||||
* \param songid song to add to playlist
|
||||
* \returns 0 on success, DB_E_ code otherwise
|
||||
*/
|
||||
int db_add_playlist_item(int playlistid, int songid) {
|
||||
int db_add_playlist_item(char **pe, int playlistid, int songid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_add_playlist_item(playlistid,songid);
|
||||
retval=db_current->dbs_add_playlist_item(pe,playlistid,songid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
@ -522,11 +548,11 @@ int db_add_playlist_item(int playlistid, int songid) {
|
||||
* \param playlistid id of the playlist to delete
|
||||
* \returns 0 on success, error code otherwise
|
||||
*/
|
||||
int db_delete_playlist(int playlistid) {
|
||||
int db_delete_playlist(char **pe, int playlistid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_delete_playlist(playlistid);
|
||||
retval=db_current->dbs_delete_playlist(pe,playlistid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
@ -541,11 +567,11 @@ int db_delete_playlist(int playlistid) {
|
||||
* \param songid id of the song to delete
|
||||
* \returns 0 on success, error code otherwise
|
||||
*/
|
||||
int db_delete_playlist_item(int playlistid, int songid) {
|
||||
int db_delete_playlist_item(char **pe, int playlistid, int songid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_delete_playlist_item(playlistid,songid);
|
||||
retval=db_current->dbs_delete_playlist_item(pe,playlistid,songid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
@ -560,12 +586,12 @@ int db_delete_playlist_item(int playlistid, int songid) {
|
||||
* @param name new name of playlist
|
||||
* @param clause new where clause
|
||||
*/
|
||||
int db_edit_playlist(int id, char *name, char *clause) {
|
||||
int db_edit_playlist(char **pe, int id, char *name, char *clause) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
|
||||
retval = db_current->dbs_edit_playlist(id, name, clause);
|
||||
retval = db_current->dbs_edit_playlist(pe, id, name, clause);
|
||||
db_unlock();
|
||||
return retval;
|
||||
}
|
||||
@ -577,11 +603,11 @@ int db_edit_playlist(int id, char *name, char *clause) {
|
||||
* \param pinfo pointer to DBQUERYINFO struction
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int db_enum_start(DBQUERYINFO *pinfo) {
|
||||
int db_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_enum_start(pinfo);
|
||||
retval=db_current->dbs_enum_start(pe, pinfo);
|
||||
|
||||
if(retval) {
|
||||
db_unlock();
|
||||
@ -596,8 +622,8 @@ int db_enum_start(DBQUERYINFO *pinfo) {
|
||||
* db_<dbase>_enum_reset, so it should be positioned at the head
|
||||
* of the list of returned items.
|
||||
*/
|
||||
int db_enum_size(DBQUERYINFO *pinfo, int *count) {
|
||||
return db_current->dbs_enum_size(pinfo,count);
|
||||
int db_enum_size(char **pe, DBQUERYINFO *pinfo, int *size, int *count) {
|
||||
return db_current->dbs_enum_size(pe,pinfo,size,count);
|
||||
}
|
||||
|
||||
|
||||
@ -609,25 +635,27 @@ int db_enum_size(DBQUERYINFO *pinfo, int *count) {
|
||||
* \param plen length of the dmap item returned
|
||||
* \returns dmap item
|
||||
*/
|
||||
int db_enum_fetch(DBQUERYINFO *pinfo, unsigned char **pdmap) {
|
||||
return db_current->dbs_enum_fetch(pinfo,pdmap);
|
||||
int db_enum_fetch(char **pe, DBQUERYINFO *pinfo, int *size,
|
||||
unsigned char **pdmap)
|
||||
{
|
||||
return db_current->dbs_enum_fetch(pe,pinfo,size,pdmap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reset the enum, without coming out the the db_writelock
|
||||
*/
|
||||
int db_enum_reset(DBQUERYINFO *pinfo) {
|
||||
return db_current->dbs_enum_reset(pinfo);
|
||||
int db_enum_reset(char **pe, DBQUERYINFO *pinfo) {
|
||||
return db_current->dbs_enum_reset(pe,pinfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* finish the enumeration
|
||||
*/
|
||||
int db_enum_end(void) {
|
||||
int db_enum_end(char **pe) {
|
||||
int retval;
|
||||
|
||||
retval=db_current->dbs_enum_end();
|
||||
retval=db_current->dbs_enum_end(pe);
|
||||
db_unlock();
|
||||
return retval;
|
||||
}
|
||||
@ -639,31 +667,31 @@ int db_enum_end(void) {
|
||||
*
|
||||
* \param id id of the item to get details for
|
||||
*/
|
||||
MP3FILE *db_fetch_item(int id) {
|
||||
MP3FILE *db_fetch_item(char **pe, int id) {
|
||||
MP3FILE *retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_fetch_item(id);
|
||||
retval=db_current->dbs_fetch_item(pe, id);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
MP3FILE *db_fetch_path(char *path,int index) {
|
||||
MP3FILE *db_fetch_path(char **pe, char *path,int index) {
|
||||
MP3FILE *retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_fetch_path(path, index);
|
||||
retval=db_current->dbs_fetch_path(pe,path, index);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
M3UFILE *db_fetch_playlist(char *path, int index) {
|
||||
M3UFILE *db_fetch_playlist(char **pe, char *path, int index) {
|
||||
M3UFILE *retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_fetch_playlist(path,index);
|
||||
retval=db_current->dbs_fetch_playlist(pe,path,index);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
@ -709,11 +737,11 @@ void db_dispose_playlist(M3UFILE *pm3u) {
|
||||
return db_current->dbs_dispose_playlist(pm3u);
|
||||
}
|
||||
|
||||
int db_get_count(CountType_t type) {
|
||||
int db_get_count(char **pe, int *count, CountType_t type) {
|
||||
int retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_get_count(type);
|
||||
retval=db_current->dbs_get_count(pe,count,type);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
@ -723,12 +751,12 @@ int db_get_count(CountType_t type) {
|
||||
/*
|
||||
* FIXME: clearly a stub
|
||||
*/
|
||||
int db_get_song_count() {
|
||||
return db_get_count(countSongs);
|
||||
int db_get_song_count(char **pe, int *count) {
|
||||
return db_get_count(pe, count, countSongs);
|
||||
}
|
||||
|
||||
int db_get_playlist_count() {
|
||||
return db_get_count(countPlaylists);
|
||||
int db_get_playlist_count(char **pe, int *count) {
|
||||
return db_get_count(pe, count, countPlaylists);
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,34 +137,36 @@ extern DAAP_ITEMS taglist[];
|
||||
|
||||
extern int db_set_backend(char *type);
|
||||
|
||||
extern int db_open(char *parameters);
|
||||
extern int db_open(char **pe, char *parameters);
|
||||
extern int db_init(int reload);
|
||||
extern int db_deinit(void);
|
||||
|
||||
extern int db_revision(void);
|
||||
|
||||
extern int db_add(MP3FILE *pmp3);
|
||||
extern int db_add(char **pe, MP3FILE *pmp3);
|
||||
|
||||
extern int db_enum_start(DBQUERYINFO *pinfo);
|
||||
extern int db_enum_size(DBQUERYINFO *pinfo, int *count);
|
||||
extern int db_enum_fetch(DBQUERYINFO *pinfo, unsigned char **pdmap);
|
||||
extern int db_enum_reset(DBQUERYINFO *pinfo);
|
||||
extern int db_enum_end(void);
|
||||
extern int db_enum_start(char **pe, DBQUERYINFO *pinfo);
|
||||
extern int db_enum_size(char **pe, DBQUERYINFO *pinfo, int *count, int *total_size);
|
||||
extern int db_enum_fetch(char **pe, DBQUERYINFO *pinfo, int *size, unsigned char **pdmap);
|
||||
extern int db_enum_reset(char **pe, DBQUERYINFO *pinfo);
|
||||
extern int db_enum_end(char **pe);
|
||||
extern int db_start_scan(void);
|
||||
extern int db_end_song_scan(void);
|
||||
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, char *path, int index, int *playlistid);
|
||||
extern int db_add_playlist_item(int playlistid, int songid);
|
||||
extern int db_edit_playlist(int id, char *name, char *clause);
|
||||
extern int db_delete_playlist(int playlistid);
|
||||
extern int db_delete_playlist_item(int playlistid, int songid);
|
||||
extern int db_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid);
|
||||
extern int db_add_playlist_item(char **pe, int playlistid, int songid);
|
||||
extern int db_edit_playlist(char **pe, int id, char *name, char *clause);
|
||||
extern int db_delete_playlist(char **pe, int playlistid);
|
||||
extern int db_delete_playlist_item(char **pe, int playlistid, int songid);
|
||||
|
||||
extern MP3FILE *db_fetch_item(int id);
|
||||
extern MP3FILE *db_fetch_path(char *path, int index);
|
||||
extern M3UFILE *db_fetch_playlist(char *path, int index);
|
||||
extern void db_get_error(char **pe, int err, ...);
|
||||
|
||||
extern MP3FILE *db_fetch_item(char **pe, int id);
|
||||
extern MP3FILE *db_fetch_path(char **pe, char *path, int index);
|
||||
extern M3UFILE *db_fetch_playlist(char **pe, char *path, int index);
|
||||
|
||||
|
||||
/* metatag parsing */
|
||||
@ -182,8 +184,9 @@ extern int db_dmap_add_container(unsigned char *where, char *tag, int size);
|
||||
/* Holdover functions from old db interface...
|
||||
* should these be removed? Refactored?
|
||||
*/
|
||||
extern int db_get_song_count(void);
|
||||
extern int db_get_playlist_count(void);
|
||||
|
||||
extern int db_get_song_count(char **pe, int *count);
|
||||
extern int db_get_playlist_count(char **pe, int *count);
|
||||
extern void db_dispose_item(MP3FILE *pmp3);
|
||||
extern void db_dispose_playlist(M3UFILE *pm3u);
|
||||
|
||||
|
456
src/db-sql-sqlite2.c
Normal file
456
src/db-sql-sqlite2.c
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* $Id$
|
||||
* sqlite2-specific db implementation
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron@pedde.com)
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles sqlite2 databases. SQLite2 databases
|
||||
* should have a dsn of:
|
||||
*
|
||||
* sqlite2:/path/to/folder
|
||||
*
|
||||
* The actual db will be appended to the passed path.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sqlite.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "err.h"
|
||||
#include "db-generic.h"
|
||||
#include "db-sql.h"
|
||||
#include "db-sql-sqlite2.h"
|
||||
|
||||
#ifndef TRUE
|
||||
# define TRUE 1
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Globals */
|
||||
static sqlite *db_sqlite2_songs; /**< Database that holds the mp3 info */
|
||||
static pthread_mutex_t db_sqlite2_mutex = PTHREAD_MUTEX_INITIALIZER; /**< sqlite not reentrant */
|
||||
static sqlite_vm *db_sqlite2_pvm;
|
||||
static int db_sqlite2_reload=0;
|
||||
static char *db_sqlite2_enum_query;
|
||||
static int db_sqlite2_in_enum=0;
|
||||
|
||||
static char db_sqlite2_path[PATH_MAX + 1];
|
||||
|
||||
#define DB_SQLITE2_VERSION 8
|
||||
|
||||
|
||||
/* Forwards */
|
||||
void db_sqlite2_lock(void);
|
||||
void db_sqlite2_unlock(void);
|
||||
extern char *db_initial;
|
||||
|
||||
/**
|
||||
* lock the db_mutex
|
||||
*/
|
||||
void db_sqlite2_lock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_lock(&db_sqlite2_mutex))) {
|
||||
DPRINTF(E_FATAL,L_DB,"cannot lock sqlite lock: %s\n",strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unlock the db_mutex
|
||||
*/
|
||||
void db_sqlite2_unlock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_unlock(&db_sqlite2_mutex))) {
|
||||
DPRINTF(E_FATAL,L_DB,"cannot unlock sqlite2 lock: %s\n",strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char *db_sqlite2_vmquery(char *fmt,va_list ap) {
|
||||
return sqlite_vmprintf(fmt,ap);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void db_sqlite2_vmfree(char *query) {
|
||||
sqlite_freemem(query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* open a sqlite2 database
|
||||
*
|
||||
* @param dsn the full dns to the database
|
||||
* (sqlite2:/path/to/database)
|
||||
*
|
||||
* @returns DB_E_SUCCESS on success
|
||||
*/
|
||||
int db_sqlite2_open(char **pe, char *dsn) {
|
||||
char *perr;
|
||||
int ver;
|
||||
int err;
|
||||
|
||||
snprintf(db_sqlite2_path,sizeof(db_sqlite2_path),"%s/songs.db",dsn);
|
||||
|
||||
db_sqlite2_lock();
|
||||
db_sqlite2_songs=sqlite_open(db_sqlite2_path,0666,&perr);
|
||||
if(!db_sqlite2_songs) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||
DPRINTF(E_LOG,L_DB,"db_sqlite2_open: %s (%s)\n",perr,
|
||||
db_sqlite2_path);
|
||||
sqlite_freemem(perr);
|
||||
db_sqlite2_unlock();
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
|
||||
sqlite_busy_timeout(db_sqlite2_songs,30000); /* 30 seconds */
|
||||
|
||||
err = db_sql_fetch_int(pe,&ver,"select value from config where term='version'");
|
||||
if(err != DB_E_SUCCESS) {
|
||||
free(*pe);
|
||||
/* create the table */
|
||||
DPRINTF(E_FATAL,L_DB,"Can't create table yet!\n");
|
||||
}
|
||||
|
||||
if(ver != DB_SQLITE2_VERSION) {
|
||||
DPRINTF(E_FATAL,L_DB,"Can't upgrade database!\n");
|
||||
}
|
||||
|
||||
db_sqlite2_unlock();
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* close the database
|
||||
*/
|
||||
int db_sqlite2_close(void) {
|
||||
db_sqlite2_lock();
|
||||
sqlite_close(db_sqlite2_songs);
|
||||
db_sqlite2_unlock();
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute a throwaway query against the database, disregarding
|
||||
* the outcome
|
||||
*
|
||||
* @param pe db error structure
|
||||
* @param loglevel error level to return if the query fails
|
||||
* @param fmt sprintf-style arguements
|
||||
*
|
||||
* @returns DB_E_SUCCESS on success
|
||||
*/
|
||||
int db_sqlite2_exec(char **pe, int loglevel, char *fmt, ...) {
|
||||
va_list ap;
|
||||
char *query;
|
||||
int err;
|
||||
char *perr;
|
||||
|
||||
va_start(ap,fmt);
|
||||
query=sqlite_vmprintf(fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Executing: %s\n",query);
|
||||
|
||||
db_sqlite2_lock();
|
||||
err=sqlite_exec(db_sqlite2_songs,query,NULL,NULL,&perr);
|
||||
if(err != SQLITE_OK) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||
|
||||
DPRINTF(loglevel == E_FATAL ? E_LOG : loglevel,L_DB,"Query: %s\n",
|
||||
query);
|
||||
DPRINTF(loglevel,L_DB,"Error: %s\n",perr);
|
||||
sqlite_freemem(perr);
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite_changes(db_sqlite2_songs));
|
||||
}
|
||||
sqlite_freemem(query);
|
||||
|
||||
db_sqlite2_unlock();
|
||||
|
||||
if(err != SQLITE_OK)
|
||||
return DB_E_SQL_ERROR;
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* start enumerating rows in a select
|
||||
*/
|
||||
int db_sqlite2_enum_begin(char **pe, char *fmt, ...) {
|
||||
va_list ap;
|
||||
int err;
|
||||
char *perr;
|
||||
const char *ptail;
|
||||
|
||||
if(!db_sqlite2_in_enum) {
|
||||
va_start(ap, fmt);
|
||||
db_sqlite2_lock();
|
||||
db_sqlite2_enum_query = sqlite_vmprintf(fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Executing :%s\n",db_sqlite2_enum_query);
|
||||
db_sqlite2_in_enum=1;
|
||||
|
||||
err=sqlite_compile(db_sqlite2_songs,db_sqlite2_enum_query,&ptail,&db_sqlite2_pvm,&perr);
|
||||
|
||||
if(err != SQLITE_OK) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||
sqlite_freemem(perr);
|
||||
db_sqlite2_in_enum=0;
|
||||
db_sqlite2_unlock();
|
||||
sqlite_freemem(db_sqlite2_enum_query);
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
|
||||
/* otherwise, we leave the db locked while we walk through the enums */
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch the next row
|
||||
*
|
||||
* @param pe error string, if result isn't DB_E_SUCCESS
|
||||
* @param pr pointer to a row struct
|
||||
*
|
||||
* @returns DB_E_SUCCESS with *pr=NULL when end of table,
|
||||
* DB_E_SUCCESS with a valid row when more data,
|
||||
* DB_E_* on error
|
||||
*/
|
||||
int db_sqlite2_enum_fetch(char **pe, SQL_ROW *pr) {
|
||||
int err;
|
||||
char *perr=NULL;;
|
||||
const char **colarray;
|
||||
int cols;
|
||||
int counter=10;
|
||||
|
||||
while(counter--) {
|
||||
err=sqlite_step(db_sqlite2_pvm,&cols,(const char ***)pr,&colarray);
|
||||
if(err != SQLITE_BUSY)
|
||||
break;
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
if(err == SQLITE_DONE) {
|
||||
*pr = NULL;
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
if(err == SQLITE_ROW) {
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* end the db enumeration
|
||||
*/
|
||||
int db_sqlite2_enum_end(char **pe) {
|
||||
int err;
|
||||
char *perr;
|
||||
|
||||
db_sqlite2_in_enum=0;
|
||||
sqlite_freemem(db_sqlite2_enum_query);
|
||||
|
||||
err = sqlite_finalize(db_sqlite2_pvm,&perr);
|
||||
if(err != SQLITE_OK) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||
sqlite_freemem(perr);
|
||||
db_sqlite2_unlock();
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
|
||||
db_sqlite2_unlock();
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* restart the enumeration
|
||||
*/
|
||||
int db_sqlite2_enum_restart(char **pe) {
|
||||
return db_sqlite2_enum_begin(pe,NULL);
|
||||
}
|
||||
|
||||
|
||||
int db_sqlite2_event(int event_type) {
|
||||
switch(event_type) {
|
||||
|
||||
case DB_SQL_EVENT_STARTUP: /* this is a startup with existing songs */
|
||||
db_sqlite2_exec(NULL,E_FATAL,"vacuum");
|
||||
db_sqlite2_reload=0;
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_FULLRELOAD: /* either a fresh load or force load */
|
||||
db_sqlite2_exec(NULL,E_DBG,"delete index idx_path");
|
||||
db_sqlite2_exec(NULL,E_DBG,"delete index idx_songid");
|
||||
db_sqlite2_exec(NULL,E_DBG,"delete index idx_playlistid");
|
||||
|
||||
db_sqlite2_exec(NULL,E_DBG,"drop table songs");
|
||||
db_sqlite2_exec(NULL,E_DBG,"drop table playlists");
|
||||
db_sqlite2_exec(NULL,E_DBG,"drop table playlistitems");
|
||||
db_sqlite2_exec(NULL,E_DBG,"drop table config");
|
||||
|
||||
db_sqlite2_exec(NULL,E_DBG,"vacuum");
|
||||
|
||||
db_sqlite2_exec(NULL,E_DBG,db_initial);
|
||||
db_sqlite2_reload=1;
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_SONGSCANSTART:
|
||||
if(db_sqlite2_reload) {
|
||||
db_sqlite2_exec(NULL,E_FATAL,"pragma synchronous = off");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"begin transaction");
|
||||
} else {
|
||||
db_sqlite2_exec(NULL,E_DBG,"drop table updated");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"create temp table updated (id int)");
|
||||
db_sqlite2_exec(NULL,E_DBG,"drop table plupdated");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"create temp table plupdated(id int)");
|
||||
}
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_SONGSCANEND:
|
||||
if(db_sqlite2_reload) {
|
||||
db_sqlite2_exec(NULL,E_FATAL,"commit transaction");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"create index idx_path on songs(path)");
|
||||
db_sqlite2_exec(NULL,E_DBG,"delete from config where term='rescan'");
|
||||
} else {
|
||||
db_sqlite2_exec(NULL,E_FATAL,"delete from songs where id not in (select id from updated)");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"update songs set force_update=0");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"drop table updated");
|
||||
}
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_PLSCANSTART:
|
||||
db_sqlite2_exec(NULL,E_FATAL,"begin transaction");
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_PLSCANEND:
|
||||
db_sqlite2_exec(NULL,E_FATAL,"end transaction");
|
||||
|
||||
if(db_sqlite2_reload) {
|
||||
db_sqlite2_exec(NULL,E_FATAL,"pragma synchronous=normal");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"create index idx_songid on playlistitems(songid)");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"create index idx_playlistid on playlistitems(playlistid)");
|
||||
|
||||
} else {
|
||||
db_sqlite2_exec(NULL,E_FATAL,"delete from playlists where "
|
||||
"((type=%d) OR (type=%d)) and "
|
||||
"id not in (select id from plupdated)",
|
||||
PL_STATICFILE,PL_STATICXML);
|
||||
db_sqlite2_exec(NULL,E_FATAL,"delete from playlistitems where "
|
||||
"playlistid not in (select distinct "
|
||||
"id from playlists)");
|
||||
db_sqlite2_exec(NULL,E_FATAL,"drop table plupdated");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
char *db_initial =
|
||||
"create table songs (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" path VARCHAR(4096) UNIQUE NOT NULL,\n"
|
||||
" fname VARCHAR(255) NOT NULL,\n"
|
||||
" title VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" artist VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" album VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" genre VARCHAR(255) DEFAULT NULL,\n"
|
||||
" comment VARCHAR(4096) DEFAULT NULL,\n"
|
||||
" type VARCHAR(255) DEFAULT NULL,\n"
|
||||
" composer VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" orchestra VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" conductor VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" grouping VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" url VARCHAR(1024) DEFAULT NULL,\n"
|
||||
" bitrate INTEGER DEFAULT 0,\n"
|
||||
" samplerate INTEGER DEFAULT 0,\n"
|
||||
" song_length INTEGER DEFAULT 0,\n"
|
||||
" file_size INTEGER DEFAULT 0,\n"
|
||||
" year INTEGER DEFAULT 0,\n"
|
||||
" track INTEGER DEFAULT 0,\n"
|
||||
" total_tracks INTEGER DEFAULT 0,\n"
|
||||
" disc INTEGER DEFAULT 0,\n"
|
||||
" total_discs INTEGER DEFAULT 0,\n"
|
||||
" bpm INTEGER DEFAULT 0,\n"
|
||||
" compilation INTEGER DEFAULT 0,\n"
|
||||
" rating INTEGER DEFAULT 0,\n"
|
||||
" play_count INTEGER DEFAULT 0,\n"
|
||||
" data_kind INTEGER DEFAULT 0,\n"
|
||||
" item_kind INTEGER DEFAULT 0,\n"
|
||||
" description INTEGER DEFAULT 0,\n"
|
||||
" time_added INTEGER DEFAULT 0,\n"
|
||||
" time_modified INTEGER DEFAULT 0,\n"
|
||||
" time_played INTEGER DEFAULT 0,\n"
|
||||
" db_timestamp INTEGER DEFAULT 0,\n"
|
||||
" disabled INTEGER DEFAULT 0,\n"
|
||||
" sample_count INTEGER DEFAULT 0,\n"
|
||||
" force_update INTEGER DEFAULT 0,\n"
|
||||
" codectype VARCHAR(5) DEFAULT NULL,\n"
|
||||
" idx INTEGER NOT NULL\n"
|
||||
");\n"
|
||||
"create table config (\n"
|
||||
" term VARCHAR(255) NOT NULL,\n"
|
||||
" subterm VARCHAR(255) DEFAULT NULL,\n"
|
||||
" value VARCHAR(1024) NOT NULL\n"
|
||||
");\n"
|
||||
"create table playlistitems (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" playlistid INTEGER NOT NULL,\n"
|
||||
" songid INTEGER NOT NULL\n"
|
||||
");\n"
|
||||
"create table playlists (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" title VARCHAR(255) NOT NULL,\n"
|
||||
" type INTEGER NOT NULL,\n"
|
||||
" items INTEGER NOT NULL,\n"
|
||||
" query VARCHAR(1024),\n"
|
||||
" db_timestamp INTEGER NOT NULL,\n"
|
||||
" path VARCHAR(4096),\n"
|
||||
" idx INTEGER NOT NULL\n"
|
||||
");\n"
|
||||
"insert into config values ('version','','1');\n"
|
||||
"insert into playlists values (1,'Library',1,0,'1',0,'',0);\n"
|
||||
"create index idx_path on songs(path);\n"
|
||||
"create index idx_songid on playlistitems(songid);\n"
|
||||
"create index idx_playlistid on playlistitems(playlistid);\n";
|
||||
|
||||
|
42
src/db-sql-sqlite2.h
Normal file
42
src/db-sql-sqlite2.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* $Id$
|
||||
* sqlite2-specific db implementation
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron@pedde.com)
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _DB_SQL_SQLITE2_
|
||||
#define _DB_SQL_SQLITE2_
|
||||
|
||||
extern int db_sqlite2_open(char **pe, char *dsn);
|
||||
extern int db_sqlite2_close(void);
|
||||
|
||||
/* simple utility functions */
|
||||
extern int db_sqlite2_exec(char **pe, int loglevel, char *fmt, ...);
|
||||
extern char *db_sqlite2_vmquery(char *fmt,va_list ap);
|
||||
extern void db_sqlite2_vmfree(char *query);
|
||||
|
||||
/* walk through a table */
|
||||
extern int db_sqlite2_enum_begin(char **pe, char *fmt, ...);
|
||||
extern int db_sqlite2_enum_fetch(char **pe, SQL_ROW *pr);
|
||||
extern int db_sqlite2_enum_end(char **pe);
|
||||
extern int db_sqlite2_enum_restart(char **pe);
|
||||
|
||||
int db_sqlite2_event(int event_type);
|
||||
|
||||
#endif /* _DB_SQL_SQLITE2_ */
|
||||
|
1636
src/db-sql.c
Normal file
1636
src/db-sql.c
Normal file
File diff suppressed because it is too large
Load Diff
114
src/db-sql.h
Normal file
114
src/db-sql.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* $Id$
|
||||
* sql-specific db implementation
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron@pedde.com)
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _DB_SQL_H_
|
||||
#define _DB_SQL_H_
|
||||
|
||||
typedef char** SQL_ROW;
|
||||
|
||||
extern int db_sql_open(char **pe, char *parameters);
|
||||
extern int db_sql_init(int reload);
|
||||
extern int db_sql_deinit(void);
|
||||
extern int db_sql_add(char **pe, MP3FILE *pmp3);
|
||||
extern int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo);
|
||||
extern int db_sql_enum_size(char **pe, DBQUERYINFO *pinfo, int *count, int *total_size);
|
||||
extern int db_sql_enum_fetch(char **pe, DBQUERYINFO *pinfo, int *size, unsigned char **pdmap);
|
||||
extern int db_sql_enum_reset(char **pe, DBQUERYINFO *pinfo);
|
||||
extern int db_sql_enum_end(char **pe);
|
||||
extern int db_sql_start_scan(void);
|
||||
extern int db_sql_end_song_scan(void);
|
||||
extern int db_sql_end_scan(void);
|
||||
extern int db_sql_get_count(char **pe, int *count, CountType_t type);
|
||||
extern MP3FILE *db_sql_fetch_item(char **pe, int id);
|
||||
extern MP3FILE *db_sql_fetch_path(char **pe, char *path,int index);
|
||||
extern M3UFILE *db_sql_fetch_playlist(char **pe, char *path, int index);
|
||||
extern void db_sql_dispose_item(MP3FILE *pmp3);
|
||||
extern void db_sql_dispose_playlist(M3UFILE *pm3u);
|
||||
extern int db_sql_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid);
|
||||
extern int db_sql_add_playlist_item(char **pe, int playlistid, int songid);
|
||||
extern int db_sql_edit_playlist(char **pe, int id, char *name, char *clause);
|
||||
extern int db_sql_delete_playlist(char **pe, int playlistid);
|
||||
extern int db_sql_delete_playlist_item(char **pe, int playlistid, int songid);
|
||||
|
||||
extern int db_sql_fetch_row(char **pe, SQL_ROW *row, char *fmt, ...);
|
||||
extern int db_sql_fetch_int(char **pe, int *result, char *fmt, ...);
|
||||
extern int db_sql_fetch_char(char **pe, char **result, char *fmt, ...);
|
||||
extern int db_sql_dispose_row(void);
|
||||
|
||||
typedef enum {
|
||||
songID,
|
||||
songPath,
|
||||
songFname,
|
||||
songTitle,
|
||||
songArtist,
|
||||
songAlbum,
|
||||
songGenre,
|
||||
songComment,
|
||||
songType,
|
||||
songComposer,
|
||||
songOrchestra,
|
||||
songGrouping,
|
||||
songURL,
|
||||
songBitrate,
|
||||
songSampleRate,
|
||||
songLength,
|
||||
songFilesize,
|
||||
songYear,
|
||||
songTrack,
|
||||
songTotalTracks,
|
||||
songDisc,
|
||||
songTotalDiscs,
|
||||
songBPM,
|
||||
songCompilation,
|
||||
songRating,
|
||||
songPlayCount,
|
||||
songDataKind,
|
||||
songItemKind,
|
||||
songDescription,
|
||||
songTimeAdded,
|
||||
songTimeModified,
|
||||
songTimePlayed,
|
||||
songDBTimestamp,
|
||||
songDisabled,
|
||||
songSampleCount,
|
||||
songForceUpdate,
|
||||
songCodecType
|
||||
} SongField_t;
|
||||
|
||||
typedef enum {
|
||||
plID,
|
||||
plTitle,
|
||||
plType,
|
||||
plItems,
|
||||
plQuery,
|
||||
plDBTimestamp,
|
||||
plPath
|
||||
} PlaylistField_t;
|
||||
|
||||
#define DB_SQL_EVENT_STARTUP 0
|
||||
#define DB_SQL_EVENT_SONGSCANSTART 1
|
||||
#define DB_SQL_EVENT_SONGSCANEND 2
|
||||
#define DB_SQL_EVENT_PLSCANSTART 3
|
||||
#define DB_SQL_EVENT_PLSCANEND 4
|
||||
#define DB_SQL_EVENT_FULLRELOAD 5
|
||||
|
||||
|
||||
#endif /* _DB_SQL_H_ */
|
1935
src/dbs-sqlite.c
1935
src/dbs-sqlite.c
File diff suppressed because it is too large
Load Diff
100
src/dbs-sqlite.h
100
src/dbs-sqlite.h
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
* sqlite-specific db implementation
|
||||
*
|
||||
* Copyright (C) 2005 Ron Pedde (ron@pedde.com)
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _DBS_SQLITE_H_
|
||||
#define _DBS_SQLITE_H_
|
||||
|
||||
extern int db_sqlite_open(char *parameters);
|
||||
extern int db_sqlite_init(int reload);
|
||||
extern int db_sqlite_deinit(void);
|
||||
extern int db_sqlite_add(MP3FILE *pmp3);
|
||||
extern int db_sqlite_enum_start(DBQUERYINFO *pinfo);
|
||||
extern int db_sqlite_enum_size(DBQUERYINFO *pinfo, int *count);
|
||||
extern int db_sqlite_enum_fetch(DBQUERYINFO *pinfo, unsigned char **pdmap);
|
||||
extern int db_sqlite_enum_reset(DBQUERYINFO *pinfo);
|
||||
extern int db_sqlite_enum_end(void);
|
||||
extern int db_sqlite_start_scan(void);
|
||||
extern int db_sqlite_end_song_scan(void);
|
||||
extern int db_sqlite_end_scan(void);
|
||||
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,int index);
|
||||
extern M3UFILE *db_sqlite_fetch_playlist(char *path, int index);
|
||||
extern void db_sqlite_dispose_item(MP3FILE *pmp3);
|
||||
extern void db_sqlite_dispose_playlist(M3UFILE *pm3u);
|
||||
extern int db_sqlite_add_playlist(char *name, int type, char *clause, char *path, int index, int *playlistid);
|
||||
extern int db_sqlite_add_playlist_item(int playlistid, int songid);
|
||||
extern int db_sqlite_edit_playlist(int id, char *name, char *clause);
|
||||
extern int db_sqlite_delete_playlist(int playlistid);
|
||||
extern int db_sqlite_delete_playlist_item(int playlistid, int songid);
|
||||
|
||||
typedef enum {
|
||||
songID,
|
||||
songPath,
|
||||
songFname,
|
||||
songTitle,
|
||||
songArtist,
|
||||
songAlbum,
|
||||
songGenre,
|
||||
songComment,
|
||||
songType,
|
||||
songComposer,
|
||||
songOrchestra,
|
||||
songGrouping,
|
||||
songURL,
|
||||
songBitrate,
|
||||
songSampleRate,
|
||||
songLength,
|
||||
songFilesize,
|
||||
songYear,
|
||||
songTrack,
|
||||
songTotalTracks,
|
||||
songDisc,
|
||||
songTotalDiscs,
|
||||
songBPM,
|
||||
songCompilation,
|
||||
songRating,
|
||||
songPlayCount,
|
||||
songDataKind,
|
||||
songItemKind,
|
||||
songDescription,
|
||||
songTimeAdded,
|
||||
songTimeModified,
|
||||
songTimePlayed,
|
||||
songDBTimestamp,
|
||||
songDisabled,
|
||||
songSampleCount,
|
||||
songForceUpdate,
|
||||
songCodecType
|
||||
} SongField_t;
|
||||
|
||||
typedef enum {
|
||||
plID,
|
||||
plTitle,
|
||||
plType,
|
||||
plItems,
|
||||
plQuery,
|
||||
plDBTimestamp,
|
||||
plPath
|
||||
} PlaylistField_t;
|
||||
|
||||
|
||||
#endif /* _DBS_SQLITE_H_ */
|
@ -633,7 +633,8 @@ void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
offset=(off_t)atol(ws_getrequestheader(pwsc,"range") + 6);
|
||||
}
|
||||
|
||||
pmp3=db_fetch_item(item);
|
||||
/* FIXME: error handling */
|
||||
pmp3=db_fetch_item(NULL,item);
|
||||
if(!pmp3) {
|
||||
DPRINTF(E_LOG,L_DAAP|L_WS|L_DB,"Could not find requested item %lu\n",item);
|
||||
ws_returnerror(pwsc,404,"File Not Found");
|
||||
@ -836,7 +837,8 @@ void dispatch_addplaylistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
while((token=strsep((char**)¤t,","))) {
|
||||
if(token) {
|
||||
db_add_playlist_item(pqi->playlist_id,atoi(token));
|
||||
/* FIXME: error handling */
|
||||
db_add_playlist_item(NULL,pqi->playlist_id,atoi(token));
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,7 +871,8 @@ void dispatch_deleteplaylist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
return;
|
||||
}
|
||||
|
||||
db_delete_playlist(atoi(ws_getvar(pwsc,"dmap.itemid")));
|
||||
/* FIXME: error handling */
|
||||
db_delete_playlist(NULL,atoi(ws_getvar(pwsc,"dmap.itemid")));
|
||||
|
||||
/* success(ish)... spool out a dmap block */
|
||||
current = playlist_response;
|
||||
@ -905,7 +908,8 @@ void dispatch_deleteplaylistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
while((token=strsep((char**)¤t,","))) {
|
||||
if(token) {
|
||||
db_delete_playlist_item(pqi->playlist_id,atoi(token));
|
||||
/* FIXME: Error handling */
|
||||
db_delete_playlist_item(NULL,pqi->playlist_id,atoi(token));
|
||||
}
|
||||
}
|
||||
|
||||
@ -946,7 +950,8 @@ void dispatch_addplaylist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
name=ws_getvar(pwsc,"dmap.itemname");
|
||||
query=ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec");
|
||||
|
||||
retval=db_add_playlist(name,type,query,NULL,0,&playlistid);
|
||||
/* FIXME: Error handling */
|
||||
retval=db_add_playlist(NULL,name,type,query,NULL,0,&playlistid);
|
||||
if(retval != DB_E_SUCCESS) {
|
||||
DPRINTF(E_LOG,L_DAAP,"error adding playlist. aborting\n");
|
||||
ws_returnerror(pwsc,500,"error adding playlist");
|
||||
@ -990,7 +995,8 @@ void dispatch_editplaylist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
query=ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec");
|
||||
id=atoi(ws_getvar(pwsc,"dmap.itemid"));
|
||||
|
||||
retval=db_edit_playlist(id,name,query);
|
||||
/* FIXME: Error handling */
|
||||
retval=db_edit_playlist(NULL,id,name,query);
|
||||
if(retval != DB_E_SUCCESS) {
|
||||
DPRINTF(E_LOG,L_DAAP,"error editing playlist.");
|
||||
ws_returnerror(pwsc,500,"Error editing playlist");
|
||||
@ -1031,13 +1037,16 @@ void dispatch_playlistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
pqi->query_type = queryTypePlaylistItems;
|
||||
pqi->index_type=indexTypeNone;
|
||||
if(db_enum_start(pqi)) {
|
||||
|
||||
/* FIXME: Error handling */
|
||||
if(db_enum_start(NULL,pqi)) {
|
||||
DPRINTF(E_LOG,L_DAAP,"Could not start enum\n");
|
||||
ws_returnerror(pwsc,500,"Internal server error: out of memory!");
|
||||
return;
|
||||
}
|
||||
|
||||
list_length=db_enum_size(pqi,&song_count);
|
||||
/* FIXME: Error handling */
|
||||
db_enum_size(NULL,pqi,&song_count,&list_length);
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP,"Item enum: got %d songs, dmap size: %d\n",song_count,list_length);
|
||||
|
||||
@ -1051,7 +1060,9 @@ void dispatch_playlistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
dispatch_output_start(pwsc,pqi,61+list_length);
|
||||
dispatch_output_write(pwsc,pqi,items_response,61);
|
||||
|
||||
while((list_length=db_enum_fetch(pqi,&block)) > 0) {
|
||||
while((db_enum_fetch(NULL,pqi,&list_length,&block) == DB_E_SUCCESS) &&
|
||||
(list_length))
|
||||
{
|
||||
DPRINTF(E_SPAM,L_DAAP,"Got block of size %d\n",list_length);
|
||||
dispatch_output_write(pwsc,pqi,block,list_length);
|
||||
free(block);
|
||||
@ -1059,7 +1070,7 @@ void dispatch_playlistitems(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP,"Done enumerating.\n");
|
||||
|
||||
db_enum_end();
|
||||
db_enum_end(NULL);
|
||||
|
||||
dispatch_output_end(pwsc,pqi);
|
||||
return;
|
||||
@ -1095,7 +1106,7 @@ void dispatch_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
pqi->index_type = indexTypeNone;
|
||||
|
||||
if(db_enum_start(pqi)) {
|
||||
if(db_enum_start(NULL,pqi)) {
|
||||
DPRINTF(E_LOG,L_DAAP|L_BROW,"Could not start enum\n");
|
||||
ws_returnerror(pwsc,500,"Internal server error: out of memory!\n");
|
||||
return;
|
||||
@ -1103,7 +1114,8 @@ void dispatch_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP|L_BROW,"Getting enum size.\n");
|
||||
|
||||
list_length=db_enum_size(pqi,&item_count);
|
||||
/* FIXME: Error handling */
|
||||
db_enum_size(NULL,pqi,&item_count,&list_length);
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP|L_BROW,"Item enum: got %d items, dmap size: %d\n",
|
||||
item_count,list_length);
|
||||
@ -1117,7 +1129,9 @@ void dispatch_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
dispatch_output_start(pwsc,pqi,52+list_length);
|
||||
dispatch_output_write(pwsc,pqi,browse_response,52);
|
||||
|
||||
while((list_length=db_enum_fetch(pqi,&block)) > 0) {
|
||||
while((db_enum_fetch(NULL,pqi,&list_length,&block) == DB_E_SUCCESS) &&
|
||||
(list_length))
|
||||
{
|
||||
DPRINTF(E_SPAM,L_DAAP|L_BROW,"Got block of size %d\n",list_length);
|
||||
dispatch_output_write(pwsc,pqi,block,list_length);
|
||||
free(block);
|
||||
@ -1125,7 +1139,7 @@ void dispatch_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP|L_BROW,"Done enumerating\n");
|
||||
|
||||
db_enum_end();
|
||||
db_enum_end(NULL);
|
||||
|
||||
dispatch_output_end(pwsc,pqi);
|
||||
return;
|
||||
@ -1151,13 +1165,14 @@ void dispatch_playlists(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
pqi->query_type = queryTypePlaylists;
|
||||
pqi->index_type = indexTypeNone;
|
||||
if(db_enum_start(pqi)) {
|
||||
if(db_enum_start(NULL,pqi)) {
|
||||
DPRINTF(E_LOG,L_DAAP,"Could not start enum\n");
|
||||
ws_returnerror(pwsc,500,"Internal server error: out of memory!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
list_length=db_enum_size(pqi,&pl_count);
|
||||
/* FIXME: Error handling */
|
||||
db_enum_size(NULL,pqi,&pl_count,&list_length);
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP,"Item enum: got %d playlists, dmap size: %d\n",pl_count,list_length);
|
||||
|
||||
@ -1171,7 +1186,9 @@ void dispatch_playlists(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
dispatch_output_start(pwsc,pqi,61+list_length);
|
||||
dispatch_output_write(pwsc,pqi,playlist_response,61);
|
||||
|
||||
while((list_length=db_enum_fetch(pqi,&block)) > 0) {
|
||||
while((db_enum_fetch(NULL,pqi,&list_length,&block) == DB_E_SUCCESS) &&
|
||||
(list_length))
|
||||
{
|
||||
DPRINTF(E_SPAM,L_DAAP,"Got block of size %d\n",list_length);
|
||||
dispatch_output_write(pwsc,pqi,block,list_length);
|
||||
free(block);
|
||||
@ -1179,7 +1196,7 @@ void dispatch_playlists(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP,"Done enumerating.\n");
|
||||
|
||||
db_enum_end();
|
||||
db_enum_end(NULL);
|
||||
|
||||
dispatch_output_end(pwsc,pqi);
|
||||
return;
|
||||
@ -1200,13 +1217,14 @@ void dispatch_items(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
pqi->query_type = queryTypeItems;
|
||||
pqi->index_type=indexTypeNone;
|
||||
if(db_enum_start(pqi)) {
|
||||
if(db_enum_start(NULL,pqi)) {
|
||||
DPRINTF(E_LOG,L_DAAP,"Could not start enum\n");
|
||||
ws_returnerror(pwsc,500,"Internal server error: out of memory!");
|
||||
return;
|
||||
}
|
||||
|
||||
list_length=db_enum_size(pqi,&song_count);
|
||||
/* FIXME: Error handling */
|
||||
db_enum_size(NULL,pqi,&song_count,&list_length);
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP,"Item enum: got %d songs, dmap size: %d\n",song_count,list_length);
|
||||
|
||||
@ -1220,7 +1238,9 @@ void dispatch_items(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
dispatch_output_start(pwsc,pqi,61+list_length);
|
||||
dispatch_output_write(pwsc,pqi,items_response,61);
|
||||
|
||||
while((list_length=db_enum_fetch(pqi,&block)) > 0) {
|
||||
while((db_enum_fetch(NULL,pqi,&list_length,&block) == DB_E_SUCCESS) &&
|
||||
(list_length))
|
||||
{
|
||||
DPRINTF(E_SPAM,L_DAAP,"Got block of size %d\n",list_length);
|
||||
dispatch_output_write(pwsc,pqi,block,list_length);
|
||||
free(block);
|
||||
@ -1228,7 +1248,7 @@ void dispatch_items(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
|
||||
DPRINTF(E_DBG,L_DAAP,"Done enumerating.\n");
|
||||
|
||||
db_enum_end();
|
||||
db_enum_end(NULL);
|
||||
|
||||
dispatch_output_end(pwsc,pqi);
|
||||
return;
|
||||
@ -1280,6 +1300,7 @@ void dispatch_dbinfo(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
unsigned char dbinfo_response[255]; /* FIXME */
|
||||
unsigned char *current = dbinfo_response;
|
||||
int namelen;
|
||||
int count;
|
||||
|
||||
namelen=strlen(config.servername);
|
||||
|
||||
@ -1292,8 +1313,10 @@ void dispatch_dbinfo(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
current += db_dmap_add_container(current,"mlit",44 + namelen);
|
||||
current += db_dmap_add_int(current,"miid",1); /* 12 */
|
||||
current += db_dmap_add_string(current,"minm",config.servername); /* 8 + namelen */
|
||||
current += db_dmap_add_int(current,"mimc",db_get_song_count()); /* 12 */
|
||||
current += db_dmap_add_int(current,"mctc",db_get_playlist_count()); /* 12 */
|
||||
db_get_song_count(NULL,&count);
|
||||
current += db_dmap_add_int(current,"mimc",count); /* 12 */
|
||||
db_get_playlist_count(NULL,&count);
|
||||
current += db_dmap_add_int(current,"mctc",count); /* 12 */
|
||||
|
||||
dispatch_output_start(pwsc,pqi,113+namelen);
|
||||
dispatch_output_write(pwsc,pqi,dbinfo_response,113+namelen);
|
||||
|
18
src/main.c
18
src/main.c
@ -353,13 +353,14 @@ int main(int argc, char *argv[]) {
|
||||
int start_time;
|
||||
int end_time;
|
||||
int rescan_counter=0;
|
||||
int old_song_count;
|
||||
int old_song_count, song_count;
|
||||
int force_non_root=0;
|
||||
int skip_initial=0;
|
||||
pthread_t signal_tid;
|
||||
|
||||
int pid_fd;
|
||||
FILE *pid_fp=NULL;
|
||||
char *perr;
|
||||
|
||||
config.use_mdns=1;
|
||||
err_debuglevel=1;
|
||||
@ -482,8 +483,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
/* this will require that the db be readable by the runas user */
|
||||
if(db_open(config.dbdir))
|
||||
DPRINTF(E_FATAL,L_MAIN|L_DB,"Error in db_open: %s\n",strerror(errno));
|
||||
if(db_open(&perr,config.dbdir))
|
||||
DPRINTF(E_FATAL,L_MAIN|L_DB,"Error in db_open: %s\n",perr);
|
||||
|
||||
/* Initialize the database before starting */
|
||||
DPRINTF(E_LOG,L_MAIN|L_DB,"Initializing database\n");
|
||||
@ -529,7 +530,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
end_time=time(NULL);
|
||||
|
||||
DPRINTF(E_LOG,L_MAIN,"Scanned %d songs in %d seconds\n",db_get_song_count(),
|
||||
db_get_song_count(NULL,&song_count);
|
||||
DPRINTF(E_LOG,L_MAIN,"Scanned %d songs in %d seconds\n",song_count,
|
||||
end_time-start_time);
|
||||
|
||||
while(!config.stop) {
|
||||
@ -543,7 +545,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if(config.reload) {
|
||||
old_song_count = db_get_song_count();
|
||||
old_song_count = song_count;
|
||||
start_time=time(NULL);
|
||||
|
||||
DPRINTF(E_LOG,L_MAIN|L_DB|L_SCAN,"Rescanning database\n");
|
||||
@ -552,8 +554,10 @@ int main(int argc, char *argv[]) {
|
||||
config.stop=1;
|
||||
}
|
||||
config.reload=0;
|
||||
DPRINTF(E_INF,L_MAIN|L_DB|L_SCAN,"Scanned %d songs (was %d) in %d seconds\n",
|
||||
db_get_song_count(),old_song_count,time(NULL)-start_time);
|
||||
db_get_song_count(NULL,&song_count);
|
||||
DPRINTF(E_INF,L_MAIN|L_DB|L_SCAN,"Scanned %d songs (was %d) in "
|
||||
"%d seconds\n",song_count,old_song_count,
|
||||
time(NULL)-start_time);
|
||||
}
|
||||
|
||||
sleep(MAIN_SLEEP_INTERVAL);
|
||||
|
@ -344,7 +344,7 @@ int scan_path(char *path) {
|
||||
(strcasestr(config.extensions, ext))) {
|
||||
/* only scan if it's been changed, or empty db */
|
||||
modified_time=sb.st_mtime;
|
||||
pmp3=db_fetch_path(mp3_path,0);
|
||||
pmp3=db_fetch_path(NULL,mp3_path,0);
|
||||
|
||||
if((!pmp3) || (pmp3->db_timestamp < modified_time) ||
|
||||
(pmp3->force_update)) {
|
||||
@ -380,6 +380,7 @@ int scan_static_playlist(char *path) {
|
||||
MP3FILE *pmp3;
|
||||
struct stat sb;
|
||||
char *current;
|
||||
char *perr;
|
||||
|
||||
DPRINTF(E_WARN,L_SCAN|L_PL,"Processing static playlist: %s\n",path);
|
||||
if(stat(path,&sb)) {
|
||||
@ -399,7 +400,7 @@ int scan_static_playlist(char *path) {
|
||||
*current='\x0';
|
||||
}
|
||||
|
||||
pm3u = db_fetch_playlist(path,0);
|
||||
pm3u = db_fetch_playlist(NULL,path,0);
|
||||
if(pm3u && (pm3u->db_timestamp > sb.st_mtime)) {
|
||||
/* already up-to-date */
|
||||
DPRINTF(E_DBG,L_SCAN,"Playlist already up-to-date\n");
|
||||
@ -408,12 +409,14 @@ int scan_static_playlist(char *path) {
|
||||
}
|
||||
|
||||
if(pm3u)
|
||||
db_delete_playlist(pm3u->id);
|
||||
db_delete_playlist(NULL,pm3u->id);
|
||||
|
||||
fd=open(path,O_RDONLY);
|
||||
if(fd != -1) {
|
||||
if(db_add_playlist(base_path,PL_STATICFILE,NULL,path,0,&playlistid) != DB_E_SUCCESS) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Error adding m3u playlist %s\n",path);
|
||||
if(db_add_playlist(&perr,base_path,PL_STATICFILE,NULL,path,
|
||||
0,&playlistid) != DB_E_SUCCESS) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Error adding m3u %s: %s\n",path,perr);
|
||||
free(perr);
|
||||
db_dispose_playlist(pm3u);
|
||||
return FALSE;
|
||||
}
|
||||
@ -447,12 +450,14 @@ int scan_static_playlist(char *path) {
|
||||
DPRINTF(E_DBG,L_SCAN|L_PL,"Checking %s\n",real_path);
|
||||
|
||||
// might be valid, might not...
|
||||
if((pmp3=db_fetch_path(real_path,0))) {
|
||||
db_add_playlist_item(playlistid,pmp3->id);
|
||||
if((pmp3=db_fetch_path(&perr,real_path,0))) {
|
||||
/* FIXME: better error handling */
|
||||
db_add_playlist_item(NULL,playlistid,pmp3->id);
|
||||
db_dispose_item(pmp3);
|
||||
} else {
|
||||
DPRINTF(E_WARN,L_SCAN|L_PL,"Playlist entry %s bad: %s\n",
|
||||
path,strerror(errno));
|
||||
path,perr);
|
||||
free(perr);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
@ -538,7 +543,8 @@ void scan_music_file(char *path, struct dirent *pde,
|
||||
if(is_compdir)
|
||||
mp3file.compilation = 1;
|
||||
|
||||
db_add(&mp3file);
|
||||
/* FIXME: error handling */
|
||||
db_add(NULL,&mp3file);
|
||||
} else {
|
||||
DPRINTF(E_WARN,L_SCAN,"Skipping %s - scan failed\n",mp3file.path);
|
||||
}
|
||||
|
@ -636,7 +636,8 @@ int scan_xml_tracks_section(int action, char *info) {
|
||||
state = XML_TRACK_ST_MAIN_DICT;
|
||||
/* but more importantly, we gotta process the track */
|
||||
if(scan_xml_translate_path(song_path,real_path)) {
|
||||
pmp3=db_fetch_path(real_path,0);
|
||||
/* FIXME: Error handling */
|
||||
pmp3=db_fetch_path(NULL,real_path,0);
|
||||
if(pmp3) {
|
||||
/* Update the existing record with the
|
||||
* updated stuff we got from the iTunes xml file
|
||||
@ -660,7 +661,7 @@ int scan_xml_tracks_section(int action, char *info) {
|
||||
/* must add to the red-black tree */
|
||||
scan_xml_add_lookup(current_track_id,pmp3->id);
|
||||
|
||||
db_add(pmp3);
|
||||
db_add(NULL,pmp3);
|
||||
db_dispose_item(pmp3);
|
||||
|
||||
memset((void*)&mp3,0,sizeof(MP3FILE));
|
||||
@ -807,13 +808,16 @@ int scan_xml_playlists_section(int action, char *info) {
|
||||
if(dont_scan == 0) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Creating playlist for %s\n",current_name);
|
||||
/* delete the old one first */
|
||||
pm3u = db_fetch_playlist(scan_xml_file,native_plid);
|
||||
/* FIXME: Error handling */
|
||||
pm3u = db_fetch_playlist(NULL,scan_xml_file,native_plid);
|
||||
if(pm3u) {
|
||||
db_delete_playlist(pm3u->id);
|
||||
db_delete_playlist(NULL,pm3u->id);
|
||||
db_dispose_playlist(pm3u);
|
||||
}
|
||||
if(db_add_playlist(current_name,PL_STATICXML,NULL,scan_xml_file,
|
||||
native_plid,¤t_id) != DB_E_SUCCESS) {
|
||||
if(db_add_playlist(NULL,current_name,PL_STATICXML,NULL,
|
||||
scan_xml_file,native_plid,
|
||||
¤t_id) != DB_E_SUCCESS)
|
||||
{
|
||||
DPRINTF(E_LOG,L_SCAN,"err adding playlist %s\n",current_name);
|
||||
current_id=0;
|
||||
}
|
||||
@ -855,7 +859,8 @@ int scan_xml_playlists_section(int action, char *info) {
|
||||
DPRINTF(E_DBG,L_SCAN,"Adding itunes track #%s\n",info);
|
||||
/* add it to the current playlist (current_id) */
|
||||
if(current_id && scan_xml_get_index(native_track_id, &track_id)) {
|
||||
db_add_playlist_item(current_id,track_id);
|
||||
/* FIXME: Error handling */
|
||||
db_add_playlist_item(NULL,current_id,track_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ void xml_get_stats(WS_CONNINFO *pwsc) {
|
||||
WS_CONNINFO *pci;
|
||||
SCAN_STATUS *pss;
|
||||
WSTHREADENUM wste;
|
||||
|
||||
int count;
|
||||
XMLSTRUCT *pxml;
|
||||
|
||||
pxml=xml_init(pwsc,1);
|
||||
@ -276,7 +276,8 @@ void xml_get_stats(WS_CONNINFO *pwsc) {
|
||||
|
||||
xml_push(pxml,"stat");
|
||||
xml_output(pxml,"name","Songs");
|
||||
xml_output(pxml,"value","%d",db_get_song_count());
|
||||
db_get_song_count(NULL,&count);
|
||||
xml_output(pxml,"value","%d",count);
|
||||
xml_pop(pxml); /* stat */
|
||||
|
||||
xml_push(pxml,"stat");
|
||||
|
Loading…
x
Reference in New Issue
Block a user