diff --git a/CMakeLists.txt b/CMakeLists.txt index 58071df1..5cb9481c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,38 +25,45 @@ set(DEPLIBS ${JSONCPP_LIBRARIES}) set(BASE_SOURCES - src/base/Cache.cpp) + src/stalker/base/Cache.cpp) set(SOURCES - src/ChannelManager.cpp - src/CWatchdog.cpp - src/GuideManager.cpp - src/HTTPSocket.cpp - src/SAPI.cpp - src/SData.cpp - src/SessionManager.cpp - src/Utils.cpp - src/XMLTV.cpp) + src/addon.cpp + src/StalkerInstance.cpp + src/stalker/AddonSettings.cpp + src/stalker/ChannelManager.cpp + src/stalker/CWatchdog.cpp + src/stalker/GuideManager.cpp + src/stalker/HTTPSocket.cpp + src/stalker/InstanceSettings.cpp + src/stalker/SAPI.cpp + src/stalker/SessionManager.cpp + src/stalker/SettingsMigration.cpp + src/stalker/Utils.cpp + src/stalker/XMLTV.cpp) set(STALKER_SOURCES ${BASE_SOURCES} ${SOURCES}) set(STALKER_HEADERS - src/ChannelManager.h - src/CWatchdog.h - src/Error.h - src/GuideManager.h - src/HTTPSocket.h - src/SAPI.h - src/SData.h - src/SessionManager.h - src/Settings.h - src/Utils.h - src/XMLTV.h - src/base/Cache.h - src/base/ChannelManager.h - src/base/GuideManager.h) + src/addon.h + src/StalkerInstance.h + src/stalker/AddonSettings.h + src/stalker/ChannelManager.h + src/stalker/CWatchdog.h + src/stalker/Error.h + src/stalker/GuideManager.h + src/stalker/HTTPSocket.h + src/stalker/InstanceSettings.h + src/stalker/SAPI.h + src/stalker/SessionManager.h + src/stalker/SettingsMigration.h + src/stalker/Utils.h + src/stalker/XMLTV.h + src/stalker/base/Cache.h + src/stalker/base/ChannelManager.h + src/stalker/base/GuideManager.h) build_addon(pvr.stalker STALKER DEPLIBS) diff --git a/build-install-mac.sh b/build-install-mac.sh new file mode 100755 index 00000000..6cc85127 --- /dev/null +++ b/build-install-mac.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -e + +if [ "$#" -ne 1 ] || ! [ -d "$1" ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +if [[ "$OSTYPE" != "darwin"* ]]; then + echo "Error: Script only for use on MacOSX" >&2 + exit 1 +fi + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +if [[ "$1" = /* ]] +then + #absolute path + SCRIPT_DIR="" +else + #relative + SCRIPT_DIR="$SCRIPT_DIR/" +fi + +BINARY_ADDONS_TARGET_DIR="$1/tools/depends/target/binary-addons" +MACOSX_BINARY_ADDONS_TARGET_DIR="" +KODI_ADDONS_DIR="$HOME/Library/Application Support/Kodi/addons" +ADDON_NAME=`basename -s .git \`git config --get remote.origin.url\`` + +if [ ! -d "$BINARY_ADDONS_TARGET_DIR" ]; then + echo "Error: Could not find binary addons directory at: $BINARY_ADDONS_TARGET_DIR" >&2 + exit 1 +fi + +for DIR in "$BINARY_ADDONS_TARGET_DIR/"macosx*; do + if [ -d "${DIR}" ]; then + MACOSX_BINARY_ADDONS_TARGET_DIR="${DIR}" + break + fi +done + +if [ -z "$MACOSX_BINARY_ADDONS_TARGET_DIR" ]; then + echo "Error: Could not find binary addons build directory at: $BINARY_ADDONS_TARGET_DIR/macosx*" >&2 + exit 1 +fi + +if [ ! -d "$KODI_ADDONS_DIR" ]; then + echo "Error: Kodi addons dir does not exist at: $KODI_ADDONS_DIR" >&2 + exit 1 +fi + +cd "$MACOSX_BINARY_ADDONS_TARGET_DIR" +make + +XBMC_BUILD_ADDON_INSTALL_DIR=$(cd "$SCRIPT_DIR$1/addons/$ADDON_NAME" 2> /dev/null && pwd -P) +rm -rf "$KODI_ADDONS_DIR/$ADDON_NAME" +echo "Removed previous addon build from: $KODI_ADDONS_DIR" +cp -rf "$XBMC_BUILD_ADDON_INSTALL_DIR" "$KODI_ADDONS_DIR" +echo "Copied new addon build to: $KODI_ADDONS_DIR" diff --git a/depends/common/libxml2/libxml2.txt b/depends/common/libxml2/libxml2.txt index fb5f44aa..61551cc0 100644 --- a/depends/common/libxml2/libxml2.txt +++ b/depends/common/libxml2/libxml2.txt @@ -1 +1 @@ -libxml2-2.9.10 http://xmlsoft.org/sources/libxml2-2.9.10.tar.gz +libxml2 http://xmlsoft.org/sources/libxml2-2.9.10.tar.gz diff --git a/depends/common/zlib/01-build-static.patch b/depends/common/zlib/01-build-static.patch index 8cc3cfc3..652cd5c9 100644 --- a/depends/common/zlib/01-build-static.patch +++ b/depends/common/zlib/01-build-static.patch @@ -1,33 +1,35 @@ --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -183,10 +183,11 @@ +@@ -149,12 +149,12 @@ set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) endif(MINGW) - --add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) --add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) + +-add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) ++add_library(zlib ${ZLIB_SRCS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) + target_include_directories(zlib PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) +-add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +-target_include_directories(zlibstatic PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) -set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) -set_target_properties(zlib PROPERTIES SOVERSION 1) -+add_library(zlib ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +if(BUILD_SHARED_LIBS) + set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) + set_target_properties(zlib PROPERTIES SOVERSION 1) +endif() - + if(NOT CYGWIN) # This property causes shared libraries on Linux to have the full version -@@ -201,7 +202,7 @@ - +@@ -169,7 +169,7 @@ + if(UNIX) # On unix-like platforms the library is almost always called libz - set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) + set_target_properties(zlib PROPERTIES OUTPUT_NAME z) - if(NOT APPLE) + if(NOT APPLE AND NOT(CMAKE_SYSTEM_NAME STREQUAL AIX)) set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") endif() -@@ -211,7 +212,7 @@ +@@ -179,7 +179,7 @@ endif() - + if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) - install(TARGETS zlib zlibstatic + install(TARGETS zlib diff --git a/depends/common/zlib/02-install-pkgconfig-in-lib.patch b/depends/common/zlib/02-install-pkgconfig-in-lib.patch new file mode 100644 index 00000000..c156aea3 --- /dev/null +++ b/depends/common/zlib/02-install-pkgconfig-in-lib.patch @@ -0,0 +1,11 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -11,7 +11,7 @@ + set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") + set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") + set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") +-set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") ++set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") + + include(CheckTypeSize) + include(CheckFunctionExists) diff --git a/depends/common/zlib/flags.txt b/depends/common/zlib/flags.txt new file mode 100644 index 00000000..1c78300d --- /dev/null +++ b/depends/common/zlib/flags.txt @@ -0,0 +1 @@ +-DZLIB_BUILD_EXAMPLES=OFF \ No newline at end of file diff --git a/depends/common/zlib/zlib.sha256 b/depends/common/zlib/zlib.sha256 index ec1ba07f..26c6a507 100644 --- a/depends/common/zlib/zlib.sha256 +++ b/depends/common/zlib/zlib.sha256 @@ -1 +1 @@ -c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 +38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32 diff --git a/depends/common/zlib/zlib.txt b/depends/common/zlib/zlib.txt index 4bf36450..4a49179e 100644 --- a/depends/common/zlib/zlib.txt +++ b/depends/common/zlib/zlib.txt @@ -1 +1 @@ -zlib http://mirrors.kodi.tv/build-deps/sources/zlib-1.2.11.tar.gz +zlib https://www.zlib.net/zlib-1.3.1.tar.xz diff --git a/depends/windows/libxml2/libxml2.txt b/depends/windows/libxml2/libxml2.txt index fb5f44aa..61551cc0 100644 --- a/depends/windows/libxml2/libxml2.txt +++ b/depends/windows/libxml2/libxml2.txt @@ -1 +1 @@ -libxml2-2.9.10 http://xmlsoft.org/sources/libxml2-2.9.10.tar.gz +libxml2 http://xmlsoft.org/sources/libxml2-2.9.10.tar.gz diff --git a/pvr.stalker/addon.xml.in b/pvr.stalker/addon.xml.in index b46497fc..e601a100 100644 --- a/pvr.stalker/addon.xml.in +++ b/pvr.stalker/addon.xml.in @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ diff --git a/pvr.stalker/changelog.txt b/pvr.stalker/changelog.txt index 5e9db6e8..f7696a7a 100644 --- a/pvr.stalker/changelog.txt +++ b/pvr.stalker/changelog.txt @@ -1,3 +1,8 @@ +v21.1.0 +- Move to new settings format and support PVR multi-instance + - Note that only the first portal will be migrated in settings, the other portal will need to be set up manually +- Add setting for EPG timeShift + v21.0.1 - Translations updates from Weblate - ar_sa, ast_es, be_by, bs_ba, cs_cz, cy_gb, de_de, en_au, eo, es_ar, es_es, et_ee, fa_af, fa_ir, fi_fi, fo_fo, fr_fr, hr_hr, hy_am, id_id, it_it, ja_jp, mi, mk_mk, mn_mn, my_mm, ru_ru, si_lk, sk_sk, sq_al, sv_se, ta_in, te_in, tg_tj, th_th, uk_ua, uz_uz diff --git a/pvr.stalker/resources/instance-settings.xml b/pvr.stalker/resources/instance-settings.xml new file mode 100644 index 00000000..de54fc0a --- /dev/null +++ b/pvr.stalker/resources/instance-settings.xml @@ -0,0 +1,198 @@ + + +
+ + + + + 0 + 00:1A:79:00:00:00 + + false + + + + + 0 + 127.0.0.1 + + false + + + + + 0 + Europe/Kiev + + false + + + + + 3 + 5 + + 0 + 5 + 120 + + + 30127 + + + + + + + + + 0 + + + true + + + + + 0 + + + true + + + true + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + true + + + + 0 + 24 + + 0 + 1 + 168 + + + + + 0 + 0 + + -12 + 0.5 + 14 + + + 30126 + + + + + + 0 + 0 + + + + + + + + + + 0 + + + true + + + 0 + + + + + 0 + + + true + false + + + 1 + + + 1033 + + + + + + + + + 3 + + + true + + + + + 3 + + + true + + + + + 3 + + + true + + + + + 3 + + + true + + + + + 3 + + + true + + + + + + +
+
\ No newline at end of file diff --git a/pvr.stalker/resources/language/resource.language.bs_ba/strings.po b/pvr.stalker/resources/language/resource.language.bs_ba/strings.po index 1a3ba246..e4afa00d 100644 --- a/pvr.stalker/resources/language/resource.language.bs_ba/strings.po +++ b/pvr.stalker/resources/language/resource.language.bs_ba/strings.po @@ -59,7 +59,7 @@ msgid "Time Zone" msgstr "" msgctxt "#30104" -msgid "Auth Credentials" +msgid "Authentication" msgstr "" msgctxt "#30105" diff --git a/pvr.stalker/resources/language/resource.language.en_gb/strings.po b/pvr.stalker/resources/language/resource.language.en_gb/strings.po index 2fb76a72..34b3ceaf 100644 --- a/pvr.stalker/resources/language/resource.language.en_gb/strings.po +++ b/pvr.stalker/resources/language/resource.language.en_gb/strings.po @@ -35,7 +35,7 @@ msgid "General" msgstr "" msgctxt "#30001" -msgid "Active Portal" +msgid "Connection" msgstr "" msgctxt "#30002" @@ -43,7 +43,7 @@ msgid "Misc" msgstr "" msgctxt "#30003" -msgid "Connection Timeout (seconds)" +msgid "Connection Timeout" msgstr "" #empty strings from id 30004 to 30100 @@ -61,7 +61,7 @@ msgid "Time Zone" msgstr "" msgctxt "#30104" -msgid "Auth Credentials" +msgid "Authentication" msgstr "" msgctxt "#30105" @@ -144,7 +144,24 @@ msgctxt "#30124" msgid "Signature" msgstr "" -#empty strings from id 30125 to 30500 +msgctxt "#30125" +msgid "EPG time shift" +msgstr "" + +#. format-label: EPG Settings - epg_timeShift +msgctxt "#30126" +msgid "{0:.1f} hours" +msgstr "" + +msgctxt "#30127" +msgid "{0:d} seconds" +msgstr "" + +msgctxt "#30128" +msgid "EPG" +msgstr "" + +#empty strings from id 30129 to 30500 msgctxt "#30501" msgid "Unknown error. See log for details." @@ -186,32 +203,78 @@ msgctxt "#30510" msgid "Re-authenticated." msgstr "" -#empty strings from id 30511 to 30999 +#empty strings from id 30511 to 30599 -msgctxt "#31000" -msgid "Portal 1" +msgctxt "#30600" +msgid "The connection timeout to use for the stalker protal" msgstr "" -#empty strings from id 31001 to 31999 +msgctxt "#30601" +msgid "The mac of the stalker portal" +msgstr "" + +msgctxt "#30601" +msgid "The address of the stalker portal" +msgstr "" + +msgctxt "#30603" +msgid "The timezone of this stalker portal" +msgstr "" -msgctxt "#32000" -msgid "Portal 2" +msgctxt "#30604" +msgid "Adjust the EPG times by this value, from -12 hours to +14 hours." msgstr "" -#empty strings from id 32001 to 32999 +msgctxt "#30605" +msgid "The username for login." +msgstr "" -msgctxt "#33000" -msgid "Portal 3" +msgctxt "#30606" +msgid "The login password." msgstr "" -#empty strings from id 33001 to 33999 +msgctxt "#30607" +msgid "The source of guide data." +msgstr "" -msgctxt "#34000" -msgid "Portal 4" +msgctxt "#30608" +msgid "Enable cache for guide data." msgstr "" -#empty strings from id 34001 to 34999 +msgctxt "#30609" +msgid "The length of time to cache the guide data for." +msgstr "" -msgctxt "#35000" -msgid "Portal 5" +msgctxt "#30610" +msgid "Remote URL or local path selection." msgstr "" + +msgctxt "#30611" +msgid "Remote URL for XMLTV data." +msgstr "" + +msgctxt "#30612" +msgid "Local path used for XMLTV data." +msgstr "" + +msgctxt "#30613" +msgid "The token to be used with the stalker portal." +msgstr "" + +msgctxt "#30614" +msgid "The serial number of the stalker portal." +msgstr "" + +msgctxt "#30615" +msgid "The device ID of the stalker portal." +msgstr "" + +msgctxt "#30616" +msgid "The device ID2 of the stalker portal." +msgstr "" + +msgctxt "#30617" +msgid "The signature of the stalker portal." +msgstr "" + +#empty strings from id 30618 to 34999 diff --git a/pvr.stalker/resources/settings.xml b/pvr.stalker/resources/settings.xml index c7af85a9..0a3f2e85 100644 --- a/pvr.stalker/resources/settings.xml +++ b/pvr.stalker/resources/settings.xml @@ -1,118 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+ + + + + + 4 + 0:1A:79:00:00:00 + + + 4 + 127.0.0.1 + + + 4 + 5 + + + + 4 + Europe/Kiev + + + 4 + 0 + + + + 4 + + + true + + + + 4 + + + true + + + + + 4 + 0 + + + 4 + true + + + 4 + 24 + + + + 4 + 0 + + + 4 + + + true + + + + 4 + + + true + + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + + +
diff --git a/src/SData.cpp b/src/StalkerInstance.cpp similarity index 68% rename from src/SData.cpp rename to src/StalkerInstance.cpp index 7807f64b..ad50380d 100644 --- a/src/SData.cpp +++ b/src/StalkerInstance.cpp @@ -6,9 +6,9 @@ * See LICENSE.md for more information. */ -#include "SData.h" +#include "StalkerInstance.h" -#include "Utils.h" +#include "stalker/Utils.h" #include "libstalkerclient/util.h" #include @@ -27,13 +27,17 @@ #define SERROR_MSG_AUTHORIZATION 30509 #define MSG_RE_AUTHENTICATED 30510 -SData::SData() : Base::Cache() +using namespace Stalker; + +StalkerInstance::StalkerInstance(const kodi::addon::IInstanceInfo& instance) : kodi::addon::CInstancePVRClient(instance), Base::Cache() { sc_identity_defaults(&m_identity); sc_stb_profile_defaults(&m_profile); + + settings = std::make_shared(*this); } -SData::~SData() +StalkerInstance::~StalkerInstance() { m_epgThreadActive = false; if (m_epgThread.joinable()) @@ -45,7 +49,19 @@ SData::~SData() delete m_guideManager; } -void SData::QueueErrorNotification(SError error) const +ADDON_STATUS StalkerInstance::Initialize() +{ + // Settings are loaded on creation of the instance, as they are already loaded we can safely configure the API + + if (!ConfigureStalkerAPISettings()) + { + return ADDON_STATUS_LOST_CONNECTION; + } + + return ADDON_STATUS_OK; +} + +void StalkerInstance::QueueErrorNotification(SError error) const { int errorMsg = 0; @@ -90,7 +106,7 @@ void SData::QueueErrorNotification(SError error) const kodi::QueueNotification(QUEUE_ERROR, "", kodi::addon::GetLocalizedString(errorMsg)); } -bool SData::LoadCache() +bool StalkerInstance::LoadCache() { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); @@ -100,7 +116,7 @@ bool SData::LoadCache() xmlNodePtr node = nullptr; xmlNodePtr portalsNode = nullptr; xmlNodePtr portalNode = nullptr; - std::string portalNum = std::to_string(settings.activePortal); + std::string portalNum = std::to_string(settings->activePortal); cacheFile = Utils::GetFilePath("cache.xml"); @@ -152,7 +168,7 @@ bool SData::LoadCache() return true; } -bool SData::SaveCache() +bool StalkerInstance::SaveCache() { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); @@ -163,7 +179,7 @@ bool SData::SaveCache() xmlNodePtr node = nullptr; xmlNodePtr portalsNode = nullptr; xmlNodePtr portalNode = nullptr; - std::string portalNum = std::to_string(settings.activePortal); + std::string portalNum = std::to_string(settings->activePortal); cacheFile = Utils::GetFilePath("cache.xml"); @@ -232,22 +248,22 @@ bool SData::SaveCache() return ret; } -bool SData::ReloadSettings() +bool StalkerInstance::ConfigureStalkerAPISettings() { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); SError ret; sc_identity_defaults(&m_identity); - SC_STR_SET(m_identity.mac, settings.mac.c_str()); - SC_STR_SET(m_identity.time_zone, settings.timeZone.c_str()); - SC_STR_SET(m_identity.token, settings.token.c_str()); - SC_STR_SET(m_identity.login, settings.login.c_str()); - SC_STR_SET(m_identity.password, settings.password.c_str()); - SC_STR_SET(m_identity.serial_number, settings.serialNumber.c_str()); - SC_STR_SET(m_identity.device_id, settings.deviceId.c_str()); - SC_STR_SET(m_identity.device_id2, settings.deviceId2.c_str()); - SC_STR_SET(m_identity.signature, settings.signature.c_str()); + SC_STR_SET(m_identity.mac, settings->mac.c_str()); + SC_STR_SET(m_identity.time_zone, settings->timeZone.c_str()); + SC_STR_SET(m_identity.token, settings->token.c_str()); + SC_STR_SET(m_identity.login, settings->login.c_str()); + SC_STR_SET(m_identity.password, settings->password.c_str()); + SC_STR_SET(m_identity.serial_number, settings->serialNumber.c_str()); + SC_STR_SET(m_identity.device_id, settings->deviceId.c_str()); + SC_STR_SET(m_identity.device_id2, settings->deviceId2.c_str()); + SC_STR_SET(m_identity.signature, settings->signature.c_str()); // skip handshake if token setting was set if (strlen(m_identity.token) > 0) @@ -256,8 +272,8 @@ bool SData::ReloadSettings() LoadCache(); m_api->SetIdentity(&m_identity); - m_api->SetEndpoint(settings.server); - m_api->SetTimeout(settings.connectionTimeout); + m_api->SetEndpoint(settings->server); + m_api->SetTimeout(settings->connectionTimeout); m_sessionManager->SetIdentity(&m_identity, m_tokenManuallySet); m_sessionManager->SetProfile(&m_profile); @@ -276,8 +292,8 @@ bool SData::ReloadSettings() m_channelManager->SetAPI(m_api); m_guideManager->SetAPI(m_api); - m_guideManager->SetGuidePreference(settings.guidePreference); - m_guideManager->SetCacheOptions(settings.guideCache, settings.guideCacheHours * 3600); + m_guideManager->SetGuidePreference(settings->guidePreference); + m_guideManager->SetCacheOptions(settings->guideCache, settings->guideCacheHours * 3600); ret = Authenticate(); if (ret != SERROR_OK) @@ -286,12 +302,12 @@ bool SData::ReloadSettings() return ret == SERROR_OK; } -bool SData::IsAuthenticated() const +bool StalkerInstance::IsAuthenticated() const { return m_sessionManager->IsAuthenticated(); } -SError SData::Authenticate() +SError StalkerInstance::Authenticate() { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); @@ -320,87 +336,7 @@ std::string ParseAsW3CDateString(time_t time) } // unnamed namespace -#define PORTAL_SUFFIX_FORMAT "%s_%d" - -#define GET_SETTING_STR2(setting, name, portal, store, def) \ - sprintf(setting, PORTAL_SUFFIX_FORMAT, name, portal); \ - store = kodi::addon::GetSettingString(setting, def); - -#define GET_SETTING_INT2(setting, name, portal, store, def) \ - sprintf(setting, PORTAL_SUFFIX_FORMAT, name, portal); \ - store = kodi::addon::GetSettingInt(setting, def); - -ADDON_STATUS SData::Create() -{ - settings.activePortal = kodi::addon::GetSettingInt("active_portal", SC_SETTINGS_DEFAULT_ACTIVE_PORTAL); - settings.connectionTimeout = - kodi::addon::GetSettingInt("connection_timeout", SC_SETTINGS_DEFAULT_CONNECTION_TIMEOUT); - // calc based on index (5 second steps) - settings.connectionTimeout *= 5; - - char setting[256]; - int enumTemp; - int portal = settings.activePortal; - GET_SETTING_STR2(setting, "mac", portal, settings.mac, SC_SETTINGS_DEFAULT_MAC); - GET_SETTING_STR2(setting, "server", portal, settings.server, SC_SETTINGS_DEFAULT_SERVER); - GET_SETTING_STR2(setting, "time_zone", portal, settings.timeZone, SC_SETTINGS_DEFAULT_TIME_ZONE); - GET_SETTING_STR2(setting, "login", portal, settings.login, SC_SETTINGS_DEFAULT_LOGIN); - GET_SETTING_STR2(setting, "password", portal, settings.password, SC_SETTINGS_DEFAULT_PASSWORD); - GET_SETTING_INT2(setting, "guide_preference", portal, enumTemp, - SC_SETTINGS_DEFAULT_GUIDE_PREFERENCE); - settings.guidePreference = (SC::Settings::GuidePreference)enumTemp; - GET_SETTING_INT2(setting, "guide_cache", portal, settings.guideCache, - SC_SETTINGS_DEFAULT_GUIDE_CACHE); - GET_SETTING_INT2(setting, "guide_cache_hours", portal, settings.guideCacheHours, - SC_SETTINGS_DEFAULT_GUIDE_CACHE_HOURS); - GET_SETTING_INT2(setting, "xmltv_scope", portal, enumTemp, SC_SETTINGS_DEFAULT_XMLTV_SCOPE); - settings.xmltvScope = (HTTPSocket::Scope)enumTemp; - if (settings.xmltvScope == HTTPSocket::Scope::SCOPE_REMOTE) - { - GET_SETTING_STR2(setting, "xmltv_url", portal, settings.xmltvPath, - SC_SETTINGS_DEFAULT_XMLTV_URL); - } - else - { - GET_SETTING_STR2(setting, "xmltv_path", portal, settings.xmltvPath, - SC_SETTINGS_DEFAULT_XMLTV_PATH); - } - GET_SETTING_STR2(setting, "token", portal, settings.token, SC_SETTINGS_DEFAULT_TOKEN); - GET_SETTING_STR2(setting, "serial_number", portal, settings.serialNumber, - SC_SETTINGS_DEFAULT_SERIAL_NUMBER); - GET_SETTING_STR2(setting, "device_id", portal, settings.deviceId, SC_SETTINGS_DEFAULT_DEVICE_ID); - GET_SETTING_STR2(setting, "device_id2", portal, settings.deviceId2, - SC_SETTINGS_DEFAULT_DEVICE_ID2); - GET_SETTING_STR2(setting, "signature", portal, settings.signature, SC_SETTINGS_DEFAULT_SIGNATURE); - - kodi::Log(ADDON_LOG_DEBUG, "active_portal=%d", settings.activePortal); - kodi::Log(ADDON_LOG_DEBUG, "connection_timeout=%d", settings.connectionTimeout); - - kodi::Log(ADDON_LOG_DEBUG, "mac=%s", settings.mac.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "server=%s", settings.server.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "timeZone=%s", settings.timeZone.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "login=%s", settings.login.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "password=%s", settings.password.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "guidePreference=%d", settings.guidePreference); - kodi::Log(ADDON_LOG_DEBUG, "guideCache=%d", settings.guideCache); - kodi::Log(ADDON_LOG_DEBUG, "guideCacheHours=%d", settings.guideCacheHours); - kodi::Log(ADDON_LOG_DEBUG, "xmltvScope=%d", settings.xmltvScope); - kodi::Log(ADDON_LOG_DEBUG, "xmltvPath=%s", settings.xmltvPath.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "token=%s", settings.token.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "serialNumber=%s", settings.serialNumber.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "deviceId=%s", settings.deviceId.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "deviceId2=%s", settings.deviceId2.c_str()); - kodi::Log(ADDON_LOG_DEBUG, "signature=%s", settings.signature.c_str()); - - if (!ReloadSettings()) - { - return ADDON_STATUS_LOST_CONNECTION; - } - - return ADDON_STATUS_OK; -} - -PVR_ERROR SData::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) +PVR_ERROR StalkerInstance::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) { capabilities.SetSupportsEPG(true); capabilities.SetSupportsTV(true); @@ -412,32 +348,32 @@ PVR_ERROR SData::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetBackendName(std::string& name) +PVR_ERROR StalkerInstance::GetBackendName(std::string& name) { name = "Stalker Middleware"; return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetBackendVersion(std::string& version) +PVR_ERROR StalkerInstance::GetBackendVersion(std::string& version) { version = "Unknown"; return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetConnectionString(std::string& connection) +PVR_ERROR StalkerInstance::GetConnectionString(std::string& connection) { - connection = settings.server; + connection = settings->server; return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetEPGForChannel(int channelUid, +PVR_ERROR StalkerInstance::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi::addon::PVREPGTagsResultSet& results) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); - SC::Channel* chan; + Stalker::Channel* chan; time_t now; SError ret; @@ -458,7 +394,7 @@ PVR_ERROR SData::GetEPGForChannel(int channelUid, if (m_nextEpgLoadTime < now) { // limit to 1 hour if caching is disabled - m_nextEpgLoadTime = now + (settings.guideCache ? settings.guideCacheHours : 1) * 3600; + m_nextEpgLoadTime = now + (settings->guideCache ? settings->guideCacheHours : 1) * 3600; kodi::Log(ADDON_LOG_DEBUG, "%s: m_nextEpgLoadTime=%d", __func__, m_nextEpgLoadTime); if (IsAuthenticated()) @@ -468,15 +404,16 @@ PVR_ERROR SData::GetEPGForChannel(int channelUid, QueueErrorNotification(ret); } - ret = m_guideManager->LoadXMLTV(settings.xmltvScope, settings.xmltvPath); + ret = m_guideManager->LoadXMLTV(settings->xmltvScope, settings->xmltvPath); if (ret != SERROR_OK) QueueErrorNotification(ret); } - std::vector events; + std::vector events; - events = m_guideManager->GetChannelEvents(*chan, start, end); - for (std::vector::iterator event = events.begin(); event != events.end(); ++event) + int epgTimeshiftSecs = static_cast(settings->epgTimeshiftHours * 60 * 60); + events = m_guideManager->GetChannelEvents(*chan, start, end, epgTimeshiftSecs); + for (std::vector::iterator event = events.begin(); event != events.end(); ++event) { kodi::addon::PVREPGTag tag; @@ -544,13 +481,13 @@ PVR_ERROR SData::GetEPGForChannel(int channelUid, return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetChannelGroupsAmount(int& amount) +PVR_ERROR StalkerInstance::GetChannelGroupsAmount(int& amount) { amount = m_channelManager->GetChannelGroups().size(); return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) +PVR_ERROR StalkerInstance::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); @@ -569,10 +506,10 @@ PVR_ERROR SData::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResul return PVR_ERROR_SERVER_ERROR; } - std::vector channelGroups; + std::vector channelGroups; channelGroups = m_channelManager->GetChannelGroups(); - for (std::vector::iterator group = channelGroups.begin(); + for (std::vector::iterator group = channelGroups.begin(); group != channelGroups.end(); ++group) { // exclude group id '*' (all) @@ -590,12 +527,12 @@ PVR_ERROR SData::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResul return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, +PVR_ERROR StalkerInstance::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, kodi::addon::PVRChannelGroupMembersResultSet& results) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); - SC::ChannelGroup* channelGroup; + Stalker::ChannelGroup* channelGroup; channelGroup = m_channelManager->GetChannelGroup(group.GetGroupName()); if (channelGroup == nullptr) @@ -604,10 +541,10 @@ PVR_ERROR SData::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& grou return PVR_ERROR_SERVER_ERROR; } - std::vector channels; + std::vector channels; channels = m_channelManager->GetChannels(); - for (std::vector::iterator channel = channels.begin(); channel != channels.end(); + for (std::vector::iterator channel = channels.begin(); channel != channels.end(); ++channel) { if (channel->tvGenreId.compare(channelGroup->id)) @@ -625,13 +562,13 @@ PVR_ERROR SData::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& grou return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetChannelsAmount(int& amount) +PVR_ERROR StalkerInstance::GetChannelsAmount(int& amount) { amount = m_channelManager->GetChannels().size(); return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) +PVR_ERROR StalkerInstance::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); @@ -650,10 +587,10 @@ PVR_ERROR SData::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& resu return PVR_ERROR_SERVER_ERROR; } - std::vector channels; + std::vector channels; channels = m_channelManager->GetChannels(); - for (std::vector::iterator channel = channels.begin(); channel != channels.end(); + for (std::vector::iterator channel = channels.begin(); channel != channels.end(); ++channel) { kodi::addon::PVRChannel tag; @@ -671,7 +608,7 @@ PVR_ERROR SData::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& resu return PVR_ERROR_NO_ERROR; } -PVR_ERROR SData::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, +PVR_ERROR StalkerInstance::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, std::vector& properties) { const std::string strUrl = GetChannelStreamURL(channel); @@ -685,7 +622,7 @@ PVR_ERROR SData::GetChannelStreamProperties(const kodi::addon::PVRChannel& chann return PVR_ERROR_NO_ERROR; } -std::string SData::GetChannelStreamURL(const kodi::addon::PVRChannel& channel) const +std::string StalkerInstance::GetChannelStreamURL(const kodi::addon::PVRChannel& channel) const { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); @@ -694,7 +631,7 @@ std::string SData::GetChannelStreamURL(const kodi::addon::PVRChannel& channel) c if (!IsAuthenticated()) return streamUrl; - SC::Channel* chan; + Stalker::Channel* chan; std::string cmd; size_t pos; @@ -716,7 +653,7 @@ std::string SData::GetChannelStreamURL(const kodi::addon::PVRChannel& channel) c std::ostringstream oss; HTTPSocket::Request request; HTTPSocket::Response response; - HTTPSocket sock(settings.connectionTimeout); + HTTPSocket sock(settings->connectionTimeout); bool failed(false); strSplit = kodi::tools::StringUtils::Split(chan->cmd, "/"); @@ -781,8 +718,8 @@ std::string SData::GetChannelStreamURL(const kodi::addon::PVRChannel& channel) c { // protocol options for http(s) urls only // <= zero disables timeout - // if (streamUrl.find("http") == 0 && settings.connectionTimeout > 0) - // streamUrl += "|Connection-Timeout=" + std::to_string(settings.connectionTimeout); + // if (streamUrl.find("http") == 0 && settings->connectionTimeout > 0) + // streamUrl += "|Connection-Timeout=" + std::to_string(settings->connectionTimeout); kodi::Log(ADDON_LOG_DEBUG, "%s: streamUrl=%s", __func__, streamUrl.c_str()); } @@ -790,4 +727,3 @@ std::string SData::GetChannelStreamURL(const kodi::addon::PVRChannel& channel) c return streamUrl; } -ADDONCREATOR(SData) diff --git a/src/SData.h b/src/StalkerInstance.h similarity index 65% rename from src/SData.h rename to src/StalkerInstance.h index a0a7c441..371f4779 100644 --- a/src/SData.h +++ b/src/StalkerInstance.h @@ -8,39 +8,43 @@ #pragma once -#include "CWatchdog.h" -#include "ChannelManager.h" -#include "Error.h" -#include "GuideManager.h" -#include "SAPI.h" -#include "SessionManager.h" -#include "Settings.h" -#include "XMLTV.h" -#include "base/Cache.h" +#include "stalker/CWatchdog.h" +#include "stalker/ChannelManager.h" +#include "stalker/Error.h" +#include "stalker/GuideManager.h" +#include "stalker/SAPI.h" +#include "stalker/SessionManager.h" +#include "stalker/InstanceSettings.h" +#include "stalker/XMLTV.h" +#include "stalker/base/Cache.h" #include "libstalkerclient/identity.h" #include "libstalkerclient/stb.h" #include #include +#include #include #include #include -class ATTR_DLL_LOCAL SData : public kodi::addon::CAddonBase, - public kodi::addon::CInstancePVRClient, - private Base::Cache +namespace Stalker +{ + +class ATTR_DLL_LOCAL StalkerInstance : public kodi::addon::CInstancePVRClient, + private Base::Cache { public: - SData(); - ~SData(); + StalkerInstance(const kodi::addon::IInstanceInfo& instance); + ~StalkerInstance(); - ADDON_STATUS Create() override; - ADDON_STATUS SetSetting(const std::string& settingName, - const kodi::addon::CSettingValue& settingValue) override + ADDON_STATUS SetInstanceSetting(const std::string& settingName, + const kodi::addon::CSettingValue& settingValue) override { return ADDON_STATUS_NEED_RESTART; } + ADDON_STATUS Initialize(); + PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) override; PVR_ERROR GetBackendName(std::string& name) override; PVR_ERROR GetBackendVersion(std::string& version) override; @@ -62,7 +66,7 @@ class ATTR_DLL_LOCAL SData : public kodi::addon::CAddonBase, const kodi::addon::PVRChannel& channel, std::vector& properties) override; - SC::Settings settings; + std::shared_ptr settings; protected: bool LoadCache(); @@ -76,7 +80,7 @@ class ATTR_DLL_LOCAL SData : public kodi::addon::CAddonBase, void QueueErrorNotification(SError error) const; private: - bool ReloadSettings(); + bool ConfigureStalkerAPISettings(); std::string GetChannelStreamURL(const kodi::addon::PVRChannel& channel) const; bool m_tokenManuallySet = false; @@ -87,8 +91,10 @@ class ATTR_DLL_LOCAL SData : public kodi::addon::CAddonBase, bool m_epgThreadActive = false; std::thread m_epgThread; mutable std::mutex m_epgMutex; - SC::SAPI* m_api = new SC::SAPI; - SC::SessionManager* m_sessionManager = new SC::SessionManager; - SC::ChannelManager* m_channelManager = new SC::ChannelManager; - SC::GuideManager* m_guideManager = new SC::GuideManager; + Stalker::SAPI* m_api = new Stalker::SAPI; + Stalker::SessionManager* m_sessionManager = new Stalker::SessionManager; + Stalker::ChannelManager* m_channelManager = new Stalker::ChannelManager; + Stalker::GuideManager* m_guideManager = new Stalker::GuideManager; }; + +} // SC \ No newline at end of file diff --git a/src/addon.cpp b/src/addon.cpp new file mode 100644 index 00000000..85100a4b --- /dev/null +++ b/src/addon.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) + * Copyright (C) 2015 Sam Stenvall + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#include "addon.h" +#include "StalkerInstance.h" +#include "stalker/SettingsMigration.h" + +using namespace Stalker; + +ADDON_STATUS CStalkerAddon::Create() +{ + /* Init settings */ + m_settings.reset(new AddonSettings()); + + kodi::Log(ADDON_LOG_DEBUG, "%s starting PVR client...", __func__); + + return ADDON_STATUS_OK; +} + +ADDON_STATUS CStalkerAddon::CreateInstance(const kodi::addon::IInstanceInfo& instance, KODI_ADDON_INSTANCE_HDL& hdl) +{ + if (instance.IsType(ADDON_INSTANCE_PVR)) + { + kodi::Log(ADDON_LOG_DEBUG, "creating Stalker Portal PVR addon"); + + m_stalker = new Stalker::StalkerInstance(instance); + ADDON_STATUS status = m_stalker->Initialize(); + + // Try to migrate settings from a pre-multi-instance setup + if (SettingsMigration::MigrateSettings(*m_stalker)) + { + // Initial client operated on old/incomplete settings + delete m_stalker; + m_stalker = new Stalker::StalkerInstance(instance); + } + + hdl = m_stalker; + + return status; + } + + return ADDON_STATUS_UNKNOWN; +} + +ADDON_STATUS CStalkerAddon::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +{ + return m_settings->SetSetting(settingName, settingValue); +} + +void CStalkerAddon::DestroyInstance(const kodi::addon::IInstanceInfo& instance, const KODI_ADDON_INSTANCE_HDL hdl) +{ + if (instance.IsType(ADDON_INSTANCE_PVR)) + { + m_stalker = nullptr; + } +} + +ADDONCREATOR(CStalkerAddon) diff --git a/src/addon.h b/src/addon.h new file mode 100644 index 00000000..c31f9db6 --- /dev/null +++ b/src/addon.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015-2021 Team Kodi (https://kodi.tv) + * Copyright (C) 2015 Sam Stenvall + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#include + +#include + +#include "stalker/AddonSettings.h" + +namespace Stalker +{ +class StalkerInstance; +} + +class StalkerInstance; + +class ATTR_DLL_LOCAL CStalkerAddon : public kodi::addon::CAddonBase +{ +public: + CStalkerAddon() = default; + + ADDON_STATUS Create() override; + ADDON_STATUS CreateInstance(const kodi::addon::IInstanceInfo& instance, KODI_ADDON_INSTANCE_HDL& hdl) override; + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) override; + void DestroyInstance(const kodi::addon::IInstanceInfo& instance, const KODI_ADDON_INSTANCE_HDL hdl) override; + +private: + + Stalker::StalkerInstance* m_stalker = nullptr; + std::shared_ptr m_settings; +}; diff --git a/src/stalker/AddonSettings.cpp b/src/stalker/AddonSettings.cpp new file mode 100644 index 00000000..79d6ec9e --- /dev/null +++ b/src/stalker/AddonSettings.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005-2022 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#include "AddonSettings.h" + +#include "SettingsMigration.h" + +#include "kodi/General.h" + +using namespace Stalker; + +AddonSettings::AddonSettings() +{ + ReadSettings(); +} + +void AddonSettings::ReadSettings() +{ + // This add-on only has instance settings! +} + +ADDON_STATUS AddonSettings::SetSetting(const std::string& settingName, + const kodi::addon::CSettingValue& settingValue) +{ + if (SettingsMigration::IsMigrationSetting(settingName)) + { + // ignore settings from pre-multi-instance setup + return ADDON_STATUS_OK; + } + + kodi::Log(ADDON_LOG_ERROR, "AddonSettings::SetSetting - unknown setting '%s'", + settingName.c_str()); + return ADDON_STATUS_UNKNOWN; +} \ No newline at end of file diff --git a/src/stalker/AddonSettings.h b/src/stalker/AddonSettings.h new file mode 100644 index 00000000..f2331d39 --- /dev/null +++ b/src/stalker/AddonSettings.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2022 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#include + +#include "kodi/AddonBase.h" + +namespace Stalker +{ +/** + * Represents the current addon settings + */ +class AddonSettings +{ + public: + AddonSettings(); + + /** + * Set a value according to key definition in settings.xml + */ + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue); + + private: + AddonSettings(const AddonSettings&) = delete; + void operator=(const AddonSettings&) = delete; + + /** + * Read all settings defined in settings.xml + */ + void ReadSettings(); +}; + +} // namespace Stalker \ No newline at end of file diff --git a/src/CWatchdog.cpp b/src/stalker/CWatchdog.cpp similarity index 98% rename from src/CWatchdog.cpp rename to src/stalker/CWatchdog.cpp index af1b6ff2..ffd713b7 100644 --- a/src/CWatchdog.cpp +++ b/src/stalker/CWatchdog.cpp @@ -12,7 +12,7 @@ #include #include -using namespace SC; +using namespace Stalker; CWatchdog::CWatchdog(uint32_t interval, SAPI* api, std::function errorCallback) : m_interval(interval), m_api(api), m_errorCallback(errorCallback) diff --git a/src/CWatchdog.h b/src/stalker/CWatchdog.h similarity index 93% rename from src/CWatchdog.h rename to src/stalker/CWatchdog.h index e9e5b91f..ac428789 100644 --- a/src/CWatchdog.h +++ b/src/stalker/CWatchdog.h @@ -13,7 +13,7 @@ #include #include -namespace SC +namespace Stalker { class CWatchdog { @@ -35,4 +35,4 @@ class CWatchdog bool m_threadActive = false; std::thread m_thread; }; -} // namespace SC +} // namespace Stalker diff --git a/src/ChannelManager.cpp b/src/stalker/ChannelManager.cpp similarity index 99% rename from src/ChannelManager.cpp rename to src/stalker/ChannelManager.cpp index d4f5da8c..4fb1ddba 100644 --- a/src/ChannelManager.cpp +++ b/src/stalker/ChannelManager.cpp @@ -13,7 +13,7 @@ #include #include -using namespace SC; +using namespace Stalker; SError ChannelManager::LoadChannels() { diff --git a/src/ChannelManager.h b/src/stalker/ChannelManager.h similarity index 97% rename from src/ChannelManager.h rename to src/stalker/ChannelManager.h index a4945f8e..ba28d649 100644 --- a/src/ChannelManager.h +++ b/src/stalker/ChannelManager.h @@ -12,7 +12,7 @@ #include "SAPI.h" #include "base/ChannelManager.h" -namespace SC +namespace Stalker { struct Channel : Base::Channel { @@ -69,4 +69,4 @@ class ChannelManager : public Base::ChannelManager SAPI* m_api = nullptr; std::vector m_channelGroups; }; -} // namespace SC +} // namespace Stalker diff --git a/src/Error.h b/src/stalker/Error.h similarity index 100% rename from src/Error.h rename to src/stalker/Error.h diff --git a/src/GuideManager.cpp b/src/stalker/GuideManager.cpp similarity index 80% rename from src/GuideManager.cpp rename to src/stalker/GuideManager.cpp index 6ee8c69f..91755cc3 100644 --- a/src/GuideManager.cpp +++ b/src/stalker/GuideManager.cpp @@ -15,7 +15,7 @@ #include #include -using namespace SC; +using namespace Stalker; GuideManager::~GuideManager() { @@ -27,7 +27,7 @@ SError GuideManager::LoadGuide(time_t start, time_t end) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); - if (m_guidePreference == SC::Settings::GUIDE_PREFERENCE_XMLTV_ONLY) + if (m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_XMLTV_ONLY) return SERROR_OK; bool ret(false); @@ -69,7 +69,7 @@ SError GuideManager::LoadXMLTV(HTTPSocket::Scope scope, const std::string& path) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); - if (m_guidePreference == SC::Settings::GUIDE_PREFERENCE_PROVIDER_ONLY || path.empty()) + if (m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_PROVIDER_ONLY || path.empty()) return SERROR_OK; bool ret(false); @@ -94,7 +94,7 @@ SError GuideManager::LoadXMLTV(HTTPSocket::Scope scope, const std::string& path) } int GuideManager::AddEvents( - int type, std::vector& events, Channel& channel, time_t start, time_t end) + int type, std::vector& events, Channel& channel, time_t start, time_t end, int epgTimeshiftSecs) { int addedEvents(0); @@ -123,8 +123,8 @@ int GuideManager::AddEvents( { try { - startTimestamp = Utils::GetIntFromJsonValue((*it)["start_timestamp"]); - stopTimestamp = Utils::GetIntFromJsonValue((*it)["stop_timestamp"]); + startTimestamp = Utils::GetIntFromJsonValue((*it)["start_timestamp"]) + epgTimeshiftSecs; + stopTimestamp = Utils::GetIntFromJsonValue((*it)["stop_timestamp"]) + epgTimeshiftSecs; if (start != 0 && end != 0 && !(startTimestamp >= start && stopTimestamp <= end)) continue; @@ -177,8 +177,8 @@ int GuideManager::AddEvents( e.uniqueBroadcastId = p->extra.broadcastId; e.title = p->title; e.channelNumber = channel.number; - e.startTime = p->start; - e.endTime = p->stop; + e.startTime = p->start + epgTimeshiftSecs; + e.endTime = p->stop + epgTimeshiftSecs; e.plot = p->desc; e.cast = p->extra.cast; e.directors = p->extra.directors; @@ -203,27 +203,27 @@ int GuideManager::AddEvents( return addedEvents; } -std::vector GuideManager::GetChannelEvents(Channel& channel, time_t start, time_t end) +std::vector GuideManager::GetChannelEvents(Channel& channel, time_t start, time_t end, int epgTimeshiftSecs) { kodi::Log(ADDON_LOG_DEBUG, "%s", __func__); std::vector events; int addedEvents; - if (m_guidePreference == SC::Settings::GUIDE_PREFERENCE_PREFER_PROVIDER || - m_guidePreference == SC::Settings::GUIDE_PREFERENCE_PROVIDER_ONLY) + if (m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_PREFER_PROVIDER || + m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_PROVIDER_ONLY) { - addedEvents = AddEvents(0, events, channel, start, end); - if (m_guidePreference == SC::Settings::GUIDE_PREFERENCE_PREFER_PROVIDER && !addedEvents) - AddEvents(1, events, channel, start, end); + addedEvents = AddEvents(0, events, channel, start, end, epgTimeshiftSecs); + if (m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_PREFER_PROVIDER && !addedEvents) + AddEvents(1, events, channel, start, end, epgTimeshiftSecs); } - if (m_guidePreference == SC::Settings::GUIDE_PREFERENCE_PREFER_XMLTV || - m_guidePreference == SC::Settings::GUIDE_PREFERENCE_XMLTV_ONLY) + if (m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_PREFER_XMLTV || + m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_XMLTV_ONLY) { - addedEvents = AddEvents(1, events, channel, start, end); - if (m_guidePreference == SC::Settings::GUIDE_PREFERENCE_PREFER_XMLTV && !addedEvents) - AddEvents(0, events, channel, start, end); + addedEvents = AddEvents(1, events, channel, start, end, epgTimeshiftSecs); + if (m_guidePreference == Stalker::InstanceSettings::GUIDE_PREFERENCE_PREFER_XMLTV && !addedEvents) + AddEvents(0, events, channel, start, end, epgTimeshiftSecs); } return events; diff --git a/src/GuideManager.h b/src/stalker/GuideManager.h similarity index 79% rename from src/GuideManager.h rename to src/stalker/GuideManager.h index 621607a4..abd53045 100644 --- a/src/GuideManager.h +++ b/src/stalker/GuideManager.h @@ -11,14 +11,14 @@ #include "ChannelManager.h" #include "HTTPSocket.h" #include "SAPI.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "XMLTV.h" #include "base/GuideManager.h" #include #include -namespace SC +namespace Stalker { struct Event : Base::Event { @@ -45,7 +45,7 @@ class GuideManager : public Base::GuideManager virtual void SetAPI(SAPI* api) { m_api = api; } - virtual void SetGuidePreference(Settings::GuidePreference guidePreference) + virtual void SetGuidePreference(InstanceSettings::GuidePreference guidePreference) { m_guidePreference = guidePreference; } @@ -60,19 +60,19 @@ class GuideManager : public Base::GuideManager virtual SError LoadXMLTV(HTTPSocket::Scope scope, const std::string& path); - virtual std::vector GetChannelEvents(Channel& channel, time_t start = 0, time_t end = 0); + virtual std::vector GetChannelEvents(Channel& channel, time_t start, time_t end, int epgTimeshiftSecs); virtual void Clear(); private: - int AddEvents(int type, std::vector& events, Channel& channel, time_t start, time_t end); + int AddEvents(int type, std::vector& events, Channel& channel, time_t start, time_t end, int epgTimeshiftSecs); SAPI* m_api = nullptr; - Settings::GuidePreference m_guidePreference = - (SC::Settings::GuidePreference)SC_SETTINGS_DEFAULT_GUIDE_PREFERENCE; + InstanceSettings::GuidePreference m_guidePreference = + (Stalker::InstanceSettings::GuidePreference)SC_SETTINGS_DEFAULT_GUIDE_PREFERENCE; bool m_useCache = SC_SETTINGS_DEFAULT_GUIDE_CACHE; unsigned int m_expiry = SC_SETTINGS_DEFAULT_GUIDE_CACHE_HOURS * 3600; std::shared_ptr m_xmltv = std::make_shared(); Json::Value m_epgData; }; -} // namespace SC +} // namespace Stalker diff --git a/src/HTTPSocket.cpp b/src/stalker/HTTPSocket.cpp similarity index 97% rename from src/HTTPSocket.cpp rename to src/stalker/HTTPSocket.cpp index b376a3f0..d1709d6d 100644 --- a/src/HTTPSocket.cpp +++ b/src/stalker/HTTPSocket.cpp @@ -71,7 +71,7 @@ void HTTPSocket::BuildRequestURL(Request& request) for (std::vector::iterator it = request.options.begin(); it != request.options.end(); ++it) { - sprintf(buffer, "%s=%s", it->name.c_str(), Utils::UrlEncode(it->value).c_str()); + snprintf(buffer, sizeof(buffer), "%s=%s", it->name.c_str(), Utils::UrlEncode(it->value).c_str()); requestUrl += buffer; if (it + 1 != request.options.end()) diff --git a/src/HTTPSocket.h b/src/stalker/HTTPSocket.h similarity index 100% rename from src/HTTPSocket.h rename to src/stalker/HTTPSocket.h diff --git a/src/stalker/InstanceSettings.cpp b/src/stalker/InstanceSettings.cpp new file mode 100644 index 00000000..9d67e657 --- /dev/null +++ b/src/stalker/InstanceSettings.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2021 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#include "InstanceSettings.h" + +using namespace Stalker; + +InstanceSettings::InstanceSettings(kodi::addon::IAddonInstance& instance) + : m_instance(instance) +{ + ReadSettings(); +} + +void InstanceSettings::ReadSettings() +{ + if (!m_instance.CheckInstanceSettingInt("connection_timeout", connectionTimeout)) + connectionTimeout = SC_SETTINGS_DEFAULT_CONNECTION_TIMEOUT; + if (!m_instance.CheckInstanceSettingString("mac", mac)) + mac = SC_SETTINGS_DEFAULT_MAC; + if (!m_instance.CheckInstanceSettingString("server", server)) + server = SC_SETTINGS_DEFAULT_MAC; + if (!m_instance.CheckInstanceSettingString("time_zone", timeZone)) + timeZone = SC_SETTINGS_DEFAULT_TIME_ZONE; + if (!m_instance.CheckInstanceSettingFloat("epg_timeshift", epgTimeshiftHours)) + epgTimeshiftHours = SC_SETTINGS_DEFAULT_EPG_TIMESHIFT; + + if (!m_instance.CheckInstanceSettingString("login", login)) + login = SC_SETTINGS_DEFAULT_LOGIN; + if (!m_instance.CheckInstanceSettingString("password", password)) + password = SC_SETTINGS_DEFAULT_PASSWORD; + + if (!m_instance.CheckInstanceSettingEnum("guide_preference", guidePreference)) + guidePreference = GuidePreference::GUIDE_PREFERENCE_PREFER_PROVIDER; + if (!m_instance.CheckInstanceSettingBoolean("guide_cache", guideCache)) + guideCache = SC_SETTINGS_DEFAULT_GUIDE_CACHE; + if (!m_instance.CheckInstanceSettingInt("guide_cache_hours", guideCacheHours)) + guideCacheHours = SC_SETTINGS_DEFAULT_GUIDE_CACHE_HOURS; + + if (!m_instance.CheckInstanceSettingEnum("xmltv_scope", xmltvScope)) + xmltvScope = HTTPSocket::Scope::SCOPE_REMOTE; + if (xmltvScope == HTTPSocket::Scope::SCOPE_REMOTE) + m_instance.CheckInstanceSettingString("xmltv_url", xmltvPath); + else + m_instance.CheckInstanceSettingString("xmltv_path", xmltvPath); + + if (!m_instance.CheckInstanceSettingString("token", token)) + token = SC_SETTINGS_DEFAULT_TOKEN; + if (!m_instance.CheckInstanceSettingString("serial_number", serialNumber)) + serialNumber = SC_SETTINGS_DEFAULT_SERIAL_NUMBER; + if (!m_instance.CheckInstanceSettingString("device_id", deviceId)) + deviceId = SC_SETTINGS_DEFAULT_DEVICE_ID; + if (!m_instance.CheckInstanceSettingString("device_id2", deviceId2)) + deviceId2 = SC_SETTINGS_DEFAULT_DEVICE_ID2; + if (!m_instance.CheckInstanceSettingString("signature", signature)) + signature = SC_SETTINGS_DEFAULT_SIGNATURE; + + kodi::Log(ADDON_LOG_DEBUG, "connection_timeout=%d", connectionTimeout); + + kodi::Log(ADDON_LOG_DEBUG, "mac=%s", mac.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "server=%s", server.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "timeZone=%s", timeZone.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "epgTimeshift=%f", epgTimeshiftHours); + kodi::Log(ADDON_LOG_DEBUG, "login=%s", login.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "password=%s", password.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "guidePreference=%d", guidePreference); + kodi::Log(ADDON_LOG_DEBUG, "guideCache=%d", guideCache); + kodi::Log(ADDON_LOG_DEBUG, "guideCacheHours=%d", guideCacheHours); + kodi::Log(ADDON_LOG_DEBUG, "xmltvScope=%d", xmltvScope); + kodi::Log(ADDON_LOG_DEBUG, "xmltvPath=%s", xmltvPath.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "token=%s", token.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "serialNumber=%s", serialNumber.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "deviceId=%s", deviceId.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "deviceId2=%s", deviceId2.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "signature=%s", signature.c_str()); +} + +ADDON_STATUS InstanceSettings::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +{ + return ADDON_STATUS_OK; +} diff --git a/src/Settings.h b/src/stalker/InstanceSettings.h similarity index 75% rename from src/Settings.h rename to src/stalker/InstanceSettings.h index 5e645fd9..aa1d96c8 100644 --- a/src/Settings.h +++ b/src/stalker/InstanceSettings.h @@ -10,15 +10,18 @@ #include "HTTPSocket.h" +#include + #include #define SC_SETTINGS_DEFAULT_ACTIVE_PORTAL 0 #define SC_SETTINGS_DEFAULT_MAC "00:1A:79:00:00:00" #define SC_SETTINGS_DEFAULT_SERVER "127.0.0.1" #define SC_SETTINGS_DEFAULT_TIME_ZONE "Europe/Kiev" +#define SC_SETTINGS_DEFAULT_EPG_TIMESHIFT 0.0f #define SC_SETTINGS_DEFAULT_LOGIN "" #define SC_SETTINGS_DEFAULT_PASSWORD "" -#define SC_SETTINGS_DEFAULT_CONNECTION_TIMEOUT 1 // 5 seconds +#define SC_SETTINGS_DEFAULT_CONNECTION_TIMEOUT 5 // 5 seconds #define SC_SETTINGS_DEFAULT_GUIDE_PREFERENCE 0 // prefer provider #define SC_SETTINGS_DEFAULT_GUIDE_CACHE 1 // true #define SC_SETTINGS_DEFAULT_GUIDE_CACHE_HOURS 24 @@ -31,9 +34,9 @@ #define SC_SETTINGS_DEFAULT_DEVICE_ID2 "" #define SC_SETTINGS_DEFAULT_SIGNATURE "" -namespace SC +namespace Stalker { -class Settings +class InstanceSettings { public: typedef enum @@ -44,16 +47,22 @@ class Settings GUIDE_PREFERENCE_XMLTV_ONLY } GuidePreference; + explicit InstanceSettings(kodi::addon::IAddonInstance& instance); + + void ReadSettings(); + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue); + int activePortal; std::string mac; std::string server; std::string timeZone; + float epgTimeshiftHours = 0.0f; std::string login; std::string password; - unsigned int connectionTimeout; + int connectionTimeout; GuidePreference guidePreference; bool guideCache; - unsigned int guideCacheHours; + int guideCacheHours; HTTPSocket::Scope xmltvScope; std::string xmltvPath; std::string token; @@ -61,5 +70,7 @@ class Settings std::string deviceId; std::string deviceId2; std::string signature; + + kodi::addon::IAddonInstance& m_instance; }; -} // namespace SC +} // namespace Stalker diff --git a/src/SAPI.cpp b/src/stalker/SAPI.cpp similarity index 99% rename from src/SAPI.cpp rename to src/stalker/SAPI.cpp index f4da380b..110226d0 100644 --- a/src/SAPI.cpp +++ b/src/stalker/SAPI.cpp @@ -20,7 +20,7 @@ #define SC_SAPI_AUTHORIZATION_FAILED "Authorization failed." -using namespace SC; +using namespace Stalker; void SAPI::SetEndpoint(const std::string& endpoint) { diff --git a/src/SAPI.h b/src/stalker/SAPI.h similarity index 97% rename from src/SAPI.h rename to src/stalker/SAPI.h index 36c6ab18..83cc4de8 100644 --- a/src/SAPI.h +++ b/src/stalker/SAPI.h @@ -15,7 +15,7 @@ #include #include -namespace SC +namespace Stalker { class SAPI { @@ -65,4 +65,4 @@ class SAPI std::string m_referer; unsigned int m_timeout = 0; }; -} // namespace SC +} // namespace Stalker diff --git a/src/SessionManager.cpp b/src/stalker/SessionManager.cpp similarity index 99% rename from src/SessionManager.cpp rename to src/stalker/SessionManager.cpp index 77b28487..547b6f17 100644 --- a/src/SessionManager.cpp +++ b/src/stalker/SessionManager.cpp @@ -14,7 +14,7 @@ #include #include -using namespace SC; +using namespace Stalker; SessionManager::~SessionManager() { diff --git a/src/SessionManager.h b/src/stalker/SessionManager.h similarity index 97% rename from src/SessionManager.h rename to src/stalker/SessionManager.h index cc18a0f1..60ab1c97 100644 --- a/src/SessionManager.h +++ b/src/stalker/SessionManager.h @@ -15,7 +15,7 @@ #include -namespace SC +namespace Stalker { class SessionManager { @@ -78,4 +78,4 @@ class SessionManager bool m_threadActive = false; std::thread m_thread; }; -} // namespace SC +} // namespace Stalker diff --git a/src/stalker/SettingsMigration.cpp b/src/stalker/SettingsMigration.cpp new file mode 100644 index 00000000..d89b7d9d --- /dev/null +++ b/src/stalker/SettingsMigration.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2005-2022 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#include "SettingsMigration.h" + +#include "kodi/General.h" + +#include +#include +#include + +using namespace Stalker; + +namespace +{ +// maps +const std::vector> stringMap = {{"mac", "0:1A:79:00:00:00"}, + {"server", "127.0.0.1"}, + {"time_zone", "Europe/Kiev"}, + {"login", ""}, + {"password", ""}, + {"xmltv_url", ""}, + {"xmltv_path", ""}, + {"token", ""}, + {"serial_number", ""}, + {"device_id", ""}, + {"device_id2", ""}, + {"signature", ""}}; + +const std::vector> intMap = {{"connection_timeout", 5}, + {"guide_preference", 1}, + {"guide_cache_hours", 24}, + {"xmltv_scope", 0}}; + +const std::vector> floatMap = {{"epg_timeshift", 0.0f}}; + +const std::vector> boolMap = {{"guide_cache", true}}; + +} // unnamed namespace + +bool SettingsMigration::MigrateSettings(kodi::addon::IAddonInstance& target) +{ + std::string stringValue; + bool boolValue{false}; + int intValue{0}; + + if (target.CheckInstanceSettingString("kodi_addon_instance_name", stringValue) && + !stringValue.empty()) + { + // Instance already has valid instance settings + return false; + } + + // Read pre-multi-instance settings from settings.xml, transfer to instance settings + SettingsMigration mig(target); + + for (const auto& setting : stringMap) + mig.MigrateStringSetting(setting.first, setting.second); + + for (const auto& setting : intMap) + mig.MigrateIntSetting(setting.first, setting.second); + + for (const auto& setting : floatMap) + mig.MigrateFloatSetting(setting.first, setting.second); + + for (const auto& setting : boolMap) + mig.MigrateBoolSetting(setting.first, setting.second); + + if (mig.Changed()) + { + // Set a title for the new instance settings + std::string title = "Migrated Add-on Config"; + target.SetInstanceSettingString("kodi_addon_instance_name", title); + + return true; + } + return false; +} + +bool SettingsMigration::IsMigrationSetting(const std::string& key) +{ + std::string oldSettingsKey{key}; + oldSettingsKey += "_0"; + + return std::any_of(stringMap.cbegin(), stringMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(intMap.cbegin(), intMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(floatMap.cbegin(), floatMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(boolMap.cbegin(), boolMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(stringMap.cbegin(), stringMap.cend(), + [&oldSettingsKey](const auto& entry) { return entry.first == oldSettingsKey; }) || + std::any_of(intMap.cbegin(), intMap.cend(), + [&oldSettingsKey](const auto& entry) { return entry.first == oldSettingsKey; }) || + std::any_of(floatMap.cbegin(), floatMap.cend(), + [&oldSettingsKey](const auto& entry) { return entry.first == oldSettingsKey; }) || + std::any_of(boolMap.cbegin(), boolMap.cend(), + [&oldSettingsKey](const auto& entry) { return entry.first == oldSettingsKey; }); +} + +void SettingsMigration::MigrateStringSetting(const char* key, const std::string& defaultValue) +{ + std::string oldSettingsKey{key}; + oldSettingsKey += "_0"; + + std::string value; + if (kodi::addon::CheckSettingString(oldSettingsKey, value) && value != defaultValue) + { + m_target.SetInstanceSettingString(key, value); + m_changed = true; + } + else if (kodi::addon::CheckSettingString(key, value) && value != defaultValue) + { + m_target.SetInstanceSettingString(key, value); + m_changed = true; + } +} + +void SettingsMigration::MigrateIntSetting(const char* key, int defaultValue) +{ + std::string oldSettingsKey{key}; + oldSettingsKey += "_0"; + + // Stalker uses the old settings format prior to migration and reading int and boolean reliably requires reading into + // a string and then into a int. Luckily after this messy migration, the settings will be in the new format going forward. + int value; + std::string stringValue; + if (kodi::addon::CheckSettingString(oldSettingsKey, stringValue) && stringValue != std::to_string(defaultValue)) + { + value = std::atoi(stringValue.c_str()); + m_target.SetInstanceSettingInt(key, value); + m_changed = true; + } + else if (kodi::addon::CheckSettingString(key, stringValue) && stringValue != std::to_string(defaultValue)) + { + value = std::atoi(stringValue.c_str()); + if (oldSettingsKey == "connection_timeout_0") + value *= 5; + + m_target.SetInstanceSettingInt(key, value); + m_changed = true; + } +} + +void SettingsMigration::MigrateFloatSetting(const char* key, float defaultValue) +{ + std::string oldSettingsKey{key}; + oldSettingsKey += "_0"; + + float value; + if (kodi::addon::CheckSettingFloat(oldSettingsKey, value) && value != defaultValue) + { + m_target.SetInstanceSettingFloat(key, value); + m_changed = true; + } + else if (kodi::addon::CheckSettingFloat(key, value) && value != defaultValue) + { + m_target.SetInstanceSettingFloat(key, value); + m_changed = true; + } +} + +void SettingsMigration::MigrateBoolSetting(const char* key, bool defaultValue) +{ + std::string oldSettingsKey{key}; + oldSettingsKey += "_0"; + + // Stalker uses the old settings format prior to migration and reading int and boolean reliably requires reading into + // a string and then into a int. Luckily after this messy migration, the settings will be in the new format going forward. + bool value; + std::string stringValue; + if (kodi::addon::CheckSettingString(oldSettingsKey, stringValue) && stringValue != (defaultValue ? "true" : "false")) + { + value = stringValue == "true"; + m_target.SetInstanceSettingBoolean(key, value); + m_changed = true; + } +} diff --git a/src/stalker/SettingsMigration.h b/src/stalker/SettingsMigration.h new file mode 100644 index 00000000..32aad099 --- /dev/null +++ b/src/stalker/SettingsMigration.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2022 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#include + +namespace kodi +{ +namespace addon +{ +class IAddonInstance; +} +} // namespace kodi + +namespace Stalker +{ +class SettingsMigration +{ +public: + static bool MigrateSettings(kodi::addon::IAddonInstance& target); + static bool IsMigrationSetting(const std::string& key); + +private: + SettingsMigration() = delete; + explicit SettingsMigration(kodi::addon::IAddonInstance& target) : m_target(target) {} + + void MigrateStringSetting(const char* key, const std::string& defaultValue); + void MigrateIntSetting(const char* key, int defaultValue); + void MigrateFloatSetting(const char* key, float defaultValue); + void MigrateBoolSetting(const char* key, bool defaultValue); + + bool Changed() const { return m_changed; } + + kodi::addon::IAddonInstance& m_target; + bool m_changed{false}; +}; + +} // namespace Stalker diff --git a/src/Utils.cpp b/src/stalker/Utils.cpp similarity index 100% rename from src/Utils.cpp rename to src/stalker/Utils.cpp diff --git a/src/Utils.h b/src/stalker/Utils.h similarity index 100% rename from src/Utils.h rename to src/stalker/Utils.h diff --git a/src/XMLTV.cpp b/src/stalker/XMLTV.cpp similarity index 100% rename from src/XMLTV.cpp rename to src/stalker/XMLTV.cpp diff --git a/src/XMLTV.h b/src/stalker/XMLTV.h similarity index 100% rename from src/XMLTV.h rename to src/stalker/XMLTV.h diff --git a/src/base/Cache.cpp b/src/stalker/base/Cache.cpp similarity index 100% rename from src/base/Cache.cpp rename to src/stalker/base/Cache.cpp diff --git a/src/base/Cache.h b/src/stalker/base/Cache.h similarity index 100% rename from src/base/Cache.h rename to src/stalker/base/Cache.h diff --git a/src/base/ChannelManager.h b/src/stalker/base/ChannelManager.h similarity index 100% rename from src/base/ChannelManager.h rename to src/stalker/base/ChannelManager.h diff --git a/src/base/GuideManager.h b/src/stalker/base/GuideManager.h similarity index 100% rename from src/base/GuideManager.h rename to src/stalker/base/GuideManager.h