Flexible thumbnail matching (#16040)

Add logic to handle 3 possible thumbnail names, in following order:
- most exact name derived from content file (same name, with .png extension)
- usual name derived from playlist (usually coming from database)
- shortened name up to first bracket, chopping off region/publisher etc. info

For local file system, names are checked always.
For thumbnail downloads, names are checked each time the item comes up
in the playlist, meaning that it may take going back and forth 3 times
for a thumbnail to appear. However, as a positive change, failed thumbnail
downloads are not repeated for the same playlist, which was not the case
earlier.
This commit is contained in:
zoltanvb 2023-12-27 11:26:46 +01:00 committed by GitHub
parent 824a0f86fd
commit 3ce56c5b42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 29 deletions

View file

@ -292,12 +292,12 @@ void gfx_thumbnail_request(
const char *system = NULL;
const char *img_name = NULL;
static char last_img_name[PATH_MAX_LENGTH] = {0};
enum playlist_thumbnail_name_flags next_flag;
if (!playlist)
goto end;
/* Get current image name */
if (!gfx_thumbnail_get_img_name(path_data, &img_name))
/* Validate entry */
if (!gfx_thumbnail_get_img_name(path_data, &img_name, PLAYLIST_THUMBNAIL_FLAG_STD_NAME))
goto end;
/* Only trigger a thumbnail download if image
@ -321,7 +321,15 @@ void gfx_thumbnail_request(
if (!gfx_thumbnail_get_system(path_data, &system))
goto end;
/* Trigger thumbnail download */
/* Apply flexible thumbnail naming: ROM file name - database name - short name */
next_flag = playlist_get_next_thumbnail_name_flag(playlist,idx);
if (next_flag == PLAYLIST_THUMBNAIL_FLAG_NONE)
goto end;
/* Trigger thumbnail download *
* Note: download will grab all 3 possible thumbnails, no matter
* what left/right thumbnails are set at the moment */
playlist_update_thumbnail_name_flag(playlist, idx, next_flag);
task_push_pl_entry_thumbnail_download(
system, playlist, (unsigned)idx,
false, true);

View file

@ -37,14 +37,23 @@
/* Fills content_img field of path_data using existing
* content_label field (for internal use only) */
static void gfx_thumbnail_fill_content_img(char *s, size_t len, const char *src)
static void gfx_thumbnail_fill_content_img(char *s, size_t len, const char *src, bool shorten)
{
const char* cut = " (";
char *scrub_char_ptr = NULL;
/* Copy source label string */
size_t _len = strlcpy(s, src, len);
int bracketpos = -1;
/* Shortening logic: up to first space + bracket */
if (shorten) {
bracketpos = string_find_index_substring_string(src, cut);
if (bracketpos > 2)
_len = bracketpos;
}
/* Scrub characters that are not cross-platform and/or violate the
* No-Intro filename standard:
* http://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).zip
* https://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).pdf
* Replace these characters in the entry name with underscores */
while ((scrub_char_ptr = strpbrk(s, "&*/:`\"<>?\\|")))
*scrub_char_ptr = '_';
@ -289,7 +298,9 @@ bool gfx_thumbnail_set_content(gfx_thumbnail_path_data_t *path_data, const char
/* Determine content image name */
gfx_thumbnail_fill_content_img(path_data->content_img,
sizeof(path_data->content_img), path_data->content_label);
sizeof(path_data->content_img), path_data->content_label, false);
gfx_thumbnail_fill_content_img(path_data->content_img_short,
sizeof(path_data->content_img_short), path_data->content_label, true);
/* Have to set content path to *something*...
* Just use label value (it doesn't matter) */
@ -444,8 +455,6 @@ bool gfx_thumbnail_set_content_playlist(
"", sizeof(path_data->content_label));
/* Determine content image name */
if (settings->bools.playlist_use_filename ||
playlist_thumbnail_match_with_filename(playlist))
{
char* content_name_no_ext = NULL;
char tmp_buf[PATH_MAX_LENGTH];
@ -457,13 +466,12 @@ bool gfx_thumbnail_set_content_playlist(
strlcpy(tmp_buf, base_name, sizeof(tmp_buf));
content_name_no_ext = path_remove_extension(tmp_buf);
gfx_thumbnail_fill_content_img(path_data->content_img_full,
sizeof(path_data->content_img_full), content_name_no_ext,false);
gfx_thumbnail_fill_content_img(path_data->content_img,
sizeof(path_data->content_img), content_name_no_ext);
}
else
{
gfx_thumbnail_fill_content_img(path_data->content_img,
sizeof(path_data->content_img), path_data->content_label);
sizeof(path_data->content_img), path_data->content_label,false);
gfx_thumbnail_fill_content_img(path_data->content_img_short,
sizeof(path_data->content_img_short), path_data->content_label,true);
}
/* Store playlist index */
@ -620,10 +628,28 @@ bool gfx_thumbnail_update_path(
/* >> Add type */
fill_pathname_join_special(tmp_buf, thumbnail_path, type, sizeof(tmp_buf));
/* >> Add content image */
thumbnail_path[0] = '\0';
fill_pathname_join_special(thumbnail_path, tmp_buf,
path_data->content_img, PATH_MAX_LENGTH * sizeof(char));
/* >> Add content image - first try with full file name */
if(path_data->content_img_full[0] != '\0') {
fill_pathname_join_special(thumbnail_path, tmp_buf,
path_data->content_img_full, PATH_MAX_LENGTH * sizeof(char));
}
/* >> Add content image - second try with label (database name) */
if(!path_is_valid(thumbnail_path) && path_data->content_img[0] != '\0')
{
thumbnail_path[0] = '\0';
fill_pathname_join_special(thumbnail_path, tmp_buf,
path_data->content_img, PATH_MAX_LENGTH * sizeof(char));
}
/* >> Add content image - third try with shortened name (title only) */
if(!path_is_valid(thumbnail_path) && path_data->content_img_short[0] != '\0')
{
thumbnail_path[0] = '\0';
fill_pathname_join_special(thumbnail_path, tmp_buf,
path_data->content_img_short, PATH_MAX_LENGTH * sizeof(char));
}
/* This logic is valid for locally stored thumbnails. For optional downloads,
* gfx_thumbnail_get_img_name() is used */
}
/* Final error check - is cached path empty? */
@ -715,18 +741,35 @@ bool gfx_thumbnail_get_core_name(
return true;
}
/* Fetches current thumbnail image name
/* Fetches current thumbnail image name according to name flag
* (name is the same for all thumbnail types).
* Returns true if image name is valid. */
bool gfx_thumbnail_get_img_name(
gfx_thumbnail_path_data_t *path_data, const char **img_name)
gfx_thumbnail_path_data_t *path_data, const char **img_name,
enum playlist_thumbnail_name_flags name_flags)
{
if (!path_data || !img_name)
return false;
if (string_is_empty(path_data->content_img))
if (!path_data || !img_name || name_flags == PLAYLIST_THUMBNAIL_FLAG_NONE)
return false;
if (name_flags & PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME) {
if (string_is_empty(path_data->content_img_short))
return false;
*img_name = path_data->content_img;
*img_name = path_data->content_img_short;
}
else if (name_flags & PLAYLIST_THUMBNAIL_FLAG_STD_NAME) {
if (string_is_empty(path_data->content_img))
return false;
*img_name = path_data->content_img;
}
else if (name_flags & PLAYLIST_THUMBNAIL_FLAG_FULL_NAME) {
if (string_is_empty(path_data->content_img_full))
return false;
*img_name = path_data->content_img_full;
}
else
return false;
return true;
}

View file

@ -60,6 +60,8 @@ struct gfx_thumbnail_path_data
size_t playlist_index;
char content_path[PATH_MAX_LENGTH];
char content_img[PATH_MAX_LENGTH];
char content_img_short[PATH_MAX_LENGTH];
char content_img_full[PATH_MAX_LENGTH];
char right_path[PATH_MAX_LENGTH];
char left_path[PATH_MAX_LENGTH];
char content_label[256];
@ -147,7 +149,7 @@ bool gfx_thumbnail_get_core_name(gfx_thumbnail_path_data_t *path_data, const cha
/* Fetches current thumbnail image name
* (name is the same for all thumbnail types).
* Returns true if image name is valid. */
bool gfx_thumbnail_get_img_name(gfx_thumbnail_path_data_t *path_data, const char **img_name);
bool gfx_thumbnail_get_img_name(gfx_thumbnail_path_data_t *path_data, const char **img_name, enum playlist_thumbnail_name_flags name_flags);
/* Fetches current content directory.
* Returns true if content directory is valid. */

View file

@ -1059,6 +1059,48 @@ error:
return false;
}
void playlist_update_thumbnail_name_flag(playlist_t *playlist, size_t idx,
enum playlist_thumbnail_name_flags thumbnail_flags)
{
struct playlist_entry *entry = NULL;
if (!playlist || idx >= RBUF_LEN(playlist->entries))
return;
entry = &playlist->entries[idx];
entry->thumbnail_flags |= thumbnail_flags;
}
enum playlist_thumbnail_name_flags playlist_get_curr_thumbnail_name_flag(playlist_t *playlist, size_t idx)
{
struct playlist_entry *entry = NULL;
if (!playlist || idx >= RBUF_LEN(playlist->entries))
return PLAYLIST_THUMBNAIL_FLAG_NONE;
entry = &playlist->entries[idx];
return entry->thumbnail_flags;
}
enum playlist_thumbnail_name_flags playlist_get_next_thumbnail_name_flag(playlist_t *playlist, size_t idx)
{
struct playlist_entry *entry = NULL;
if (!playlist || idx >= RBUF_LEN(playlist->entries))
return PLAYLIST_THUMBNAIL_FLAG_NONE;
entry = &playlist->entries[idx];
if (entry->thumbnail_flags & PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME)
return PLAYLIST_THUMBNAIL_FLAG_NONE;
if (entry->thumbnail_flags & PLAYLIST_THUMBNAIL_FLAG_STD_NAME)
return PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME;
if (entry->thumbnail_flags & PLAYLIST_THUMBNAIL_FLAG_FULL_NAME)
return PLAYLIST_THUMBNAIL_FLAG_STD_NAME;
return PLAYLIST_THUMBNAIL_FLAG_FULL_NAME;
}
/**
* playlist_resolve_path:
* @mode : PLAYLIST_LOAD or PLAYLIST_SAVE

View file

@ -87,6 +87,15 @@ enum playlist_thumbnail_id
PLAYLIST_THUMBNAIL_LEFT
};
enum playlist_thumbnail_name_flags
{
PLAYLIST_THUMBNAIL_FLAG_INVALID = 0,
PLAYLIST_THUMBNAIL_FLAG_FULL_NAME = (1 << 0),
PLAYLIST_THUMBNAIL_FLAG_STD_NAME = (1 << 1),
PLAYLIST_THUMBNAIL_FLAG_SHORT_NAME = (1 << 2),
PLAYLIST_THUMBNAIL_FLAG_NONE = (1 << 3)
};
typedef struct content_playlist playlist_t;
/* Holds all parameters required to uniquely
@ -129,6 +138,7 @@ struct playlist_entry
unsigned last_played_minute;
unsigned last_played_second;
enum playlist_runtime_status runtime_status;
enum playlist_thumbnail_name_flags thumbnail_flags;
};
/* Holds all configuration parameters required
@ -291,6 +301,11 @@ void playlist_update_runtime(playlist_t *playlist, size_t idx,
const struct playlist_entry *update_entry,
bool register_update);
void playlist_update_thumbnail_name_flag(playlist_t *playlist, size_t idx,
enum playlist_thumbnail_name_flags thumbnail_flags);
enum playlist_thumbnail_name_flags playlist_get_next_thumbnail_name_flag(playlist_t *playlist, size_t idx);
enum playlist_thumbnail_name_flags playlist_get_curr_thumbnail_name_flag(playlist_t *playlist, size_t idx);
void playlist_get_index_by_path(playlist_t *playlist,
const char *search_path,
const struct playlist_entry **entry);

View file

@ -74,7 +74,8 @@ typedef struct pl_thumb_handle
unsigned type_idx;
enum pl_thumb_status status;
enum playlist_thumbnail_name_flags name_flags;
uint8_t flags;
} pl_thumb_handle_t;
@ -155,7 +156,7 @@ static bool get_thumbnail_paths(
/* Extract required strings */
gfx_thumbnail_get_system( pl_thumb->thumbnail_path_data, &system);
gfx_thumbnail_get_db_name(pl_thumb->thumbnail_path_data, &db_name);
if (!gfx_thumbnail_get_img_name(pl_thumb->thumbnail_path_data, &img_name))
if (!gfx_thumbnail_get_img_name(pl_thumb->thumbnail_path_data, &img_name, pl_thumb->name_flags))
return false;
if (!gfx_thumbnail_get_sub_directory(pl_thumb->type_idx, &sub_dir))
return false;
@ -816,7 +817,8 @@ bool task_push_pl_entry_thumbnail_download(
gfx_thumbnail_path_data_t *
thumbnail_path_data = NULL;
const char *dir_thumbnails = NULL;
enum playlist_thumbnail_name_flags curr_flag = PLAYLIST_THUMBNAIL_FLAG_INVALID;
/* Sanity check */
if (!settings || !task || !pl_thumb || !playlist || !entry_id)
goto error;
@ -871,7 +873,11 @@ bool task_push_pl_entry_thumbnail_download(
if (!gfx_thumbnail_set_content_playlist(
thumbnail_path_data, playlist, idx))
goto error;
curr_flag = playlist_get_curr_thumbnail_name_flag(playlist,idx);
if (curr_flag == PLAYLIST_THUMBNAIL_FLAG_NONE)
goto error;
/* Configure handle
* > Note: playlist_config is unused by this task */
pl_thumb->system = NULL;
@ -883,6 +889,7 @@ bool task_push_pl_entry_thumbnail_download(
pl_thumb->list_size = playlist_size(playlist);
pl_thumb->list_index = idx;
pl_thumb->type_idx = 1;
pl_thumb->name_flags = curr_flag;
pl_thumb->status = PL_THUMB_BEGIN;
if (overwrite)