diff -Nru kodi-pvr-hts-20.3.0+ds1/azure-pipelines.yml kodi-pvr-hts-20.6.0+ds1/azure-pipelines.yml --- kodi-pvr-hts-20.3.0+ds1/azure-pipelines.yml 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/azure-pipelines.yml 2022-10-07 16:22:25.000000000 +0000 @@ -17,25 +17,25 @@ - job: Windows pool: - vmImage: 'VS2017-Win2016' + vmImage: 'windows-2022' strategy: matrix: Win32: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: Win32 CONFIGURATION: Release Win64: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release Win64-UWP: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: x64 CONFIGURATION: Release WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" ARM64-UWP: - GENERATOR: "Visual Studio 15 2017" + GENERATOR: "Visual Studio 17 2022" ARCHITECTURE: ARM64 CONFIGURATION: Release WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" diff -Nru kodi-pvr-hts-20.3.0+ds1/CMakeLists.txt kodi-pvr-hts-20.6.0+ds1/CMakeLists.txt --- kodi-pvr-hts-20.3.0+ds1/CMakeLists.txt 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/CMakeLists.txt 2022-10-07 16:22:25.000000000 +0000 @@ -48,6 +48,8 @@ src/aac/huffman/Decoder.h) set(HTS_SOURCES_TVHEADEND + src/tvheadend/AddonSettings.cpp + src/tvheadend/AddonSettings.h src/tvheadend/AutoRecordings.cpp src/tvheadend/AutoRecordings.h src/tvheadend/ChannelTuningPredictor.h @@ -60,11 +62,11 @@ src/tvheadend/HTSPTypes.h src/tvheadend/HTSPVFS.h src/tvheadend/HTSPVFS.cpp + src/tvheadend/InstanceSettings.h + src/tvheadend/InstanceSettings.cpp src/tvheadend/IHTSPConnectionListener.h src/tvheadend/IHTSPDemuxPacketHandler.h src/tvheadend/Profile.h - src/tvheadend/Settings.cpp - src/tvheadend/Settings.h src/tvheadend/Subscription.cpp src/tvheadend/Subscription.h src/tvheadend/TimeRecordings.cpp @@ -106,7 +108,9 @@ src/tvheadend/utilities/RDSExtractor.cpp src/tvheadend/utilities/SyncedBuffer.h src/tvheadend/utilities/TCPSocket.h - src/tvheadend/utilities/TCPSocket.cpp) + src/tvheadend/utilities/TCPSocket.cpp + src/tvheadend/utilities/SettingsMigration.h + src/tvheadend/utilities/SettingsMigration.cpp) source_group("Source Files" FILES ${HTS_SOURCES}) source_group("Source Files\\aac" FILES ${HTS_SOURCES_AAC}) diff -Nru kodi-pvr-hts-20.3.0+ds1/debian/changelog kodi-pvr-hts-20.6.0+ds1/debian/changelog --- kodi-pvr-hts-20.3.0+ds1/debian/changelog 2022-08-04 09:54:42.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/debian/changelog 2022-10-15 16:54:36.000000000 +0000 @@ -1,3 +1,11 @@ +kodi-pvr-hts (20.6.0+ds1-1) unstable; urgency=medium + + * New upstream version 20.6.0+ds1 + * Fix lintian warnings + * d/watch: switch to git tags + + -- Vasyl Gello Sat, 15 Oct 2022 16:54:36 +0000 + kodi-pvr-hts (20.3.0+ds1-1) unstable; urgency=medium * New upstream version 20.3.0+ds1 diff -Nru kodi-pvr-hts-20.3.0+ds1/debian/kodi-pvr-hts.lintian-overrides kodi-pvr-hts-20.6.0+ds1/debian/kodi-pvr-hts.lintian-overrides --- kodi-pvr-hts-20.3.0+ds1/debian/kodi-pvr-hts.lintian-overrides 2022-08-04 09:54:42.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/debian/kodi-pvr-hts.lintian-overrides 2022-10-15 16:54:36.000000000 +0000 @@ -3,4 +3,4 @@ # changelog.txt is still a part of Kodi addon specification so # it should not be removed -package-contains-documentation-outside-usr-share-doc usr/share/kodi/addons/pvr.hts/changelog.txt +package-contains-documentation-outside-usr-share-doc [usr/share/kodi/addons/pvr.hts/changelog.txt] diff -Nru kodi-pvr-hts-20.3.0+ds1/debian/watch kodi-pvr-hts-20.6.0+ds1/debian/watch --- kodi-pvr-hts-20.3.0+ds1/debian/watch 2022-08-04 09:54:42.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/debian/watch 2022-10-15 16:54:36.000000000 +0000 @@ -1,8 +1,14 @@ version=4 -opts="repack, \ - compression=xz, \ +# Release git tags +# TODO: Change Kodi codename in refs/tags before packaging next Kodi major release + +opts="mode=git, \ + pgpmode=none, \ + repack, \ repacksuffix=+ds1, \ + compression=xz, \ dversionmangle=auto" \ -https://github.com/kodi-pvr/pvr.hts/releases \ -/kodi-pvr/pvr.hts/archive/refs/tags/?(\d\S*)-Nexus\.tar\.gz +https://github.com/kodi-pvr/pvr.hts \ +refs/tags/@ANY_VERSION@-Nexus \ +debian diff -Nru kodi-pvr-hts-20.3.0+ds1/pvr.hts/addon.xml.in kodi-pvr-hts-20.6.0+ds1/pvr.hts/addon.xml.in --- kodi-pvr-hts-20.3.0+ds1/pvr.hts/addon.xml.in 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/pvr.hts/addon.xml.in 2022-10-07 16:22:25.000000000 +0000 @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ diff -Nru kodi-pvr-hts-20.3.0+ds1/pvr.hts/changelog.txt kodi-pvr-hts-20.6.0+ds1/pvr.hts/changelog.txt --- kodi-pvr-hts-20.3.0+ds1/pvr.hts/changelog.txt 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/pvr.hts/changelog.txt 2022-10-07 16:22:25.000000000 +0000 @@ -1,3 +1,14 @@ +v20.6.0 +- Drop support for Tvheadend < 4.2.0 + +v20.5.0 +- Kodi inputstream API update to version 3.2.0 +- Kodi PVR API update to version 8.0.2 + +v20.4.0 +- Add support for multiple backends. +- Request addon-restart only on settings changes which require a reconnect to the backend. + v20.3.0 - Inputstream API bump. diff -Nru kodi-pvr-hts-20.3.0+ds1/pvr.hts/resources/instance-settings.xml kodi-pvr-hts-20.6.0+ds1/pvr.hts/resources/instance-settings.xml --- kodi-pvr-hts-20.3.0+ds1/pvr.hts/resources/instance-settings.xml 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/pvr.hts/resources/instance-settings.xml 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,286 @@ + + +
+ + + + 0 + 127.0.0.1 + + + + 0 + false + + + + 0 + 9981 + + 1 + 1 + 65535 + + + + + 0 + 9982 + + 1 + 1 + 65535 + + + + + 0 + + + true + + + + + 0 + + + true + + + true + + + + + + + 0 + 10 + + 1 + 1 + 60 + + + + + 0 + 5 + + 1 + 1 + 60 + + + + + 0 + + + true + + + + + + + + + + + + 0 + + + true + + + + + 0 + false + + + + + + + 0 + false + + + + 0 + 2 + + 2 + 1 + 10 + + + true + + + + + 0 + 10 + + 5 + 5 + 60 + + + true + + + + + + + + 0 + 64 + + 4 + 4 + 512 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + 0 + 15 + + 0 + 5 + 120 + + + 1 + + + + + 0 + false + + + + + + + 0 + true + + + + + + + 0 + 2 + + + + + + + + + + + + + 0 + 15 + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + true + + + + + + + 0 + true + + + + + +
+
diff -Nru kodi-pvr-hts-20.3.0+ds1/pvr.hts/resources/language/resource.language.en_gb/strings.po kodi-pvr-hts-20.6.0+ds1/pvr.hts/resources/language/resource.language.en_gb/strings.po --- kodi-pvr-hts-20.3.0+ds1/pvr.hts/resources/language/resource.language.en_gb/strings.po 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/pvr.hts/resources/language/resource.language.en_gb/strings.po 2022-10-07 16:22:25.000000000 +0000 @@ -294,17 +294,7 @@ msgid "Record if unique episode according EPG/XMLTV" msgstr "" -#. Recording lifetime representation -#: src/Tvheadend.cpp -msgctxt "#30373" -msgid "Until space needed" -msgstr "" - -#. Recording lifetime representation -#: src/Tvheadend.cpp -msgctxt "#30374" -msgid "Forever" -msgstr "" +#empty strings from id 30373 to 30374 #. Recording lifetime representation #: src/Tvheadend.cpp @@ -384,14 +374,14 @@ msgid "3 years" msgstr "" -#. Recording lifetime representation (for setting dialog only) +#. Recording lifetime representation msgctxt "#30388" -msgid "Until space needed (tvh 4.1+)" +msgid "Until space needed" msgstr "" -#. Recording lifetime representation (for setting dialog only) +#. Recording lifetime representation msgctxt "#30389" -msgid "Forever (tvh 4.1+)" +msgid "Forever" msgstr "" #. Recording lifetime representation diff -Nru kodi-pvr-hts-20.3.0+ds1/pvr.hts/resources/settings.xml kodi-pvr-hts-20.6.0+ds1/pvr.hts/resources/settings.xml --- kodi-pvr-hts-20.3.0+ds1/pvr.hts/resources/settings.xml 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/pvr.hts/resources/settings.xml 2022-10-07 16:22:25.000000000 +0000 @@ -1,291 +1,129 @@
- - - + + + + 0 + false + + + + + + + + + + 4 127.0.0.1 - - - 0 + + 4 false - - - 0 + + 4 9981 - - 1 - 1 - 65535 - - - - 0 + + 4 9982 - - 1 - 1 - 65535 - - - - 0 + + 4 true - - - 0 + + 4 true - - true - - - - - - 0 + + 4 10 - - 1 - 1 - 60 - - - - 0 + + 4 5 - - 1 - 1 - 60 - - - - 0 + + 4 true - - - - - - - - - - 0 + + 4 true - - - 0 + + 4 false - - - - - - 0 + + 4 false - - - 0 + + 4 2 - - 2 - 1 - 10 - - - true - - - - 0 + + 4 10 - - 5 - 5 - 60 - - - true - - - - - - - 0 + + 4 64 - - 4 - 4 - 512 - - - - - - - - - - - 0 - 0 - - - - - - - + + 4 + 0 - - 0 + + 4 15 - - 0 - 5 - 120 - - - 1 - - - - 0 + + 4 false - - - - - - 0 + + 4 true - - - - - - 0 + + 4 2 - - - - - - - - - - - - 0 - 15 - - - - - - - - - - - - - - - - - - - - - + + 4 + 15 - - 0 - 0 - - - - - - - - - - - - - - - - - - - - + + 4 + 0 - - - - - - - - - 0 + + 4 true - - - - - - 0 + + 4 true - - - - - - - 0 - false - diff -Nru kodi-pvr-hts-20.3.0+ds1/src/addon.cpp kodi-pvr-hts-20.6.0+ds1/src/addon.cpp --- kodi-pvr-hts-20.3.0+ds1/src/addon.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/addon.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -8,49 +8,53 @@ #include "addon.h" #include "Tvheadend.h" -#include "tvheadend/Settings.h" +#include "tvheadend/AddonSettings.h" #include "tvheadend/utilities/Logger.h" +#include "tvheadend/utilities/SettingsMigration.h" using namespace tvheadend; using namespace tvheadend::utilities; ADDON_STATUS CHTSAddon::Create() { - /* Configure the logger */ - Logger::GetInstance().SetImplementation([](LogLevel level, const char* message) { - /* Convert the log level */ - ADDON_LOG addonLevel; - - switch (level) - { - case LogLevel::LEVEL_FATAL: - addonLevel = ADDON_LOG::ADDON_LOG_FATAL; - break; - case LogLevel::LEVEL_ERROR: - addonLevel = ADDON_LOG::ADDON_LOG_ERROR; - break; - case LogLevel::LEVEL_WARNING: - addonLevel = ADDON_LOG::ADDON_LOG_WARNING; - break; - case LogLevel::LEVEL_INFO: - addonLevel = ADDON_LOG::ADDON_LOG_INFO; - break; - default: - addonLevel = ADDON_LOG::ADDON_LOG_DEBUG; - break; - } + /* Init settings */ + m_settings.reset(new AddonSettings()); - /* Don't log trace messages unless told so */ - if (level == LogLevel::LEVEL_TRACE && !Settings::GetInstance().GetTraceDebug()) - return; + /* Configure the logger */ + Logger::GetInstance().SetImplementation( + [this](LogLevel level, const char* message) + { + /* Don't log trace messages unless told so */ + if (level == LogLevel::LEVEL_TRACE && !m_settings->GetTraceDebug()) + return; + + /* Convert the log level */ + ADDON_LOG addonLevel; + + switch (level) + { + case LogLevel::LEVEL_FATAL: + addonLevel = ADDON_LOG::ADDON_LOG_FATAL; + break; + case LogLevel::LEVEL_ERROR: + addonLevel = ADDON_LOG::ADDON_LOG_ERROR; + break; + case LogLevel::LEVEL_WARNING: + addonLevel = ADDON_LOG::ADDON_LOG_WARNING; + break; + case LogLevel::LEVEL_INFO: + addonLevel = ADDON_LOG::ADDON_LOG_INFO; + break; + default: + addonLevel = ADDON_LOG::ADDON_LOG_DEBUG; + break; + } - kodi::Log(addonLevel, "%s", message); - }); + kodi::Log(addonLevel, "%s", message); + }); Logger::Log(LogLevel::LEVEL_INFO, "starting PVR client"); - Settings::GetInstance().ReadSettings(); - return ADDON_STATUS_OK; } @@ -58,7 +62,8 @@ const kodi::addon::CSettingValue& settingValue) { std::lock_guard lock(m_mutex); - return Settings::GetInstance().SetSetting(settingName, settingValue); + + return m_settings->SetSetting(settingName, settingValue); } ADDON_STATUS CHTSAddon::CreateInstance(const kodi::addon::IInstanceInfo& instance, @@ -70,8 +75,17 @@ { Logger::Log(LogLevel::LEVEL_DEBUG, "%s: Creating PVR-Client instance", __FUNCTION__); - /* Connect to ARGUS TV */ + /* Connect to TVHeadend backend */ CTvheadend* client = new CTvheadend(instance); + + // Try to migrate settings from a pre-multi-instance setup + if (SettingsMigration::MigrateSettings(*client)) + { + // Initial client operated on old/incomplete settings + delete client; + client = new CTvheadend(instance); + } + client->Start(); hdl = client; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/addon.h kodi-pvr-hts-20.6.0+ds1/src/addon.h --- kodi-pvr-hts-20.3.0+ds1/src/addon.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/addon.h 2022-10-07 16:22:25.000000000 +0000 @@ -9,8 +9,14 @@ #include "kodi/AddonBase.h" +#include #include +namespace tvheadend +{ +class AddonSettings; +} + class ATTR_DLL_LOCAL CHTSAddon : public kodi::addon::CAddonBase { public: @@ -24,4 +30,5 @@ private: std::recursive_mutex m_mutex; + std::shared_ptr m_settings; }; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AddonSettings.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AddonSettings.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AddonSettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AddonSettings.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,60 @@ +/* + * 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 "utilities/Logger.h" +#include "utilities/SettingsMigration.h" + +#include "kodi/General.h" + +using namespace tvheadend; +using namespace tvheadend::utilities; + +namespace +{ +constexpr bool DEFAULT_TRACE_DEBUG = false; + +bool ReadBoolSetting(const std::string& key, bool def) +{ + bool value; + if (kodi::addon::CheckSettingBoolean(key, value)) + return value; + + return def; +} + +} // unnamed namespace + +AddonSettings::AddonSettings() : m_bTraceDebug(DEFAULT_TRACE_DEBUG) +{ + ReadSettings(); +} + +void AddonSettings::ReadSettings() +{ + SetTraceDebug(ReadBoolSetting("trace_debug", DEFAULT_TRACE_DEBUG)); +} + +ADDON_STATUS AddonSettings::SetSetting(const std::string& key, + const kodi::addon::CSettingValue& value) +{ + if (key == "trace_debug") + { + SetTraceDebug(value.GetBoolean()); + return ADDON_STATUS_OK; + } + else if (SettingsMigration::IsMigrationSetting(key)) + { + // ignore settings from pre-multi-instance setup + return ADDON_STATUS_OK; + } + + Logger::Log(LogLevel::LEVEL_ERROR, "AddonSettings::SetSetting - unknown setting '%s'", + key.c_str()); + return ADDON_STATUS_UNKNOWN; +} diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AddonSettings.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AddonSettings.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AddonSettings.h 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AddonSettings.h 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * 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 "kodi/AddonBase.h" + +#include + +namespace tvheadend +{ +/** + * 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& key, const kodi::addon::CSettingValue& value); + + /** + * Getters for the settings values + */ + bool GetTraceDebug() const { return m_bTraceDebug; } + +private: + AddonSettings(const AddonSettings&) = delete; + void operator=(const AddonSettings&) = delete; + + /** + * Read all settings defined in settings.xml + */ + void ReadSettings(); + + /** + * Setters + */ + void SetTraceDebug(bool value) { m_bTraceDebug = value; } + + bool m_bTraceDebug{false}; +}; + +} // namespace tvheadend diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AutoRecordings.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AutoRecordings.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AutoRecordings.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AutoRecordings.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -8,7 +8,7 @@ #include "AutoRecordings.h" #include "HTSPConnection.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "entity/Recording.h" #include "utilities/LifetimeMapper.h" #include "utilities/Logger.h" @@ -22,7 +22,9 @@ using namespace tvheadend::entity; using namespace tvheadend::utilities; -AutoRecordings::AutoRecordings(HTSPConnection& conn) : m_conn(conn) +AutoRecordings::AutoRecordings(const std::shared_ptr& settings, + HTSPConnection& conn) + : m_settings(settings), m_conn(conn) { } @@ -90,12 +92,7 @@ tmr.SetLifetime(rec.second.GetLifetime()); tmr.SetMaxRecordings(0); // not supported by tvh tmr.SetRecordingGroup(0); // not supported by tvh - - if (m_conn.GetProtocol() >= 20) - tmr.SetPreventDuplicateEpisodes(rec.second.GetDupDetect()); - else - tmr.SetPreventDuplicateEpisodes(0); // not supported by tvh - + tmr.SetPreventDuplicateEpisodes(rec.second.GetDupDetect()); tmr.SetFirstDay(0); // not supported by tvh tmr.SetWeekdays(rec.second.GetDaysOfWeek()); tmr.SetEPGUid(PVR_TIMER_NO_EPG_UID); // n/a for repeating timers @@ -141,16 +138,7 @@ PVR_ERROR AutoRecordings::SendAutorecUpdate(const kodi::addon::PVRTimer& timer) { - if (m_conn.GetProtocol() >= 25) - return SendAutorecAddOrUpdate(timer, true); - - /* Note: there is no "updateAutorec" htsp method for htsp version < 25, thus delete + add. */ - PVR_ERROR error = SendAutorecDelete(timer); - - if (error == PVR_ERROR_NO_ERROR) - error = SendAutorecAdd(timer); - - return error; + return SendAutorecAddOrUpdate(timer, true); } PVR_ERROR AutoRecordings::SendAutorecAddOrUpdate(const kodi::addon::PVRTimer& timer, bool update) @@ -176,7 +164,7 @@ /* epg search data match string */ std::string searchString = timer.GetEPGSearchString(); - if (!Settings::GetInstance().GetAutorecUseRegEx()) + if (!m_settings->GetAutorecUseRegEx()) { // escape regex special chars static const std::regex specialChars(R"([-[\]{}()*+?.,\^$|#])"); @@ -188,34 +176,14 @@ /* "title" not empty && !fulltext => match strEpgSearchString against episode title only */ /* "title" not empty && fulltext => match strEpgSearchString against episode title, episode */ /* subtitle, episode summary and episode description (HTSPv19) */ - if (m_conn.GetProtocol() >= 20) - htsmsg_add_u32(m, "fulltext", timer.GetFullTextEpgSearch() ? 1 : 0); + htsmsg_add_u32(m, "fulltext", timer.GetFullTextEpgSearch() ? 1 : 0); htsmsg_add_s64(m, "startExtra", timer.GetMarginStart()); htsmsg_add_s64(m, "stopExtra", timer.GetMarginEnd()); - - if (m_conn.GetProtocol() >= 25) - { - htsmsg_add_u32(m, "removal", timer.GetLifetime()); // remove from disk - htsmsg_add_s64(m, "channelId", - timer.GetClientChannelUid()); // channelId is signed for >= htspv25, -1 = any - } - else - { - htsmsg_add_u32(m, "retention", - LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from tvh database - - if (timer.GetClientChannelUid() >= 0) - htsmsg_add_u32( - m, "channelId", - timer.GetClientChannelUid()); // channelId is unsigned for < htspv25, not sending = any - } - + htsmsg_add_u32(m, "removal", timer.GetLifetime()); // remove from disk + htsmsg_add_s64(m, "channelId", timer.GetClientChannelUid()); // -1 = any htsmsg_add_u32(m, "daysOfWeek", timer.GetWeekdays()); - - if (m_conn.GetProtocol() >= 20) - htsmsg_add_u32(m, "dupDetect", timer.GetPreventDuplicateEpisodes()); - + htsmsg_add_u32(m, "dupDetect", timer.GetPreventDuplicateEpisodes()); htsmsg_add_u32(m, "priority", timer.GetPriority()); htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); @@ -231,9 +199,7 @@ /* */ /* bAutorecApproxTime disabled: => start time in kodi = begin of starting window in tvh */ /* => end time in kodi = end of starting window in tvh */ - const Settings& settings = Settings::GetInstance(); - - if (settings.GetAutorecApproxTime()) + if (m_settings->GetAutorecApproxTime()) { /* Not sending causes server to set start and startWindow to any time */ if (timer.GetStartTime() > 0 && !timer.GetStartAnyTime()) @@ -241,9 +207,9 @@ time_t startTime = timer.GetStartTime(); struct tm* tm_start = std::localtime(&startTime); int32_t startWindowBegin = - tm_start->tm_hour * 60 + tm_start->tm_min - settings.GetAutorecMaxDiff(); + tm_start->tm_hour * 60 + tm_start->tm_min - m_settings->GetAutorecMaxDiff(); int32_t startWindowEnd = - tm_start->tm_hour * 60 + tm_start->tm_min + settings.GetAutorecMaxDiff(); + tm_start->tm_hour * 60 + tm_start->tm_min + m_settings->GetAutorecMaxDiff(); /* Past midnight correction */ if (startWindowBegin < 0) @@ -354,6 +320,7 @@ /* Locate/create entry */ AutoRecording& rec = m_autoRecordings[std::string(str)]; + rec.SetSettings(m_settings); rec.SetStringId(std::string(str)); rec.SetDirty(false); @@ -370,29 +337,14 @@ return false; } - if (m_conn.GetProtocol() >= 25) + if (!htsmsg_get_u32(msg, "removal", &u32)) { - if (!htsmsg_get_u32(msg, "removal", &u32)) - { - rec.SetLifetime(u32); - } - else if (bAdd) - { - Logger::Log(LogLevel::LEVEL_ERROR, "malformed autorecEntryAdd: 'removal' missing"); - return false; - } + rec.SetLifetime(u32); } - else + else if (bAdd) { - if (!htsmsg_get_u32(msg, "retention", &u32)) - { - rec.SetLifetime(u32); - } - else if (bAdd) - { - Logger::Log(LogLevel::LEVEL_ERROR, "malformed autorecEntryAdd: 'retention' missing"); - return false; - } + Logger::Log(LogLevel::LEVEL_ERROR, "malformed autorecEntryAdd: 'removal' missing"); + return false; } if (!htsmsg_get_u32(msg, "daysOfWeek", &u32)) @@ -461,7 +413,7 @@ { rec.SetDupDetect(u32); } - else if (bAdd && (m_conn.GetProtocol() >= 20)) + else if (bAdd) { Logger::Log(LogLevel::LEVEL_ERROR, "malformed autorecEntryAdd: 'dupDetect' missing"); return false; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AutoRecordings.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AutoRecordings.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/AutoRecordings.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/AutoRecordings.h 2022-10-07 16:22:25.000000000 +0000 @@ -7,6 +7,7 @@ #pragma once +#include #include extern "C" @@ -24,11 +25,12 @@ { class HTSPConnection; +class InstanceSettings; class AutoRecordings { public: - AutoRecordings(HTSPConnection& conn); + AutoRecordings(const std::shared_ptr& settings, HTSPConnection& conn); ~AutoRecordings(); /* state updates */ @@ -55,6 +57,7 @@ HTSPConnection& m_conn; tvheadend::entity::AutoRecordingsMap m_autoRecordings; + std::shared_ptr m_settings; }; } // namespace tvheadend diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/entity/AutoRecording.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/entity/AutoRecording.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/entity/AutoRecording.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/entity/AutoRecording.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -7,7 +7,7 @@ #include "AutoRecording.h" -#include "../Settings.h" +#include "../InstanceSettings.h" using namespace tvheadend; using namespace tvheadend::entity; @@ -38,7 +38,7 @@ time_t AutoRecording::GetStart() const { - if (Settings::GetInstance().GetAutorecApproxTime()) + if (m_settings->GetAutorecApproxTime()) { /* Calculate the approximate start time from the starting window */ if ((m_startWindowBegin == -1) || @@ -76,7 +76,7 @@ time_t AutoRecording::GetStop() const { - if (Settings::GetInstance().GetAutorecApproxTime()) + if (m_settings->GetAutorecApproxTime()) { /* Tvh doesn't have an approximate stop time => "any time" */ return 0; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/entity/AutoRecording.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/entity/AutoRecording.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/entity/AutoRecording.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/entity/AutoRecording.h 2022-10-07 16:22:25.000000000 +0000 @@ -10,9 +10,12 @@ #include "RecordingBase.h" #include +#include namespace tvheadend { +class InstanceSettings; + namespace entity { @@ -24,6 +27,8 @@ bool operator==(const AutoRecording& right); bool operator!=(const AutoRecording& right); + void SetSettings(const std::shared_ptr& settings) { m_settings = settings; } + time_t GetStart() const; void SetStartWindowBegin(int32_t begin); @@ -46,6 +51,8 @@ void SetSeriesLink(const std::string& seriesLink); private: + std::shared_ptr m_settings; + int32_t m_startWindowBegin; // Begin of the starting window (minutes from midnight). int32_t m_startWindowEnd; // End of the starting window (minutes from midnight). int64_t m_startExtra; // Extra start minutes (pre-time). diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPConnection.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPConnection.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPConnection.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPConnection.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -14,7 +14,7 @@ } #include "IHTSPConnectionListener.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "utilities/Logger.h" #include "utilities/TCPSocket.h" @@ -32,9 +32,9 @@ #define FAST_RECONNECT_INTERVAL (500) // ms #define SLOW_RECONNECT_INTERVAL (5000) // ms -#define HTSP_MIN_SERVER_VERSION (19) // Server must support at least this htsp version +#define HTSP_MIN_SERVER_VERSION (26) // Server must support at least this htsp version #define HTSP_CLIENT_VERSION \ - (34) // Client uses HTSP features up to this version. If the respective \ + (35) // Client uses HTSP features up to this version. If the respective \ // addon feature requires htsp features introduced after \ // HTSP_MIN_SERVER_VERSION this feature will only be available if the \ // actual server HTSP version matches (runtime htsp version check). @@ -86,8 +86,10 @@ * HTSP Connection handler */ -HTSPConnection::HTSPConnection(IHTSPConnectionListener& connListener) - : m_connListener(connListener), +HTSPConnection::HTSPConnection(const std::shared_ptr& settings, + IHTSPConnectionListener& connListener) + : m_settings(settings), + m_connListener(connListener), m_regThread(new HTSPRegister(this)), m_ready(false), m_seq(0), @@ -155,20 +157,18 @@ std::string HTSPConnection::GetWebURL(const char* fmt, ...) const { - const Settings& settings = Settings::GetInstance(); - // Generate the authentication string (user:pass@) - std::string auth = settings.GetUsername(); - if (!(auth.empty() || settings.GetPassword().empty())) - auth += ":" + settings.GetPassword(); + std::string auth = m_settings->GetUsername(); + if (!(auth.empty() || m_settings->GetPassword().empty())) + auth += ":" + m_settings->GetPassword(); if (!auth.empty()) auth += "@"; - const char* proto = settings.GetUseHTTPS() ? "https" : "http"; - bool isIPv6 = IsIPv6NumericHost(settings.GetHostname()); + const char* proto = m_settings->GetUseHTTPS() ? "https" : "http"; + bool isIPv6 = IsIPv6NumericHost(m_settings->GetHostname()); std::string url = kodi::tools::StringUtils::Format( - "%s://%s%s%s%s:%d", proto, auth.c_str(), isIPv6 ? "[" : "", settings.GetHostname().c_str(), - isIPv6 ? "]" : "", settings.GetPortHTTP()); + "%s://%s%s%s%s:%d", proto, auth.c_str(), isIPv6 ? "[" : "", m_settings->GetHostname().c_str(), + isIPv6 ? "]" : "", m_settings->GetPortHTTP()); va_list va; @@ -186,7 +186,7 @@ if (!m_ready) { Logger::Log(LogLevel::LEVEL_TRACE, "waiting for registration..."); - m_regCond.wait_for(lock, std::chrono::milliseconds(Settings::GetInstance().GetConnectTimeout()), + m_regCond.wait_for(lock, std::chrono::milliseconds(m_settings->GetConnectTimeout()), [this] { return m_ready == true; }); } return m_ready; @@ -212,11 +212,9 @@ std::string HTSPConnection::GetServerString() const { - const Settings& settings = Settings::GetInstance(); - std::lock_guard lock(m_mutex); - return kodi::tools::StringUtils::Format("%s:%d", settings.GetHostname().c_str(), - settings.GetPortHTSP()); + return kodi::tools::StringUtils::Format("%s:%d", m_settings->GetHostname().c_str(), + m_settings->GetPortHTSP()); } bool HTSPConnection::HasCapability(const std::string& capability) const @@ -313,7 +311,7 @@ size_t cnt = 0; while (cnt < len) { - int64_t r = m_socket->Read(buf + cnt, len - cnt, Settings::GetInstance().GetResponseTimeout()); + int64_t r = m_socket->Read(buf + cnt, len - cnt, m_settings->GetResponseTimeout()); if (r < 0) { Logger::Log(LogLevel::LEVEL_ERROR, "failed to read packet from socket"); @@ -414,7 +412,7 @@ int iResponseTimeout) { if (iResponseTimeout == -1) - iResponseTimeout = Settings::GetInstance().GetResponseTimeout(); + iResponseTimeout = m_settings->GetResponseTimeout(); /* Add Sequence number */ uint32_t seq = ++m_seq; @@ -475,7 +473,7 @@ int iResponseTimeout) { if (iResponseTimeout == -1) - iResponseTimeout = Settings::GetInstance().GetResponseTimeout(); + iResponseTimeout = m_settings->GetResponseTimeout(); if (!WaitForConnection(lock)) return nullptr; @@ -591,8 +589,8 @@ */ void HTSPConnection::Register() { - std::string user = Settings::GetInstance().GetUsername(); - std::string pass = Settings::GetInstance().GetPassword(); + std::string user = m_settings->GetUsername(); + std::string pass = m_settings->GetPassword(); { std::unique_lock lock(m_mutex); @@ -654,15 +652,14 @@ { static bool log = false; static unsigned int retryAttempt = 0; - const Settings& settings = Settings::GetInstance(); while (!ShouldStopProcessing()) { Logger::Log(LogLevel::LEVEL_DEBUG, "new connection requested"); - std::string host = settings.GetHostname(); - int port = settings.GetPortHTSP(); - int timeout = settings.GetConnectTimeout(); + std::string host = m_settings->GetHostname(); + int port = m_settings->GetPortHTSP(); + int timeout = m_settings->GetConnectTimeout(); /* Create socket (ensure mutex protection) */ { @@ -701,7 +698,7 @@ } /* wakeup server */ - std::string wol_mac = settings.GetWolMac(); + std::string wol_mac = m_settings->GetWolMac(); if (!wol_mac.empty()) { Logger::Log(LogLevel::LEVEL_TRACE, "send wol packet..."); diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPConnection.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPConnection.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPConnection.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPConnection.h 2022-10-07 16:22:25.000000000 +0000 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ class HTSPRegister; class HTSPResponse; class IHTSPConnectionListener; +class InstanceSettings; namespace utilities { @@ -42,7 +44,8 @@ class HTSPConnection : public kodi::tools::CThread { public: - HTSPConnection(IHTSPConnectionListener& connListener); + HTSPConnection(const std::shared_ptr& settings, + IHTSPConnectionListener& connListener); ~HTSPConnection() override; void Start(); @@ -107,6 +110,7 @@ HTSPConnection* m_conn; }; + std::shared_ptr m_settings; IHTSPConnectionListener& m_connListener; tvheadend::utilities::TCPSocket* m_socket = nullptr; mutable std::recursive_mutex m_mutex; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPDemuxer.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPDemuxer.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPDemuxer.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPDemuxer.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -9,7 +9,7 @@ #include "HTSPDemuxer.h" #include "HTSPConnection.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "utilities/Logger.h" #include "utilities/RDSExtractor.h" @@ -34,8 +34,11 @@ using namespace tvheadend; using namespace tvheadend::utilities; -HTSPDemuxer::HTSPDemuxer(IHTSPDemuxPacketHandler& demuxPktHdl, HTSPConnection& conn) - : m_conn(conn), +HTSPDemuxer::HTSPDemuxer(const std::shared_ptr& settings, + IHTSPDemuxPacketHandler& demuxPktHdl, + HTSPConnection& conn) + : m_settings(settings), + m_conn(conn), m_pktBuffer(static_cast(-1)), m_seektime(nullptr), m_subscription(conn), @@ -233,7 +236,7 @@ return false; /* Wait for time */ - int64_t seekedTo = (*m_seektime).Get(lock, Settings::GetInstance().GetResponseTimeout()); + int64_t seekedTo = (*m_seektime).Get(lock, m_settings->GetResponseTimeout()); m_seektime = nullptr; if (seekedTo == INVALID_SEEKTIME) diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPDemuxer.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPDemuxer.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPDemuxer.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPDemuxer.h 2022-10-07 16:22:25.000000000 +0000 @@ -35,6 +35,7 @@ { class HTSPConnection; +class InstanceSettings; class SubscriptionSeekTime; namespace utilities @@ -48,7 +49,9 @@ class HTSPDemuxer { public: - HTSPDemuxer(IHTSPDemuxPacketHandler& demuxPktHdl, HTSPConnection& conn); + HTSPDemuxer(const std::shared_ptr& settings, + IHTSPDemuxPacketHandler& demuxPktHdl, + HTSPConnection& conn); ~HTSPDemuxer(); bool ProcessMessage(const std::string& method, htsmsg_t* m); @@ -112,6 +115,7 @@ void ProcessRDS(uint32_t idx, const void* bin, size_t binlen); mutable std::recursive_mutex m_mutex; + std::shared_ptr m_settings; HTSPConnection& m_conn; tvheadend::utilities::SyncedBuffer m_pktBuffer; std::vector m_streams; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPVFS.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPVFS.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPVFS.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPVFS.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -12,7 +12,8 @@ #include "libhts/htsmsg_binary.h" } #include "HTSPConnection.h" -#include "Settings.h" +#include "HTSPTypes.h" +#include "InstanceSettings.h" #include "utilities/Logger.h" #include "kodi/addon-instance/pvr/Recordings.h" @@ -29,8 +30,9 @@ /* * VFS handler */ -HTSPVFS::HTSPVFS(HTSPConnection& conn) - : m_conn(conn), +HTSPVFS::HTSPVFS(const std::shared_ptr& settings, HTSPConnection& conn) + : m_settings(settings), + m_conn(conn), m_path(""), m_fileId(0), m_offset(0), @@ -264,8 +266,8 @@ /* If setting set, we will increase play count with CTvheadend::SetPlayCount */ if (m_conn.GetProtocol() >= 27) htsmsg_add_u32(m, "playcount", - Settings::GetInstance().GetDvrPlayStatus() ? HTSP_DVR_PLAYCOUNT_KEEP - : HTSP_DVR_PLAYCOUNT_INCR); + m_settings->GetDvrPlayStatus() ? HTSP_DVR_PLAYCOUNT_KEEP + : HTSP_DVR_PLAYCOUNT_INCR); Logger::Log(LogLevel::LEVEL_DEBUG, "vfs close id=%d", m_fileId); diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPVFS.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPVFS.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/HTSPVFS.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/HTSPVFS.h 2022-10-07 16:22:25.000000000 +0000 @@ -7,6 +7,7 @@ #pragma once +#include #include namespace kodi @@ -21,6 +22,7 @@ { class HTSPConnection; +class InstanceSettings; /* * HTSP VFS - recordings @@ -28,7 +30,7 @@ class HTSPVFS { public: - HTSPVFS(HTSPConnection& conn); + HTSPVFS(const std::shared_ptr& settings, HTSPConnection& conn); ~HTSPVFS(); void RebuildState(); @@ -47,6 +49,7 @@ int64_t SendFileRead(unsigned char* buf, unsigned int len); long long SendFileSeek(int64_t pos, int whence, bool force = false); + std::shared_ptr m_settings; HTSPConnection& m_conn; std::string m_path; uint32_t m_fileId; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/InstanceSettings.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/InstanceSettings.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/InstanceSettings.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/InstanceSettings.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,314 @@ +/* + * 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" + +#include "HTSPTypes.h" +#include "utilities/Logger.h" + +#include "kodi/General.h" + +using namespace tvheadend; +using namespace tvheadend::utilities; + +namespace +{ +const std::string DEFAULT_HOST = "127.0.0.1"; +const bool DEFAULT_USE_HTTPS = false; +const int DEFAULT_HTTP_PORT = 9981; +const int DEFAULT_HTSP_PORT = 9982; +const std::string DEFAULT_USERNAME = ""; +const std::string DEFAULT_PASSWORD = ""; +const std::string DEFAULT_WOL_MAC = ""; +const int DEFAULT_CONNECT_TIMEOUT = 10000; // millisecs +const int DEFAULT_RESPONSE_TIMEOUT = 5000; // millisecs +const bool DEFAULT_ASYNC_EPG = true; +const bool DEFAULT_PRETUNER_ENABLED = false; +const int DEFAULT_TOTAL_TUNERS = 1; // total tuners > 1 => predictive tuning active +const int DEFAULT_PRETUNER_CLOSEDELAY = 10; // secs +const int DEFAULT_AUTOREC_MAXDIFF = + 15; // mins. Maximum difference between real and approximate start time for auto recordings +const bool DEFAULT_AUTOREC_USE_REGEX = false; +const int DEFAULT_APPROX_TIME = + 0; // don't use an approximate start time, use a fixed time instead for auto recordings +const std::string DEFAULT_STREAMING_PROFILE = ""; +const bool DEFAULT_STREAMING_HTTP = false; +const int DEFAULT_DVR_PRIO = DVR_PRIO_NORMAL; +const int DEFAULT_DVR_LIFETIME = 15; // use backend setting +const int DEFAULT_DVR_DUPDETECT = DVR_AUTOREC_RECORD_ALL; +const bool DEFAULT_DVR_PLAYSTATUS = true; +const int DEFAULT_STREAM_CHUNKSIZE = 64; // KB +const bool DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES = true; +} // namespace + +InstanceSettings::InstanceSettings(kodi::addon::IAddonInstance& instance) + : m_instance(instance), + m_strHostname(DEFAULT_HOST), + m_iPortHTSP(DEFAULT_HTTP_PORT), + m_iPortHTTP(DEFAULT_HTSP_PORT), + m_bUseHTTPS(DEFAULT_USE_HTTPS), + m_strUsername(DEFAULT_USERNAME), + m_strPassword(DEFAULT_PASSWORD), + m_strWolMac(DEFAULT_WOL_MAC), + m_iConnectTimeout(DEFAULT_CONNECT_TIMEOUT), + m_iResponseTimeout(DEFAULT_RESPONSE_TIMEOUT), + m_bAsyncEpg(DEFAULT_ASYNC_EPG), + m_bPretunerEnabled(DEFAULT_PRETUNER_ENABLED), + m_iTotalTuners(DEFAULT_TOTAL_TUNERS), + m_iPreTunerCloseDelay(DEFAULT_PRETUNER_CLOSEDELAY), + m_iAutorecApproxTime(DEFAULT_APPROX_TIME), + m_iAutorecMaxDiff(DEFAULT_AUTOREC_MAXDIFF), + m_bAutorecUseRegEx(DEFAULT_AUTOREC_USE_REGEX), + m_strStreamingProfile(DEFAULT_STREAMING_PROFILE), + m_bUseHTTPStreaming(DEFAULT_STREAMING_HTTP), + m_iDvrPriority(DEFAULT_DVR_PRIO), + m_iDvrLifetime(DEFAULT_DVR_LIFETIME), + m_iDvrDupdetect(DEFAULT_DVR_DUPDETECT), + m_bDvrPlayStatus(DEFAULT_DVR_PLAYSTATUS), + m_iStreamReadChunkSizeKB(DEFAULT_STREAM_CHUNKSIZE), + m_bIgnoreDuplicateSchedules(DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES) +{ + ReadSettings(); +} + +void InstanceSettings::ReadSettings() +{ + /* Connection */ + SetHostname(ReadStringSetting("host", DEFAULT_HOST)); + SetPortHTSP(ReadIntSetting("htsp_port", DEFAULT_HTSP_PORT)); + SetPortHTTP(ReadIntSetting("http_port", DEFAULT_HTTP_PORT)); + SetUseHTTPS(ReadBoolSetting("https", DEFAULT_USE_HTTPS)); + SetUsername(ReadStringSetting("user", DEFAULT_USERNAME)); + SetPassword(ReadStringSetting("pass", DEFAULT_PASSWORD)); + SetWolMac(ReadStringSetting("wol_mac", DEFAULT_WOL_MAC)); + + /* Note: Timeouts in settings UI are defined in seconds but we expect them to be in milliseconds. */ + SetConnectTimeout(ReadIntSetting("connect_timeout", DEFAULT_CONNECT_TIMEOUT / 1000) * 1000); + SetResponseTimeout(ReadIntSetting("response_timeout", DEFAULT_RESPONSE_TIMEOUT / 1000) * 1000); + + /* Data Transfer */ + SetAsyncEpg(ReadBoolSetting("epg_async", DEFAULT_ASYNC_EPG)); + + /* Predictive Tuning */ + m_bPretunerEnabled = ReadBoolSetting("pretuner_enabled", DEFAULT_PRETUNER_ENABLED); + SetTotalTuners(m_bPretunerEnabled ? ReadIntSetting("total_tuners", DEFAULT_TOTAL_TUNERS) : 1); + SetPreTunerCloseDelay( + m_bPretunerEnabled ? ReadIntSetting("pretuner_closedelay", DEFAULT_PRETUNER_CLOSEDELAY) : 0); + + /* Auto recordings */ + SetAutorecApproxTime(ReadIntSetting("autorec_approxtime", DEFAULT_APPROX_TIME)); + SetAutorecMaxDiff(ReadIntSetting("autorec_maxdiff", DEFAULT_AUTOREC_MAXDIFF)); + SetAutorecUseRegEx(ReadBoolSetting("autorec_use_regex", DEFAULT_AUTOREC_USE_REGEX)); + + /* Streaming */ + SetStreamingProfile(ReadStringSetting("streaming_profile", DEFAULT_STREAMING_PROFILE)); + SetStreamingHTTP(ReadBoolSetting("streaming_http", DEFAULT_STREAMING_HTTP)); + + /* Default dvr settings */ + SetDvrPriority(ReadIntSetting("dvr_priority", DEFAULT_DVR_PRIO)); + SetDvrLifetime(ReadIntSetting("dvr_lifetime2", DEFAULT_DVR_LIFETIME)); + SetDvrDupdetect(ReadIntSetting("dvr_dubdetect", DEFAULT_DVR_DUPDETECT)); + + /* Sever based play status */ + SetDvrPlayStatus(ReadBoolSetting("dvr_playstatus", DEFAULT_DVR_PLAYSTATUS)); + + /* Stream read chunk size */ + SetStreamReadChunkSizeKB(ReadIntSetting("stream_readchunksize", DEFAULT_STREAM_CHUNKSIZE)); + + /* Scheduled recordings */ + SetIgnoreDuplicateSchedules( + ReadBoolSetting("dvr_ignore_duplicates", DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES)); +} + +ADDON_STATUS InstanceSettings::SetSetting(const std::string& key, + const kodi::addon::CSettingValue& value) +{ + /* Connection */ + if (key == "host") + return SetStringSetting(GetHostname(), value); + else if (key == "htsp_port") + return SetIntSetting(GetPortHTSP(), value); + else if (key == "http_port") + return SetIntSetting(GetPortHTTP(), value); + else if (key == "https") + return SetBoolSetting(GetUseHTTPS(), value); + else if (key == "user") + return SetStringSetting(GetUsername(), value); + else if (key == "pass") + return SetStringSetting(GetPassword(), value); + else if (key == "wol_mac") + return SetStringSetting(GetWolMac(), value); + else if (key == "connect_timeout") + { + SetConnectTimeout(value.GetInt() * 1000); + return ADDON_STATUS_OK; + } + else if (key == "response_timeout") + { + SetResponseTimeout(value.GetInt() * 1000); + return ADDON_STATUS_OK; + } + /* Data Transfer */ + else if (key == "epg_async") + return SetBoolSetting(GetAsyncEpg(), value); + /* Predictive Tuning */ + else if (key == "pretuner_enabled") + return SetBoolSetting(m_bPretunerEnabled, value); + else if (key == "total_tuners") + { + if (!m_bPretunerEnabled) + return ADDON_STATUS_OK; + else + return SetIntSetting(GetTotalTuners(), value); + } + else if (key == "pretuner_closedelay") + { + SetPreTunerCloseDelay(value.GetInt()); + return ADDON_STATUS_OK; + } + /* Auto recordings */ + else if (key == "autorec_approxtime") + return SetIntSetting(GetAutorecApproxTime(), value); + else if (key == "autorec_maxdiff") + { + SetAutorecMaxDiff(value.GetInt()); + return ADDON_STATUS_OK; + } + else if (key == "autorec_use_regex") + { + SetAutorecUseRegEx(value.GetBoolean()); + return ADDON_STATUS_OK; + } + /* Streaming */ + else if (key == "streaming_profile") + return SetStringSetting(GetStreamingProfile(), value); + else if (key == "streaming_http") + return SetBoolSetting(GetStreamingHTTP(), value); + /* Default dvr settings */ + else if (key == "dvr_priority") + return SetIntSetting(GetDvrPriority(), value); + else if (key == "dvr_lifetime2") + return SetIntSetting(GetDvrLifetime(true), value); + else if (key == "dvr_dubdetect") + return SetIntSetting(GetDvrDupdetect(), value); + /* Server based play status */ + else if (key == "dvr_playstatus") + return SetBoolSetting(GetDvrPlayStatus(), value); + else if (key == "stream_readchunksize") + return SetIntSetting(GetStreamReadChunkSize(), value); + else if (key == "dvr_ignore_duplicates") + { + SetIgnoreDuplicateSchedules(value.GetBoolean()); + return ADDON_STATUS_OK; + } + else + { + Logger::Log(LogLevel::LEVEL_ERROR, "InstanceSettings::SetSetting - unknown setting '%s'", + key.c_str()); + return ADDON_STATUS_UNKNOWN; + } +} + +std::string InstanceSettings::ReadStringSetting(const std::string& key, + const std::string& def) const +{ + std::string value; + if (m_instance.CheckInstanceSettingString(key, value)) + return value; + + return def; +} + +int InstanceSettings::ReadIntSetting(const std::string& key, int def) const +{ + int value; + if (m_instance.CheckInstanceSettingInt(key, value)) + return value; + + return def; +} + +bool InstanceSettings::ReadBoolSetting(const std::string& key, bool def) const +{ + bool value; + if (m_instance.CheckInstanceSettingBoolean(key, value)) + return value; + + return def; +} + +ADDON_STATUS InstanceSettings::SetStringSetting(const std::string& oldValue, + const kodi::addon::CSettingValue& newValue) +{ + if (oldValue == newValue.GetString()) + return ADDON_STATUS_OK; + + return ADDON_STATUS_NEED_RESTART; +} + +ADDON_STATUS InstanceSettings::SetIntSetting(int oldValue, + const kodi::addon::CSettingValue& newValue) +{ + if (oldValue == newValue.GetInt()) + return ADDON_STATUS_OK; + + return ADDON_STATUS_NEED_RESTART; +} + +ADDON_STATUS InstanceSettings::SetBoolSetting(bool oldValue, + const kodi::addon::CSettingValue& newValue) +{ + if (oldValue == newValue.GetBoolean()) + return ADDON_STATUS_OK; + + return ADDON_STATUS_NEED_RESTART; +} + +int InstanceSettings::GetDvrLifetime(bool asEnum) const +{ + if (asEnum) + return m_iDvrLifetime; + else + { + switch (m_iDvrLifetime) + { + case 0: + return DVR_RET_1DAY; + case 1: + return DVR_RET_3DAY; + case 2: + return DVR_RET_5DAY; + case 3: + return DVR_RET_1WEEK; + case 4: + return DVR_RET_2WEEK; + case 5: + return DVR_RET_3WEEK; + case 6: + return DVR_RET_1MONTH; + case 7: + return DVR_RET_2MONTH; + case 8: + return DVR_RET_3MONTH; + case 9: + return DVR_RET_6MONTH; + case 10: + return DVR_RET_1YEAR; + case 11: + return DVR_RET_2YEARS; + case 12: + return DVR_RET_3YEARS; + case 13: + return DVR_RET_SPACE; + case 14: + return DVR_RET_FOREVER; + case 15: + default: + return DVR_RET_DVRCONFIG; + } + } +} diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/InstanceSettings.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/InstanceSettings.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/InstanceSettings.h 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/InstanceSettings.h 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005-2021 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#include "kodi/AddonBase.h" + +#include + +namespace tvheadend +{ +/** + * Represents the current addon instance settings + */ +class InstanceSettings +{ +public: + explicit InstanceSettings(kodi::addon::IAddonInstance& instance); + + /** + * Set a value according to key definition in instance-settings.xml + */ + ADDON_STATUS SetSetting(const std::string& key, const kodi::addon::CSettingValue& value); + + /** + * Getters for the settings values + */ + std::string GetHostname() const { return m_strHostname; } + const char* GetConstCharHostname() const { return m_strHostname.c_str(); } + int GetPortHTSP() const { return m_iPortHTSP; } + int GetPortHTTP() const { return m_iPortHTTP; } + bool GetUseHTTPS() const { return m_bUseHTTPS; } + std::string GetUsername() const { return m_strUsername; } + std::string GetPassword() const { return m_strPassword; } + std::string GetWolMac() const { return m_strWolMac; } + int GetConnectTimeout() const { return m_iConnectTimeout; } + int GetResponseTimeout() const { return m_iResponseTimeout; } + bool GetAsyncEpg() const { return m_bAsyncEpg; } + int GetTotalTuners() const { return m_iTotalTuners; } + int GetPreTunerCloseDelay() const { return m_iPreTunerCloseDelay; } + int GetAutorecApproxTime() const { return m_iAutorecApproxTime; } + int GetAutorecMaxDiff() const { return m_iAutorecMaxDiff; } + bool GetAutorecUseRegEx() const { return m_bAutorecUseRegEx; } + std::string GetStreamingProfile() const { return m_strStreamingProfile; } + bool GetStreamingHTTP() const { return m_bUseHTTPStreaming; } + int GetDvrPriority() const { return m_iDvrPriority; } + int GetDvrDupdetect() const { return m_iDvrDupdetect; } + int GetDvrLifetime(bool asEnum = false) const; + bool GetDvrPlayStatus() const { return m_bDvrPlayStatus; } + int GetStreamReadChunkSize() const { return m_iStreamReadChunkSizeKB; } + bool GetIgnoreDuplicateSchedules() const { return m_bIgnoreDuplicateSchedules; } + +private: + InstanceSettings(const InstanceSettings&) = delete; + void operator=(const InstanceSettings&) = delete; + + /** + * Read all settings defined in instance-settings.xml + */ + void ReadSettings(); + + /** + * Setters + */ + void SetHostname(const std::string& value) { m_strHostname = value; } + void SetPortHTSP(int value) { m_iPortHTSP = value; } + void SetPortHTTP(int value) { m_iPortHTTP = value; } + void SetUseHTTPS(bool value) { m_bUseHTTPS = value; } + void SetUsername(const std::string& value) { m_strUsername = value; } + void SetPassword(const std::string& value) { m_strPassword = value; } + void SetWolMac(const std::string& value) { m_strWolMac = value; } + void SetConnectTimeout(int value) { m_iConnectTimeout = value; } + void SetResponseTimeout(int value) { m_iResponseTimeout = value; } + void SetAsyncEpg(bool value) { m_bAsyncEpg = value; } + void SetTotalTuners(int value) { m_iTotalTuners = value; } + void SetPreTunerCloseDelay(int value) { m_iPreTunerCloseDelay = value; } + void SetAutorecApproxTime(int value) { m_iAutorecApproxTime = value; } + void SetAutorecMaxDiff(int value) { m_iAutorecMaxDiff = value; } + void SetAutorecUseRegEx(bool value) { m_bAutorecUseRegEx = value; } + void SetStreamingProfile(const std::string& value) { m_strStreamingProfile = value; } + void SetStreamingHTTP(bool value) { m_bUseHTTPStreaming = value; } + void SetDvrPriority(int value) { m_iDvrPriority = value; } + void SetDvrLifetime(int value) { m_iDvrLifetime = value; } + void SetDvrDupdetect(int value) { m_iDvrDupdetect = value; } + void SetDvrPlayStatus(bool value) { m_bDvrPlayStatus = value; } + void SetStreamReadChunkSizeKB(int value) { m_iStreamReadChunkSizeKB = value; } + void SetIgnoreDuplicateSchedules(bool value) { m_bIgnoreDuplicateSchedules = value; } + + /** + * Read/Set values according to definition in settings.xml + */ + std::string ReadStringSetting(const std::string& key, const std::string& def) const; + int ReadIntSetting(const std::string& key, int def) const; + bool ReadBoolSetting(const std::string& key, bool def) const; + + // @return ADDON_STATUS_OK if value has not changed, ADDON_STATUS_NEED_RESTART otherwise + ADDON_STATUS SetStringSetting(const std::string& oldValue, + const kodi::addon::CSettingValue& newValue); + ADDON_STATUS SetIntSetting(int oldValue, const kodi::addon::CSettingValue& newValue); + ADDON_STATUS SetBoolSetting(bool oldValue, const kodi::addon::CSettingValue& newValue); + + kodi::addon::IAddonInstance& m_instance; + + std::string m_strHostname; + int m_iPortHTSP; + int m_iPortHTTP; + bool m_bUseHTTPS; + std::string m_strUsername; + std::string m_strPassword; + std::string m_strWolMac; + int m_iConnectTimeout; + int m_iResponseTimeout; + bool m_bAsyncEpg; + bool m_bPretunerEnabled; + int m_iTotalTuners; + int m_iPreTunerCloseDelay; + bool m_iAutorecApproxTime; + int m_iAutorecMaxDiff; + bool m_bAutorecUseRegEx; + std::string m_strStreamingProfile; + bool m_bUseHTTPStreaming; + int m_iDvrPriority; + int m_iDvrLifetime; + int m_iDvrDupdetect; + bool m_bDvrPlayStatus; + int m_iStreamReadChunkSizeKB; + bool m_bIgnoreDuplicateSchedules; +}; + +} // namespace tvheadend diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/Settings.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/Settings.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/Settings.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/Settings.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2005-2021 Team Kodi (https://kodi.tv) - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSE.md for more information. - */ - -#include "Settings.h" - -#include "utilities/Logger.h" - -#include "kodi/General.h" - -using namespace tvheadend; -using namespace tvheadend::utilities; - -const std::string Settings::DEFAULT_HOST = "127.0.0.1"; -const bool Settings::DEFAULT_USE_HTTPS = false; -const int Settings::DEFAULT_HTTP_PORT = 9981; -const int Settings::DEFAULT_HTSP_PORT = 9982; -const std::string Settings::DEFAULT_USERNAME = ""; -const std::string Settings::DEFAULT_PASSWORD = ""; -const std::string Settings::DEFAULT_WOL_MAC = ""; -const int Settings::DEFAULT_CONNECT_TIMEOUT = 10000; // millisecs -const int Settings::DEFAULT_RESPONSE_TIMEOUT = 5000; // millisecs -const bool Settings::DEFAULT_TRACE_DEBUG = false; -const bool Settings::DEFAULT_ASYNC_EPG = true; -const bool Settings::DEFAULT_PRETUNER_ENABLED = false; -const int Settings::DEFAULT_TOTAL_TUNERS = 1; // total tuners > 1 => predictive tuning active -const int Settings::DEFAULT_PRETUNER_CLOSEDELAY = 10; // secs -const int Settings::DEFAULT_AUTOREC_MAXDIFF = - 15; // mins. Maximum difference between real and approximate start time for auto recordings -const bool Settings::DEFAULT_AUTOREC_USE_REGEX = false; -const int Settings::DEFAULT_APPROX_TIME = - 0; // don't use an approximate start time, use a fixed time instead for auto recordings -const std::string Settings::DEFAULT_STREAMING_PROFILE = ""; -const bool Settings::DEFAULT_STREAMING_HTTP = false; -const int Settings::DEFAULT_DVR_PRIO = DVR_PRIO_NORMAL; -const int Settings::DEFAULT_DVR_LIFETIME = 15; // use backend setting -const int Settings::DEFAULT_DVR_DUPDETECT = DVR_AUTOREC_RECORD_ALL; -const bool Settings::DEFAULT_DVR_PLAYSTATUS = true; -const int Settings::DEFAULT_STREAM_CHUNKSIZE = 64; // KB -const bool Settings::DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES = true; - -void Settings::ReadSettings() -{ - /* Connection */ - SetHostname(ReadStringSetting("host", DEFAULT_HOST)); - SetPortHTSP(ReadIntSetting("htsp_port", DEFAULT_HTSP_PORT)); - SetPortHTTP(ReadIntSetting("http_port", DEFAULT_HTTP_PORT)); - SetUseHTTPS(ReadBoolSetting("https", DEFAULT_USE_HTTPS)); - SetUsername(ReadStringSetting("user", DEFAULT_USERNAME)); - SetPassword(ReadStringSetting("pass", DEFAULT_PASSWORD)); - SetWolMac(ReadStringSetting("wol_mac", DEFAULT_WOL_MAC)); - - /* Note: Timeouts in settings UI are defined in seconds but we expect them to be in milliseconds. */ - SetConnectTimeout(ReadIntSetting("connect_timeout", DEFAULT_CONNECT_TIMEOUT / 1000) * 1000); - SetResponseTimeout(ReadIntSetting("response_timeout", DEFAULT_RESPONSE_TIMEOUT / 1000) * 1000); - - /* Debug */ - SetTraceDebug(ReadBoolSetting("trace_debug", DEFAULT_TRACE_DEBUG)); - - /* Data Transfer */ - SetAsyncEpg(ReadBoolSetting("epg_async", DEFAULT_ASYNC_EPG)); - - /* Predictive Tuning */ - m_bPretunerEnabled = ReadBoolSetting("pretuner_enabled", DEFAULT_PRETUNER_ENABLED); - SetTotalTuners(m_bPretunerEnabled ? ReadIntSetting("total_tuners", DEFAULT_TOTAL_TUNERS) : 1); - SetPreTunerCloseDelay( - m_bPretunerEnabled ? ReadIntSetting("pretuner_closedelay", DEFAULT_PRETUNER_CLOSEDELAY) : 0); - - /* Auto recordings */ - SetAutorecApproxTime(ReadIntSetting("autorec_approxtime", DEFAULT_APPROX_TIME)); - SetAutorecMaxDiff(ReadIntSetting("autorec_maxdiff", DEFAULT_AUTOREC_MAXDIFF)); - SetAutorecUseRegEx(ReadBoolSetting("autorec_use_regex", DEFAULT_AUTOREC_USE_REGEX)); - - /* Streaming */ - SetStreamingProfile(ReadStringSetting("streaming_profile", DEFAULT_STREAMING_PROFILE)); - SetStreamingHTTP(ReadBoolSetting("streaming_http", DEFAULT_STREAMING_HTTP)); - - /* Default dvr settings */ - SetDvrPriority(ReadIntSetting("dvr_priority", DEFAULT_DVR_PRIO)); - SetDvrLifetime(ReadIntSetting("dvr_lifetime2", DEFAULT_DVR_LIFETIME)); - SetDvrDupdetect(ReadIntSetting("dvr_dubdetect", DEFAULT_DVR_DUPDETECT)); - - /* Sever based play status */ - SetDvrPlayStatus(ReadBoolSetting("dvr_playstatus", DEFAULT_DVR_PLAYSTATUS)); - - /* Stream read chunk size */ - SetStreamReadChunkSizeKB(ReadIntSetting("stream_readchunksize", DEFAULT_STREAM_CHUNKSIZE)); - - /* Scheduled recordings */ - SetIgnoreDuplicateSchedules( - ReadBoolSetting("dvr_ignore_duplicates", DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES)); -} - -ADDON_STATUS Settings::SetSetting(const std::string& key, const kodi::addon::CSettingValue& value) -{ - /* Connection */ - if (key == "host") - return SetStringSetting(GetHostname(), value); - else if (key == "htsp_port") - return SetIntSetting(GetPortHTSP(), value); - else if (key == "http_port") - return SetIntSetting(GetPortHTTP(), value); - else if (key == "https") - return SetBoolSetting(GetUseHTTPS(), value); - else if (key == "user") - return SetStringSetting(GetUsername(), value); - else if (key == "pass") - return SetStringSetting(GetPassword(), value); - else if (key == "wol_mac") - return SetStringSetting(GetWolMac(), value); - else if (key == "connect_timeout") - { - if (GetConnectTimeout() == value.GetInt() * 1000) - return ADDON_STATUS_OK; - else - return ADDON_STATUS_NEED_RESTART; - } - else if (key == "response_timeout") - { - if (GetResponseTimeout() == value.GetInt() * 1000) - return ADDON_STATUS_OK; - else - return ADDON_STATUS_NEED_RESTART; - } - /* Debug */ - else if (key == "trace_debug") - return SetBoolSetting(GetTraceDebug(), value); - /* Data Transfer */ - else if (key == "epg_async") - return SetBoolSetting(GetAsyncEpg(), value); - /* Predictive Tuning */ - else if (key == "pretuner_enabled") - return SetBoolSetting(m_bPretunerEnabled, value); - else if (key == "total_tuners") - { - if (!m_bPretunerEnabled) - return ADDON_STATUS_OK; - else - return SetIntSetting(GetTotalTuners(), value); - } - else if (key == "pretuner_closedelay") - { - if (!m_bPretunerEnabled) - return ADDON_STATUS_OK; - else - return SetIntSetting(GetPreTunerCloseDelay(), value); - } - /* Auto recordings */ - else if (key == "autorec_approxtime") - return SetIntSetting(GetAutorecApproxTime(), value); - else if (key == "autorec_maxdiff") - return SetIntSetting(GetAutorecMaxDiff(), value); - else if (key == "autorec_use_regex") - return SetBoolSetting(GetAutorecUseRegEx(), value); - /* Streaming */ - else if (key == "streaming_profile") - return SetStringSetting(GetStreamingProfile(), value); - else if (key == "streaming_http") - return SetBoolSetting(GetStreamingHTTP(), value); - /* Default dvr settings */ - else if (key == "dvr_priority") - return SetIntSetting(GetDvrPriority(), value); - else if (key == "dvr_lifetime2") - return SetIntSetting(GetDvrLifetime(true), value); - else if (key == "dvr_dubdetect") - return SetIntSetting(GetDvrDupdetect(), value); - /* Server based play status */ - else if (key == "dvr_playstatus") - return SetBoolSetting(GetDvrPlayStatus(), value); - else if (key == "stream_readchunksize") - return SetIntSetting(GetStreamReadChunkSize(), value); - else if (key == "dvr_ignore_duplicates") - return SetBoolSetting(GetIgnoreDuplicateSchedules(), value); - else - { - Logger::Log(LogLevel::LEVEL_ERROR, "Settings::SetSetting - unknown setting '%s'", key.c_str()); - return ADDON_STATUS_UNKNOWN; - } -} - -std::string Settings::ReadStringSetting(const std::string& key, const std::string& def) -{ - std::string value; - if (kodi::addon::CheckSettingString(key, value)) - return value; - - return def; -} - -int Settings::ReadIntSetting(const std::string& key, int def) -{ - int value; - if (kodi::addon::CheckSettingInt(key, value)) - return value; - - return def; -} - -bool Settings::ReadBoolSetting(const std::string& key, bool def) -{ - bool value; - if (kodi::addon::CheckSettingBoolean(key, value)) - return value; - - return def; -} - -ADDON_STATUS Settings::SetStringSetting(const std::string& oldValue, - const kodi::addon::CSettingValue& newValue) -{ - if (oldValue == newValue.GetString()) - return ADDON_STATUS_OK; - - return ADDON_STATUS_NEED_RESTART; -} - -ADDON_STATUS Settings::SetIntSetting(int oldValue, const kodi::addon::CSettingValue& newValue) -{ - if (oldValue == newValue.GetInt()) - return ADDON_STATUS_OK; - - return ADDON_STATUS_NEED_RESTART; -} - -ADDON_STATUS Settings::SetBoolSetting(bool oldValue, const kodi::addon::CSettingValue& newValue) -{ - if (oldValue == newValue.GetBoolean()) - return ADDON_STATUS_OK; - - return ADDON_STATUS_NEED_RESTART; -} - -int Settings::GetDvrLifetime(bool asEnum) const -{ - if (asEnum) - return m_iDvrLifetime; - else - { - switch (m_iDvrLifetime) - { - case 0: - return DVR_RET_1DAY; - case 1: - return DVR_RET_3DAY; - case 2: - return DVR_RET_5DAY; - case 3: - return DVR_RET_1WEEK; - case 4: - return DVR_RET_2WEEK; - case 5: - return DVR_RET_3WEEK; - case 6: - return DVR_RET_1MONTH; - case 7: - return DVR_RET_2MONTH; - case 8: - return DVR_RET_3MONTH; - case 9: - return DVR_RET_6MONTH; - case 10: - return DVR_RET_1YEAR; - case 11: - return DVR_RET_2YEARS; - case 12: - return DVR_RET_3YEARS; - case 13: - return DVR_RET_SPACE; - case 14: - return DVR_RET_FOREVER; - case 15: - default: - return DVR_RET_DVRCONFIG; - } - } -} diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/Settings.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/Settings.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/Settings.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/Settings.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2005-2021 Team Kodi (https://kodi.tv) - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSE.md for more information. - */ - -#pragma once - -#include "HTSPTypes.h" - -#include "kodi/AddonBase.h" - -#include - -namespace tvheadend -{ - -/** - * Represents the current addon settings - */ -class Settings -{ -public: - // Default values. - static const std::string DEFAULT_HOST; - static const int DEFAULT_HTTP_PORT; - static const int DEFAULT_HTSP_PORT; - static const bool DEFAULT_USE_HTTPS; - static const std::string DEFAULT_USERNAME; - static const std::string DEFAULT_PASSWORD; - static const std::string DEFAULT_WOL_MAC; - static const int DEFAULT_CONNECT_TIMEOUT; // millisecs - static const int DEFAULT_RESPONSE_TIMEOUT; // millisecs - static const bool DEFAULT_TRACE_DEBUG; - static const bool DEFAULT_ASYNC_EPG; - static const bool DEFAULT_PRETUNER_ENABLED; - static const int DEFAULT_TOTAL_TUNERS; - static const int DEFAULT_PRETUNER_CLOSEDELAY; // secs - static const int - DEFAULT_AUTOREC_MAXDIFF; // mins. Maximum difference between real and approximate start time for auto recordings - static const bool DEFAULT_AUTOREC_USE_REGEX; - static const int - DEFAULT_APPROX_TIME; // 0..1 (0 = use a fixed start time, 1 = use an approximate start time for auto recordings) - static const std::string DEFAULT_STREAMING_PROFILE; - static const bool DEFAULT_STREAMING_HTTP; - static const int DEFAULT_DVR_PRIO; // any dvr_prio_t numeric value - static const int DEFAULT_DVR_LIFETIME; // 0..15 (0 = 1 day, 15 = use backend setting) - static const int DEFAULT_DVR_DUPDETECT; // 0..5 (0 = record all, 5 = limit to once a day) - static const bool DEFAULT_DVR_PLAYSTATUS; - static const int DEFAULT_STREAM_CHUNKSIZE; // KB - static const bool DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES; - - /** - * Singleton getter for the instance - */ - static Settings& GetInstance() - { - static Settings settings; - return settings; - } - - /** - * Read all settings defined in settings.xml - */ - void ReadSettings(); - - /** - * Set a value according to key definition in settings.xml - */ - ADDON_STATUS SetSetting(const std::string& key, const kodi::addon::CSettingValue& value); - - /** - * Getters for the settings values - */ - std::string GetHostname() const { return m_strHostname; } - const char* GetConstCharHostname() const { return m_strHostname.c_str(); } - int GetPortHTSP() const { return m_iPortHTSP; } - int GetPortHTTP() const { return m_iPortHTTP; } - bool GetUseHTTPS() const { return m_bUseHTTPS; } - std::string GetUsername() const { return m_strUsername; } - std::string GetPassword() const { return m_strPassword; } - std::string GetWolMac() const { return m_strWolMac; } - int GetConnectTimeout() const { return m_iConnectTimeout; } - int GetResponseTimeout() const { return m_iResponseTimeout; } - bool GetTraceDebug() const { return m_bTraceDebug; } - bool GetAsyncEpg() const { return m_bAsyncEpg; } - int GetTotalTuners() const { return m_iTotalTuners; } - int GetPreTunerCloseDelay() const { return m_iPreTunerCloseDelay; } - int GetAutorecApproxTime() const { return m_iAutorecApproxTime; } - int GetAutorecMaxDiff() const { return m_iAutorecMaxDiff; } - bool GetAutorecUseRegEx() const { return m_bAutorecUseRegEx; } - std::string GetStreamingProfile() const { return m_strStreamingProfile; } - bool GetStreamingHTTP() const { return m_bUseHTTPStreaming; } - int GetDvrPriority() const { return m_iDvrPriority; } - int GetDvrDupdetect() const { return m_iDvrDupdetect; } - int GetDvrLifetime(bool asEnum = false) const; - bool GetDvrPlayStatus() const { return m_bDvrPlayStatus; } - int GetStreamReadChunkSize() const { return m_iStreamReadChunkSizeKB; } - bool GetIgnoreDuplicateSchedules() const { return m_bIgnoreDuplicateSchedules; } - -private: - Settings() - : m_strHostname(DEFAULT_HOST), - m_iPortHTSP(DEFAULT_HTTP_PORT), - m_iPortHTTP(DEFAULT_HTSP_PORT), - m_bUseHTTPS(DEFAULT_USE_HTTPS), - m_strUsername(DEFAULT_USERNAME), - m_strPassword(DEFAULT_PASSWORD), - m_strWolMac(DEFAULT_WOL_MAC), - m_iConnectTimeout(DEFAULT_CONNECT_TIMEOUT), - m_iResponseTimeout(DEFAULT_RESPONSE_TIMEOUT), - m_bTraceDebug(DEFAULT_TRACE_DEBUG), - m_bAsyncEpg(DEFAULT_ASYNC_EPG), - m_bPretunerEnabled(DEFAULT_PRETUNER_ENABLED), - m_iTotalTuners(DEFAULT_TOTAL_TUNERS), - m_iPreTunerCloseDelay(DEFAULT_PRETUNER_CLOSEDELAY), - m_iAutorecApproxTime(DEFAULT_APPROX_TIME), - m_iAutorecMaxDiff(DEFAULT_AUTOREC_MAXDIFF), - m_bAutorecUseRegEx(DEFAULT_AUTOREC_USE_REGEX), - m_strStreamingProfile(DEFAULT_STREAMING_PROFILE), - m_bUseHTTPStreaming(DEFAULT_STREAMING_HTTP), - m_iDvrPriority(DEFAULT_DVR_PRIO), - m_iDvrLifetime(DEFAULT_DVR_LIFETIME), - m_iDvrDupdetect(DEFAULT_DVR_DUPDETECT), - m_bDvrPlayStatus(DEFAULT_DVR_PLAYSTATUS), - m_iStreamReadChunkSizeKB(DEFAULT_STREAM_CHUNKSIZE), - m_bIgnoreDuplicateSchedules(DEFAULT_DVR_IGNORE_DUPLICATE_SCHEDULES) - { - } - - Settings(Settings const&) = delete; - void operator=(Settings const&) = delete; - - /** - * Setters - */ - void SetHostname(const std::string& value) { m_strHostname = value; } - void SetPortHTSP(int value) { m_iPortHTSP = value; } - void SetPortHTTP(int value) { m_iPortHTTP = value; } - void SetUseHTTPS(bool value) { m_bUseHTTPS = value; } - void SetUsername(const std::string& value) { m_strUsername = value; } - void SetPassword(const std::string& value) { m_strPassword = value; } - void SetWolMac(const std::string& value) { m_strWolMac = value; } - void SetConnectTimeout(int value) { m_iConnectTimeout = value; } - void SetResponseTimeout(int value) { m_iResponseTimeout = value; } - void SetTraceDebug(bool value) { m_bTraceDebug = value; } - void SetAsyncEpg(bool value) { m_bAsyncEpg = value; } - void SetTotalTuners(int value) { m_iTotalTuners = value; } - void SetPreTunerCloseDelay(int value) { m_iPreTunerCloseDelay = value; } - void SetAutorecApproxTime(int value) { m_iAutorecApproxTime = value; } - void SetAutorecMaxDiff(int value) { m_iAutorecMaxDiff = value; } - void SetAutorecUseRegEx(bool value) { m_bAutorecUseRegEx = value; } - void SetStreamingProfile(const std::string& value) { m_strStreamingProfile = value; } - void SetStreamingHTTP(bool value) { m_bUseHTTPStreaming = value; } - void SetDvrPriority(int value) { m_iDvrPriority = value; } - void SetDvrLifetime(int value) { m_iDvrLifetime = value; } - void SetDvrDupdetect(int value) { m_iDvrDupdetect = value; } - void SetDvrPlayStatus(bool value) { m_bDvrPlayStatus = value; } - void SetStreamReadChunkSizeKB(int value) { m_iStreamReadChunkSizeKB = value; } - void SetIgnoreDuplicateSchedules(bool value) { m_bIgnoreDuplicateSchedules = value; } - - /** - * Read/Set values according to definition in settings.xml - */ - static std::string ReadStringSetting(const std::string& key, const std::string& def); - static int ReadIntSetting(const std::string& key, int def); - static bool ReadBoolSetting(const std::string& key, bool def); - - // @return ADDON_STATUS_OK if value has not changed, ADDON_STATUS_NEED_RESTART otherwise - static ADDON_STATUS SetStringSetting(const std::string& oldValue, - const kodi::addon::CSettingValue& newValue); - static ADDON_STATUS SetIntSetting(int oldValue, const kodi::addon::CSettingValue& newValue); - static ADDON_STATUS SetBoolSetting(bool oldValue, const kodi::addon::CSettingValue& newValue); - - std::string m_strHostname; - int m_iPortHTSP; - int m_iPortHTTP; - bool m_bUseHTTPS; - std::string m_strUsername; - std::string m_strPassword; - std::string m_strWolMac; - int m_iConnectTimeout; - int m_iResponseTimeout; - bool m_bTraceDebug; - bool m_bAsyncEpg; - bool m_bPretunerEnabled; - int m_iTotalTuners; - int m_iPreTunerCloseDelay; - bool m_iAutorecApproxTime; - int m_iAutorecMaxDiff; - bool m_bAutorecUseRegEx; - std::string m_strStreamingProfile; - bool m_bUseHTTPStreaming; - int m_iDvrPriority; - int m_iDvrLifetime; - int m_iDvrDupdetect; - bool m_bDvrPlayStatus; - int m_iStreamReadChunkSizeKB; - bool m_bIgnoreDuplicateSchedules; -}; - -} // namespace tvheadend diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/Subscription.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/Subscription.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/Subscription.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/Subscription.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -240,49 +240,31 @@ } const char* status = htsmsg_get_str(m, "status"); + const char* error = htsmsg_get_str(m, "subscriptionError"); - /* 'subscriptionErrors' was added in htsp v20, use 'status' for older backends */ - if (m_conn.GetProtocol() >= 20) + /* This field is absent when everything is fine */ + if (error) { - const char* error = htsmsg_get_str(m, "subscriptionError"); - - /* This field is absent when everything is fine */ - if (error) - { - if (!std::strcmp("badSignal", error)) - SetState(SUBSCRIPTION_NOSIGNAL); - else if (!std::strcmp("scrambled", error)) - SetState(SUBSCRIPTION_SCRAMBLED); - else if (!std::strcmp("userLimit", error)) - SetState(SUBSCRIPTION_USERLIMIT); - else if (!std::strcmp("noFreeAdapter", error)) - SetState(SUBSCRIPTION_NOFREEADAPTER); - else if (!std::strcmp("tuningFailed", error)) - SetState(SUBSCRIPTION_TUNINGFAILED); - else if (!std::strcmp("userAccess", error)) - SetState(SUBSCRIPTION_NOACCESS); - else - SetState(SUBSCRIPTION_UNKNOWN); - - /* Show an OSD message */ - ShowStateNotification(); - } + if (!std::strcmp("badSignal", error)) + SetState(SUBSCRIPTION_NOSIGNAL); + else if (!std::strcmp("scrambled", error)) + SetState(SUBSCRIPTION_SCRAMBLED); + else if (!std::strcmp("userLimit", error)) + SetState(SUBSCRIPTION_USERLIMIT); + else if (!std::strcmp("noFreeAdapter", error)) + SetState(SUBSCRIPTION_NOFREEADAPTER); + else if (!std::strcmp("tuningFailed", error)) + SetState(SUBSCRIPTION_TUNINGFAILED); + else if (!std::strcmp("userAccess", error)) + SetState(SUBSCRIPTION_NOACCESS); else - SetState(SUBSCRIPTION_RUNNING); - } - else - { - /* This field is absent when everything is fine */ - if (status) - { SetState(SUBSCRIPTION_UNKNOWN); - /* Show an OSD message */ - kodi::QueueNotification(QUEUE_INFO, "", status); - } - else - SetState(SUBSCRIPTION_RUNNING); + /* Show an OSD message */ + ShowStateNotification(); } + else + SetState(SUBSCRIPTION_RUNNING); } void Subscription::ShowStateNotification() diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/TimeRecordings.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/TimeRecordings.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/TimeRecordings.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/TimeRecordings.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -114,16 +114,7 @@ PVR_ERROR TimeRecordings::SendTimerecUpdate(const kodi::addon::PVRTimer& timer) { - if (m_conn.GetProtocol() >= 25) - return SendTimerecAddOrUpdate(timer, true); - - /* Note: there is no "updateTimerec" htsp method for htsp version < 25, thus delete + add. */ - PVR_ERROR error = SendTimerecDelete(timer); - - if (error == PVR_ERROR_NO_ERROR) - error = SendTimerecAdd(timer); - - return error; + return SendTimerecAddOrUpdate(timer, true); } PVR_ERROR TimeRecordings::SendTimerecAddOrUpdate(const kodi::addon::PVRTimer& timer, bool update) @@ -159,21 +150,8 @@ struct tm* tm_stop = std::localtime(&endTime); htsmsg_add_u32(m, "stop", tm_stop->tm_hour * 60 + tm_stop->tm_min); // end time in minutes from midnight - - if (m_conn.GetProtocol() >= 25) - { - htsmsg_add_u32(m, "removal", timer.GetLifetime()); // remove from disk - htsmsg_add_s64(m, "channelId", - timer.GetClientChannelUid()); // channelId is signed for >= htspv25 - } - else - { - htsmsg_add_u32(m, "retention", - LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from tvh database - htsmsg_add_u32(m, "channelId", - timer.GetClientChannelUid()); // channelId is unsigned for < htspv25 - } - + htsmsg_add_u32(m, "removal", timer.GetLifetime()); // remove from disk + htsmsg_add_s64(m, "channelId", timer.GetClientChannelUid()); htsmsg_add_u32(m, "daysOfWeek", timer.GetWeekdays()); htsmsg_add_u32(m, "priority", timer.GetPriority()); htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); @@ -273,29 +251,14 @@ return false; } - if (m_conn.GetProtocol() >= 25) + if (!htsmsg_get_u32(msg, "removal", &u32)) { - if (!htsmsg_get_u32(msg, "removal", &u32)) - { - rec.SetLifetime(u32); - } - else if (bAdd) - { - Logger::Log(LogLevel::LEVEL_ERROR, "malformed timerecEntryAdd: 'removal' missing"); - return false; - } + rec.SetLifetime(u32); } - else + else if (bAdd) { - if (!htsmsg_get_u32(msg, "retention", &u32)) - { - rec.SetLifetime(u32); - } - else if (bAdd) - { - Logger::Log(LogLevel::LEVEL_ERROR, "malformed timerecEntryAdd: 'retention' missing"); - return false; - } + Logger::Log(LogLevel::LEVEL_ERROR, "malformed timerecEntryAdd: 'removal' missing"); + return false; } if (!htsmsg_get_u32(msg, "priority", &u32)) diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/utilities/SettingsMigration.cpp kodi-pvr-hts-20.6.0+ds1/src/tvheadend/utilities/SettingsMigration.cpp --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/utilities/SettingsMigration.cpp 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/utilities/SettingsMigration.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,127 @@ +/* + * 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 "../HTSPTypes.h" + +#include "kodi/General.h" + +#include +#include +#include + +using namespace tvheadend; +using namespace tvheadend::utilities; + +namespace +{ +// maps +const std::vector> stringMap = { + {"host", "127.0.0.1"}, {"user", ""}, {"pass", ""}, {"wol_mac", ""}, {"streaming_profile", ""}}; + +const std::vector> intMap = {{"htsp_port", 9981}, + {"http_port", 9982}, + {"connect_timeout", 10000}, + {"response_timeout", 5000}, + {"total_tuners", 1}, + {"pretuner_closedelay", 10}, + {"autorec_approxtime", 0}, + {"autorec_maxdiff", 15}, + {"dvr_priority", DVR_PRIO_NORMAL}, + {"dvr_lifetime2", 15}, + {"dvr_dubdetect", DVR_AUTOREC_RECORD_ALL}, + {"stream_readchunksize", 64}}; + +const std::vector> boolMap = {{"https", false}, + {"epg_async", true}, + {"pretuner_enabled", false}, + {"autorec_use_regex", false}, + {"streaming_http", false}, + {"dvr_playstatus", true}, + {"dvr_ignore_duplicates", 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 : boolMap) + mig.MigrateBoolSetting(setting.first, setting.second); + + if (mig.Changed()) + { + // Set a title for the new instance settings + std::string title; + target.CheckInstanceSettingString("host", title); + if (title.empty()) + title = "Migrated Add-on Config"; + + target.SetInstanceSettingString("kodi_addon_instance_name", title); + return true; + } + return false; +} + +bool SettingsMigration::IsMigrationSetting(const std::string& key) +{ + 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(boolMap.cbegin(), boolMap.cend(), + [&key](const auto& entry) { return entry.first == key; }); +} + +void SettingsMigration::MigrateStringSetting(const char* key, const std::string& defaultValue) +{ + std::string value; + if (kodi::addon::CheckSettingString(key, value) && value != defaultValue) + { + m_target.SetInstanceSettingString(key, value); + m_changed = true; + } +} + +void SettingsMigration::MigrateIntSetting(const char* key, int defaultValue) +{ + int value; + if (kodi::addon::CheckSettingInt(key, value) && value != defaultValue) + { + m_target.SetInstanceSettingInt(key, value); + m_changed = true; + } +} + +void SettingsMigration::MigrateBoolSetting(const char* key, bool defaultValue) +{ + bool value; + if (kodi::addon::CheckSettingBoolean(key, value) && value != defaultValue) + { + m_target.SetInstanceSettingBoolean(key, value); + m_changed = true; + } +} diff -Nru kodi-pvr-hts-20.3.0+ds1/src/tvheadend/utilities/SettingsMigration.h kodi-pvr-hts-20.6.0+ds1/src/tvheadend/utilities/SettingsMigration.h --- kodi-pvr-hts-20.3.0+ds1/src/tvheadend/utilities/SettingsMigration.h 1970-01-01 00:00:00.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/tvheadend/utilities/SettingsMigration.h 2022-10-07 16:22:25.000000000 +0000 @@ -0,0 +1,45 @@ +/* + * 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 tvheadend +{ +namespace utilities +{ +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 MigrateBoolSetting(const char* key, bool defaultValue); + + bool Changed() const { return m_changed; } + + kodi::addon::IAddonInstance& m_target; + bool m_changed{false}; +}; + +} // namespace utilities +} // namespace tvheadend diff -Nru kodi-pvr-hts-20.3.0+ds1/src/Tvheadend.cpp kodi-pvr-hts-20.6.0+ds1/src/Tvheadend.cpp --- kodi-pvr-hts-20.3.0+ds1/src/Tvheadend.cpp 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/Tvheadend.cpp 2022-10-07 16:22:25.000000000 +0000 @@ -11,7 +11,7 @@ #include "tvheadend/HTSPDemuxer.h" #include "tvheadend/HTSPMessage.h" #include "tvheadend/HTSPVFS.h" -#include "tvheadend/Settings.h" +#include "tvheadend/InstanceSettings.h" #include "tvheadend/utilities/LifetimeMapper.h" #include "tvheadend/utilities/Logger.h" #include "tvheadend/utilities/Utilities.h" @@ -30,20 +30,21 @@ CTvheadend::CTvheadend(const kodi::addon::IInstanceInfo& instance) : kodi::addon::CInstancePVRClient(instance), - m_conn(new HTSPConnection(*this)), + m_settings(new InstanceSettings(*this)), + m_conn(new HTSPConnection(m_settings, *this)), m_streamchange(false), - m_vfs(new HTSPVFS(*m_conn)), + m_vfs(new HTSPVFS(m_settings, *m_conn)), m_queue(static_cast(-1)), - m_asyncState(Settings::GetInstance().GetResponseTimeout()), + m_asyncState(m_settings->GetResponseTimeout()), m_timeRecordings(*m_conn), - m_autoRecordings(*m_conn), + m_autoRecordings(m_settings, *m_conn), m_epgMaxDays(EpgMaxFutureDays()), m_playingLiveStream(false), m_playingRecording(nullptr) { - for (int i = 0; i < 1 || i < Settings::GetInstance().GetTotalTuners(); i++) + for (int i = 0; i < 1 || i < m_settings->GetTotalTuners(); i++) { - m_dmx.emplace_back(new HTSPDemuxer(*this, *m_conn)); + m_dmx.emplace_back(new HTSPDemuxer(m_settings, *this, *m_conn)); } m_dmx_active = m_dmx[0]; } @@ -78,6 +79,12 @@ * Miscellaneous * *************************************************************************/ +ADDON_STATUS CTvheadend::SetInstanceSetting(const std::string& settingName, + const kodi::addon::CSettingValue& settingValue) +{ + return m_settings->SetSetting(settingName, settingValue); +} + PVR_ERROR CTvheadend::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) { capabilities.SetSupportsEPG(true); @@ -92,11 +99,11 @@ capabilities.SetHandlesDemuxing(true); capabilities.SetSupportsRecordingEdl(true); capabilities.SetSupportsRecordingPlayCount(m_conn->GetProtocol() >= 27 && - Settings::GetInstance().GetDvrPlayStatus()); + m_settings->GetDvrPlayStatus()); capabilities.SetSupportsLastPlayedPosition(m_conn->GetProtocol() >= 27 && - Settings::GetInstance().GetDvrPlayStatus()); + m_settings->GetDvrPlayStatus()); capabilities.SetSupportsDescrambleInfo(true); - capabilities.SetSupportsAsyncEPGTransfer(Settings::GetInstance().GetAsyncEpg()); + capabilities.SetSupportsAsyncEPGTransfer(m_settings->GetAsyncEpg()); if (m_conn->GetProtocol() >= 28) { @@ -367,7 +374,7 @@ PVR_ERROR CTvheadend::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, std::vector& properties) { - if (!Settings::GetInstance().GetStreamingHTTP()) + if (!m_settings->GetStreamingHTTP()) return PVR_ERROR_NO_ERROR; std::lock_guard lock(m_mutex); @@ -377,7 +384,7 @@ return PVR_ERROR_FAILED; std::string path = "/stream/channelid/" + std::to_string(it->first); - const std::string streamingProfile = Settings::GetInstance().GetStreamingProfile(); + const std::string streamingProfile = m_settings->GetStreamingProfile(); if (!streamingProfile.empty()) path += "?profile=" + streamingProfile; @@ -402,8 +409,7 @@ htsmsg_add_u32(m, "id", id); /* Send and wait a bit longer than usual */ - m = m_conn->SendAndWait(lock, method, m, - std::max(30000, Settings::GetInstance().GetResponseTimeout())); + m = m_conn->SendAndWait(lock, method, m, std::max(30000, m_settings->GetResponseTimeout())); if (!m) return PVR_ERROR_SERVER_ERROR; @@ -699,19 +705,14 @@ /* Build message */ htsmsg_t* m = htsmsg_create_map(); htsmsg_add_u32(m, "id", std::stoul(rec.GetRecordingId())); - - if (m_conn->GetProtocol() >= 25) - htsmsg_add_u32(m, "removal", LifetimeMapper::KodiToTvh(rec.GetLifetime())); // remove from disk - else - htsmsg_add_u32(m, "retention", - LifetimeMapper::KodiToTvh(rec.GetLifetime())); // remove from tvh database + htsmsg_add_u32(m, "removal", LifetimeMapper::KodiToTvh(rec.GetLifetime())); // remove from disk return SendDvrUpdate(m); } PVR_ERROR CTvheadend::SetRecordingPlayCount(const kodi::addon::PVRRecording& rec, int playCount) { - if (m_conn->GetProtocol() < 27 || !Settings::GetInstance().GetDvrPlayStatus()) + if (m_conn->GetProtocol() < 27 || !m_settings->GetDvrPlayStatus()) return PVR_ERROR_NOT_IMPLEMENTED; Logger::Log(LogLevel::LEVEL_DEBUG, "Setting play count to %i for recording %s", playCount, @@ -727,7 +728,7 @@ PVR_ERROR CTvheadend::SetRecordingLastPlayedPosition(const kodi::addon::PVRRecording& rec, int playPosition) { - if (m_conn->GetProtocol() < 27 || !Settings::GetInstance().GetDvrPlayStatus()) + if (m_conn->GetProtocol() < 27 || !m_settings->GetDvrPlayStatus()) return PVR_ERROR_NOT_IMPLEMENTED; Logger::Log(LogLevel::LEVEL_DEBUG, "Setting play position to %i for recording %s", playPosition, @@ -744,7 +745,7 @@ PVR_ERROR CTvheadend::GetRecordingLastPlayedPosition(const kodi::addon::PVRRecording& rec, int& playPosition) { - if (m_conn->GetProtocol() < 27 || !Settings::GetInstance().GetDvrPlayStatus()) + if (m_conn->GetProtocol() < 27 || !m_settings->GetDvrPlayStatus()) return PVR_ERROR_NOT_IMPLEMENTED; std::lock_guard lock(m_mutex); @@ -764,7 +765,8 @@ { struct TimerType : kodi::addon::PVRTimerType { - TimerType(unsigned int id, + TimerType(const std::shared_ptr& settings, + unsigned int id, unsigned int attributes, const std::string& description, const std::vector& priorityValues = @@ -777,10 +779,9 @@ SetId(id); SetAttributes(attributes); SetDescription(description); - SetPriorities(priorityValues, Settings::GetInstance().GetDvrPriority()); - SetLifetimes(lifetimeValues, - LifetimeMapper::TvhToKodi(Settings::GetInstance().GetDvrLifetime())); - SetPreventDuplicateEpisodes(dupEpisodesValues, Settings::GetInstance().GetDvrDupdetect()); + SetPriorities(priorityValues, settings->GetDvrPriority()); + SetLifetimes(lifetimeValues, LifetimeMapper::TvhToKodi(settings->GetDvrLifetime())); + SetPreventDuplicateEpisodes(dupEpisodesValues, settings->GetDvrDupdetect()); } }; @@ -803,15 +804,9 @@ {LifetimeMapper::TvhToKodi(DVR_RET_1YEAR), kodi::addon::GetLocalizedString(30385)}, {LifetimeMapper::TvhToKodi(DVR_RET_2YEARS), kodi::addon::GetLocalizedString(30386)}, {LifetimeMapper::TvhToKodi(DVR_RET_3YEARS), kodi::addon::GetLocalizedString(30387)}, + {LifetimeMapper::TvhToKodi(DVR_RET_SPACE), kodi::addon::GetLocalizedString(30388)}, + {LifetimeMapper::TvhToKodi(DVR_RET_FOREVER), kodi::addon::GetLocalizedString(30389)}, }; - - if (m_conn->GetProtocol() >= 25) - { - lifetimeValues.emplace_back(LifetimeMapper::TvhToKodi(DVR_RET_SPACE), - kodi::addon::GetLocalizedString(30373)); - lifetimeValues.emplace_back(LifetimeMapper::TvhToKodi(DVR_RET_FOREVER), - kodi::addon::GetLocalizedString(30374)); - } } PVR_ERROR CTvheadend::GetTimerTypes(std::vector& types) @@ -846,29 +841,23 @@ kodi::addon::GetLocalizedString(30360)); deDupValues.emplace_back(DVR_AUTOREC_RECORD_ONCE_PER_DAY, kodi::addon::GetLocalizedString(30361)); - if (m_conn->GetProtocol() >= 26) - { - deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_EPISODE_NUMBER, - kodi::addon::GetLocalizedString(30362)); - deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_SUBTITLE, - kodi::addon::GetLocalizedString(30363)); - deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_TITLE, - kodi::addon::GetLocalizedString(30364)); - deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_DESCRIPTION, - kodi::addon::GetLocalizedString(30365)); - } + deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_EPISODE_NUMBER, + kodi::addon::GetLocalizedString(30362)); + deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_SUBTITLE, + kodi::addon::GetLocalizedString(30363)); + deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_TITLE, + kodi::addon::GetLocalizedString(30364)); + deDupValues.emplace_back(DVR_AUTOREC_LRECORD_DIFFERENT_DESCRIPTION, + kodi::addon::GetLocalizedString(30365)); if (m_conn->GetProtocol() >= 27) deDupValues.emplace_back(DVR_AUTOREC_LRECORD_ONCE_PER_MONTH, kodi::addon::GetLocalizedString(30371)); - if (m_conn->GetProtocol() >= 26) - { - deDupValues.emplace_back(DVR_AUTOREC_LRECORD_ONCE_PER_WEEK, - kodi::addon::GetLocalizedString(30366)); - deDupValues.emplace_back(DVR_AUTOREC_LRECORD_ONCE_PER_DAY, - kodi::addon::GetLocalizedString(30367)); - } + deDupValues.emplace_back(DVR_AUTOREC_LRECORD_ONCE_PER_WEEK, + kodi::addon::GetLocalizedString(30366)); + deDupValues.emplace_back(DVR_AUTOREC_LRECORD_ONCE_PER_DAY, + kodi::addon::GetLocalizedString(30367)); if (m_conn->GetProtocol() >= 31) deDupValues.emplace_back(DVR_AUTOREC_RECORD_UNIQUE, kodi::addon::GetLocalizedString(30372)); @@ -880,24 +869,21 @@ unsigned int TIMER_ONCE_MANUAL_ATTRIBS = PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME | PVR_TIMER_TYPE_SUPPORTS_END_TIME | - PVR_TIMER_TYPE_SUPPORTS_PRIORITY | PVR_TIMER_TYPE_SUPPORTS_LIFETIME; + PVR_TIMER_TYPE_SUPPORTS_PRIORITY | PVR_TIMER_TYPE_SUPPORTS_LIFETIME | + PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE; unsigned int TIMER_ONCE_EPG_ATTRIBS = PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME | PVR_TIMER_TYPE_SUPPORTS_END_TIME | PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN | PVR_TIMER_TYPE_SUPPORTS_PRIORITY | - PVR_TIMER_TYPE_SUPPORTS_LIFETIME; - - if (m_conn->GetProtocol() >= 23) - { - TIMER_ONCE_MANUAL_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE; - TIMER_ONCE_EPG_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE; - } + PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE; /* Timer types definition. */ /* One-shot manual (time and channel based) */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_ONCE_MANUAL, /* Attributes. */ @@ -911,6 +897,8 @@ /* One-shot epg based */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_ONCE_EPG, /* Attributes. */ @@ -924,6 +912,8 @@ /* Read-only one-shot for timers generated by timerec */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_ONCE_CREATED_BY_TIMEREC, /* Attributes. */ @@ -937,6 +927,8 @@ /* Read-only one-shot for timers generated by autorec */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_ONCE_CREATED_BY_AUTOREC, /* Attributes. */ @@ -950,6 +942,8 @@ /* Repeating manual (time and channel based) - timerec */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_REPEATING_MANUAL, /* Attributes. */ @@ -975,7 +969,7 @@ PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS | PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL | PVR_TIMER_TYPE_REQUIRES_EPG_SERIESLINK_ON_CREATE; - if (!Settings::GetInstance().GetAutorecApproxTime()) + if (!m_settings->GetAutorecApproxTime()) { /* We need the end time to represent the end of the tvh starting window */ TIMER_REPEATING_SERIESLINK_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_END_TIME; @@ -984,6 +978,8 @@ /* Repeating epg based - series link autorec */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_REPEATING_SERIESLINK, /* Attributes. */ @@ -1002,15 +998,10 @@ PVR_TIMER_TYPE_SUPPORTS_START_TIME | PVR_TIMER_TYPE_SUPPORTS_START_ANYTIME | PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS | PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN | PVR_TIMER_TYPE_SUPPORTS_PRIORITY | PVR_TIMER_TYPE_SUPPORTS_LIFETIME | - PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS | PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL; + PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS | PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL | + PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH | PVR_TIMER_TYPE_SUPPORTS_RECORD_ONLY_NEW_EPISODES; - if (m_conn->GetProtocol() >= 20) - { - TIMER_REPEATING_EPG_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH; - TIMER_REPEATING_EPG_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_RECORD_ONLY_NEW_EPISODES; - } - - if (!Settings::GetInstance().GetAutorecApproxTime()) + if (!m_settings->GetAutorecApproxTime()) { /* We need the end time to represent the end of the tvh starting window */ TIMER_REPEATING_EPG_ATTRIBS |= PVR_TIMER_TYPE_SUPPORTS_END_TIME; @@ -1019,6 +1010,8 @@ /* Repeating epg based - autorec */ types.emplace_back(TimerType( + /* Settings */ + m_settings, /* Type id. */ TIMER_REPEATING_EPG, /* Attributes. */ @@ -1064,12 +1057,7 @@ tmr.SetEPGSearchString(""); // n/a for one-shot timers tmr.SetDirectory(""); // n/a for one-shot timers tmr.SetSummary(tvhTmr.GetDescription()); - - if (m_conn->GetProtocol() >= 23) - tmr.SetState(!tvhTmr.IsEnabled() ? PVR_TIMER_STATE_DISABLED : tvhTmr.GetState()); - else - tmr.SetState(tvhTmr.GetState()); - + tmr.SetState(!tvhTmr.IsEnabled() ? PVR_TIMER_STATE_DISABLED : tvhTmr.GetState()); tmr.SetPriority(tvhTmr.GetPriority()); tmr.SetLifetime(tvhTmr.GetLifetime()); tmr.SetTimerType(tvhTmr.GetTimerType()); @@ -1165,19 +1153,11 @@ htsmsg_add_str(m, "description", timer.GetSummary().c_str()); } - if (m_conn->GetProtocol() >= 23) - htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); - + htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); htsmsg_add_s64(m, "startExtra", timer.GetMarginStart()); htsmsg_add_s64(m, "stopExtra", timer.GetMarginEnd()); - - if (m_conn->GetProtocol() >= 25) - htsmsg_add_u32(m, "removal", - LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from disk - else - htsmsg_add_u32(m, "retention", - LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from tvh database - + htsmsg_add_u32(m, "removal", + LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from disk htsmsg_add_u32(m, "priority", timer.GetPriority()); /* Send and Wait */ @@ -1227,18 +1207,8 @@ const auto& it = m_recordings.find(timer.GetClientIndex()); if (it != m_recordings.end() && it->second.IsRecording()) { - // This is a request to stop an active recording. - if (m_conn->GetProtocol() >= 26) - { - // gracefully stop the recording (mark as success in tvh) - return SendDvrDelete(timer.GetClientIndex(), "stopDvrEntry"); - } - else - { - // abort the recording (mark as failure in tvh) - no other choice, - // because graceful stop HTSP method was not available before HTSP v26. - return SendDvrDelete(timer.GetClientIndex(), "cancelDvrEntry"); - } + // gracefully stop the recording (mark as success in tvh) + return SendDvrDelete(timer.GetClientIndex(), "stopDvrEntry"); } } @@ -1282,36 +1252,9 @@ /* Build message */ htsmsg_t* m = htsmsg_create_map(); htsmsg_add_u32(m, "id", timer.GetClientIndex()); - - if (m_conn->GetProtocol() >= 22) - { - /* support for updating the channel was added very late to the htsp protocol. */ - htsmsg_add_u32(m, "channelId", timer.GetClientChannelUid()); - } - else - { - std::lock_guard lock(m_mutex); - - const auto& it = m_recordings.find(timer.GetClientIndex()); - if (it == m_recordings.end()) - { - Logger::Log(LogLevel::LEVEL_ERROR, "cannot find the timer to update"); - return PVR_ERROR_INVALID_PARAMETERS; - } - - if (it->second.GetChannel() != static_cast(timer.GetClientChannelUid())) - { - Logger::Log(LogLevel::LEVEL_ERROR, - "updating channels of one-shot timers not supported by HTSP v%d", - m_conn->GetProtocol()); - return PVR_ERROR_NOT_IMPLEMENTED; - } - } - + htsmsg_add_u32(m, "channelId", timer.GetClientChannelUid()); htsmsg_add_str(m, "title", timer.GetTitle().c_str()); - - if (m_conn->GetProtocol() >= 23) - htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); + htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); int64_t start = timer.GetStartTime(); if (start == 0) @@ -1325,14 +1268,8 @@ htsmsg_add_str(m, "description", timer.GetSummary().c_str()); htsmsg_add_s64(m, "startExtra", timer.GetMarginStart()); htsmsg_add_s64(m, "stopExtra", timer.GetMarginEnd()); - - if (m_conn->GetProtocol() >= 25) - htsmsg_add_u32(m, "removal", - LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from disk - else - htsmsg_add_u32(m, "retention", - LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from tvh database - + htsmsg_add_u32(m, "removal", + LifetimeMapper::KodiToTvh(timer.GetLifetime())); // remove from disk htsmsg_add_u32(m, "priority", timer.GetPriority()); return SendDvrUpdate(m); @@ -1351,21 +1288,18 @@ else if ((timer.GetTimerType() == TIMER_ONCE_CREATED_BY_TIMEREC) || (timer.GetTimerType() == TIMER_ONCE_CREATED_BY_AUTOREC)) { - if (m_conn->GetProtocol() >= 23) - { - /* Read-only timer created by autorec or timerec */ - std::lock_guard lock(m_mutex); + /* Read-only timer created by autorec or timerec */ + std::lock_guard lock(m_mutex); - const auto& it = m_recordings.find(timer.GetClientIndex()); - if (it != m_recordings.end() && - (it->second.IsEnabled() == (timer.GetState() == PVR_TIMER_STATE_DISABLED))) - { - /* This is actually a request to enable/disable a timer. */ - htsmsg_t* m = htsmsg_create_map(); - htsmsg_add_u32(m, "id", timer.GetClientIndex()); - htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); - return SendDvrUpdate(m); - } + const auto& it = m_recordings.find(timer.GetClientIndex()); + if (it != m_recordings.end() && + (it->second.IsEnabled() == (timer.GetState() == PVR_TIMER_STATE_DISABLED))) + { + /* This is actually a request to enable/disable a timer. */ + htsmsg_t* m = htsmsg_create_map(); + htsmsg_add_u32(m, "id", timer.GetClientIndex()); + htsmsg_add_u32(m, "enabled", timer.GetState() == PVR_TIMER_STATE_DISABLED ? 0 : 1); + return SendDvrUpdate(m); } Logger::Log(LogLevel::LEVEL_ERROR, "timer is read-only"); @@ -1501,7 +1435,7 @@ int iOldMaxDays = m_epgMaxDays; m_epgMaxDays = iFutureDays; - if (Settings::GetInstance().GetAsyncEpg()) + if (m_settings->GetAsyncEpg()) { Logger::Log(LogLevel::LEVEL_TRACE, "reconnecting to synchronize epg data. epg max time: old = %d, new = %d", @@ -1527,7 +1461,7 @@ QueryAvailableProfiles(lock); /* Show a notification if the profile is not available */ - const std::string streamingProfile = Settings::GetInstance().GetStreamingProfile(); + const std::string streamingProfile = m_settings->GetStreamingProfile(); if (!streamingProfile.empty() && !HasStreamingProfile(streamingProfile)) { @@ -1545,7 +1479,7 @@ m_asyncState.SetState(ASYNC_INIT); htsmsg_t* msg = htsmsg_create_map(); - if (Settings::GetInstance().GetAsyncEpg()) + if (m_settings->GetAsyncEpg()) { Logger::Log(LogLevel::LEVEL_INFO, "Request async EPG (%d days)", m_epgMaxDays); htsmsg_add_u32(msg, "epg", 1); @@ -1590,7 +1524,7 @@ PVR_ERROR CTvheadend::GetBackendHostname(std::string& hostname) { - hostname = Settings::GetInstance().GetConstCharHostname(); + hostname = m_settings->GetConstCharHostname(); return PVR_ERROR_NO_ERROR; } @@ -1672,7 +1606,7 @@ if (!chunksize) return PVR_ERROR_INVALID_PARAMETERS; - chunksize = Settings::GetInstance().GetStreamReadChunkSize() * 1024; + chunksize = m_settings->GetStreamReadChunkSize() * 1024; return PVR_ERROR_NO_ERROR; } @@ -1738,7 +1672,7 @@ // predictive tuning active? if (m_dmx.size() > 1) { - int closeDelay = Settings::GetInstance().GetPreTunerCloseDelay(); + int closeDelay = m_settings->GetPreTunerCloseDelay(); if (closeDelay > 0) { for (auto* dmx : m_dmx) @@ -2029,7 +1963,7 @@ if (m_asyncState.GetState() != ASYNC_EPG) return; - if (!Settings::GetInstance().GetAsyncEpg()) + if (!m_settings->GetAsyncEpg()) { m_asyncState.SetState(ASYNC_DONE); return; @@ -2226,22 +2160,8 @@ continue; /* Channel type */ - if (m_conn->GetProtocol() >= 26) - { - if (!htsmsg_get_u32(&f->hmf_msg, "content", &u32)) - channel.SetType(u32); - } - else - { - str = htsmsg_get_str(&f->hmf_msg, "type"); - if (str) - { - if (!std::strcmp(str, "Radio")) - channel.SetType(CHANNEL_TYPE_RADIO); - else if (!std::strcmp(str, "SDTV") || !std::strcmp(str, "HDTV")) - channel.SetType(CHANNEL_TYPE_TV); - } - } + if (!htsmsg_get_u32(&f->hmf_msg, "content", &u32)) + channel.SetType(u32); /* CAID */ if (caid == 0) @@ -2302,8 +2222,8 @@ /* Ignore duplicates */ uint32_t dup = 0; - if (Settings::GetInstance().GetIgnoreDuplicateSchedules() && - !htsmsg_get_u32(msg, "duplicate", &dup) && dup == 1) + if (m_settings->GetIgnoreDuplicateSchedules() && !htsmsg_get_u32(msg, "duplicate", &dup) && + dup == 1) return; /* Ignore recordings without a file (e.g. removed recordings) */ @@ -2378,7 +2298,7 @@ htsmsg_t* files = htsmsg_get_list(msg, "files"); if (files) { - bool needChannelType = !rec.GetChannelType() && m_conn->GetProtocol() >= 25; + bool needChannelType = !rec.GetChannelType(); bool hasAudio = false; bool hasVideo = false; @@ -2445,7 +2365,7 @@ } /* Channel name fallback (in case channel was deleted) */ - if (rec.GetChannelName().empty() && m_conn->GetProtocol() >= 25) + if (rec.GetChannelName().empty()) { const char* str = htsmsg_get_str(msg, "channelName"); if (str) @@ -2470,31 +2390,15 @@ return; } - if (m_conn->GetProtocol() >= 25) + uint32_t removal = 0; + if (!htsmsg_get_u32(msg, "removal", &removal)) { - uint32_t removal = 0; - if (!htsmsg_get_u32(msg, "removal", &removal)) - { - rec.SetLifetime(removal); - } - else if (bAdd) - { - Logger::Log(LogLevel::LEVEL_ERROR, "malformed dvrEntryAdd: 'removal' missing"); - return; - } + rec.SetLifetime(removal); } - else + else if (bAdd) { - uint32_t retention = 0; - if (!htsmsg_get_u32(msg, "retention", &retention)) - { - rec.SetLifetime(retention); - } - else if (bAdd) - { - Logger::Log(LogLevel::LEVEL_ERROR, "malformed dvrEntryAdd: 'retention' missing"); - return; - } + Logger::Log(LogLevel::LEVEL_ERROR, "malformed dvrEntryAdd: 'removal' missing"); + return; } uint32_t priority = 0; diff -Nru kodi-pvr-hts-20.3.0+ds1/src/Tvheadend.h kodi-pvr-hts-20.6.0+ds1/src/Tvheadend.h --- kodi-pvr-hts-20.3.0+ds1/src/Tvheadend.h 2022-05-01 14:57:35.000000000 +0000 +++ kodi-pvr-hts-20.6.0+ds1/src/Tvheadend.h 2022-10-07 16:22:25.000000000 +0000 @@ -31,6 +31,7 @@ #include "kodi/addon-instance/PVR.h" #include "kodi/tools/Thread.h" +#include #include #include #include @@ -46,6 +47,7 @@ class HTSPConnection; class HTSPDemuxer; class HTSPVFS; +class InstanceSettings; } // namespace tvheadend /* Typedefs */ @@ -66,6 +68,10 @@ void Start(); void Stop(); + // kodi::addon::CInstancePVRClient -> kodi::addon::IAddonInstance overrides + ADDON_STATUS SetInstanceSetting(const std::string& settingName, + const kodi::addon::CSettingValue& settingValue) override; + // IHTSPConnectionListener implementation void Disconnected() override; bool Connected(std::unique_lock& lock) override; @@ -256,6 +262,8 @@ std::recursive_mutex m_mutex; + std::shared_ptr m_settings; + tvheadend::HTSPConnection* m_conn; std::vector m_dmx;