[db/filescanner] Add index on fname, change playlist matching (wip)
This commit is contained in:
parent
45bd2d6cc8
commit
4d47307a02
20
src/db.c
20
src/db.c
|
@ -684,9 +684,10 @@ db_purge_cruft(time_t ref)
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
char *query;
|
char *query;
|
||||||
char *queries_tmpl[3] =
|
char *queries_tmpl[4] =
|
||||||
{
|
{
|
||||||
"DELETE FROM playlistitems WHERE playlistid IN (SELECT id FROM playlists p WHERE p.type <> %d AND p.db_timestamp < %" PRIi64 ");",
|
"DELETE FROM playlistitems WHERE playlistid IN (SELECT p.id FROM playlists p WHERE p.type <> %d AND p.db_timestamp < %" PRIi64 ");",
|
||||||
|
"DELETE FROM playlistitems WHERE filepath IN (SELECT f.path FROM files f WHERE -1 <> %d AND f.db_timestamp < %" PRIi64 ");",
|
||||||
"DELETE FROM playlists WHERE type <> %d AND db_timestamp < %" PRIi64 ";",
|
"DELETE FROM playlists WHERE type <> %d AND db_timestamp < %" PRIi64 ";",
|
||||||
"DELETE FROM files WHERE -1 <> %d AND db_timestamp < %" PRIi64 ";",
|
"DELETE FROM files WHERE -1 <> %d AND db_timestamp < %" PRIi64 ";",
|
||||||
};
|
};
|
||||||
|
@ -2959,6 +2960,21 @@ db_pl_add(struct playlist_info *pli, int *id)
|
||||||
#undef QADD_TMPL
|
#undef QADD_TMPL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
db_pl_add_item_byfile(int plid, const char *filename)
|
||||||
|
{
|
||||||
|
#define Q_TMPL "INSERT INTO playlistitems (playlistid, filepath) SELECT %d, path FROM files WHERE fname='%q' GROUP BY fname HAVING COUNT(*)=1;"
|
||||||
|
char *query;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
query = sqlite3_mprintf(Q_TMPL, plid, filename);
|
||||||
|
|
||||||
|
ret = db_query_run(query, 1, 0);
|
||||||
|
|
||||||
|
return ((ret < 0) ? -1 : sqlite3_changes(hdl));
|
||||||
|
#undef Q_TMPL
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
db_pl_add_item_bypath(int plid, const char *path)
|
db_pl_add_item_bypath(int plid, const char *path)
|
||||||
{
|
{
|
||||||
|
|
3
src/db.h
3
src/db.h
|
@ -593,6 +593,9 @@ db_pl_fetch_bytitlepath(const char *title, const char *path);
|
||||||
int
|
int
|
||||||
db_pl_add(struct playlist_info *pli, int *id);
|
db_pl_add(struct playlist_info *pli, int *id);
|
||||||
|
|
||||||
|
int
|
||||||
|
db_pl_add_item_byfile(int plid, const char *filename);
|
||||||
|
|
||||||
int
|
int
|
||||||
db_pl_add_item_bypath(int plid, const char *path);
|
db_pl_add_item_bypath(int plid, const char *path);
|
||||||
|
|
||||||
|
|
|
@ -293,6 +293,9 @@ static const struct db_init_query db_init_table_queries[] =
|
||||||
#define I_RESCAN \
|
#define I_RESCAN \
|
||||||
"CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp);"
|
"CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp);"
|
||||||
|
|
||||||
|
#define I_FNAME \
|
||||||
|
"CREATE INDEX IF NOT EXISTS idx_fname ON files(disabled, fname);"
|
||||||
|
|
||||||
#define I_SONGARTISTID \
|
#define I_SONGARTISTID \
|
||||||
"CREATE INDEX IF NOT EXISTS idx_sari ON files(songartistid);"
|
"CREATE INDEX IF NOT EXISTS idx_sari ON files(songartistid);"
|
||||||
|
|
||||||
|
@ -370,6 +373,7 @@ static const struct db_init_query db_init_table_queries[] =
|
||||||
static const struct db_init_query db_init_index_queries[] =
|
static const struct db_init_query db_init_index_queries[] =
|
||||||
{
|
{
|
||||||
{ I_RESCAN, "create rescan index" },
|
{ I_RESCAN, "create rescan index" },
|
||||||
|
{ I_FNAME, "create filename index" },
|
||||||
{ I_SONGARTISTID, "create songartistid index" },
|
{ I_SONGARTISTID, "create songartistid index" },
|
||||||
{ I_SONGALBUMID, "create songalbumid index" },
|
{ I_SONGALBUMID, "create songalbumid index" },
|
||||||
{ I_STATEMKINDSARI, "create state/mkind/sari index" },
|
{ I_STATEMKINDSARI, "create state/mkind/sari index" },
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* 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 19
|
||||||
#define SCHEMA_VERSION_MINOR 04
|
#define SCHEMA_VERSION_MINOR 05
|
||||||
|
|
||||||
int
|
int
|
||||||
db_init_indices(sqlite3 *hdl);
|
db_init_indices(sqlite3 *hdl);
|
||||||
|
|
|
@ -1564,6 +1564,16 @@ static const struct db_upgrade_query db_upgrade_v1904_queries[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define U_V1905_SCVER_MINOR \
|
||||||
|
"UPDATE admin SET value = '05' WHERE key = 'schema_version_minor';"
|
||||||
|
|
||||||
|
// Purpose of this upgrade is to reset the indeces, so that I_FNAME gets added
|
||||||
|
static const struct db_upgrade_query db_upgrade_v1905_queries[] =
|
||||||
|
{
|
||||||
|
{ U_V1905_SCVER_MINOR, "set schema_version_minor to 05" },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
db_upgrade(sqlite3 *hdl, int db_ver)
|
db_upgrade(sqlite3 *hdl, int db_ver)
|
||||||
{
|
{
|
||||||
|
@ -1702,6 +1712,13 @@ db_upgrade(sqlite3 *hdl, int db_ver)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
|
case 1904:
|
||||||
|
ret = db_generic_upgrade(hdl, db_upgrade_v1905_queries, sizeof(db_upgrade_v1905_queries) / sizeof(db_upgrade_v1905_queries[0]));
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -73,13 +73,32 @@ extinf_get(char *string, struct media_file_info *mfi, int *extinf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
process_url(const char *path, time_t mtime, int extinf, struct media_file_info *mfi, char **filename)
|
parent_dir(const char **current, const char *path)
|
||||||
|
{
|
||||||
|
const char *ptr;
|
||||||
|
|
||||||
|
if (*current)
|
||||||
|
ptr = *current;
|
||||||
|
else
|
||||||
|
ptr = strrchr(path, '/');
|
||||||
|
|
||||||
|
if (!ptr || (ptr == path))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (ptr--; (ptr > path) && (*ptr != '/'); ptr--)
|
||||||
|
;
|
||||||
|
|
||||||
|
*current = ptr;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_url(int pl_id, const char *path, time_t mtime, int extinf, struct media_file_info *mfi)
|
||||||
{
|
{
|
||||||
char virtual_path[PATH_MAX];
|
char virtual_path[PATH_MAX];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
*filename = strdup(path);
|
|
||||||
|
|
||||||
if (extinf)
|
if (extinf)
|
||||||
DPRINTF(E_INFO, L_SCAN, "Playlist has EXTINF metadata, artist is '%s', title is '%s'\n", mfi->artist, mfi->title);
|
DPRINTF(E_INFO, L_SCAN, "Playlist has EXTINF metadata, artist is '%s', title is '%s'\n", mfi->artist, mfi->title);
|
||||||
|
|
||||||
|
@ -107,67 +126,99 @@ process_url(const char *path, time_t mtime, int extinf, struct media_file_info *
|
||||||
|
|
||||||
library_add_media(mfi);
|
library_add_media(mfi);
|
||||||
|
|
||||||
return 0;
|
return db_pl_add_item_bypath(pl_id, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
process_regular_file(char **filename, char *path)
|
process_regular_file(int pl_id, char *path)
|
||||||
{
|
{
|
||||||
|
struct query_params qp;
|
||||||
|
char filter[PATH_MAX];
|
||||||
|
const char *a;
|
||||||
|
const char *b;
|
||||||
|
char *dbpath;
|
||||||
|
char *winner;
|
||||||
|
int score;
|
||||||
int i;
|
int i;
|
||||||
int mfi_id;
|
|
||||||
char *ptr;
|
|
||||||
char *entry;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Playlist might be from Windows so we change backslash to forward slash */
|
// Playlist might be from Windows so we change backslash to forward slash
|
||||||
for (i = 0; i < strlen(path); i++)
|
for (i = 0; i < strlen(path); i++)
|
||||||
{
|
{
|
||||||
if (path[i] == '\\')
|
if (path[i] == '\\')
|
||||||
path[i] = '/';
|
path[i] = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now search for the library item where the path has closest match to playlist item */
|
ret = snprintf(filter, sizeof(filter), "(f.fname = '%s')", filename_from_path(path)); // TODO make case insensitive?
|
||||||
/* Succes is when we find an unambiguous match, or when we no longer can expand the */
|
if (ret < 0 || ret >= sizeof(filter))
|
||||||
/* the path to refine our search. */
|
|
||||||
entry = NULL;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
ptr = strrchr(path, '/');
|
DPRINTF(E_LOG, L_SCAN, "Playlist contains bad filename: '%s'\n", path);
|
||||||
if (entry)
|
|
||||||
*(entry - 1) = '/';
|
|
||||||
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
*ptr = '\0';
|
|
||||||
entry = ptr + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
entry = path;
|
|
||||||
|
|
||||||
DPRINTF(E_SPAM, L_SCAN, "Playlist entry is now %s\n", entry);
|
|
||||||
ret = db_files_get_count_bymatch(entry);
|
|
||||||
}
|
|
||||||
while (ptr && (ret > 1));
|
|
||||||
|
|
||||||
if (ret > 0)
|
|
||||||
{
|
|
||||||
mfi_id = db_file_id_bymatch(entry);
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_SCAN, "Found playlist entry match, id is %d, entry is %s\n", mfi_id, entry);
|
|
||||||
|
|
||||||
*filename = db_file_path_byid(mfi_id);
|
|
||||||
if (!(*filename))
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_SCAN, "Playlist entry %s matches file id %d, but file path is missing.\n", entry, mfi_id);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
// Fast path - only works if there are not multiple items in the lib with the
|
||||||
|
// same filename
|
||||||
|
/* ret = db_pl_add_item_byfile(pl_id, filename_from_path(path));
|
||||||
|
if (ret == 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_SCAN, "Fast path adding '%s' to playlist did not work (ret=%d), now searching\n", path, ret);
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(&qp, 0, sizeof(struct query_params));
|
||||||
|
|
||||||
|
qp.type = Q_BROWSE_PATH;
|
||||||
|
qp.sort = S_NONE;
|
||||||
|
qp.filter = filter;
|
||||||
|
|
||||||
|
ret = db_query_start(&qp);
|
||||||
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
DPRINTF(E_DBG, L_SCAN, "No match for playlist entry %s\n", entry);
|
db_query_end(&qp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
winner = NULL;
|
||||||
|
score = 0;
|
||||||
|
while (((ret = db_query_fetch_string(&qp, &dbpath)) == 0) && (dbpath))
|
||||||
|
{
|
||||||
|
if (qp.results == 1)
|
||||||
|
{
|
||||||
|
DPRINTF(E_DBG, L_SCAN, "Adding '%s' to playlist %d (fast path)\n", dbpath, pl_id);
|
||||||
|
|
||||||
|
winner = strdup(dbpath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, a = NULL, b = NULL; (parent_dir(&a, path) == 0) && (parent_dir(&b, dbpath) == 0) && (strcasecmp(a, b) == 0); i++)
|
||||||
|
;
|
||||||
|
|
||||||
|
DPRINTF(E_DBG, L_SCAN, "Comparison of '%s' and '%s' gave score %d\n", dbpath, path, i);
|
||||||
|
|
||||||
|
if (i > score)
|
||||||
|
{
|
||||||
|
free(winner);
|
||||||
|
winner = strdup(dbpath);
|
||||||
|
score = ret;
|
||||||
|
}
|
||||||
|
else if (i == score)
|
||||||
|
{
|
||||||
|
free(winner);
|
||||||
|
winner = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db_query_end(&qp);
|
||||||
|
|
||||||
|
if (!winner)
|
||||||
|
{
|
||||||
|
DPRINTF(E_LOG, L_SCAN, "No file in the library matches playlist entry '%s'\n", path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
db_pl_add_item_bypath(pl_id, winner);
|
||||||
|
free(winner);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +240,6 @@ scan_playlist(char *file, time_t mtime, int dir_id)
|
||||||
int counter;
|
int counter;
|
||||||
int ret;
|
int ret;
|
||||||
char virtual_path[PATH_MAX];
|
char virtual_path[PATH_MAX];
|
||||||
char *plitem_path;
|
|
||||||
|
|
||||||
ptr = strrchr(file, '.');
|
ptr = strrchr(file, '.');
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
|
@ -309,14 +359,10 @@ scan_playlist(char *file, time_t mtime, int dir_id)
|
||||||
|
|
||||||
/* Check if line is an URL, will be added to library, otherwise it should already be there */
|
/* Check if line is an URL, will be added to library, otherwise it should already be there */
|
||||||
if (strncasecmp(path, "http://", 7) == 0)
|
if (strncasecmp(path, "http://", 7) == 0)
|
||||||
ret = process_url(path, sb.st_mtime, extinf, &mfi, &plitem_path);
|
ret = process_url(pl_id, path, sb.st_mtime, extinf, &mfi);
|
||||||
else
|
else
|
||||||
ret = process_regular_file(&plitem_path, path);
|
ret = process_regular_file(pl_id, path);
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = db_pl_add_item_bypath(pl_id, plitem_path);
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
counter++;
|
counter++;
|
||||||
|
@ -327,13 +373,10 @@ scan_playlist(char *file, time_t mtime, int dir_id)
|
||||||
db_transaction_begin();
|
db_transaction_begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
DPRINTF(E_WARN, L_SCAN, "Could not add '%s' to playlist\n", plitem_path);
|
|
||||||
|
|
||||||
/* Clean up in preparation for next item */
|
/* Clean up in preparation for next item */
|
||||||
extinf = 0;
|
extinf = 0;
|
||||||
free_mfi(&mfi, 1);
|
free_mfi(&mfi, 1);
|
||||||
free(plitem_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db_transaction_end();
|
db_transaction_end();
|
||||||
|
|
Loading…
Reference in New Issue