diff --git a/config.def.h b/config.def.h index 7ae77928c6..3861864a28 100644 --- a/config.def.h +++ b/config.def.h @@ -1056,6 +1056,8 @@ static const int default_content_favorites_size = 200; #define DEFAULT_PLAYLIST_FUZZY_ARCHIVE_MATCH false +#define DEFAULT_PLAYLIST_PORTABLE_PATHS false + /* Show Menu start-up screen on boot. */ #define DEFAULT_MENU_SHOW_START_SCREEN true diff --git a/configuration.c b/configuration.c index d721e7006f..74b855ac40 100644 --- a/configuration.c +++ b/configuration.c @@ -1723,6 +1723,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("playlist_show_sublabels", &settings->bools.playlist_show_sublabels, true, DEFAULT_PLAYLIST_SHOW_SUBLABELS, false); SETTING_BOOL("playlist_sort_alphabetical", &settings->bools.playlist_sort_alphabetical, true, DEFAULT_PLAYLIST_SORT_ALPHABETICAL, false); SETTING_BOOL("playlist_fuzzy_archive_match", &settings->bools.playlist_fuzzy_archive_match, true, DEFAULT_PLAYLIST_FUZZY_ARCHIVE_MATCH, false); + SETTING_BOOL("playlist_portable_paths", &settings->bools.playlist_portable_paths, true, DEFAULT_PLAYLIST_PORTABLE_PATHS, false); SETTING_BOOL("quit_press_twice", &settings->bools.quit_press_twice, true, DEFAULT_QUIT_PRESS_TWICE, false); SETTING_BOOL("vibrate_on_keypress", &settings->bools.vibrate_on_keypress, true, vibrate_on_keypress, false); diff --git a/configuration.h b/configuration.h index fc4617cb71..0ce30b8f02 100644 --- a/configuration.h +++ b/configuration.h @@ -405,6 +405,7 @@ typedef struct settings bool playlist_sort_alphabetical; bool playlist_show_sublabels; bool playlist_fuzzy_archive_match; + bool playlist_portable_paths; bool quit_press_twice; bool vibrate_on_keypress; diff --git a/core_info.c b/core_info.c index 3f31480f54..6a07849d11 100644 --- a/core_info.c +++ b/core_info.c @@ -873,6 +873,53 @@ void core_info_list_get_supported_cores(core_info_list_t *core_info_list, *num_infos = supported; } +/* + * Matches core path A and B "base" filename (ignoring everything after _libretro) + * + * Ex: + * snes9x_libretro.dll and snes9x_libretro_android.so are matched + * snes9x__2005_libretro.dll and snes9x_libretro_android.so are NOT matched + */ +bool core_info_core_file_id_is_equal(const char* core_path_a, const char* core_path_b) +{ + const char *core_path_basename_a = NULL; + const char *extension_pos = NULL; + const char *underscore_pos = NULL; + + if (!core_path_a || !core_path_b) + return false; + + core_path_basename_a = path_basename(core_path_a); + + if (core_path_basename_a) + { + extension_pos = strrchr(core_path_basename_a, '.'); + + if (extension_pos) + { + /* Remove extension */ + *((char*)extension_pos) = '\0'; + + underscore_pos = strrchr(core_path_basename_a, '_'); + + /* Restore extension */ + *((char*)extension_pos) = '.'; + + if (underscore_pos) + { + size_t core_base_file_id_length = underscore_pos - core_path_basename_a; + const char* core_path_basename_b = path_basename(core_path_b); + + if (string_starts_with_size(core_path_basename_a, core_path_basename_b, + core_base_file_id_length)) + return true; + } + } + } + + return false; +} + void core_info_get_name(const char *path, char *s, size_t len, const char *path_info, const char *dir_cores, const char *exts, bool dir_show_hidden_files, diff --git a/core_info.h b/core_info.h index de6e927dd2..3fc042100c 100644 --- a/core_info.h +++ b/core_info.h @@ -220,6 +220,8 @@ bool core_info_get_core_lock(const char *core_path, bool validate_path); core_info_state_t *coreinfo_get_ptr(void); +bool core_info_core_file_id_is_equal(const char* core_path_a, const char* core_path_b); + RETRO_END_DECLS #endif /* CORE_INFO_H_ */ diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 325b04efe1..b7a9b3f11c 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -4312,6 +4312,10 @@ MSG_HASH( MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, "playlist_sublabel_last_played_style" ) +MSG_HASH( + MENU_ENUM_LABEL_PLAYLIST_PORTABLE_PATHS, + "playlist_portable_paths" + ) MSG_HASH( MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO, "help_send_debug_info" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 49ff9ad6d7..5ef6b504f6 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4911,6 +4911,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_LIST, "Perform maintenance tasks on playlists." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_PORTABLE_PATHS, + "Portable Playlists" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_PORTABLE_PATHS, + "When enabled, and 'File Browser' directory is also selected, the current value of parameter 'File Browser' is saved in the playlist. When the playlist is loaded on another system where the same option is enabled, the value of parameter 'File Browser' is compared with the playlist value; if different, the playlist entries' paths are automatically fixed." + ) /* Settings > Playlists > Playlist Management */ diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 9f2808fca6..fc314cbcad 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -2076,6 +2076,7 @@ static int action_ok_playlist_entry_collection(const char *path, playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); content_path[0] = '\0'; content_label[0] = '\0'; @@ -6360,6 +6361,7 @@ static int action_ok_manual_content_scan_start(const char *path, playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); task_push_manual_content_scan(&playlist_config, directory_playlist); return 0; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 002c77f9fd..c1641b93c5 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -850,6 +850,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_sort_alphabetical, DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_fuzzy_archive_match, MENU_ENUM_SUBLABEL_PLAYLIST_FUZZY_ARCHIVE_MATCH) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_use_old_format, MENU_ENUM_SUBLABEL_PLAYLIST_USE_OLD_FORMAT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_compression, MENU_ENUM_SUBLABEL_PLAYLIST_COMPRESSION) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_playlist_portable_paths, MENU_ENUM_SUBLABEL_PLAYLIST_PORTABLE_PATHS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_rgui_full_width_layout, MENU_ENUM_SUBLABEL_MENU_RGUI_FULL_WIDTH_LAYOUT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_rgui_extended_ascii, MENU_ENUM_SUBLABEL_MENU_RGUI_EXTENDED_ASCII) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_rgui_switch_icons, MENU_ENUM_SUBLABEL_MENU_RGUI_SWITCH_ICONS) @@ -3811,6 +3812,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_PLAYLIST_FUZZY_ARCHIVE_MATCH: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_fuzzy_archive_match); break; + case MENU_ENUM_LABEL_PLAYLIST_PORTABLE_PATHS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_portable_paths); + break; case MENU_ENUM_LABEL_PLAYLIST_USE_OLD_FORMAT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_use_old_format); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 39ba8eda9f..f03b9c7507 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -1673,6 +1673,7 @@ static int menu_displaylist_parse_database_entry(menu_handle_t *menu, playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); path_playlist[0] = path_base[0] = query[0] = '\0'; @@ -2314,6 +2315,7 @@ static void menu_displaylist_set_new_playlist( playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); menu->db_playlist_file[0] = '\0'; @@ -5145,6 +5147,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_PLAYLIST_PORTABLE_PATHS, PARSE_ONLY_BOOL, true}, }; for (i = 0; i < ARRAY_SIZE(build_list); i++) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 31a06b5899..d47fa54eab 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -16249,6 +16249,22 @@ static bool setting_append_list( SD_FLAG_NONE ); + CONFIG_BOOL( + list, list_info, + &settings->bools.playlist_portable_paths, + MENU_ENUM_LABEL_PLAYLIST_PORTABLE_PATHS, + MENU_ENUM_LABEL_VALUE_PLAYLIST_PORTABLE_PATHS, + DEFAULT_PLAYLIST_PORTABLE_PATHS, + 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 + ); + #ifdef HAVE_OZONE if (string_is_equal(settings->arrays.menu_driver, "ozone")) { diff --git a/msg_hash.h b/msg_hash.h index ee00e3bb46..4d68964db6 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2869,6 +2869,7 @@ enum msg_hash_enums MENU_LABEL(PLAYLIST_FUZZY_ARCHIVE_MATCH), MENU_LABEL(PLAYLIST_SUBLABEL_RUNTIME_TYPE), MENU_LABEL(PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE), + MENU_LABEL(PLAYLIST_PORTABLE_PATHS), MENU_ENUM_LABEL_VALUE_PLAYLIST_INLINE_CORE_DISPLAY_HIST_FAV, MENU_ENUM_LABEL_VALUE_PLAYLIST_INLINE_CORE_DISPLAY_ALWAYS, diff --git a/playlist.c b/playlist.c index 294fb687b7..ab37a0d258 100644 --- a/playlist.c +++ b/playlist.c @@ -34,11 +34,23 @@ #include "playlist.h" #include "verbosity.h" #include "file_path_special.h" +#include "core_info.h" #ifndef PLAYLIST_ENTRIES #define PLAYLIST_ENTRIES 6 #endif +#define WINDOWS_PATH_DELIMITER '\\' +#define POSIX_PATH_DELIMITER '/' + +#ifdef _WIN32 +#define LOCAL_FILE_SYSTEM_PATH_DELIMITER WINDOWS_PATH_DELIMITER +#define USING_WINDOWS_FILE_SYSTEM +#else +#define LOCAL_FILE_SYSTEM_PATH_DELIMITER POSIX_PATH_DELIMITER +#define USING_POSIX_FILE_SYSTEM +#endif + struct content_playlist { bool modified; @@ -54,6 +66,7 @@ struct content_playlist char *default_core_path; char *default_core_name; + char *base_content_directory; struct playlist_entry *entries; playlist_config_t config; @@ -112,6 +125,22 @@ void playlist_config_set_path(playlist_config_t *config, const char *path) strlcpy(config->path, path, sizeof(config->path)); } +/* Convenience function: copies base content directory + * path to specified playlist configuration object. + * Also sets autofix_paths boolean, depending on base content directory value */ +void playlist_config_set_base_content_directory(playlist_config_t* config, const char* path) +{ + if (!config) + return; + + config->autofix_paths = !string_is_empty(path); + if (!config->autofix_paths) + config->base_content_directory[0] = '\0'; + else + strlcpy(config->base_content_directory, path, sizeof(config->base_content_directory)); +} + + /* Creates a copy of the specified playlist configuration. * Returns false in the event of an error */ bool playlist_config_copy(const playlist_config_t *src, playlist_config_t *dst) @@ -120,11 +149,13 @@ bool playlist_config_copy(const playlist_config_t *src, playlist_config_t *dst) return false; strlcpy(dst->path, src->path, sizeof(dst->path)); + strlcpy(dst->base_content_directory, src->base_content_directory, sizeof(dst->base_content_directory)); dst->capacity = src->capacity; dst->old_format = src->old_format; dst->compress = src->compress; dst->fuzzy_archive_match = src->fuzzy_archive_match; + dst->autofix_paths = src->autofix_paths; return true; } @@ -140,6 +171,43 @@ playlist_config_t *playlist_get_config(playlist_t *playlist) return &playlist->config; } +static void path_replace_base_path_and_convert_to_local_file_system( + char *out_path, const char *in_path, + const char *in_oldrefpath, const char *in_refpath, + size_t size) +{ + const char fs_delimeter = LOCAL_FILE_SYSTEM_PATH_DELIMITER; + size_t in_oldrefpath_length = strlen(in_oldrefpath); + size_t in_refpath_length = strlen(in_refpath); + + /* If entry path is inside playlist base path, + * replace it with new base content directory */ + if (string_starts_with_size(in_path, in_oldrefpath, in_oldrefpath_length)) + { + memcpy(out_path, in_refpath, in_refpath_length); + memcpy(out_path + in_refpath_length, in_path + in_oldrefpath_length, + strlen(in_path) - in_oldrefpath_length + 1); + +#ifdef USING_WINDOWS_FILE_SYSTEM + /* If we are running under a win fs, '/' characters + * are not allowed anywhere. we replace with '\' and + * hope for the best... */ + string_replace_all_chars(out_path, + POSIX_PATH_DELIMITER, WINDOWS_PATH_DELIMITER); +#endif + +#ifdef USING_POSIX_FILE_SYSTEM + /* Under posix fs, we replace '\' characters with '/' */ + string_replace_all_chars(out_path, + WINDOWS_PATH_DELIMITER, POSIX_PATH_DELIMITER); +#endif + } + else + { + strlcpy(out_path, in_path, size); + } +} + /** * playlist_path_equal: * @real_path : 'Real' search path, generated by path_resolve_realpath() @@ -235,14 +303,15 @@ static bool playlist_path_equal(const char *real_path, /** * playlist_core_path_equal: - * @real_core_path : 'Real' search path, generated by path_resolve_realpath() - * @entry_core_path : Existing playlist entry 'core path' value + * @real_core_path : 'Real' search path, generated by path_resolve_realpath() + * @entry_core_path : Existing playlist entry 'core path' value + * @config : Playlist config parameters * * Returns 'true' if real_core_path matches entry_core_path * (Taking into account relative paths, case insensitive * filesystems) **/ -static bool playlist_core_path_equal(const char *real_core_path, const char *entry_core_path) +static bool playlist_core_path_equal(const char *real_core_path, const char *entry_core_path, const playlist_config_t *config) { char entry_real_core_path[PATH_MAX_LENGTH]; @@ -270,6 +339,10 @@ static bool playlist_core_path_equal(const char *real_core_path, const char *ent return true; #endif + if (config->autofix_paths && + core_info_core_file_id_is_equal(real_core_path, entry_core_path)) + return true; + return false; } @@ -706,7 +779,7 @@ bool playlist_push_runtime(playlist_t *playlist, if (!equal_path) continue; - if (!playlist_core_path_equal(real_core_path, playlist->entries[i].core_path)) + if (!playlist_core_path_equal(real_core_path, playlist->entries[i].core_path, &playlist->config)) continue; /* If top entry, we don't want to push a new entry since @@ -889,7 +962,7 @@ bool playlist_push(playlist_t *playlist, if (!equal_path) continue; - if (!playlist_core_path_equal(real_core_path, playlist->entries[i].core_path)) + if (!playlist_core_path_equal(real_core_path, playlist->entries[i].core_path, &playlist->config)) continue; if ( !string_is_empty(entry->subsystem_ident) @@ -1487,6 +1560,21 @@ void playlist_write_file(playlist_t *playlist) JSON_Writer_WriteComma(context.writer); json_write_new_line(context.writer); + if (!string_is_empty(playlist->base_content_directory)) + { + json_write_space(context.writer, 2); + JSON_Writer_WriteString(context.writer, "base_content_directory", + STRLEN_CONST("base_content_directory"), JSON_UTF8); + JSON_Writer_WriteColon(context.writer); + json_write_space(context.writer, 1); + JSON_Writer_WriteString(context.writer, + playlist->base_content_directory, + strlen(playlist->base_content_directory), + JSON_UTF8); + JSON_Writer_WriteComma(context.writer); + json_write_new_line(context.writer); + } + uint_str[0] = '\0'; snprintf(uint_str, sizeof(uint_str), "%u", playlist->label_display_mode); @@ -1766,17 +1854,24 @@ void playlist_free(playlist_t *playlist) free(playlist->default_core_name); playlist->default_core_name = NULL; - for (i = 0; i < playlist->size; i++) + if (playlist->base_content_directory != NULL) + free(playlist->base_content_directory); + playlist->base_content_directory = NULL; + + if (playlist->entries) { - struct playlist_entry *entry = &playlist->entries[i]; + for (i = 0; i < playlist->size; i++) + { + struct playlist_entry *entry = &playlist->entries[i]; - if (entry) - playlist_free_entry(entry); + if (entry) + playlist_free_entry(entry); + } + + free(playlist->entries); + playlist->entries = NULL; } - free(playlist->entries); - playlist->entries = NULL; - free(playlist); } @@ -2148,6 +2243,9 @@ static JSON_Parser_HandlerResult JSONObjectMemberHandler(JSON_Parser parser, cha pCtx->current_meta_thumbnail_mode_val = &pCtx->playlist->left_thumbnail_mode; else if (string_is_equal(pValue, "sort_mode")) pCtx->current_meta_sort_mode_val = &pCtx->playlist->sort_mode; + else if (string_is_equal(pValue, "base_content_directory")) + pCtx->current_meta_val = &pCtx->playlist->base_content_directory; + } } } @@ -2568,27 +2666,94 @@ playlist_t *playlist_init(const playlist_config_t *config) goto error; /* Set initial values */ - playlist->modified = false; - playlist->old_format = false; - playlist->compressed = false; - playlist->size = 0; - playlist->default_core_name = NULL; - playlist->default_core_path = NULL; - playlist->entries = entries; - playlist->label_display_mode = LABEL_DISPLAY_MODE_DEFAULT; - playlist->right_thumbnail_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; - playlist->left_thumbnail_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; - playlist->sort_mode = PLAYLIST_SORT_MODE_DEFAULT; + playlist->modified = false; + playlist->old_format = false; + playlist->compressed = false; + playlist->size = 0; + playlist->default_core_name = NULL; + playlist->default_core_path = NULL; + playlist->base_content_directory = NULL; + playlist->entries = entries; + playlist->label_display_mode = LABEL_DISPLAY_MODE_DEFAULT; + playlist->right_thumbnail_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; + playlist->left_thumbnail_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; + playlist->sort_mode = PLAYLIST_SORT_MODE_DEFAULT; /* Attempt to read any existing playlist file */ playlist_read_file(playlist); + /* Try auto-fixing paths if enabled, and playlist + * base content directory is different */ + if (playlist->config.autofix_paths && + !string_is_empty(playlist->base_content_directory) && + !string_is_equal(playlist->base_content_directory, + playlist->config.base_content_directory)) + { + size_t playlist_base_content_directory_length = strlen(playlist->base_content_directory); + size_t new_base_content_directory_length = strlen(playlist->config.base_content_directory); + size_t i; + size_t j; + char tmp_entry_path[PATH_MAX_LENGTH]; + + for (i = 0; i < playlist->size; i++) + { + struct playlist_entry *entry = &playlist->entries[i]; + + if (!entry || string_is_empty(entry->path)) + continue; + + /* Fix entry path */ + tmp_entry_path[0] = '\0'; + path_replace_base_path_and_convert_to_local_file_system( + tmp_entry_path, entry->path, + playlist->base_content_directory, playlist->config.base_content_directory, + sizeof(tmp_entry_path)); + + free(entry->path); + entry->path = strdup(tmp_entry_path); + + /* Fix subsystem roms paths*/ + if (entry->subsystem_roms && (entry->subsystem_roms->size > 0)) + { + struct string_list* subsystem_roms_new_paths = string_list_new(); + union string_list_elem_attr attributes = {0}; + + if (!subsystem_roms_new_paths) + goto error; + + for (j = 0; j < entry->subsystem_roms->size; j++) + { + const char *subsystem_rom_path = entry->subsystem_roms->elems[j].data; + + if (string_is_empty(subsystem_rom_path)) + continue; + + tmp_entry_path[0] = '\0'; + path_replace_base_path_and_convert_to_local_file_system( + tmp_entry_path, subsystem_rom_path, + playlist->base_content_directory, playlist->config.base_content_directory, + sizeof(tmp_entry_path)); + string_list_append(subsystem_roms_new_paths, tmp_entry_path, attributes); + } + + string_list_free(entry->subsystem_roms); + entry->subsystem_roms = subsystem_roms_new_paths; + } + } + + /* Update playlist base content directory*/ + free(playlist->base_content_directory); + playlist->base_content_directory = strdup(playlist->config.base_content_directory); + + /* Save playlist */ + playlist->modified = true; + playlist_write_file(playlist); + } + return playlist; error: - if (playlist) - free(playlist); - + playlist_free(playlist); return NULL; } @@ -2767,7 +2932,7 @@ bool playlist_entries_are_equal( path_resolve_realpath(real_core_path_a, sizeof(real_core_path_a), true); } - return playlist_core_path_equal(real_core_path_a, entry_b->core_path); + return playlist_core_path_equal(real_core_path_a, entry_b->core_path, config); } void playlist_get_crc32(playlist_t *playlist, size_t idx, diff --git a/playlist.h b/playlist.h index 72388ad249..0271f4e634 100644 --- a/playlist.h +++ b/playlist.h @@ -119,16 +119,22 @@ struct playlist_entry typedef struct { char path[PATH_MAX_LENGTH]; + char base_content_directory[PATH_MAX_LENGTH]; size_t capacity; bool old_format; bool compress; bool fuzzy_archive_match; + bool autofix_paths; } playlist_config_t; /* Convenience function: copies specified playlist * path to specified playlist configuration object */ void playlist_config_set_path(playlist_config_t *config, const char *path); +/* Convenience function: copies base content directory + * path to specified playlist configuration object */ +void playlist_config_set_base_content_directory(playlist_config_t* config, const char* path); + /* Creates a copy of the specified playlist configuration. * Returns false in the event of an error */ bool playlist_config_copy(const playlist_config_t *src, playlist_config_t *dst); diff --git a/retroarch.c b/retroarch.c index 546718e2b8..3db3e26214 100644 --- a/retroarch.c +++ b/retroarch.c @@ -16006,6 +16006,8 @@ bool command_event(enum event_command cmd, void *data) playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + /* don't use relative paths for content, music, video, and image histories */ + playlist_config_set_base_content_directory(&playlist_config, NULL); command_event(CMD_EVENT_HISTORY_DEINIT, NULL); @@ -39626,6 +39628,7 @@ void rarch_favorites_init(void) playlist_config.old_format = settings ? settings->bools.playlist_use_old_format : false; playlist_config.compress = settings ? settings->bools.playlist_compression : false; playlist_config.fuzzy_archive_match = settings ? settings->bools.playlist_fuzzy_archive_match : false; + playlist_config_set_base_content_directory(&playlist_config, NULL); if (!settings) return; diff --git a/tasks/task_database.c b/tasks/task_database.c index 8ff81a27e3..61ec8db0d6 100644 --- a/tasks/task_database.c +++ b/tasks/task_database.c @@ -1368,11 +1368,13 @@ bool task_push_dbscan( db->playlist_config.old_format = settings->bools.playlist_use_old_format; db->playlist_config.compress = settings->bools.playlist_compression; db->playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&db->playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); #else db->playlist_config.capacity = COLLECTION_SIZE; db->playlist_config.old_format = false; db->playlist_config.compress = false; db->playlist_config.fuzzy_archive_match = false; + playlist_config_set_base_content_directory(&db->playlist_config, NULL); #endif db->show_hidden_files = db_dir_show_hidden_files; db->is_directory = directory; diff --git a/tasks/task_netplay_find_content.c b/tasks/task_netplay_find_content.c index 9f902561ba..a23aea436a 100644 --- a/tasks/task_netplay_find_content.c +++ b/tasks/task_netplay_find_content.c @@ -437,6 +437,7 @@ bool task_push_netplay_crc_scan(uint32_t crc, char* name, state->playlist_config.old_format = settings->bools.playlist_use_old_format; state->playlist_config.compress = settings->bools.playlist_compression; state->playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&state->playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); state->content_crc[0] = '\0'; state->content_path[0] = '\0'; diff --git a/ui/drivers/qt/qt_playlist.cpp b/ui/drivers/qt/qt_playlist.cpp index 228dd2bf45..d30d81c4a2 100644 --- a/ui/drivers/qt/qt_playlist.cpp +++ b/ui/drivers/qt/qt_playlist.cpp @@ -391,6 +391,7 @@ void MainWindow::addFilesToPlaylist(QStringList files) playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); /* Assume a blank list means we will manually enter in all fields. */ if (files.isEmpty()) @@ -697,6 +698,7 @@ bool MainWindow::updateCurrentPlaylistEntry( playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); if ( playlistPath.isEmpty() || contentHash.isEmpty() || @@ -825,6 +827,7 @@ void MainWindow::onPlaylistWidgetContextMenuRequested(const QPoint&) playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); if (selectedItem) { @@ -1361,6 +1364,7 @@ void MainWindow::deleteCurrentPlaylistItem() playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); if (isAllPlaylist) return; @@ -1408,6 +1412,7 @@ QString MainWindow::getPlaylistDefaultCore(QString dbName) playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); playlistPath[0] = '\0'; @@ -1478,6 +1483,7 @@ void PlaylistModel::getPlaylistItems(QString path) playlist_config.old_format = settings->bools.playlist_use_old_format; playlist_config.compress = settings->bools.playlist_compression; playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match; + playlist_config_set_base_content_directory(&playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL); pathArray.append(path); pathData = pathArray.constData();