diff --git a/Makefile.common b/Makefile.common index 48fec58b18..64c0fb81e3 100644 --- a/Makefile.common +++ b/Makefile.common @@ -175,6 +175,7 @@ OBJ += frontend/frontend.o \ tasks/task_file_transfer.o \ tasks/task_image.o \ tasks/task_audio_mixer.o \ + tasks/task_playlist_manager.o \ $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.o \ $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.o \ $(LIBRETRO_COMM_DIR)/encodings/encoding_base64.o \ diff --git a/griffin/griffin.c b/griffin/griffin.c index 8c397179dc..d423f009a7 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1198,6 +1198,7 @@ DATA RUNLOOP #include "../tasks/task_save.c" #include "../tasks/task_image.c" #include "../tasks/task_file_transfer.c" +#include "../tasks/task_playlist_manager.c" #ifdef HAVE_ZLIB #include "../tasks/task_decompress.c" #endif diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 3b81c6471d..c6ed9c64f1 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -873,6 +873,8 @@ MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS, "playlist_manager_settings") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE, "playlist_manager_default_core") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES, + "playlist_manager_reset_cores") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SETTINGS_BEGIN, "playlist_settings_begin") MSG_HASH(MENU_ENUM_LABEL_POINTER_ENABLE, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index d2a39a9f86..746595e72d 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2164,6 +2164,22 @@ MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_DEFAULT_CORE, "Specify core to use when launching content via a playlist entry that does not have an existing core association." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_RESET_CORES, + "Reset Core Associations" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_RESET_CORES, + "Remove existing core associations for all playlist entries." + ) +MSG_HASH( + MSG_PLAYLIST_MANAGER_RESETTING_CORES, + "Resetting cores: " + ) +MSG_HASH( + MSG_PLAYLIST_MANAGER_CORES_RESET, + "Cores reset: " + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, "Touch Support" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index d3c0f2b46a..b1e47fb7e6 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -5517,6 +5517,25 @@ static int action_ok_pl_entry_content_thumbnails(const char *path, } #endif +static int action_ok_playlist_reset_cores(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + playlist_t *playlist = playlist_get_cached(); + const char *playlist_path = NULL; + + if (!playlist) + return -1; + + playlist_path = playlist_get_conf_path(playlist); + + if (string_is_empty(playlist_path)) + return -1; + + task_push_pl_manager_reset_cores(playlist_path); + + return 0; +} + static int is_rdb_entry(enum msg_hash_enums enum_idx) { switch (enum_idx) @@ -5868,6 +5887,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS: BIND_ACTION_OK(cbs, action_ok_push_playlist_manager_settings); break; + case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES: + BIND_ACTION_OK(cbs, action_ok_playlist_reset_cores); + break; case MENU_ENUM_LABEL_RECORDING_SETTINGS: BIND_ACTION_OK(cbs, action_ok_push_recording_settings_list); break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 7c379bc7fa..db367ef5b3 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -130,6 +130,7 @@ default_sublabel_macro(action_bind_sublabel_directory_settings_list, MENU_ default_sublabel_macro(action_bind_sublabel_playlist_settings_list, MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS) default_sublabel_macro(action_bind_sublabel_playlist_manager_list, MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_LIST) default_sublabel_macro(action_bind_sublabel_playlist_manager_default_core, MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_DEFAULT_CORE) +default_sublabel_macro(action_bind_sublabel_playlist_manager_reset_cores, MENU_ENUM_SUBLABEL_PLAYLIST_MANAGER_RESET_CORES) default_sublabel_macro(action_bind_sublabel_network_settings_list, MENU_ENUM_SUBLABEL_NETWORK_SETTINGS) default_sublabel_macro(action_bind_sublabel_network_on_demand_thumbnails, MENU_ENUM_SUBLABEL_NETWORK_ON_DEMAND_THUMBNAILS) default_sublabel_macro(action_bind_sublabel_user_settings_list, MENU_ENUM_SUBLABEL_USER_SETTINGS) @@ -2391,6 +2392,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_manager_default_core); break; + case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_manager_reset_cores); + break; case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_user_interface_settings_list); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index fbe6a0795d..f40dd80bec 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -2504,7 +2504,8 @@ static void materialui_list_insert(void *userdata, node->texture_switch2_set = true; } else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RENAME_ENTRY)) || - string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION))) + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION)) || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES))) { node->texture_switch2_index = MUI_TEXTURE_RENAME; node->texture_switch2_set = true; diff --git a/menu/drivers/ozone/ozone_texture.c b/menu/drivers/ozone/ozone_texture.c index d9b0194c00..bb1c7071da 100644 --- a/menu/drivers/ozone/ozone_texture.c +++ b/menu/drivers/ozone/ozone_texture.c @@ -40,6 +40,7 @@ menu_texture_item ozone_entries_icon_get_texture(ozone_handle_t *ozone, case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ADD_FAVORITE]; case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: + case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_UNDO]; case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_REMAPPING_OPTIONS]; diff --git a/menu/drivers/stripes.c b/menu/drivers/stripes.c index b318237c36..352fdd36da 100644 --- a/menu/drivers/stripes.c +++ b/menu/drivers/stripes.c @@ -2127,6 +2127,7 @@ static uintptr_t stripes_icon_get_id(stripes_handle_t *stripes, case MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST: return stripes->textures.list[STRIPES_TEXTURE_ADD_FAVORITE]; case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: + case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES: return stripes->textures.list[STRIPES_TEXTURE_RENAME]; case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: return stripes->textures.list[STRIPES_TEXTURE_INPUT_REMAPPING_OPTIONS]; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index b6ad6c7ee6..7111e99356 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2323,6 +2323,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_UNDO_LOAD_STATE: case MENU_ENUM_LABEL_UNDO_SAVE_STATE: case MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION: + case MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES: return xmb->textures.list[XMB_TEXTURE_UNDO]; case MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS: return xmb->textures.list[XMB_TEXTURE_INPUT_REMAPPING_OPTIONS]; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 92f168bc85..c5fe7f814c 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -2631,8 +2631,14 @@ static bool menu_displaylist_parse_playlist_manager_settings( MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE, MENU_SETTING_PLAYLIST_MANAGER_DEFAULT_CORE, 0, 0); + /* Reset core associations */ + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_RESET_CORES), + msg_hash_to_str(MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES), + MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES, + FILE_TYPE_PLAYLIST_ENTRY, 0, 0); + /* TODO: Add - * - Reset core associations * - Remove invalid entries */ return true; diff --git a/msg_hash.h b/msg_hash.h index ae32d0191f..b8eb112b90 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1815,6 +1815,11 @@ enum msg_hash_enums MENU_LABEL(PLAYLIST_MANAGER_LIST), MENU_LABEL(PLAYLIST_MANAGER_SETTINGS), MENU_LABEL(PLAYLIST_MANAGER_DEFAULT_CORE), + MENU_LABEL(PLAYLIST_MANAGER_RESET_CORES), + + MSG_PLAYLIST_MANAGER_RESETTING_CORES, + MSG_PLAYLIST_MANAGER_CORES_RESET, + MENU_LABEL(CORE_UPDATER_SETTINGS), MENU_LABEL(LAKKA_SERVICES), MENU_LABEL(SHADER_APPLY_CHANGES), diff --git a/tasks/task_playlist_manager.c b/tasks/task_playlist_manager.c new file mode 100644 index 0000000000..0de83ef450 --- /dev/null +++ b/tasks/task_playlist_manager.c @@ -0,0 +1,315 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2016-2019 - Brad Parker + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include + +#include +#include + +#include "tasks_internal.h" + +#include "../msg_hash.h" +#include "../file_path_special.h" +#include "../playlist.h" + +#ifndef COLLECTION_SIZE +#define COLLECTION_SIZE 99999 +#endif + +enum pl_manager_status +{ + PL_MANAGER_BEGIN = 0, + PL_MANAGER_ITERATE_ENTRY, + PL_MANAGER_END +}; + +typedef struct pl_manager_handle +{ + char *playlist_path; + char *playlist_name; + playlist_t *playlist; + size_t list_size; + size_t list_index; + enum pl_manager_status status; +} pl_manager_handle_t; + +/**************************/ +/* Reset Associated Cores */ +/**************************/ + +static void free_pl_manager_handle(pl_manager_handle_t *pl_manager) +{ + if (!pl_manager) + return; + + if (!string_is_empty(pl_manager->playlist_path)) + { + free(pl_manager->playlist_path); + pl_manager->playlist_path = NULL; + } + + if (!string_is_empty(pl_manager->playlist_name)) + { + free(pl_manager->playlist_name); + pl_manager->playlist_name = NULL; + } + + if (pl_manager->playlist) + { + playlist_free(pl_manager->playlist); + pl_manager->playlist = NULL; + } + + free(pl_manager); + pl_manager = NULL; +} + +static void task_pl_manager_reset_cores_handler(retro_task_t *task) +{ + pl_manager_handle_t *pl_manager = NULL; + + if (!task) + goto task_finished; + + pl_manager = (pl_manager_handle_t*)task->state; + + if (!pl_manager) + goto task_finished; + + if (task_get_cancelled(task)) + goto task_finished; + + switch (pl_manager->status) + { + case PL_MANAGER_BEGIN: + { + /* Load playlist */ + if (!path_is_valid(pl_manager->playlist_path)) + goto task_finished; + + pl_manager->playlist = playlist_init(pl_manager->playlist_path, COLLECTION_SIZE); + + if (!pl_manager->playlist) + goto task_finished; + + pl_manager->list_size = playlist_size(pl_manager->playlist); + + if (pl_manager->list_size < 1) + goto task_finished; + + /* All good - can start iterating */ + pl_manager->status = PL_MANAGER_ITERATE_ENTRY; + } + break; + case PL_MANAGER_ITERATE_ENTRY: + { + const struct playlist_entry *entry = NULL; + + /* Get current entry */ + playlist_get_index( + pl_manager->playlist, pl_manager->list_index, &entry); + + if (entry) + { + struct playlist_entry update_entry = {0}; + char task_title[PATH_MAX_LENGTH]; + char detect_string[PATH_MAX_LENGTH]; + + task_title[0] = '\0'; + detect_string[0] = '\0'; + + /* Update progress display */ + task_free_title(task); + + strlcpy( + task_title, msg_hash_to_str(MSG_PLAYLIST_MANAGER_RESETTING_CORES), + sizeof(task_title)); + + if (!string_is_empty(entry->label)) + strlcat(task_title, entry->label, sizeof(task_title)); + else if (!string_is_empty(entry->path)) + { + char entry_name[PATH_MAX_LENGTH]; + entry_name[0] = '\0'; + + fill_pathname_base_noext(entry_name, entry->path, sizeof(entry_name)); + strlcat(task_title, entry_name, sizeof(task_title)); + } + + task_set_title(task, strdup(task_title)); + task_set_progress(task, (pl_manager->list_index * 100) / pl_manager->list_size); + + /* Reset core association */ + strlcpy(detect_string, file_path_str(FILE_PATH_DETECT), sizeof(detect_string)); + + update_entry.core_path = detect_string; + update_entry.core_name = detect_string; + + playlist_update( + pl_manager->playlist, pl_manager->list_index, &update_entry); + } + + /* Increment entry index */ + pl_manager->list_index++; + if (pl_manager->list_index >= pl_manager->list_size) + pl_manager->status = PL_MANAGER_END; + } + break; + case PL_MANAGER_END: + { + playlist_t *cached_playlist = playlist_get_cached(); + char task_title[PATH_MAX_LENGTH]; + + task_title[0] = '\0'; + + /* Save playlist changes to disk */ + playlist_write_file(pl_manager->playlist); + + /* If this is the currently cached playlist, then + * it must be re-cached (otherwise changes will be + * lost if the currently cached playlist is saved + * to disk for any reason...) */ + if (cached_playlist) + { + if (string_is_equal(pl_manager->playlist_path, playlist_get_conf_path(cached_playlist))) + { + playlist_free_cached(); + playlist_init_cached(pl_manager->playlist_path, COLLECTION_SIZE); + } + } + + /* Update progress display */ + task_free_title(task); + + strlcpy( + task_title, msg_hash_to_str(MSG_PLAYLIST_MANAGER_CORES_RESET), + sizeof(task_title)); + strlcat(task_title, pl_manager->playlist_name, sizeof(task_title)); + + task_set_title(task, strdup(task_title)); + task_set_progress(task, 100); + + goto task_finished; + } + break; + default: + task_set_progress(task, 100); + goto task_finished; + break; + } + + return; + +task_finished: + + if (task) + task_set_finished(task, true); + + free_pl_manager_handle(pl_manager); +} + +static bool task_pl_manager_reset_cores_finder(retro_task_t *task, void *user_data) +{ + pl_manager_handle_t *pl_manager = NULL; + + if (!task || !user_data) + return false; + + if (task->handler != task_pl_manager_reset_cores_handler) + return false; + + pl_manager = (pl_manager_handle_t*)task->state; + if (!pl_manager) + return false; + + return string_is_equal((const char*)user_data, pl_manager->playlist_path); +} + +bool task_push_pl_manager_reset_cores(const char *playlist_path) +{ + task_finder_data_t find_data; + char playlist_name[PATH_MAX_LENGTH]; + char task_title[PATH_MAX_LENGTH]; + retro_task_t *task = task_init(); + pl_manager_handle_t *pl_manager = (pl_manager_handle_t*)calloc(1, sizeof(pl_manager_handle_t)); + + playlist_name[0] = '\0'; + task_title[0] = '\0'; + + /* Sanity check */ + if (!task || !pl_manager) + goto error; + + if (string_is_empty(playlist_path)) + goto error; + + fill_pathname_base_noext(playlist_name, playlist_path, sizeof(playlist_name)); + + if (string_is_empty(playlist_name)) + goto error; + + /* Concurrent management of the same playlist + * is not allowed */ + find_data.func = task_pl_manager_reset_cores_finder; + find_data.userdata = (void*)playlist_path; + + if (task_queue_find(&find_data)) + goto error; + + /* Configure task */ + strlcpy( + task_title, msg_hash_to_str(MSG_PLAYLIST_MANAGER_RESETTING_CORES), + sizeof(task_title)); + strlcat(task_title, playlist_name, sizeof(task_title)); + + task->handler = task_pl_manager_reset_cores_handler; + task->state = pl_manager; + task->title = strdup(task_title); + task->alternative_look = true; + task->progress = 0; + + /* Configure handle */ + pl_manager->playlist_path = strdup(playlist_path); + pl_manager->playlist_name = strdup(playlist_name); + pl_manager->playlist = NULL; + pl_manager->list_size = 0; + pl_manager->list_index = 0; + pl_manager->status = PL_MANAGER_BEGIN; + + task_queue_push(task); + + return true; + +error: + + if (task) + { + free(task); + task = NULL; + } + + if (pl_manager) + { + free(pl_manager); + pl_manager = NULL; + } + + return false; +} diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index 4a1cd58fde..1de890b9c9 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -73,6 +73,8 @@ bool task_push_pl_entry_thumbnail_download( #endif +bool task_push_pl_manager_reset_cores(const char *playlist_path); + bool task_push_image_load(const char *fullpath, bool supports_rgba, unsigned upscale_threshold, retro_task_callback_t cb, void *userdata);