From 829d263bc7fcc55dbaccbcb273b33c44ddeda2b4 Mon Sep 17 00:00:00 2001 From: loki-47-6F-64 Date: Wed, 3 Aug 2022 14:53:45 +0200 Subject: [PATCH] Show local cloud save files --- include/downloader.h | 3 ++ main.cpp | 13 +++++ src/downloader.cpp | 111 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 116 insertions(+), 11 deletions(-) diff --git a/include/downloader.h b/include/downloader.h index ad97169..cc78c51 100644 --- a/include/downloader.h +++ b/include/downloader.h @@ -117,10 +117,13 @@ class Downloader void galaxyInstallGameById(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64); void galaxyShowBuilds(const std::string& product_id, int build_index = -1); void galaxyShowCloudSaves(const std::string& product_id, int build_index = -1); + void galaxyShowLocalCloudSaves(const std::string& product_id, int build_index = -1); + void galaxyShowLocalCloudSavesById(const std::string& product_id, int build_index = -1); void galaxyShowBuildsById(const std::string& product_id, int build_index = -1); void galaxyShowCloudSavesById(const std::string& product_id, int build_index = -1); protected: private: + std::map cloudSaveLocations(const std::string& product_id, int build_index); int cloudSaveListByIdForEach(const std::string& product_id, int build_index, const std::function &f); CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string()); diff --git a/main.cpp b/main.cpp index 949dfb0..429605c 100644 --- a/main.cpp +++ b/main.cpp @@ -164,6 +164,7 @@ int main(int argc, char *argv[]) std::string galaxy_product_id_install; std::string galaxy_product_id_show_builds; std::string galaxy_product_id_show_cloud_paths; + std::string galaxy_product_id_show_local_cloud_paths; std::string galaxy_product_cloud_saves; std::string tags; @@ -288,6 +289,7 @@ int main(int argc, char *argv[]) ("galaxy-show-builds", bpo::value(&galaxy_product_id_show_builds)->default_value(""), "Show game builds using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") ("galaxy-download-cloud-saves", bpo::value(&galaxy_product_cloud_saves)->default_value(""), "Download cloud saves using product-id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") ("galaxy-show-cloud-saves", bpo::value(&galaxy_product_id_show_cloud_paths)->default_value(""), "Show game cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") + ("galaxy-show-local-cloud-saves", bpo::value(&galaxy_product_id_show_local_cloud_paths)->default_value(""), "Show local cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") ("galaxy-platform", bpo::value(&sGalaxyPlatform)->default_value("w"), galaxy_platform_text.c_str()) ("galaxy-language", bpo::value(&sGalaxyLanguage)->default_value("en"), galaxy_language_text.c_str()) ("galaxy-arch", bpo::value(&sGalaxyArch)->default_value("x64"), galaxy_arch_text.c_str()) @@ -798,6 +800,17 @@ int main(int argc, char *argv[]) } downloader.galaxyShowCloudSaves(product_id, build_index); } + else if (!galaxy_product_id_show_local_cloud_paths.empty()) + { + int build_index = -1; + std::vector tokens = Util::tokenize(galaxy_product_id_show_local_cloud_paths, "/"); + std::string product_id = tokens[0]; + if (tokens.size() == 2) + { + build_index = std::stoi(tokens[1]); + } + downloader.galaxyShowLocalCloudSaves(product_id, build_index); + } else if (!galaxy_product_id_install.empty()) { int build_index = -1; diff --git a/src/downloader.cpp b/src/downloader.cpp index 0bc751b..f4dcc20 100644 --- a/src/downloader.cpp +++ b/src/downloader.cpp @@ -4410,13 +4410,23 @@ void Downloader::galaxyShowCloudSaves(const std::string& product_id, int build_i } } -int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int build_index, const std::function &f) { +void Downloader::galaxyShowLocalCloudSaves(const std::string& product_id, int build_index) +{ + std::string id; + if(this->galaxySelectProductIdHelper(product_id, id)) + { + if (!id.empty()) + this->galaxyShowLocalCloudSavesById(id, build_index); + } +} + +std::map Downloader::cloudSaveLocations(const std::string& product_id, int build_index) { std::string sPlatform; unsigned int iPlatform = Globals::globalConfig.dlConf.iGalaxyPlatform; if (iPlatform == GlobalConstants::PLATFORM_LINUX) { // Linux is not yet supported for cloud saves std::cout << "Cloud saves for Linux builds not yet supported" << std::endl; - return -1; + return {}; } else if (iPlatform == GlobalConstants::PLATFORM_MAC) sPlatform = "osx"; @@ -4433,7 +4443,7 @@ int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int buil if (json["items"][build_index]["generation"].asInt() != 2) { std::cout << "Only generation 2 builds are supported currently" << std::endl; - return -1; + return {}; } std::string buildHash; buildHash.assign(link.begin()+link.find_last_of("/")+1, link.end()); @@ -4444,7 +4454,7 @@ int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int buil if(!gogGalaxy->refreshLogin(clientId, secret, Globals::galaxyConf.getRefreshToken(), false)) { std::cout << "Couldn't refresh login" << std::endl; - return -1; + return {}; } std::string install_directory; @@ -4469,8 +4479,6 @@ int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int buil std::string appdata_local_low_path = Globals::globalConfig.dirConf.sWinePrefix + "drive_c/users/" + username() + "/AppData/LocalLow/"; std::string saved_games = Globals::globalConfig.dirConf.sWinePrefix + "drive_c/users/" + username() + "/Save Games/"; - std::string url = "https://cloudstorage.gog.com/v1/" + Globals::galaxyConf.getUserId() + "/" + clientId; - auto cloud_saves_json = gogGalaxy->getCloudPathAsJson(manifest["clientId"].asString())["content"][platform]["cloudStorage"]["locations"]; std::map vars { @@ -4489,12 +4497,17 @@ int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int buil name_to_location.insert({cloud_save["name"].asString(), std::move(location)}); } + return name_to_location; +} + +int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int build_index, const std::function &f) { + auto name_to_location = this->cloudSaveLocations(product_id, build_index); if(name_to_location.empty()) { std::cout << "No cloud save locations found" << std::endl; return -1; } - + std::string url = "https://cloudstorage.gog.com/v1/" + Globals::galaxyConf.getUserId() + "/" + Globals::galaxyConf.getClientId(); auto fileList = gogGalaxy->getResponseJson(url, "application/json"); for(auto &fileJson : fileList) { @@ -4502,8 +4515,6 @@ int Downloader::cloudSaveListByIdForEach(const std::string& product_id, int buil auto pos = path.find_first_of('/'); auto location = name_to_location[path.substr(0, pos)] + path.substr(pos); - // std::cout << location << std::endl; - // std::cout << path < &f) { + boost::filesystem::directory_iterator begin { location }; + boost::filesystem::directory_iterator end; + + for(boost::filesystem::directory_iterator curr_dir { begin }; curr_dir != end; ++curr_dir) { + if(boost::filesystem::is_directory(*curr_dir)) { + + dirForEachHelper(*curr_dir, f); + } + else { + f(curr_dir); + } + } +} + +void dirForEach(const std::string &location, std::function &&f) { + dirForEachHelper(location, f); +} + +void Downloader::galaxyShowLocalCloudSavesById(const std::string& product_id, int build_index) { + auto name_to_locations = cloudSaveLocations(product_id, build_index); + + if(name_to_locations.empty()) { + std::cout << "Cloud saves not supported for this game" << std::endl; + } + + std::map path_to_cloudSaveFile; + for(auto &name_to_location : name_to_locations) { + auto &name = name_to_location.first; + auto &location = name_to_location.second; + + if(!boost::filesystem::exists(location) || !boost::filesystem::is_directory(location)) { + continue; + } + + dirForEach(location, [&](boost::filesystem::directory_iterator file) { + cloudSaveFile csf { + boost::posix_time::from_time_t(boost::filesystem::last_write_time(*file) - 1), + boost::filesystem::file_size(*file), + (name / boost::filesystem::relative(*file, location)).string(), + file->path().string() + }; + + path_to_cloudSaveFile.insert(std::make_pair(csf.path, std::move(csf))); + }); + } + + if(path_to_cloudSaveFile.empty()) { + std::cout << "No local cloud saves found" << std::endl; + + return; + } + + this->cloudSaveListByIdForEach(product_id, build_index, [&](cloudSaveFile &csf) { + auto it = path_to_cloudSaveFile.find(csf.path); + + //If remote save is not locally stored, skip + if(it == std::end(path_to_cloudSaveFile)) { + return; + } + + cloudSaveFile local_csf { std::move(it->second) }; + path_to_cloudSaveFile.erase(it); + + std::cout << csf.path << ": "; + if(csf.lastModified < local_csf.lastModified) { + std::cout << "remote save out of date: it should be synchronized" << std::endl; + } + else { + std::cout << "up to date" << std::endl; + } + }); + + for(auto &path_csf : path_to_cloudSaveFile) { + auto &csf = path_csf.second; + + std::cout << csf.path << ": there's only a local copy" << std::endl; + } +} + std::vector Downloader::galaxyGetOrphanedFiles(const std::vector& items, const std::string& install_path) { std::vector orphans;