Batch create/remove steam shortcuts
This commit is contained in:
@@ -846,16 +846,19 @@ bool game_list_actions::RemoveContentList(const std::string& serial, bool is_int
|
|||||||
RemoveContentBySerial(rpcs3::utils::get_icons_dir(), serial, "icons");
|
RemoveContentBySerial(rpcs3::utils::get_icons_dir(), serial, "icons");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove shortcuts in "games/shortcuts" folder and from desktop / start menu (if any)
|
// Remove shortcuts in "games/shortcuts" folder and from desktop / start menu / Steam (if any)
|
||||||
if (content_types & SHORTCUTS)
|
if (content_types & SHORTCUTS)
|
||||||
{
|
{
|
||||||
if (const auto it = m_content_info.name_list.find(serial); it != m_content_info.name_list.cend())
|
if (const auto it = m_content_info.name_list.find(serial); it != m_content_info.name_list.cend())
|
||||||
{
|
{
|
||||||
|
std::vector<std::pair<std::string, std::string>> games;
|
||||||
for (const std::string& name : it->second)
|
for (const std::string& name : it->second)
|
||||||
{
|
{
|
||||||
// Remove all shortcuts
|
games.push_back(std::pair(name, serial));
|
||||||
gui::utils::remove_shortcuts(name, serial);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Batch remove all shortcuts
|
||||||
|
gui::utils::batch_remove_shortcuts(games);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1452,15 +1455,7 @@ void game_list_actions::CreateShortcuts(const std::vector<game_info>& games, con
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = true;
|
const bool success = gui::utils::batch_create_shortcuts(games, locations);
|
||||||
|
|
||||||
for (const game_info& gameinfo : games)
|
|
||||||
{
|
|
||||||
if (!gui::utils::create_shortcuts(gameinfo, locations))
|
|
||||||
{
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (locations.size() == 1 && locations.contains(gui::utils::shortcut_location::rpcs3_shortcuts))
|
if (locations.size() == 1 && locations.contains(gui::utils::shortcut_location::rpcs3_shortcuts))
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace gui::utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gui::utils::create_square_pixmap(icon, size))
|
if (!create_square_pixmap(icon, size))
|
||||||
{
|
{
|
||||||
sys_log.error("Failed to create shortcut. Icon empty.");
|
sys_log.error("Failed to create shortcut. Icon empty.");
|
||||||
return false;
|
return false;
|
||||||
@@ -109,6 +109,12 @@ namespace gui::utils
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string make_simple_name(const std::string& name)
|
||||||
|
{
|
||||||
|
const std::string simple_name = QString::fromStdString(vfs::escape(name, true)).simplified().toStdString();
|
||||||
|
return simple_name;
|
||||||
|
}
|
||||||
|
|
||||||
bool create_shortcut(const std::string& name,
|
bool create_shortcut(const std::string& name,
|
||||||
const std::string& path,
|
const std::string& path,
|
||||||
[[maybe_unused]] const std::string& serial,
|
[[maybe_unused]] const std::string& serial,
|
||||||
@@ -118,6 +124,7 @@ namespace gui::utils
|
|||||||
[[maybe_unused]] const std::string& target_icon_dir,
|
[[maybe_unused]] const std::string& target_icon_dir,
|
||||||
const std::string& src_banner_path,
|
const std::string& src_banner_path,
|
||||||
shortcut_location location,
|
shortcut_location location,
|
||||||
|
std::shared_ptr<steam_shortcut> steam_sc,
|
||||||
std::shared_ptr<iso_archive> archive)
|
std::shared_ptr<iso_archive> archive)
|
||||||
{
|
{
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
@@ -127,7 +134,7 @@ namespace gui::utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove illegal characters from filename
|
// Remove illegal characters from filename
|
||||||
const std::string simple_name = QString::fromStdString(vfs::escape(name, true)).simplified().toStdString();
|
const std::string simple_name = make_simple_name(name);
|
||||||
if (simple_name.empty() || simple_name == "." || simple_name == "..")
|
if (simple_name.empty() || simple_name == "." || simple_name == "..")
|
||||||
{
|
{
|
||||||
sys_log.error("Failed to create shortcut: Cleaned file name empty or not allowed");
|
sys_log.error("Failed to create shortcut: Cleaned file name empty or not allowed");
|
||||||
@@ -194,9 +201,8 @@ namespace gui::utils
|
|||||||
if (location == shortcut_location::steam)
|
if (location == shortcut_location::steam)
|
||||||
{
|
{
|
||||||
sys_log.notice("Creating %s shortcut with arguments '%s'", location, target_cli_args);
|
sys_log.notice("Creating %s shortcut with arguments '%s'", location, target_cli_args);
|
||||||
steam_shortcut steam_sc{};
|
ensure(steam_sc)->add_shortcut(simple_name, rpcs3_path, working_dir, target_cli_args, target_icon_path, src_icon_path, src_banner_path, archive);
|
||||||
steam_sc.add_shortcut(simple_name, rpcs3_path, working_dir, target_cli_args, target_icon_path, src_icon_path, src_banner_path, archive);
|
return true;
|
||||||
return steam_sc.write_file();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sys_log.notice("Creating %s shortcut '%s' with arguments '%s' and .ico dir '%s'", location, link_path, target_cli_args, target_icon_dir);
|
sys_log.notice("Creating %s shortcut '%s' with arguments '%s' and .ico dir '%s'", location, link_path, target_cli_args, target_icon_dir);
|
||||||
@@ -381,9 +387,8 @@ namespace gui::utils
|
|||||||
|
|
||||||
if (location == shortcut_location::steam)
|
if (location == shortcut_location::steam)
|
||||||
{
|
{
|
||||||
steam_shortcut steam_sc{};
|
ensure(steam_sc)->add_shortcut(simple_name, link_path, macos_dir, ""/*target_cli_args are already in the launcher*/, "", src_icon_path, src_banner_path, archive);
|
||||||
steam_sc.add_shortcut(simple_name, link_path, macos_dir, ""/*target_cli_args are already in the launcher*/, "", src_icon_path, src_banner_path, archive);
|
return true;
|
||||||
return steam_sc.write_file();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -410,9 +415,8 @@ namespace gui::utils
|
|||||||
{
|
{
|
||||||
sys_log.notice("Creating %s shortcut with arguments '%s'", location, target_cli_args);
|
sys_log.notice("Creating %s shortcut with arguments '%s'", location, target_cli_args);
|
||||||
const std::string working_dir{fs::get_executable_dir()};
|
const std::string working_dir{fs::get_executable_dir()};
|
||||||
steam_shortcut steam_sc{};
|
ensure(steam_sc)->add_shortcut(simple_name, exe_path, working_dir, target_cli_args, target_icon_path, src_icon_path, src_banner_path, archive);
|
||||||
steam_sc.add_shortcut(simple_name, exe_path, working_dir, target_cli_args, target_icon_path, src_icon_path, src_banner_path, archive);
|
return true;
|
||||||
return steam_sc.write_file();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::append(link_path, "/%s.desktop", simple_name);
|
fmt::append(link_path, "/%s.desktop", simple_name);
|
||||||
@@ -466,7 +470,8 @@ namespace gui::utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool create_shortcuts(const std::shared_ptr<gui_game_info>& game,
|
bool create_shortcuts(const std::shared_ptr<gui_game_info>& game,
|
||||||
const std::set<gui::utils::shortcut_location>& locations)
|
const std::set<shortcut_location>& locations,
|
||||||
|
std::shared_ptr<steam_shortcut> steam_sc)
|
||||||
{
|
{
|
||||||
if (!game || locations.empty()) return false;
|
if (!game || locations.empty()) return false;
|
||||||
|
|
||||||
@@ -530,11 +535,11 @@ namespace gui::utils
|
|||||||
const std::string cli_arg_token = is_vsh ? "RPCS3_VFS" : "RPCS3_GAMEID";
|
const std::string cli_arg_token = is_vsh ? "RPCS3_VFS" : "RPCS3_GAMEID";
|
||||||
const std::string cli_arg_value = is_vsh ? ("dev_flash/" + game->info.path.substr(dev_flash.size())) : gameid_token_value;
|
const std::string cli_arg_value = is_vsh ? ("dev_flash/" + game->info.path.substr(dev_flash.size())) : gameid_token_value;
|
||||||
|
|
||||||
for (gui::utils::shortcut_location location : locations)
|
for (shortcut_location location : locations)
|
||||||
{
|
{
|
||||||
std::string banner_path;
|
std::string banner_path;
|
||||||
|
|
||||||
if (location == gui::utils::shortcut_location::steam)
|
if (location == shortcut_location::steam)
|
||||||
{
|
{
|
||||||
// Try to find a nice banner for steam
|
// Try to find a nice banner for steam
|
||||||
const std::string sfo_dir = is_iso ? "PS3_GAME" : rpcs3::utils::get_sfo_dir_from_game_path(game->info.path);
|
const std::string sfo_dir = is_iso ? "PS3_GAME" : rpcs3::utils::get_sfo_dir_from_game_path(game->info.path);
|
||||||
@@ -550,19 +555,27 @@ namespace gui::utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
const std::string percent = location == gui::utils::shortcut_location::steam ? "%" : "%%";
|
const std::string percent = location == shortcut_location::steam ? "%" : "%%";
|
||||||
#else
|
#else
|
||||||
const std::string percent = "%";
|
const std::string percent = "%";
|
||||||
#endif
|
#endif
|
||||||
const std::string target_cli_args = fmt::format("--no-gui \"%s%s%s:%s\"", percent, cli_arg_token, percent, cli_arg_value);
|
const std::string target_cli_args = fmt::format("--no-gui \"%s%s%s:%s\"", percent, cli_arg_token, percent, cli_arg_value);
|
||||||
|
|
||||||
if (!gameid_token_value.empty() && create_shortcut(game->info.name, game->icon_in_archive ? game->info.path : "", game->info.serial, target_cli_args, game->info.name, game->info.icon_path, target_icon_dir, banner_path, location, archive))
|
if (!gameid_token_value.empty() && create_shortcut(game->info.name, game->icon_in_archive ? game->info.path : "", game->info.serial, target_cli_args, game->info.name, game->info.icon_path, target_icon_dir, banner_path, location, steam_sc, archive))
|
||||||
{
|
{
|
||||||
sys_log.success("Created %s shortcut for %s", location, QString::fromStdString(game->info.name).simplified());
|
if (location == shortcut_location::steam)
|
||||||
|
{
|
||||||
|
// Creation is done in caller
|
||||||
|
sys_log.notice("Prepared %s shortcut for '%s'", location, QString::fromStdString(game->info.name).simplified());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sys_log.success("Created %s shortcut for '%s'", location, QString::fromStdString(game->info.name).simplified());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sys_log.error("Failed to create %s shortcut for %s", location, QString::fromStdString(game->info.name).simplified());
|
sys_log.error("Failed to create %s shortcut for '%s'", location, QString::fromStdString(game->info.name).simplified());
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -570,9 +583,36 @@ namespace gui::utils
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_shortcuts(const std::string& name, [[maybe_unused]] const std::string& serial)
|
bool batch_create_shortcuts(const std::vector<std::shared_ptr<gui_game_info>>& games,
|
||||||
|
const std::set<shortcut_location>& locations)
|
||||||
|
{
|
||||||
|
if (games.empty() || locations.empty()) return false;
|
||||||
|
|
||||||
|
std::shared_ptr<steam_shortcut> steam_sc;
|
||||||
|
|
||||||
|
if (locations.contains(shortcut_location::steam))
|
||||||
|
{
|
||||||
|
// Batch steam shortcut creation
|
||||||
|
steam_sc = std::make_shared<steam_shortcut>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
for (const auto& game : games)
|
||||||
|
{
|
||||||
|
result &= create_shortcuts(game, locations, steam_sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (steam_sc)
|
||||||
|
{
|
||||||
|
result &= steam_sc->write_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_shortcuts(const std::string& simple_name, [[maybe_unused]] const std::string& serial)
|
||||||
{
|
{
|
||||||
const std::string simple_name = QString::fromStdString(vfs::escape(name, true)).simplified().toStdString();
|
|
||||||
if (simple_name.empty() || simple_name == "." || simple_name == "..")
|
if (simple_name.empty() || simple_name == "." || simple_name == "..")
|
||||||
{
|
{
|
||||||
sys_log.error("Failed to remove shortcuts: Cleaned file name empty or not allowed");
|
sys_log.error("Failed to remove shortcuts: Cleaned file name empty or not allowed");
|
||||||
@@ -611,7 +651,7 @@ namespace gui::utils
|
|||||||
std::vector<shortcut_location> locations = {
|
std::vector<shortcut_location> locations = {
|
||||||
shortcut_location::desktop,
|
shortcut_location::desktop,
|
||||||
shortcut_location::applications,
|
shortcut_location::applications,
|
||||||
shortcut_location::steam,
|
//shortcut_location::steam, // Handled separately
|
||||||
};
|
};
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
locations.push_back(shortcut_location::rpcs3_shortcuts);
|
locations.push_back(shortcut_location::rpcs3_shortcuts);
|
||||||
@@ -631,18 +671,8 @@ namespace gui::utils
|
|||||||
link_path += "/RPCS3";
|
link_path += "/RPCS3";
|
||||||
break;
|
break;
|
||||||
case shortcut_location::steam:
|
case shortcut_location::steam:
|
||||||
{
|
fmt::throw_exception("Steam shortcuts should be removed in batch");
|
||||||
const std::string exe_path = fs::get_executable_path();
|
break;
|
||||||
const std::string working_dir = fs::get_executable_dir();
|
|
||||||
steam_shortcut steam_sc{};
|
|
||||||
steam_sc.remove_shortcut(simple_name, exe_path, working_dir);
|
|
||||||
if (!steam_sc.write_file())
|
|
||||||
{
|
|
||||||
sys_log.error("Failed to remove steam shortcut for '%s'", simple_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
case shortcut_location::rpcs3_shortcuts:
|
case shortcut_location::rpcs3_shortcuts:
|
||||||
link_path = rpcs3::utils::get_games_shortcuts_dir();
|
link_path = rpcs3::utils::get_games_shortcuts_dir();
|
||||||
@@ -665,4 +695,32 @@ namespace gui::utils
|
|||||||
const std::string icon_path = fmt::format("%sIcons/game_icons/%s/shortcut.%s", fs::get_config_dir(), serial, icon_extension);
|
const std::string icon_path = fmt::format("%sIcons/game_icons/%s/shortcut.%s", fs::get_config_dir(), serial, icon_extension);
|
||||||
remove_path(icon_path, true);
|
remove_path(icon_path, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void batch_remove_shortcuts(const std::vector<std::pair<std::string /*name*/, std::string /*serial*/>>& games)
|
||||||
|
{
|
||||||
|
if (games.empty()) return;
|
||||||
|
|
||||||
|
// Batch steam shortcut removal
|
||||||
|
const std::string exe_path = fs::get_executable_path();
|
||||||
|
const std::string working_dir = fs::get_executable_dir();
|
||||||
|
const bool is_steam_installed = steam_shortcut::steam_installed();
|
||||||
|
steam_shortcut steam_sc{};
|
||||||
|
|
||||||
|
for (const auto& [name, serial] : games)
|
||||||
|
{
|
||||||
|
const std::string simple_name = make_simple_name(name);
|
||||||
|
|
||||||
|
remove_shortcuts(simple_name, serial);
|
||||||
|
|
||||||
|
if (is_steam_installed)
|
||||||
|
{
|
||||||
|
steam_sc.remove_shortcut(simple_name, exe_path, working_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_steam_installed && !steam_sc.write_file())
|
||||||
|
{
|
||||||
|
sys_log.error("Failed to remove steam shortcuts");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ class iso_archive;
|
|||||||
|
|
||||||
namespace gui::utils
|
namespace gui::utils
|
||||||
{
|
{
|
||||||
|
class steam_shortcut;
|
||||||
|
|
||||||
enum class shortcut_location
|
enum class shortcut_location
|
||||||
{
|
{
|
||||||
desktop,
|
desktop,
|
||||||
@@ -24,10 +26,11 @@ namespace gui::utils
|
|||||||
const std::string& target_icon_dir,
|
const std::string& target_icon_dir,
|
||||||
const std::string& src_banner_path,
|
const std::string& src_banner_path,
|
||||||
shortcut_location shortcut_location,
|
shortcut_location shortcut_location,
|
||||||
|
std::shared_ptr<steam_shortcut> steam_sc = nullptr,
|
||||||
std::shared_ptr<iso_archive> archive = nullptr);
|
std::shared_ptr<iso_archive> archive = nullptr);
|
||||||
|
|
||||||
bool create_shortcuts(const std::shared_ptr<gui_game_info>& game,
|
bool batch_create_shortcuts(const std::vector<std::shared_ptr<gui_game_info>>& games,
|
||||||
const std::set<gui::utils::shortcut_location>& locations);
|
const std::set<shortcut_location>& locations);
|
||||||
|
|
||||||
void remove_shortcuts(const std::string& name, const std::string& serial);
|
void batch_remove_shortcuts(const std::vector<std::pair<std::string /*name*/, std::string /*serial*/>>& games);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,7 +346,9 @@ namespace gui::utils
|
|||||||
const auto launch_options = entry.value<std::string>("LaunchOptions");
|
const auto launch_options = entry.value<std::string>("LaunchOptions");
|
||||||
const auto icon = entry.value<std::string>("icon");
|
const auto icon = entry.value<std::string>("icon");
|
||||||
|
|
||||||
if (appid.has_value() && appid.value() == it->appid &&
|
const bool appid_matches = appid.has_value() && appid.value() == it->appid;
|
||||||
|
|
||||||
|
if (appid_matches &&
|
||||||
exe.has_value() && exe.value() == it->exe &&
|
exe.has_value() && exe.value() == it->exe &&
|
||||||
start_dir.has_value() && start_dir.value() == it->start_dir &&
|
start_dir.has_value() && start_dir.value() == it->start_dir &&
|
||||||
launch_options.has_value() && launch_options.value() == it->launch_options &&
|
launch_options.has_value() && launch_options.value() == it->launch_options &&
|
||||||
@@ -357,6 +359,11 @@ namespace gui::utils
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (appid_matches)
|
||||||
|
{
|
||||||
|
sys_log.notice("Entry '%s' already exists in steam shortcut file '%s' but with other parameters. Creating an additional one...", it->app_name, file_path);
|
||||||
|
}
|
||||||
|
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,7 +376,7 @@ namespace gui::utils
|
|||||||
|
|
||||||
if (m_entries_to_add.empty() && removed_entries.empty())
|
if (m_entries_to_add.empty() && removed_entries.empty())
|
||||||
{
|
{
|
||||||
sys_log.notice("No matching entries found in steam shortcut file '%s'.", file_path);
|
sys_log.notice("Nothing to add or remove in steam shortcut file '%s'.", file_path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user