diff --git a/config.def.h b/config.def.h index 703036c0e7..8f7ce3ecf5 100644 --- a/config.def.h +++ b/config.def.h @@ -310,6 +310,8 @@ static bool quick_menu_show_save_core_overrides = true; static bool quick_menu_show_save_game_overrides = true; static bool quick_menu_show_save_content_dir_overrides = true; +static bool quick_menu_show_download_thumbnails = true; + static bool kiosk_mode_enable = false; static bool menu_horizontal_animation = true; diff --git a/configuration.c b/configuration.c index a5978dcbe9..2f431ec576 100644 --- a/configuration.c +++ b/configuration.c @@ -1487,6 +1487,9 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("quick_menu_show_save_game_overrides", &settings->bools.quick_menu_show_save_game_overrides, true, quick_menu_show_save_game_overrides, false); SETTING_BOOL("quick_menu_show_save_content_dir_overrides", &settings->bools.quick_menu_show_save_content_dir_overrides, true, quick_menu_show_save_content_dir_overrides, false); SETTING_BOOL("quick_menu_show_information", &settings->bools.quick_menu_show_information, true, quick_menu_show_information, false); +#ifdef HAVE_NETWORKING + SETTING_BOOL("quick_menu_show_download_thumbnails", &settings->bools.quick_menu_show_download_thumbnails, true, quick_menu_show_download_thumbnails, false); +#endif SETTING_BOOL("kiosk_mode_enable", &settings->bools.kiosk_mode_enable, true, kiosk_mode_enable, false); SETTING_BOOL("menu_use_preferred_system_color_theme", &settings->bools.menu_use_preferred_system_color_theme, true, menu_use_preferred_system_color_theme, false); SETTING_BOOL("content_show_settings", &settings->bools.menu_content_show_settings, true, content_show_settings, false); diff --git a/configuration.h b/configuration.h index d054847a28..9eeea244fa 100644 --- a/configuration.h +++ b/configuration.h @@ -214,6 +214,7 @@ typedef struct settings bool quick_menu_show_information; bool quick_menu_show_recording; bool quick_menu_show_streaming; + bool quick_menu_show_download_thumbnails; bool kiosk_mode_enable; bool crt_switch_custom_refresh_enable; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index fa8d69d982..8e0dfd30d2 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1029,6 +1029,8 @@ MSG_HASH(MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST, "favorites_add_playlist") MSG_HASH(MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION, "reset_core_association") +MSG_HASH(MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS, + "download_pl_entry_thumbnails") MSG_HASH(MENU_ENUM_LABEL_RUN, "collection") MSG_HASH(MENU_ENUM_LABEL_RUN_MUSIC, @@ -1593,6 +1595,8 @@ MSG_HASH(MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, "quick_menu_show_save_game_overrides") MSG_HASH(MENU_ENUM_LABEL_QUICK_MENU_SHOW_INFORMATION, "quick_menu_show_information") +MSG_HASH(MENU_ENUM_LABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, + "quick_menu_show_download_thumbnails") MSG_HASH(MENU_ENUM_LABEL_MENU_ENABLE_KIOSK_MODE, "menu_enable_kiosk_mode") MSG_HASH(MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index c540209e32..04472da7d6 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2462,6 +2462,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST, "Add to Favorites" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DOWNLOAD_PL_ENTRY_THUMBNAILS, + "Download Thumbnails" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS, + "Download screenshot/box art/title screen thumbnail images for current content. Updates any existing thumbnails." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION, "Reset Core Association" @@ -6819,6 +6827,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION, "Show/hide the 'Information' option." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, + "Show Download Thumbnails" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, + "Show/hide the 'Download Thumbnails' option." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_BGCOLOR_ENABLE, "Notification Background" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 4e50822413..b49403cecc 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -5392,6 +5392,29 @@ static int action_ok_pl_content_thumbnails(const char *path, #endif } +#ifdef HAVE_NETWORKING +static int action_ok_pl_entry_content_thumbnails(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + menu_handle_t *menu = NULL; + playlist_t *playlist = playlist_get_cached(); + char system[PATH_MAX_LENGTH]; + + system[0] = '\0'; + + if (!playlist) + return -1; + + if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu)) + return menu_cbs_exit(); + + menu_driver_get_thumbnail_system(system, sizeof(system)); + + task_push_pl_entry_thumbnail_download(system, playlist, menu->rpl_entry_selection_ptr); + return 0; +} +#endif + static int is_rdb_entry(enum msg_hash_enums enum_idx) { switch (enum_idx) @@ -5693,6 +5716,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST: BIND_ACTION_OK(cbs, action_ok_pl_thumbnails_updater_list); break; + case MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS: + BIND_ACTION_OK(cbs, action_ok_pl_entry_content_thumbnails); + break; case MENU_ENUM_LABEL_UPDATE_LAKKA: BIND_ACTION_OK(cbs, action_ok_lakka_list); break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 9d570d8dce..dc025c8d2d 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -348,6 +348,7 @@ default_sublabel_macro(action_bind_sublabel_delete_entry, default_sublabel_macro(action_bind_sublabel_information, MENU_ENUM_SUBLABEL_INFORMATION) default_sublabel_macro(action_bind_sublabel_run, MENU_ENUM_SUBLABEL_RUN) default_sublabel_macro(action_bind_sublabel_add_to_favorites, MENU_ENUM_SUBLABEL_ADD_TO_FAVORITES) +default_sublabel_macro(action_bind_sublabel_download_pl_entry_thumbnails, MENU_ENUM_SUBLABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS) default_sublabel_macro(action_bind_sublabel_goto_favorites, MENU_ENUM_SUBLABEL_GOTO_FAVORITES) default_sublabel_macro(action_bind_sublabel_goto_images, MENU_ENUM_SUBLABEL_GOTO_IMAGES) default_sublabel_macro(action_bind_sublabel_goto_music, MENU_ENUM_SUBLABEL_GOTO_MUSIC) @@ -433,6 +434,7 @@ default_sublabel_macro(action_bind_sublabel_content_show_latency, default_sublabel_macro(action_bind_sublabel_quick_menu_show_save_core_overrides, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES) default_sublabel_macro(action_bind_sublabel_quick_menu_show_save_game_overrides, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES) default_sublabel_macro(action_bind_sublabel_quick_menu_show_information, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_INFORMATION) +default_sublabel_macro(action_bind_sublabel_quick_menu_show_download_thumbnails, MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS) default_sublabel_macro(action_bind_sublabel_menu_enable_kiosk_mode, MENU_ENUM_SUBLABEL_MENU_ENABLE_KIOSK_MODE) default_sublabel_macro(action_bind_sublabel_menu_disable_kiosk_mode, MENU_ENUM_SUBLABEL_MENU_DISABLE_KIOSK_MODE) default_sublabel_macro(action_bind_sublabel_menu_kiosk_mode_password, MENU_ENUM_SUBLABEL_MENU_KIOSK_MODE_PASSWORD) @@ -1319,6 +1321,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_QUICK_MENU_SHOW_INFORMATION: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_quick_menu_show_information); break; + case MENU_ENUM_LABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_quick_menu_show_download_thumbnails); + break; case MENU_ENUM_LABEL_MENU_ENABLE_KIOSK_MODE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_enable_kiosk_mode); break; @@ -1569,6 +1574,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_ADD_TO_FAVORITES: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_add_to_favorites); break; + case MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_download_pl_entry_thumbnails); + break; case MENU_ENUM_LABEL_RUN: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_run); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index d296231ce3..c52d14095f 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -2361,6 +2361,7 @@ static void materialui_list_insert(void *userdata, node->texture_switch2_set = true; break; case FILE_TYPE_DOWNLOAD_THUMBNAIL_CONTENT: + case FILE_TYPE_DOWNLOAD_PL_THUMBNAIL_CONTENT: node->texture_switch2_index = MUI_TEXTURE_IMAGE; node->texture_switch2_set = true; break; @@ -2678,6 +2679,7 @@ static void materialui_list_insert(void *userdata, string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CORE_UPDATER_LIST)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST)) || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_UPDATER_SETTINGS)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS)) ) @@ -2785,6 +2787,7 @@ menu_ctx_driver_t menu_ctx_mui = { NULL, NULL, NULL, + NULL, menu_display_osk_ptr_at_pos, NULL, /* update_savestate_thumbnail_path */ NULL, /* update_savestate_thumbnail_image */ diff --git a/menu/drivers/null.c b/menu/drivers/null.c index 5ddacd62e0..30dd9a88d7 100644 --- a/menu/drivers/null.c +++ b/menu/drivers/null.c @@ -92,6 +92,7 @@ menu_ctx_driver_t menu_ctx_null = { NULL, /* update_thumbnail_path */ NULL, /* update_thumbnail_image */ NULL, /* set_thumbnail_system */ + NULL, /* get_thumbnail_system */ NULL, /* set_thumbnail_content */ NULL, /* osk_ptr_at_pos */ NULL, /* update_savestate_thumbnail_path */ diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index f47655db74..e365c6bf45 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -1276,6 +1276,17 @@ static void ozone_set_thumbnail_system(void *data, char*s, size_t len) menu_thumbnail_set_system(ozone->thumbnail_path_data, s); } +static void ozone_get_thumbnail_system(void *data, char*s, size_t len) +{ + ozone_handle_t *ozone = (ozone_handle_t*)data; + const char *system = NULL; + if (!ozone) + return; + + if (menu_thumbnail_get_system(ozone->thumbnail_path_data, &system)) + strlcpy(s, system, len); +} + static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) { menu_entry_t entry; @@ -2298,6 +2309,7 @@ menu_ctx_driver_t menu_ctx_ozone = { ozone_update_thumbnail_path, ozone_update_thumbnail_image, ozone_set_thumbnail_system, + ozone_get_thumbnail_system, ozone_set_thumbnail_content, menu_display_osk_ptr_at_pos, NULL, /* update_savestate_thumbnail_path */ diff --git a/menu/drivers/ozone/ozone_texture.c b/menu/drivers/ozone/ozone_texture.c index 23c25d8f19..f9353feaa1 100644 --- a/menu/drivers/ozone/ozone_texture.c +++ b/menu/drivers/ozone/ozone_texture.c @@ -121,6 +121,8 @@ menu_texture_item ozone_entries_icon_get_texture(ozone_handle_t *ozone, case MENU_ENUM_LABEL_UPDATE_CHEATS: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CHEAT_OPTIONS]; case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: + case MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST: + case MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; case MENU_ENUM_LABEL_UPDATE_OVERLAYS: case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS: diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index b8624f14fd..e449539fc7 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -4148,6 +4148,16 @@ static void rgui_set_thumbnail_system(void *userdata, char *s, size_t len) menu_thumbnail_set_system(rgui->thumbnail_path_data, s); } +static void rgui_get_thumbnail_system(void *userdata, char *s, size_t len) +{ + rgui_t *rgui = (rgui_t*)userdata; + const char *system = NULL; + if (!rgui) + return; + if (menu_thumbnail_get_system(rgui->thumbnail_path_data, &system)) + strlcpy(s, system, len); +} + static void rgui_load_current_thumbnails(rgui_t *rgui) { const char *thumbnail_path = NULL; @@ -4685,6 +4695,7 @@ menu_ctx_driver_t menu_ctx_rgui = { NULL, /* update_thumbnail_path */ rgui_update_thumbnail_image, rgui_set_thumbnail_system, + rgui_get_thumbnail_system, NULL, /* set_thumbnail_content */ NULL, /* osk_ptr_at_pos */ NULL, /* update_savestate_thumbnail_path */ diff --git a/menu/drivers/stripes.c b/menu/drivers/stripes.c index 3a38af4f69..d699ae0985 100644 --- a/menu/drivers/stripes.c +++ b/menu/drivers/stripes.c @@ -1101,6 +1101,16 @@ static void stripes_set_thumbnail_system(void *data, char*s, size_t len) stripes->thumbnail_system = strdup(s); } +static void stripes_get_thumbnail_system(void *data, char*s, size_t len) +{ + stripes_handle_t *stripes = (stripes_handle_t*)data; + if (!stripes) + return; + + if (!string_is_empty(stripes->thumbnail_system)) + strlcpy(s, stripes->thumbnail_system, len); +} + static void stripes_reset_thumbnail_content(void *data) { stripes_handle_t *stripes = (stripes_handle_t*)data; @@ -4442,6 +4452,7 @@ menu_ctx_driver_t menu_ctx_stripes = { stripes_update_thumbnail_path, stripes_update_thumbnail_image, stripes_set_thumbnail_system, + stripes_get_thumbnail_system, stripes_set_thumbnail_content, stripes_osk_ptr_at_pos, stripes_update_savestate_thumbnail_path, diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 133eeaa36a..b44f67dfac 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1040,6 +1040,17 @@ static void xmb_set_thumbnail_system(void *data, char*s, size_t len) menu_thumbnail_set_system(xmb->thumbnail_path_data, s); } +static void xmb_get_thumbnail_system(void *data, char*s, size_t len) +{ + xmb_handle_t *xmb = (xmb_handle_t*)data; + const char *system = NULL; + if (!xmb) + return; + + if (menu_thumbnail_get_system(xmb->thumbnail_path_data, &system)) + strlcpy(s, system, len); +} + static void xmb_unload_thumbnail_textures(void *data) { xmb_handle_t *xmb = (xmb_handle_t*)data; @@ -2304,6 +2315,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_UPDATE_CHEATS: return xmb->textures.list[XMB_TEXTURE_CHEAT_OPTIONS]; case MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST: + case MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST: + case MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS: return xmb->textures.list[XMB_TEXTURE_IMAGE]; case MENU_ENUM_LABEL_UPDATE_OVERLAYS: case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS: @@ -5735,6 +5748,7 @@ menu_ctx_driver_t menu_ctx_xmb = { xmb_update_thumbnail_path, xmb_update_thumbnail_image, xmb_set_thumbnail_system, + xmb_get_thumbnail_system, xmb_set_thumbnail_content, menu_display_osk_ptr_at_pos, xmb_update_savestate_thumbnail_path, diff --git a/menu/drivers/xui.cpp b/menu/drivers/xui.cpp index 500f7fab56..6c7a1e4c07 100644 --- a/menu/drivers/xui.cpp +++ b/menu/drivers/xui.cpp @@ -742,6 +742,7 @@ menu_ctx_driver_t menu_ctx_xui = { NULL, /* update_thumbnail_path */ NULL, /* update_thumbnail_image */ NULL, /* set_thumbnail_system */ + NULL, /* get_thumbnail_system */ NULL, /* set_thumbnail_content */ NULL, /* osk_ptr_at_pos */ NULL, /* update_savestate_thumbnail_path */ diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 833f337226..fb43273301 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -841,10 +841,15 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info, * is nonsensical in these cases (and we *do* need * to call set_thumbnail_system() in these cases, * since all three playlist types have thumbnail - * support) */ + * support) + * EDIT: For correct operation of the quick menu + * 'download thumbnails' option, we must also extend + * this to music_history and video_history */ if (string_is_equal(path_playlist, "history") || string_is_equal(path_playlist, "favorites") || - string_is_equal(path_playlist, "images_history")) + string_is_equal(path_playlist, "images_history") || + string_is_equal(path_playlist, "music_history") || + string_is_equal(path_playlist, "video_history")) { char system_name[15]; system_name[0] = '\0'; @@ -2074,6 +2079,47 @@ static int menu_displaylist_parse_horizontal_content_actions( free(db_path); } +#ifdef HAVE_NETWORKING + if (settings->bools.quick_menu_show_download_thumbnails && !settings->bools.kiosk_mode_enable) + { + bool download_enabled = true; + + /* If content is currently running, have to make sure + * we have a valid playlist to work with */ + if (content_loaded) + { + const char *core_path = path_get(RARCH_PATH_CORE); + + download_enabled = false; + if (!string_is_empty(fullpath) && !string_is_empty(core_path)) + download_enabled = playlist_index_is_valid( + playlist, idx, fullpath, core_path); + } + + if (download_enabled) + { + char system[PATH_MAX_LENGTH]; + + system[0] = '\0'; + + /* Only show 'download thumbnails' on supported playlists */ + download_enabled = false; + menu_driver_get_thumbnail_system(system, sizeof(system)); + + if (!string_is_empty(system)) + download_enabled = !string_is_equal(system, "images_history") && + !string_is_equal(system, "music_history") && + !string_is_equal(system, "video_history"); + } + + if (download_enabled) + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_PL_ENTRY_THUMBNAILS), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS), + MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS, FILE_TYPE_PLAYLIST_ENTRY, 0, 0); + } +#endif + return 0; } @@ -2549,6 +2595,7 @@ static void menu_displaylist_parse_playlist_associations( string_list_free(str_list); } +#ifdef HAVE_NETWORKING static unsigned menu_displaylist_parse_pl_thumbnail_download_list( menu_displaylist_info_t *info) { @@ -2598,6 +2645,7 @@ static unsigned menu_displaylist_parse_pl_thumbnail_download_list( return count; } +#endif static bool menu_displaylist_push_internal( const char *label, @@ -4141,6 +4189,9 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct {MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_QUICK_MENU_SHOW_INFORMATION, PARSE_ONLY_BOOL}, +#ifdef HAVE_NETWORKING + {MENU_ENUM_LABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, PARSE_ONLY_BOOL}, +#endif }; for (i = 0; i < ARRAY_SIZE(build_list); i++) diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 89b7c0cbc1..678f8dec1f 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -2230,6 +2230,12 @@ void menu_driver_set_thumbnail_system(char *s, size_t len) menu_driver_ctx->set_thumbnail_system(menu_userdata, s, len); } +void menu_driver_get_thumbnail_system(char *s, size_t len) +{ + if (menu_driver_ctx && menu_driver_ctx->get_thumbnail_system) + menu_driver_ctx->get_thumbnail_system(menu_userdata, s, len); +} + void menu_driver_set_thumbnail_content(char *s, size_t len) { if (menu_driver_ctx && menu_driver_ctx->set_thumbnail_content) diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 46d8c67943..7bf1808a01 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -385,6 +385,7 @@ typedef struct menu_ctx_driver void (*update_thumbnail_path)(void *data, unsigned i, char pos); void (*update_thumbnail_image)(void *data); void (*set_thumbnail_system)(void *data, char* s, size_t len); + void (*get_thumbnail_system)(void *data, char* s, size_t len); void (*set_thumbnail_content)(void *data, const char *s); int (*osk_ptr_at_pos)(void *data, int x, int y, unsigned width, unsigned height); void (*update_savestate_thumbnail_path)(void *data, unsigned i); @@ -527,6 +528,8 @@ void menu_driver_free(void); void menu_driver_set_thumbnail_system(char *s, size_t len); +void menu_driver_get_thumbnail_system(char *s, size_t len); + void menu_driver_set_thumbnail_content(char *s, size_t len); bool menu_driver_list_insert(menu_ctx_list_t *list); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 4ae4b2d6a2..23ed2272ea 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -12813,6 +12813,23 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); +#ifdef HAVE_NETWORKING + CONFIG_BOOL( + list, list_info, + &settings->bools.quick_menu_show_download_thumbnails, + MENU_ENUM_LABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, + quick_menu_show_download_thumbnails, + 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); +#endif + if (string_is_not_equal(ui_companion_driver_get_ident(), "null")) { CONFIG_BOOL( diff --git a/menu/menu_thumbnail_path.c b/menu/menu_thumbnail_path.c index 6babac1f61..6022622025 100644 --- a/menu/menu_thumbnail_path.c +++ b/menu/menu_thumbnail_path.c @@ -470,6 +470,7 @@ bool menu_thumbnail_update_path(menu_thumbnail_path_data_t *path_data, enum menu } thumbnail_path[0] = '\0'; + content_dir[0] = '\0'; /* Sundry error checking */ if (!settings) @@ -500,24 +501,10 @@ bool menu_thumbnail_update_path(menu_thumbnail_path_data_t *path_data, enum menu if (string_is_equal(path_data->system, "history") || string_is_equal(path_data->system, "favorites")) { - char tmp_buf[PATH_MAX_LENGTH] = {0}; - const char *last_slash = find_last_slash(path_data->content_path); - - content_dir[0] = '\0'; - system_name = content_dir; - - if (last_slash) - { - size_t path_length = last_slash + 1 - path_data->content_path; - if ((path_length > 1) && (path_length < PATH_MAX_LENGTH)) - { - strlcpy(tmp_buf, path_data->content_path, path_length * sizeof(char)); - strlcpy(content_dir, path_basename(tmp_buf), sizeof(content_dir)); - } - } - - if (string_is_empty(system_name)) + if (!menu_thumbnail_get_content_dir(path_data, content_dir, sizeof(content_dir))) return false; + + system_name = content_dir; } else system_name = path_data->system; @@ -705,3 +692,36 @@ bool menu_thumbnail_get_img_name(menu_thumbnail_path_data_t *path_data, const ch return true; } + +/* Fetches current content directory. + * Returns true if content directory is valid. */ +bool menu_thumbnail_get_content_dir(menu_thumbnail_path_data_t *path_data, char *content_dir, size_t len) +{ + const char *last_slash = NULL; + char tmp_buf[PATH_MAX_LENGTH] = {0}; + size_t path_length; + + if (!path_data) + return false; + + if (string_is_empty(path_data->content_path)) + return false; + + last_slash = find_last_slash(path_data->content_path); + + if (!last_slash) + return false; + + path_length = last_slash + 1 - path_data->content_path; + + if (!((path_length > 1) && (path_length < PATH_MAX_LENGTH))) + return false; + + strlcpy(tmp_buf, path_data->content_path, path_length * sizeof(char)); + strlcpy(content_dir, path_basename(tmp_buf), len); + + if (string_is_empty(content_dir)) + return false; + + return true; +} diff --git a/menu/menu_thumbnail_path.h b/menu/menu_thumbnail_path.h index d96df13706..958f585be6 100644 --- a/menu/menu_thumbnail_path.h +++ b/menu/menu_thumbnail_path.h @@ -147,6 +147,10 @@ bool menu_thumbnail_get_db_name(menu_thumbnail_path_data_t *path_data, const cha * Returns true if image name is valid. */ bool menu_thumbnail_get_img_name(menu_thumbnail_path_data_t *path_data, const char **img_name); +/* Fetches current content directory. + * Returns true if content directory is valid. */ +bool menu_thumbnail_get_content_dir(menu_thumbnail_path_data_t *path_data, char *content_dir, size_t len); + RETRO_END_DECLS #endif diff --git a/msg_hash.h b/msg_hash.h index 8f1f817098..bcfc62065d 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -965,6 +965,7 @@ enum msg_hash_enums MENU_LABEL(QUICK_MENU_STOP_RECORDING), MENU_LABEL(QUICK_MENU_START_STREAMING), MENU_LABEL(QUICK_MENU_STOP_STREAMING), + MENU_LABEL(QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS), MENU_LABEL(MENU_TICKER_TYPE), MENU_LABEL(MENU_TICKER_SPEED), @@ -1032,6 +1033,7 @@ enum msg_hash_enums MENU_LABEL(MENU_THROTTLE_FRAMERATE), MENU_LABEL(NO_ACHIEVEMENTS_TO_DISPLAY), MENU_LABEL(NO_ENTRIES_TO_DISPLAY), + MENU_LABEL(DOWNLOAD_PL_ENTRY_THUMBNAILS), /* Help */ diff --git a/tasks/task_pl_thumbnail_download.c b/tasks/task_pl_thumbnail_download.c index 8a8f92a61b..5639bfc6af 100644 --- a/tasks/task_pl_thumbnail_download.c +++ b/tasks/task_pl_thumbnail_download.c @@ -33,6 +33,7 @@ #include "../playlist.h" #include "../menu/menu_thumbnail_path.h" #include "../menu/menu_cbs.h" +#include "../menu/menu_driver.h" #ifndef COLLECTION_SIZE #define COLLECTION_SIZE 99999 @@ -59,6 +60,10 @@ typedef struct pl_thumb_handle enum pl_thumb_status status; } pl_thumb_handle_t; +/*********************/ +/* Utility Functions */ +/*********************/ + /* Fetches local and remote paths for current thumbnail * of current type */ static bool get_thumbnail_paths( @@ -72,11 +77,13 @@ static bool get_thumbnail_paths( const char *img_name = NULL; const char *sub_dir = NULL; const char *system_name = NULL; + char content_dir[PATH_MAX_LENGTH]; char raw_url[2048]; char tmp_buf[PATH_MAX_LENGTH]; - raw_url[0] = '\0'; - tmp_buf[0] = '\0'; + content_dir[0] = '\0'; + raw_url[0] = '\0'; + tmp_buf[0] = '\0'; /* Sanity check */ if (!pl_thumb || !settings) @@ -97,9 +104,29 @@ static bool get_thumbnail_paths( return false; /* Dermine system name */ - system_name = string_is_empty(db_name) ? system : db_name; - if (string_is_empty(system_name)) - return false; + if (string_is_empty(db_name)) + { + if (string_is_empty(system)) + return false; + + /* If this is a content history or favorites playlist + * then the current 'path_data->system' string is + * meaningless. In this case, we fall back to the + * content directory name */ + if (string_is_equal(system, "history") || + string_is_equal(system, "favorites")) + { + if (!menu_thumbnail_get_content_dir( + pl_thumb->thumbnail_path_data, content_dir, sizeof(content_dir))) + return false; + + system_name = content_dir; + } + else + system_name = system; + } + else + system_name = db_name; /* Generate local path */ fill_pathname_join(path, settings->paths.directory_thumbnails, @@ -132,7 +159,7 @@ static bool get_thumbnail_paths( /* Download thumbnail of the current type for the current * playlist entry */ -static void download_pl_thumbnail(pl_thumb_handle_t *pl_thumb) +static void download_pl_thumbnail(pl_thumb_handle_t *pl_thumb, bool overwrite) { char path[PATH_MAX_LENGTH]; char url[2048]; @@ -148,7 +175,7 @@ static void download_pl_thumbnail(pl_thumb_handle_t *pl_thumb) if (get_thumbnail_paths(pl_thumb, path, sizeof(path), url, sizeof(url))) { /* Only download missing thumbnails */ - if (!filestream_exists(path)) + if (!filestream_exists(path) || overwrite) { file_transfer_t *transf = (file_transfer_t*)calloc(1, sizeof(file_transfer_t)); if (!transf) @@ -166,6 +193,61 @@ static void download_pl_thumbnail(pl_thumb_handle_t *pl_thumb) } } +static void free_pl_thumb_handle(pl_thumb_handle_t *pl_thumb, bool free_playlist) +{ + if (pl_thumb) + { + if (!string_is_empty(pl_thumb->system)) + { + free(pl_thumb->system); + pl_thumb->system = NULL; + } + + if (!string_is_empty(pl_thumb->playlist_path)) + { + free(pl_thumb->playlist_path); + pl_thumb->playlist_path = NULL; + } + + if (pl_thumb->playlist && free_playlist) + { + playlist_free(pl_thumb->playlist); + pl_thumb->playlist = NULL; + } + + if (pl_thumb->thumbnail_path_data) + { + free(pl_thumb->thumbnail_path_data); + pl_thumb->thumbnail_path_data = NULL; + } + + free(pl_thumb); + pl_thumb = NULL; + } +} + +/* Callback: Refresh menu thumbnail display once + * download is complete */ +static void cb_task_pl_thumbnail_refresh_menu( + retro_task_t *task, void *task_data, + void *user_data, const char *err) +{ + settings_t *settings = config_get_ptr(); + + if (!settings) + return; + + /* RGUI is a special case where update_thumbnail_image() + * toggles fullscreen thumbnails - it should therefore + * never be 'refreshed' like this */ + if(!string_is_equal(settings->arrays.menu_driver, "rgui")) + menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE, NULL); +} + +/*******************************/ +/* Playlist Thumbnail Download */ +/*******************************/ + static void task_pl_thumbnail_download_handler(retro_task_t *task) { pl_thumb_handle_t *pl_thumb = NULL; @@ -232,6 +314,14 @@ static void task_pl_thumbnail_download_handler(retro_task_t *task) pl_thumb->type_idx = 1; pl_thumb->status = PL_THUMB_ITERATE_TYPE; } + else + { + /* Current playlist entry is broken - advance to + * the next one */ + pl_thumb->list_index++; + if (pl_thumb->list_index >= pl_thumb->list_size) + pl_thumb->status = PL_THUMB_END; + } } break; case PL_THUMB_ITERATE_TYPE: @@ -246,11 +336,7 @@ static void task_pl_thumbnail_download_handler(retro_task_t *task) break; } - /* Download current thumbnail */ - download_pl_thumbnail(pl_thumb); - - /* Increment thumbnail type */ - pl_thumb->type_idx++; + /* Check whether all thumbnail types have been processed */ if (pl_thumb->type_idx > 3) { /* Time to move on to the next entry */ @@ -259,7 +345,14 @@ static void task_pl_thumbnail_download_handler(retro_task_t *task) pl_thumb->status = PL_THUMB_ITERATE_ENTRY; else pl_thumb->status = PL_THUMB_END; + break; } + + /* Download current thumbnail */ + download_pl_thumbnail(pl_thumb, false); + + /* Increment thumbnail type */ + pl_thumb->type_idx++; } break; case PL_THUMB_END: @@ -276,35 +369,7 @@ task_finished: if (task) task_set_finished(task, true); - if (pl_thumb) - { - if (!string_is_empty(pl_thumb->system)) - { - free(pl_thumb->system); - pl_thumb->system = NULL; - } - - if (!string_is_empty(pl_thumb->playlist_path)) - { - free(pl_thumb->playlist_path); - pl_thumb->playlist_path = NULL; - } - - if (pl_thumb->playlist) - { - playlist_free(pl_thumb->playlist); - pl_thumb->playlist = NULL; - } - - if (pl_thumb->thumbnail_path_data) - { - free(pl_thumb->thumbnail_path_data); - pl_thumb->thumbnail_path_data = NULL; - } - - free(pl_thumb); - pl_thumb = NULL; - } + free_pl_thumb_handle(pl_thumb, true); } bool task_push_pl_thumbnail_download( @@ -312,12 +377,22 @@ bool task_push_pl_thumbnail_download( { retro_task_t *task = task_init(); pl_thumb_handle_t *pl_thumb = (pl_thumb_handle_t*)calloc(1, sizeof(pl_thumb_handle_t)); + const char *playlist_file = path_basename(playlist_path); /* Sanity check */ - if (!task || !pl_thumb || string_is_empty(system) || string_is_empty(playlist_path)) + if (!task || !pl_thumb || + string_is_empty(system) || + string_is_empty(playlist_path) || + string_is_empty(playlist_file)) goto error; - if (string_is_equal(system, "history") || + /* Only parse supported playlist types */ + if (string_is_equal(playlist_file, file_path_str(FILE_PATH_CONTENT_HISTORY)) || + string_is_equal(playlist_file, file_path_str(FILE_PATH_CONTENT_FAVORITES)) || + string_is_equal(playlist_file, file_path_str(FILE_PATH_CONTENT_MUSIC_HISTORY)) || + string_is_equal(playlist_file, file_path_str(FILE_PATH_CONTENT_VIDEO_HISTORY)) || + string_is_equal(playlist_file, file_path_str(FILE_PATH_CONTENT_IMAGE_HISTORY)) || + string_is_equal(system, "history") || string_is_equal(system, "favorites") || string_is_equal(system, "images_history")) goto error; @@ -360,3 +435,158 @@ error: return false; } + +/*************************************/ +/* Playlist Entry Thumbnail Download */ +/*************************************/ + +static void task_pl_entry_thumbnail_download_handler(retro_task_t *task) +{ + pl_thumb_handle_t *pl_thumb = NULL; + + if (!task) + goto task_finished; + + pl_thumb = (pl_thumb_handle_t*)task->state; + + if (!pl_thumb) + goto task_finished; + + if (task_get_cancelled(task)) + goto task_finished; + + switch (pl_thumb->status) + { + case PL_THUMB_BEGIN: + { + const char *label = NULL; + + /* Initialise thumbnail path data */ + pl_thumb->thumbnail_path_data = menu_thumbnail_path_init(); + + if (!pl_thumb->thumbnail_path_data) + goto task_finished; + + if (!menu_thumbnail_set_system(pl_thumb->thumbnail_path_data, pl_thumb->system)) + goto task_finished; + + if (!menu_thumbnail_set_content_playlist( + pl_thumb->thumbnail_path_data, pl_thumb->playlist, pl_thumb->list_index)) + goto task_finished; + + /* Set task title */ + task_free_title(task); + if (menu_thumbnail_get_label(pl_thumb->thumbnail_path_data, &label)) + task_set_title(task, strdup(label)); + else + task_set_title(task, strdup("")); + task_set_progress(task, 0); + + /* All good - can start iterating */ + pl_thumb->status = PL_THUMB_ITERATE_TYPE; + } + break; + case PL_THUMB_ITERATE_TYPE: + { + /* Ensure that we only enqueue one transfer + * at a time... */ + if (pl_thumb->http_task) + { + if (task_get_finished(pl_thumb->http_task)) + pl_thumb->http_task = NULL; + else + break; + } + + /* Check whether all thumbnail types have been processed */ + if (pl_thumb->type_idx > 3) + { + pl_thumb->status = PL_THUMB_END; + break; + } + + /* Update progress */ + task_set_progress(task, ((pl_thumb->type_idx - 1) * 100) / 3); + + /* Download current thumbnail */ + download_pl_thumbnail(pl_thumb, true); + + /* Increment thumbnail type */ + pl_thumb->type_idx++; + } + break; + case PL_THUMB_END: + default: + task_set_progress(task, 100); + goto task_finished; + break; + } + + return; + +task_finished: + + if (task) + task_set_finished(task, true); + + free_pl_thumb_handle(pl_thumb, false); +} + +bool task_push_pl_entry_thumbnail_download( + const char *system, playlist_t *playlist, unsigned idx) +{ + retro_task_t *task = task_init(); + pl_thumb_handle_t *pl_thumb = (pl_thumb_handle_t*)calloc(1, sizeof(pl_thumb_handle_t)); + + /* Sanity check */ + if (!task || !pl_thumb || !playlist || string_is_empty(system)) + goto error; + + if (idx >= playlist_size(playlist)) + goto error; + + /* Only parse supported playlist types */ + if (string_is_equal(system, "images_history") || + string_is_equal(system, "music_history") || + string_is_equal(system, "video_history")) + goto error; + + /* Configure task */ + task->handler = task_pl_entry_thumbnail_download_handler; + task->state = pl_thumb; + task->title = strdup(system); + task->alternative_look = true; + task->progress = 0; + task->callback = cb_task_pl_thumbnail_refresh_menu; + + /* Configure handle */ + pl_thumb->system = strdup(system); + pl_thumb->playlist_path = NULL; + pl_thumb->playlist = playlist; + pl_thumb->thumbnail_path_data = NULL; + pl_thumb->http_task = NULL; + pl_thumb->list_size = playlist_size(playlist); + pl_thumb->list_index = idx; + pl_thumb->type_idx = 1; + pl_thumb->status = PL_THUMB_BEGIN; + + task_queue_push(task); + + return true; + +error: + + if (task) + { + free(task); + task = NULL; + } + + if (pl_thumb) + { + free(pl_thumb); + pl_thumb = NULL; + } + + return false; +} diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index 2056adec21..d7c6924e36 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -28,6 +28,11 @@ #include "../config.h" #endif +#if defined(HAVE_NETWORKING) && defined(HAVE_MENU) +/* Required for task_push_pl_entry_thumbnail_download() */ +#include "../playlist.h" +#endif + RETRO_BEGIN_DECLS #ifdef HAVE_NETWORKING @@ -58,6 +63,7 @@ bool task_push_netplay_nat_traversal(void *nat_traversal_state, uint16_t port); #ifdef HAVE_MENU bool task_push_pl_thumbnail_download(const char *system, const char *playlist_path); +bool task_push_pl_entry_thumbnail_download(const char *system, playlist_t *playlist, unsigned idx); #endif #endif