[db] Generic fixup + align fixing up between mfi, pli and queue_item

The idea here is to make sure the fixing up of tags is done in a consistent
manner. For strings, this means stuff like trimming and empty strings -> null
are applied the same unless there are special exception rules set. It also
means that defaults are applied the same across structs, e.g. "Unknown artist"
for both mfi->artist and queue_item->artist.

The change is also necessary because we want to remove trimming from the sql
query and instead implement it ourselves.
This commit is contained in:
ejurgensen 2018-12-28 19:10:17 +01:00
parent fc5a66f86d
commit 1de8f39264
5 changed files with 361 additions and 292 deletions

573
src/db.c
View File

@ -55,7 +55,7 @@
#define STR(x) ((x) ? (x) : "") #define STR(x) ((x) ? (x) : "")
/* Inotify cookies are uint32_t */ // Inotify cookies are uint32_t
#define INOTIFY_FAKE_COOKIE ((int64_t)1 << 32) #define INOTIFY_FAKE_COOKIE ((int64_t)1 << 32)
#define DB_TYPE_CHAR 1 #define DB_TYPE_CHAR 1
@ -70,6 +70,27 @@ enum group_type {
G_ARTISTS = 2, G_ARTISTS = 2,
}; };
enum fixup_type {
DB_FIXUP_STANDARD = 0,
DB_FIXUP_NO_SANITIZE,
DB_FIXUP_TITLE,
DB_FIXUP_ARTIST,
DB_FIXUP_ALBUM,
DB_FIXUP_ALBUM_ARTIST,
DB_FIXUP_GENRE,
DB_FIXUP_COMPOSER,
DB_FIXUP_TYPE,
DB_FIXUP_CODECTYPE,
DB_FIXUP_MEDIA_KIND,
DB_FIXUP_TITLE_SORT,
DB_FIXUP_ARTIST_SORT,
DB_FIXUP_ALBUM_SORT,
DB_FIXUP_ALBUM_ARTIST_SORT,
DB_FIXUP_COMPOSER_SORT,
DB_FIXUP_TIME_ADDED,
DB_FIXUP_TIME_MODIFIED,
};
struct db_unlock { struct db_unlock {
int proceed; int proceed;
pthread_cond_t cond; pthread_cond_t cond;
@ -85,11 +106,22 @@ struct db_statements
struct col_type_map { struct col_type_map {
char *name; char *name;
ssize_t offset; size_t offset;
short type; short type;
enum fixup_type fixup;
short flag; short flag;
}; };
struct fixup_ctx
{
const struct col_type_map *map;
size_t map_size;
void *data;
struct media_file_info *mfi;
struct playlist_info *pli;
struct db_queue_item *queue_item;
};
struct query_clause { struct query_clause {
char *where; char *where;
char *group; char *group;
@ -110,16 +142,16 @@ struct browse_clause {
*/ */
static const struct col_type_map mfi_cols_map[] = static const struct col_type_map mfi_cols_map[] =
{ {
{ "id", mfi_offsetof(id), DB_TYPE_INT, DB_FLAG_AUTO }, { "id", mfi_offsetof(id), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_AUTO },
{ "path", mfi_offsetof(path), DB_TYPE_STRING }, { "path", mfi_offsetof(path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "fname", mfi_offsetof(fname), DB_TYPE_STRING }, { "fname", mfi_offsetof(fname), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "title", mfi_offsetof(title), DB_TYPE_STRING }, { "title", mfi_offsetof(title), DB_TYPE_STRING, DB_FIXUP_TITLE },
{ "artist", mfi_offsetof(artist), DB_TYPE_STRING }, { "artist", mfi_offsetof(artist), DB_TYPE_STRING, DB_FIXUP_ARTIST },
{ "album", mfi_offsetof(album), DB_TYPE_STRING }, { "album", mfi_offsetof(album), DB_TYPE_STRING, DB_FIXUP_ALBUM },
{ "genre", mfi_offsetof(genre), DB_TYPE_STRING }, { "genre", mfi_offsetof(genre), DB_TYPE_STRING, DB_FIXUP_GENRE },
{ "comment", mfi_offsetof(comment), DB_TYPE_STRING }, { "comment", mfi_offsetof(comment), DB_TYPE_STRING },
{ "type", mfi_offsetof(type), DB_TYPE_STRING }, { "type", mfi_offsetof(type), DB_TYPE_STRING, DB_FIXUP_TYPE },
{ "composer", mfi_offsetof(composer), DB_TYPE_STRING }, { "composer", mfi_offsetof(composer), DB_TYPE_STRING, DB_FIXUP_COMPOSER },
{ "orchestra", mfi_offsetof(orchestra), DB_TYPE_STRING }, { "orchestra", mfi_offsetof(orchestra), DB_TYPE_STRING },
{ "conductor", mfi_offsetof(conductor), DB_TYPE_STRING }, { "conductor", mfi_offsetof(conductor), DB_TYPE_STRING },
{ "grouping", mfi_offsetof(grouping), DB_TYPE_STRING }, { "grouping", mfi_offsetof(grouping), DB_TYPE_STRING },
@ -142,31 +174,31 @@ static const struct col_type_map mfi_cols_map[] =
{ "data_kind", mfi_offsetof(data_kind), DB_TYPE_INT }, { "data_kind", mfi_offsetof(data_kind), DB_TYPE_INT },
{ "item_kind", mfi_offsetof(item_kind), DB_TYPE_INT }, { "item_kind", mfi_offsetof(item_kind), DB_TYPE_INT },
{ "description", mfi_offsetof(description), DB_TYPE_STRING }, { "description", mfi_offsetof(description), DB_TYPE_STRING },
{ "time_added", mfi_offsetof(time_added), DB_TYPE_INT }, { "time_added", mfi_offsetof(time_added), DB_TYPE_INT, DB_FIXUP_TIME_ADDED },
{ "time_modified", mfi_offsetof(time_modified), DB_TYPE_INT }, { "time_modified", mfi_offsetof(time_modified), DB_TYPE_INT, DB_FIXUP_TIME_MODIFIED },
{ "time_played", mfi_offsetof(time_played), DB_TYPE_INT }, { "time_played", mfi_offsetof(time_played), DB_TYPE_INT },
{ "db_timestamp", mfi_offsetof(db_timestamp), DB_TYPE_INT }, { "db_timestamp", mfi_offsetof(db_timestamp), DB_TYPE_INT },
{ "disabled", mfi_offsetof(disabled), DB_TYPE_INT }, { "disabled", mfi_offsetof(disabled), DB_TYPE_INT },
{ "sample_count", mfi_offsetof(sample_count), DB_TYPE_INT64 }, { "sample_count", mfi_offsetof(sample_count), DB_TYPE_INT64 },
{ "codectype", mfi_offsetof(codectype), DB_TYPE_STRING }, { "codectype", mfi_offsetof(codectype), DB_TYPE_STRING, DB_FIXUP_CODECTYPE },
{ "idx", mfi_offsetof(index), DB_TYPE_INT }, { "idx", mfi_offsetof(index), DB_TYPE_INT },
{ "has_video", mfi_offsetof(has_video), DB_TYPE_INT }, { "has_video", mfi_offsetof(has_video), DB_TYPE_INT },
{ "contentrating", mfi_offsetof(contentrating), DB_TYPE_INT }, { "contentrating", mfi_offsetof(contentrating), DB_TYPE_INT },
{ "bits_per_sample", mfi_offsetof(bits_per_sample), DB_TYPE_INT }, { "bits_per_sample", mfi_offsetof(bits_per_sample), DB_TYPE_INT },
{ "album_artist", mfi_offsetof(album_artist), DB_TYPE_STRING }, { "album_artist", mfi_offsetof(album_artist), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST },
{ "media_kind", mfi_offsetof(media_kind), DB_TYPE_INT }, { "media_kind", mfi_offsetof(media_kind), DB_TYPE_INT, DB_FIXUP_MEDIA_KIND },
{ "tv_series_name", mfi_offsetof(tv_series_name), DB_TYPE_STRING }, { "tv_series_name", mfi_offsetof(tv_series_name), DB_TYPE_STRING },
{ "tv_episode_num_str", mfi_offsetof(tv_episode_num_str), DB_TYPE_STRING }, { "tv_episode_num_str", mfi_offsetof(tv_episode_num_str), DB_TYPE_STRING },
{ "tv_network_name", mfi_offsetof(tv_network_name), DB_TYPE_STRING }, { "tv_network_name", mfi_offsetof(tv_network_name), DB_TYPE_STRING },
{ "tv_episode_sort", mfi_offsetof(tv_episode_sort), DB_TYPE_INT }, { "tv_episode_sort", mfi_offsetof(tv_episode_sort), DB_TYPE_INT },
{ "tv_season_num", mfi_offsetof(tv_season_num), DB_TYPE_INT }, { "tv_season_num", mfi_offsetof(tv_season_num), DB_TYPE_INT },
{ "songartistid", mfi_offsetof(songartistid), DB_TYPE_INT64, DB_FLAG_AUTO }, { "songartistid", mfi_offsetof(songartistid), DB_TYPE_INT64, DB_FIXUP_STANDARD, DB_FLAG_AUTO },
{ "songalbumid", mfi_offsetof(songalbumid), DB_TYPE_INT64, DB_FLAG_AUTO }, { "songalbumid", mfi_offsetof(songalbumid), DB_TYPE_INT64, DB_FIXUP_STANDARD, DB_FLAG_AUTO },
{ "title_sort", mfi_offsetof(title_sort), DB_TYPE_STRING }, { "title_sort", mfi_offsetof(title_sort), DB_TYPE_STRING, DB_FIXUP_TITLE_SORT },
{ "artist_sort", mfi_offsetof(artist_sort), DB_TYPE_STRING }, { "artist_sort", mfi_offsetof(artist_sort), DB_TYPE_STRING, DB_FIXUP_ARTIST_SORT },
{ "album_sort", mfi_offsetof(album_sort), DB_TYPE_STRING }, { "album_sort", mfi_offsetof(album_sort), DB_TYPE_STRING, DB_FIXUP_ALBUM_SORT },
{ "composer_sort", mfi_offsetof(composer_sort), DB_TYPE_STRING }, { "composer_sort", mfi_offsetof(composer_sort), DB_TYPE_STRING, DB_FIXUP_COMPOSER_SORT },
{ "album_artist_sort", mfi_offsetof(album_artist_sort), DB_TYPE_STRING }, { "album_artist_sort", mfi_offsetof(album_artist_sort), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST_SORT },
{ "virtual_path", mfi_offsetof(virtual_path), DB_TYPE_STRING }, { "virtual_path", mfi_offsetof(virtual_path), DB_TYPE_STRING },
{ "directory_id", mfi_offsetof(directory_id), DB_TYPE_INT }, { "directory_id", mfi_offsetof(directory_id), DB_TYPE_INT },
{ "date_released", mfi_offsetof(date_released), DB_TYPE_INT }, { "date_released", mfi_offsetof(date_released), DB_TYPE_INT },
@ -180,24 +212,57 @@ static const struct col_type_map mfi_cols_map[] =
*/ */
static const struct col_type_map pli_cols_map[] = static const struct col_type_map pli_cols_map[] =
{ {
{ "id", pli_offsetof(id), DB_TYPE_INT, DB_FLAG_AUTO }, { "id", pli_offsetof(id), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_AUTO },
{ "title", pli_offsetof(title), DB_TYPE_STRING }, { "title", pli_offsetof(title), DB_TYPE_STRING, DB_FIXUP_TITLE },
{ "type", pli_offsetof(type), DB_TYPE_INT }, { "type", pli_offsetof(type), DB_TYPE_INT },
{ "query", pli_offsetof(query), DB_TYPE_STRING }, { "query", pli_offsetof(query), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "db_timestamp", pli_offsetof(db_timestamp), DB_TYPE_INT }, { "db_timestamp", pli_offsetof(db_timestamp), DB_TYPE_INT },
{ "disabled", pli_offsetof(disabled), DB_TYPE_INT }, { "disabled", pli_offsetof(disabled), DB_TYPE_INT },
{ "path", pli_offsetof(path), DB_TYPE_STRING }, { "path", pli_offsetof(path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "idx", pli_offsetof(index), DB_TYPE_INT }, { "idx", pli_offsetof(index), DB_TYPE_INT },
{ "special_id", pli_offsetof(special_id), DB_TYPE_INT }, { "special_id", pli_offsetof(special_id), DB_TYPE_INT },
{ "virtual_path", pli_offsetof(virtual_path), DB_TYPE_STRING }, { "virtual_path", pli_offsetof(virtual_path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "parent_id", pli_offsetof(parent_id), DB_TYPE_INT }, { "parent_id", pli_offsetof(parent_id), DB_TYPE_INT },
{ "directory_id", pli_offsetof(directory_id), DB_TYPE_INT }, { "directory_id", pli_offsetof(directory_id), DB_TYPE_INT },
{ "query_order", pli_offsetof(query_order), DB_TYPE_STRING }, { "query_order", pli_offsetof(query_order), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "query_limit", pli_offsetof(query_limit), DB_TYPE_INT }, { "query_limit", pli_offsetof(query_limit), DB_TYPE_INT },
/* items is computed on the fly */ /* items is computed on the fly */
}; };
/* This list must be kept in sync with
* - the order of the columns in the queue table
* - the type and name of the fields in struct db_queue_item
*/
static const struct col_type_map qi_cols_map[] =
{
{ "id", qi_offsetof(id), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_AUTO },
{ "file_id", qi_offsetof(id), DB_TYPE_INT },
{ "pos", qi_offsetof(pos), DB_TYPE_INT },
{ "shuffle_pos", qi_offsetof(shuffle_pos), DB_TYPE_INT },
{ "data_kind", qi_offsetof(data_kind), DB_TYPE_INT },
{ "media_kind", qi_offsetof(media_kind), DB_TYPE_INT, DB_FIXUP_MEDIA_KIND },
{ "song_length", qi_offsetof(song_length), DB_TYPE_INT },
{ "path", qi_offsetof(path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "virtual_path", qi_offsetof(virtual_path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "title", qi_offsetof(title), DB_TYPE_STRING, DB_FIXUP_TITLE },
{ "artist", qi_offsetof(artist), DB_TYPE_STRING, DB_FIXUP_ARTIST },
{ "album_artist", qi_offsetof(album_artist), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST },
{ "album", qi_offsetof(album), DB_TYPE_STRING, DB_FIXUP_ALBUM },
{ "genre", qi_offsetof(genre), DB_TYPE_STRING, DB_FIXUP_GENRE },
{ "songalbumid", qi_offsetof(songalbumid), DB_TYPE_INT64 },
{ "time_modified", qi_offsetof(time_modified), DB_TYPE_INT },
{ "artist_sort", qi_offsetof(artist_sort), DB_TYPE_STRING, DB_FIXUP_ARTIST_SORT },
{ "album_sort", qi_offsetof(album_sort), DB_TYPE_STRING, DB_FIXUP_ALBUM_SORT },
{ "album_artist_sort", qi_offsetof(album_artist_sort), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST_SORT },
{ "year", qi_offsetof(year), DB_TYPE_INT },
{ "track", qi_offsetof(track), DB_TYPE_INT },
{ "disc", qi_offsetof(disc), DB_TYPE_INT },
{ "artwork_url", qi_offsetof(artwork_url), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
{ "queue_version", qi_offsetof(queue_version), DB_TYPE_INT },
{ "composer", qi_offsetof(composer), DB_TYPE_STRING, DB_FIXUP_COMPOSER },
};
/* This list must be kept in sync with /* This list must be kept in sync with
* - the order of the columns in the files table * - the order of the columns in the files table
* - the name of the fields in struct db_media_file_info * - the name of the fields in struct db_media_file_info
@ -363,6 +428,7 @@ struct media_kind_label {
const char *label; const char *label;
}; };
/* Keep in sync with enum media_kind */ /* Keep in sync with enum media_kind */
static const struct media_kind_label media_kind_labels[] = static const struct media_kind_label media_kind_labels[] =
{ {
@ -638,42 +704,8 @@ free_queue_item(struct db_queue_item *queue_item, int content_only)
memset(queue_item, 0, sizeof(struct db_queue_item)); memset(queue_item, 0, sizeof(struct db_queue_item));
} }
void
unicode_fixup_mfi(struct media_file_info *mfi)
{
char *ret;
char **field;
int i;
for (i = 0; i < ARRAY_SIZE(mfi_cols_map); i++)
{
if (mfi_cols_map[i].type != DB_TYPE_STRING)
continue;
switch (mfi_cols_map[i].offset)
{
case mfi_offsetof(path):
case mfi_offsetof(fname):
case mfi_offsetof(codectype):
continue;
}
field = (char **) ((char *)mfi + mfi_cols_map[i].offset);
if (!*field)
continue;
ret = unicode_fixup_string(*field, "ascii");
if (ret != *field)
{
free(*field);
*field = ret;
}
}
}
static void static void
sort_tag_create(char **sort_tag, char *src_tag) sort_tag_create(char **sort_tag, const char *src_tag)
{ {
const uint8_t *i_ptr; const uint8_t *i_ptr;
const uint8_t *n_ptr; const uint8_t *n_ptr;
@ -773,224 +805,270 @@ sort_tag_create(char **sort_tag, char *src_tag)
*sort_tag = (char *)u8_normalize(UNINORM_NFD, (uint8_t *)&out, u8_strlen(out) + 1, NULL, &len); *sort_tag = (char *)u8_normalize(UNINORM_NFD, (uint8_t *)&out, u8_strlen(out) + 1, NULL, &len);
} }
void static void
fixup_tags_mfi(struct media_file_info *mfi) fixup_sanitize(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx)
{
char *ret;
if (!tag || !*tag)
return;
switch (fixup)
{
case DB_FIXUP_NO_SANITIZE:
case DB_FIXUP_CODECTYPE:
break; // Don't touch the above
default:
trim(*tag);
// By default we set empty strings to NULL
if (*tag[0] == '\0')
{
free(*tag);
*tag = NULL;
break;
}
ret = unicode_fixup_string(*tag, "ascii");
if (ret != *tag)
{
free(*tag);
*tag = ret;
}
}
}
static void
fixup_defaults(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx)
{ {
cfg_t *lib;
size_t len;
char *tag;
char *sep = " - ";
char *ca; char *ca;
if (mfi->genre && (strlen(mfi->genre) == 0)) switch(fixup)
{ {
free(mfi->genre); case DB_FIXUP_TITLE:
mfi->genre = NULL; if (*tag)
break;
// fname is left untouched by fixup_sanitize() for obvious reasons, so ensure it is proper UTF-8
if (ctx->mfi && ctx->mfi->fname)
{
*tag = unicode_fixup_string(ctx->mfi->fname, "ascii");
if (*tag == ctx->mfi->fname)
*tag = strdup(ctx->mfi->fname);
}
else if (ctx->pli && ctx->pli->path)
*tag = strdup(ctx->pli->path);
else if (ctx->queue_item && ctx->queue_item->path)
*tag = strdup(ctx->queue_item->path);
else
*tag = strdup("Unknown title");
break;
case DB_FIXUP_ARTIST:
if (*tag)
break;
if (ctx->mfi && ctx->mfi->orchestra && ctx->mfi->conductor)
*tag = safe_asprintf("%s - %s", ctx->mfi->orchestra, ctx->mfi->conductor);
else if (ctx->mfi && ctx->mfi->orchestra)
*tag = strdup(ctx->mfi->orchestra);
else if (ctx->mfi && ctx->mfi->conductor)
*tag = strdup(ctx->mfi->conductor);
else if (ctx->mfi && ctx->mfi->tv_series_name)
*tag = strdup(ctx->mfi->tv_series_name);
else
*tag = strdup("Unknown artist");
break;
case DB_FIXUP_ALBUM:
if (*tag)
break;
if (ctx->mfi && ctx->mfi->tv_series_name)
*tag = safe_asprintf("%s, Season %u", ctx->mfi->tv_series_name, ctx->mfi->tv_season_num);
else
*tag = strdup("Unknown album");
break;
case DB_FIXUP_ALBUM_ARTIST: // Will be set after artist, because artist (must) come first in the col_maps
if (ctx->mfi && ctx->mfi->compilation && (ca = cfg_getstr(cfg_getsec(cfg, "library"), "compilation_artist")))
{
free(*tag);
*tag = strdup(ca);
}
else if (ctx->mfi && ctx->mfi->compilation)
*tag = strdup("");
if (ctx->mfi && ctx->mfi->media_kind == MEDIA_KIND_PODCAST)
{
free(*tag);
*tag = strdup("");
} }
if (mfi->artist && (strlen(mfi->artist) == 0)) if (*tag)
{ break;
free(mfi->artist);
mfi->artist = NULL;
}
if (mfi->title && (strlen(mfi->title) == 0)) if (ctx->mfi && ctx->mfi->artist)
{ *tag = strdup(ctx->mfi->artist);
free(mfi->title); else if (ctx->queue_item && ctx->queue_item->artist)
mfi->title = NULL; *tag = strdup(ctx->queue_item->artist);
} else
*tag = strdup("Unknown album artist");
break;
/* case DB_FIXUP_GENRE:
* Default to mpeg4 video/audio for unknown file types if (*tag)
* in an attempt to allow streaming of DRM-afflicted files break;
*/
if (mfi->codectype && strcmp(mfi->codectype, "unkn") == 0) *tag = strdup("Unknown genre");
break;
case DB_FIXUP_MEDIA_KIND:
if (ctx->mfi && ctx->mfi->tv_series_name)
ctx->mfi->media_kind = MEDIA_KIND_TVSHOW;
break;
case DB_FIXUP_TIME_ADDED:
if (ctx->mfi && ctx->mfi->time_added == 0)
ctx->mfi->time_added = ctx->mfi->db_timestamp;
break;
case DB_FIXUP_TIME_MODIFIED:
if (ctx->mfi && ctx->mfi->time_modified == 0)
ctx->mfi->time_modified = ctx->mfi->db_timestamp;
break;
case DB_FIXUP_CODECTYPE:
case DB_FIXUP_TYPE:
// Default to mpeg4 video/audio for unknown file types in an attempt to allow streaming of DRM-afflicted files
if (ctx->mfi && ctx->mfi->codectype && strcmp(ctx->mfi->codectype, "unkn") == 0)
{ {
if (mfi->has_video) if (ctx->mfi->has_video)
{ {
strcpy(mfi->codectype, "mp4v"); strcpy(ctx->mfi->codectype, "mp4v");
strcpy(mfi->type, "m4v"); strcpy(ctx->mfi->type, "m4v");
} }
else else
{ {
strcpy(mfi->codectype, "mp4a"); strcpy(ctx->mfi->codectype, "mp4a");
strcpy(mfi->type, "m4a"); strcpy(ctx->mfi->type, "m4a");
} }
} }
break;
if (!mfi->artist) default:
{ break;
if (mfi->orchestra && mfi->conductor)
{
len = strlen(mfi->orchestra) + strlen(sep) + strlen(mfi->conductor);
tag = (char *)malloc(len + 1);
if (tag)
{
sprintf(tag,"%s%s%s", mfi->orchestra, sep, mfi->conductor);
mfi->artist = tag;
}
}
else if (mfi->orchestra)
{
mfi->artist = strdup(mfi->orchestra);
}
else if (mfi->conductor)
{
mfi->artist = strdup(mfi->conductor);
}
} }
}
/* Handle TV shows, try to present prettier metadata */ static void
if (mfi->tv_series_name && strlen(mfi->tv_series_name) != 0) fixup_sort_tags(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx)
{
switch(fixup)
{ {
mfi->media_kind = MEDIA_KIND_TVSHOW; /* tv show */ case DB_FIXUP_TITLE_SORT:
if (ctx->mfi)
sort_tag_create(tag, ctx->mfi->title);
break;
/* Default to artist = series_name */ case DB_FIXUP_ARTIST_SORT:
if (mfi->artist && strlen(mfi->artist) == 0) if (ctx->mfi)
{ sort_tag_create(tag, ctx->mfi->artist);
free(mfi->artist); else if (ctx->queue_item)
mfi->artist = NULL; sort_tag_create(tag, ctx->queue_item->artist);
} break;
if (!mfi->artist) case DB_FIXUP_ALBUM_SORT:
mfi->artist = strdup(mfi->tv_series_name); if (ctx->mfi)
sort_tag_create(tag, ctx->mfi->album);
else if (ctx->queue_item)
sort_tag_create(tag, ctx->queue_item->album);
break;
/* Default to album = "<series_name>, Season <season_num>" */ case DB_FIXUP_ALBUM_ARTIST_SORT:
if (mfi->album && strlen(mfi->album) == 0) if (ctx->mfi)
{ sort_tag_create(tag, ctx->mfi->album_artist);
free(mfi->album); else if (ctx->queue_item)
mfi->album = NULL; sort_tag_create(tag, ctx->queue_item->album_artist);
} break;
if (!mfi->album) case DB_FIXUP_COMPOSER_SORT:
{ if (ctx->mfi)
len = snprintf(NULL, 0, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num); sort_tag_create(tag, ctx->mfi->composer);
break;
mfi->album = (char *)malloc(len + 1); default:
if (mfi->album) break;
sprintf(mfi->album, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);
}
} }
}
/* Check the 4 top-tags are filled */ static void
if (!mfi->artist) fixup_tags(struct fixup_ctx *ctx)
mfi->artist = strdup("Unknown artist"); {
if (!mfi->album) void (*fixup_func[])(char **, enum fixup_type, struct fixup_ctx *) = { fixup_sanitize, fixup_defaults, fixup_sort_tags };
mfi->album = strdup("Unknown album"); char **tag;
if (!mfi->genre) int i;
mfi->genre = strdup("Unknown genre"); int j;
if (!mfi->title)
{
/* fname is left untouched by unicode_fixup_mfi() for
* obvious reasons, so ensure it is proper UTF-8
*/
mfi->title = unicode_fixup_string(mfi->fname, "ascii");
if (mfi->title == mfi->fname)
mfi->title = strdup(mfi->fname);
}
/* Ensure sort tags are filled, manipulated and normalized */ for (i = 0; i < ARRAY_SIZE(fixup_func); i++)
sort_tag_create(&mfi->artist_sort, mfi->artist); {
sort_tag_create(&mfi->album_sort, mfi->album); for (j = 0; j < ctx->map_size; j++)
sort_tag_create(&mfi->title_sort, mfi->title); {
switch (ctx->map[j].type)
{
case DB_TYPE_STRING:
tag = (char **) ((char *)ctx->data + ctx->map[j].offset);
fixup_func[i](tag, ctx->map[j].fixup, ctx);
break;
/* We need to set album_artist according to media type and config */ case DB_TYPE_CHAR:
if (mfi->compilation) /* Compilation */ case DB_TYPE_INT:
{ case DB_TYPE_INT64:
lib = cfg_getsec(cfg, "library"); fixup_func[i](NULL, ctx->map[j].fixup, ctx);
ca = cfg_getstr(lib, "compilation_artist"); break;
if (ca && mfi->album_artist)
{
free(mfi->album_artist);
mfi->album_artist = strdup(ca);
}
else if (ca && !mfi->album_artist)
{
mfi->album_artist = strdup(ca);
}
else if (!ca && !mfi->album_artist)
{
mfi->album_artist = strdup("");
mfi->album_artist_sort = strdup("");
} }
} }
else if (mfi->media_kind == MEDIA_KIND_PODCAST) /* Podcast */
{
if (mfi->album_artist)
free(mfi->album_artist);
mfi->album_artist = strdup("");
mfi->album_artist_sort = strdup("");
}
else if (!mfi->album_artist) /* Regular media without album_artist */
{
mfi->album_artist = strdup(mfi->artist);
} }
}
if (!mfi->album_artist_sort && (strcmp(mfi->album_artist, mfi->artist) == 0)) static void
mfi->album_artist_sort = strdup(mfi->artist_sort); fixup_tags_mfi(struct media_file_info *mfi)
else {
sort_tag_create(&mfi->album_artist_sort, mfi->album_artist); struct fixup_ctx ctx = { 0 };
ctx.data = mfi;
ctx.mfi = mfi;
ctx.map = mfi_cols_map;
ctx.map_size = ARRAY_SIZE(mfi_cols_map);
/* Composer is not one of our mandatory tags, so take extra care */ fixup_tags(&ctx);
if (mfi->composer_sort || mfi->composer) }
sort_tag_create(&mfi->composer_sort, mfi->composer);
static void
fixup_tags_pli(struct playlist_info *pli)
{
struct fixup_ctx ctx = { 0 };
ctx.data = pli;
ctx.pli = pli;
ctx.map = pli_cols_map;
ctx.map_size = ARRAY_SIZE(pli_cols_map);
fixup_tags(&ctx);
} }
static void static void
fixup_tags_queue_item(struct db_queue_item *queue_item) fixup_tags_queue_item(struct db_queue_item *queue_item)
{ {
if (queue_item->genre && (strlen(queue_item->genre) == 0)) struct fixup_ctx ctx = { 0 };
{ ctx.data = queue_item;
free(queue_item->genre); ctx.queue_item = queue_item;
queue_item->genre = NULL; ctx.map = qi_cols_map;
} ctx.map_size = ARRAY_SIZE(qi_cols_map);
if (queue_item->artist && (strlen(queue_item->artist) == 0)) fixup_tags(&ctx);
{
free(queue_item->artist);
queue_item->artist = NULL;
}
if (queue_item->title && (strlen(queue_item->title) == 0))
{
free(queue_item->title);
queue_item->title = NULL;
}
/* Check the 4 top-tags are filled */
if (!queue_item->artist)
queue_item->artist = strdup("Unknown artist");
if (!queue_item->album)
queue_item->album = strdup("Unknown album");
if (!queue_item->genre)
queue_item->genre = strdup("Unknown genre");
if (!queue_item->title)
queue_item->title = strdup(queue_item->path);
/* Ensure sort tags are filled, manipulated and normalized */
sort_tag_create(&queue_item->artist_sort, queue_item->artist);
sort_tag_create(&queue_item->album_sort, queue_item->album);
/* We need to set album_artist according to media type and config */
if (queue_item->media_kind == MEDIA_KIND_PODCAST) /* Podcast */
{
if (queue_item->album_artist)
free(queue_item->album_artist);
queue_item->album_artist = strdup("");
queue_item->album_artist_sort = strdup("");
}
else if (!queue_item->album_artist) /* Regular media without album_artist */
{
queue_item->album_artist = strdup(queue_item->artist);
}
if (!queue_item->album_artist_sort && queue_item->artist_sort && (strcmp(queue_item->album_artist, queue_item->artist) == 0))
queue_item->album_artist_sort = strdup(queue_item->artist_sort);
else
sort_tag_create(&queue_item->album_artist_sort, queue_item->album_artist);
} }
// TODO Make sure fixup_tags_mfi takes care of trimming whitespace
static int static int
bind_mfi(sqlite3_stmt *stmt, struct media_file_info *mfi) bind_mfi(sqlite3_stmt *stmt, struct media_file_info *mfi)
{ {
@ -2908,11 +2986,7 @@ db_file_add(struct media_file_info *mfi)
mfi->db_timestamp = (uint64_t)time(NULL); mfi->db_timestamp = (uint64_t)time(NULL);
if (mfi->time_added == 0) fixup_tags_mfi(mfi);
mfi->time_added = mfi->db_timestamp;
if (mfi->time_modified == 0)
mfi->time_modified = mfi->db_timestamp;
ret = bind_mfi(db_statements.files_insert, mfi); ret = bind_mfi(db_statements.files_insert, mfi);
if (ret < 0) if (ret < 0)
@ -2940,8 +3014,7 @@ db_file_update(struct media_file_info *mfi)
mfi->db_timestamp = (uint64_t)time(NULL); mfi->db_timestamp = (uint64_t)time(NULL);
if (mfi->time_modified == 0) fixup_tags_mfi(mfi);
mfi->time_modified = mfi->db_timestamp;
ret = bind_mfi(db_statements.files_update, mfi); ret = bind_mfi(db_statements.files_update, mfi);
if (ret < 0) if (ret < 0)
@ -3464,6 +3537,8 @@ db_pl_add(struct playlist_info *pli, int *id)
char *errmsg; char *errmsg;
int ret; int ret;
fixup_tags_pli(pli);
/* Check duplicates */ /* Check duplicates */
query = sqlite3_mprintf(QDUP_TMPL, pli->title, STR(pli->path)); query = sqlite3_mprintf(QDUP_TMPL, pli->title, STR(pli->path));
if (!query) if (!query)
@ -3557,6 +3632,8 @@ db_pl_update(struct playlist_info *pli)
char *query; char *query;
int ret; int ret;
fixup_tags_pli(pli);
query = sqlite3_mprintf(Q_TMPL, query = sqlite3_mprintf(Q_TMPL,
pli->title, pli->type, pli->query, (int64_t)time(NULL), pli->disabled, STR(pli->path), pli->title, pli->type, pli->query, (int64_t)time(NULL), pli->disabled, STR(pli->path),
pli->index, pli->special_id, pli->parent_id, pli->virtual_path, pli->directory_id, pli->index, pli->special_id, pli->parent_id, pli->virtual_path, pli->directory_id,

View File

@ -425,8 +425,7 @@ struct directory_enum {
void *stmt; void *stmt;
}; };
struct db_queue_item struct db_queue_item {
{
/* A unique id for this queue item. If the same item appears multiple /* A unique id for this queue item. If the same item appears multiple
times in the queue each corresponding queue item has its own id. */ times in the queue each corresponding queue item has its own id. */
uint32_t id; uint32_t id;
@ -434,18 +433,16 @@ struct db_queue_item
/* Id of the file/item in the files database */ /* Id of the file/item in the files database */
uint32_t file_id; uint32_t file_id;
/* Length of the item in ms */ uint32_t pos;
uint32_t song_length; uint32_t shuffle_pos;
/* Data type of the item */ /* Data type of the item */
enum data_kind data_kind; enum data_kind data_kind;
/* Media type of the item */ /* Media type of the item */
enum media_kind media_kind; enum media_kind media_kind;
uint32_t seek; /* Length of the item in ms */
uint32_t song_length;
uint32_t pos;
uint32_t shuffle_pos;
char *path; char *path;
char *virtual_path; char *virtual_path;
@ -453,7 +450,6 @@ struct db_queue_item
char *title; char *title;
char *artist; char *artist;
char *album_artist; char *album_artist;
char *composer;
char *album; char *album;
char *genre; char *genre;
@ -471,8 +467,15 @@ struct db_queue_item
char *artwork_url; char *artwork_url;
uint32_t queue_version; uint32_t queue_version;
char *composer;
/* Not saved in queue table */
uint32_t seek;
}; };
#define qi_offsetof(field) offsetof(struct db_queue_item, field)
struct db_queue_add_info struct db_queue_add_info
{ {
int queue_version; int queue_version;
@ -510,12 +513,6 @@ free_query_params(struct query_params *qp, int content_only);
void void
free_queue_item(struct db_queue_item *queue_item, int content_only); free_queue_item(struct db_queue_item *queue_item, int content_only);
void
unicode_fixup_mfi(struct media_file_info *mfi);
void
fixup_tags_mfi(struct media_file_info *mfi);
/* Maintenance and DB hygiene */ /* Maintenance and DB hygiene */
void void
db_hook_post_scan(void); db_hook_post_scan(void);

View File

@ -133,9 +133,6 @@ library_add_media(struct media_file_info *mfi)
if (!mfi->media_kind) if (!mfi->media_kind)
mfi->media_kind = MEDIA_KIND_MUSIC; /* music */ mfi->media_kind = MEDIA_KIND_MUSIC; /* music */
unicode_fixup_mfi(mfi);
fixup_tags_mfi(mfi);
if (mfi->id == 0) if (mfi->id == 0)
db_file_add(mfi); db_file_add(mfi);
else else

View File

@ -1686,7 +1686,6 @@ queue_add_stream(const char *path, int position, char reshuffle, uint32_t item_i
memset(&mfi, 0, sizeof(struct media_file_info)); memset(&mfi, 0, sizeof(struct media_file_info));
scan_metadata_stream(path, &mfi); scan_metadata_stream(path, &mfi);
unicode_fixup_mfi(&mfi);
map_media_file_to_queue_item(&item, &mfi); map_media_file_to_queue_item(&item, &mfi);

View File

@ -548,7 +548,6 @@ process_track_file(plist_t trk)
mfi->album_artist = strdup(mfi->artist); mfi->album_artist = strdup(mfi->artist);
} }
unicode_fixup_mfi(mfi);
db_file_update(mfi); db_file_update(mfi);
free_mfi(mfi, 0); free_mfi(mfi, 0);