[scan] Don't iTunes playlist scan timestamp on failed scan

Also some refactoring.

Closes #1359
This commit is contained in:
ejurgensen 2021-12-01 20:11:54 +01:00
parent a55f2c6220
commit 1418bfb245

View File

@ -57,8 +57,6 @@ struct itml_to_db_map {
uint32_t db_id; uint32_t db_id;
struct itml_to_db_map *next; struct itml_to_db_map *next;
}; };
struct itml_to_db_map **id_map;
/* Mapping between iTunes library metadata keys and the offset /* Mapping between iTunes library metadata keys and the offset
* of the equivalent metadata field in struct media_file_info */ * of the equivalent metadata field in struct media_file_info */
@ -136,11 +134,14 @@ static struct metadata_map md_map[] =
}; };
static void static void
id_map_free(void) id_map_free(struct itml_to_db_map **id_map)
{ {
struct itml_to_db_map *map; struct itml_to_db_map *map;
int i; int i;
if (!id_map)
return;
for (i = 0; i < ID_MAP_SIZE; i++) for (i = 0; i < ID_MAP_SIZE; i++)
{ {
if (!id_map[i]) if (!id_map[i])
@ -158,7 +159,7 @@ id_map_free(void)
/* Inserts a linked list item into "hash" position in the id_table */ /* Inserts a linked list item into "hash" position in the id_table */
static int static int
id_map_add(uint64_t itml_id, uint32_t db_id) id_map_add(struct itml_to_db_map **id_map, uint64_t itml_id, uint32_t db_id)
{ {
struct itml_to_db_map *new_map; struct itml_to_db_map *new_map;
struct itml_to_db_map *cur_map; struct itml_to_db_map *cur_map;
@ -180,7 +181,7 @@ id_map_add(uint64_t itml_id, uint32_t db_id)
} }
static uint32_t static uint32_t
id_map_get(uint64_t itml_id) id_map_get(struct itml_to_db_map **id_map, uint64_t itml_id)
{ {
struct itml_to_db_map *map; struct itml_to_db_map *map;
int i; int i;
@ -580,7 +581,7 @@ process_track_stream(plist_t trk)
} }
static int static int
process_tracks(plist_t tracks) process_tracks(struct itml_to_db_map **id_map, plist_t tracks)
{ {
plist_t trk; plist_t trk;
plist_dict_iter iter; plist_dict_iter iter;
@ -679,7 +680,7 @@ process_tracks(plist_t tracks)
continue; continue;
} }
ret = id_map_add(trk_id, mfi_id); ret = id_map_add(id_map, trk_id, mfi_id);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_SCAN, "Out of memory for itml -> db mapping\n"); DPRINTF(E_LOG, L_SCAN, "Out of memory for itml -> db mapping\n");
@ -696,7 +697,7 @@ process_tracks(plist_t tracks)
} }
static void static void
process_pl_items(plist_t items, int pl_id, const char *name) process_pl_items(plist_t items, int pl_id, const char *name, struct itml_to_db_map **id_map)
{ {
plist_t trk; plist_t trk;
uint64_t itml_id; uint64_t itml_id;
@ -725,7 +726,7 @@ process_pl_items(plist_t items, int pl_id, const char *name)
continue; continue;
} }
db_id = id_map_get(itml_id); db_id = id_map_get(id_map, itml_id);
if (!db_id) if (!db_id)
{ {
DPRINTF(E_INFO, L_SCAN, "Did not find a match for track ID %" PRIu64 " in '%s'\n", itml_id, name); DPRINTF(E_INFO, L_SCAN, "Did not find a match for track ID %" PRIu64 " in '%s'\n", itml_id, name);
@ -785,7 +786,7 @@ ignore_pl(plist_t pl, const char *name)
} }
static void static void
process_pls(plist_t playlists, const char *file) process_pls(plist_t playlists, const char *file, struct itml_to_db_map **id_map)
{ {
plist_t pl; plist_t pl;
plist_t items; plist_t items;
@ -852,7 +853,7 @@ process_pls(plist_t playlists, const char *file)
DPRINTF(E_INFO, L_SCAN, "Added playlist as id %d\n", ret); DPRINTF(E_INFO, L_SCAN, "Added playlist as id %d\n", ret);
process_pl_items(items, ret, name); process_pl_items(items, ret, name, id_map);
free_pli(&pli, 1); free_pli(&pli, 1);
free(name); free(name);
@ -917,120 +918,121 @@ itml_is_modified(const char *path, time_t mtime)
} }
void void
scan_itunes_itml(const char *file, time_t mtime, int dir_id) scan_itunes_itml(const char *path, time_t mtime, int dir_id)
{ {
struct stat sb; struct stat sb;
struct itml_to_db_map **id_map = NULL;
char *itml_xml; char *itml_xml;
plist_t itml; plist_t itml = NULL;
plist_t node; plist_t node;
int fd; int fd = -1;
int ret; int ret;
if (!itml_is_modified(file, mtime)) if (!itml_is_modified(path, mtime))
{
return; return;
}
fd = open(file, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) if (fd < 0)
{ {
DPRINTF(E_LOG, L_SCAN, "Could not open iTunes library '%s': %s\n", file, strerror(errno)); DPRINTF(E_LOG, L_SCAN, "Could not open iTunes library '%s': %s\n", path, strerror(errno));
goto error;
return;
} }
ret = fstat(fd, &sb); ret = fstat(fd, &sb);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_SCAN, "Could not stat iTunes library '%s': %s\n", file, strerror(errno)); DPRINTF(E_LOG, L_SCAN, "Could not stat iTunes library '%s': %s\n", path, strerror(errno));
goto error;
close(fd);
return;
} }
itml_xml = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); itml_xml = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (itml_xml == MAP_FAILED) if (itml_xml == MAP_FAILED)
{ {
DPRINTF(E_LOG, L_SCAN, "Could not map iTunes library '%s': %s\n", file, strerror(errno)); DPRINTF(E_LOG, L_SCAN, "Could not map iTunes library '%s': %s\n", path, strerror(errno));
goto error;
close(fd);
return;
} }
itml = NULL;
plist_from_xml(itml_xml, sb.st_size, &itml); plist_from_xml(itml_xml, sb.st_size, &itml);
ret = munmap(itml_xml, sb.st_size); ret = munmap(itml_xml, sb.st_size);
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_SCAN, "Could not unmap iTunes library '%s': %s\n", file, strerror(errno)); DPRINTF(E_LOG, L_SCAN, "Could not unmap iTunes library '%s': %s\n", path, strerror(errno));
close(fd); close(fd);
fd = -1;
if (!itml) if (!itml)
{ {
DPRINTF(E_LOG, L_SCAN, "iTunes XML playlist '%s' failed to parse\n", file); DPRINTF(E_LOG, L_SCAN, "iTunes XML playlist '%s' failed to parse\n", path);
goto error;
return;
} }
if (plist_get_node_type(itml) != PLIST_DICT) if (plist_get_node_type(itml) != PLIST_DICT)
{ {
DPRINTF(E_LOG, L_SCAN, "Malformed iTunes XML playlist '%s'\n", file); DPRINTF(E_LOG, L_SCAN, "Malformed iTunes XML playlist '%s'\n", path);
goto error;
plist_free(itml);
return;
} }
/* Meta data */ /* Meta data */
ret = check_meta(itml); ret = check_meta(itml);
if (ret < 0) if (ret < 0)
{ {
plist_free(itml); DPRINTF(E_LOG, L_SCAN, "Missing meta elements in iTunes XML playlist '%s'\n", path);
return; goto error;
} }
/* Tracks */ /* Tracks */
ret = get_dictval_dict_from_key(itml, "Tracks", &node); ret = get_dictval_dict_from_key(itml, "Tracks", &node);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_SCAN, "Could not find Tracks dict in '%s'\n", file); DPRINTF(E_LOG, L_SCAN, "Could not find Tracks dict in '%s'\n", path);
goto error;
plist_free(itml);
return;
} }
id_map = calloc(ID_MAP_SIZE, sizeof(struct itml_to_db_map *)); id_map = calloc(ID_MAP_SIZE, sizeof(struct itml_to_db_map *));
if (!id_map) if (!id_map)
{ {
DPRINTF(E_FATAL, L_SCAN, "iTunes library parser could not allocate ID map\n"); DPRINTF(E_LOG, L_SCAN, "iTunes library parser could not allocate ID map\n");
goto error;
plist_free(itml);
return;
} }
ret = process_tracks(node); ret = process_tracks(id_map, node);
if (ret <= 0) if (ret <= 0)
{ {
DPRINTF(E_LOG, L_SCAN, "No tracks loaded from iTunes XML '%s'\n", file); DPRINTF(E_LOG, L_SCAN, "No tracks loaded from iTunes XML '%s'\n", path);
goto error;
id_map_free();
plist_free(itml);
return;
} }
DPRINTF(E_LOG, L_SCAN, "Loaded %d tracks from iTunes XML '%s'\n", ret, file); DPRINTF(E_LOG, L_SCAN, "Loaded %d tracks from iTunes XML '%s'\n", ret, path);
/* Playlists */ /* Playlists */
ret = get_dictval_array_from_key(itml, "Playlists", &node); ret = get_dictval_array_from_key(itml, "Playlists", &node);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_SCAN, "Could not find Playlists dict in '%s'\n", file); DPRINTF(E_LOG, L_SCAN, "Could not find Playlists dict in '%s'\n", path);
goto error;
}
id_map_free(); process_pls(node, path, id_map);
id_map_free(id_map);
plist_free(itml); plist_free(itml);
return; return;
}
process_pls(node, file); error:
if (fd >= 0)
id_map_free(); close(fd);
if (itml)
plist_free(itml); plist_free(itml);
id_map_free(id_map);
// We failed this time, but if another request for a scan is made we want to
// try again - even if the mtime is the same. So here we delete the special
// playlist made by itml_is_modified(), so that the request will get a virgin
// treatment.
db_pl_delete_bypath(path);
} }