Merge of manual and autoscan

Scanning options are unified for a single operation, which can be
customized to cover previous autoscan, manual scan, DAT scan, and
a lot of combinations in-between.

More details in the pull request.
This commit is contained in:
zoltanvb authored and LibretroAdmin committed 2026-04-06 19:11:06 +02:00
1 parent fe27d9d7b0
commit 2fdf736d51
15 files changed
+1356 -733

No files matched your search

+1 -1
View File
@@ -432,6 +432,7 @@ OBJ += \
$(LIBRETRO_COMM_DIR)/playlists/label_sanitization.o \
$(LIBRETRO_COMM_DIR)/time/rtime.o \
manual_content_scan.o \
tasks/task_database.o \
disk_control_interface.o
ifeq ($(HAVE_CONFIGFILE), 1)
@@ -581,7 +582,6 @@ ifeq ($(HAVE_LIBRETRODB), 1)
libretro-db/rmsgpack.o \
libretro-db/rmsgpack_dom.o \
database_info.o \
tasks/task_database.o \
tasks/task_database_cue.o
ifeq ($(HAVE_MENU), 1)
+15 -12
View File
@@ -23,11 +23,13 @@
#include <file/file_path.h>
#include <lists/string_list.h>
#include <lists/dir_list.h>
#include <string/stdstring.h>
#include "libretro-db/libretrodb.h"
#include "core_info.h"
#include "database_info.h"
#include "manual_content_scan.h"
int database_info_build_query_enum(char *s, size_t len,
enum database_query_type type,
@@ -860,8 +862,9 @@ static int dir_entry_compare(const void *left, const void *right)
}
database_info_handle_t *database_info_dir_init(const char *dir,
enum database_type type, retro_task_t *task,
bool show_hidden_files)
enum database_type type, char *file_exts,
bool show_hidden_files, bool recursive, bool include_archive,
struct string_list **content_list)
{
core_info_list_t *core_info_list = NULL;
struct string_list *list = NULL;
@@ -871,11 +874,13 @@ database_info_handle_t *database_info_dir_init(const char *dir,
if (!db)
return NULL;
core_info_get_list(&core_info_list);
/* File list will include all supported files, unless extension list is given */
if (string_is_empty(file_exts))
core_info_get_list(&core_info_list);
if (!(list = dir_list_new(dir, core_info_list ? core_info_list->all_ext : NULL,
if (!(list = dir_list_new(dir, core_info_list ? core_info_list->all_ext : file_exts,
false, show_hidden_files,
false, true)))
include_archive, recursive)))
{
free(db);
return NULL;
@@ -886,14 +891,13 @@ database_info_handle_t *database_info_dir_init(const char *dir,
db->status = DATABASE_STATUS_ITERATE;
db->type = type;
db->list_ptr = 0;
db->list = list;
*content_list = list;
return db;
}
database_info_handle_t *database_info_file_init(const char *path,
enum database_type type, retro_task_t *task)
enum database_type type, retro_task_t *task, struct string_list **content_list)
{
union string_list_elem_attr attr;
struct string_list *list = NULL;
@@ -914,16 +918,15 @@ database_info_handle_t *database_info_file_init(const char *path,
db->status = DATABASE_STATUS_ITERATE;
db->type = type;
db->list_ptr = 0;
db->list = list;
*content_list = list;
return db;
}
void database_info_free(database_info_handle_t *db)
{
if (db)
string_list_free(db->list);
/* if (db)
string_list_free(db->list);*/
}
database_info_list_t *database_info_list_new(
+4 -5
View File
@@ -75,8 +75,6 @@ enum database_query_type
typedef struct
{
struct string_list *list;
size_t list_ptr;
enum database_status status;
enum database_type type;
} database_info_handle_t;
@@ -145,11 +143,12 @@ database_info_list_t *database_info_list_new(const char *rdb_path,
void database_info_list_free(database_info_list_t *list);
database_info_handle_t *database_info_dir_init(const char *dir,
enum database_type type, retro_task_t *task,
bool show_hidden_files);
enum database_type type, char* file_exts,
bool show_hidden_files, bool recursive, bool include_archive,
struct string_list **content_list);
database_info_handle_t *database_info_file_init(const char *path,
enum database_type type, retro_task_t *task);
enum database_type type, retro_task_t *task, struct string_list **content_list);
void database_info_free(database_info_handle_t *handle);
+10 -10
View File
@@ -8073,7 +8073,7 @@ MSG_HASH(
)
MSG_HASH(
MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST,
"Add new content and remove invalid entries by repeating the 'Manual Scan' operation last used to create or edit the playlist."
"Add new content and remove invalid entries by repeating the content scan operation last used to create or edit the playlist."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_DELETE_PLAYLIST,
@@ -8670,11 +8670,11 @@ MSG_HASH(
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_LIST,
"Manual Scan"
"Content Scan"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_LIST,
"Configurable scan based on content file names. Does not require content to match the database."
"Configurable scan based on content file names and/or database match."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_SCAN_ENTRY,
@@ -8740,31 +8740,31 @@ MSG_HASH(
"Add to Mixer and Play"
)
/* Import Content > Manual Scan */
/* Import Content > Content Scan */
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DIR,
"Content Directory"
"Content Location"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_DIR,
"Select a directory to scan for content."
"Select a directory (or file) to scan for content."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME,
"System Name"
"Target Playlist"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME,
"Specify a 'system name' with which to associate scanned content. Used to name to the generated playlist file and to identify playlist thumbnails."
"Name of the generated playlist file, also used to identify playlist thumbnails. Automatic setting will use the same name as the matching database or content directory."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM,
"Custom System Name"
"Custom Playlist Name"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM,
"Manually specify a 'system name' for scanned content. Only used when 'System Name' is set to '<Custom>'."
"Custom playlist name for scanned content."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_CORE_NAME,
+296 -101
View File
@@ -39,8 +39,11 @@
* with a manual content scan */
typedef struct
{
enum manual_content_scan_method scan_method;
enum manual_content_scan_system_name_type system_name_type;
enum manual_content_scan_core_type core_type;
enum manual_content_scan_db_usage db_usage;
enum manual_content_scan_db_selection db_selection;
char core_path[PATH_MAX_LENGTH];
char file_exts_core[PATH_MAX_LENGTH];
@@ -54,6 +57,8 @@ typedef struct
bool search_recursively;
bool search_archives;
bool scan_single_file;
bool omit_db_ref;
bool filter_dat_content;
bool overwrite_playlist;
bool validate_entries;
@@ -70,19 +75,24 @@ typedef struct
* are not thread safe, but we only access them when pushing a
* task, not in the task thread itself, so all is well) */
static scan_settings_t scan_settings = {
MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR, /* system_name_type */
MANUAL_CONTENT_SCAN_METHOD_AUTOMATIC, /* scan method */
MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO, /* system_name_type */
MANUAL_CONTENT_SCAN_CORE_DETECT, /* core_type */
MANUAL_CONTENT_SCAN_USE_DB_STRICT,
MANUAL_CONTENT_SCAN_SELECT_DB_AUTO,
"", /* core_path */
"", /* file_exts_core */
"", /* file_exts_custom */
"", /* dat_file_path */
"", /* content_dir */
"", /* system_name_content_dir */
"", /* system_name_database */
"", /* system_name_custom */
"", /* core_name */
"", /* core_path */
"", /* file_exts_core */
"", /* file_exts_custom */
"", /* dat_file_path */
true, /* search_recursively */
false, /* search_archives */
true, /* search_archives */
false,
false,
false, /* filter_dat_content */
false, /* overwrite_playlist */
false /* validate_entries */
@@ -103,12 +113,12 @@ char *manual_content_scan_get_content_dir_ptr(void)
unsigned manual_content_scan_get_scan_method_enum(void)
{
return 0;
return scan_settings.scan_method;
}
unsigned manual_content_scan_get_scan_use_db_enum(void)
{
return 0;
return scan_settings.db_usage;
}
/* Returns a pointer to the internal
@@ -169,12 +179,12 @@ bool *manual_content_scan_get_search_archives_ptr(void)
bool *manual_content_scan_get_scan_single_file_ptr(void)
{
return NULL;
return &scan_settings.scan_single_file;
}
bool *manual_content_scan_get_omit_db_ref_ptr(void)
{
return NULL;
return &scan_settings.omit_db_ref;
}
/* Returns a pointer to the internal
@@ -312,9 +322,6 @@ bool manual_content_scan_set_menu_content_dir(const char *content_dir)
if (string_is_empty(content_dir))
goto error;
if (!path_is_directory(content_dir))
goto error;
/* Copy directory path to settings struct.
* Remove trailing slash, if required */
if ((_len = strlcpy(
@@ -357,19 +364,55 @@ error:
bool manual_content_scan_set_menu_scan_method(
enum manual_content_scan_method method)
{
scan_settings.scan_method = method;
return true;
}
bool manual_content_scan_set_menu_scan_use_db(
enum manual_content_scan_db_usage usage)
{
return true;
if (usage <= MANUAL_CONTENT_SCAN_USE_DB_NONE)
{
scan_settings.db_usage = usage;
return true;
}
else
{
scan_settings.db_usage = MANUAL_CONTENT_SCAN_USE_DB_NONE;
return false;
}
}
bool manual_content_scan_set_menu_scan_db_select(
enum manual_content_scan_db_selection select,
const char *db_name)
{
if (select == MANUAL_CONTENT_SCAN_SELECT_DB_AUTO ||
select == MANUAL_CONTENT_SCAN_SELECT_DB_AUTO_FIRST_MATCH)
{
scan_settings.db_selection = select;
/*scan_settings.system_name_database[0] = '\0';*/
}
else
{
/* We are using a database name... */
if (string_is_empty(db_name))
goto error;
scan_settings.db_selection = MANUAL_CONTENT_SCAN_SELECT_DB_SPECIFIC;
/* Copy database name to settings struct */
strlcpy(
scan_settings.system_name_database,
db_name,
sizeof(scan_settings.system_name_database));
}
return true;
error:
/* Input parameters are invalid - reset internal
* 'system_name_type' and 'system_name_database' */
scan_settings.db_selection = MANUAL_CONTENT_SCAN_SELECT_DB_AUTO;
scan_settings.system_name_database[0] = '\0';
return false;
}
@@ -396,8 +439,10 @@ bool manual_content_scan_set_menu_system_name(
/* Check if we are using a non-database name */
if ((scan_settings.system_name_type == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR) ||
(scan_settings.system_name_type == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM))
scan_settings.system_name_database[0] = '\0';
(scan_settings.system_name_type == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM) ||
(scan_settings.system_name_type == MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO))
/* No-op. Keep the existing system_name_database. */
;
else
{
/* We are using a database name... */
@@ -416,7 +461,7 @@ bool manual_content_scan_set_menu_system_name(
error:
/* Input parameters are invalid - reset internal
* 'system_name_type' and 'system_name_database' */
scan_settings.system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR;
scan_settings.system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO;
scan_settings.system_name_database[0] = '\0';
return false;
}
@@ -547,10 +592,13 @@ enum manual_content_scan_playlist_refresh_status
const char *core_name = NULL;
const char *file_exts = NULL;
const char *dat_file_path = NULL;
const char *database_name_lpl = NULL;
bool search_recursively = false;
bool search_archives = false;
bool filter_dat_content = false;
bool overwrite_playlist = false;
bool omit_db_ref = false;
int db_usage = MANUAL_CONTENT_SCAN_USE_DB_NONE;
#ifdef HAVE_LIBRETRODB
struct string_list *rdb_list = NULL;
#endif
@@ -559,6 +607,7 @@ enum manual_content_scan_playlist_refresh_status
enum manual_content_scan_core_type
core_type = MANUAL_CONTENT_SCAN_CORE_DETECT;
char system_name[NAME_MAX_LENGTH];
char database_name[NAME_MAX_LENGTH];
if (!playlist_scan_refresh_enabled(playlist))
return MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_MISSING_CONFIG;
@@ -569,11 +618,14 @@ enum manual_content_scan_playlist_refresh_status
core_name = playlist_get_default_core_name(playlist);
file_exts = playlist_get_scan_file_exts(playlist);
dat_file_path = playlist_get_scan_dat_file_path(playlist);
database_name_lpl = playlist_get_scan_database_name(playlist);
search_recursively = playlist_get_scan_search_recursively(playlist);
search_archives = playlist_get_scan_search_archives(playlist);
filter_dat_content = playlist_get_scan_filter_dat_content(playlist);
overwrite_playlist = playlist_get_scan_overwrite_playlist(playlist);
omit_db_ref = playlist_get_scan_omit_db_ref(playlist);
db_usage = playlist_get_scan_db_usage(playlist);
/* Determine system name (playlist basename
* without extension) */
@@ -585,6 +637,8 @@ enum manual_content_scan_playlist_refresh_status
fill_pathname(system_name, path_basename(playlist_path),
"", sizeof(system_name));
if (database_name_lpl && !string_is_empty(database_name_lpl))
fill_pathname(database_name,database_name_lpl,"",sizeof(database_name));
/* Cannot happen, but would constitute a
* 'system name' error */
if (string_is_empty(system_name))
@@ -594,6 +648,11 @@ enum manual_content_scan_playlist_refresh_status
if (!manual_content_scan_set_menu_content_dir(content_dir))
return MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_INVALID_CONTENT_DIR;
if (!manual_content_scan_set_menu_scan_use_db(db_usage))
return MANUAL_CONTENT_SCAN_PLAYLIST_REFRESH_MISSING_CONFIG;
scan_settings.db_selection = MANUAL_CONTENT_SCAN_SELECT_DB_AUTO;
/* Set system name */
#ifdef HAVE_LIBRETRODB
/* > If platform has database support, get names
@@ -623,8 +682,17 @@ enum manual_content_scan_playlist_refresh_status
if (string_is_equal(system_name, rdb_name))
{
system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE;
strlcpy(scan_settings.system_name_database, system_name,
sizeof(scan_settings.system_name_database));
scan_settings.db_selection = MANUAL_CONTENT_SCAN_SELECT_DB_SPECIFIC;
break;
}
if (string_is_equal(database_name, rdb_name))
{
strlcpy(scan_settings.system_name_database, database_name,
sizeof(scan_settings.system_name_database));
scan_settings.db_selection = MANUAL_CONTENT_SCAN_SELECT_DB_SPECIFIC;
}
}
}
@@ -712,6 +780,8 @@ enum manual_content_scan_playlist_refresh_status
scan_settings.search_archives = search_archives;
scan_settings.filter_dat_content = filter_dat_content;
scan_settings.overwrite_playlist = overwrite_playlist;
scan_settings.omit_db_ref = omit_db_ref;
scan_settings.scan_method = MANUAL_CONTENT_SCAN_METHOD_CUSTOM;
/* When refreshing a playlist:
* > We always validate entries in the
* existing file */
@@ -737,21 +807,88 @@ bool manual_content_scan_get_menu_content_dir(const char **content_dir)
bool manual_content_scan_get_menu_scan_method(const char **scan_method)
{
if (scan_method)
{
switch (scan_settings.scan_method)
{
case MANUAL_CONTENT_SCAN_METHOD_AUTOMATIC:
*scan_method = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_METHOD_AUTO);
return true;
case MANUAL_CONTENT_SCAN_METHOD_CUSTOM:
*scan_method = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_METHOD_CUSTOM);
return true;
default:
break;
}
}
return false;
}
bool manual_content_scan_get_menu_scan_use_db(const char **scan_use_db)
{
if (scan_use_db)
{
switch (scan_settings.db_usage)
{
case MANUAL_CONTENT_SCAN_USE_DB_STRICT:
*scan_use_db = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_USE_DB_STRICT);
return true;
case MANUAL_CONTENT_SCAN_USE_DB_LOOSE:
*scan_use_db = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_USE_DB_LOOSE);
return true;
case MANUAL_CONTENT_SCAN_USE_DB_DAT_STRICT:
*scan_use_db = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_USE_DB_CUSTOM_DAT);
return true;
case MANUAL_CONTENT_SCAN_USE_DB_DAT_LOOSE:
*scan_use_db = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_USE_DB_CUSTOM_DAT_LOOSE);
return true;
case MANUAL_CONTENT_SCAN_USE_DB_NONE:
*scan_use_db = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_USE_DB_NONE);
return true;
default:
break;
}
}
return false;
}
unsigned manual_content_scan_get_scan_db_select_enum(void)
{
return 0;
return scan_settings.db_selection;
}
bool manual_content_scan_get_menu_scan_db_select(const char **scan_db_select)
{
if (scan_db_select)
{
switch (scan_settings.db_selection)
{
case MANUAL_CONTENT_SCAN_SELECT_DB_AUTO:
*scan_db_select = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_DB_SELECT_AUTO_ANY);
return true;
case MANUAL_CONTENT_SCAN_SELECT_DB_AUTO_FIRST_MATCH:
*scan_db_select = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_DB_SELECT_AUTO_FIRST);
return true;
case MANUAL_CONTENT_SCAN_SELECT_DB_SPECIFIC:
if (!string_is_empty(scan_settings.system_name_database))
{
*scan_db_select = scan_settings.system_name_database;
return true;
}
break;
default:
break;
}
}
return false;
}
@@ -774,6 +911,11 @@ bool manual_content_scan_get_menu_system_name(const char **system_name)
*system_name = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME_USE_CUSTOM);
return true;
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO:
*system_name = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME_USE_AUTO);
return true;
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE:
if (!string_is_empty(scan_settings.system_name_database))
{
@@ -791,7 +933,7 @@ bool manual_content_scan_get_menu_system_name(const char **system_name)
unsigned manual_content_scan_get_menu_system_name_type(void)
{
return 0;
return scan_settings.system_name_type;
}
/* Fetches core name for the next manual scan operation.
* Returns true if core name is valid. */
@@ -825,6 +967,28 @@ bool manual_content_scan_get_menu_core_name(const char **core_name)
struct string_list *manual_content_scan_get_menu_scan_method_list(void)
{
union string_list_elem_attr attr;
struct string_list *name_list = string_list_new();
/* Sanity check */
if (!name_list)
return NULL;
attr.i = 0;
if (!string_list_append(name_list, msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_METHOD_AUTO), attr))
goto error;
if (!string_list_append(name_list, msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_SCAN_METHOD_CUSTOM), attr))
goto error;
return name_list;
error:
if (name_list)
string_list_free(name_list);
return NULL;
}
@@ -971,6 +1135,11 @@ struct string_list *manual_content_scan_get_menu_system_name_list(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME_USE_CUSTOM), attr))
goto error;
/* Add 'use custom' entry */
if (!string_list_append(name_list, msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME_USE_AUTO), attr))
goto error;
#ifdef HAVE_LIBRETRODB
/* If platform has database support, get names
* of all installed database files */
@@ -1103,19 +1272,44 @@ bool manual_content_scan_get_task_config(
task_config->file_exts[0] = '\0';
task_config->dat_file_path[0] = '\0';
/* Ensure defaults for "fully automatic" method. */
if (scan_settings.scan_method == MANUAL_CONTENT_SCAN_METHOD_AUTOMATIC)
{
/* Not all settings are zeroed, but the list below should ensure a consistent task setup */
scan_settings.system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO;
scan_settings.core_type = MANUAL_CONTENT_SCAN_CORE_DETECT;
scan_settings.db_usage = MANUAL_CONTENT_SCAN_USE_DB_STRICT;
scan_settings.db_selection = MANUAL_CONTENT_SCAN_SELECT_DB_AUTO;
scan_settings.file_exts_custom[0] = '\0';
scan_settings.search_recursively = true;
scan_settings.search_archives = true;
scan_settings.scan_single_file = false;
}
/* Get content directory */
if (string_is_empty(scan_settings.content_dir))
return false;
if (!path_is_directory(scan_settings.content_dir))
return false;
scan_settings.scan_single_file = true;
else
scan_settings.scan_single_file = false;
strlcpy(
task_config->content_dir,
scan_settings.content_dir,
sizeof(task_config->content_dir));
/* Get system name */
/* If name is set as automatic, but is predictable, fill it now. */
if (scan_settings.system_name_type == MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO)
{
if (scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_DAT_STRICT ||
scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_DAT_LOOSE ||
scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_NONE)
scan_settings.system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR;
else if (scan_settings.db_selection == MANUAL_CONTENT_SCAN_SELECT_DB_SPECIFIC)
scan_settings.system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE;
}
/* Get target playlist ("system name") */
switch (scan_settings.system_name_type)
{
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR:
@@ -1125,6 +1319,7 @@ bool manual_content_scan_get_task_config(
task_config->system_name,
scan_settings.system_name_content_dir,
sizeof(task_config->system_name));
task_config->target_is_single_determined_playlist = true;
break;
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM:
if (string_is_empty(scan_settings.system_name_custom))
@@ -1133,6 +1328,7 @@ bool manual_content_scan_get_task_config(
task_config->system_name,
scan_settings.system_name_custom,
sizeof(task_config->system_name));
task_config->target_is_single_determined_playlist = true;
break;
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE:
if (string_is_empty(scan_settings.system_name_database))
@@ -1141,13 +1337,19 @@ bool manual_content_scan_get_task_config(
task_config->system_name,
scan_settings.system_name_database,
sizeof(task_config->system_name));
task_config->target_is_single_determined_playlist = true;
break;
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO:
/* Leave it as empty intentionally. */
task_config->target_is_single_determined_playlist = false;
break;
default:
return false;
}
/* Now we have a valid system name, can generate
* a 'database' name... */
/* Store database name and playlist path, depending on scan settings */
/* Old manual scan method: db name == target playlist */
fill_pathname(
task_config->database_name,
task_config->system_name,
@@ -1168,6 +1370,34 @@ bool manual_content_scan_get_task_config(
if (string_is_empty(task_config->playlist_file))
return false;
if (scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_LOOSE)
{
/* Pass the selected DB name to the task if there is one */
if (scan_settings.db_selection == MANUAL_CONTENT_SCAN_SELECT_DB_SPECIFIC)
{
fill_pathname(
task_config->database_name,
scan_settings.system_name_database,
".lpl",
sizeof(task_config->database_name));
}
/* Or make it empty (auto DB select case). The omit_db_ref is handled elsewhere. */
else
{
task_config->database_name[0] = '\0';
if (scan_settings.system_name_type == MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO)
task_config->playlist_file[0] = '\0';
/* Abuse dat_file_path for a convenient placeholder value */
fill_pathname(
task_config->dat_file_path,
scan_settings.system_name_content_dir,
".lpl",
sizeof(task_config->dat_file_path));
}
}
/* Get core name and path */
switch (scan_settings.core_type)
{
@@ -1198,6 +1428,7 @@ bool manual_content_scan_get_task_config(
}
/* Get file extensions list */
/* Possible improvement: if DB is set (but not core), some filtering may be applied */
task_config->file_exts_custom_set = false;
if (!string_is_empty(scan_settings.file_exts_custom))
{
@@ -1221,7 +1452,9 @@ bool manual_content_scan_get_task_config(
string_replace_all_chars(task_config->file_exts, ' ', '|');
/* Get DAT file path */
if (!string_is_empty(scan_settings.dat_file_path))
if ((scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_DAT_STRICT ||
scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_DAT_LOOSE) &&
!string_is_empty(scan_settings.dat_file_path))
{
if (!logiqx_dat_path_is_valid(scan_settings.dat_file_path, NULL))
return false;
@@ -1235,12 +1468,17 @@ bool manual_content_scan_get_task_config(
task_config->search_recursively = scan_settings.search_recursively;
/* Copy 'search inside archives' setting */
task_config->search_archives = scan_settings.search_archives;
/* Copy 'DAT file filter' setting */
task_config->filter_dat_content = scan_settings.filter_dat_content;
/* Set up filter if DB usage requires */
task_config->filter_dat_content =
(scan_settings.db_usage == MANUAL_CONTENT_SCAN_USE_DB_DAT_STRICT) ? true : false;
/* Copy 'overwrite playlist' setting */
task_config->overwrite_playlist = scan_settings.overwrite_playlist;
/* Copy 'validate_entries' setting */
task_config->validate_entries = scan_settings.validate_entries;
task_config->omit_db_reference = scan_settings.omit_db_ref;
task_config->db_usage = scan_settings.db_usage;
task_config->db_selection = scan_settings.db_selection;
return true;
}
@@ -1277,16 +1515,28 @@ struct string_list *manual_content_scan_get_content_list(
* then compressed files must of course be included */
include_compressed = (!filter_exts || task_config->search_archives);
/* Get directory listing
* > Exclude directories and hidden files */
dir_list = dir_list_new(
task_config->content_dir,
filter_exts ? task_config->file_exts : NULL,
false, /* include_dirs */
false, /* include_hidden */
include_compressed,
task_config->search_recursively
);
if (path_is_directory(task_config->content_dir))
{
/* Get directory listing
* > Exclude directories and hidden files */
dir_list = dir_list_new(
task_config->content_dir,
filter_exts ? task_config->file_exts : NULL,
false, /* include_dirs */
false, /* include_hidden */ /* todo: obey global settings? */
include_compressed,
task_config->search_recursively
);
}
else
{
if ((dir_list = string_list_new()))
{
union string_list_elem_attr attr;
attr.i = 0;
string_list_append(dir_list, task_config->content_dir, attr);
}
}
/* Sanity check */
if (!dir_list || dir_list->size < 1)
@@ -1315,79 +1565,24 @@ bool manual_content_scan_get_playlist_content_path(
const char *content_path, int content_type,
char *s, size_t len)
{
size_t _len;
struct string_list *archive_list = NULL;
/* Sanity check */
if (!task_config || string_is_empty(content_path))
return false;
/* Allow paths inside archives, but do not add directories in or outside of archives. */
if (!path_is_valid(content_path))
{
if(!(string_index_last_occurance(content_path,'#') > 0) ||
(string_index_last_occurance(content_path,'/') + 1 == (int)strlen(content_path)))
return false;
}
if (path_is_directory(content_path))
return false;
/* In all cases, base content path must be
* copied to @s */
_len = strlcpy(s, content_path, len);
/* Check whether this is an archive file
* requiring special attention... */
if ( (content_type == RARCH_COMPRESSED_ARCHIVE)
&& task_config->search_archives)
{
bool filter_exts = !string_is_empty(task_config->file_exts);
const char *archive_file = NULL;
/* Important note:
* > If an archive file of a particular type is
* included in the task_config->file_exts list,
* dir_list_new() will assign it a file type of
* RARCH_PLAIN_FILE
* > Thus we will only reach this point if
* (a) We are not filtering by extension
* (b) This is an archive file type *not*
* already included in the supported
* extensions list
* > These guarantees substantially reduce the
* complexity of the following code... */
/* Get archive file contents */
if (!(archive_list = file_archive_get_file_list(
content_path, filter_exts ? task_config->file_exts : NULL)))
return false;
if (archive_list->size < 1)
goto error;
/* Get first file contained in archive */
dir_list_sort(archive_list, true);
archive_file = archive_list->elems[0].data;
if (string_is_empty(archive_file))
goto error;
/* Have to take care to ensure that we don't make
* a mess of arcade content...
* > If we are filtering by extension, then the
* archive file itself is *not* valid content,
* so link to the first file inside the archive
* > If we are not filtering by extension, then:
* - If archive contains one valid file, assume
* it is a compressed ROM
* - If archive contains multiple files, have to
* assume it is MAME/FBA-style content, where
* only the archive itself is valid */
if (filter_exts || (archive_list->size == 1))
{
/* Build path to file inside archive */
s[ _len] = '#';
s[++_len] = '\0';
strlcpy(s + _len, archive_file, len - _len);
}
string_list_free(archive_list);
}
strlcpy(s, content_path, len);
return true;
error:
if (archive_list)
string_list_free(archive_list);
return false;
/* no need to do all the other magic here any more */
}
/* Extracts content 'label' (name) from content path
+5
View File
@@ -49,6 +49,7 @@ enum manual_content_scan_system_name_type
{
MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR = 0,
MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM,
MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO,
MANUAL_CONTENT_SCAN_SYSTEM_NAME_DATABASE
};
@@ -121,6 +122,10 @@ typedef struct
bool filter_dat_content;
bool overwrite_playlist;
bool validate_entries;
bool omit_db_reference;
bool target_is_single_determined_playlist;
enum manual_content_scan_db_usage db_usage;
enum manual_content_scan_db_selection db_selection;
} manual_content_scan_task_config_t;
/*****************/
+4
View File
@@ -714,6 +714,7 @@ static int manual_content_scan_system_name_left(
unsigned current_index = 0;
unsigned next_index = 0;
unsigned i;
struct menu_state *menu_st = menu_state_get_ptr();
if (!system_name_list)
return -1;
@@ -745,12 +746,15 @@ static int manual_content_scan_system_name_left(
next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR;
else if (next_index == (unsigned)MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM)
next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM;
else if (next_index == (unsigned)MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO)
next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO;
next_system_name = system_name_list->elems[next_index].data;
/* Set system name */
manual_content_scan_set_menu_system_name(
next_system_name_type, next_system_name);
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH;
/* Clean up */
string_list_free(system_name_list);
+38 -15
View File
@@ -1297,11 +1297,20 @@ int generic_action_ok_displaylist_push(
dl_type = DISPLAYLIST_FILE_BROWSER_SCAN_DIR;
break;
case ACTION_OK_DL_MANUAL_SCAN_DIR_LIST:
filebrowser_set_type(FILEBROWSER_MANUAL_SCAN_DIR);
info.type = FILE_TYPE_DIRECTORY;
if (*(manual_content_scan_get_scan_single_file_ptr()) == true)
{
filebrowser_set_type(FILEBROWSER_SCAN_FILE);
info.type = FILE_TYPE_PLAIN;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_FILE;
}
else
{
filebrowser_set_type(FILEBROWSER_MANUAL_SCAN_DIR);
info.type = FILE_TYPE_DIRECTORY;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_DIR;
}
info.directory_ptr = idx;
info_label = label;
dl_type = DISPLAYLIST_FILE_BROWSER_SELECT_DIR;
action_ok_get_file_browser_start_path(
manual_content_scan_get_content_dir_ptr(),
@@ -4239,21 +4248,38 @@ static int action_ok_path_scan_directory(const char *path,
static int action_ok_path_manual_scan_directory(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#if IOS
char dir_path[DIR_MAX_LENGTH];
#endif
char content_dir[DIR_MAX_LENGTH];
unsigned flush_type = 0;
const char *menu_path = NULL;
content_dir[0] = '\0';
if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE)
{
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
#if IOS
fill_pathname_expand_special(dir_path, menu_path, sizeof(dir_path));
menu_path = dir_path;
#endif
fill_pathname_join_special(content_dir, menu_path, path, sizeof(content_dir));
}
else
{
/* Get user-selected scan directory */
menu_entries_get_last_stack(&menu_path,
NULL, NULL, NULL, NULL);
if (!string_is_empty(menu_path))
strlcpy(content_dir, menu_path, sizeof(content_dir));
}
/* 'Reset' file browser */
filebrowser_clear_type();
/* Get user-selected scan directory */
menu_entries_get_last_stack(&menu_path,
NULL, NULL, NULL, NULL);
if (!string_is_empty(menu_path))
strlcpy(content_dir, menu_path, sizeof(content_dir));
#ifdef HAVE_COCOATOUCH
{
@@ -7580,6 +7606,7 @@ static int action_ok_push_dropdown_item_manual_content_scan_system_name(
{
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR:
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM:
case MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO:
system_name_type = (enum manual_content_scan_system_name_type)idx;
break;
default:
@@ -9915,9 +9942,7 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
case FILE_TYPE_CARCHIVE:
if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE)
{
#ifdef HAVE_LIBRETRODB
BIND_ACTION_OK(cbs, action_ok_scan_file);
#endif
BIND_ACTION_OK(cbs, action_ok_path_manual_scan_directory);
}
#ifdef HAVE_COMPRESSION
else if (filebrowser_get_type() == FILEBROWSER_SELECT_OVERLAY)
@@ -10079,9 +10104,7 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
case FILE_TYPE_PLAIN:
if (filebrowser_get_type() == FILEBROWSER_SCAN_FILE)
{
#ifdef HAVE_LIBRETRODB
BIND_ACTION_OK(cbs, action_ok_scan_file);
#endif
BIND_ACTION_OK(cbs, action_ok_path_manual_scan_directory);
}
else if (cbs->enum_idx != MSG_UNKNOWN)
{
+4
View File
@@ -851,6 +851,7 @@ static int manual_content_scan_system_name_right(unsigned type, const char *labe
unsigned current_index = 0;
unsigned next_index = 0;
unsigned i;
struct menu_state *menu_st = menu_state_get_ptr();
if (!system_name_list)
return -1;
@@ -885,12 +886,15 @@ static int manual_content_scan_system_name_right(unsigned type, const char *labe
next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR;
else if (next_index == (unsigned)MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM)
next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM;
else if (next_index == (unsigned)MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO)
next_system_name_type = MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO;
next_system_name = system_name_list->elems[next_index].data;
/* Set system name */
manual_content_scan_set_menu_system_name(
next_system_name_type, next_system_name);
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH;
/* Clean up */
string_list_free(system_name_list);
+3 -1
View File
@@ -568,9 +568,11 @@ static int action_start_manual_content_scan_system_name(
const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
struct menu_state *menu_st = menu_state_get_ptr();
/* Reset system name */
manual_content_scan_set_menu_system_name(
MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR, "");
MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO, "");
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH;
return 0;
}
+135 -54
View File
@@ -6532,70 +6532,151 @@ static unsigned menu_displaylist_parse_manual_content_scan_list(
MENU_SETTING_MANUAL_CONTENT_SCAN_DIR, 0, 0, NULL))
count++;
/* System name */
/* Scan method - automatic or custom (more entries) */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME,
MENU_SETTING_MANUAL_CONTENT_SCAN_SYSTEM_NAME, 0, 0, NULL))
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_METHOD),
msg_hash_to_str(MENU_ENUM_LABEL_SCAN_METHOD),
MENU_ENUM_LABEL_SCAN_METHOD,
MENU_SETTING_SCAN_METHOD, 0, 0, NULL))
count++;
/* Custom system name */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM, PARSE_ONLY_STRING,
false) == 0)
count++;
if (manual_content_scan_get_scan_method_enum() == MANUAL_CONTENT_SCAN_METHOD_CUSTOM)
{
/* DB usage - matching strategy */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_USE_DB),
msg_hash_to_str(MENU_ENUM_LABEL_SCAN_USE_DB),
MENU_ENUM_LABEL_SCAN_USE_DB,
MENU_SETTING_SCAN_USE_DB, 0, 0, NULL))
count++;
/* Core name */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_CORE_NAME),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME,
MENU_SETTING_MANUAL_CONTENT_SCAN_CORE_NAME, 0, 0, NULL))
count++;
if (manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_DAT_LOOSE ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_DAT_STRICT)
{
/* Arcade DAT file - only if DAT file is used*/
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DAT_FILE, PARSE_ONLY_PATH,
false) == 0)
count++;
}
else if (manual_content_scan_get_scan_use_db_enum() != MANUAL_CONTENT_SCAN_USE_DB_NONE)
{
/* Database selection */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DB_SELECT),
msg_hash_to_str(MENU_ENUM_LABEL_SCAN_DB_SELECT),
MENU_ENUM_LABEL_SCAN_DB_SELECT,
MENU_SETTING_SCAN_DB_SELECT, 0, 0, NULL))
count++;
}
/* File extensions */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_FILE_EXTS, PARSE_ONLY_STRING,
false) == 0)
count++;
/* Target playlist (system name in old terminology) */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME),
msg_hash_to_str(MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME,
MENU_SETTING_MANUAL_CONTENT_SCAN_SYSTEM_NAME, 0, 0, NULL))
count++;
/* Search recursively */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_RECURSIVELY, PARSE_ONLY_BOOL,
false) == 0)
count++;
if (manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM)
{
/* Custom target playlist */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM, PARSE_ONLY_STRING,
false) == 0)
count++;
}
if (manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM ||
manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR)
{
/* DB reference skipping only makes sense if there is a DB used */
if (manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_LOOSE)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_OMIT_DB_REF, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
}
/* Search inside archive files */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Core name */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_CORE_NAME),
msg_hash_to_str(MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME,
MENU_SETTING_MANUAL_CONTENT_SCAN_CORE_NAME, 0, 0, NULL))
count++;
/* Arcade DAT file */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DAT_FILE, PARSE_ONLY_PATH,
false) == 0)
count++;
/* File extensions */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_FILE_EXTS, PARSE_ONLY_STRING,
false) == 0)
count++;
/* Arcade DAT filter */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DAT_FILE_FILTER, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Search recursively */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_RECURSIVELY, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Overwrite playlist */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_OVERWRITE, PARSE_ONLY_BOOL,
false) == 0)
count++;
if (*(manual_content_scan_get_search_recursively_ptr()) == false)
{
/* Scan only one file */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_SINGLE_FILE, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
/* Validate existing entries */
if (!(*manual_content_scan_get_overwrite_playlist_ptr())
&& MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_VALIDATE_ENTRIES, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Search inside archive files */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Arcade DAT filter is merged with DB usage setting */
/* Hiding validate / overwrite in cases when target playlist can not be determined in advance */
if ((manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_LOOSE) &&
(manual_content_scan_get_scan_db_select_enum() == MANUAL_CONTENT_SCAN_SELECT_DB_AUTO ||
manual_content_scan_get_scan_db_select_enum() == MANUAL_CONTENT_SCAN_SELECT_DB_AUTO_FIRST_MATCH ) &&
manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO)
{
;
}
else
{
/* Overwrite playlist */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_OVERWRITE, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Validate existing entries */
if (!(*manual_content_scan_get_overwrite_playlist_ptr())
&& MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_VALIDATE_ENTRIES, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
}
/* Scan without core match and CRC duplicate check only makes sense if there is a DB used */
if (manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_LOOSE)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_WITHOUT_CORE_MATCH, PARSE_ONLY_BOOL,
false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_SERIAL_AND_CRC, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
/* Start scan */
if (menu_entries_append(info_list,
@@ -7674,7 +7755,7 @@ unsigned menu_displaylist_build_list(
#endif
break;
case DISPLAYLIST_SCAN_DIRECTORY_LIST:
#ifdef HAVE_LIBRETRODB
#if 0
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY),
MENU_ENUM_LABEL_SCAN_DIRECTORY_STR,
+33
View File
@@ -25234,6 +25234,21 @@ static bool setting_append_list(
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_STRING_LINE_EDIT;
(*list)[list_info->index - 1].action_start = setting_generic_action_start_default;
CONFIG_BOOL(
list, list_info,
manual_content_scan_get_omit_db_ref_ptr(),
MENU_ENUM_LABEL_SCAN_OMIT_DB_REF,
MENU_ENUM_LABEL_VALUE_SCAN_OMIT_DB_REF,
false,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE);
CONFIG_STRING(
list, list_info,
manual_content_scan_get_file_exts_custom_ptr(),
@@ -25264,12 +25279,30 @@ static bool setting_append_list(
general_write_handler,
general_read_handler,
SD_FLAG_NONE);
(*list)[list_info->index - 1].action_ok = setting_bool_action_left_with_refresh;
(*list)[list_info->index - 1].action_left = setting_bool_action_left_with_refresh;
(*list)[list_info->index - 1].action_right = setting_bool_action_right_with_refresh;
CONFIG_BOOL(
list, list_info,
manual_content_scan_get_search_archives_ptr(),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES,
MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES,
true,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE);
CONFIG_BOOL(
list, list_info,
manual_content_scan_get_scan_single_file_ptr(),
MENU_ENUM_LABEL_SCAN_SINGLE_FILE,
MENU_ENUM_LABEL_VALUE_SCAN_SINGLE_FILE,
false,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
+119 -1
View File
@@ -55,10 +55,13 @@ typedef struct
char *content_dir;
char *file_exts;
char *dat_file_path;
char *database_name;
bool search_recursively;
bool search_archives;
bool filter_dat_content;
bool overwrite_playlist;
bool omit_db_ref;
int db_usage;
} playlist_manual_scan_record_t;
enum content_playlist_flags
@@ -106,6 +109,7 @@ typedef struct
enum playlist_thumbnail_mode *current_meta_thumbnail_mode_val;
enum playlist_thumbnail_match_mode *current_meta_thumbnail_match_mode_val;
enum playlist_sort_mode *current_meta_sort_mode_val;
unsigned *current_meta_db_usage_val;
bool *current_meta_bool_val;
playlist_t *playlist;
@@ -1686,7 +1690,7 @@ void playlist_write_runtime_file(playlist_t *playlist)
| CNT_PLAYLIST_FLG_OLD_FMT
| CNT_PLAYLIST_FLG_COMPRESSED);
RARCH_LOG("[Playlist] Written to file: \"%s\".\n", playlist->config.path);
RARCH_DBG("[Playlist] Runtime written to file: \"%s\".\n", playlist->config.path);
end:
intfstream_close(file);
free(file);
@@ -1863,6 +1867,14 @@ void playlist_write_file(playlist_t *playlist)
rjsonwriter_add_string(writer, playlist->scan_record.dat_file_path);
rjsonwriter_raw(writer, ",\n", 2);
rjsonwriter_add_spaces(writer, 2);
rjsonwriter_add_string(writer, "scan_database_name");
rjsonwriter_raw(writer, ":", 1);
rjsonwriter_raw(writer, " ", 1);
rjsonwriter_add_string(writer, playlist->scan_record.database_name);
rjsonwriter_raw(writer, ",", 1);
rjsonwriter_raw(writer, "\n", 1);
rjsonwriter_add_spaces(writer, 2);
rjsonwriter_add_string(writer, "scan_search_recursively");
rjsonwriter_raw(writer, ": ", 2);
@@ -1890,6 +1902,17 @@ void playlist_write_file(playlist_t *playlist)
}
rjsonwriter_raw(writer, ",\n", 2);
rjsonwriter_add_spaces(writer, 2);
rjsonwriter_add_string(writer, "scan_omit_db_ref");
rjsonwriter_raw(writer, ":", 1);
rjsonwriter_raw(writer, " ", 1);
{
bool value = playlist->scan_record.omit_db_ref;
rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
}
rjsonwriter_raw(writer, ",", 1);
rjsonwriter_raw(writer, "\n", 1);
rjsonwriter_add_spaces(writer, 2);
rjsonwriter_add_string(writer, "scan_overwrite_playlist");
rjsonwriter_raw(writer, ": ", 2);
@@ -1898,6 +1921,14 @@ void playlist_write_file(playlist_t *playlist)
rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
}
rjsonwriter_raw(writer, ",\n", 2);
rjsonwriter_add_spaces(writer, 2);
rjsonwriter_add_string(writer, "scan_db_usage");
rjsonwriter_raw(writer, ":", 1);
rjsonwriter_raw(writer, " ", 1);
rjsonwriter_rawf(writer, "%d", (int)playlist->scan_record.db_usage);
rjsonwriter_raw(writer, ",", 1);
rjsonwriter_raw(writer, "\n", 1);
}
rjsonwriter_add_spaces(writer, 2);
@@ -2095,6 +2126,10 @@ void playlist_free(playlist_t *playlist)
free(playlist->scan_record.dat_file_path);
playlist->scan_record.dat_file_path = NULL;
if (playlist->scan_record.database_name)
free(playlist->scan_record.database_name);
playlist->scan_record.database_name = NULL;
if (playlist->entries)
{
for (i = 0, _len = RBUF_LEN(playlist->entries); i < _len; i++)
@@ -2337,6 +2372,8 @@ static bool JSONNumberHandler(void *context, const char *pValue, size_t len)
*pCtx->current_meta_thumbnail_match_mode_val = (enum playlist_thumbnail_match_mode)strtoul(pValue, NULL, 10);
else if (pCtx->current_meta_sort_mode_val)
*pCtx->current_meta_sort_mode_val = (enum playlist_sort_mode)strtoul(pValue, NULL, 10);
else if (pCtx->current_meta_db_usage_val)
*pCtx->current_meta_db_usage_val = (enum playlist_sort_mode)strtoul(pValue, NULL, 10);
}
}
}
@@ -2346,6 +2383,7 @@ static bool JSONNumberHandler(void *context, const char *pValue, size_t len)
pCtx->current_meta_thumbnail_mode_val = NULL;
pCtx->current_meta_thumbnail_match_mode_val = NULL;
pCtx->current_meta_sort_mode_val = NULL;
pCtx->current_meta_db_usage_val = NULL;
return true;
}
@@ -2450,6 +2488,7 @@ static bool JSONObjectMemberHandler(void *context, const char *pValue, size_t le
pCtx->current_meta_thumbnail_mode_val = NULL;
pCtx->current_meta_thumbnail_match_mode_val = NULL;
pCtx->current_meta_sort_mode_val = NULL;
pCtx->current_meta_db_usage_val = NULL;
pCtx->current_meta_bool_val = NULL;
pCtx->flags &= ~(JSON_CTX_FLG_IN_ITEMS);
@@ -2486,12 +2525,18 @@ static bool JSONObjectMemberHandler(void *context, const char *pValue, size_t le
pCtx->current_string_val = &pCtx->playlist->scan_record.file_exts;
else if (memcmp(pValue, "scan_dat_file_path", sizeof("scan_dat_file_path")) == 0)
pCtx->current_string_val = &pCtx->playlist->scan_record.dat_file_path;
else if (string_is_equal(pValue, "scan_database_name"))
pCtx->current_string_val = &pCtx->playlist->scan_record.database_name;
else if (memcmp(pValue, "scan_search_recursively", sizeof("scan_search_recursively")) == 0)
pCtx->current_meta_bool_val = &pCtx->playlist->scan_record.search_recursively;
else if (memcmp(pValue, "scan_search_archives", sizeof("scan_search_archives")) == 0)
pCtx->current_meta_bool_val = &pCtx->playlist->scan_record.search_archives;
else if (memcmp(pValue, "scan_filter_dat_content", sizeof("scan_filter_dat_content")) == 0)
pCtx->current_meta_bool_val = &pCtx->playlist->scan_record.filter_dat_content;
else if (string_is_equal(pValue, "scan_omit_db_ref"))
pCtx->current_meta_bool_val = &pCtx->playlist->scan_record.omit_db_ref;
else if (string_is_equal(pValue, "scan_db_usage"))
pCtx->current_meta_db_usage_val = (unsigned int*)&pCtx->playlist->scan_record.db_usage;
else if (memcmp(pValue, "scan_overwrite_playlist", sizeof("scan_overwrite_playlist")) == 0)
pCtx->current_meta_bool_val = &pCtx->playlist->scan_record.overwrite_playlist;
else if (memcmp(pValue, "sort_mode", sizeof("sort_mode")) == 0)
@@ -2872,9 +2917,12 @@ playlist_t *playlist_init(const playlist_config_t *config)
playlist->scan_record.search_recursively = false;
playlist->scan_record.search_archives = false;
playlist->scan_record.filter_dat_content = false;
playlist->scan_record.omit_db_ref = false;
playlist->scan_record.content_dir = NULL;
playlist->scan_record.file_exts = NULL;
playlist->scan_record.dat_file_path = NULL;
playlist->scan_record.database_name = NULL;
playlist->scan_record.db_usage = 4; /*MANUAL_CONTENT_SCAN_USE_DB_NONE*/
/* Cache configuration parameters */
if (!playlist_config_copy(config, &playlist->config))
@@ -3310,6 +3358,13 @@ const char *playlist_get_scan_dat_file_path(playlist_t *playlist)
return playlist->scan_record.dat_file_path;
}
const char *playlist_get_scan_database_name(playlist_t *playlist)
{
if (!playlist)
return NULL;
return playlist->scan_record.database_name;
}
bool playlist_get_scan_search_recursively(playlist_t *playlist)
{
if (!playlist)
@@ -3331,6 +3386,13 @@ bool playlist_get_scan_filter_dat_content(playlist_t *playlist)
return playlist->scan_record.filter_dat_content;
}
bool playlist_get_scan_omit_db_ref(playlist_t *playlist)
{
if (!playlist)
return false;
return playlist->scan_record.omit_db_ref;
}
bool playlist_get_scan_overwrite_playlist(playlist_t *playlist)
{
if (!playlist)
@@ -3338,6 +3400,13 @@ bool playlist_get_scan_overwrite_playlist(playlist_t *playlist)
return playlist->scan_record.overwrite_playlist;
}
int playlist_get_scan_db_usage(playlist_t *playlist)
{
if (!playlist)
return 4;
return playlist->scan_record.db_usage;
}
bool playlist_scan_refresh_enabled(playlist_t *playlist)
{
if (!playlist)
@@ -3534,6 +3603,37 @@ void playlist_set_scan_dat_file_path(playlist_t *playlist, const char *dat_file_
playlist->scan_record.dat_file_path = strdup(dat_file_path);
}
void playlist_set_scan_database_name(playlist_t *playlist, const char *database_name)
{
bool current_string_empty;
bool new_string_empty;
if (!playlist)
return;
current_string_empty = string_is_empty(playlist->scan_record.database_name);
new_string_empty = string_is_empty(database_name);
/* Check whether string value has changed
* (note that a NULL or empty argument will
* unset the playlist value) */
if ( ( current_string_empty && !new_string_empty)
|| (!current_string_empty && new_string_empty)
|| !string_is_equal(playlist->scan_record.database_name, database_name))
playlist->flags |= CNT_PLAYLIST_FLG_MOD;
else
return; /* Strings are identical; do nothing */
if (playlist->scan_record.database_name)
{
free(playlist->scan_record.database_name);
playlist->scan_record.database_name = NULL;
}
if (!new_string_empty)
playlist->scan_record.database_name = strdup(database_name);
}
void playlist_set_scan_search_recursively(playlist_t *playlist, bool search_recursively)
{
if (playlist && playlist->scan_record.search_recursively != search_recursively)
@@ -3561,6 +3661,24 @@ void playlist_set_scan_filter_dat_content(playlist_t *playlist, bool filter_dat_
}
}
void playlist_set_scan_omit_db_ref(playlist_t *playlist, bool omit_db_ref)
{
if (playlist && playlist->scan_record.omit_db_ref != omit_db_ref)
{
playlist->scan_record.omit_db_ref = omit_db_ref;
playlist->flags |= CNT_PLAYLIST_FLG_MOD;
}
}
void playlist_set_scan_db_usage(playlist_t *playlist, int db_usage)
{
if (playlist && playlist->scan_record.db_usage != db_usage)
{
playlist->scan_record.db_usage = db_usage;
playlist->flags |= CNT_PLAYLIST_FLG_MOD;
}
}
void playlist_set_scan_overwrite_playlist(playlist_t *playlist, bool overwrite_playlist)
{
if (playlist && playlist->scan_record.overwrite_playlist != overwrite_playlist)
+6
View File
@@ -385,10 +385,13 @@ enum playlist_sort_mode playlist_get_sort_mode(playlist_t *playlist);
const char *playlist_get_scan_content_dir(playlist_t *playlist);
const char *playlist_get_scan_file_exts(playlist_t *playlist);
const char *playlist_get_scan_dat_file_path(playlist_t *playlist);
const char *playlist_get_scan_database_name(playlist_t *playlist);
bool playlist_get_scan_search_recursively(playlist_t *playlist);
bool playlist_get_scan_search_archives(playlist_t *playlist);
bool playlist_get_scan_filter_dat_content(playlist_t *playlist);
bool playlist_get_scan_omit_db_ref(playlist_t *playlist);
bool playlist_get_scan_overwrite_playlist(playlist_t *playlist);
int playlist_get_scan_db_usage(playlist_t *playlist);
bool playlist_scan_refresh_enabled(playlist_t *playlist);
void playlist_set_default_core_path(playlist_t *playlist, const char *core_path);
@@ -400,10 +403,13 @@ void playlist_set_sort_mode(playlist_t *playlist, enum playlist_sort_mode sort_m
void playlist_set_scan_content_dir(playlist_t *playlist, const char *content_dir);
void playlist_set_scan_file_exts(playlist_t *playlist, const char *file_exts);
void playlist_set_scan_dat_file_path(playlist_t *playlist, const char *dat_file_path);
void playlist_set_scan_database_name(playlist_t *playlist, const char *database_name);
void playlist_set_scan_search_recursively(playlist_t *playlist, bool search_recursively);
void playlist_set_scan_search_archives(playlist_t *playlist, bool search_archives);
void playlist_set_scan_filter_dat_content(playlist_t *playlist, bool filter_dat_content);
void playlist_set_scan_omit_db_ref(playlist_t *playlist, bool omit_db_ref);
void playlist_set_scan_overwrite_playlist(playlist_t *playlist, bool overwrite_playlist);
void playlist_set_scan_db_usage(playlist_t *playlist, int db_usage);
/* Returns true if specified entry has a valid
* core association (i.e. a non-empty string
+683 -533
View File
File diff suppressed because it is too large. Load diff