diff --git a/UI/cmake/feature-macos-update.cmake b/UI/cmake/feature-macos-update.cmake index d31ce424d..4b4328c85 100644 --- a/UI/cmake/feature-macos-update.cmake +++ b/UI/cmake/feature-macos-update.cmake @@ -14,7 +14,8 @@ target_sources( update/shared-update.hpp update/update-helpers.cpp update/update-helpers.hpp - update/models/branches.hpp) + update/models/branches.hpp + update/models/whatsnew.hpp) target_link_libraries(obs-studio PRIVATE "$" nlohmann_json::nlohmann_json OBS::blake2) diff --git a/UI/cmake/feature-whatsnew.cmake b/UI/cmake/feature-whatsnew.cmake index a4d9be6d4..caa737f3a 100644 --- a/UI/cmake/feature-whatsnew.cmake +++ b/UI/cmake/feature-whatsnew.cmake @@ -5,11 +5,18 @@ if(ENABLE_WHATSNEW AND TARGET OBS::browser-panels) include(cmake/feature-macos-update.cmake) elseif(OS_LINUX) find_package(MbedTLS REQUIRED) - target_link_libraries(obs-studio PRIVATE MbedTLS::MbedTLS OBS::blake2) + find_package(nlohmann_json REQUIRED) + target_link_libraries(obs-studio PRIVATE MbedTLS::MbedTLS nlohmann_json::nlohmann_json OBS::blake2) target_sources( - obs-studio PRIVATE update/crypto-helpers-mbedtls.cpp update/crypto-helpers.hpp update/shared-update.cpp - update/shared-update.hpp update/update-helpers.cpp update/update-helpers.hpp) + obs-studio + PRIVATE update/crypto-helpers-mbedtls.cpp + update/crypto-helpers.hpp + update/shared-update.cpp + update/shared-update.hpp + update/update-helpers.cpp + update/update-helpers.hpp + update/models/whatsnew.hpp) endif() target_enable_feature(obs-studio "What's New panel" WHATSNEW_ENABLED) diff --git a/UI/cmake/legacy.cmake b/UI/cmake/legacy.cmake index aea502efe..99d4728d9 100644 --- a/UI/cmake/legacy.cmake +++ b/UI/cmake/legacy.cmake @@ -358,6 +358,7 @@ if(OS_WINDOWS) update/crypto-helpers-mbedtls.cpp update/crypto-helpers.hpp update/models/branches.hpp + update/models/whatsnew.hpp win-update/updater/manifest.hpp ${CMAKE_BINARY_DIR}/obs.rc) @@ -438,7 +439,8 @@ elseif(OS_MACOS) update/shared-update.cpp update/shared-update.hpp update/update-helpers.cpp - update/update-helpers.hpp) + update/update-helpers.hpp + update/models/whatsnew.hpp) if(SPARKLE_APPCAST_URL AND SPARKLE_PUBLIC_KEY) find_library(SPARKLE Sparkle) @@ -477,13 +479,14 @@ elseif(OS_POSIX) if(OS_LINUX AND ENABLE_WHATSNEW) find_package(MbedTLS) + find_package(nlohmann_json REQUIRED) if(NOT MBEDTLS_FOUND) obs_status(FATAL_ERROR "mbedTLS not found, but required for WhatsNew support on Linux") endif() target_sources(obs PRIVATE update/crypto-helpers.hpp update/crypto-helpers-mbedtls.cpp update/shared-update.cpp update/shared-update.hpp update/update-helpers.cpp update/update-helpers.hpp) - target_link_libraries(obs PRIVATE Mbedtls::Mbedtls OBS::blake2) + target_link_libraries(obs PRIVATE Mbedtls::Mbedtls nlohmann_json::nlohmann_json OBS::blake2) endif() endif() diff --git a/UI/cmake/os-windows.cmake b/UI/cmake/os-windows.cmake index 99b4254ad..645787f5f 100644 --- a/UI/cmake/os-windows.cmake +++ b/UI/cmake/os-windows.cmake @@ -29,6 +29,7 @@ target_sources( update/win-update.cpp update/win-update.hpp update/models/branches.hpp + update/models/whatsnew.hpp win-update/updater/manifest.hpp) target_link_libraries(obs-studio PRIVATE crypt32 OBS::blake2 OBS::w32-pthreads MbedTLS::MbedTLS diff --git a/UI/update/models/whatsnew.hpp b/UI/update/models/whatsnew.hpp new file mode 100644 index 000000000..59722ebf4 --- /dev/null +++ b/UI/update/models/whatsnew.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Dennis Sädtler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +#include +#include + +#include + +/* Ubuntu 22.04 be damned. */ +#ifndef NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) \ + nlohmann_json_t.v1 = \ + nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json &nlohmann_json_j, \ + const Type &nlohmann_json_t) \ + { \ + NLOHMANN_JSON_EXPAND( \ + NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \ + } \ + friend void from_json(const nlohmann::json &nlohmann_json_j, \ + Type &nlohmann_json_t) \ + { \ + Type nlohmann_json_default_obj; \ + NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE( \ + NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) \ + } + +#endif + +/* + * Support for (de-)serialising std::optional + * Adapted from https://github.com/nlohmann/json/issues/1749#issuecomment-1555093802 + */ +template struct nlohmann::adl_serializer> { + static std::optional from_json(const json &json) + { + return json.is_null() ? std::nullopt + : std::optional{json.get()}; + } + + static void to_json(json &json, std::optional t) + { + if (t) + json = *t; + else + json = nullptr; + } +}; + +struct WhatsNewPlatforms { + bool windows = false; + bool macos = false; + bool linux = false; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(WhatsNewPlatforms, windows, + macos, linux) +}; + +struct WhatsNewItem { + /* Target OBS version (patch is ignored) */ + std::string version; + /* Beta/RC release to target */ + int Beta = 0; + int RC = 0; + /* URL of webpage to be displayed */ + std::string url; + /* Increment for this version's item */ + int increment = 0; + /* Optional OS filter */ + std::optional os = std::nullopt; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(WhatsNewItem, version, Beta, + RC, url, increment, os) +}; + +using WhatsNewList = std::vector; diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 80ff75d65..db2960917 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -97,13 +97,12 @@ #include -#include +#include "update/models/whatsnew.hpp" #ifdef ENABLE_WAYLAND #include #endif -using namespace json11; using namespace std; #ifdef BROWSER_AVAILABLE @@ -2397,54 +2396,52 @@ void OBSBasic::ReceivedIntroJson(const QString &text) if (closing) return; - std::string err; - Json json = Json::parse(QT_TO_UTF8(text), err); - if (!err.empty()) + WhatsNewList items; + try { + nlohmann::json json = nlohmann::json::parse(text.toStdString()); + items = json.get(); + } catch (nlohmann::json::exception &e) { + blog(LOG_WARNING, "Parsing whatsnew data failed: %s", e.what()); return; + } std::string info_url; int info_increment = -1; /* check to see if there's an info page for this version */ - const Json::array &items = json.array_items(); - for (const Json &item : items) { - if (item["os"].is_object()) { - Json::object platforms = item["os"].object_items(); + for (const WhatsNewItem &item : items) { + if (item.os) { + WhatsNewPlatforms platforms = *item.os; #ifdef _WIN32 - if (!platforms["windows"].bool_value()) + if (!platforms.windows) continue; #elif defined(__APPLE__) - if (!platforms["macos"].bool_value()) + if (!platforms.macos) continue; #else - if (!platforms["linux"].bool_value()) + if (!platforms.linux) continue; #endif } - const std::string &version = item["version"].string_value(); - const std::string &url = item["url"].string_value(); - int increment = item["increment"].int_value(); - int beta = item["Beta"].int_value(); - int rc = item["RC"].int_value(); - int major = 0; int minor = 0; - sscanf(version.c_str(), "%d.%d", &major, &minor); + sscanf(item.version.c_str(), "%d.%d", &major, &minor); #if defined(OBS_RELEASE_CANDIDATE) && OBS_RELEASE_CANDIDATE > 0 if (major == OBS_RELEASE_CANDIDATE_MAJOR && minor == OBS_RELEASE_CANDIDATE_MINOR && - rc == OBS_RELEASE_CANDIDATE) { + item.RC == OBS_RELEASE_CANDIDATE) { #elif OBS_BETA > 0 if (major == OBS_BETA_MAJOR && minor == OBS_BETA_MINOR && - beta == OBS_BETA) { + item.Beta == OBS_BETA) { #else if (major == LIBOBS_API_MAJOR_VER && - minor == LIBOBS_API_MINOR_VER && rc == 0 && beta == 0) { + minor == LIBOBS_API_MINOR_VER && item.RC == 0 && + item.Beta == 0) { #endif - info_url = url; - info_increment = increment; + info_url = item.url; + info_increment = item.increment; } }