mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-27 15:45:56 -05:00
Merge remote branch 'upstream/libevent'
This commit is contained in:
commit
54d3951c20
@ -1,6 +1,12 @@
|
||||
ChangeLog for forked-daapd
|
||||
--------------------------
|
||||
|
||||
version 0.19:
|
||||
- more libav 0.7 updates.
|
||||
- database speedups.
|
||||
- fix for iTunes 30-minute timeout.
|
||||
- fixes, big and small.
|
||||
|
||||
version 0.18:
|
||||
- add config knob for ALSA mixer channel name.
|
||||
- do not elevate privileges for reopening the log file; log file
|
||||
|
@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(config.h.in)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE(forked-daapd, 0.18)
|
||||
AM_INIT_AUTOMAKE(forked-daapd, 0.19)
|
||||
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
|
81
ffmpeg/libav-0.7.patch
Normal file
81
ffmpeg/libav-0.7.patch
Normal file
@ -0,0 +1,81 @@
|
||||
--- libav/libavformat/mov.c 2011-08-09 14:03:47.622688230 -0700
|
||||
+++ libav/libavformat/mov.c 2011-08-09 14:09:33.181475099 -0700
|
||||
@@ -81,19 +81,46 @@
|
||||
|
||||
static const MOVParseTableEntry mov_default_parse_table[];
|
||||
|
||||
-static int mov_metadata_trkn(MOVContext *c, AVIOContext *pb, unsigned len)
|
||||
+static int mov_metadata_trkn(MOVContext *c, AVIOContext *pb, unsigned len, const char *key)
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
avio_rb16(pb); // unknown
|
||||
snprintf(buf, sizeof(buf), "%d", avio_rb16(pb));
|
||||
- av_dict_set(&c->fc->metadata, "track", buf, 0);
|
||||
+ av_dict_set(&c->fc->metadata, key, buf, 0);
|
||||
|
||||
avio_rb16(pb); // total tracks
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int mov_metadata_int8(MOVContext *c, AVIOContext *pb, unsigned len, const char *key)
|
||||
+{
|
||||
+ char buf[16];
|
||||
+
|
||||
+ /* bypass padding bytes */
|
||||
+ get_byte(pb);
|
||||
+ get_byte(pb);
|
||||
+ get_byte(pb);
|
||||
+
|
||||
+ snprintf(buf, sizeof(buf-1), "%hu", get_byte(pb));
|
||||
+ buf[sizeof(buf)-1] = 0;
|
||||
+ av_metadata_set2(&c->fc->metadata, key, buf, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mov_metadata_stik(MOVContext *c, AVIOContext *pb, unsigned len, const char *key)
|
||||
+{
|
||||
+ char buf[16];
|
||||
+
|
||||
+ snprintf(buf, sizeof(buf-1), "%hu", get_byte(pb));
|
||||
+ buf[sizeof(buf)-1] = 0;
|
||||
+ av_metadata_set2(&c->fc->metadata, key, buf, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static const uint32_t mac_to_unicode[128] = {
|
||||
0x00C4,0x00C5,0x00C7,0x00C9,0x00D1,0x00D6,0x00DC,0x00E1,
|
||||
0x00E0,0x00E2,0x00E4,0x00E3,0x00E5,0x00E7,0x00E9,0x00E8,
|
||||
@@ -140,7 +167,7 @@
|
||||
const char *key = NULL;
|
||||
uint16_t str_size, langcode = 0;
|
||||
uint32_t data_type = 0;
|
||||
- int (*parse)(MOVContext*, AVIOContext*, unsigned) = NULL;
|
||||
+ int (*parse)(MOVContext*, AVIOContext*, unsigned, const char *) = NULL;
|
||||
|
||||
switch (atom.type) {
|
||||
case MKTAG(0xa9,'n','a','m'): key = "title"; break;
|
||||
@@ -162,6 +189,11 @@
|
||||
case MKTAG( 't','v','s','h'): key = "show"; break;
|
||||
case MKTAG( 't','v','e','n'): key = "episode_id";break;
|
||||
case MKTAG( 't','v','n','n'): key = "network"; break;
|
||||
+ case MKTAG( 't','v','e','s'): key = "episode_sort";
|
||||
+ case MKTAG( 't','v','s','n'): key = "season_number";
|
||||
+ parse = mov_metadata_int8; break;
|
||||
+ case MKTAG( 's','t','i','k'): key = "stik";
|
||||
+ parse = mov_metadata_stik; break;
|
||||
case MKTAG( 't','r','k','n'): key = "track";
|
||||
parse = mov_metadata_trkn; break;
|
||||
}
|
||||
@@ -198,7 +230,7 @@
|
||||
str_size = FFMIN3(sizeof(str)-1, str_size, atom.size);
|
||||
|
||||
if (parse)
|
||||
- parse(c, pb, str_size);
|
||||
+ parse(c, pb, str_size, key);
|
||||
else {
|
||||
if (data_type == 3 || (data_type == 0 && langcode < 0x800)) { // MAC Encoded
|
||||
mov_read_mac_string(c, pb, str_size, str, sizeof(str));
|
@ -205,6 +205,7 @@ strcrit returns [ pANTLR3_STRING result, int valid ]
|
||||
}
|
||||
|
||||
$result = field->factory->newRaw(field->factory);
|
||||
$result->append8($result, "f.");
|
||||
$result->appendS($result, field);
|
||||
$result->append8($result, op);
|
||||
$result->append8($result, "'");
|
||||
@ -289,6 +290,7 @@ intcrit returns [ pANTLR3_STRING result, int valid ]
|
||||
}
|
||||
|
||||
$result = field->factory->newRaw(field->factory);
|
||||
$result->append8($result, "f.");
|
||||
$result->appendS($result, field);
|
||||
$result->append8($result, op);
|
||||
$result->appendS($result, $i->getText($i));
|
||||
@ -362,6 +364,7 @@ datecrit returns [ pANTLR3_STRING result, int valid ]
|
||||
}
|
||||
|
||||
$result = field->factory->newRaw(field->factory);
|
||||
$result->append8($result, "f.");
|
||||
$result->appendS($result, field);
|
||||
$result->append8($result, op);
|
||||
$result->append8($result, buf);
|
||||
|
@ -265,6 +265,7 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int forma
|
||||
dst->width = out_w;
|
||||
dst->height = out_h;
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR <= 52 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR <= 1)
|
||||
ret = av_set_parameters(dst_ctx, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -273,6 +274,7 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int forma
|
||||
ret = -1;
|
||||
goto out_free_dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open encoder */
|
||||
ret = avcodec_open(dst, img_encoder);
|
||||
@ -411,7 +413,11 @@ artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int forma
|
||||
pkt.data = outbuf;
|
||||
pkt.size = ret;
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3)
|
||||
ret = avformat_write_header(dst_ctx, NULL);
|
||||
#else
|
||||
ret = av_write_header(dst_ctx);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_ART, "Could not write artwork header: %s\n", strerror(AVUNERROR(ret)));
|
||||
@ -500,7 +506,13 @@ artwork_get(char *filename, int max_w, int max_h, int format, struct evbuffer *e
|
||||
|
||||
DPRINTF(E_DBG, L_ART, "Artwork request parameters: max w = %d, max h = %d\n", max_w, max_h);
|
||||
|
||||
src_ctx = NULL;
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3)
|
||||
ret = avformat_open_input(&src_ctx, filename, NULL, NULL);
|
||||
#else
|
||||
ret = av_open_input_file(&src_ctx, filename, NULL, 0, NULL);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_WARN, L_ART, "Cannot open artwork file '%s': %s\n", filename, strerror(AVUNERROR(ret)));
|
||||
|
@ -10,30 +10,30 @@
|
||||
%omit-struct-type
|
||||
struct dmap_query_field_map;
|
||||
%%
|
||||
"dmap.itemname", "title", 0
|
||||
"dmap.itemid", "id", 1
|
||||
"daap.songalbum", "album", 0
|
||||
"daap.songalbumid", "songalbumid", 1
|
||||
"daap.songartist", "artist", 0
|
||||
"daap.songalbumartist", "album_artist", 0
|
||||
"daap.songbitrate", "bitrate", 1
|
||||
"daap.songcomment", "comment", 0
|
||||
"daap.songcompilation", "compilation", 1
|
||||
"daap.songcomposer", "composer", 0
|
||||
"daap.songdatakind", "data_kind", 1
|
||||
"daap.songdataurl", "url", 0
|
||||
"daap.songdateadded", "time_added", 1
|
||||
"daap.songdatemodified", "time_modified", 1
|
||||
"daap.songdescription", "description", 0
|
||||
"daap.songdisccount", "total_discs", 1
|
||||
"daap.songdiscnumber", "disc", 1
|
||||
"daap.songformat", "type", 0
|
||||
"daap.songgenre", "genre", 0
|
||||
"daap.songsamplerate", "samplerate", 1
|
||||
"daap.songsize", "file_size", 1
|
||||
"daap.songstoptime", "song_length", 1
|
||||
"daap.songtime", "song_length", 1
|
||||
"daap.songtrackcount", "total_tracks", 1
|
||||
"daap.songtracknumber", "track", 1
|
||||
"daap.songyear", "year", 1
|
||||
"com.apple.itunes.mediakind", "media_kind", 1
|
||||
"dmap.itemname", "f.title", 0
|
||||
"dmap.itemid", "f.id", 1
|
||||
"daap.songalbum", "f.album", 0
|
||||
"daap.songalbumid", "f.songalbumid", 1
|
||||
"daap.songartist", "f.artist", 0
|
||||
"daap.songalbumartist", "f.album_artist", 0
|
||||
"daap.songbitrate", "f.bitrate", 1
|
||||
"daap.songcomment", "f.comment", 0
|
||||
"daap.songcompilation", "f.compilation", 1
|
||||
"daap.songcomposer", "f.composer", 0
|
||||
"daap.songdatakind", "f.data_kind", 1
|
||||
"daap.songdataurl", "f.url", 0
|
||||
"daap.songdateadded", "f.time_added", 1
|
||||
"daap.songdatemodified", "f.time_modified", 1
|
||||
"daap.songdescription", "f.description", 0
|
||||
"daap.songdisccount", "f.total_discs", 1
|
||||
"daap.songdiscnumber", "f.disc", 1
|
||||
"daap.songformat", "f.type", 0
|
||||
"daap.songgenre", "f.genre", 0
|
||||
"daap.songsamplerate", "f.samplerate", 1
|
||||
"daap.songsize", "f.file_size", 1
|
||||
"daap.songstoptime", "f.song_length", 1
|
||||
"daap.songtime", "f.song_length", 1
|
||||
"daap.songtrackcount", "f.total_tracks", 1
|
||||
"daap.songtracknumber", "f.track", 1
|
||||
"daap.songyear", "f.year", 1
|
||||
"com.apple.itunes.mediakind", "f.media_kind", 1
|
||||
|
467
src/db.c
467
src/db.c
@ -260,9 +260,9 @@ static const struct col_type_map wi_cols_map[] =
|
||||
static const char *sort_clause[] =
|
||||
{
|
||||
"",
|
||||
"ORDER BY title_sort ASC",
|
||||
"ORDER BY album_sort ASC, disc ASC, track ASC",
|
||||
"ORDER BY artist_sort ASC",
|
||||
"ORDER BY f.title_sort ASC",
|
||||
"ORDER BY f.album_sort ASC, f.disc ASC, f.track ASC",
|
||||
"ORDER BY f.artist_sort ASC",
|
||||
};
|
||||
|
||||
static char *db_path;
|
||||
@ -568,6 +568,35 @@ db_exec(const char *query, char **errmsg)
|
||||
}
|
||||
|
||||
|
||||
/* Maintenance and DB hygiene */
|
||||
static void
|
||||
db_analyze(void)
|
||||
{
|
||||
char *query = "ANALYZE;";
|
||||
char *errmsg;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
|
||||
ret = db_exec(query, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "ANALYZE failed: %s\n", errmsg);
|
||||
|
||||
sqlite3_free(errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
db_hook_post_scan(void)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "Running post-scan DB maintenance tasks...\n");
|
||||
|
||||
db_analyze();
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Done with post-scan DB maintenance\n");
|
||||
}
|
||||
|
||||
void
|
||||
db_purge_cruft(time_t ref)
|
||||
{
|
||||
@ -577,7 +606,7 @@ db_purge_cruft(time_t ref)
|
||||
char *queries[3] = { NULL, NULL, NULL };
|
||||
char *queries_tmpl[3] =
|
||||
{
|
||||
"DELETE FROM playlistitems WHERE playlistid IN (SELECT id FROM playlists WHERE type <> 1 AND db_timestamp < %" PRIi64 ");",
|
||||
"DELETE FROM playlistitems WHERE playlistid IN (SELECT id FROM playlists p WHERE p.type <> 1 AND p.db_timestamp < %" PRIi64 ");",
|
||||
"DELETE FROM playlists WHERE type <> 1 AND db_timestamp < %" PRIi64 ";",
|
||||
"DELETE FROM files WHERE db_timestamp < %" PRIi64 ";"
|
||||
};
|
||||
@ -647,6 +676,11 @@ db_get_count(char *query)
|
||||
|
||||
ret = sqlite3_column_int(stmt, 0);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return ret;
|
||||
@ -703,9 +737,9 @@ db_build_query_items(struct query_params *qp, char **q)
|
||||
int ret;
|
||||
|
||||
if (qp->filter)
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files WHERE disabled = 0 AND %s;", qp->filter);
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files f WHERE f.disabled = 0 AND %s;", qp->filter);
|
||||
else
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files WHERE disabled = 0;");
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files f WHERE f.disabled = 0;");
|
||||
|
||||
if (!count)
|
||||
{
|
||||
@ -728,13 +762,13 @@ db_build_query_items(struct query_params *qp, char **q)
|
||||
sort = sort_clause[qp->sort];
|
||||
|
||||
if (idx && qp->filter)
|
||||
query = sqlite3_mprintf("SELECT * FROM files WHERE disabled = 0 AND %s %s %s;", qp->filter, sort, idx);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f WHERE f.disabled = 0 AND %s %s %s;", qp->filter, sort, idx);
|
||||
else if (idx)
|
||||
query = sqlite3_mprintf("SELECT * FROM files WHERE disabled = 0 %s %s;", sort, idx);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f WHERE f.disabled = 0 %s %s;", sort, idx);
|
||||
else if (qp->filter)
|
||||
query = sqlite3_mprintf("SELECT * FROM files WHERE disabled = 0 AND %s %s;", qp->filter, sort);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f WHERE f.disabled = 0 AND %s %s;", qp->filter, sort);
|
||||
else
|
||||
query = sqlite3_mprintf("SELECT * FROM files WHERE disabled = 0 %s;", sort);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f WHERE f.disabled = 0 %s;", sort);
|
||||
|
||||
if (!query)
|
||||
{
|
||||
@ -754,7 +788,7 @@ db_build_query_pls(struct query_params *qp, char **q)
|
||||
char *idx;
|
||||
int ret;
|
||||
|
||||
qp->results = db_get_count("SELECT COUNT(*) FROM playlists WHERE disabled = 0;");
|
||||
qp->results = db_get_count("SELECT COUNT(*) FROM playlists p WHERE p.disabled = 0;");
|
||||
if (qp->results < 0)
|
||||
return -1;
|
||||
|
||||
@ -764,13 +798,13 @@ db_build_query_pls(struct query_params *qp, char **q)
|
||||
return -1;
|
||||
|
||||
if (idx && qp->filter)
|
||||
query = sqlite3_mprintf("SELECT * FROM playlists WHERE disabled = 0 AND %s %s;", qp->filter, idx);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM playlists f WHERE f.disabled = 0 AND %s %s;", qp->filter, idx);
|
||||
else if (idx)
|
||||
query = sqlite3_mprintf("SELECT * FROM playlists WHERE disabled = 0 %s;", idx);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM playlists f WHERE f.disabled = 0 %s;", idx);
|
||||
else if (qp->filter)
|
||||
query = sqlite3_mprintf("SELECT * FROM playlists WHERE disabled = 0 AND %s;", qp->filter);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM playlists f WHERE f.disabled = 0 AND %s;", qp->filter);
|
||||
else
|
||||
query = sqlite3_mprintf("SELECT * FROM playlists WHERE disabled = 0;");
|
||||
query = sqlite3_mprintf("SELECT f.* FROM playlists f WHERE f.disabled = 0;");
|
||||
|
||||
if (!query)
|
||||
{
|
||||
@ -792,11 +826,11 @@ db_build_query_plitems_plain(struct query_params *qp, char **q)
|
||||
int ret;
|
||||
|
||||
if (qp->filter)
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files JOIN playlistitems ON files.path = playlistitems.filepath"
|
||||
" WHERE playlistitems.playlistid = %d AND files.disabled = 0 AND %s;", qp->id, qp->filter);
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files f JOIN playlistitems pi ON f.path = pi.filepath"
|
||||
" WHERE pi.playlistid = %d AND f.disabled = 0 AND %s;", qp->id, qp->filter);
|
||||
else
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files JOIN playlistitems ON files.path = playlistitems.filepath"
|
||||
" WHERE playlistitems.playlistid = %d AND files.disabled = 0;", qp->id);
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files f JOIN playlistitems pi ON f.path = pi.filepath"
|
||||
" WHERE pi.playlistid = %d AND f.disabled = 0;", qp->id);
|
||||
|
||||
if (!count)
|
||||
{
|
||||
@ -817,20 +851,20 @@ db_build_query_plitems_plain(struct query_params *qp, char **q)
|
||||
return -1;
|
||||
|
||||
if (idx && qp->filter)
|
||||
query = sqlite3_mprintf("SELECT files.* FROM files JOIN playlistitems ON files.path = playlistitems.filepath"
|
||||
" WHERE playlistitems.playlistid = %d AND files.disabled = 0 AND %s ORDER BY playlistitems.id ASC %s;",
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath"
|
||||
" WHERE pi.playlistid = %d AND f.disabled = 0 AND %s ORDER BY pi.id ASC %s;",
|
||||
qp->id, qp->filter, idx);
|
||||
else if (idx)
|
||||
query = sqlite3_mprintf("SELECT files.* FROM files JOIN playlistitems ON files.path = playlistitems.filepath"
|
||||
" WHERE playlistitems.playlistid = %d AND files.disabled = 0 ORDER BY playlistitems.id ASC %s;",
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath"
|
||||
" WHERE pi.playlistid = %d AND f.disabled = 0 ORDER BY pi.id ASC %s;",
|
||||
qp->id, idx);
|
||||
else if (qp->filter)
|
||||
query = sqlite3_mprintf("SELECT files.* FROM files JOIN playlistitems ON files.path = playlistitems.filepath"
|
||||
" WHERE playlistitems.playlistid = %d AND files.disabled = 0 AND %s ORDER BY playlistitems.id ASC;",
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath"
|
||||
" WHERE pi.playlistid = %d AND f.disabled = 0 AND %s ORDER BY pi.id ASC;",
|
||||
qp->id, qp->filter);
|
||||
else
|
||||
query = sqlite3_mprintf("SELECT files.* FROM files JOIN playlistitems ON files.path = playlistitems.filepath"
|
||||
" WHERE playlistitems.playlistid = %d AND files.disabled = 0 ORDER BY playlistitems.id ASC;",
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath"
|
||||
" WHERE pi.playlistid = %d AND f.disabled = 0 ORDER BY pi.id ASC;",
|
||||
qp->id);
|
||||
|
||||
if (!query)
|
||||
@ -859,7 +893,7 @@ db_build_query_plitems_smart(struct query_params *qp, char *smartpl_query, char
|
||||
else
|
||||
filter = "1 = 1";
|
||||
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files WHERE disabled = 0 AND %s AND %s;", filter, smartpl_query);
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files f WHERE f.disabled = 0 AND %s AND %s;", filter, smartpl_query);
|
||||
if (!count)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for count query string\n");
|
||||
@ -883,7 +917,7 @@ db_build_query_plitems_smart(struct query_params *qp, char *smartpl_query, char
|
||||
|
||||
sort = sort_clause[qp->sort];
|
||||
|
||||
query = sqlite3_mprintf("SELECT * FROM files WHERE disabled = 0 AND %s AND %s %s %s;", smartpl_query, filter, sort, idx);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f WHERE f.disabled = 0 AND %s AND %s %s %s;", smartpl_query, filter, sort, idx);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
@ -939,7 +973,7 @@ db_build_query_groups(struct query_params *qp, char **q)
|
||||
char *idx;
|
||||
int ret;
|
||||
|
||||
qp->results = db_get_count("SELECT COUNT(DISTINCT songalbumid) FROM files WHERE disabled = 0;");
|
||||
qp->results = db_get_count("SELECT COUNT(DISTINCT f.songalbumid) FROM files f WHERE f.disabled = 0;");
|
||||
if (qp->results < 0)
|
||||
return -1;
|
||||
|
||||
@ -949,13 +983,13 @@ db_build_query_groups(struct query_params *qp, char **q)
|
||||
return -1;
|
||||
|
||||
if (idx && qp->filter)
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album, g.name HAVING g.type = %d AND disabled = 0 AND %s %s;", G_ALBUMS, qp->filter, idx);
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f, groups g WHERE f.songalbumid = g.persistentid AND g.type = %d AND f.disabled = 0 AND %s GROUP BY f.album, g.name %s;", G_ALBUMS, qp->filter, idx);
|
||||
else if (idx)
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album, g.name HAVING g.type = %d AND disabled = 0 %s;", G_ALBUMS, idx);
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f, groups g WHERE f.songalbumid = g.persistentid AND g.type = %d AND f.disabled = 0 GROUP BY f.album, g.name %s;", G_ALBUMS, idx);
|
||||
else if (qp->filter)
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album, g.name HAVING g.type = %d AND disabled = 0 AND %s;", G_ALBUMS, qp->filter);
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f, groups g WHERE f.songalbumid = g.persistentid AND g.type = %d AND f.disabled = 0 AND %s GROUP BY f.album, g.name;", G_ALBUMS, qp->filter);
|
||||
else
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f JOIN groups g ON f.songalbumid = g.persistentid GROUP BY f.album, g.name HAVING g.type = %d AND disabled = 0;", G_ALBUMS);
|
||||
query = sqlite3_mprintf("SELECT COUNT(*), g.id, g.persistentid, f.album_artist, g.name FROM files f, groups g WHERE f.songalbumid = g.persistentid AND g.type = %d AND f.disabled = 0 GROUP BY f.album, g.name;", G_ALBUMS);
|
||||
|
||||
if (!query)
|
||||
{
|
||||
@ -980,8 +1014,8 @@ db_build_query_groupitems(struct query_params *qp, char **q)
|
||||
switch (gt)
|
||||
{
|
||||
case G_ALBUMS:
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files JOIN groups ON files.songalbumid = groups.persistentid"
|
||||
" WHERE groups.id = %d AND files.disabled = 0;", qp->id);
|
||||
count = sqlite3_mprintf("SELECT COUNT(*) FROM files f JOIN groups g ON f.songalbumid = g.persistentid"
|
||||
" WHERE g.id = %d AND f.disabled = 0;", qp->id);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1005,8 +1039,8 @@ db_build_query_groupitems(struct query_params *qp, char **q)
|
||||
switch (gt)
|
||||
{
|
||||
case G_ALBUMS:
|
||||
query = sqlite3_mprintf("SELECT files.* FROM files JOIN groups ON files.songalbumid = groups.persistentid"
|
||||
" WHERE groups.id = %d AND files.disabled = 0;", qp->id);
|
||||
query = sqlite3_mprintf("SELECT f.* FROM files f JOIN groups g ON f.songalbumid = g.persistentid"
|
||||
" WHERE g.id = %d AND f.disabled = 0;", qp->id);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1033,9 +1067,9 @@ db_build_query_group_dirs(struct query_params *qp, char **q)
|
||||
switch (gt)
|
||||
{
|
||||
case G_ALBUMS:
|
||||
count = sqlite3_mprintf("SELECT COUNT(DISTINCT(SUBSTR(files.path, 1, LENGTH(files.path) - LENGTH(files.fname) - 1)))"
|
||||
" FROM files JOIN groups ON files.songalbumid = groups.persistentid"
|
||||
" WHERE groups.id = %d AND files.disabled = 0;", qp->id);
|
||||
count = sqlite3_mprintf("SELECT COUNT(DISTINCT(SUBSTR(f.path, 1, LENGTH(f.path) - LENGTH(f.fname) - 1)))"
|
||||
" FROM files f JOIN groups g ON f.songalbumid = g.persistentid"
|
||||
" WHERE g.id = %d AND f.disabled = 0;", qp->id);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1059,9 +1093,9 @@ db_build_query_group_dirs(struct query_params *qp, char **q)
|
||||
switch (gt)
|
||||
{
|
||||
case G_ALBUMS:
|
||||
query = sqlite3_mprintf("SELECT DISTINCT(SUBSTR(files.path, 1, LENGTH(files.path) - LENGTH(files.fname) - 1))"
|
||||
" FROM files JOIN groups ON files.songalbumid = groups.persistentid"
|
||||
" WHERE groups.id = %d AND files.disabled = 0;", qp->id);
|
||||
query = sqlite3_mprintf("SELECT DISTINCT(SUBSTR(f.path, 1, LENGTH(f.path) - LENGTH(f.fname) - 1))"
|
||||
" FROM files f JOIN groups g ON f.songalbumid = g.persistentid"
|
||||
" WHERE g.id = %d AND f.disabled = 0;", qp->id);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1085,10 +1119,10 @@ db_build_query_browse(struct query_params *qp, char *field, char **q)
|
||||
int ret;
|
||||
|
||||
if (qp->filter)
|
||||
count = sqlite3_mprintf("SELECT COUNT(DISTINCT %s) FROM files WHERE data_kind = 0 AND disabled = 0 AND %s != '' AND %s;",
|
||||
count = sqlite3_mprintf("SELECT COUNT(DISTINCT f.%s) FROM files f WHERE f.data_kind = 0 AND f.disabled = 0 AND f.%s != '' AND %s;",
|
||||
field, field, qp->filter);
|
||||
else
|
||||
count = sqlite3_mprintf("SELECT COUNT(DISTINCT %s) FROM files WHERE data_kind = 0 AND disabled = 0 AND %s != '';",
|
||||
count = sqlite3_mprintf("SELECT COUNT(DISTINCT f.%s) FROM files f WHERE f.data_kind = 0 AND f.disabled = 0 AND f.%s != '';",
|
||||
field, field);
|
||||
|
||||
if (!count)
|
||||
@ -1110,16 +1144,16 @@ db_build_query_browse(struct query_params *qp, char *field, char **q)
|
||||
return -1;
|
||||
|
||||
if (idx && qp->filter)
|
||||
query = sqlite3_mprintf("SELECT DISTINCT %s, %s FROM files WHERE data_kind = 0 AND disabled = 0 AND %s != ''"
|
||||
query = sqlite3_mprintf("SELECT DISTINCT f.%s, f.%s FROM files f WHERE f.data_kind = 0 AND f.disabled = 0 AND f.%s != ''"
|
||||
" AND %s %s;", field, field, field, qp->filter, idx);
|
||||
else if (idx)
|
||||
query = sqlite3_mprintf("SELECT DISTINCT %s, %s FROM files WHERE data_kind = 0 AND disabled = 0 AND %s != ''"
|
||||
query = sqlite3_mprintf("SELECT DISTINCT f.%s, f.%s FROM files f WHERE f.data_kind = 0 AND f.disabled = 0 AND f.%s != ''"
|
||||
" %s;", field, field, field, idx);
|
||||
else if (qp->filter)
|
||||
query = sqlite3_mprintf("SELECT DISTINCT %s, %s FROM files WHERE data_kind = 0 AND disabled = 0 AND %s != ''"
|
||||
query = sqlite3_mprintf("SELECT DISTINCT f.%s, f.%s FROM files f WHERE f.data_kind = 0 AND f.disabled = 0 AND f.%s != ''"
|
||||
" AND %s;", field, field, field, qp->filter);
|
||||
else
|
||||
query = sqlite3_mprintf("SELECT DISTINCT %s, %s FROM files WHERE data_kind = 0 AND disabled = 0 AND %s != ''",
|
||||
query = sqlite3_mprintf("SELECT DISTINCT f.%s, f.%s FROM files f WHERE f.data_kind = 0 AND f.disabled = 0 AND f.%s != ''",
|
||||
field, field, field);
|
||||
|
||||
if (!query)
|
||||
@ -1487,7 +1521,7 @@ db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortst
|
||||
int
|
||||
db_files_get_count(void)
|
||||
{
|
||||
return db_get_count("SELECT COUNT(*) FROM files WHERE disabled = 0;");
|
||||
return db_get_count("SELECT COUNT(*) FROM files f WHERE f.disabled = 0;");
|
||||
}
|
||||
|
||||
void
|
||||
@ -1537,14 +1571,14 @@ db_file_inc_playcount(int id)
|
||||
}
|
||||
|
||||
void
|
||||
db_file_ping(char *path)
|
||||
db_file_ping(int id)
|
||||
{
|
||||
#define Q_TMPL "UPDATE files SET db_timestamp = %" PRIi64 ", disabled = 0 WHERE path = '%q';"
|
||||
#define Q_TMPL "UPDATE files SET db_timestamp = %" PRIi64 ", disabled = 0 WHERE id = %d;"
|
||||
char *query;
|
||||
char *errmsg;
|
||||
int ret;
|
||||
|
||||
query = sqlite3_mprintf(Q_TMPL, (int64_t)time(NULL), path);
|
||||
query = sqlite3_mprintf(Q_TMPL, (int64_t)time(NULL), id);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
@ -1556,7 +1590,7 @@ db_file_ping(char *path)
|
||||
|
||||
ret = db_exec(query, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
DPRINTF(E_LOG, L_DB, "Error pinging file '%s': %s\n", path, errmsg);
|
||||
DPRINTF(E_LOG, L_DB, "Error pinging file ID %d: %s\n", id, errmsg);
|
||||
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
@ -1567,7 +1601,7 @@ db_file_ping(char *path)
|
||||
char *
|
||||
db_file_path_byid(int id)
|
||||
{
|
||||
#define Q_TMPL "SELECT path FROM files WHERE id = %d;"
|
||||
#define Q_TMPL "SELECT f.path FROM files f WHERE f.id = %d;"
|
||||
char *query;
|
||||
sqlite3_stmt *stmt;
|
||||
char *res;
|
||||
@ -1609,6 +1643,11 @@ db_file_path_byid(int id)
|
||||
if (res)
|
||||
res = strdup(res);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
|
||||
@ -1650,6 +1689,11 @@ db_file_id_byquery(char *query)
|
||||
|
||||
ret = sqlite3_column_int(stmt, 0);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return ret;
|
||||
@ -1658,7 +1702,7 @@ db_file_id_byquery(char *query)
|
||||
int
|
||||
db_file_id_bypath(char *path)
|
||||
{
|
||||
#define Q_TMPL "SELECT id FROM files WHERE path = '%q';"
|
||||
#define Q_TMPL "SELECT f.id FROM files f WHERE f.path = '%q';"
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
@ -1682,7 +1726,7 @@ db_file_id_bypath(char *path)
|
||||
int
|
||||
db_file_id_byfilebase(char *filename, char *base)
|
||||
{
|
||||
#define Q_TMPL "SELECT id FROM files WHERE path LIKE '%q/%%/%q';"
|
||||
#define Q_TMPL "SELECT f.id FROM files f WHERE f.path LIKE '%q/%%/%q';"
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
@ -1706,7 +1750,7 @@ db_file_id_byfilebase(char *filename, char *base)
|
||||
int
|
||||
db_file_id_byfile(char *filename)
|
||||
{
|
||||
#define Q_TMPL "SELECT id FROM files WHERE fname = '%q';"
|
||||
#define Q_TMPL "SELECT f.id FROM files f WHERE f.fname = '%q';"
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
@ -1730,7 +1774,7 @@ db_file_id_byfile(char *filename)
|
||||
int
|
||||
db_file_id_byurl(char *url)
|
||||
{
|
||||
#define Q_TMPL "SELECT id FROM files WHERE url = '%q';"
|
||||
#define Q_TMPL "SELECT f.id FROM files f WHERE f.url = '%q';"
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
@ -1751,21 +1795,22 @@ db_file_id_byurl(char *url)
|
||||
#undef Q_TMPL
|
||||
}
|
||||
|
||||
time_t
|
||||
db_file_stamp_bypath(char *path)
|
||||
void
|
||||
db_file_stamp_bypath(char *path, time_t *stamp, int *id)
|
||||
{
|
||||
#define Q_TMPL "SELECT db_timestamp FROM files WHERE path = '%q';"
|
||||
#define Q_TMPL "SELECT f.id, f.db_timestamp FROM files f WHERE f.path = '%q';"
|
||||
char *query;
|
||||
sqlite3_stmt *stmt;
|
||||
time_t stamp;
|
||||
int ret;
|
||||
|
||||
*stamp = 0;
|
||||
|
||||
query = sqlite3_mprintf(Q_TMPL, path);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
@ -1776,7 +1821,7 @@ db_file_stamp_bypath(char *path)
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = db_blocking_step(stmt);
|
||||
@ -1789,16 +1834,20 @@ db_file_stamp_bypath(char *path)
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
stamp = (time_t)sqlite3_column_int64(stmt, 0);
|
||||
*id = sqlite3_column_int(stmt, 0);
|
||||
*stamp = (time_t)sqlite3_column_int64(stmt, 1);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
|
||||
return stamp;
|
||||
|
||||
#undef Q_TMPL
|
||||
}
|
||||
|
||||
@ -1908,6 +1957,11 @@ db_file_fetch_byquery(char *query)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return mfi;
|
||||
@ -1916,7 +1970,7 @@ db_file_fetch_byquery(char *query)
|
||||
struct media_file_info *
|
||||
db_file_fetch_byid(int id)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM files WHERE id = %d;"
|
||||
#define Q_TMPL "SELECT f.* FROM files f WHERE f.id = %d;"
|
||||
struct media_file_info *mfi;
|
||||
char *query;
|
||||
|
||||
@ -2222,14 +2276,14 @@ db_file_enable_bycookie(uint32_t cookie, char *path)
|
||||
int
|
||||
db_pl_get_count(void)
|
||||
{
|
||||
return db_get_count("SELECT COUNT(*) FROM playlists WHERE disabled = 0;");
|
||||
return db_get_count("SELECT COUNT(*) FROM playlists p WHERE p.disabled = 0;");
|
||||
}
|
||||
|
||||
static int
|
||||
db_pl_count_items(int id)
|
||||
{
|
||||
#define Q_TMPL "SELECT COUNT(*) FROM playlistitems JOIN files" \
|
||||
" ON playlistitems.filepath = files.path WHERE files.disabled = 0 AND playlistitems.playlistid = %d;"
|
||||
#define Q_TMPL "SELECT COUNT(*) FROM playlistitems pi JOIN files f" \
|
||||
" ON pi.filepath = f.path WHERE f.disabled = 0 AND pi.playlistid = %d;"
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
@ -2253,7 +2307,7 @@ db_pl_count_items(int id)
|
||||
static int
|
||||
db_smartpl_count_items(const char *smartpl_query)
|
||||
{
|
||||
#define Q_TMPL "SELECT COUNT(*) FROM files WHERE disabled = 0 AND %s;"
|
||||
#define Q_TMPL "SELECT COUNT(*) FROM files f WHERE f.disabled = 0 AND %s;"
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
@ -2305,7 +2359,7 @@ db_pl_ping(int id)
|
||||
static int
|
||||
db_pl_id_bypath(char *path, int *id)
|
||||
{
|
||||
#define Q_TMPL "SELECT id FROM playlists WHERE path = '%q';"
|
||||
#define Q_TMPL "SELECT p.id FROM playlists p WHERE p.path = '%q';"
|
||||
char *query;
|
||||
sqlite3_stmt *stmt;
|
||||
int ret;
|
||||
@ -2344,6 +2398,11 @@ db_pl_id_bypath(char *path, int *id)
|
||||
|
||||
*id = sqlite3_column_int(stmt, 0);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
|
||||
@ -2478,7 +2537,7 @@ db_pl_fetch_byquery(char *query)
|
||||
struct playlist_info *
|
||||
db_pl_fetch_bypath(char *path)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM playlists WHERE path = '%q';"
|
||||
#define Q_TMPL "SELECT p.* FROM playlists p WHERE p.path = '%q';"
|
||||
struct playlist_info *pli;
|
||||
char *query;
|
||||
|
||||
@ -2502,7 +2561,7 @@ db_pl_fetch_bypath(char *path)
|
||||
struct playlist_info *
|
||||
db_pl_fetch_byid(int id)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM playlists WHERE id = %d;"
|
||||
#define Q_TMPL "SELECT p.* FROM playlists p WHERE p.id = %d;"
|
||||
struct playlist_info *pli;
|
||||
char *query;
|
||||
|
||||
@ -2526,7 +2585,7 @@ db_pl_fetch_byid(int id)
|
||||
struct playlist_info *
|
||||
db_pl_fetch_bytitlepath(char *title, char *path)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM playlists WHERE title = '%q' AND path = '%q';"
|
||||
#define Q_TMPL "SELECT p.* FROM playlists p WHERE p.title = '%q' AND p.path = '%q';"
|
||||
struct playlist_info *pli;
|
||||
char *query;
|
||||
|
||||
@ -2550,7 +2609,7 @@ db_pl_fetch_bytitlepath(char *title, char *path)
|
||||
int
|
||||
db_pl_add(char *title, char *path, int *id)
|
||||
{
|
||||
#define QDUP_TMPL "SELECT COUNT(*) FROM playlists WHERE title = '%q' AND path = '%q';"
|
||||
#define QDUP_TMPL "SELECT COUNT(*) FROM playlists p WHERE p.title = '%q' AND p.path = '%q';"
|
||||
#define QADD_TMPL "INSERT INTO playlists (title, type, query, db_timestamp, disabled, path, idx, special_id)" \
|
||||
" VALUES ('%q', 0, NULL, %" PRIi64 ", 0, '%q', 0, 0);"
|
||||
char *query;
|
||||
@ -2649,7 +2708,7 @@ db_pl_add_item_bypath(int plid, char *path)
|
||||
int
|
||||
db_pl_add_item_byid(int plid, int fileid)
|
||||
{
|
||||
#define Q_TMPL "INSERT INTO playlistitems (playlistid, filepath) VALUES (%d, (SELECT path FROM files WHERE id = %d));"
|
||||
#define Q_TMPL "INSERT INTO playlistitems (playlistid, filepath) VALUES (%d, (SELECT f.path FROM files f WHERE f.id = %d));"
|
||||
char *query;
|
||||
char *errmsg;
|
||||
int ret;
|
||||
@ -2882,7 +2941,7 @@ db_groups_clear(void)
|
||||
enum group_type
|
||||
db_group_type_byid(int id)
|
||||
{
|
||||
#define Q_TMPL "SELECT type FROM groups WHERE id = '%d';"
|
||||
#define Q_TMPL "SELECT g.type FROM groups g WHERE g.id = '%d';"
|
||||
char *query;
|
||||
sqlite3_stmt *stmt;
|
||||
int ret;
|
||||
@ -2921,6 +2980,11 @@ db_group_type_byid(int id)
|
||||
|
||||
ret = sqlite3_column_int(stmt, 0);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
|
||||
@ -3007,7 +3071,7 @@ db_pairing_add(struct pairing_info *pi)
|
||||
int
|
||||
db_pairing_fetch_byguid(struct pairing_info *pi)
|
||||
{
|
||||
#define Q_TMPL "SELECT * FROM pairings WHERE guid = '%q';"
|
||||
#define Q_TMPL "SELECT p.* FROM pairings p WHERE p.guid = '%q';"
|
||||
char *query;
|
||||
sqlite3_stmt *stmt;
|
||||
int ret;
|
||||
@ -3044,6 +3108,11 @@ db_pairing_fetch_byguid(struct pairing_info *pi)
|
||||
pi->remote_id = strdup((char *)sqlite3_column_text(stmt, 0));
|
||||
pi->name = strdup((char *)sqlite3_column_text(stmt, 1));
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
|
||||
@ -3093,7 +3162,7 @@ db_speaker_save(uint64_t id, int selected, int volume)
|
||||
int
|
||||
db_speaker_get(uint64_t id, int *selected, int *volume)
|
||||
{
|
||||
#define Q_TMPL "SELECT selected, volume FROM speakers WHERE id = %" PRIi64 ";"
|
||||
#define Q_TMPL "SELECT s.selected, s.volume FROM speakers s WHERE s.id = %" PRIi64 ";"
|
||||
sqlite3_stmt *stmt;
|
||||
char *query;
|
||||
int ret;
|
||||
@ -3132,6 +3201,11 @@ db_speaker_get(uint64_t id, int *selected, int *volume)
|
||||
*selected = sqlite3_column_int(stmt, 0);
|
||||
*volume = sqlite3_column_int(stmt, 1);
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
ret = 0;
|
||||
@ -3422,6 +3496,11 @@ db_watch_get_bywd(struct watch_info *wi)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DB_PROFILE
|
||||
while (db_blocking_step(stmt) == SQLITE_ROW)
|
||||
; /* EMPTY */
|
||||
#endif
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_free(query);
|
||||
|
||||
@ -3646,8 +3725,57 @@ db_watch_enum_fetchwd(struct watch_enum *we, uint32_t *wd)
|
||||
static void
|
||||
db_xprofile(void *notused, const char *pquery, sqlite3_uint64 ptime)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "SQL PROFILE query: %s\n", pquery);
|
||||
DPRINTF(E_DBG, L_DB, "SQL PROFILE time: %" PRIu64 "\n", (uint64_t)ptime);
|
||||
sqlite3_stmt *stmt;
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_DBPERF, "SQL PROFILE query: %s\n", pquery);
|
||||
DPRINTF(E_DBG, L_DBPERF, "SQL PROFILE time: %" PRIu64 " ms\n", ((uint64_t)ptime / 1000000));
|
||||
|
||||
if ((strncmp(pquery, "SELECT", 6) != 0)
|
||||
&& (strncmp(pquery, "UPDATE", 6) != 0)
|
||||
&& (strncmp(pquery, "DELETE", 6) != 0))
|
||||
return;
|
||||
|
||||
/* Disable profiling callback */
|
||||
sqlite3_profile(hdl, NULL, NULL);
|
||||
|
||||
query = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", pquery);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DBPERF, "Query plan: Out of memory\n");
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = db_blocking_prepare_v2(query, -1, &stmt, NULL);
|
||||
sqlite3_free(query);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DBPERF, "Query plan: Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_DBPERF, "Query plan:\n");
|
||||
|
||||
while ((ret = db_blocking_step(stmt)) == SQLITE_ROW)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DBPERF, "(%d,%d,%d) %s\n",
|
||||
sqlite3_column_int(stmt, 0), sqlite3_column_int(stmt, 1), sqlite3_column_int(stmt, 2),
|
||||
sqlite3_column_text(stmt, 3));
|
||||
}
|
||||
|
||||
if (ret != SQLITE_DONE)
|
||||
DPRINTF(E_DBG, L_DBPERF, "Query plan: Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
DPRINTF(E_DBG, L_DBPERF, "---\n");
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
out:
|
||||
/* Reenable profiling callback */
|
||||
sqlite3_profile(hdl, db_xprofile, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3838,8 +3966,35 @@ db_perthread_deinit(void)
|
||||
" path VARCHAR(4096) NOT NULL" \
|
||||
");"
|
||||
|
||||
#define I_PATH \
|
||||
"CREATE INDEX IF NOT EXISTS idx_path ON files(path, idx);"
|
||||
#define I_RESCAN \
|
||||
"CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp);"
|
||||
|
||||
#define I_SONGALBUMID \
|
||||
"CREATE INDEX IF NOT EXISTS idx_sai ON files(songalbumid);"
|
||||
|
||||
#define I_STATEMKINDSAI \
|
||||
"CREATE INDEX IF NOT EXISTS idx_state_mkind_sai ON files(disabled, media_kind, songalbumid);"
|
||||
|
||||
#define I_ARTIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_artist ON files(artist, artist_sort);"
|
||||
|
||||
#define I_ALBUMARTIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_albumartist ON files(album_artist, album_artist_sort);"
|
||||
|
||||
#define I_COMPOSER \
|
||||
"CREATE INDEX IF NOT EXISTS idx_composer ON files(composer, composer_sort);"
|
||||
|
||||
#define I_TITLE \
|
||||
"CREATE INDEX IF NOT EXISTS idx_title ON files(title, title_sort);"
|
||||
|
||||
#define I_ALBUM \
|
||||
"CREATE INDEX IF NOT EXISTS idx_album ON files(album, album_sort);"
|
||||
|
||||
#define I_PL_PATH \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_path ON playlists(path);"
|
||||
|
||||
#define I_PL_DISABLED \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled);"
|
||||
|
||||
#define I_FILEPATH \
|
||||
"CREATE INDEX IF NOT EXISTS idx_filepath ON playlistitems(filepath ASC);"
|
||||
@ -3847,17 +4002,12 @@ db_perthread_deinit(void)
|
||||
#define I_PLITEMID \
|
||||
"CREATE INDEX IF NOT EXISTS idx_playlistid ON playlistitems(playlistid, filepath);"
|
||||
|
||||
#define I_GRP_TYPE_PERSIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_grp_type_persist ON groups(type, persistentid);"
|
||||
|
||||
#define I_PAIRING \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pairingguid ON pairings(guid);"
|
||||
|
||||
#define I_TITLESORT \
|
||||
"CREATE INDEX IF NOT EXISTS idx_titlesort ON files(title_sort);"
|
||||
|
||||
#define I_ARTISTSORT \
|
||||
"CREATE INDEX IF NOT EXISTS idx_artistsort ON files(artist_sort);"
|
||||
|
||||
#define I_ALBUMSORT \
|
||||
"CREATE INDEX IF NOT EXISTS idx_albumsort ON files(album_sort);"
|
||||
|
||||
#define TRG_GROUPS_INSERT_FILES \
|
||||
"CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW" \
|
||||
@ -3877,15 +4027,15 @@ db_perthread_deinit(void)
|
||||
|
||||
#define Q_PL2 \
|
||||
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
|
||||
" VALUES(2, 'Music', 1, 'media_kind = 1', 0, '', 0, 6);"
|
||||
" VALUES(2, 'Music', 1, 'f.media_kind = 1', 0, '', 0, 6);"
|
||||
|
||||
#define Q_PL3 \
|
||||
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
|
||||
" VALUES(3, 'Movies', 1, 'media_kind = 2', 0, '', 0, 4);"
|
||||
" VALUES(3, 'Movies', 1, 'f.media_kind = 2', 0, '', 0, 4);"
|
||||
|
||||
#define Q_PL4 \
|
||||
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
|
||||
" VALUES(4, 'TV Shows', 1, 'media_kind = 64', 0, '', 0, 5);"
|
||||
" VALUES(4, 'TV Shows', 1, 'f.media_kind = 64', 0, '', 0, 5);"
|
||||
|
||||
/* These are the remaining automatically-created iTunes playlists, but
|
||||
* their query is unknown
|
||||
@ -3895,9 +4045,9 @@ db_perthread_deinit(void)
|
||||
" VALUES(8, 'Purchased', 0, 'media_kind = 1024', 0, '', 0, 8);"
|
||||
*/
|
||||
|
||||
#define SCHEMA_VERSION 12
|
||||
#define SCHEMA_VERSION 13
|
||||
#define Q_SCVER \
|
||||
"INSERT INTO admin (key, value) VALUES ('schema_version', '12');"
|
||||
"INSERT INTO admin (key, value) VALUES ('schema_version', '13');"
|
||||
|
||||
struct db_init_query {
|
||||
char *query;
|
||||
@ -3915,13 +4065,25 @@ static const struct db_init_query db_init_queries[] =
|
||||
{ T_SPEAKERS, "create table speakers" },
|
||||
{ T_INOTIFY, "create table inotify" },
|
||||
|
||||
{ I_PATH, "create file path index" },
|
||||
{ I_RESCAN, "create rescan index" },
|
||||
{ I_SONGALBUMID, "create songalbumid index" },
|
||||
{ I_STATEMKINDSAI, "create state/mkind/sai index" },
|
||||
|
||||
{ I_ARTIST, "create artist index" },
|
||||
{ I_ALBUMARTIST, "create album_artist index" },
|
||||
{ I_COMPOSER, "create composer index" },
|
||||
{ I_TITLE, "create title index" },
|
||||
{ I_ALBUM, "create album index" },
|
||||
|
||||
{ I_PL_PATH, "create playlist path index" },
|
||||
{ I_PL_DISABLED, "create playlist state index" },
|
||||
|
||||
{ I_FILEPATH, "create file path index" },
|
||||
{ I_PLITEMID, "create playlist id index" },
|
||||
|
||||
{ I_GRP_TYPE_PERSIST, "create groups type/persistentid index" },
|
||||
|
||||
{ I_PAIRING, "create pairing guid index" },
|
||||
{ I_TITLESORT, "create file titlesort index" },
|
||||
{ I_ARTISTSORT,"create file artistsort index" },
|
||||
{ I_ALBUMSORT, "create file albumsort index" },
|
||||
|
||||
{ TRG_GROUPS_INSERT_FILES, "create trigger update_groups_new_file" },
|
||||
{ TRG_GROUPS_UPDATE_FILES, "create trigger update_groups_update_file" },
|
||||
@ -4461,6 +4623,92 @@ db_upgrade_v12(void)
|
||||
#undef Q_DUMP
|
||||
}
|
||||
|
||||
/* Upgrade from schema v12 to v13 */
|
||||
|
||||
#define U_V13_DROP_IDX_PATH \
|
||||
"DROP INDEX idx_path;"
|
||||
|
||||
#define U_V13_DROP_IDX_TS \
|
||||
"DROP INDEX idx_titlesort;"
|
||||
|
||||
#define U_V13_DROP_IDX_AS \
|
||||
"DROP INDEX idx_artistsort;"
|
||||
|
||||
#define U_V13_DROP_IDX_BS \
|
||||
"DROP INDEX idx_albumsort;"
|
||||
|
||||
#define U_V13_IDX_RESCAN \
|
||||
"CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp);"
|
||||
|
||||
#define U_V13_IDX_SONGALBUMID \
|
||||
"CREATE INDEX IF NOT EXISTS idx_sai ON files(songalbumid);"
|
||||
|
||||
#define U_V13_IDX_STATEMKINDSAI \
|
||||
"CREATE INDEX IF NOT EXISTS idx_state_mkind_sai ON files(disabled, media_kind, songalbumid);"
|
||||
|
||||
#define U_V13_IDX_ARTIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_artist ON files(artist, artist_sort);"
|
||||
|
||||
#define U_V13_IDX_ALBUMARTIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_albumartist ON files(album_artist, album_artist_sort);"
|
||||
|
||||
#define U_V13_IDX_COMPOSER \
|
||||
"CREATE INDEX IF NOT EXISTS idx_composer ON files(composer, composer_sort);"
|
||||
|
||||
#define U_V13_IDX_TITLE \
|
||||
"CREATE INDEX IF NOT EXISTS idx_title ON files(title, title_sort);"
|
||||
|
||||
#define U_V13_IDX_ALBUM \
|
||||
"CREATE INDEX IF NOT EXISTS idx_album ON files(album, album_sort);"
|
||||
|
||||
#define U_V13_IDX_GRP_TYPE_PERSIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_grp_type_persist ON groups(type, persistentid);"
|
||||
|
||||
#define U_V13_IDX_PL_PATH \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_path ON playlists(path);"
|
||||
|
||||
#define U_V13_IDX_PL_DISABLED \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled);"
|
||||
|
||||
#define U_V13_PL2 \
|
||||
"UPDATE playlists SET query = 'f.media_kind = 1' where id = 2;"
|
||||
|
||||
#define U_V13_PL3 \
|
||||
"UPDATE playlists SET query = 'f.media_kind = 2' where id = 3;"
|
||||
|
||||
#define U_V13_PL4 \
|
||||
"UPDATE playlists SET query = 'f.media_kind = 64' where id = 4;"
|
||||
|
||||
#define U_V13_SCVER \
|
||||
"UPDATE admin SET value = '13' WHERE key = 'schema_version';"
|
||||
|
||||
static const struct db_init_query db_upgrade_v13_queries[] =
|
||||
{
|
||||
{ U_V13_DROP_IDX_PATH, "drop index path table files" },
|
||||
{ U_V13_DROP_IDX_TS, "drop index titlesort table files" },
|
||||
{ U_V13_DROP_IDX_AS, "drop index artistsort table files" },
|
||||
{ U_V13_DROP_IDX_BS, "drop index albumsort table files" },
|
||||
|
||||
{ U_V13_IDX_RESCAN, "create rescan index" },
|
||||
{ U_V13_IDX_SONGALBUMID, "create songalbumid index" },
|
||||
{ U_V13_IDX_STATEMKINDSAI, "create state/mkind/sai index" },
|
||||
{ U_V13_IDX_ARTIST, "create artist index" },
|
||||
{ U_V13_IDX_ALBUMARTIST, "create album_artist index" },
|
||||
{ U_V13_IDX_COMPOSER, "create composer index" },
|
||||
{ U_V13_IDX_TITLE, "create title index" },
|
||||
{ U_V13_IDX_ALBUM, "create album index" },
|
||||
|
||||
{ U_V13_IDX_GRP_TYPE_PERSIST, "create groups type/persistentid index" },
|
||||
|
||||
{ U_V13_IDX_PL_PATH, "create playlist path index" },
|
||||
{ U_V13_IDX_PL_DISABLED, "create playlist state index" },
|
||||
|
||||
{ U_V13_PL2, "update default smart playlist 'Music'" },
|
||||
{ U_V13_PL3, "update default smart playlist 'Movies'" },
|
||||
{ U_V13_PL4, "update default smart playlist 'TV Shows'" },
|
||||
|
||||
{ U_V13_SCVER, "set schema_version to 13" },
|
||||
};
|
||||
|
||||
static int
|
||||
db_check_version(void)
|
||||
@ -4526,6 +4774,13 @@ db_check_version(void)
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 12:
|
||||
ret = db_generic_upgrade(db_upgrade_v13_queries, sizeof(db_upgrade_v13_queries) / sizeof(db_upgrade_v13_queries[0]));
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -4613,6 +4868,8 @@ db_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
db_analyze();
|
||||
|
||||
files = db_files_get_count();
|
||||
pls = db_pl_get_count();
|
||||
|
||||
|
10
src/db.h
10
src/db.h
@ -286,6 +286,10 @@ unicode_fixup_mfi(struct media_file_info *mfi);
|
||||
void
|
||||
free_pli(struct playlist_info *pli, int content_only);
|
||||
|
||||
/* Maintenance and DB hygiene */
|
||||
void
|
||||
db_hook_post_scan(void);
|
||||
|
||||
void
|
||||
db_purge_cruft(time_t ref);
|
||||
|
||||
@ -322,7 +326,7 @@ void
|
||||
db_file_inc_playcount(int id);
|
||||
|
||||
void
|
||||
db_file_ping(char *path);
|
||||
db_file_ping(int id);
|
||||
|
||||
char *
|
||||
db_file_path_byid(int id);
|
||||
@ -339,8 +343,8 @@ db_file_id_byfile(char *filename);
|
||||
int
|
||||
db_file_id_byurl(char *url);
|
||||
|
||||
time_t
|
||||
db_file_stamp_bypath(char *path);
|
||||
void
|
||||
db_file_stamp_bypath(char *path, time_t *stamp, int *id);
|
||||
|
||||
struct media_file_info *
|
||||
db_file_fetch_byid(int id);
|
||||
|
@ -301,13 +301,14 @@ process_media_file(char *file, time_t mtime, off_t size, int compilation)
|
||||
char *filename;
|
||||
char *ext;
|
||||
time_t stamp;
|
||||
int id;
|
||||
int ret;
|
||||
|
||||
stamp = db_file_stamp_bypath(file);
|
||||
db_file_stamp_bypath(file, &stamp, &id);
|
||||
|
||||
if (stamp >= mtime)
|
||||
{
|
||||
db_file_ping(file);
|
||||
db_file_ping(id);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -811,6 +812,8 @@ filescanner(void *arg)
|
||||
|
||||
bulk_scan();
|
||||
|
||||
db_hook_post_scan();
|
||||
|
||||
if (!scan_exit)
|
||||
{
|
||||
/* Enable inotify */
|
||||
|
@ -203,9 +203,17 @@ static const struct metadata_map md_map_id3[] =
|
||||
|
||||
|
||||
static int
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 5)
|
||||
extract_metadata_core(struct media_file_info *mfi, AVDictionary *md, const struct metadata_map *md_map)
|
||||
#else
|
||||
extract_metadata_core(struct media_file_info *mfi, AVMetadata *md, const struct metadata_map *md_map)
|
||||
#endif
|
||||
{
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 5)
|
||||
AVDictionaryEntry *mdt;
|
||||
#else
|
||||
AVMetadataTag *mdt;
|
||||
#endif
|
||||
char **strval;
|
||||
uint32_t *intval;
|
||||
int mdcount;
|
||||
@ -215,7 +223,11 @@ extract_metadata_core(struct media_file_info *mfi, AVMetadata *md, const struct
|
||||
#if 0
|
||||
/* Dump all the metadata reported by ffmpeg */
|
||||
mdt = NULL;
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 5)
|
||||
while ((mdt = av_dict_get(md, "", mdt, AV_DICT_IGNORE_SUFFIX)) != NULL)
|
||||
#else
|
||||
while ((mdt = av_metadata_get(md, "", mdt, AV_METADATA_IGNORE_SUFFIX)) != NULL)
|
||||
#endif
|
||||
fprintf(stderr, " -> %s = %s\n", mdt->key, mdt->value);
|
||||
#endif
|
||||
|
||||
@ -224,7 +236,11 @@ extract_metadata_core(struct media_file_info *mfi, AVMetadata *md, const struct
|
||||
/* Extract actual metadata */
|
||||
for (i = 0; md_map[i].key != NULL; i++)
|
||||
{
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 5)
|
||||
mdt = av_dict_get(md, md_map[i].key, NULL, 0);
|
||||
#else
|
||||
mdt = av_metadata_get(md, md_map[i].key, NULL, 0);
|
||||
#endif
|
||||
if (mdt == NULL)
|
||||
continue;
|
||||
|
||||
@ -311,7 +327,13 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ctx = NULL;
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3)
|
||||
ret = avformat_open_input(&ctx, file, NULL, NULL);
|
||||
#else
|
||||
ret = av_open_input_file(&ctx, file, NULL, 0, NULL);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINTF(E_WARN, L_SCAN, "Cannot open media file '%s': %s\n", file, strerror(AVUNERROR(ret)));
|
||||
@ -330,7 +352,11 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||
|
||||
#if 0
|
||||
/* Dump input format as determined by ffmpeg */
|
||||
# if LIBAVFORMAT_VERSION_MAJOR >= 52 || (LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 101)
|
||||
av_dump_format(ctx, 0, file, 0);
|
||||
# else
|
||||
dump_format(ctx, 0, file, FALSE);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
DPRINTF(E_DBG, L_SCAN, "File has %d streams\n", ctx->nb_streams);
|
||||
@ -404,7 +430,9 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi)
|
||||
mfi->samplerate = audio_stream->codec->sample_rate;
|
||||
|
||||
/* Try sample format first */
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 53
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4)
|
||||
mfi->bits_per_sample = 8 * av_get_bytes_per_sample(audio_stream->codec->sample_fmt);
|
||||
#elif LIBAVCODEC_VERSION_MAJOR >= 53
|
||||
mfi->bits_per_sample = av_get_bits_per_sample_fmt(audio_stream->codec->sample_fmt);
|
||||
#else
|
||||
mfi->bits_per_sample = av_get_bits_per_sample_format(audio_stream->codec->sample_fmt);
|
||||
|
113
src/httpd_daap.c
113
src/httpd_daap.c
@ -59,6 +59,8 @@ extern struct event_base *evbase_httpd;
|
||||
|
||||
/* Session timeout in seconds */
|
||||
#define DAAP_SESSION_TIMEOUT 1800
|
||||
/* Update requests refresh interval in seconds */
|
||||
#define DAAP_UPDATE_REFRESH 300
|
||||
|
||||
|
||||
struct uri_map {
|
||||
@ -76,6 +78,9 @@ struct daap_session {
|
||||
struct daap_update_request {
|
||||
struct evhttp_request *req;
|
||||
|
||||
/* Refresh tiemout */
|
||||
struct event timeout;
|
||||
|
||||
struct daap_update_request *next;
|
||||
};
|
||||
|
||||
@ -98,6 +103,7 @@ static avl_tree_t *daap_sessions;
|
||||
static int next_session_id;
|
||||
|
||||
/* Update requests */
|
||||
static int current_rev;
|
||||
static struct daap_update_request *update_requests;
|
||||
|
||||
|
||||
@ -149,14 +155,10 @@ daap_session_timeout_cb(int fd, short what, void *arg)
|
||||
static struct daap_session *
|
||||
daap_session_register(void)
|
||||
{
|
||||
#if 0
|
||||
struct timeval tv;
|
||||
#endif
|
||||
struct daap_session *s;
|
||||
avl_node_t *node;
|
||||
#if 0
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
s = (struct daap_session *)malloc(sizeof(struct daap_session));
|
||||
if (!s)
|
||||
@ -183,14 +185,12 @@ daap_session_register(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_SESSION_TIMEOUT;
|
||||
|
||||
ret = evtimer_add(&s->timeout, &tv);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add session timeout event for session %d\n", s->id);
|
||||
#endif /* 0 */
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -199,9 +199,7 @@ struct daap_session *
|
||||
daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct evbuffer *evbuf)
|
||||
{
|
||||
struct daap_session needle;
|
||||
#if 0
|
||||
struct timeval tv;
|
||||
#endif
|
||||
struct daap_session *s;
|
||||
avl_node_t *node;
|
||||
const char *param;
|
||||
@ -227,7 +225,6 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev
|
||||
|
||||
s = (struct daap_session *)node->item;
|
||||
|
||||
#if 0
|
||||
event_del(&s->timeout);
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
@ -236,7 +233,6 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev
|
||||
ret = evtimer_add(&s->timeout, &tv);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add session timeout event for session %d\n", s->id);
|
||||
#endif /* 0 */
|
||||
|
||||
return s;
|
||||
|
||||
@ -248,18 +244,10 @@ daap_session_find(struct evhttp_request *req, struct evkeyvalq *query, struct ev
|
||||
|
||||
/* Update requests helpers */
|
||||
static void
|
||||
update_fail_cb(struct evhttp_connection *evcon, void *arg)
|
||||
update_remove(struct daap_update_request *ur)
|
||||
{
|
||||
struct daap_update_request *ur;
|
||||
struct daap_update_request *p;
|
||||
|
||||
ur = (struct daap_update_request *)arg;
|
||||
|
||||
DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n");
|
||||
|
||||
if (ur->req->evcon)
|
||||
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
|
||||
|
||||
if (ur == update_requests)
|
||||
update_requests = ur->next;
|
||||
else
|
||||
@ -275,10 +263,70 @@ update_fail_cb(struct evhttp_connection *evcon, void *arg)
|
||||
|
||||
p->next = ur->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_free(struct daap_update_request *ur)
|
||||
{
|
||||
if (event_initialized(&ur->timeout))
|
||||
evtimer_del(&ur->timeout);
|
||||
free(ur);
|
||||
}
|
||||
|
||||
static void
|
||||
update_refresh_cb(int fd, short event, void *arg)
|
||||
{
|
||||
struct daap_update_request *ur;
|
||||
struct evbuffer *evbuf;
|
||||
int ret;
|
||||
|
||||
ur = (struct daap_update_request *)arg;
|
||||
|
||||
evbuf = evbuffer_new();
|
||||
if (!evbuf)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not allocate evbuffer for DAAP update data\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ret = evbuffer_expand(evbuf, 32);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not expand evbuffer for DAAP update data\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send back current revision */
|
||||
dmap_add_container(evbuf, "mupd", 24);
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12 */
|
||||
dmap_add_int(evbuf, "musr", current_rev); /* 12 */
|
||||
|
||||
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
|
||||
|
||||
httpd_send_reply(ur->req, HTTP_OK, "OK", evbuf);
|
||||
|
||||
update_remove(ur);
|
||||
update_free(ur);
|
||||
}
|
||||
|
||||
static void
|
||||
update_fail_cb(struct evhttp_connection *evcon, void *arg)
|
||||
{
|
||||
struct daap_update_request *ur;
|
||||
|
||||
ur = (struct daap_update_request *)arg;
|
||||
|
||||
DPRINTF(E_DBG, L_DAAP, "Update request: client closed connection\n");
|
||||
|
||||
if (ur->req->evcon)
|
||||
evhttp_connection_set_closecb(ur->req->evcon, NULL, NULL);
|
||||
|
||||
update_remove(ur);
|
||||
update_free(ur);
|
||||
}
|
||||
|
||||
|
||||
/* DAAP sort headers helpers */
|
||||
static struct sort_ctx *
|
||||
@ -598,7 +646,7 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
passwd = cfg_getstr(lib, "password");
|
||||
name = cfg_getstr(lib, "name");
|
||||
|
||||
len = 136 + strlen(name);
|
||||
len = 157 + strlen(name);
|
||||
|
||||
ret = evbuffer_expand(evbuf, len);
|
||||
if (ret < 0)
|
||||
@ -633,10 +681,8 @@ daap_reply_server_info(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
dmap_add_int(evbuf, "apro", apro); /* 12 */
|
||||
dmap_add_string(evbuf, "minm", name); /* 8 + strlen(name) */
|
||||
|
||||
#if 0
|
||||
dmap_add_int(evbuf, "mstm", DAAP_SESSION_TIMEOUT); /* 12 */
|
||||
dmap_add_char(evbuf, "msal", 1); /* 9 */
|
||||
#endif
|
||||
|
||||
dmap_add_char(evbuf, "mslr", 1); /* 9 */
|
||||
dmap_add_char(evbuf, "msau", (passwd) ? 2 : 0); /* 9 */
|
||||
@ -780,10 +826,10 @@ daap_reply_logout(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
|
||||
static void
|
||||
daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct daap_session *s;
|
||||
struct daap_update_request *ur;
|
||||
const char *param;
|
||||
int current_rev = 2;
|
||||
int reqd_rev;
|
||||
int ret;
|
||||
|
||||
@ -839,6 +885,24 @@ daap_reply_update(struct evhttp_request *req, struct evbuffer *evbuf, char **uri
|
||||
dmap_send_error(req, "mupd", "Out of memory");
|
||||
return;
|
||||
}
|
||||
memset(ur, 0, sizeof(struct daap_update_request));
|
||||
|
||||
evtimer_set(&ur->timeout, update_refresh_cb, ur);
|
||||
event_base_set(evbase_httpd, &ur->timeout);
|
||||
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = DAAP_UPDATE_REFRESH;
|
||||
|
||||
ret = evtimer_add(&ur->timeout, &tv);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DAAP, "Could not add update timeout event\n");
|
||||
|
||||
dmap_send_error(req, "mupd", "Could not register timer");
|
||||
|
||||
update_free(ur);
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: we may need to keep reqd_rev in there too */
|
||||
ur->req = req;
|
||||
@ -2428,6 +2492,7 @@ daap_init(void)
|
||||
int ret;
|
||||
|
||||
next_session_id = 100; /* gotta start somewhere, right? */
|
||||
current_rev = 2;
|
||||
update_requests = NULL;
|
||||
|
||||
for (i = 0; daap_handlers[i].handler; i++)
|
||||
@ -2480,6 +2545,6 @@ daap_deinit(void)
|
||||
evhttp_connection_free(ur->req->evcon);
|
||||
}
|
||||
|
||||
free(ur);
|
||||
update_free(ur);
|
||||
}
|
||||
}
|
||||
|
@ -1260,16 +1260,15 @@ dacp_reply_getproperty(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
while (prop)
|
||||
{
|
||||
dpm = dacp_find_prop(prop, strlen(prop));
|
||||
if (!dpm)
|
||||
if (dpm)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not find requested property '%s'\n", prop);
|
||||
continue;
|
||||
if (dpm->propget)
|
||||
dpm->propget(proplist, &status, mfi);
|
||||
else
|
||||
DPRINTF(E_WARN, L_DACP, "No getter method for DACP property %s\n", prop);
|
||||
}
|
||||
|
||||
if (dpm->propget)
|
||||
dpm->propget(proplist, &status, mfi);
|
||||
else
|
||||
DPRINTF(E_WARN, L_DACP, "No getter method for DACP property %s\n", prop);
|
||||
DPRINTF(E_LOG, L_DACP, "Could not find requested property '%s'\n", prop);
|
||||
|
||||
prop = strtok_r(NULL, ",", &ptr);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ static int threshold;
|
||||
static int console;
|
||||
static char *logfilename;
|
||||
static FILE *logfile;
|
||||
static char *labels[] = { "config", "daap", "db", "httpd", "main", "mdns", "misc", "rsp", "scan", "xcode", "event", "remote", "dacp", "ffmpeg", "artwork", "player", "raop", "laudio", "dmap" };
|
||||
static char *labels[] = { "config", "daap", "db", "httpd", "main", "mdns", "misc", "rsp", "scan", "xcode", "event", "remote", "dacp", "ffmpeg", "artwork", "player", "raop", "laudio", "dmap", "dbperf" };
|
||||
|
||||
|
||||
static int
|
||||
|
@ -25,8 +25,9 @@
|
||||
#define L_RAOP 16
|
||||
#define L_LAUDIO 17
|
||||
#define L_DMAP 18
|
||||
#define L_DBPERF 19
|
||||
|
||||
#define N_LOGDOMAINS 19
|
||||
#define N_LOGDOMAINS 20
|
||||
|
||||
/* Severities */
|
||||
#define E_FATAL 0
|
||||
|
@ -354,7 +354,11 @@ transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
|
||||
}
|
||||
memset(ctx, 0, sizeof(struct transcode_ctx));
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 3)
|
||||
ret = avformat_open_input(&ctx->fmtctx, mfi->path, NULL, NULL);
|
||||
#else
|
||||
ret = av_open_input_file(&ctx->fmtctx, mfi->path, NULL, 0, NULL);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINTF(E_WARN, L_XCODE, "Could not open file %s: %s\n", mfi->fname, strerror(AVUNERROR(ret)));
|
||||
@ -450,7 +454,9 @@ transcode_setup(struct media_file_info *mfi, off_t *est_size, int wavhdr)
|
||||
}
|
||||
|
||||
ctx->need_resample = 1;
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 53
|
||||
#if LIBAVUTIL_VERSION_MAJOR >= 51 || (LIBAVUTIL_VERSION_MAJOR == 51 && LIBAVUTIL_VERSION_MINOR >= 4)
|
||||
ctx->input_size = ctx->acodec->channels * av_get_bytes_per_sample(ctx->acodec->sample_fmt);
|
||||
#elif LIBAVCODEC_VERSION_MAJOR >= 53
|
||||
ctx->input_size = ctx->acodec->channels * av_get_bits_per_sample_fmt(ctx->acodec->sample_fmt) / 8;
|
||||
#else
|
||||
ctx->input_size = ctx->acodec->channels * av_get_bits_per_sample_format(ctx->acodec->sample_fmt) / 8;
|
||||
|
Loading…
Reference in New Issue
Block a user