[filescanner] Copy playlist scan optimisations to itunes scanner
This commit is contained in:
parent
3520ab030e
commit
322abb8274
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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(¤t, path) -> ret = 0, current = /bar/file.mp3
|
||||
* ret = parent_dir(¤t, path) -> ret = 0, current = /foo/bar/file.mp3
|
||||
* ret = parent_dir(¤t, 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__ */
|
||||
|
|
|
@ -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)
|
||||
db_query_end(&qp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
winner = NULL;
|
||||
score = 0;
|
||||
while ((db_query_fetch_string(&qp, &dbpath) == 0) && dbpath)
|
||||
{
|
||||
if (qp.results == 1)
|
||||
{
|
||||
*ptr = '\0';
|
||||
entry = ptr + 1;
|
||||
winner = strdup(dbpath);
|
||||
break;
|
||||
}
|
||||
else
|
||||
entry = location;
|
||||
|
||||
DPRINTF(E_SPAM, L_SCAN, "iTunes XML playlist entry is now %s\n", entry);
|
||||
ret = db_files_get_count_bymatch(entry);
|
||||
for (i = 0, a = NULL, b = NULL; (parent_dir(&a, path) == 0) && (parent_dir(&b, dbpath) == 0) && (strcasecmp(a, b) == 0); i++)
|
||||
;
|
||||
|
||||
} while (ptr && (ret > 1));
|
||||
DPRINTF(E_SPAM, L_SCAN, "Comparison of '%s' and '%s' gave score %d\n", dbpath, path, i);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue