mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-25 22:55:56 -05:00
Remove the old database code
This commit is contained in:
parent
a200703393
commit
4e3b29f502
688
src/db-generic.c
688
src/db-generic.c
@ -1,688 +0,0 @@
|
||||
/*
|
||||
* Generic db implementation for specific sql backend
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#define _XOPEN_SOURCE 500 /** unix98? pthread_once_t, etc */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "db-generic.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include "db-sql.h"
|
||||
|
||||
#define DB_VERSION 1
|
||||
#define MAYBEFREE(a) { if((a)) free((a)); };
|
||||
|
||||
/** pointers to database-specific functions */
|
||||
typedef struct tag_db_functions {
|
||||
char *name;
|
||||
int(*dbs_open)(char **, char *);
|
||||
int(*dbs_init)(int);
|
||||
int(*dbs_deinit)(void);
|
||||
int(*dbs_add)(char **, MP3FILE*, int*);
|
||||
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_playcount_increment)(char **, int);
|
||||
int(*dbs_enum_start)(char **, DBQUERYINFO *);
|
||||
int(*dbs_enum_fetch_row)(char **, PACKED_MP3FILE **, DBQUERYINFO *);
|
||||
int(*dbs_enum_reset)(char **, DBQUERYINFO *);
|
||||
int(*dbs_enum_end)(char **);
|
||||
int(*dbs_force_rescan)(char **);
|
||||
int(*dbs_start_scan)(void);
|
||||
int(*dbs_end_song_scan)(void);
|
||||
int(*dbs_end_scan)(void);
|
||||
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_SQLITE3
|
||||
{
|
||||
"sqlite3",
|
||||
db_sql_open_sqlite3,
|
||||
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_playcount_increment,
|
||||
db_sql_enum_start,
|
||||
db_sql_enum_fetch_row,
|
||||
db_sql_enum_reset,
|
||||
db_sql_enum_end,
|
||||
db_sql_force_rescan,
|
||||
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 }
|
||||
};
|
||||
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: %s",
|
||||
"No backend database support for type: %s",
|
||||
"Could not initialize thread pool",
|
||||
"Passed buffer too small for result",
|
||||
"Wrong db schema. Use mtd-update to upgrade the db.",
|
||||
"Database error: %s",
|
||||
"Malloc error",
|
||||
"Path not found"
|
||||
};
|
||||
|
||||
/* Globals */
|
||||
static DB_FUNCTIONS *db_current=&db_functions[0]; /**< current database backend */
|
||||
static int db_revision_no=2; /**< current revision of the db */
|
||||
static pthread_once_t db_initlock=PTHREAD_ONCE_INIT; /**< to initialize the rwlock */
|
||||
static int db_is_scanning=0;
|
||||
static pthread_rwlock_t db_rwlock; /**< pthread r/w sync for the database */
|
||||
|
||||
/* Forwards */
|
||||
static void db_writelock(void);
|
||||
static void db_readlock(void);
|
||||
static int db_unlock(void);
|
||||
static void db_init_once(void);
|
||||
static void db_utf8_validate(MP3FILE *pmp3);
|
||||
static int db_utf8_validate_string(char *string);
|
||||
static void db_trim_strings(MP3FILE *pmp3);
|
||||
static void db_trim_string(char *string);
|
||||
|
||||
/*
|
||||
* db_readlock
|
||||
*
|
||||
* If this fails, something is so amazingly hosed, we might just as well
|
||||
* terminate.
|
||||
*/
|
||||
void db_readlock(void) {
|
||||
int err;
|
||||
|
||||
DPRINTF(E_SPAM,L_LOCK,"entering db_readlock\n");
|
||||
if((err=pthread_rwlock_rdlock(&db_rwlock))) {
|
||||
DPRINTF(E_FATAL,L_DB,"cannot lock rdlock: %s\n",strerror(err));
|
||||
}
|
||||
DPRINTF(E_SPAM,L_LOCK,"db_readlock acquired\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* db_writelock
|
||||
*
|
||||
* same as above
|
||||
*/
|
||||
void db_writelock(void) {
|
||||
int err;
|
||||
|
||||
DPRINTF(E_SPAM,L_LOCK,"entering db_writelock\n");
|
||||
if((err=pthread_rwlock_wrlock(&db_rwlock))) {
|
||||
DPRINTF(E_FATAL,L_DB,"cannot lock rwlock: %s\n",strerror(err));
|
||||
}
|
||||
DPRINTF(E_SPAM,L_LOCK,"db_writelock acquired\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* db_unlock
|
||||
*
|
||||
* useless, but symmetrical
|
||||
*/
|
||||
int db_unlock(void) {
|
||||
DPRINTF(E_SPAM,L_LOCK,"releasing db lock\n");
|
||||
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);
|
||||
|
||||
DPRINTF(E_SPAM,L_MISC,"Raising error: %s\n",errbuf);
|
||||
|
||||
*pe = strdup(errbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must dynamically initialize the rwlock, as Mac OSX 10.3 (at least)
|
||||
* doesn't have a static initializer for rwlocks
|
||||
*/
|
||||
void db_init_once(void) {
|
||||
pthread_rwlock_init(&db_rwlock,NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the database. This is done before we drop privs, that
|
||||
* way if the database only has root perms, then it can still
|
||||
* be opened.
|
||||
*
|
||||
* \param parameters This is backend-specific (mysql, sqlite, etc)
|
||||
*/
|
||||
int db_open(char **pe, char *type, char *parameters) {
|
||||
int result;
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Opening database\n");
|
||||
|
||||
if(pthread_once(&db_initlock,db_init_once))
|
||||
return -1;
|
||||
|
||||
db_current = &db_functions[0];
|
||||
if(type) {
|
||||
while((db_current->name) && (strcasecmp(db_current->name,type))) {
|
||||
db_current++;
|
||||
}
|
||||
|
||||
if(!db_current->name) {
|
||||
/* end of list -- no match */
|
||||
db_get_error(pe,DB_E_BADPROVIDER,type);
|
||||
return DB_E_BADPROVIDER;
|
||||
}
|
||||
}
|
||||
|
||||
result=db_current->dbs_open(pe, parameters);
|
||||
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Results: %d\n",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the database, including marking it for full reload if necessary.
|
||||
*
|
||||
* \param reload whether or not to do a full reload of the database
|
||||
*/
|
||||
int db_init(int reload) {
|
||||
return db_current->dbs_init(reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the database.
|
||||
*/
|
||||
int db_deinit(void) {
|
||||
return db_current->dbs_deinit();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the current db revision. this is mostly to determine
|
||||
* when its time to send an updated version to the client
|
||||
*/
|
||||
int db_revision(void) {
|
||||
int revision;
|
||||
|
||||
db_readlock();
|
||||
revision=db_revision_no;
|
||||
db_unlock();
|
||||
|
||||
return revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* is the db currently in scanning mode?
|
||||
*/
|
||||
int db_scanning(void) {
|
||||
return db_is_scanning;
|
||||
}
|
||||
|
||||
/**
|
||||
* add (or update) a file
|
||||
*/
|
||||
int db_add(char **pe, MP3FILE *pmp3, int *id) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
db_utf8_validate(pmp3);
|
||||
db_trim_strings(pmp3);
|
||||
retval=db_current->dbs_add(pe,pmp3,id);
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
|
||||
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 **pe, char *name, int type, char *clause, char *path, int index, int *playlistid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_add_playlist(pe,name,type,clause,path,index,playlistid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a song to a static playlist
|
||||
*
|
||||
* \param playlistid playlist to add song to
|
||||
* \param songid song to add to playlist
|
||||
* \returns 0 on success, DB_E_ code otherwise
|
||||
*/
|
||||
int db_add_playlist_item(char **pe, int playlistid, int songid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_add_playlist_item(pe,playlistid,songid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a playlist
|
||||
*
|
||||
* \param playlistid id of the playlist to delete
|
||||
* \returns 0 on success, error code otherwise
|
||||
*/
|
||||
int db_delete_playlist(char **pe, int playlistid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_delete_playlist(pe,playlistid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete an item from a playlist
|
||||
*
|
||||
* \param playlistid id of the playlist to delete
|
||||
* \param songid id of the song to delete
|
||||
* \returns 0 on success, error code otherwise
|
||||
*/
|
||||
int db_delete_playlist_item(char **pe, int playlistid, int songid) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_delete_playlist_item(pe,playlistid,songid);
|
||||
if(retval == DB_E_SUCCESS)
|
||||
db_revision_no++;
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* edit a playlist
|
||||
*
|
||||
* @param id playlist id to edit
|
||||
* @param name new name of playlist
|
||||
* @param clause new where clause
|
||||
*/
|
||||
int db_edit_playlist(char **pe, int id, char *name, char *clause) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
|
||||
retval = db_current->dbs_edit_playlist(pe, id, name, clause);
|
||||
db_unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* increment the playcount info for a particular song
|
||||
* (play_count and time_played).
|
||||
*
|
||||
* @param pe error string
|
||||
* @param id id of song to incrmrent
|
||||
* @returns DB_E_SUCCESS on success, error code otherwise
|
||||
*/
|
||||
int db_playcount_increment(char **pe, int id) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval = db_current->dbs_playcount_increment(pe, id);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* start a db enumeration, based info in the DBQUERYINFO struct
|
||||
*
|
||||
* \param pinfo pointer to DBQUERYINFO struction
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int db_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_enum_start(pe, pinfo);
|
||||
|
||||
if(retval) {
|
||||
db_unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch the next item int he result set started by the db enum. this
|
||||
* will be in native packed row format
|
||||
*/
|
||||
int db_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo) {
|
||||
return db_current->dbs_enum_fetch_row(pe, row, pinfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reset the enum, without coming out the the db_writelock
|
||||
*/
|
||||
int db_enum_reset(char **pe, DBQUERYINFO *pinfo) {
|
||||
return db_current->dbs_enum_reset(pe,pinfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* finish the enumeration
|
||||
*/
|
||||
int db_enum_end(char **pe) {
|
||||
int retval;
|
||||
|
||||
retval=db_current->dbs_enum_end(pe);
|
||||
db_unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetch a MP3FILE struct given an id. This will be done
|
||||
* mostly only by the web interface, and when streaming a song
|
||||
*
|
||||
* \param id id of the item to get details for
|
||||
*/
|
||||
MP3FILE *db_fetch_item(char **pe, int id) {
|
||||
MP3FILE *retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_fetch_item(pe, id);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
MP3FILE *db_fetch_path(char **pe, char *path,int index) {
|
||||
MP3FILE *retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_fetch_path(pe,path, index);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
M3UFILE *db_fetch_playlist(char **pe, char *path, int index) {
|
||||
M3UFILE *retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_fetch_playlist(pe,path,index);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int db_force_rescan(char **pe) {
|
||||
int retval;
|
||||
db_writelock();
|
||||
retval = db_current->dbs_force_rescan(pe);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int db_start_scan(void) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_start_scan();
|
||||
db_is_scanning=1;
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int db_end_song_scan(void) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_end_song_scan();
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int db_end_scan(void) {
|
||||
int retval;
|
||||
|
||||
db_writelock();
|
||||
retval=db_current->dbs_end_scan();
|
||||
db_is_scanning=0;
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void db_dispose_item(MP3FILE *pmp3) {
|
||||
db_current->dbs_dispose_item(pmp3);
|
||||
}
|
||||
|
||||
void db_dispose_playlist(M3UFILE *pm3u) {
|
||||
db_current->dbs_dispose_playlist(pm3u);
|
||||
}
|
||||
|
||||
int db_get_count(char **pe, int *count, CountType_t type) {
|
||||
int retval;
|
||||
|
||||
db_readlock();
|
||||
retval=db_current->dbs_get_count(pe,count,type);
|
||||
db_unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FIXME: clearly a stub
|
||||
*/
|
||||
int db_get_song_count(char **pe, int *count) {
|
||||
return db_get_count(pe, count, countSongs);
|
||||
}
|
||||
|
||||
int db_get_playlist_count(char **pe, int *count) {
|
||||
return db_get_count(pe, count, countPlaylists);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check the strings in a MP3FILE to ensure they are
|
||||
* valid utf-8. If they are not, the string will be corrected
|
||||
*
|
||||
* \param pmp3 MP3FILE to verify for valid utf-8
|
||||
*/
|
||||
void db_utf8_validate(MP3FILE *pmp3) {
|
||||
int is_invalid=0;
|
||||
|
||||
/* we won't bother with path and fname... those were culled with the
|
||||
* scan. Even if they are invalid (_could_ they be?), then we
|
||||
* won't be able to open the file if we change them. Likewise,
|
||||
* we won't do type or description, as these can't be bad, or they
|
||||
* wouldn't have been scanned */
|
||||
|
||||
is_invalid = db_utf8_validate_string(pmp3->title);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->artist);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->album);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->genre);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->comment);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->composer);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->orchestra);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->conductor);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->grouping);
|
||||
is_invalid |= db_utf8_validate_string(pmp3->url);
|
||||
|
||||
if(is_invalid) {
|
||||
DPRINTF(E_LOG,L_SCAN,"Invalid UTF-8 in %s\n",pmp3->path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check a string to verify it is valid utf-8. The passed
|
||||
* string will be in-place modified to be utf-8 clean by substituting
|
||||
* the character '?' for invalid utf-8 codepoints
|
||||
*
|
||||
* \param string string to clean
|
||||
*/
|
||||
int db_utf8_validate_string(char *string) {
|
||||
char *current = string;
|
||||
int run,r_current;
|
||||
int retval=0;
|
||||
|
||||
if(!string)
|
||||
return 0;
|
||||
|
||||
while(*current) {
|
||||
if(!((*current) & 0x80)) {
|
||||
current++;
|
||||
} else {
|
||||
run=0;
|
||||
|
||||
/* it's a lead utf-8 character */
|
||||
if((*current & 0xE0) == 0xC0) run=1;
|
||||
if((*current & 0xF0) == 0xE0) run=2;
|
||||
if((*current & 0xF8) == 0xF0) run=3;
|
||||
|
||||
if(!run) {
|
||||
/* high bit set, but invalid */
|
||||
*current++='?';
|
||||
retval=1;
|
||||
} else {
|
||||
r_current=0;
|
||||
while((r_current != run) && (*(current + r_current + 1)) &&
|
||||
((*(current + r_current + 1) & 0xC0) == 0x80)) {
|
||||
r_current++;
|
||||
}
|
||||
|
||||
if(r_current != run) {
|
||||
*current++ = '?';
|
||||
retval=1;
|
||||
} else {
|
||||
current += (1 + run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the spaces off the string values. It throws off
|
||||
* browsing when there are some with and without spaces.
|
||||
* This should probably be better fixed by having clean tags,
|
||||
* but seemed simple enough, and it does make sense that
|
||||
* while we are cleaning tags for, say, utf-8 hygene we might
|
||||
* as well get this too.
|
||||
*
|
||||
* @param pmp3 mp3 struct to fix
|
||||
*/
|
||||
void db_trim_strings(MP3FILE *pmp3) {
|
||||
db_trim_string(pmp3->title);
|
||||
db_trim_string(pmp3->artist);
|
||||
db_trim_string(pmp3->album);
|
||||
db_trim_string(pmp3->genre);
|
||||
db_trim_string(pmp3->comment);
|
||||
db_trim_string(pmp3->composer);
|
||||
db_trim_string(pmp3->orchestra);
|
||||
db_trim_string(pmp3->conductor);
|
||||
db_trim_string(pmp3->grouping);
|
||||
db_trim_string(pmp3->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* trim trailing spaces in a string. Used by db_trim_strings
|
||||
*
|
||||
* @param string string to trim
|
||||
*/
|
||||
void db_trim_string(char *string) {
|
||||
if(!string)
|
||||
return;
|
||||
|
||||
while(strlen(string) && (string[strlen(string) - 1] == ' '))
|
||||
string[strlen(string) - 1] = '\0';
|
||||
}
|
||||
|
133
src/db-generic.h
133
src/db-generic.h
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Header info for generic database
|
||||
*
|
||||
* 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_GENERIC_H_
|
||||
#define _DB_GENERIC_H_
|
||||
|
||||
#include "ff-dbstruct.h" /** for MP3FILE */
|
||||
|
||||
typedef enum {
|
||||
queryTypeItems,
|
||||
queryTypePlaylists,
|
||||
queryTypePlaylistItems,
|
||||
queryTypeBrowseArtists,
|
||||
queryTypeBrowseAlbums,
|
||||
queryTypeBrowseGenres,
|
||||
queryTypeBrowseComposers
|
||||
} QueryType_t;
|
||||
|
||||
typedef enum {
|
||||
indexTypeNone,
|
||||
indexTypeFirst,
|
||||
indexTypeLast,
|
||||
indexTypeSub
|
||||
} IndexType_t;
|
||||
|
||||
typedef enum {
|
||||
countSongs,
|
||||
countPlaylists
|
||||
} CountType_t;
|
||||
|
||||
typedef struct tag_dbqueryinfo {
|
||||
QueryType_t query_type;
|
||||
IndexType_t index_type;
|
||||
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;
|
||||
int correct_order;
|
||||
char *uri_sections[10];
|
||||
char *filter; /* SQL WHERE clause */
|
||||
void *output_info;
|
||||
} DBQUERYINFO;
|
||||
|
||||
extern int db_open(char **pe, char *type, char *parameters);
|
||||
extern int db_init(int reload);
|
||||
extern int db_deinit(void);
|
||||
|
||||
extern int db_revision(void);
|
||||
|
||||
extern int db_add(char **pe, MP3FILE *pmp3, int *id);
|
||||
|
||||
extern int db_enum_start(char **pe, DBQUERYINFO *pinfo);
|
||||
extern int db_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo);
|
||||
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 **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 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);
|
||||
|
||||
|
||||
/* Holdover functions from old db interface...
|
||||
* should these be removed? Refactored?
|
||||
*/
|
||||
|
||||
extern int db_playcount_increment(char **pe, int id);
|
||||
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);
|
||||
extern int db_force_rescan(char **pe);
|
||||
|
||||
#define DB_E_SUCCESS 0x00
|
||||
#define DB_E_SQL_ERROR 0x01 /**< some kind of sql error - typically bad syntax */
|
||||
#define DB_E_DUPLICATE_PLAYLIST 0x02 /**< playlist already exists when adding */
|
||||
#define DB_E_NOCLAUSE 0x03 /**< adding smart playlist with no clause */
|
||||
#define DB_E_INVALIDTYPE 0x04 /**< trying to add playlist items to invalid type */
|
||||
#define DB_E_NOROWS 0x05 /**< sql query returned no rows */
|
||||
#define DB_E_INVALID_PLAYLIST 0x06 /**< bad playlist id */
|
||||
#define DB_E_INVALID_SONGID 0x07 /**< bad song id */
|
||||
#define DB_E_PARSE 0x08 /**< could not parse result */
|
||||
#define DB_E_BADPROVIDER 0x09 /**< requested db backend not there */
|
||||
#define DB_E_PROC 0x0A /**< could not start threadpool */
|
||||
#define DB_E_SIZE 0x0B /**< passed buffer too small */
|
||||
#define DB_E_WRONGVERSION 0x0C /**< must upgrade db */
|
||||
#define DB_E_MALLOC 0x0E /**< malloc error */
|
||||
#define DB_E_NOTFOUND 0x0F /**< path not found */
|
||||
|
||||
/* describes the individual database handlers */
|
||||
typedef struct tag_dbinfo {
|
||||
char *handler_name;
|
||||
char *description;
|
||||
int stores_playlists;
|
||||
} DB_INFO;
|
||||
|
||||
|
||||
|
||||
#endif /* _DB_GENERIC_H_ */
|
@ -1,576 +0,0 @@
|
||||
/*
|
||||
* sqlite3-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 sqlite3 databases. SQLite3 databases
|
||||
* should have a dsn of:
|
||||
*
|
||||
* sqlite3:/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 <sqlite3.h>
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "logger.h"
|
||||
#include "db-generic.h"
|
||||
#include "db-sql.h"
|
||||
#include "db-sql-sqlite3.h"
|
||||
|
||||
#ifndef TRUE
|
||||
# define TRUE 1
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Globals */
|
||||
static pthread_mutex_t db_sqlite3_mutex = PTHREAD_MUTEX_INITIALIZER; /**< sqlite not reentrant */
|
||||
static sqlite3_stmt *db_sqlite3_stmt;
|
||||
static const char *db_sqlite3_ptail;
|
||||
static int db_sqlite3_finalized;
|
||||
static int db_sqlite3_reload=0;
|
||||
static char *db_sqlite3_enum_query=NULL;
|
||||
static char **db_sqlite3_row = NULL;
|
||||
static pthread_key_t db_sqlite3_key;
|
||||
static char db_sqlite3_path[PATH_MAX + 1];
|
||||
|
||||
#define DB_SQLITE3_VERSION 13
|
||||
|
||||
|
||||
/* Forwards */
|
||||
void db_sqlite3_lock(void);
|
||||
void db_sqlite3_unlock(void);
|
||||
extern char *db_sqlite3_initial1;
|
||||
extern char *db_sqlite3_initial2;
|
||||
int db_sqlite3_enum_begin_helper(char **pe);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* get (or create) the db handle
|
||||
*/
|
||||
sqlite3 *db_sqlite3_handle(void) {
|
||||
sqlite3 *pdb = NULL;
|
||||
char *pe = NULL;
|
||||
|
||||
pdb = (sqlite3*)pthread_getspecific(db_sqlite3_key);
|
||||
if(pdb == NULL) { /* don't have a handle yet */
|
||||
DPRINTF(E_DBG,L_DB,"Creating new db handle\n");
|
||||
if(sqlite3_open(db_sqlite3_path,&pdb) != SQLITE_OK) {
|
||||
db_get_error(&pe,DB_E_SQL_ERROR,sqlite3_errmsg(pdb));
|
||||
DPRINTF(E_FATAL,L_DB,"db_sqlite3_open: %s (%s)\n",pe,db_sqlite3_path);
|
||||
db_sqlite3_unlock();
|
||||
return NULL;
|
||||
}
|
||||
sqlite3_busy_timeout(pdb,30000); /* 30 seconds */
|
||||
pthread_setspecific(db_sqlite3_key,(void*)pdb);
|
||||
}
|
||||
|
||||
return pdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* free a thread-specific db handle
|
||||
*/
|
||||
void db_sqlite3_freedb(sqlite3 *pdb) {
|
||||
sqlite3_close(pdb);
|
||||
}
|
||||
|
||||
/**
|
||||
* lock the db_mutex
|
||||
*/
|
||||
void db_sqlite3_lock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_lock(&db_sqlite3_mutex))) {
|
||||
DPRINTF(E_FATAL,L_DB,"cannot lock sqlite lock: %s\n",strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unlock the db_mutex
|
||||
*/
|
||||
void db_sqlite3_unlock(void) {
|
||||
int err;
|
||||
|
||||
if((err=pthread_mutex_unlock(&db_sqlite3_mutex))) {
|
||||
DPRINTF(E_FATAL,L_DB,"cannot unlock sqlite3 lock: %s\n",strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char *db_sqlite3_vmquery(char *fmt,va_list ap) {
|
||||
return sqlite3_vmprintf(fmt,ap);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void db_sqlite3_vmfree(char *query) {
|
||||
sqlite3_free(query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* open a sqlite3 database
|
||||
*
|
||||
* @param dsn the full dns to the database
|
||||
* (sqlite3:/path/to/database)
|
||||
*
|
||||
* @returns DB_E_SUCCESS on success
|
||||
*/
|
||||
int db_sqlite3_open(char **pe, char *dsn) {
|
||||
int ver;
|
||||
int err;
|
||||
sqlite3 *pdb;
|
||||
|
||||
pthread_key_create(&db_sqlite3_key, (void*)db_sqlite3_freedb);
|
||||
snprintf(db_sqlite3_path,sizeof(db_sqlite3_path),"%s/songs3.db",dsn);
|
||||
|
||||
db_sqlite3_lock();
|
||||
if(sqlite3_open(db_sqlite3_path,&pdb) != SQLITE_OK) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(pdb));
|
||||
DPRINTF(E_LOG,L_DB,"db_sqlite3_open: %s (%s)\n",pe ? *pe : "Unknown",
|
||||
db_sqlite3_path);
|
||||
db_sqlite3_unlock();
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
sqlite3_close(pdb);
|
||||
db_sqlite3_unlock();
|
||||
|
||||
err = db_sql_fetch_int(pe,&ver,"select value from config where "
|
||||
"term='version'");
|
||||
if(err != DB_E_SUCCESS) {
|
||||
if(pe) { free(*pe); }
|
||||
/* we'll catch this on the init */
|
||||
DPRINTF(E_LOG,L_DB,"Can't get db version. New database?\n");
|
||||
} else if(ver < DB_SQLITE3_VERSION) {
|
||||
DPRINTF(E_LOG,L_DB,"Old database version: %d, expecting %d\n",
|
||||
ver,DB_SQLITE3_VERSION);
|
||||
db_get_error(pe,DB_E_WRONGVERSION);
|
||||
return DB_E_WRONGVERSION;
|
||||
} else if(ver > DB_SQLITE3_VERSION) {
|
||||
db_sqlite3_exec(pe,E_FATAL,"insert into config (term, value) "
|
||||
"values ('rescan',1)");
|
||||
}
|
||||
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* close the database
|
||||
*/
|
||||
int db_sqlite3_close(void) {
|
||||
/* this doens't actually make much sense, as the closes get done by the threads */
|
||||
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_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) {
|
||||
va_list ap;
|
||||
char *query;
|
||||
int err;
|
||||
char *perr;
|
||||
|
||||
db_sqlite3_lock();
|
||||
|
||||
va_start(ap,fmt);
|
||||
query=sqlite3_vmprintf(fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Executing: %s\n",query);
|
||||
|
||||
err=sqlite3_exec(db_sqlite3_handle(),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);
|
||||
sqlite3_free(perr);
|
||||
} else {
|
||||
DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite3_changes(db_sqlite3_handle()));
|
||||
}
|
||||
sqlite3_free(query);
|
||||
|
||||
db_sqlite3_unlock();
|
||||
|
||||
if(err != SQLITE_OK)
|
||||
return DB_E_SQL_ERROR;
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* start enumerating rows in a select
|
||||
*/
|
||||
int db_sqlite3_enum_begin(char **pe, char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
db_sqlite3_lock();
|
||||
va_start(ap, fmt);
|
||||
db_sqlite3_enum_query = sqlite3_vmprintf(fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
db_sqlite3_finalized=0;
|
||||
return db_sqlite3_enum_begin_helper(pe);
|
||||
}
|
||||
|
||||
int db_sqlite3_enum_begin_helper(char **pe) {
|
||||
int err;
|
||||
|
||||
if(!db_sqlite3_enum_query)
|
||||
*((int*)NULL) = 1;
|
||||
|
||||
DPRINTF(E_DBG,L_DB,"Executing: %s\n",db_sqlite3_enum_query);
|
||||
err=sqlite3_prepare(db_sqlite3_handle(),db_sqlite3_enum_query,-1,
|
||||
&db_sqlite3_stmt,&db_sqlite3_ptail);
|
||||
|
||||
if(err != SQLITE_OK) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle()));
|
||||
sqlite3_free(db_sqlite3_enum_query);
|
||||
db_sqlite3_enum_query=NULL;
|
||||
db_sqlite3_unlock();
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
|
||||
DPRINTF(E_SPAM,L_DB,"Prepared statement: %08X\n",db_sqlite3_stmt);
|
||||
|
||||
/* otherwise, we leave the db locked while we walk through the enums */
|
||||
if(db_sqlite3_row)
|
||||
free(db_sqlite3_row);
|
||||
db_sqlite3_row=NULL;
|
||||
|
||||
return DB_E_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch the next row. This will return DB_E_SUCCESS if it got a
|
||||
* row, or it's done. If it's done, the row will be empty, otherwise
|
||||
* it will be full of data. Either way, if fetch fails, you must close.
|
||||
*
|
||||
* @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_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
|
||||
int err;
|
||||
int cols;
|
||||
int idx;
|
||||
int counter=10;
|
||||
|
||||
if(!db_sqlite3_enum_query)
|
||||
*((int*)NULL) = 1;
|
||||
|
||||
while(counter--) {
|
||||
DPRINTF(E_SPAM,L_DB,"Fetching statement: %08X\n",db_sqlite3_stmt);
|
||||
err=sqlite3_step(db_sqlite3_stmt);
|
||||
if(err != SQLITE_BUSY)
|
||||
break;
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
if(err == SQLITE_DONE) {
|
||||
*pr = NULL;
|
||||
if(db_sqlite3_row)
|
||||
free(db_sqlite3_row);
|
||||
db_sqlite3_row = NULL;
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
if(err == SQLITE_ROW) {
|
||||
DPRINTF(E_SPAM,L_DB,"Got row\n");
|
||||
cols = sqlite3_column_count(db_sqlite3_stmt);
|
||||
|
||||
if(!db_sqlite3_row) {
|
||||
/* gotta alloc space */
|
||||
db_sqlite3_row = (char**)malloc((sizeof(char*)) * cols);
|
||||
if(!db_sqlite3_row)
|
||||
DPRINTF(E_FATAL,L_DB,"Malloc error\n");
|
||||
}
|
||||
|
||||
for(idx=0; idx < cols; idx++) {
|
||||
db_sqlite3_row[idx] = (char*) sqlite3_column_blob(db_sqlite3_stmt,idx);
|
||||
}
|
||||
|
||||
*pr = db_sqlite3_row;
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
if(db_sqlite3_row)
|
||||
free(db_sqlite3_row);
|
||||
db_sqlite3_row = NULL;
|
||||
|
||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle()));
|
||||
DPRINTF(E_SPAM,L_DB,"Finalizing statement: %08X\n",db_sqlite3_stmt);
|
||||
sqlite3_finalize(db_sqlite3_stmt);
|
||||
db_sqlite3_finalized=1;
|
||||
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* end the db enumeration
|
||||
*/
|
||||
int db_sqlite3_enum_end(char **pe) {
|
||||
int err;
|
||||
|
||||
if(!db_sqlite3_enum_query)
|
||||
*((int*)NULL) = 1;
|
||||
|
||||
if(db_sqlite3_row)
|
||||
free(db_sqlite3_row);
|
||||
db_sqlite3_row = NULL;
|
||||
sqlite3_free(db_sqlite3_enum_query);
|
||||
db_sqlite3_enum_query = NULL;
|
||||
|
||||
if(!db_sqlite3_finalized) {
|
||||
DPRINTF(E_SPAM,L_DB,"Finalizing statement: %08X\n",db_sqlite3_stmt);
|
||||
err = sqlite3_finalize(db_sqlite3_stmt);
|
||||
if(err != SQLITE_OK) {
|
||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle()));
|
||||
db_sqlite3_unlock();
|
||||
return DB_E_SQL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
db_sqlite3_unlock();
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* restart the enumeration
|
||||
*/
|
||||
int db_sqlite3_enum_restart(char **pe) {
|
||||
return db_sqlite3_enum_begin_helper(pe);
|
||||
}
|
||||
|
||||
|
||||
int db_sqlite3_event(int event_type) {
|
||||
switch(event_type) {
|
||||
|
||||
case DB_SQL_EVENT_STARTUP: /* this is a startup with existing songs */
|
||||
db_sqlite3_exec(NULL,E_DBG,"create index idx_path on "
|
||||
"songs(path,idx)");
|
||||
db_sqlite3_exec(NULL,E_DBG,"create index idx_songid on "
|
||||
"playlistitems(songid)");
|
||||
db_sqlite3_exec(NULL,E_DBG,"create index idx_playlistid on "
|
||||
"playlistitems(playlistid,songid)");
|
||||
db_sqlite3_reload=0;
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_FULLRELOAD: /* either a fresh load or force load */
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop index idx_path");
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop index idx_songid");
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop index idx_playlistid");
|
||||
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop table songs");
|
||||
// db_sqlite3_exec(NULL,E_DBG,"drop table playlists");
|
||||
db_sqlite3_exec(NULL,E_DBG,"delete from playlists where not type=1 and not type=0");
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop table playlistitems");
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop table config");
|
||||
|
||||
db_sqlite3_exec(NULL,E_DBG,"vacuum");
|
||||
|
||||
db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial1);
|
||||
db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial2);
|
||||
db_sqlite3_reload=1;
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_SONGSCANSTART:
|
||||
if(db_sqlite3_reload) {
|
||||
db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous = off");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"begin transaction");
|
||||
} else {
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop table updated");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"create temp table updated (id int)");
|
||||
db_sqlite3_exec(NULL,E_DBG,"drop table plupdated");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"create temp table plupdated(id int)");
|
||||
}
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_SONGSCANEND:
|
||||
if(db_sqlite3_reload) {
|
||||
db_sqlite3_exec(NULL,E_FATAL,"commit transaction");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous = normal");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"create index idx_path on songs(path,idx)");
|
||||
db_sqlite3_exec(NULL,E_DBG,"delete from config where term='rescan'");
|
||||
}
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_PLSCANSTART:
|
||||
db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous = off");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"begin transaction");
|
||||
break;
|
||||
|
||||
case DB_SQL_EVENT_PLSCANEND:
|
||||
db_sqlite3_exec(NULL,E_FATAL,"end transaction");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous=normal");
|
||||
|
||||
if(db_sqlite3_reload) {
|
||||
db_sqlite3_exec(NULL,E_FATAL,"create index idx_songid on playlistitems(songid)");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"create index idx_playlistid on playlistitems(playlistid,songid)");
|
||||
|
||||
} else {
|
||||
db_sqlite3_exec(NULL,E_FATAL,"delete from songs where id not in (select id from updated)");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"update songs set force_update=0");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"drop table updated");
|
||||
|
||||
db_sqlite3_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_sqlite3_exec(NULL,E_FATAL,"delete from playlistitems where "
|
||||
"playlistid not in (select distinct "
|
||||
"id from playlists)");
|
||||
db_sqlite3_exec(NULL,E_FATAL,"drop table plupdated");
|
||||
}
|
||||
db_sqlite3_reload=0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DB_E_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the id of the last auto_update inserted item
|
||||
*
|
||||
* @returns autoupdate value
|
||||
*/
|
||||
|
||||
int db_sqlite3_insert_id(void) {
|
||||
int result;
|
||||
|
||||
db_sqlite3_lock();
|
||||
result = (int)sqlite3_last_insert_rowid(db_sqlite3_handle());
|
||||
db_sqlite3_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *db_sqlite3_initial1 =
|
||||
"create table songs (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" path VARCHAR(4096) 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"
|
||||
" has_video INTEGER DEFAULT 0,\n"
|
||||
" contentrating INTEGER DEFAULT 0,\n"
|
||||
" bits_per_sample INTEGER DEFAULT 0,\n"
|
||||
" album_artist VARCHAR(1024)\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 config (\n"
|
||||
" term VARCHAR(255) NOT NULL,\n"
|
||||
" subterm VARCHAR(255) DEFAULT NULL,\n"
|
||||
" value VARCHAR(1024) NOT NULL\n"
|
||||
");\n"
|
||||
"insert into config values ('version','','13');\n";
|
||||
|
||||
char *db_sqlite3_initial2 =
|
||||
"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 playlists values (1,'Library',1,0,'1',0,'',0);\n";
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* sqlite3-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_SQLITE3_
|
||||
#define _DB_SQL_SQLITE3_
|
||||
|
||||
extern int db_sqlite3_open(char **pe, char *dsn);
|
||||
extern int db_sqlite3_close(void);
|
||||
|
||||
/* simple utility functions */
|
||||
extern int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...);
|
||||
extern char *db_sqlite3_vmquery(char *fmt,va_list ap);
|
||||
extern void db_sqlite3_vmfree(char *query);
|
||||
|
||||
/* walk through a table */
|
||||
extern int db_sqlite3_enum_begin(char **pe, char *fmt, ...);
|
||||
extern int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr);
|
||||
extern int db_sqlite3_enum_end(char **pe);
|
||||
extern int db_sqlite3_enum_restart(char **pe);
|
||||
|
||||
extern int db_sqlite3_event(int event_type);
|
||||
extern int db_sqlite3_insert_id(void);
|
||||
|
||||
#endif /* _DB_SQL_SQLITE3_ */
|
||||
|
@ -1,418 +0,0 @@
|
||||
/*
|
||||
* Commands to update database to new version
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
char *db_sqlite_updates[] = {
|
||||
/* version 0 -> version 1 -- initial update */
|
||||
"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"
|
||||
");\n"
|
||||
"CREATE INDEX idx_path ON songs(path);\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 playlists (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" title VARCHAR(255) NOT NULL,\n"
|
||||
" smart INTEGER NOT NULL,\n"
|
||||
" items INTEGER NOT NULL,\n"
|
||||
" query VARCHAR(1024)\n"
|
||||
");\n"
|
||||
"CREATE TABLE playlistitems (\n"
|
||||
" id INTEGER NOT NULL,\n"
|
||||
" songid INTEGER NOT NULL\n"
|
||||
");\n"
|
||||
"INSERT INTO config VALUES ('version','','1');\n"
|
||||
"INSERT INTO playlists VALUES (1,'Library',1,0,'1');\n",
|
||||
|
||||
/* version 1 -> version 2 */
|
||||
/* force rescan for invalid utf-8 data */
|
||||
"REPLACE INTO config VALUES('rescan',NULL,1);\n"
|
||||
"UPDATE config SET value=2 WHERE term='version';\n",
|
||||
|
||||
/* version 2 -> version 3 */
|
||||
/* add daap.songcodectype, normalize daap.songformat and daap.songdescription */
|
||||
"drop index idx_path;\n"
|
||||
"create temp table tempsongs as select * from songs;\n"
|
||||
"drop table songs;\n"
|
||||
"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"
|
||||
");\n"
|
||||
"begin transaction;\n"
|
||||
"insert into songs select *,NULL from tempsongs;\n"
|
||||
"commit transaction;\n"
|
||||
"update songs set type=lower(type);\n"
|
||||
"update songs set type='m4a' where type='aac' or type='mp4';\n"
|
||||
"update songs set type='flac' where type='fla';\n"
|
||||
"update songs set type='mpc' where type='mpp';\n"
|
||||
"update songs set type='mpc' where type='mp+';\n"
|
||||
"update songs set description='AAC audio file' where type='m4a';\n"
|
||||
"update songs set description='MPEG audio file' where type='mp3';\n"
|
||||
"update songs set description='WAV audio file' where type='wav';\n"
|
||||
"update songs set description='Playlist URL' where type='pls';\n"
|
||||
"update songs set description='Ogg Vorbis audio file' where type='ogg';\n"
|
||||
"update songs set description='FLAC audio file' where type='flac';\n"
|
||||
"update songs set description='Musepack audio file' where type='mpc';\n"
|
||||
"update songs set codectype='mp4a' where type='m4a' or type='m4p';\n"
|
||||
"update songs set codectype='mpeg' where type='mp3';\n"
|
||||
"update songs set codectype='ogg' where type='ogg';\n"
|
||||
"update songs set codectype='flac' where type='flac';\n"
|
||||
"update songs set codectype='mpc' where type='mpc';\n"
|
||||
"update songs set force_update=1 where type='m4a';\n" /* look for alac */
|
||||
"create index idx_path on songs(path);\n"
|
||||
"drop table tempsongs;\n"
|
||||
"update config set value=3 where term='version';\n",
|
||||
|
||||
/* version 3 -> version 4 */
|
||||
/* add db_timestamp and path to playlist table */
|
||||
"create temp table tempplaylists as select * from playlists;\n"
|
||||
"drop table playlists;\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"
|
||||
");\n"
|
||||
"insert into playlists select *,0,NULL from tempplaylists;\n"
|
||||
"drop table tempplaylists;\n"
|
||||
"update config set value=4 where term='version';\n",
|
||||
|
||||
/* version 4 -> version 5 */
|
||||
/* add index to playlist table */
|
||||
"create temp table tempplaylists as select * from playlists;\n"
|
||||
"drop table playlists;\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 playlists select *,0 from tempplaylists;\n"
|
||||
"drop table tempplaylists;\n"
|
||||
"update config set value=5 where term='version';\n",
|
||||
|
||||
/* version 5 -> version 6 */
|
||||
"drop index idx_path;\n"
|
||||
"create temp table tempsongs as select * from songs;\n"
|
||||
"drop table songs;\n"
|
||||
"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"
|
||||
"begin transaction;\n"
|
||||
"insert into songs select *,0 from tempsongs;\n"
|
||||
"commit transaction;\n"
|
||||
"create index idx_path on songs(path);\n"
|
||||
"drop table tempsongs;\n"
|
||||
"update config set value=6 where term='version';\n",
|
||||
|
||||
/* version 6 -> version 7 */
|
||||
"create temp table tempitems as select * from playlistitems;\n"
|
||||
"drop table playlistitems;\n"
|
||||
"CREATE TABLE playlistitems (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" playlistid INTEGER NOT NULL,\n"
|
||||
" songid INTEGER NOT NULL\n"
|
||||
");\n"
|
||||
"insert into playlistitems (playlistid, songid) select * from tempitems;\n"
|
||||
"drop table tempitems;\n"
|
||||
"update config set value=7 where term='version';\n",
|
||||
|
||||
/* version 7 -> version 8 */
|
||||
"create index idx_songid on playlistitems(songid)\n"
|
||||
"create index idx_playlistid on playlistitems(playlistid)\n"
|
||||
"update config set value=8 where term='version';\n",
|
||||
|
||||
/* version 8 -> version 9 */
|
||||
"drop index idx_path;\n"
|
||||
"create temp table tempsongs as select * from songs;\n"
|
||||
"drop table songs;\n"
|
||||
"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"
|
||||
" has_video INTEGER DEFAULT 0,\n"
|
||||
" contentrating INTEGER DEFAULT 0\n"
|
||||
");\n"
|
||||
"begin transaction;\n"
|
||||
"insert into songs select *,0,0 from tempsongs;\n"
|
||||
"commit transaction;\n"
|
||||
"update songs set has_video=1 where fname like '%.m4v';\n"
|
||||
"create index idx_path on songs(path);\n"
|
||||
"drop table tempsongs;\n"
|
||||
"update config set value=9 where term='version';\n",
|
||||
|
||||
/* version 9 -> version 10 */
|
||||
"drop index idx_path;\n"
|
||||
"create temp table tempsongs as select * from songs;\n"
|
||||
"drop table songs;\n"
|
||||
"CREATE TABLE songs (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" path VARCHAR(4096) 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"
|
||||
" has_video INTEGER DEFAULT 0,\n"
|
||||
" contentrating INTEGER DEFAULT 0\n"
|
||||
");\n"
|
||||
"begin transaction;\n"
|
||||
"insert into songs select * from tempsongs;\n"
|
||||
"commit transaction;\n"
|
||||
"create index idx_path on songs(path,idx);\n"
|
||||
"drop table tempsongs;\n"
|
||||
"update config set value=10 where term='version';\n",
|
||||
/* version 10 -> version 11 */
|
||||
"drop index idx_playlistid;\n"
|
||||
"create index idx_playlistid on playlistitems(playlistid,songid);\n"
|
||||
"update config set value=11 where term='version';\n",
|
||||
/* version 11 -> version 12 */
|
||||
"REPLACE INTO config VALUES('rescan',NULL,1);\n"
|
||||
"UPDATE config SET value=12 WHERE term='version';\n",
|
||||
/* version 12 -> version 13 */
|
||||
"create temp table tempsongs as select * from songs;\n"
|
||||
"drop table songs;\n"
|
||||
"CREATE TABLE songs (\n"
|
||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||
" path VARCHAR(4096) 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"
|
||||
" has_video INTEGER DEFAULT 0,\n"
|
||||
" contentrating INTEGER DEFAULT 0,\n"
|
||||
" bits_per_sample INTEGER DEFAULT 0,\n"
|
||||
" album_artist VARCHAR(1024)\n"
|
||||
");\n"
|
||||
"begin transaction;\n"
|
||||
"insert into songs select *,0,'' from tempsongs;\n"
|
||||
"commit transaction;\n"
|
||||
"drop table tempsongs;\n"
|
||||
"update config set value=13 where term='version';\n",
|
||||
NULL /* No more versions! */
|
||||
|
||||
};
|
1649
src/db-sql.c
1649
src/db-sql.c
File diff suppressed because it is too large
Load Diff
126
src/db-sql.h
126
src/db-sql.h
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#ifdef HAVE_SQLITE3
|
||||
extern int db_sql_open_sqlite3(char **pe, char *parameters);
|
||||
#endif
|
||||
|
||||
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_escape(char *buffer, int *size, char *fmt, ...);
|
||||
extern char * db_sql_escape_dup(char *fmt, ...);
|
||||
extern int db_sql_add(char **pe, MP3FILE *pmp3, int *id);
|
||||
extern int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo);
|
||||
|
||||
|
||||
extern int db_sql_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo);
|
||||
extern int db_sql_enum_reset(char **pe, DBQUERYINFO *pinfo);
|
||||
extern int db_sql_enum_end(char **pe);
|
||||
extern int db_sql_force_rescan(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_playcount_increment(char **pe, int id);
|
||||
|
||||
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_ */
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Database structure and fields
|
||||
*/
|
||||
|
||||
#ifndef _FF_DBSTRUCT_H_
|
||||
#define _FF_DBSTRUCT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PL_ID 0
|
||||
#define PL_TITLE 1
|
||||
#define PL_TYPE 2
|
||||
#define PL_ITEMS 3
|
||||
#define PL_QUERY 4
|
||||
#define PL_DB_TIMESTAMP 5
|
||||
#define PL_PATH 6
|
||||
#define PL_IDX 7
|
||||
|
||||
#define SG_ID 0
|
||||
#define SG_PATH 1
|
||||
#define SG_FNAME 2
|
||||
#define SG_TITLE 3
|
||||
#define SG_ARTIST 4
|
||||
#define SG_ALBUM 5
|
||||
#define SG_GENRE 6
|
||||
#define SG_COMMENT 7
|
||||
#define SG_TYPE 8
|
||||
#define SG_COMPOSER 9
|
||||
#define SG_ORCHESTRA 10
|
||||
#define SG_CONDUCTOR 11
|
||||
#define SG_GROUPING 12
|
||||
#define SG_URL 13
|
||||
#define SG_BITRATE 14
|
||||
#define SG_SAMPLERATE 15
|
||||
#define SG_SONG_LENGTH 16
|
||||
#define SG_FILE_SIZE 17
|
||||
#define SG_YEAR 18
|
||||
#define SG_TRACK 19
|
||||
#define SG_TOTAL_TRACKS 20
|
||||
#define SG_DISC 21
|
||||
#define SG_TOTAL_DISCS 22
|
||||
#define SG_BPM 23
|
||||
#define SG_COMPILATION 24
|
||||
#define SG_RATING 25
|
||||
#define SG_PLAY_COUNT 26
|
||||
#define SG_DATA_KIND 27
|
||||
#define SG_ITEM_KIND 28
|
||||
#define SG_DESCRIPTION 29
|
||||
#define SG_TIME_ADDED 30
|
||||
#define SG_TIME_MODIFIED 31
|
||||
#define SG_TIME_PLAYED 32
|
||||
#define SG_DB_TIMESTAMP 33
|
||||
#define SG_DISABLED 34
|
||||
#define SG_SAMPLE_COUNT 35
|
||||
#define SG_FORCE_UPDATE 36
|
||||
#define SG_CODECTYPE 37
|
||||
#define SG_IDX 38
|
||||
#define SG_HAS_VIDEO 39
|
||||
#define SG_CONTENTRATING 40
|
||||
#define SG_BITS_PER_SAMPLE 41
|
||||
#define SG_ALBUM_ARTIST 42
|
||||
|
||||
/* Packed and unpacked formats */
|
||||
typedef struct media_file_info {
|
||||
char *path;
|
||||
uint32_t index;
|
||||
char *fname;
|
||||
char *title; /* TIT2 */
|
||||
char *artist; /* TPE1 */
|
||||
char *album; /* TALB */
|
||||
char *genre; /* TCON */
|
||||
char *comment; /* COMM */
|
||||
char *type; /* daap.songformat */
|
||||
char *composer; /* TCOM */
|
||||
char *orchestra; /* TPE2 */
|
||||
char *conductor; /* TPE3 */
|
||||
char *grouping; /* TIT1 */
|
||||
char *url; /* daap.songdataurl (asul) */
|
||||
|
||||
uint32_t bitrate;
|
||||
uint32_t samplerate;
|
||||
uint32_t song_length;
|
||||
uint64_t file_size; /* ?? */
|
||||
uint32_t year; /* TDRC */
|
||||
|
||||
uint32_t track; /* TRCK */
|
||||
uint32_t total_tracks;
|
||||
|
||||
uint32_t disc; /* TPOS */
|
||||
uint32_t total_discs;
|
||||
|
||||
uint32_t time_added; /* really should be a time_t */
|
||||
uint32_t time_modified;
|
||||
uint32_t time_played;
|
||||
|
||||
uint32_t play_count;
|
||||
uint32_t rating;
|
||||
uint32_t db_timestamp;
|
||||
|
||||
uint32_t disabled;
|
||||
uint32_t bpm; /* TBPM */
|
||||
|
||||
uint32_t got_id3;
|
||||
uint32_t id;
|
||||
|
||||
char *description; /* daap.songdescription */
|
||||
char *codectype; /* song.codectype */
|
||||
/* codectype will be encoded as a short int, no more than 4 chars */
|
||||
|
||||
uint32_t item_kind; /* song or movie */
|
||||
uint32_t data_kind; /* dmap.datakind (asdk) */
|
||||
uint32_t force_update;
|
||||
uint64_t sample_count;
|
||||
char compilation;
|
||||
|
||||
/* iTunes 5+ */
|
||||
uint32_t contentrating;
|
||||
|
||||
/* iTunes 6.0.2 */
|
||||
uint32_t has_video;
|
||||
uint32_t bits_per_sample;
|
||||
|
||||
char *album_artist;
|
||||
} MP3FILE;
|
||||
|
||||
typedef struct playlist_info {
|
||||
uint32_t id; /**< integer id (miid) */
|
||||
char *title; /**< playlist name as displayed in iTunes (minm) */
|
||||
uint32_t type; /**< see PL_ types */
|
||||
uint32_t items; /**< number of items (mimc) */
|
||||
char *query; /**< where clause if type 1 (MSPS) */
|
||||
uint32_t db_timestamp;/**< time last updated */
|
||||
char *path; /**< path of underlying playlist (if type 2) */
|
||||
uint32_t index; /**< index of playlist for paths with multiple playlists */
|
||||
} M3UFILE;
|
||||
|
||||
typedef struct db_playlist_info {
|
||||
char *id;
|
||||
char *title;
|
||||
char *type;
|
||||
char *items;
|
||||
char *query;
|
||||
char *db_timestamp;
|
||||
char *path;
|
||||
char *index;
|
||||
} PACKED_M3UFILE;
|
||||
|
||||
typedef struct db_media_file_info {
|
||||
char *id;
|
||||
char *path;
|
||||
char *fname;
|
||||
char *title;
|
||||
char *artist;
|
||||
char *album;
|
||||
char *genre;
|
||||
char *comment;
|
||||
char *type;
|
||||
char *composer;
|
||||
char *orchestra;
|
||||
char *conductor;
|
||||
char *grouping;
|
||||
char *url;
|
||||
char *bitrate;
|
||||
char *samplerate;
|
||||
char *song_length;
|
||||
char *file_size;
|
||||
char *year;
|
||||
char *track;
|
||||
char *total_tracks;
|
||||
char *disc;
|
||||
char *total_discs;
|
||||
char *bpm;
|
||||
char *compilation;
|
||||
char *rating;
|
||||
char *play_count;
|
||||
char *data_kind;
|
||||
char *item_kind;
|
||||
char *description;
|
||||
char *time_added;
|
||||
char *time_modified;
|
||||
char *time_played;
|
||||
char *db_timestamp;
|
||||
char *disabled;
|
||||
char *sample_count;
|
||||
char *force_update;
|
||||
char *codectype;
|
||||
char *idx;
|
||||
char *has_video;
|
||||
char *contentrating;
|
||||
char *bits_per_sample;
|
||||
char *album_artist;
|
||||
} PACKED_MP3FILE;
|
||||
|
||||
#define PL_STATICWEB 0
|
||||
#define PL_SMART 1
|
||||
#define PL_STATICFILE 2
|
||||
#define PL_STATICXML 3
|
||||
|
||||
#endif /* _FF_DBSTRUCT_H_ */
|
Loading…
Reference in New Issue
Block a user