Merge branch 'db_refactor1'

This commit is contained in:
ejurgensen 2018-12-31 15:57:49 +01:00
commit 333c46318d
14 changed files with 1172 additions and 1614 deletions

View File

@ -122,6 +122,8 @@ FORK_MODULES_CHECK([COMMON], [SQLITE3], [sqlite3 >= 3.5.0],
[dnl Check that SQLite3 has the unlock notify API built-in [dnl Check that SQLite3 has the unlock notify API built-in
AC_CHECK_FUNC([[sqlite3_unlock_notify]], [], AC_CHECK_FUNC([[sqlite3_unlock_notify]], [],
[AC_MSG_ERROR([[SQLite3 was built without unlock notify support]])]) [AC_MSG_ERROR([[SQLite3 was built without unlock notify support]])])
dnl Check for sqlite3_expanded_sql (optional)
AC_CHECK_FUNCS([sqlite3_expanded_sql])
dnl Check that SQLite3 has been built with threadsafe operations dnl Check that SQLite3 has been built with threadsafe operations
AC_MSG_CHECKING([[if SQLite3 was built with threadsafe operations support]]) AC_MSG_CHECKING([[if SQLite3 was built with threadsafe operations support]])
AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <sqlite3.h> AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <sqlite3.h>

View File

@ -95,11 +95,13 @@ library {
# (changing this setting only takes effect after rescan, see the README) # (changing this setting only takes effect after rescan, see the README)
compilations = { "/Compilations" } compilations = { "/Compilations" }
# Compilations usually have many artists, and if you don't want every # Compilations usually have many artists, and sometimes no album artist.
# artist to be listed when artist browsing in Remote, you can set # If you don't want every artist to be listed in artist views, you can
# a single name which will be used for all music in the compilation dir # set a single name which will be used for all compilation tracks
# without an album artist, and for all tracks in the compilation
# directories.
# (changing this setting only takes effect after rescan, see the README) # (changing this setting only takes effect after rescan, see the README)
compilation_artist = "Various artists" compilation_artist = "Various Artists"
# If your album and artist lists are cluttered, you can choose to hide # If your album and artist lists are cluttered, you can choose to hide
# albums and artists with only one track. The tracks will still be # albums and artists with only one track. The tracks will still be

View File

@ -208,6 +208,34 @@ sqlext_daap_songalbumid_xfunc(sqlite3_context *pv, int n, sqlite3_value **ppv)
sqlite3_result_int64(pv, result); sqlite3_result_int64(pv, result);
} }
static void
sqlext_daap_no_zero_xfunc(sqlite3_context *pv, int n, sqlite3_value **ppv)
{
sqlite3_int64 new_value;
sqlite3_int64 old_value;
if (n != 2)
{
sqlite3_result_error(pv, "daap_no_zero() requires 2 parameters, new_value and old_value", -1);
return;
}
if ((sqlite3_value_type(ppv[0]) != SQLITE_INTEGER)
|| (sqlite3_value_type(ppv[1]) != SQLITE_INTEGER))
{
sqlite3_result_error(pv, "daap_no_zero() requires 2 integer parameters", -1);
return;
}
new_value = sqlite3_value_int64(ppv[0]);
old_value = sqlite3_value_int64(ppv[1]);
if (new_value != 0)
sqlite3_result_int64(pv, new_value);
else
sqlite3_result_int64(pv, old_value);
}
static int static int
sqlext_daap_unicode_xcollation(void *notused, int llen, const void *left, int rlen, const void *right) sqlext_daap_unicode_xcollation(void *notused, int llen, const void *left, int rlen, const void *right)
{ {
@ -259,6 +287,15 @@ sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines
return -1; return -1;
} }
ret = sqlite3_create_function(db, "daap_no_zero", 2, SQLITE_UTF8, NULL, sqlext_daap_no_zero_xfunc, NULL, NULL);
if (ret != SQLITE_OK)
{
if (pzErrMsg)
*pzErrMsg = sqlite3_mprintf("Could not create daap_no_zero function: %s\n", sqlite3_errmsg(db));
return -1;
}
ret = sqlite3_create_collation(db, "DAAP", SQLITE_UTF8, NULL, sqlext_daap_unicode_xcollation); ret = sqlite3_create_collation(db, "DAAP", SQLITE_UTF8, NULL, sqlext_daap_unicode_xcollation);
if (ret != SQLITE_OK) if (ret != SQLITE_OK)
{ {

1073
src/db.c

File diff suppressed because it is too large Load Diff

108
src/db.h
View File

@ -140,12 +140,16 @@ db_data_kind_label(enum data_kind data_kind);
/* Note that fields marked as integers in the metadata map in filescanner_ffmpeg must be uint32_t here */ /* Note that fields marked as integers in the metadata map in filescanner_ffmpeg must be uint32_t here */
struct media_file_info { struct media_file_info {
uint32_t id;
char *path; char *path;
uint32_t index; char *virtual_path;
char *fname; char *fname;
uint32_t directory_id; /* Id of directory */
char *title; char *title;
char *artist; char *artist;
char *album; char *album;
char *album_artist;
char *genre; char *genre;
char *comment; char *comment;
char *type; /* daap.songformat */ char *type; /* daap.songformat */
@ -160,6 +164,7 @@ struct media_file_info {
uint32_t song_length; uint32_t song_length;
int64_t file_size; int64_t file_size;
uint32_t year; /* TDRC */ uint32_t year; /* TDRC */
uint32_t date_released;
uint32_t track; /* TRCK */ uint32_t track; /* TRCK */
uint32_t total_tracks; uint32_t total_tracks;
@ -167,44 +172,44 @@ struct media_file_info {
uint32_t disc; /* TPOS */ uint32_t disc; /* TPOS */
uint32_t total_discs; uint32_t total_discs;
uint32_t bpm; /* TBPM */
uint32_t compilation;
char artwork;
uint32_t rating;
uint32_t play_count;
uint32_t skip_count;
uint32_t seek;
uint32_t data_kind; /* dmap.datakind (asdk) */
uint32_t media_kind;
uint32_t item_kind; /* song or movie */
char *description; /* daap.songdescription */
uint32_t db_timestamp;
uint32_t time_added; /* FIXME: time_t */ uint32_t time_added; /* FIXME: time_t */
uint32_t time_modified; uint32_t time_modified;
uint32_t time_played; uint32_t time_played;
uint32_t time_skipped;
uint32_t play_count;
uint32_t seek;
uint32_t rating;
uint32_t db_timestamp;
uint32_t disabled; uint32_t disabled;
uint32_t bpm; /* TBPM */
uint32_t id; uint64_t sample_count; //TODO [unused] sample count is never set and therefor always 0
char *description; /* daap.songdescription */
char *codectype; /* song.codectype, 4 chars max (32 bits) */ char *codectype; /* song.codectype, 4 chars max (32 bits) */
uint32_t item_kind; /* song or movie */ uint32_t idx;
uint32_t data_kind; /* dmap.datakind (asdk) */
uint64_t sample_count; //TODO [unused] sample count is never set and therefor always 0
uint32_t compilation;
char artwork;
/* iTunes 5+ */ uint32_t has_video; /* iTunes 6.0.2 */
uint32_t contentrating; uint32_t contentrating;/* iTunes 5+ */
/* iTunes 6.0.2 */
uint32_t has_video;
uint32_t bits_per_sample; uint32_t bits_per_sample;
uint32_t media_kind;
uint32_t tv_episode_sort;
uint32_t tv_season_num;
char *tv_series_name; char *tv_series_name;
char *tv_episode_num_str; /* com.apple.itunes.episode-num-str, used as a unique episode identifier */ char *tv_episode_num_str; /* com.apple.itunes.episode-num-str, used as a unique episode identifier */
char *tv_network_name; char *tv_network_name;
uint32_t tv_episode_sort;
char *album_artist; uint32_t tv_season_num;
int64_t songartistid; int64_t songartistid;
int64_t songalbumid; int64_t songalbumid;
@ -212,16 +217,8 @@ struct media_file_info {
char *title_sort; char *title_sort;
char *artist_sort; char *artist_sort;
char *album_sort; char *album_sort;
char *composer_sort;
char *album_artist_sort; char *album_artist_sort;
char *composer_sort;
char *virtual_path;
uint32_t directory_id; /* Id of directory */
uint32_t date_released;
uint32_t skip_count;
uint32_t time_skipped;
}; };
#define mfi_offsetof(field) offsetof(struct media_file_info, field) #define mfi_offsetof(field) offsetof(struct media_file_info, field)
@ -308,10 +305,13 @@ struct db_group_info {
struct db_media_file_info { struct db_media_file_info {
char *id; char *id;
char *path; char *path;
char *virtual_path;
char *fname; char *fname;
char *directory_id;
char *title; char *title;
char *artist; char *artist;
char *album; char *album;
char *album_artist;
char *genre; char *genre;
char *comment; char *comment;
char *type; char *type;
@ -325,6 +325,7 @@ struct db_media_file_info {
char *song_length; char *song_length;
char *file_size; char *file_size;
char *year; char *year;
char *date_released;
char *track; char *track;
char *total_tracks; char *total_tracks;
char *disc; char *disc;
@ -334,14 +335,17 @@ struct db_media_file_info {
char *artwork; char *artwork;
char *rating; char *rating;
char *play_count; char *play_count;
char *skip_count;
char *seek; char *seek;
char *data_kind; char *data_kind;
char *media_kind;
char *item_kind; char *item_kind;
char *description; char *description;
char *db_timestamp;
char *time_added; char *time_added;
char *time_modified; char *time_modified;
char *time_played; char *time_played;
char *db_timestamp; char *time_skipped;
char *disabled; char *disabled;
char *sample_count; char *sample_count;
char *codectype; char *codectype;
@ -349,8 +353,6 @@ struct db_media_file_info {
char *has_video; char *has_video;
char *contentrating; char *contentrating;
char *bits_per_sample; char *bits_per_sample;
char *album_artist;
char *media_kind;
char *tv_episode_sort; char *tv_episode_sort;
char *tv_season_num; char *tv_season_num;
char *tv_series_name; char *tv_series_name;
@ -361,13 +363,8 @@ struct db_media_file_info {
char *title_sort; char *title_sort;
char *artist_sort; char *artist_sort;
char *album_sort; char *album_sort;
char *composer_sort;
char *album_artist_sort; char *album_artist_sort;
char *virtual_path; char *composer_sort;
char *directory_id;
char *date_released;
char *skip_count;
char *time_skipped;
}; };
#define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field) #define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field)
@ -425,8 +422,7 @@ struct directory_enum {
void *stmt; void *stmt;
}; };
struct db_queue_item struct db_queue_item {
{
/* A unique id for this queue item. If the same item appears multiple /* A unique id for this queue item. If the same item appears multiple
times in the queue each corresponding queue item has its own id. */ times in the queue each corresponding queue item has its own id. */
uint32_t id; uint32_t id;
@ -434,18 +430,16 @@ struct db_queue_item
/* Id of the file/item in the files database */ /* Id of the file/item in the files database */
uint32_t file_id; uint32_t file_id;
/* Length of the item in ms */ uint32_t pos;
uint32_t song_length; uint32_t shuffle_pos;
/* Data type of the item */ /* Data type of the item */
enum data_kind data_kind; enum data_kind data_kind;
/* Media type of the item */ /* Media type of the item */
enum media_kind media_kind; enum media_kind media_kind;
uint32_t seek; /* Length of the item in ms */
uint32_t song_length;
uint32_t pos;
uint32_t shuffle_pos;
char *path; char *path;
char *virtual_path; char *virtual_path;
@ -453,7 +447,6 @@ struct db_queue_item
char *title; char *title;
char *artist; char *artist;
char *album_artist; char *album_artist;
char *composer;
char *album; char *album;
char *genre; char *genre;
@ -471,8 +464,15 @@ struct db_queue_item
char *artwork_url; char *artwork_url;
uint32_t queue_version; uint32_t queue_version;
char *composer;
/* Not saved in queue table */
uint32_t seek;
}; };
#define qi_offsetof(field) offsetof(struct db_queue_item, field)
struct db_queue_add_info struct db_queue_add_info
{ {
int queue_version; int queue_version;
@ -510,12 +510,6 @@ free_query_params(struct query_params *qp, int content_only);
void void
free_queue_item(struct db_queue_item *queue_item, int content_only); free_queue_item(struct db_queue_item *queue_item, int content_only);
void
unicode_fixup_mfi(struct media_file_info *mfi);
void
fixup_tags_mfi(struct media_file_info *mfi);
/* Maintenance and DB hygiene */ /* Maintenance and DB hygiene */
void void
db_hook_post_scan(void); db_hook_post_scan(void);

View File

@ -36,10 +36,13 @@
"CREATE TABLE IF NOT EXISTS files (" \ "CREATE TABLE IF NOT EXISTS files (" \
" id INTEGER PRIMARY KEY NOT NULL," \ " id INTEGER PRIMARY KEY NOT NULL," \
" path VARCHAR(4096) NOT NULL," \ " path VARCHAR(4096) NOT NULL," \
" virtual_path VARCHAR(4096) DEFAULT NULL," \
" fname VARCHAR(255) NOT NULL," \ " fname VARCHAR(255) NOT NULL," \
" directory_id INTEGER DEFAULT 0," \
" title VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " title VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album VARCHAR(1024) NOT NULL COLLATE DAAP," \ " album VARCHAR(1024) NOT NULL COLLATE DAAP," \
" album_artist VARCHAR(1024) NOT NULL COLLATE DAAP," \
" genre VARCHAR(255) DEFAULT NULL COLLATE DAAP," \ " genre VARCHAR(255) DEFAULT NULL COLLATE DAAP," \
" comment VARCHAR(4096) DEFAULT NULL COLLATE DAAP," \ " comment VARCHAR(4096) DEFAULT NULL COLLATE DAAP," \
" type VARCHAR(255) DEFAULT NULL COLLATE DAAP," \ " type VARCHAR(255) DEFAULT NULL COLLATE DAAP," \
@ -53,6 +56,7 @@
" song_length INTEGER DEFAULT 0," \ " song_length INTEGER DEFAULT 0," \
" file_size INTEGER DEFAULT 0," \ " file_size INTEGER DEFAULT 0," \
" year INTEGER DEFAULT 0," \ " year INTEGER DEFAULT 0," \
" date_released INTEGER DEFAULT 0," \
" track INTEGER DEFAULT 0," \ " track INTEGER DEFAULT 0," \
" total_tracks INTEGER DEFAULT 0," \ " total_tracks INTEGER DEFAULT 0," \
" disc INTEGER DEFAULT 0," \ " disc INTEGER DEFAULT 0," \
@ -62,14 +66,17 @@
" artwork INTEGER DEFAULT 0," \ " artwork INTEGER DEFAULT 0," \
" rating INTEGER DEFAULT 0," \ " rating INTEGER DEFAULT 0," \
" play_count INTEGER DEFAULT 0," \ " play_count INTEGER DEFAULT 0," \
" skip_count INTEGER DEFAULT 0," \
" seek INTEGER DEFAULT 0," \ " seek INTEGER DEFAULT 0," \
" data_kind INTEGER DEFAULT 0," \ " data_kind INTEGER DEFAULT 0," \
" media_kind INTEGER DEFAULT 0," \
" item_kind INTEGER DEFAULT 0," \ " item_kind INTEGER DEFAULT 0," \
" description INTEGER DEFAULT 0," \ " description INTEGER DEFAULT 0," \
" db_timestamp INTEGER DEFAULT 0," \
" time_added INTEGER DEFAULT 0," \ " time_added INTEGER DEFAULT 0," \
" time_modified INTEGER DEFAULT 0," \ " time_modified INTEGER DEFAULT 0," \
" time_played INTEGER DEFAULT 0," \ " time_played INTEGER DEFAULT 0," \
" db_timestamp INTEGER DEFAULT 0," \ " time_skipped INTEGER DEFAULT 0," \
" disabled INTEGER DEFAULT 0," \ " disabled INTEGER DEFAULT 0," \
" sample_count INTEGER DEFAULT 0," \ " sample_count INTEGER DEFAULT 0," \
" codectype VARCHAR(5) DEFAULT NULL," \ " codectype VARCHAR(5) DEFAULT NULL," \
@ -77,25 +84,18 @@
" has_video INTEGER DEFAULT 0," \ " has_video INTEGER DEFAULT 0," \
" contentrating INTEGER DEFAULT 0," \ " contentrating INTEGER DEFAULT 0," \
" bits_per_sample INTEGER DEFAULT 0," \ " bits_per_sample INTEGER DEFAULT 0," \
" album_artist VARCHAR(1024) NOT NULL COLLATE DAAP," \
" media_kind INTEGER NOT NULL," \
" tv_series_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " tv_series_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_episode_num_str VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " tv_episode_num_str VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_network_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " tv_network_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_episode_sort INTEGER NOT NULL," \ " tv_episode_sort INTEGER NOT NULL," \
" tv_season_num INTEGER NOT NULL," \ " tv_season_num INTEGER NOT NULL," \
" songartistid INTEGER NOT NULL," \ " songartistid INTEGER DEFAULT 0," \
" songalbumid INTEGER NOT NULL," \ " songalbumid INTEGER DEFAULT 0," \
" title_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " title_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " album_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album_artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \ " album_artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" virtual_path VARCHAR(4096) DEFAULT NULL," \ " composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP" \
" directory_id INTEGER DEFAULT 0," \
" date_released INTEGER DEFAULT 0," \
" skip_count INTEGER DEFAULT 0," \
" time_skipped INTEGER DEFAULT 0" \
");" ");"
#define T_PL \ #define T_PL \
@ -194,20 +194,6 @@
" composer VARCHAR(1024) DEFAULT NULL" \ " composer VARCHAR(1024) DEFAULT NULL" \
");" ");"
#define TRG_GROUPS_INSERT_FILES \
"CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
#define TRG_GROUPS_UPDATE_FILES \
"CREATE TRIGGER update_groups_update_file AFTER UPDATE OF songalbumid ON files FOR EACH ROW" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
#define Q_PL1 \ #define Q_PL1 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \ "INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(1, 'Library', 0, '1 = 1', 0, '', 0, 0);" " VALUES(1, 'Library', 0, '1 = 1', 0, '', 0, 0);"
@ -278,19 +264,18 @@ static const struct db_init_query db_init_table_queries[] =
{ T_DIRECTORIES, "create table directories" }, { T_DIRECTORIES, "create table directories" },
{ T_QUEUE, "create table queue" }, { T_QUEUE, "create table queue" },
{ TRG_GROUPS_INSERT_FILES, "create trigger update_groups_new_file" },
{ TRG_GROUPS_UPDATE_FILES, "create trigger update_groups_update_file" },
{ Q_PL1, "create default playlist" }, { Q_PL1, "create default playlist" },
{ Q_PL2, "create default smart playlist 'Music'" }, { Q_PL2, "create default smart playlist 'Music'" },
{ Q_PL3, "create default smart playlist 'Movies'" }, { Q_PL3, "create default smart playlist 'Movies'" },
{ Q_PL4, "create default smart playlist 'TV Shows'" }, { Q_PL4, "create default smart playlist 'TV Shows'" },
{ Q_PL5, "create default smart playlist 'Podcasts'" }, { Q_PL5, "create default smart playlist 'Podcasts'" },
{ Q_PL6, "create default smart playlist 'Audiobooks'" }, { Q_PL6, "create default smart playlist 'Audiobooks'" },
{ Q_DIR1, "create default root directory '/'" }, { Q_DIR1, "create default root directory '/'" },
{ Q_DIR2, "create default base directory '/file:'" }, { Q_DIR2, "create default base directory '/file:'" },
{ Q_DIR3, "create default base directory '/http:'" }, { Q_DIR3, "create default base directory '/http:'" },
{ Q_DIR4, "create default base directory '/spotify:'" }, { Q_DIR4, "create default base directory '/spotify:'" },
{ Q_QUEUE_VERSION, "initialize queue version" }, { Q_QUEUE_VERSION, "initialize queue version" },
}; };
@ -411,6 +396,41 @@ static const struct db_init_query db_init_index_queries[] =
{ I_QUEUE_SHUFFLEPOS, "create queue shuffle pos index" }, { I_QUEUE_SHUFFLEPOS, "create queue shuffle pos index" },
}; };
/* Triggers must be prefixed with trg_ for db_drop_triggers() to id them */
#define TRG_FILES_INSERT_SONGIDS \
"CREATE TRIGGER trg_files_insert_songids AFTER INSERT ON files FOR EACH ROW" \
" BEGIN" \
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
" WHERE id = NEW.id;" \
" END;"
#define TRG_FILES_UPDATE_SONGIDS \
"CREATE TRIGGER trg_files_update_songids AFTER UPDATE OF album_artist, album ON files FOR EACH ROW" \
" BEGIN" \
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
" WHERE id = NEW.id;" \
" END;"
#define TRG_GROUPS_UPDATE \
"CREATE TRIGGER trg_groups_update AFTER UPDATE OF songartistid, songalbumid ON files FOR EACH ROW" \
" WHEN (NEW.songartistid != 0 AND NEW.songalbumid != 0)" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
static const struct db_init_query db_init_trigger_queries[] =
{
{ TRG_FILES_INSERT_SONGIDS, "create trigger trg_files_insert_songids" },
{ TRG_FILES_UPDATE_SONGIDS, "create trigger trg_files_update_songids" },
{ TRG_GROUPS_UPDATE, "create trigger trg_groups_update" },
};
int int
db_init_indices(sqlite3 *hdl) db_init_indices(sqlite3 *hdl)
{ {
@ -435,6 +455,30 @@ db_init_indices(sqlite3 *hdl)
return 0; return 0;
} }
int
db_init_triggers(sqlite3 *hdl)
{
char *errmsg;
int i;
int ret;
for (i = 0; i < (sizeof(db_init_trigger_queries) / sizeof(db_init_trigger_queries[0])); i++)
{
DPRINTF(E_DBG, L_DB, "DB init trigger query: %s\n", db_init_trigger_queries[i].desc);
ret = sqlite3_exec(hdl, db_init_trigger_queries[i].query, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
}
return 0;
}
int int
db_init_tables(sqlite3 *hdl) db_init_tables(sqlite3 *hdl)
{ {

View File

@ -25,12 +25,15 @@
* version of the database? If yes, then it is a minor upgrade, if no, then it * version of the database? If yes, then it is a minor upgrade, if no, then it
* is a major upgrade. In other words minor version upgrades permit downgrading * is a major upgrade. In other words minor version upgrades permit downgrading
* forked-daapd after the database was upgraded. */ * forked-daapd after the database was upgraded. */
#define SCHEMA_VERSION_MAJOR 19 #define SCHEMA_VERSION_MAJOR 20
#define SCHEMA_VERSION_MINOR 12 #define SCHEMA_VERSION_MINOR 00
int int
db_init_indices(sqlite3 *hdl); db_init_indices(sqlite3 *hdl);
int
db_init_triggers(sqlite3 *hdl);
int int
db_init_tables(sqlite3 *hdl); db_init_tables(sqlite3 *hdl);

File diff suppressed because it is too large Load Diff

View File

@ -154,7 +154,7 @@ response_process(struct http_client_ctx *ctx, char **errmsg)
DPRINTF(E_DBG, L_LASTFM, "LastFM response:\n%s\n", body); DPRINTF(E_DBG, L_LASTFM, "LastFM response:\n%s\n", body);
if (errmsg) if (errmsg)
*errmsg = trimwhitespace(mxmlGetOpaque(e_node)); *errmsg = atrim(mxmlGetOpaque(e_node));
mxmlDelete(tree); mxmlDelete(tree);
return -1; return -1;
@ -180,7 +180,7 @@ response_process(struct http_client_ctx *ctx, char **errmsg)
return -1; return -1;
} }
sk = trimwhitespace(mxmlGetOpaque(s_node)); sk = atrim(mxmlGetOpaque(s_node));
if (sk) if (sk)
{ {
DPRINTF(E_LOG, L_LASTFM, "Got session key from LastFM: %s\n", sk); DPRINTF(E_LOG, L_LASTFM, "Got session key from LastFM: %s\n", sk);

View File

@ -128,14 +128,6 @@ library_add_media(struct media_file_info *mfi)
mfi->path, mfi->directory_id, mfi->virtual_path); mfi->path, mfi->directory_id, mfi->virtual_path);
} }
if (!mfi->item_kind)
mfi->item_kind = 2; /* music */
if (!mfi->media_kind)
mfi->media_kind = MEDIA_KIND_MUSIC; /* music */
unicode_fixup_mfi(mfi);
fixup_tags_mfi(mfi);
if (mfi->id == 0) if (mfi->id == 0)
db_file_add(mfi); db_file_add(mfi);
else else

View File

@ -509,14 +509,18 @@ process_regular_file(const char *file, struct stat *sb, int type, int flags, int
else else
{ {
mfi.data_kind = DATA_KIND_FILE; mfi.data_kind = DATA_KIND_FILE;
mfi.file_size = sb->st_size;
if (type & F_SCAN_TYPE_AUDIOBOOK) if (type & F_SCAN_TYPE_AUDIOBOOK)
mfi.media_kind = MEDIA_KIND_AUDIOBOOK; mfi.media_kind = MEDIA_KIND_AUDIOBOOK;
else if (type & F_SCAN_TYPE_PODCAST) else if (type & F_SCAN_TYPE_PODCAST)
mfi.media_kind = MEDIA_KIND_PODCAST; mfi.media_kind = MEDIA_KIND_PODCAST;
mfi.compilation = (type & F_SCAN_TYPE_COMPILATION); if (type & F_SCAN_TYPE_COMPILATION)
mfi.file_size = sb->st_size; {
mfi.compilation = 1;
mfi.album_artist = safe_strdup(cfg_getstr(cfg_getsec(cfg, "library"), "compilation_artist"));
}
ret = scan_metadata_ffmpeg(file, &mfi); ret = scan_metadata_ffmpeg(file, &mfi);
if (ret < 0) if (ret < 0)
@ -1686,7 +1690,6 @@ queue_add_stream(const char *path, int position, char reshuffle, uint32_t item_i
memset(&mfi, 0, sizeof(struct media_file_info)); memset(&mfi, 0, sizeof(struct media_file_info));
scan_metadata_stream(path, &mfi); scan_metadata_stream(path, &mfi);
unicode_fixup_mfi(&mfi);
map_media_file_to_queue_item(&item, &mfi); map_media_file_to_queue_item(&item, &mfi);

View File

@ -548,7 +548,6 @@ process_track_file(plist_t trk)
mfi->album_artist = strdup(mfi->artist); mfi->album_artist = strdup(mfi->artist);
} }
unicode_fixup_mfi(mfi);
db_file_update(mfi); db_file_update(mfi);
free_mfi(mfi, 0); free_mfi(mfi, 0);

View File

@ -33,6 +33,7 @@
#include <errno.h> #include <errno.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
#include <limits.h> #include <limits.h>
#include <sys/param.h> #include <sys/param.h>
#ifndef CLOCK_REALTIME #ifndef CLOCK_REALTIME
@ -341,6 +342,7 @@ safe_asprintf(const char *fmt, ...)
{ {
char *ret = NULL; char *ret = NULL;
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
if (vasprintf(&ret, fmt, va) < 0) if (vasprintf(&ret, fmt, va) < 0)
{ {
@ -348,9 +350,34 @@ safe_asprintf(const char *fmt, ...)
abort(); abort();
} }
va_end(va); va_end(va);
return ret; return ret;
} }
int
safe_snprintf_cat(char *dst, size_t n, const char *fmt, ...)
{
size_t dstlen;
va_list va;
int ret;
if (!dst || !fmt)
return -1;
dstlen = strlen(dst);
if (n < dstlen)
return -1;
va_start(va, fmt);
ret = vsnprintf(dst + dstlen, n - dstlen, fmt, va);
va_end(va);
if (ret >= 0 && ret < n - dstlen)
return 0;
else
return -1;
}
/* Key/value functions */ /* Key/value functions */
struct keyval * struct keyval *
@ -586,7 +613,7 @@ m_readfile(const char *path, int num_lines)
goto error; goto error;
} }
lines[i] = trimwhitespace(line); lines[i] = atrim(line);
if (!lines[i] || (strlen(lines[i]) == 0)) if (!lines[i] || (strlen(lines[i]) == 0))
{ {
DPRINTF(E_LOG, L_MISC, "Line %d in '%s' is invalid\n", i+1, path); DPRINTF(E_LOG, L_MISC, "Line %d in '%s' is invalid\n", i+1, path);
@ -643,40 +670,58 @@ unicode_fixup_string(char *str, const char *fromcode)
} }
char * char *
trimwhitespace(const char *str) trim(char *str)
{ {
char *ptr; size_t start; // Position of first non-space char
char *start; size_t term; // Position of 0-terminator
char *out;
if (!str) if (!str)
return NULL; return NULL;
// Find the beginning start = 0;
while (isspace(*str)) term = strlen(str);
str++;
if (*str == 0) // All spaces? while ((start < term) && isspace(str[start]))
return strdup(""); start++;
while ((term > start) && isspace(str[term - 1]))
term--;
// Make copy, because we will need to insert a null terminator str[term] = '\0';
start = strdup(str);
if (!start) // Shift chars incl. terminator
if (start)
memmove(str, str + start, term - start + 1);
return str;
}
char *
atrim(const char *str)
{
size_t start; // Position of first non-space char
size_t term; // Position of 0-terminator
size_t size;
char *result;
if (!str)
return NULL; return NULL;
// Find the end start = 0;
ptr = start + strlen(start) - 1; term = strlen(str);
while (ptr > start && isspace(*ptr))
ptr--;
// Insert null terminator while ((start < term) && isspace(str[start]))
*(ptr+1) = 0; start++;
while ((term > start) && isspace(str[term - 1]))
term--;
out = strdup(start); size = term - start + 1;
free(start); result = malloc(size);
return out; memcpy(result, str + start, size);
result[size - 1] = '\0';
return result;
} }
void void

View File

@ -58,6 +58,10 @@ safe_strdup(const char *str);
char * char *
safe_asprintf(const char *fmt, ...); safe_asprintf(const char *fmt, ...);
int
safe_snprintf_cat(char *dst, size_t n, const char *fmt, ...);
/* Key/value functions */ /* Key/value functions */
struct keyval * struct keyval *
keyval_alloc(void); keyval_alloc(void);
@ -87,8 +91,13 @@ m_readfile(const char *path, int num_lines);
char * char *
unicode_fixup_string(char *str, const char *fromcode); unicode_fixup_string(char *str, const char *fromcode);
// Modifies str so it is trimmed. Returns pointer to str.
char * char *
trimwhitespace(const char *str); trim(char *str);
// Copies the trimmed part of str to a newly allocated string (caller must free)
char *
atrim(const char *str);
void void
swap_pointers(char **a, char **b); swap_pointers(char **a, char **b);
@ -105,8 +114,7 @@ b64_encode(const uint8_t *in, size_t len);
uint64_t uint64_t
murmur_hash64(const void *key, int len, uint32_t seed); murmur_hash64(const void *key, int len, uint32_t seed);
// Checks if the address is in a network that is configured as trusted
/* Checks if the address is in a network that is configured as trusted */
bool bool
peer_address_is_trusted(const char *addr); peer_address_is_trusted(const char *addr);