[filescanner] Copy playlist scan optimisations to itunes scanner

This commit is contained in:
ejurgensen 2017-10-15 15:43:48 +02:00
parent 3520ab030e
commit 322abb8274
4 changed files with 130 additions and 77 deletions

View File

@ -191,6 +191,27 @@ strip_extension(const char *path)
return result;
}
int
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
push_dir(struct stacked_dir **s, char *path, int parent_id)
{

View File

@ -5,7 +5,8 @@
#include "db.h"
/* Actual scanners */
/* --------------------------- Actual scanners ---------------------------- */
int
scan_metadata_ffmpeg(const char *file, struct media_file_info *mfi);
@ -20,10 +21,40 @@ void
scan_itunes_itml(const char *file);
#endif
/* ------------ Common utility functions used by the scanners ------------ */
/* Returns a pointer to the filename part of path.
*
* @in path the complete path
* @return pointer to filename
*/
const char *
filename_from_path(const char *path);
/* Returns path without file extension. Caller must free result.
*
* @in path the complete path
* @return modified path
*/
char *
strip_extension(const char *path);
/* Iterate up a file path.
*
* Example of three calls where path is '/foo/bar/file.mp3', and starting with
* current = NULL:
* ret = parent_dir(&current, path) -> ret = 0, current = /bar/file.mp3
* ret = parent_dir(&current, path) -> ret = 0, current = /foo/bar/file.mp3
* ret = parent_dir(&current, path) -> ret = -1, current = /foo/bar/file.mp3
*
* @in/out current if the input pointer is not a null pointer, it will be moved
* one level up, otherwise it will be set to the point at the
* file's directory
* @in path the complete path
* @return 0 if parent dir found, otherwise -1
*/
int
parent_dir(const char **current, const char *path);
#endif /* !__FILESCANNER_H__ */

View File

@ -41,6 +41,7 @@
#include "logger.h"
#include "db.h"
#include "library/filescanner.h"
#include "conffile.h"
#include "misc.h"
@ -307,73 +308,88 @@ check_meta(plist_t dict)
}
static int
find_track_file(char *location)
mfi_id_find(const 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 ret;
int plen;
int mfi_id;
char *entry;
char *ptr;
location = evhttp_decode_uri(location);
if (!location)
ret = db_snprintf(filter, sizeof(filter), "f.fname = '%q' COLLATE NOCASE", filename_from_path(path));
if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Could not decode iTunes XML playlist url.\n");
return 0;
DPRINTF(E_LOG, L_SCAN, "Location in iTunes XML is too long: '%s'\n", path);
return -1;
}
plen = strlen("file://");
memset(&qp, 0, sizeof(struct query_params));
/* Not a local file ... */
if (strncmp(location, "file://", plen) != 0)
return 0;
qp.type = Q_BROWSE_PATH;
qp.sort = S_NONE;
qp.filter = filter;
/* Now search for the library item where the path has closest match to playlist item */
/* Succes is when we find an unambiguous match, or when we no longer can expand the */
/* the path to refine our search. */
entry = NULL;
do
ret = db_query_start(&qp);
if (ret < 0)
{
ptr = strrchr(location, '/');
if (entry)
*(entry - 1) = '/';
if (ptr)
{
*ptr = '\0';
entry = ptr + 1;
}
else
entry = location;
DPRINTF(E_SPAM, L_SCAN, "iTunes XML 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 iTunes XML playlist entry match, id is %d, entry is %s\n", mfi_id, entry);
free(location);
return mfi_id;
}
else
{
DPRINTF(E_DBG, L_SCAN, "No match for iTunes XML playlist entry %s\n", entry);
free(location);
return 0;
db_query_end(&qp);
return -1;
}
winner = NULL;
score = 0;
while ((db_query_fetch_string(&qp, &dbpath) == 0) && dbpath)
{
if (qp.results == 1)
{
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_SPAM, L_SCAN, "Comparison of '%s' and '%s' gave score %d\n", dbpath, path, i);
if (i > score)
{
free(winner);
winner = strdup(dbpath);
score = i;
}
else if (i == score)
{
free(winner);
winner = NULL;
}
}
db_query_end(&qp);
if (!winner)
{
DPRINTF(E_LOG, L_SCAN, "No file matches iTunes XML entry '%s'\n", path);
return -1;
}
DPRINTF(E_DBG, L_SCAN, "Found '%s' from iTunes XML (results %d)\n", path, qp.results);
ret = db_file_id_bypath(winner);
free(winner);
return ret;
}
static int
process_track_file(plist_t trk)
{
char *location;
struct media_file_info *mfi;
char *location;
char *path;
char *string;
uint64_t integer;
char **strval;
@ -385,24 +401,30 @@ process_track_file(plist_t trk)
int ret;
ret = get_dictval_string_from_key(trk, "Location", &location);
if (ret < 0)
if ((ret < 0) || !location)
{
DPRINTF(E_WARN, L_SCAN, "Track type File with no Location\n");
return 0;
DPRINTF(E_LOG, L_SCAN, "Track type File with no Location\n");
return -1;
}
mfi_id = find_track_file(location);
if (strncmp(location, "file://", strlen("file://")) != 0)
{
DPRINTF(E_LOG, L_SCAN, "Track type File, but Location does not start with file://: '%s'\n", location);
free(location);
return -1;
}
path = evhttp_decode_uri(location + strlen("file://"));
free(location);
mfi_id = mfi_id_find(path);
if (mfi_id <= 0)
{
DPRINTF(E_INFO, L_SCAN, "Could not match location '%s' to any known file\n", location);
free(location);
return 0;
free(path);
return -1;
}
free(location);
free(path);
if (!cfg_getbool(cfg_getsec(cfg, "library"), "itunes_overrides"))
return mfi_id;

View File

@ -72,27 +72,6 @@ extinf_get(char *string, struct media_file_info *mfi, int *extinf)
return 1;
}
static int
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)
{