From 8109ce85252fdbc2c71e26a19e645e861fc9a84e Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Wed, 8 Feb 2023 16:31:50 +0000 Subject: [PATCH 1/4] Split out addon and eliminate Settings Singleton --- CMakeLists.txt | 6 +- src/{PVRIptvData.cpp => IptvSimple.cpp} | 138 +++++++++-------------- src/{PVRIptvData.h => IptvSimple.h} | 32 +++--- src/addon.cpp | 96 ++++++++++++++++ src/addon.h | 32 ++++++ src/iptvsimple/CatchupController.cpp | 25 ++-- src/iptvsimple/CatchupController.h | 6 +- src/iptvsimple/ChannelGroups.cpp | 11 +- src/iptvsimple/ChannelGroups.h | 6 +- src/iptvsimple/Channels.cpp | 7 +- src/iptvsimple/Channels.h | 6 +- src/iptvsimple/Epg.cpp | 44 ++++---- src/iptvsimple/Epg.h | 6 +- src/iptvsimple/Media.cpp | 6 +- src/iptvsimple/Media.h | 4 +- src/iptvsimple/PlaylistLoader.cpp | 34 +++--- src/iptvsimple/PlaylistLoader.h | 6 +- src/iptvsimple/Providers.cpp | 6 +- src/iptvsimple/Providers.h | 4 +- src/iptvsimple/Settings.cpp | 6 +- src/iptvsimple/Settings.h | 16 +-- src/iptvsimple/data/BaseEntry.h | 4 + src/iptvsimple/data/Channel.cpp | 50 ++++---- src/iptvsimple/data/Channel.h | 11 +- src/iptvsimple/data/ChannelEpg.h | 5 +- src/iptvsimple/data/EpgEntry.cpp | 2 +- src/iptvsimple/data/EpgEntry.h | 6 + src/iptvsimple/data/MediaEntry.cpp | 10 +- src/iptvsimple/data/MediaEntry.h | 5 + src/iptvsimple/utilities/FileUtils.cpp | 11 +- src/iptvsimple/utilities/FileUtils.h | 8 +- src/iptvsimple/utilities/StreamUtils.cpp | 24 ++-- src/iptvsimple/utilities/StreamUtils.h | 12 +- 33 files changed, 394 insertions(+), 251 deletions(-) rename src/{PVRIptvData.cpp => IptvSimple.cpp} (67%) rename src/{PVRIptvData.h => IptvSimple.h} (83%) create mode 100644 src/addon.cpp create mode 100644 src/addon.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bff2b3bb..8cd70b21d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,8 @@ message(STATUS "PUGIXML_LIBRARIES: ${PUGIXML_LIBRARIES}") message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}") message(STATUS "LZMA_LIBRARIES: ${LZMA_LIBRARIES}") -set(IPTV_SOURCES src/PVRIptvData.cpp +set(IPTV_SOURCES src/addon.cpp + src/IptvSimple.cpp src/iptvsimple/CatchupController.cpp src/iptvsimple/Channels.cpp src/iptvsimple/ChannelGroups.cpp @@ -43,7 +44,8 @@ set(IPTV_SOURCES src/PVRIptvData.cpp src/iptvsimple/utilities/StreamUtils.cpp src/iptvsimple/utilities/WebUtils.cpp) -set(IPTV_HEADERS src/PVRIptvData.h +set(IPTV_HEADERS src/addon.h + src/IptvSimple.h src/iptvsimple/CatchupController.h src/iptvsimple/Channels.h src/iptvsimple/ChannelGroups.h diff --git a/src/PVRIptvData.cpp b/src/IptvSimple.cpp similarity index 67% rename from src/PVRIptvData.cpp rename to src/IptvSimple.cpp index d44cdc772..146cc97d0 100644 --- a/src/PVRIptvData.cpp +++ b/src/IptvSimple.cpp @@ -5,7 +5,7 @@ * See LICENSE.md for more information. */ -#include "PVRIptvData.h" +#include "IptvSimple.h" #include "iptvsimple/Settings.h" #include "iptvsimple/utilities/Logger.h" @@ -22,7 +22,7 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; using namespace kodi::tools; -PVRIptvData::PVRIptvData() +IptvSimple::IptvSimple(const kodi::addon::IInstanceInfo& instance, std::shared_ptr& settings) : kodi::addon::CInstancePVRClient(instance), m_settings(settings) { m_channels.Clear(); m_channelGroups.Clear(); @@ -31,42 +31,11 @@ PVRIptvData::PVRIptvData() m_media.Clear(); } -ADDON_STATUS PVRIptvData::Create() +bool IptvSimple::Initialise() { std::lock_guard lock(m_mutex); - /* 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_FATAL; - break; - case LogLevel::LEVEL_ERROR: - addonLevel = ADDON_LOG_ERROR; - break; - case LogLevel::LEVEL_WARNING: - addonLevel = ADDON_LOG_WARNING; - break; - case LogLevel::LEVEL_INFO: - addonLevel = ADDON_LOG_INFO; - break; - default: - addonLevel = ADDON_LOG_DEBUG; - } - - kodi::Log(addonLevel, "%s", message); - }); - - Logger::GetInstance().SetPrefix("pvr.iptvsimple"); - - Logger::Log(LogLevel::LEVEL_INFO, "%s - Creating the PVR IPTV Simple add-on", __FUNCTION__); - - Settings::GetInstance().ReadFromAddon(kodi::addon::GetUserPath(), kodi::addon::GetAddonPath()); + m_settings->ReadFromAddon(kodi::addon::GetUserPath(), kodi::addon::GetAddonPath()); m_channels.Init(); m_channelGroups.Init(); @@ -84,10 +53,10 @@ ADDON_STATUS PVRIptvData::Create() m_running = true; m_thread = std::thread([&] { Process(); }); - return ADDON_STATUS_OK; + return true; } -PVR_ERROR PVRIptvData::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) +PVR_ERROR IptvSimple::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) { capabilities.SetSupportsEPG(true); capabilities.SetSupportsTV(true); @@ -103,28 +72,28 @@ PVR_ERROR PVRIptvData::GetCapabilities(kodi::addon::PVRCapabilities& capabilitie return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetBackendName(std::string& name) +PVR_ERROR IptvSimple::GetBackendName(std::string& name) { name = "IPTV Simple"; return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetBackendVersion(std::string& version) +PVR_ERROR IptvSimple::GetBackendVersion(std::string& version) { // Some linux platform require the full string initialisation here to compile. No idea why. version = std::string(STR(IPTV_VERSION)); return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetConnectionString(std::string& connection) +PVR_ERROR IptvSimple::GetConnectionString(std::string& connection) { connection = "connected"; return PVR_ERROR_NO_ERROR; } -void PVRIptvData::Process() +void IptvSimple::Process() { unsigned int refreshTimer = 0; time_t lastRefreshTimeSeconds = std::time(nullptr); - int lastRefreshHour = Settings::GetInstance().GetM3URefreshHour(); //ignore if we start during same hour + int lastRefreshHour = m_settings->GetM3URefreshHour(); //ignore if we start during same hour while (m_running) { @@ -135,12 +104,12 @@ void PVRIptvData::Process() refreshTimer += static_cast(currentRefreshTimeSeconds - lastRefreshTimeSeconds); lastRefreshTimeSeconds = currentRefreshTimeSeconds; - if (Settings::GetInstance().GetM3URefreshMode() == RefreshMode::REPEATED_REFRESH && - refreshTimer >= (Settings::GetInstance().GetM3URefreshIntervalMins() * 60)) + if (m_settings->GetM3URefreshMode() == RefreshMode::REPEATED_REFRESH && + refreshTimer >= (m_settings->GetM3URefreshIntervalMins() * 60)) m_reloadChannelsGroupsAndEPG = true; - if (Settings::GetInstance().GetM3URefreshMode() == RefreshMode::ONCE_PER_DAY && - lastRefreshHour != timeInfo.tm_hour && timeInfo.tm_hour == Settings::GetInstance().GetM3URefreshHour()) + if (m_settings->GetM3URefreshMode() == RefreshMode::ONCE_PER_DAY && + lastRefreshHour != timeInfo.tm_hour && timeInfo.tm_hour == m_settings->GetM3URefreshHour()) m_reloadChannelsGroupsAndEPG = true; std::lock_guard lock(m_mutex); @@ -148,7 +117,7 @@ void PVRIptvData::Process() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - Settings::GetInstance().ReloadAddonSettings(); + m_settings->ReloadAddonSettings(); m_playlistLoader.ReloadPlayList(); m_epg.ReloadEPG(); // Reloading EPG also updates media @@ -159,7 +128,7 @@ void PVRIptvData::Process() } } -PVRIptvData::~PVRIptvData() +IptvSimple::~IptvSimple() { Logger::Log(LEVEL_DEBUG, "%s Stopping update thread...", __FUNCTION__); m_running = false; @@ -177,14 +146,14 @@ PVRIptvData::~PVRIptvData() * Providers **************************************************************************/ -PVR_ERROR PVRIptvData::GetProvidersAmount(int& amount) +PVR_ERROR IptvSimple::GetProvidersAmount(int& amount) { amount = m_providers.GetNumProviders(); return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetProviders(kodi::addon::PVRProvidersResultSet& results) +PVR_ERROR IptvSimple::GetProviders(kodi::addon::PVRProvidersResultSet& results) { std::vector providers; { @@ -204,21 +173,21 @@ PVR_ERROR PVRIptvData::GetProviders(kodi::addon::PVRProvidersResultSet& results) * Channels **************************************************************************/ -PVR_ERROR PVRIptvData::GetChannelsAmount(int& amount) +PVR_ERROR IptvSimple::GetChannelsAmount(int& amount) { std::lock_guard lock(m_mutex); amount = m_channels.GetChannelsAmount(); return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) +PVR_ERROR IptvSimple::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) { std::lock_guard lock(m_mutex); return m_channels.GetChannels(results, radio); } -PVR_ERROR PVRIptvData::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, std::vector& properties) +PVR_ERROR IptvSimple::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, std::vector& properties) { if (GetChannel(channel, m_currentChannel)) { @@ -238,7 +207,7 @@ PVR_ERROR PVRIptvData::GetChannelStreamProperties(const kodi::addon::PVRChannel& else streamURL = m_catchupController.ProcessStreamUrl(m_currentChannel); - StreamUtils::SetAllStreamProperties(properties, m_currentChannel, streamURL, catchupUrl.empty(), catchupProperties); + StreamUtils::SetAllStreamProperties(properties, m_currentChannel, streamURL, catchupUrl.empty(), catchupProperties, m_settings); Logger::Log(LogLevel::LEVEL_INFO, "%s - Live %s URL: %s", __FUNCTION__, catchupUrl.empty() ? "Stream" : "Catchup", WebUtils::RedactUrl(streamURL).c_str()); @@ -248,14 +217,14 @@ PVR_ERROR PVRIptvData::GetChannelStreamProperties(const kodi::addon::PVRChannel& return PVR_ERROR_SERVER_ERROR; } -bool PVRIptvData::GetChannel(const kodi::addon::PVRChannel& channel, Channel& myChannel) +bool IptvSimple::GetChannel(const kodi::addon::PVRChannel& channel, Channel& myChannel) { std::lock_guard lock(m_mutex); return m_channels.GetChannel(channel, myChannel); } -bool PVRIptvData::GetChannel(unsigned int uniqueChannelId, iptvsimple::data::Channel& myChannel) +bool IptvSimple::GetChannel(unsigned int uniqueChannelId, iptvsimple::data::Channel& myChannel) { std::lock_guard lock(m_mutex); @@ -266,21 +235,21 @@ bool PVRIptvData::GetChannel(unsigned int uniqueChannelId, iptvsimple::data::Cha * Channel Groups **************************************************************************/ -PVR_ERROR PVRIptvData::GetChannelGroupsAmount(int& amount) +PVR_ERROR IptvSimple::GetChannelGroupsAmount(int& amount) { std::lock_guard lock(m_mutex); amount = m_channelGroups.GetChannelGroupsAmount(); return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) +PVR_ERROR IptvSimple::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) { std::lock_guard lock(m_mutex); return m_channelGroups.GetChannelGroups(results, radio); } -PVR_ERROR PVRIptvData::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, kodi::addon::PVRChannelGroupMembersResultSet& results) +PVR_ERROR IptvSimple::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, kodi::addon::PVRChannelGroupMembersResultSet& results) { std::lock_guard lock(m_mutex); @@ -291,23 +260,23 @@ PVR_ERROR PVRIptvData::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup * EPG **************************************************************************/ -PVR_ERROR PVRIptvData::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi::addon::PVREPGTagsResultSet& results) +PVR_ERROR IptvSimple::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi::addon::PVREPGTagsResultSet& results) { std::lock_guard lock(m_mutex); return m_epg.GetEPGForChannel(channelUid, start, end, results); } -PVR_ERROR PVRIptvData::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& tag, std::vector& properties) +PVR_ERROR IptvSimple::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& tag, std::vector& properties) { Logger::Log(LEVEL_DEBUG, "%s - Tag startTime: %ld \tendTime: %ld", __FUNCTION__, tag.GetStartTime(), tag.GetEndTime()); if (GetChannel(static_cast(tag.GetUniqueChannelId()), m_currentChannel)) { - Logger::Log(LEVEL_DEBUG, "%s - GetPlayEpgAsLive is %s", __FUNCTION__, Settings::GetInstance().CatchupPlayEpgAsLive() ? "enabled" : "disabled"); + Logger::Log(LEVEL_DEBUG, "%s - GetPlayEpgAsLive is %s", __FUNCTION__, m_settings->CatchupPlayEpgAsLive() ? "enabled" : "disabled"); std::map catchupProperties; - if (Settings::GetInstance().CatchupPlayEpgAsLive() && m_currentChannel.CatchupSupportsTimeshifting()) + if (m_settings->CatchupPlayEpgAsLive() && m_currentChannel.CatchupSupportsTimeshifting()) { m_catchupController.ProcessEPGTagForTimeshiftedPlayback(tag, m_currentChannel, catchupProperties); } @@ -320,7 +289,7 @@ PVR_ERROR PVRIptvData::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& t const std::string catchupUrl = m_catchupController.GetCatchupUrl(m_currentChannel); if (!catchupUrl.empty()) { - StreamUtils::SetAllStreamProperties(properties, m_currentChannel, catchupUrl, false, catchupProperties); + StreamUtils::SetAllStreamProperties(properties, m_currentChannel, catchupUrl, false, catchupProperties, m_settings); Logger::Log(LEVEL_INFO, "%s - EPG Catchup URL: %s", __FUNCTION__, WebUtils::RedactUrl(catchupUrl).c_str()); return PVR_ERROR_NO_ERROR; @@ -330,17 +299,17 @@ PVR_ERROR PVRIptvData::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& t return PVR_ERROR_FAILED; } -PVR_ERROR PVRIptvData::IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& bIsPlayable) +PVR_ERROR IptvSimple::IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& bIsPlayable) { - if (!Settings::GetInstance().IsCatchupEnabled()) + if (!m_settings->IsCatchupEnabled()) return PVR_ERROR_NOT_IMPLEMENTED; const time_t now = std::time(nullptr); - Channel channel; + Channel channel{m_settings}; // Get the channel and set the current tag on it if found bIsPlayable = GetChannel(static_cast(tag.GetUniqueChannelId()), channel) && - Settings::GetInstance().IsCatchupEnabled() && channel.IsCatchupSupported(); + m_settings->IsCatchupEnabled() && channel.IsCatchupSupported(); if (channel.IgnoreCatchupDays()) { @@ -357,19 +326,19 @@ PVR_ERROR PVRIptvData::IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& bIsPlayable = bIsPlayable && tag.GetStartTime() < now && tag.GetStartTime() >= (now - static_cast(channel.GetCatchupDaysInSeconds())) && - (!Settings::GetInstance().CatchupOnlyOnFinishedProgrammes() || tag.GetEndTime() < now); + (!m_settings->CatchupOnlyOnFinishedProgrammes() || tag.GetEndTime() < now); } return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::SetEPGMaxPastDays(int epgMaxPastDays) +PVR_ERROR IptvSimple::SetEPGMaxPastDays(int epgMaxPastDays) { m_epg.SetEPGMaxPastDays(epgMaxPastDays); return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::SetEPGMaxFutureDays(int epgMaxFutureDays) +PVR_ERROR IptvSimple::SetEPGMaxFutureDays(int epgMaxFutureDays) { m_epg.SetEPGMaxFutureDays(epgMaxFutureDays); return PVR_ERROR_NO_ERROR; @@ -379,7 +348,7 @@ PVR_ERROR PVRIptvData::SetEPGMaxFutureDays(int epgMaxFutureDays) * Media **************************************************************************/ -PVR_ERROR PVRIptvData::GetRecordingsAmount(bool deleted, int& amount) +PVR_ERROR IptvSimple::GetRecordingsAmount(bool deleted, int& amount) { std::lock_guard lock(m_mutex); if (deleted) @@ -390,7 +359,7 @@ PVR_ERROR PVRIptvData::GetRecordingsAmount(bool deleted, int& amount) return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) +PVR_ERROR IptvSimple::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) { if (!deleted) { @@ -409,7 +378,7 @@ PVR_ERROR PVRIptvData::GetRecordings(bool deleted, kodi::addon::PVRRecordingsRes return PVR_ERROR_NO_ERROR; } -PVR_ERROR PVRIptvData::GetRecordingStreamProperties(const kodi::addon::PVRRecording& recording, std::vector& properties) +PVR_ERROR IptvSimple::GetRecordingStreamProperties(const kodi::addon::PVRRecording& recording, std::vector& properties) { std::string url = m_media.GetMediaEntryURL(recording); @@ -427,7 +396,7 @@ PVR_ERROR PVRIptvData::GetRecordingStreamProperties(const kodi::addon::PVRRecord * Signal Status **************************************************************************/ -PVR_ERROR PVRIptvData::GetSignalStatus(int channelUid, kodi::addon::PVRSignalStatus& signalStatus) +PVR_ERROR IptvSimple::GetSignalStatus(int channelUid, kodi::addon::PVRSignalStatus& signalStatus) { signalStatus.SetAdapterName("IPTV Simple Adapter 1"); signalStatus.SetAdapterStatus("OK"); @@ -439,16 +408,15 @@ PVR_ERROR PVRIptvData::GetSignalStatus(int channelUid, kodi::addon::PVRSignalSta * Settings **************************************************************************/ -ADDON_STATUS PVRIptvData::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) -{ - std::lock_guard lock(m_mutex); +// ADDON_STATUS IptvSimple::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +// { +// std::lock_guard lock(m_mutex); - // When a number of settings change set this on the first one so it can be picked up - // in the process call for a reload of channels, groups and EPG. - if (!m_reloadChannelsGroupsAndEPG) - m_reloadChannelsGroupsAndEPG = true; +// // When a number of settings change set this on the first one so it can be picked up +// // in the process call for a reload of channels, groups and EPG. +// if (!m_reloadChannelsGroupsAndEPG) +// m_reloadChannelsGroupsAndEPG = true; - return Settings::GetInstance().SetValue(settingName, settingValue); -} +// return m_settings->SetValue(settingName, settingValue); +// } -ADDONCREATOR(PVRIptvData) diff --git a/src/PVRIptvData.h b/src/IptvSimple.h similarity index 83% rename from src/PVRIptvData.h rename to src/IptvSimple.h index 79df5ac3f..38c8e9b49 100644 --- a/src/PVRIptvData.h +++ b/src/IptvSimple.h @@ -22,19 +22,13 @@ #include -class ATTR_DLL_LOCAL PVRIptvData - : public kodi::addon::CAddonBase, - public kodi::addon::CInstancePVRClient +class ATTR_DLL_LOCAL IptvSimple : public kodi::addon::CInstancePVRClient { public: - PVRIptvData(); - ~PVRIptvData() override; + IptvSimple(const kodi::addon::IInstanceInfo& instance, std::shared_ptr& settings); + ~IptvSimple() override; - // kodi::addon::CAddonBase functions - //@{ - ADDON_STATUS Create() override; - ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) override; - //@} + bool Initialise(); // kodi::addon::CInstancePVRClient functions //@{ @@ -88,14 +82,16 @@ class ATTR_DLL_LOCAL PVRIptvData private: static const int PROCESS_LOOP_WAIT_SECS = 2; - iptvsimple::data::Channel m_currentChannel; - iptvsimple::Providers m_providers; - iptvsimple::Channels m_channels; - iptvsimple::ChannelGroups m_channelGroups{m_channels}; - iptvsimple::Media m_media; - iptvsimple::PlaylistLoader m_playlistLoader{this, m_channels, m_channelGroups, m_providers, m_media}; - iptvsimple::Epg m_epg{this, m_channels, m_media}; - iptvsimple::CatchupController m_catchupController{m_epg, &m_mutex}; + std::shared_ptr m_settings; + + iptvsimple::data::Channel m_currentChannel{m_settings}; + iptvsimple::Providers m_providers{m_settings}; + iptvsimple::Channels m_channels{m_settings}; + iptvsimple::ChannelGroups m_channelGroups{m_channels, m_settings}; + iptvsimple::Media m_media{m_settings}; + iptvsimple::PlaylistLoader m_playlistLoader{this, m_channels, m_channelGroups, m_providers, m_media, m_settings}; + iptvsimple::Epg m_epg{this, m_channels, m_media, m_settings}; + iptvsimple::CatchupController m_catchupController{m_epg, &m_mutex, m_settings}; std::atomic m_running{false}; std::thread m_thread; diff --git a/src/addon.cpp b/src/addon.cpp new file mode 100644 index 000000000..70421645e --- /dev/null +++ b/src/addon.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005-2021 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#include "addon.h" +#include "IptvSimple.h" + +using namespace iptvsimple; +using namespace iptvsimple::data; +using namespace iptvsimple::utilities; + +ADDON_STATUS CIptvSimpleAddon::Create() +{ + /* Init settings */ + m_settings.reset(new Settings()); + + Logger::Log(LEVEL_DEBUG, "%s - Creating IPTV Simple PVR-Client", __func__); + + /* Configure the logger */ + Logger::GetInstance().SetImplementation([this](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; + } + + kodi::Log(addonLevel, "%s", message); + }); + + Logger::GetInstance().SetPrefix("pvr.iptvsimple"); + + Logger::Log(LogLevel::LEVEL_INFO, "%s starting PVR client...", __func__); + + return ADDON_STATUS_OK; +} + +ADDON_STATUS CIptvSimpleAddon::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +{ + return m_settings->SetSetting(settingName, settingValue); +} + +ADDON_STATUS CIptvSimpleAddon::CreateInstance(const kodi::addon::IInstanceInfo& instance, KODI_ADDON_INSTANCE_HDL& hdl) +{ + if (instance.IsType(ADDON_INSTANCE_PVR)) + { + IptvSimple* usedInstance = new IptvSimple(instance, m_settings); + if (!usedInstance->Initialise()) + { + delete usedInstance; + return ADDON_STATUS_PERMANENT_FAILURE; + } + + hdl = usedInstance; + + // Store this instance also on this class, currently support Kodi only one + // instance, for that it becomes stored here to interact e.g. about + // settings. In future becomes another way added. + m_usedInstances.emplace(std::make_pair(instance.GetID(), usedInstance)); + return ADDON_STATUS_OK; + } + + return ADDON_STATUS_UNKNOWN; +} + +void CIptvSimpleAddon::DestroyInstance(const kodi::addon::IInstanceInfo& instance, const KODI_ADDON_INSTANCE_HDL hdl) +{ + if (instance.IsType(ADDON_INSTANCE_PVR)) + { + const auto& it = m_usedInstances.find(instance.GetID()); + if (it != m_usedInstances.end()) + { + m_usedInstances.erase(it); + } + } +} + +ADDONCREATOR(CIptvSimpleAddon) diff --git a/src/addon.h b/src/addon.h new file mode 100644 index 000000000..c964ca547 --- /dev/null +++ b/src/addon.h @@ -0,0 +1,32 @@ +/* + * 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 + +#include +#include + +#include "iptvsimple/Settings.h" + +class IptvSimple; + +class ATTR_DLL_LOCAL CIptvSimpleAddon : public kodi::addon::CAddonBase +{ +public: + CIptvSimpleAddon() = default; + + ADDON_STATUS Create() override; + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) override; + ADDON_STATUS CreateInstance(const kodi::addon::IInstanceInfo& instance, KODI_ADDON_INSTANCE_HDL& hdl) override; + void DestroyInstance(const kodi::addon::IInstanceInfo& instance, const KODI_ADDON_INSTANCE_HDL hdl) override; + +private: + std::unordered_map m_usedInstances; + std::shared_ptr m_settings; +}; diff --git a/src/iptvsimple/CatchupController.cpp b/src/iptvsimple/CatchupController.cpp index 6a01687b1..87c16f5d7 100644 --- a/src/iptvsimple/CatchupController.cpp +++ b/src/iptvsimple/CatchupController.cpp @@ -9,7 +9,6 @@ #include "Channels.h" #include "Epg.h" -#include "Settings.h" #include "data/Channel.h" #include "utilities/Logger.h" #include "utilities/TimeUtils.h" @@ -25,8 +24,8 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -CatchupController::CatchupController(Epg& epg, std::mutex* mutex) - : m_epg(epg), m_mutex(mutex) {} +CatchupController::CatchupController(Epg& epg, std::mutex* mutex, std::shared_ptr& settings) + : m_epg(epg), m_mutex(mutex), m_settings(settings) {} void CatchupController::ProcessChannelForPlayback(const Channel& channel, std::map& catchupProperties) { @@ -38,7 +37,7 @@ void CatchupController::ProcessChannelForPlayback(const Channel& channel, std::m if (!m_fromEpgTag || m_controlsLiveStream) { EpgEntry* liveEpgEntry = GetLiveEPGEntry(channel); - if (m_controlsLiveStream && liveEpgEntry && !Settings::GetInstance().CatchupOnlyOnFinishedProgrammes()) + if (m_controlsLiveStream && liveEpgEntry && !m_settings->CatchupOnlyOnFinishedProgrammes()) { // Live timeshifting support with EPG entry UpdateProgrammeFrom(*liveEpgEntry, channel.GetTvgShift()); @@ -149,8 +148,8 @@ void CatchupController::ProcessEPGTagForVideoPlayback(const kodi::addon::PVREPGT m_catchupStartTime = epgTag.GetStartTime(); m_catchupEndTime = epgTag.GetEndTime(); - const time_t beginBuffer = Settings::GetInstance().GetCatchupWatchEpgBeginBufferSecs(); - const time_t endBuffer = Settings::GetInstance().GetCatchupWatchEpgEndBufferSecs(); + const time_t beginBuffer = m_settings->GetCatchupWatchEpgBeginBufferSecs(); + const time_t endBuffer = m_settings->GetCatchupWatchEpgEndBufferSecs(); m_timeshiftBufferStartTime = m_catchupStartTime - beginBuffer; m_catchupStartTime = m_timeshiftBufferStartTime; m_catchupEndTime += endBuffer; @@ -172,8 +171,8 @@ void CatchupController::ProcessEPGTagForVideoPlayback(const kodi::addon::PVREPGT m_timeshiftBufferStartTime = 0; m_timeshiftBufferOffset = 0; - m_catchupStartTime = m_catchupStartTime - Settings::GetInstance().GetCatchupWatchEpgBeginBufferSecs(); - m_catchupEndTime += Settings::GetInstance().GetCatchupWatchEpgEndBufferSecs(); + m_catchupStartTime = m_catchupStartTime - m_settings->GetCatchupWatchEpgBeginBufferSecs(); + m_catchupEndTime += m_settings->GetCatchupWatchEpgEndBufferSecs(); } if (m_catchupStartTime > 0) @@ -201,8 +200,8 @@ void CatchupController::SetCatchupInputStreamProperties(bool playbackAsLive, con catchupProperties.insert({"inputstream.ffmpegdirect.catchup_granularity", std::to_string(channel.GetCatchupGranularitySeconds())}); // TODO: Should also send programme start and duration potentially - // When doing this don't forget to add Settings::GetInstance().GetCatchupWatchEpgBeginBufferSecs() + Settings::GetInstance().GetCatchupWatchEpgEndBufferSecs(); - // if in video playback mode from epg, i.e. if (!Settings::GetInstance().CatchupPlayEpgAsLive() && m_playbackIsVideo)s + // When doing this don't forget to add m_settings->GetCatchupWatchEpgBeginBufferSecs() + m_settings->GetCatchupWatchEpgEndBufferSecs(); + // if in video playback mode from epg, i.e. if (!m_settings->CatchupPlayEpgAsLive() && m_playbackIsVideo)s Logger::Log(LEVEL_DEBUG, "default_url - %s", WebUtils::RedactUrl(channel.GetStreamURL()).c_str()); Logger::Log(LEVEL_DEBUG, "playback_as_live - %s", playbackAsLive ? "true" : "false"); @@ -221,7 +220,7 @@ StreamType CatchupController::StreamTypeLookup(const Channel& channel, bool from { StreamType streamType = m_streamManager.StreamTypeLookup(channel, GetStreamTestUrl(channel, fromEpg), GetStreamKey(channel, fromEpg)); - m_controlsLiveStream = StreamUtils::GetEffectiveInputStreamName(streamType, channel) == "inputstream.ffmpegdirect" && channel.CatchupSupportsTimeshifting(); + m_controlsLiveStream = StreamUtils::GetEffectiveInputStreamName(streamType, channel, m_settings) == "inputstream.ffmpegdirect" && channel.CatchupSupportsTimeshifting(); return streamType; } @@ -457,8 +456,8 @@ std::string CatchupController::GetCatchupUrl(const Channel& channel) const { duration = static_cast(m_programmeEndTime - m_programmeStartTime); - if (!Settings::GetInstance().CatchupPlayEpgAsLive() && m_playbackIsVideo) - duration += Settings::GetInstance().GetCatchupWatchEpgBeginBufferSecs() + Settings::GetInstance().GetCatchupWatchEpgEndBufferSecs(); + if (!m_settings->CatchupPlayEpgAsLive() && m_playbackIsVideo) + duration += m_settings->GetCatchupWatchEpgBeginBufferSecs() + m_settings->GetCatchupWatchEpgEndBufferSecs(); time_t timeNow = time(0); // cap duration to timeNow diff --git a/src/iptvsimple/CatchupController.h b/src/iptvsimple/CatchupController.h index bf62e18cb..3f52ebf9c 100644 --- a/src/iptvsimple/CatchupController.h +++ b/src/iptvsimple/CatchupController.h @@ -9,11 +9,13 @@ #include +#include "Settings.h" #include "data/Channel.h" #include "data/EpgEntry.h" #include "utilities/StreamUtils.h" #include "StreamManager.h" +#include #include #include @@ -25,7 +27,7 @@ namespace iptvsimple class CatchupController { public: - CatchupController(iptvsimple::Epg& epg, std::mutex* mutex); + CatchupController(iptvsimple::Epg& epg, std::mutex* mutex, std::shared_ptr& settings); void ProcessChannelForPlayback(const data::Channel& channel, std::map& catchupProperties); void ProcessEPGTagForTimeshiftedPlayback(const kodi::addon::PVREPGTag& epgTag, const data::Channel& channel, std::map& catchupProperties); @@ -73,5 +75,7 @@ namespace iptvsimple std::mutex* m_mutex = nullptr; StreamManager m_streamManager; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/ChannelGroups.cpp b/src/iptvsimple/ChannelGroups.cpp index 54a653530..f76e4103b 100644 --- a/src/iptvsimple/ChannelGroups.cpp +++ b/src/iptvsimple/ChannelGroups.cpp @@ -7,7 +7,6 @@ #include "ChannelGroups.h" -#include "Settings.h" #include "utilities/Logger.h" #include @@ -16,7 +15,7 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -ChannelGroups::ChannelGroups(const Channels& channels) : m_channels(channels) {} +ChannelGroups::ChannelGroups(const Channels& channels, std::shared_ptr& settings) : m_channels(channels), m_settings(settings) {} bool ChannelGroups::Init() { @@ -157,17 +156,17 @@ bool ChannelGroups::CheckChannelGroupAllowed(iptvsimple::data::ChannelGroup& new if (newChannelGroup.IsRadio()) { - if (Settings::GetInstance().GetRadioChannelGroupMode() == ChannelGroupMode::ALL_GROUPS) + if (m_settings->GetRadioChannelGroupMode() == ChannelGroupMode::ALL_GROUPS) return true; - customNameList = Settings::GetInstance().GetCustomRadioChannelGroupNameList(); + customNameList = m_settings->GetCustomRadioChannelGroupNameList(); } else { - if (Settings::GetInstance().GetTVChannelGroupMode() == ChannelGroupMode::ALL_GROUPS) + if (m_settings->GetTVChannelGroupMode() == ChannelGroupMode::ALL_GROUPS) return true; - customNameList = Settings::GetInstance().GetCustomTVChannelGroupNameList(); + customNameList = m_settings->GetCustomTVChannelGroupNameList(); } for (const std::string& groupName : customNameList) diff --git a/src/iptvsimple/ChannelGroups.h b/src/iptvsimple/ChannelGroups.h index 9c44df684..71e831c11 100644 --- a/src/iptvsimple/ChannelGroups.h +++ b/src/iptvsimple/ChannelGroups.h @@ -8,8 +8,10 @@ #pragma once #include "Channels.h" +#include "Settings.h" #include "data/ChannelGroup.h" +#include #include #include @@ -20,7 +22,7 @@ namespace iptvsimple class ChannelGroups { public: - ChannelGroups(const iptvsimple::Channels& channels); + ChannelGroups(const iptvsimple::Channels& channels, std::shared_ptr& settings); int GetChannelGroupsAmount() const; PVR_ERROR GetChannelGroups(kodi::addon::PVRChannelGroupsResultSet& results, bool radio) const; @@ -40,5 +42,7 @@ namespace iptvsimple std::vector m_channelGroups; bool m_channelGroupsLoadFailed = false; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Channels.cpp b/src/iptvsimple/Channels.cpp index 2d21d7b94..a9ccf9bd9 100644 --- a/src/iptvsimple/Channels.cpp +++ b/src/iptvsimple/Channels.cpp @@ -8,7 +8,6 @@ #include "Channels.h" #include "ChannelGroups.h" -#include "Settings.h" #include "utilities/FileUtils.h" #include "utilities/Logger.h" @@ -21,6 +20,10 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; +Channels::Channels(std::shared_ptr& settings) : m_settings(settings) +{ +} + bool Channels::Init() { Clear(); @@ -31,7 +34,7 @@ void Channels::Clear() { m_channels.clear(); m_channelsLoadFailed = false; - m_currentChannelNumber = Settings::GetInstance().GetStartChannelNumber(); + m_currentChannelNumber = m_settings->GetStartChannelNumber(); } int Channels::GetChannelsAmount() const diff --git a/src/iptvsimple/Channels.h b/src/iptvsimple/Channels.h index 320c689d6..371854bb8 100644 --- a/src/iptvsimple/Channels.h +++ b/src/iptvsimple/Channels.h @@ -7,8 +7,10 @@ #pragma once +#include "Settings.h" #include "data/Channel.h" +#include #include #include @@ -26,7 +28,7 @@ namespace iptvsimple class Channels { public: - Channels() = default; + Channels(std::shared_ptr& settings); bool Init(); @@ -51,5 +53,7 @@ namespace iptvsimple bool m_channelsLoadFailed = false; std::vector m_channels; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Epg.cpp b/src/iptvsimple/Epg.cpp index aa550c3ef..32f250973 100644 --- a/src/iptvsimple/Epg.cpp +++ b/src/iptvsimple/Epg.cpp @@ -25,8 +25,8 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; using namespace pugi; -Epg::Epg(kodi::addon::CInstancePVRClient* client, Channels& channels, Media& media) - : m_lastStart(0), m_lastEnd(0), m_channels(channels), m_media(media), m_client(client) +Epg::Epg(kodi::addon::CInstancePVRClient* client, Channels& channels, Media& media, std::shared_ptr& settings) + : m_lastStart(0), m_lastEnd(0), m_channels(channels), m_media(media), m_client(client), m_settings(settings) { FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + GENRE_DIR, GENRE_ADDON_DATA_BASE_DIR, true); @@ -38,14 +38,14 @@ Epg::Epg(kodi::addon::CInstancePVRClient* client, Channels& channels, Media& med bool Epg::Init(int epgMaxPastDays, int epgMaxFutureDays) { - m_xmltvLocation = Settings::GetInstance().GetEpgLocation(); - m_epgTimeShift = Settings::GetInstance().GetEpgTimeshiftSecs(); - m_tsOverride = Settings::GetInstance().GetTsOverride(); + m_xmltvLocation = m_settings->GetEpgLocation(); + m_epgTimeShift = m_settings->GetEpgTimeshiftSecs(); + m_tsOverride = m_settings->GetTsOverride(); SetEPGMaxPastDays(epgMaxPastDays); SetEPGMaxFutureDays(epgMaxFutureDays); - if (Settings::GetInstance().IsCatchupEnabled() || Settings::GetInstance().IsMediaEnabled()) + if (m_settings->IsCatchupEnabled() || m_settings->IsMediaEnabled()) { // Kodi may not load the data on each startup so we need to make sure it's loaded whether // or not kodi considers it necessary when either 1) we need the EPG logos or 2) for @@ -137,7 +137,7 @@ bool Epg::LoadEPG(time_t start, time_t end) LoadGenres(); - if (Settings::GetInstance().GetEpgLogosMode() != EpgLogosMode::IGNORE_XMLTV) + if (m_settings->GetEpgLogosMode() != EpgLogosMode::IGNORE_XMLTV) ApplyChannelsLogosFromEPG(); int milliseconds = std::chrono::duration_cast( @@ -154,11 +154,11 @@ bool Epg::GetXMLTVFileWithRetries(std::string& data) int count = 0; // Cache is only allowed if refresh mode is disabled - bool useEPGCache = Settings::GetInstance().GetM3URefreshMode() != RefreshMode::DISABLED ? false : Settings::GetInstance().UseEPGCache(); + bool useEPGCache = m_settings->GetM3URefreshMode() != RefreshMode::DISABLED ? false : m_settings->UseEPGCache(); while (count < 3) // max 3 tries { - if ((bytesRead = FileUtils::GetCachedFileContents(XMLTV_CACHE_FILENAME, m_xmltvLocation, data, useEPGCache)) != 0) + if ((bytesRead = FileUtils::GetCachedFileContents(m_settings, XMLTV_CACHE_FILENAME, m_xmltvLocation, data, useEPGCache)) != 0) break; Logger::Log(LEVEL_ERROR, "%s - Unable to load EPG file '%s': file is missing or empty. :%dth try.", __FUNCTION__, m_xmltvLocation.c_str(), ++count); @@ -317,7 +317,7 @@ void Epg::LoadEpgEntries(const xml_node& rootElement, int start, int end) continue; } - EpgEntry entry; + EpgEntry entry{m_settings}; if (entry.UpdateFrom(programmeNode, id, start, end, minShiftTime, maxShiftTime)) { count++; @@ -332,9 +332,9 @@ void Epg::LoadEpgEntries(const xml_node& rootElement, int start, int end) void Epg::ReloadEPG() { - m_xmltvLocation = Settings::GetInstance().GetEpgLocation(); - m_epgTimeShift = Settings::GetInstance().GetEpgTimeshiftSecs(); - m_tsOverride = Settings::GetInstance().GetTsOverride(); + m_xmltvLocation = m_settings->GetEpgLocation(); + m_epgTimeShift = m_settings->GetEpgTimeshiftSecs(); + m_tsOverride = m_settings->GetTsOverride(); m_lastStart = 0; m_lastEnd = 0; @@ -401,9 +401,9 @@ PVR_ERROR Epg::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi:: namespace { - bool TvgIdMatchesCaseOrNoCase(const std::string& idOne, const std::string& idTwo) + bool TvgIdMatchesCaseOrNoCase(const std::string& idOne, const std::string& idTwo, bool ignoreCaseForEpgChannelIds) { - if (Settings::GetInstance().IgnoreCaseForEpgChannelIds()) + if (ignoreCaseForEpgChannelIds) return StringUtils::EqualsNoCase(idOne, idTwo); else return idOne == idTwo; @@ -414,7 +414,7 @@ ChannelEpg* Epg::FindEpgForChannel(const std::string& id) const { for (auto& myChannelEpg : m_channelEpgs) { - if (TvgIdMatchesCaseOrNoCase(myChannelEpg.GetId(), id)) + if (TvgIdMatchesCaseOrNoCase(myChannelEpg.GetId(), id, m_settings->IgnoreCaseForEpgChannelIds())) return const_cast(&myChannelEpg); } @@ -425,7 +425,7 @@ ChannelEpg* Epg::FindEpgForChannel(const Channel& channel) const { for (auto& myChannelEpg : m_channelEpgs) { - if (TvgIdMatchesCaseOrNoCase(myChannelEpg.GetId(), channel.GetTvgId())) + if (TvgIdMatchesCaseOrNoCase(myChannelEpg.GetId(), channel.GetTvgId(), m_settings->IgnoreCaseForEpgChannelIds())) return const_cast(&myChannelEpg); } @@ -455,7 +455,7 @@ ChannelEpg* Epg::FindEpgForMediaEntry(const MediaEntry& mediaEntry) const { for (auto& myChannelEpg : m_channelEpgs) { - if (TvgIdMatchesCaseOrNoCase(myChannelEpg.GetId(), mediaEntry.GetTvgId())) + if (TvgIdMatchesCaseOrNoCase(myChannelEpg.GetId(), mediaEntry.GetTvgId(), m_settings->IgnoreCaseForEpgChannelIds())) return const_cast(&myChannelEpg); } @@ -493,11 +493,11 @@ void Epg::ApplyChannelsLogosFromEPG() continue; // 1 - prefer icon from playlist - if (!channel.GetIconPath().empty() && Settings::GetInstance().GetEpgLogosMode() == EpgLogosMode::PREFER_M3U) + if (!channel.GetIconPath().empty() && m_settings->GetEpgLogosMode() == EpgLogosMode::PREFER_M3U) continue; // 2 - prefer icon from epg - if (!channelEpg->GetIconPath().empty() && Settings::GetInstance().GetEpgLogosMode() == EpgLogosMode::PREFER_XMLTV) + if (!channelEpg->GetIconPath().empty() && m_settings->GetEpgLogosMode() == EpgLogosMode::PREFER_XMLTV) { m_channels.GetChannel(channel.GetUniqueId())->SetIconPath(channelEpg->GetIconPath()); updated = true; @@ -510,11 +510,11 @@ void Epg::ApplyChannelsLogosFromEPG() bool Epg::LoadGenres() { - if (!FileUtils::FileExists(Settings::GetInstance().GetGenresLocation())) + if (!FileUtils::FileExists(m_settings->GetGenresLocation())) return false; std::string data; - FileUtils::GetFileContents(Settings::GetInstance().GetGenresLocation(), data); + FileUtils::GetFileContents(m_settings->GetGenresLocation(), data); if (data.empty()) return false; diff --git a/src/iptvsimple/Epg.h b/src/iptvsimple/Epg.h index 4d53d397c..a6bd9f76b 100644 --- a/src/iptvsimple/Epg.h +++ b/src/iptvsimple/Epg.h @@ -11,8 +11,10 @@ #include "Media.h" #include "Settings.h" #include "data/ChannelEpg.h" +#include "data/EpgEntry.h" #include "data/EpgGenre.h" +#include #include #include @@ -36,7 +38,7 @@ namespace iptvsimple class Epg { public: - Epg(kodi::addon::CInstancePVRClient* client, iptvsimple::Channels& channels, iptvsimple::Media& media); + Epg(kodi::addon::CInstancePVRClient* client, iptvsimple::Channels& channels, iptvsimple::Media& media, std::shared_ptr& settings); bool Init(int epgMaxPastDays, int epgMaxFutureDays); @@ -84,5 +86,7 @@ namespace iptvsimple std::vector m_genreMappings; kodi::addon::CInstancePVRClient* m_client; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Media.cpp b/src/iptvsimple/Media.cpp index 484f1106d..f45656c68 100644 --- a/src/iptvsimple/Media.cpp +++ b/src/iptvsimple/Media.cpp @@ -8,7 +8,7 @@ #include "Media.h" -#include "../PVRIptvData.h" +#include "../IptvSimple.h" #include "utilities/Logger.h" #include @@ -18,7 +18,7 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; using namespace kodi::tools; -Media::Media() +Media::Media(std::shared_ptr& settings) : m_settings(settings) { } @@ -84,7 +84,7 @@ bool Media::AddMediaEntry(MediaEntry& mediaEntry) MediaEntry Media::GetMediaEntry(const std::string& mediaEntryId) const { - MediaEntry entry; + MediaEntry entry{m_settings}; auto mediaEntryPair = m_mediaIdMap.find(mediaEntryId); if (mediaEntryPair != m_mediaIdMap.end()) diff --git a/src/iptvsimple/Media.h b/src/iptvsimple/Media.h index 2d3581189..977800282 100644 --- a/src/iptvsimple/Media.h +++ b/src/iptvsimple/Media.h @@ -19,7 +19,7 @@ namespace iptvsimple class ATTR_DLL_LOCAL Media { public: - Media(); + Media(std::shared_ptr& settings); void GetMedia(std::vector& kodiRecordings); int GetNumMedia() const; void Clear(); @@ -38,5 +38,7 @@ namespace iptvsimple std::unordered_map m_mediaIdMap; bool m_haveMediaTypes = false; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/PlaylistLoader.cpp b/src/iptvsimple/PlaylistLoader.cpp index bd41ac0ea..c80a97901 100644 --- a/src/iptvsimple/PlaylistLoader.cpp +++ b/src/iptvsimple/PlaylistLoader.cpp @@ -28,13 +28,13 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; PlaylistLoader::PlaylistLoader(kodi::addon::CInstancePVRClient* client, Channels& channels, - ChannelGroups& channelGroups, Providers& providers, Media& media) - : m_channelGroups(channelGroups), m_channels(channels), m_providers(providers), m_media(media), m_client(client) { } + ChannelGroups& channelGroups, Providers& providers, Media& media, std::shared_ptr& settings) + : m_channelGroups(channelGroups), m_channels(channels), m_providers(providers), m_media(media), m_client(client), m_settings(settings) { } bool PlaylistLoader::Init() { - m_m3uLocation = Settings::GetInstance().GetM3ULocation(); - m_logoLocation = Settings::GetInstance().GetLogoLocation(); + m_m3uLocation = m_settings->GetM3ULocation(); + m_logoLocation = m_settings->GetLogoLocation(); return true; } @@ -50,10 +50,10 @@ bool PlaylistLoader::LoadPlayList() } // Cache is only allowed if refresh mode is disabled - bool useM3UCache = Settings::GetInstance().GetM3URefreshMode() != RefreshMode::DISABLED ? false : Settings::GetInstance().UseM3UCache(); + bool useM3UCache = m_settings->GetM3URefreshMode() != RefreshMode::DISABLED ? false : m_settings->UseM3UCache(); std::string playlistContent; - if (!FileUtils::GetCachedFileContents(M3U_CACHE_FILENAME, m_m3uLocation, playlistContent, useM3UCache)) + if (!FileUtils::GetCachedFileContents(m_settings, M3U_CACHE_FILENAME, m_m3uLocation, playlistContent, useM3UCache)) { Logger::Log(LEVEL_ERROR, "%s - Unable to load playlist cache file '%s': file is missing or empty.", __FUNCTION__, m_m3uLocation.c_str()); return false; @@ -66,13 +66,13 @@ bool PlaylistLoader::LoadPlayList() bool isRealTime = true; bool isMediaEntry = false; int epgTimeShift = 0; - int catchupCorrectionSecs = Settings::GetInstance().GetCatchupCorrectionSecs(); + int catchupCorrectionSecs = m_settings->GetCatchupCorrectionSecs(); std::vector currentChannelGroupIdList; bool channelHadGroups = false; bool xeevCatchup = false; - Channel tmpChannel; - MediaEntry tmpMediaEntry; + Channel tmpChannel{m_settings}; + MediaEntry tmpMediaEntry{m_settings}; std::string line; while (std::getline(stream, line)) @@ -128,7 +128,7 @@ bool PlaylistLoader::LoadPlayList() size_t found = tvgUrl.find(','); if (found != std::string::npos) tvgUrl = tvgUrl.substr(0, found); - Settings::GetInstance().SetTvgUrl(tvgUrl); + m_settings->SetTvgUrl(tvgUrl); continue; } @@ -186,7 +186,7 @@ bool PlaylistLoader::LoadPlayList() { Logger::Log(LEVEL_DEBUG, "%s - Adding channel '%s' with URL: '%s'", __FUNCTION__, tmpChannel.GetChannelName().c_str(), line.c_str()); - if ((isRealTime || !Settings::GetInstance().IsMediaEnabled() || !Settings::GetInstance().ShowVodAsRecordings()) && !isMediaEntry) + if ((isRealTime || !m_settings->IsMediaEnabled() || !m_settings->ShowVodAsRecordings()) && !isMediaEntry) { tmpChannel.AddProperty(PVR_STREAM_PROPERTY_ISREALTIMESTREAM, "true"); @@ -315,7 +315,7 @@ std::string PlaylistLoader::ParseIntoChannel(const std::string& line, Channel& c if (strChnlNo.empty()) strChnlNo = ReadMarkerValue(infoLine, CHANNEL_NUMBER_MARKER); - if (!strChnlNo.empty() && !Settings::GetInstance().NumberChannelsByM3uOrderOnly()) + if (!strChnlNo.empty() && !m_settings->NumberChannelsByM3uOrderOnly()) { size_t found = strChnlNo.find('.'); if (found != std::string::npos) @@ -340,7 +340,7 @@ std::string PlaylistLoader::ParseIntoChannel(const std::string& line, Channel& c strCatchupSource = m_m3uHeaderStrings.m_catchupSource; channel.SetTvgShift(static_cast(tvgShiftDecimal * 3600.0)); channel.SetRadio(isRadio); - if (Settings::GetInstance().GetLogoPathType() == PathType::LOCAL_PATH && Settings::GetInstance().UseLocalLogosOnlyIgnoreM3U()) + if (m_settings->GetLogoPathType() == PathType::LOCAL_PATH && m_settings->UseLocalLogosOnlyIgnoreM3U()) channel.SetIconPathFromTvgLogo("", channelName); else channel.SetIconPathFromTvgLogo(strTvgLogo, channelName); @@ -399,7 +399,7 @@ std::string PlaylistLoader::ParseIntoChannel(const std::string& line, Channel& c else if (siptvTimeshiftDays > 0) channel.SetCatchupDays(siptvTimeshiftDays); else - channel.SetCatchupDays(Settings::GetInstance().GetCatchupDays()); + channel.SetCatchupDays(m_settings->GetCatchupDays()); // We also need to support the timeshift="days" tag from siptv // this was used before the catchup tags were introduced @@ -410,8 +410,8 @@ std::string PlaylistLoader::ParseIntoChannel(const std::string& line, Channel& c channel.SetHasCatchup(true); } - if (strProviderName.empty() && Settings::GetInstance().HasDefaultProviderName()) - strProviderName = Settings::GetInstance().GetDefaultProviderName(); + if (strProviderName.empty() && m_settings->HasDefaultProviderName()) + strProviderName = m_settings->GetDefaultProviderName(); auto provider = m_providers.AddProvider(strProviderName); if (provider) @@ -519,7 +519,7 @@ void PlaylistLoader::ParseSinglePropertyIntoChannel(const std::string& line, Cha void PlaylistLoader::ReloadPlayList() { - m_m3uLocation = Settings::GetInstance().GetM3ULocation(); + m_m3uLocation = m_settings->GetM3ULocation(); m_channels.Clear(); m_channelGroups.Clear(); diff --git a/src/iptvsimple/PlaylistLoader.h b/src/iptvsimple/PlaylistLoader.h index 8b18ad29d..d87b27ada 100644 --- a/src/iptvsimple/PlaylistLoader.h +++ b/src/iptvsimple/PlaylistLoader.h @@ -11,7 +11,9 @@ #include "ChannelGroups.h" #include "Providers.h" #include "Media.h" +#include "Settings.h" +#include #include #include @@ -64,7 +66,7 @@ namespace iptvsimple public: PlaylistLoader(kodi::addon::CInstancePVRClient* client, iptvsimple::Channels& channels, iptvsimple::ChannelGroups& channelGroups, iptvsimple::Providers& providers, - iptvsimple::Media& media); + iptvsimple::Media& media, std::shared_ptr& setting); bool Init(); @@ -88,5 +90,7 @@ namespace iptvsimple kodi::addon::CInstancePVRClient* m_client; M3UHeaderStrings m_m3uHeaderStrings; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Providers.cpp b/src/iptvsimple/Providers.cpp index cba071cb4..97c5eb4e5 100644 --- a/src/iptvsimple/Providers.cpp +++ b/src/iptvsimple/Providers.cpp @@ -8,7 +8,7 @@ #include "Providers.h" -#include "../PVRIptvData.h" +#include "../IptvSimple.h" #include "utilities/Logger.h" #include "utilities/FileUtils.h" #include "utilities/XMLUtils.h" @@ -22,7 +22,7 @@ using namespace iptvsimple::utilities; using namespace kodi::tools; using namespace pugi; -Providers::Providers() +Providers::Providers(std::shared_ptr& settings) : m_settings(settings) { } @@ -32,7 +32,7 @@ bool Providers::Init() FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + PROVIDER_DIR, PROVIDER_ADDON_DATA_BASE_DIR, true); - std::string providerMappingsFile = Settings::GetInstance().GetProviderNameMapFile(); + std::string providerMappingsFile = m_settings->GetProviderNameMapFile(); if (LoadProviderMappingFile(providerMappingsFile)) Logger::Log(LEVEL_INFO, "%s - Loaded '%d' providers mappings", __func__, m_providerMappingsMap.size()); else diff --git a/src/iptvsimple/Providers.h b/src/iptvsimple/Providers.h index d6e57a385..efae103ad 100644 --- a/src/iptvsimple/Providers.h +++ b/src/iptvsimple/Providers.h @@ -27,7 +27,7 @@ namespace iptvsimple class ATTR_DLL_LOCAL Providers { public: - Providers(); + Providers(std::shared_ptr& settings); bool Init(); @@ -53,5 +53,7 @@ namespace iptvsimple std::unordered_map> m_providersNameMap; std::unordered_map m_providerMappingsMap; + + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Settings.cpp b/src/iptvsimple/Settings.cpp index 100513867..5fcea8908 100644 --- a/src/iptvsimple/Settings.cpp +++ b/src/iptvsimple/Settings.cpp @@ -159,15 +159,15 @@ void Settings::ReloadAddonSettings() ReadFromAddon(m_userPath, m_clientPath); } -ADDON_STATUS Settings::SetValue(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +ADDON_STATUS Settings::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) { // reset cache and restart addon - std::string strFile = FileUtils::GetUserDataAddonFilePath(M3U_CACHE_FILENAME); + std::string strFile = FileUtils::GetUserDataAddonFilePath(GetUserPath(), M3U_CACHE_FILENAME); if (FileUtils::FileExists(strFile)) FileUtils::DeleteFile(strFile); - strFile = FileUtils::GetUserDataAddonFilePath(XMLTV_CACHE_FILENAME); + strFile = FileUtils::GetUserDataAddonFilePath(GetUserPath(), XMLTV_CACHE_FILENAME); if (FileUtils::FileExists(strFile)) FileUtils::DeleteFile(strFile); diff --git a/src/iptvsimple/Settings.h b/src/iptvsimple/Settings.h index b7ee18032..06af4dcae 100644 --- a/src/iptvsimple/Settings.h +++ b/src/iptvsimple/Settings.h @@ -72,14 +72,10 @@ namespace iptvsimple class Settings { public: - /** - * Singleton getter for the instance - */ - static Settings& GetInstance() - { - static Settings settings; - return settings; - } + Settings() {}; + + void ReadSettings(); + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue); void ReadFromAddon(const std::string& userPath, const std::string& clientPath); void ReloadAddonSettings(); @@ -181,10 +177,6 @@ namespace iptvsimple std::vector& GetCustomRadioChannelGroupNameList() { return m_customRadioChannelGroupNameList; } private: - Settings() = default; - - Settings(Settings const&) = delete; - void operator=(Settings const&) = delete; template V SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue, T& currentValue, V returnValueIfChanged, V defaultReturnValue) diff --git a/src/iptvsimple/data/BaseEntry.h b/src/iptvsimple/data/BaseEntry.h index c8f75c1c3..c30ef7b4b 100644 --- a/src/iptvsimple/data/BaseEntry.h +++ b/src/iptvsimple/data/BaseEntry.h @@ -9,7 +9,9 @@ #pragma once #include "EpgGenre.h" +#include "../Settings.h" +#include #include #include @@ -116,6 +118,8 @@ namespace iptvsimple bool m_new = false; bool m_premiere = false; + + std::shared_ptr m_settings; }; } //namespace data } //namespace iptvsimple diff --git a/src/iptvsimple/data/Channel.cpp b/src/iptvsimple/data/Channel.cpp index 487cfd71a..97554f3aa 100644 --- a/src/iptvsimple/data/Channel.cpp +++ b/src/iptvsimple/data/Channel.cpp @@ -130,7 +130,7 @@ void Channel::SetIconPathFromTvgLogo(const std::string& tvgLogo, std::string& ch kodi::UnknownToUTF8(m_iconPath, m_iconPath); // urlencode channel logo when set from channel name and source is Remote Path, append extension as channel wouldn't cover this - if (logoSetFromChannelName && Settings::GetInstance().GetLogoPathType() == PathType::REMOTE_PATH) + if (logoSetFromChannelName && m_settings->GetLogoPathType() == PathType::REMOTE_PATH) { m_iconPath = utilities::WebUtils::UrlEncode(m_iconPath); } @@ -164,7 +164,7 @@ void Channel::SetIconPathFromTvgLogo(const std::string& tvgLogo, std::string& ch if (m_iconPath.find("://") == std::string::npos) { - const std::string& logoLocation = Settings::GetInstance().GetLogoLocation(); + const std::string& logoLocation = m_settings->GetLogoLocation(); // If the file does not exist it must be relative if (!logoLocation.empty() && !kodi::vfs::FileExists(m_iconPath)) { @@ -183,27 +183,27 @@ void Channel::SetStreamURL(const std::string& url) if (StringUtils::StartsWith(url, HTTP_PREFIX) || StringUtils::StartsWith(url, HTTPS_PREFIX)) { - if (!Settings::GetInstance().GetDefaultUserAgent().empty() && GetProperty("http-user-agent").empty()) - AddProperty("http-user-agent", Settings::GetInstance().GetDefaultUserAgent()); + if (!m_settings->GetDefaultUserAgent().empty() && GetProperty("http-user-agent").empty()) + AddProperty("http-user-agent", m_settings->GetDefaultUserAgent()); TryToAddPropertyAsHeader("http-user-agent", "user-agent"); TryToAddPropertyAsHeader("http-referrer", "referer"); // spelling differences are correct } - if (Settings::GetInstance().TransformMulticastStreamUrls() && + if (m_settings->TransformMulticastStreamUrls() && (StringUtils::StartsWith(url, UDP_MULTICAST_PREFIX) || StringUtils::StartsWith(url, RTP_MULTICAST_PREFIX))) { const std::string typePath = StringUtils::StartsWith(url, "rtp") ? "/rtp/" : "/udp/"; - m_streamURL = "http://" + Settings::GetInstance().GetUdpxyHost() + ":" + std::to_string(Settings::GetInstance().GetUdpxyPort()) + typePath + url.substr(UDP_MULTICAST_PREFIX.length()); + m_streamURL = "http://" + m_settings->GetUdpxyHost() + ":" + std::to_string(m_settings->GetUdpxyPort()) + typePath + url.substr(UDP_MULTICAST_PREFIX.length()); Logger::Log(LEVEL_DEBUG, "%s - Transformed multicast stream URL to local relay url: %s", __FUNCTION__, m_streamURL.c_str()); } - if (!Settings::GetInstance().GetDefaultInputstream().empty() && GetProperty(PVR_STREAM_PROPERTY_INPUTSTREAM).empty()) - AddProperty(PVR_STREAM_PROPERTY_INPUTSTREAM, Settings::GetInstance().GetDefaultInputstream()); + if (!m_settings->GetDefaultInputstream().empty() && GetProperty(PVR_STREAM_PROPERTY_INPUTSTREAM).empty()) + AddProperty(PVR_STREAM_PROPERTY_INPUTSTREAM, m_settings->GetDefaultInputstream()); - if (!Settings::GetInstance().GetDefaultMimeType().empty() && GetProperty(PVR_STREAM_PROPERTY_MIMETYPE).empty()) - AddProperty(PVR_STREAM_PROPERTY_MIMETYPE, Settings::GetInstance().GetDefaultMimeType()); + if (!m_settings->GetDefaultMimeType().empty() && GetProperty(PVR_STREAM_PROPERTY_MIMETYPE).empty()) + AddProperty(PVR_STREAM_PROPERTY_MIMETYPE, m_settings->GetDefaultMimeType()); m_inputStreamName = GetProperty(PVR_STREAM_PROPERTY_INPUTSTREAM); } @@ -236,8 +236,8 @@ void Channel::TryToAddPropertyAsHeader(const std::string& propertyName, const st bool Channel::ChannelTypeAllowsGroupsOnly() const { - return ((m_radio && Settings::GetInstance().AllowRadioChannelGroupsOnly()) || - (!m_radio && Settings::GetInstance().AllowTVChannelGroupsOnly())); + return ((m_radio && m_settings->AllowRadioChannelGroupsOnly()) || + (!m_radio && m_settings->AllowTVChannelGroupsOnly())); } void Channel::SetCatchupDays(int catchupDays) @@ -245,20 +245,20 @@ void Channel::SetCatchupDays(int catchupDays) if (catchupDays > 0 || catchupDays == IGNORE_CATCHUP_DAYS) m_catchupDays = catchupDays; else - m_catchupDays = Settings::GetInstance().GetCatchupDays(); + m_catchupDays = m_settings->GetCatchupDays(); } bool Channel::IsCatchupSupported() const { - return Settings::GetInstance().IsCatchupEnabled() && m_hasCatchup && !m_catchupSource.empty(); + return m_settings->IsCatchupEnabled() && m_hasCatchup && !m_catchupSource.empty(); } bool Channel::SupportsLiveStreamTimeshifting() const { - return Settings::GetInstance().IsTimeshiftEnabled() && GetProperty(PVR_STREAM_PROPERTY_ISREALTIMESTREAM) == "true" && - (Settings::GetInstance().IsTimeshiftEnabledAll() || - (Settings::GetInstance().IsTimeshiftEnabledHttp() && StringUtils::StartsWith(m_streamURL, "http")) || - (Settings::GetInstance().IsTimeshiftEnabledUdp() && StringUtils::StartsWith(m_streamURL, "udp")) + return m_settings->IsTimeshiftEnabled() && GetProperty(PVR_STREAM_PROPERTY_ISREALTIMESTREAM) == "true" && + (m_settings->IsTimeshiftEnabledAll() || + (m_settings->IsTimeshiftEnabledHttp() && StringUtils::StartsWith(m_streamURL, "http")) || + (m_settings->IsTimeshiftEnabledUdp() && StringUtils::StartsWith(m_streamURL, "udp")) ); } @@ -335,30 +335,30 @@ void Channel::ConfigureCatchupMode() protocolOptions = m_streamURL.substr(found, m_streamURL.length()); } - if (Settings::GetInstance().GetAllChannelsCatchupMode() != CatchupMode::DISABLED) + if (m_settings->GetAllChannelsCatchupMode() != CatchupMode::DISABLED) { bool overrideCatchupMode = false; - if (Settings::GetInstance().GetCatchupOverrideMode() == CatchupOverrideMode::WITHOUT_TAGS && + if (m_settings->GetCatchupOverrideMode() == CatchupOverrideMode::WITHOUT_TAGS && (m_catchupMode == CatchupMode::DISABLED || m_catchupMode == CatchupMode::TIMESHIFT)) { // As CatchupMode::TIMESHIFT is obsolete and some providers use it // incorrectly we allow this setting to override it overrideCatchupMode = true; } - else if (Settings::GetInstance().GetCatchupOverrideMode() == CatchupOverrideMode::WITH_TAGS && + else if (m_settings->GetCatchupOverrideMode() == CatchupOverrideMode::WITH_TAGS && m_catchupMode != CatchupMode::DISABLED) { overrideCatchupMode = true; } - else if (Settings::GetInstance().GetCatchupOverrideMode() == CatchupOverrideMode::ALL_CHANNELS) + else if (m_settings->GetCatchupOverrideMode() == CatchupOverrideMode::ALL_CHANNELS) { overrideCatchupMode = true; } if (overrideCatchupMode) { - m_catchupMode = Settings::GetInstance().GetAllChannelsCatchupMode(); + m_catchupMode = m_settings->GetAllChannelsCatchupMode(); m_hasCatchup = true; } } @@ -436,9 +436,9 @@ bool Channel::GenerateAppendCatchupSource(const std::string& url) } else { - if (!Settings::GetInstance().GetCatchupQueryFormat().empty()) + if (!m_settings->GetCatchupQueryFormat().empty()) { - m_catchupSource = url + Settings::GetInstance().GetCatchupQueryFormat(); + m_catchupSource = url + m_settings->GetCatchupQueryFormat(); return true; } } diff --git a/src/iptvsimple/data/Channel.h b/src/iptvsimple/data/Channel.h index 13dec6ee7..f7da62170 100644 --- a/src/iptvsimple/data/Channel.h +++ b/src/iptvsimple/data/Channel.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -29,6 +30,8 @@ namespace iptvsimple constexpr int IGNORE_CATCHUP_DAYS = -1; + class Settings; + namespace data { static const std::string CHANNEL_LOGO_EXTENSION = ".png"; @@ -38,7 +41,7 @@ namespace iptvsimple public: static const std::string GetCatchupModeText(const CatchupMode& catchupMode); - Channel() = default; + Channel(std::shared_ptr& settings) : m_settings(settings) {}; Channel(const Channel &c) : m_radio(c.IsRadio()), m_uniqueId(c.GetUniqueId()), m_channelNumber(c.GetChannelNumber()), m_subChannelNumber(c.GetSubChannelNumber()), m_encryptionSystem(c.GetEncryptionSystem()), m_tvgShift(c.GetTvgShift()), m_channelName(c.GetChannelName()), @@ -48,7 +51,7 @@ namespace iptvsimple m_catchupSourceTerminates(c.CatchupSourceTerminates()), m_catchupGranularitySeconds(c.GetCatchupGranularitySeconds()), m_catchupCorrectionSecs(c.GetCatchupCorrectionSecs()), m_tvgId(c.GetTvgId()), m_tvgName(c.GetTvgName()), m_providerUniqueId(c.GetProviderUniqueId()), m_properties(c.GetProperties()), - m_inputStreamName(c.GetInputStreamName()) {}; + m_inputStreamName(c.GetInputStreamName()) { m_settings = c.GetSettings(); }; ~Channel() = default; bool IsRadio() const { return m_radio; } @@ -136,6 +139,8 @@ namespace iptvsimple bool ChannelTypeAllowsGroupsOnly() const; + const std::shared_ptr& GetSettings() const { return m_settings; } + private: void RemoveProperty(const std::string& propName); void TryToAddPropertyAsHeader(const std::string& propertyName, const std::string& headerName); @@ -169,6 +174,8 @@ namespace iptvsimple std::map m_properties; std::string m_inputStreamName; + + std::shared_ptr m_settings; }; } //namespace data } //namespace iptvsimple diff --git a/src/iptvsimple/data/ChannelEpg.h b/src/iptvsimple/data/ChannelEpg.h index 57c49e73f..27c6aab01 100644 --- a/src/iptvsimple/data/ChannelEpg.h +++ b/src/iptvsimple/data/ChannelEpg.h @@ -40,7 +40,10 @@ namespace iptvsimple void SetIconPath(const std::string& value) { m_iconPath = value; } std::map& GetEpgEntries() { return m_epgEntries; } - void AddEpgEntry(const EpgEntry& epgEntry) { m_epgEntries[epgEntry.GetStartTime()] = epgEntry; } + void AddEpgEntry(const EpgEntry& epgEntry) + { + m_epgEntries[epgEntry.GetStartTime()] = epgEntry; + } bool UpdateFrom(const pugi::xml_node& channelNode, iptvsimple::Channels& channels, iptvsimple::Media& media); bool CombineNamesAndIconPathFrom(const ChannelEpg& right); diff --git a/src/iptvsimple/data/EpgEntry.cpp b/src/iptvsimple/data/EpgEntry.cpp index bcf0b2792..2041b574d 100644 --- a/src/iptvsimple/data/EpgEntry.cpp +++ b/src/iptvsimple/data/EpgEntry.cpp @@ -40,7 +40,7 @@ void EpgEntry::UpdateTo(kodi::addon::PVREPGTag& left, int iChannelUid, int timeS if (SetEpgGenre(genreMappings)) { left.SetGenreType(m_genreType); - if (Settings::GetInstance().UseEpgGenreTextWhenMapping()) + if (m_settings->UseEpgGenreTextWhenMapping()) { //Setting this value in sub type allows custom text to be displayed //while still sending the type used for EPG colour diff --git a/src/iptvsimple/data/EpgEntry.h b/src/iptvsimple/data/EpgEntry.h index 761cc4e3a..1556e88d0 100644 --- a/src/iptvsimple/data/EpgEntry.h +++ b/src/iptvsimple/data/EpgEntry.h @@ -26,6 +26,12 @@ namespace iptvsimple class EpgEntry : public BaseEntry { public: + EpgEntry() {}; + EpgEntry(std::shared_ptr settings) + { + m_settings = settings; + }; + int GetBroadcastId() const { return m_broadcastId; } void SetBroadcastId(int value) { m_broadcastId = value; } diff --git a/src/iptvsimple/data/MediaEntry.cpp b/src/iptvsimple/data/MediaEntry.cpp index c07e0468a..510a3ab2e 100644 --- a/src/iptvsimple/data/MediaEntry.cpp +++ b/src/iptvsimple/data/MediaEntry.cpp @@ -134,11 +134,11 @@ std::string GetEpisodePrefix(int episodeNumber) return {}; } -std::string CreateTitle(const std::string& title, int seasonNumber, int episodeNumber) +std::string CreateTitle(const std::string& title, int seasonNumber, int episodeNumber, std::shared_ptr settings) { std::string newTitle; - if (Settings::GetInstance().IncludeShowInfoInMediaTitle() && + if (settings->IncludeShowInfoInMediaTitle() && (seasonNumber != EPG_TAG_INVALID_SERIES_EPISODE || episodeNumber != EPG_TAG_INVALID_SERIES_EPISODE)) { @@ -179,7 +179,7 @@ std::string FixPath(const std::string& path) void MediaEntry::UpdateTo(kodi::addon::PVRRecording& left, bool isInVirtualMediaEntryFolder, bool haveMediaTypes) { - left.SetTitle(CreateTitle(m_title, m_seasonNumber, m_episodeNumber)); + left.SetTitle(CreateTitle(m_title, m_seasonNumber, m_episodeNumber, m_settings)); left.SetPlotOutline(m_plotOutline); left.SetPlot(m_plot); // left.SetCast(m_cast); @@ -222,9 +222,9 @@ void MediaEntry::UpdateTo(kodi::addon::PVRRecording& left, bool isInVirtualMedia left.SetSizeInBytes(m_sizeInBytes); std::string newDirectory = FixPath(m_directory); - if (Settings::GetInstance().GroupMediaByTitle() && isInVirtualMediaEntryFolder) + if (m_settings->GroupMediaByTitle() && isInVirtualMediaEntryFolder) { - if (Settings::GetInstance().GroupMediaBySeason() && m_seasonNumber != EPG_TAG_INVALID_SERIES_EPISODE) + if (m_settings->GroupMediaBySeason() && m_seasonNumber != EPG_TAG_INVALID_SERIES_EPISODE) newDirectory = StringUtils::Format("%s%s/%s/", newDirectory.c_str(), m_title.c_str(), GetSeasonPrefix(m_seasonNumber).c_str()); else newDirectory = StringUtils::Format("%s%s/", newDirectory.c_str(), m_title.c_str()); diff --git a/src/iptvsimple/data/MediaEntry.h b/src/iptvsimple/data/MediaEntry.h index b8c8cab8d..cb71f186d 100644 --- a/src/iptvsimple/data/MediaEntry.h +++ b/src/iptvsimple/data/MediaEntry.h @@ -23,6 +23,11 @@ namespace iptvsimple class ATTR_DLL_LOCAL MediaEntry : public BaseEntry { public: + MediaEntry(std::shared_ptr settings) + { + m_settings = settings; + }; + const std::string& GetMediaEntryId() const { return m_mediaEntryId; } void SetMediaEntryId(const std::string& value) { m_mediaEntryId = value; } diff --git a/src/iptvsimple/utilities/FileUtils.cpp b/src/iptvsimple/utilities/FileUtils.cpp index c98aee587..d90d2614d 100644 --- a/src/iptvsimple/utilities/FileUtils.cpp +++ b/src/iptvsimple/utilities/FileUtils.cpp @@ -40,9 +40,9 @@ std::string FileUtils::PathCombine(const std::string& path, const std::string& f return result; } -std::string FileUtils::GetUserDataAddonFilePath(const std::string& fileName) +std::string FileUtils::GetUserDataAddonFilePath(const std::string& userFilePath, const std::string& fileName) { - return PathCombine(Settings::GetInstance().GetUserPath(), fileName); + return PathCombine(userFilePath, fileName); } int FileUtils::GetFileContents(const std::string& url, std::string& content) @@ -169,11 +169,12 @@ bool FileUtils::XzDecompress(const std::string& compressedBytes, std::string& un return true; } -int FileUtils::GetCachedFileContents(const std::string& cachedName, const std::string& filePath, - std::string& contents, const bool useCache /* false */) +int FileUtils::GetCachedFileContents(std::shared_ptr& settings, + const std::string& cachedName, const std::string& filePath, + std::string& contents, const bool useCache /* false */) { bool needReload = false; - const std::string cachedPath = FileUtils::GetUserDataAddonFilePath(cachedName); + const std::string cachedPath = FileUtils::GetUserDataAddonFilePath(settings->GetUserPath(), cachedName); // check cached file is exists if (useCache && kodi::vfs::FileExists(cachedPath, false)) diff --git a/src/iptvsimple/utilities/FileUtils.h b/src/iptvsimple/utilities/FileUtils.h index 873bf9f4a..4d856dfb4 100644 --- a/src/iptvsimple/utilities/FileUtils.h +++ b/src/iptvsimple/utilities/FileUtils.h @@ -8,10 +8,13 @@ #pragma once #include +#include #include namespace iptvsimple { + class Settings; + namespace utilities { static const int LZMA_OUT_BUF_MAX = 409600; @@ -20,11 +23,12 @@ namespace iptvsimple { public: static std::string PathCombine(const std::string& path, const std::string& fileName); - static std::string GetUserDataAddonFilePath(const std::string& fileName); + static std::string GetUserDataAddonFilePath(const std::string& userFilePath, const std::string& fileName); static int GetFileContents(const std::string& url, std::string& content); static bool GzipInflate(const std::string& compressedBytes, std::string& uncompressedBytes); static bool XzDecompress(const std::string& compressedBytes, std::string& uncompressedBytes); - static int GetCachedFileContents(const std::string& cachedName, const std::string& filePath, + static int GetCachedFileContents(std::shared_ptr& settings, + const std::string& cachedName, const std::string& filePath, std::string& content, const bool useCache = false); static bool FileExists(const std::string& file); static bool DeleteFile(const std::string& file); diff --git a/src/iptvsimple/utilities/StreamUtils.cpp b/src/iptvsimple/utilities/StreamUtils.cpp index 1f0862f39..b43156ef2 100644 --- a/src/iptvsimple/utilities/StreamUtils.cpp +++ b/src/iptvsimple/utilities/StreamUtils.cpp @@ -20,7 +20,7 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::map& catchupProperties) +void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings) { if (ChannelSpecifiesInputstream(channel)) { @@ -31,7 +31,7 @@ void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL) +void StreamUtils::InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::shared_ptr& settings) { // If there is no MIME type and no manifest type (BOTH!) set then potentially inspect the stream and set them if (!channel.HasMimeType() && !channel.GetProperty("inputstream.ffmpegdirect.manifest_type").empty()) @@ -165,7 +165,7 @@ void StreamUtils::InspectAndSetFFmpegDirectStreamProperties(std::vectorAlwaysEnableTimeshiftModeIfMissing()) { properties.emplace_back("inputstream.ffmpegdirect.stream_mode", "timeshift"); if (channel.GetProperty("inputstream.ffmpegdirect.is_realtime_stream").empty()) @@ -182,13 +182,13 @@ void StreamUtils::SetFFmpegDirectManifestTypeStreamProperty(std::vector& settings) { std::string inputStreamName = channel.GetInputStreamName(); if (inputStreamName.empty()) { - if (StreamUtils::UseKodiInputstreams(streamType)) + if (StreamUtils::UseKodiInputstreams(streamType, settings)) { if (streamType == StreamType::HLS || streamType == StreamType::TS) { @@ -301,12 +301,12 @@ bool StreamUtils::HasMimeType(const StreamType& streamType) return streamType != StreamType::OTHER_TYPE && streamType != StreamType::SMOOTH_STREAMING; } -std::string StreamUtils::GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel) +std::string StreamUtils::GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings) { std::string newStreamUrl = streamUrl; if (WebUtils::IsHttpUrl(streamUrl) && SupportsFFmpegReconnect(streamType, channel) && - (channel.GetProperty("http-reconnect") == "true" || Settings::GetInstance().UseFFmpegReconnect())) + (channel.GetProperty("http-reconnect") == "true" || settings->UseFFmpegReconnect())) { newStreamUrl = AddHeaderToStreamUrl(newStreamUrl, "reconnect", "1"); if (streamType != StreamType::HLS) @@ -352,10 +352,10 @@ std::string StreamUtils::AddHeader(const std::string& headerTarget, const std::s return newHeaderTarget; } -bool StreamUtils::UseKodiInputstreams(const StreamType& streamType) +bool StreamUtils::UseKodiInputstreams(const StreamType& streamType, std::shared_ptr& settings) { return streamType == StreamType::OTHER_TYPE || streamType == StreamType::TS || streamType == StreamType::PLUGIN || - (streamType == StreamType::HLS && !Settings::GetInstance().UseInputstreamAdaptiveforHls()); + (streamType == StreamType::HLS && !settings->UseInputstreamAdaptiveforHls()); } bool StreamUtils::ChannelSpecifiesInputstream(const iptvsimple::data::Channel& channel) diff --git a/src/iptvsimple/utilities/StreamUtils.h b/src/iptvsimple/utilities/StreamUtils.h index 80cb9b4c7..4440b32e4 100644 --- a/src/iptvsimple/utilities/StreamUtils.h +++ b/src/iptvsimple/utilities/StreamUtils.h @@ -17,6 +17,8 @@ namespace iptvsimple { + class Settings; + namespace utilities { static const std::string INPUTSTREAM_ADAPTIVE = "inputstream.adaptive"; @@ -26,23 +28,23 @@ namespace iptvsimple class StreamUtils { public: - static void SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::map& catchupProperties); + static void SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings); static const StreamType GetStreamType(const std::string& url, const iptvsimple::data::Channel& channel); static const StreamType InspectStreamType(const std::string& url, const iptvsimple::data::Channel& channel); static const std::string GetManifestType(const StreamType& streamType); static const std::string GetMimeType(const StreamType& streamType); static bool HasMimeType(const StreamType& streamType); - static std::string GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel); + static std::string GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings); static std::string AddHeader(const std::string& headerTarget, const std::string& headerName, const std::string& headerValue, bool encodeHeaderValue); static std::string AddHeaderToStreamUrl(const std::string& streamUrl, const std::string& headerName, const std::string& headerValue); - static bool UseKodiInputstreams(const StreamType& streamType); + static bool UseKodiInputstreams(const StreamType& streamType, std::shared_ptr& settings); static bool ChannelSpecifiesInputstream(const iptvsimple::data::Channel& channe); static std::string GetUrlEncodedProtocolOptions(const std::string& protocolOptions); - static std::string GetEffectiveInputStreamName(const StreamType& streamType, const iptvsimple::data::Channel& channel); + static std::string GetEffectiveInputStreamName(const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings); private: static bool SupportsFFmpegReconnect(const StreamType& streamType, const iptvsimple::data::Channel& channel); - static void InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL); + static void InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::shared_ptr& settings); static void SetFFmpegDirectManifestTypeStreamProperty(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, const StreamType& streamType); static bool CheckInputstreamInstalledAndEnabled(const std::string& inputstreamName); From 23d247331aef8ee26ab0eb1db9402799f4dec7c0 Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Wed, 8 Feb 2023 20:22:43 +0000 Subject: [PATCH 2/4] Add support for multiple instances each supporting their own M3U/XMLTV and settings --- CMakeLists.txt | 10 +- .../resources/instance-settings.xml | 892 ++++++++++++++++++ pvr.iptvsimple/resources/settings.xml | 888 +---------------- src/IptvSimple.cpp | 29 +- src/IptvSimple.h | 8 +- src/addon.cpp | 8 +- src/addon.h | 4 +- src/iptvsimple/AddonSettings.cpp | 34 + src/iptvsimple/AddonSettings.h | 99 ++ src/iptvsimple/CatchupController.cpp | 2 +- src/iptvsimple/CatchupController.h | 6 +- src/iptvsimple/ChannelGroups.cpp | 2 +- src/iptvsimple/ChannelGroups.h | 6 +- src/iptvsimple/Channels.cpp | 2 +- src/iptvsimple/Channels.h | 6 +- src/iptvsimple/Epg.cpp | 5 +- src/iptvsimple/Epg.h | 8 +- .../{Settings.cpp => InstanceSettings.cpp} | 178 ++-- .../{Settings.h => InstanceSettings.h} | 28 +- src/iptvsimple/Media.cpp | 2 +- src/iptvsimple/Media.h | 4 +- src/iptvsimple/PlaylistLoader.cpp | 6 +- src/iptvsimple/PlaylistLoader.h | 6 +- src/iptvsimple/Providers.cpp | 2 +- src/iptvsimple/Providers.h | 6 +- src/iptvsimple/data/BaseEntry.h | 4 +- src/iptvsimple/data/Channel.cpp | 2 +- src/iptvsimple/data/Channel.h | 10 +- src/iptvsimple/data/EpgEntry.cpp | 2 +- src/iptvsimple/data/EpgEntry.h | 2 +- src/iptvsimple/data/MediaEntry.cpp | 4 +- src/iptvsimple/data/MediaEntry.h | 2 +- src/iptvsimple/utilities/FileUtils.cpp | 4 +- src/iptvsimple/utilities/FileUtils.h | 4 +- src/iptvsimple/utilities/StreamUtils.cpp | 12 +- src/iptvsimple/utilities/StreamUtils.h | 12 +- 36 files changed, 1224 insertions(+), 1075 deletions(-) create mode 100644 pvr.iptvsimple/resources/instance-settings.xml create mode 100644 src/iptvsimple/AddonSettings.cpp create mode 100644 src/iptvsimple/AddonSettings.h rename src/iptvsimple/{Settings.cpp => InstanceSettings.cpp} (69%) rename src/iptvsimple/{Settings.h => InstanceSettings.h} (95%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cd70b21d..0c84ae0e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,14 +23,15 @@ message(STATUS "LZMA_LIBRARIES: ${LZMA_LIBRARIES}") set(IPTV_SOURCES src/addon.cpp src/IptvSimple.cpp + src/iptvsimple/AddonSettings.cpp src/iptvsimple/CatchupController.cpp src/iptvsimple/Channels.cpp src/iptvsimple/ChannelGroups.cpp - src/iptvsimple/Providers.cpp src/iptvsimple/Epg.cpp + src/iptvsimple/InstanceSettings.cpp src/iptvsimple/Media.cpp src/iptvsimple/PlaylistLoader.cpp - src/iptvsimple/Settings.cpp + src/iptvsimple/Providers.cpp src/iptvsimple/StreamManager.cpp src/iptvsimple/data/Channel.cpp src/iptvsimple/data/ChannelEpg.cpp @@ -46,14 +47,15 @@ set(IPTV_SOURCES src/addon.cpp set(IPTV_HEADERS src/addon.h src/IptvSimple.h + src/iptvsimple/AddonSettings.h src/iptvsimple/CatchupController.h src/iptvsimple/Channels.h src/iptvsimple/ChannelGroups.h - src/iptvsimple/Providers.cpp src/iptvsimple/Epg.h + src/iptvsimple/InstanceSettings.h src/iptvsimple/Media.h src/iptvsimple/PlaylistLoader.h - src/iptvsimple/Settings.h + src/iptvsimple/Providers.cpp src/iptvsimple/StreamManager.h src/iptvsimple/data/BaseEntry.h src/iptvsimple/data/Channel.h diff --git a/pvr.iptvsimple/resources/instance-settings.xml b/pvr.iptvsimple/resources/instance-settings.xml new file mode 100644 index 000000000..1aa1c7eb8 --- /dev/null +++ b/pvr.iptvsimple/resources/instance-settings.xml @@ -0,0 +1,892 @@ + + +
+ + + + + + 0 + 1 + + + + + + + + + + 0 + + + true + false + + + 0 + + + 1033 + + + + 0 + + + true + + + 1 + + + + + 0 + true + + 1 + + + + + 0 + 1 + + + + 2 + false + + + + + + 1 + 0 + + + + + + + + + + + 1 + 60 + + 0 + 10 + 120 + + + 1 + + + 14044 + + + + 1 + 4 + + 0 + 1 + 23 + + + 2 + + + true + 17998 + + + + + + + 2 + + + true + + + + + 2 + false + + + + 2 + special://userdata/addon_data/pvr.iptvsimple/providers/providerMappings.xml + + false + false + + + true + + + 1033 + + + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 1 + + 1 + 1 + 5 + + + 1 + + + + + 0 + + + true + + + 1 + + + + + 0 + + + true + + + + + 1 + 1 + + + + + + + 0 + + + true + + + + + 1 + 2 + + + + + + + 0 + + + true + + + + + 1 + 3 + + + + + + + 0 + + + true + + + + + 1 + 4 + + + + + + + 0 + special://userdata/addon_data/pvr.iptvsimple/channelGroups/customTVGroups-example.xml + + false + false + + + 2 + + + 1033 + + + + 2 + false + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 1 + + 1 + 1 + 5 + + + 1 + + + + + 0 + + + true + + + 1 + + + + + 0 + + + true + + + + + 1 + 1 + + + + + + + 0 + + + true + + + + + 1 + 2 + + + + + + + 0 + + + true + + + + + 1 + 3 + + + + + + + 0 + + + true + + + + + 1 + 4 + + + + + + + 0 + special://userdata/addon_data/pvr.iptvsimple/channelGroups/customRadioGroups-example.xml + + false + false + + + 2 + + + 1033 + + + + 2 + false + + + + + + + + + + 0 + 1 + + + + + + + + + + 0 + + + true + false + + + 0 + + + 1033 + + + + 0 + + + true + + + 1 + + + + + 0 + true + + 1 + + + + + 0 + 0 + + -12 + 0.5 + 14 + + + 30027 + + + + 0 + false + + + + 2 + true + + + + + + + + 0 + false + + + + 0 + 0 + + + + + + + + + + 0 + special://userdata/addon_data/pvr.iptvsimple/genres/genreTextMappings/genres.xml + + true + false + + + 0 + + + 1033 + + + + 0 + + + true + + + 1 + + + + + + + + + + + 0 + 1 + + + + + + + + + + 0 + + + true + true + true + + + 0 + + + 657 + + + + 0 + + + true + + + 1 + + + + + 2 + false + + 0 + + + + + + + 0 + 1 + + + + + + + + + + + + + + + + + 0 + true + + + + 0 + true + + true + + + + + 0 + true + + true + + + + + 0 + false + + true + + + + + 2 + true + + true + + + + + + + + + + + 0 + false + + + + 0 + true + + true + + + + + 0 + true + + + + true + true + + + + + + + 0 + true + + + + true + true + + + + + + + 2 + false + + true + + + + + + + 0 + Addon.OpenSettings(inputstream.ffmpegdirect) + + true + + + true + + + + + + + + + + 0 + false + + + + 0 + + + true + + + true + + + + + 0 + 5 + + 1 + 1 + 15 + + + true + + + 17999 + + + + 0 + 0 + + + + + + + + + + + + true + + + + + 0 + 0 + + + + + + + + + 0 + true + + + + + 0 + 0 + + -12 + 0.5 + 14 + + + true + + + 30027 + + + + + + 0 + false + + true + + + + + 0 + 5 + + 0 + 1 + 60 + + + + + true + true + + + + + 14044 + + + + 0 + 15 + + 0 + 1 + 60 + + + + + true + true + + + + + 14044 + + + + 0 + false + + true + + + + + + + + + + + 2 + false + + + + 2 + 127.0.0.1 + + true + + + + + 2 + 4022 + + 1 + 1 + 65535 + + + true + + + + + + + 3 + true + + + + 3 + false + + + + + + 3 + + + true + + + + + 3 + + + true + + + + + 3 + + + true + + + + + + +
+
diff --git a/pvr.iptvsimple/resources/settings.xml b/pvr.iptvsimple/resources/settings.xml index c941ee6f5..58632c853 100644 --- a/pvr.iptvsimple/resources/settings.xml +++ b/pvr.iptvsimple/resources/settings.xml @@ -1,889 +1,13 @@ -
+
- - - - - 0 - 1 - - - - - - - - - - 0 - - - true - false - - - 0 - - - 1033 - - - - 0 - - - true - - - 1 - - - - - 0 - true - - 1 - - - - - 0 - 1 - - - - 2 - false - - - - - - 1 - 0 - - - - - - - - - - - 1 - 60 - - 0 - 10 - 120 - - - 1 - - - 14044 - - - - 1 - 4 - - 0 - 1 - 23 - - - 2 - - - true - 17998 - - - - - - - 2 - - - true - - - - - 2 - false - - - - 2 - special://userdata/addon_data/pvr.iptvsimple/providers/providerMappings.xml - - false - false - - - true - - - 1033 - - - - - - - - - - 0 - 0 - - - - - - - - - - - 0 - 1 - - 1 - 1 - 5 - - - 1 - - - - - 0 - - - true - - - 1 - - - - - 0 - - - true - - - - - 1 - 1 - - - - - - - 0 - - - true - - - - - 1 - 2 - - - - - - - 0 - - - true - - - - - 1 - 3 - - - - - - - 0 - - - true - - - - - 1 - 4 - - - - - - - 0 - special://userdata/addon_data/pvr.iptvsimple/channelGroups/customTVGroups-example.xml - - false - false - - - 2 - - - 1033 - - - - 2 - false - - - - - - - 0 - 0 - - - - - - - - - - - 0 - 1 - - 1 - 1 - 5 - - - 1 - - - - - 0 - - - true - - - 1 - - - - - 0 - - - true - - - - - 1 - 1 - - - - - - - 0 - - - true - - - - - 1 - 2 - - - - - - - 0 - - - true - - - - - 1 - 3 - - - - - - - 0 - - - true - - - - - 1 - 4 - - - - - - - 0 - special://userdata/addon_data/pvr.iptvsimple/channelGroups/customRadioGroups-example.xml - - false - false - - - 2 - - - 1033 - - - - 2 - false - - - - - - - - - - 0 - 1 - - - - - - - - - - 0 - - - true - false - - - 0 - - - 1033 - - - - 0 - - - true - - - 1 - - - - - 0 - true - - 1 - - - - - 0 - 0 - - -12 - 0.5 - 14 - - - 30027 - - - - 0 - false - - - - 2 - true - - - - - - - - 0 - false - - - - 0 - 0 - - - - - - - - - - 0 - special://userdata/addon_data/pvr.iptvsimple/genres/genreTextMappings/genres.xml - - true - false - - - 0 - - - 1033 - - - - 0 - - - true - - - 1 - - - - - - - - - - - 0 - 1 - - - - - - - - - - 0 - - - true - true - true - - - 0 - - - 657 - - - - 0 - - - true - - - 1 - - - - - 2 - false - - 0 - - - - - - - 0 - 1 - - - - - - - - - + + + - - - - - - 0 - true - - - - 0 - true - - true - - - - - 0 - true - - true - - - - - 0 - false - - true - - - - - 2 - true - - true - - - - - - - - - - - 0 - false - - - - 0 - true - - true - - - - - 0 - true - - - - true - true - - - - - - - 0 - true - - - - true - true - - - - - - - 2 - false - - true - - - - - - - 0 - Addon.OpenSettings(inputstream.ffmpegdirect) - - true - - - true - - - - - - - - - - 0 - false - - - - 0 - - - true - - - true - - - - - 0 - - 1 - 1 - 15 - - 5 - - true - - - 17999 - - - - 0 - 0 - - - - - - - - - - - - true - - - - - 0 - false - - - - - - - - - 0 - true - - - - - 0 - 0 - - -12 - 0.5 - 14 - - - true - - - 30027 - - - - - - 0 - false - - true - - - - - 0 - 5 - - 0 - 1 - 60 - - - - - true - true - - - - - 14044 - - - - 0 - 15 - - 0 - 1 - 60 - - - - - true - true - - - - - 14044 - - - - 0 - false - - true - - - - - - - - - - - 2 - false - - - - 2 - 127.0.0.1 - - true - - - - - 2 - 4022 - - 1 - 1 - 65535 - - - true - - - - - - - 3 - true - - - - 3 - false - - - - - - 3 - - true - - - - - 3 - - true - - - - - 3 - - true - - - - - -
diff --git a/src/IptvSimple.cpp b/src/IptvSimple.cpp index 146cc97d0..c19c0a503 100644 --- a/src/IptvSimple.cpp +++ b/src/IptvSimple.cpp @@ -7,7 +7,7 @@ #include "IptvSimple.h" -#include "iptvsimple/Settings.h" +#include "iptvsimple/InstanceSettings.h" #include "iptvsimple/utilities/Logger.h" #include "iptvsimple/utilities/TimeUtils.h" #include "iptvsimple/utilities/WebUtils.h" @@ -22,7 +22,7 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; using namespace kodi::tools; -IptvSimple::IptvSimple(const kodi::addon::IInstanceInfo& instance, std::shared_ptr& settings) : kodi::addon::CInstancePVRClient(instance), m_settings(settings) +IptvSimple::IptvSimple(const kodi::addon::IInstanceInfo& instance) : kodi::addon::CInstancePVRClient(instance), m_settings(new InstanceSettings(*this, instance)) { m_channels.Clear(); m_channelGroups.Clear(); @@ -35,8 +35,6 @@ bool IptvSimple::Initialise() { std::lock_guard lock(m_mutex); - m_settings->ReadFromAddon(kodi::addon::GetUserPath(), kodi::addon::GetAddonPath()); - m_channels.Init(); m_channelGroups.Init(); m_providers.Init(); @@ -117,7 +115,7 @@ void IptvSimple::Process() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - m_settings->ReloadAddonSettings(); + m_settings->ReloadAddonInstanceSettings(); m_playlistLoader.ReloadPlayList(); m_epg.ReloadEPG(); // Reloading EPG also updates media @@ -405,18 +403,17 @@ PVR_ERROR IptvSimple::GetSignalStatus(int channelUid, kodi::addon::PVRSignalStat } /*************************************************************************** - * Settings + * InstanceSettings **************************************************************************/ -// ADDON_STATUS IptvSimple::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) -// { -// std::lock_guard lock(m_mutex); - -// // When a number of settings change set this on the first one so it can be picked up -// // in the process call for a reload of channels, groups and EPG. -// if (!m_reloadChannelsGroupsAndEPG) -// m_reloadChannelsGroupsAndEPG = true; +ADDON_STATUS IptvSimple::SetInstanceSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +{ + std::lock_guard lock(m_mutex); -// return m_settings->SetValue(settingName, settingValue); -// } + // When a number of settings change set this on the first one so it can be picked up + // in the process call for a reload of channels, groups and EPG. + if (!m_reloadChannelsGroupsAndEPG) + m_reloadChannelsGroupsAndEPG = true; + return m_settings->SetSetting(settingName, settingValue); +} diff --git a/src/IptvSimple.h b/src/IptvSimple.h index 38c8e9b49..a6c0707dd 100644 --- a/src/IptvSimple.h +++ b/src/IptvSimple.h @@ -25,11 +25,15 @@ class ATTR_DLL_LOCAL IptvSimple : public kodi::addon::CInstancePVRClient { public: - IptvSimple(const kodi::addon::IInstanceInfo& instance, std::shared_ptr& settings); + IptvSimple(const kodi::addon::IInstanceInfo& instance); ~IptvSimple() override; bool Initialise(); + // kodi::addon::CInstancePVRClient -> kodi::addon::IAddonInstance overrides + ADDON_STATUS SetInstanceSetting(const std::string& settingName, + const kodi::addon::CSettingValue& settingValue) override; + // kodi::addon::CInstancePVRClient functions //@{ PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) override; @@ -82,7 +86,7 @@ class ATTR_DLL_LOCAL IptvSimple : public kodi::addon::CInstancePVRClient private: static const int PROCESS_LOOP_WAIT_SECS = 2; - std::shared_ptr m_settings; + std::shared_ptr m_settings; iptvsimple::data::Channel m_currentChannel{m_settings}; iptvsimple::Providers m_providers{m_settings}; diff --git a/src/addon.cpp b/src/addon.cpp index 70421645e..f156728ce 100644 --- a/src/addon.cpp +++ b/src/addon.cpp @@ -15,9 +15,7 @@ using namespace iptvsimple::utilities; ADDON_STATUS CIptvSimpleAddon::Create() { /* Init settings */ - m_settings.reset(new Settings()); - - Logger::Log(LEVEL_DEBUG, "%s - Creating IPTV Simple PVR-Client", __func__); + m_settings.reset(new AddonSettings()); /* Configure the logger */ Logger::GetInstance().SetImplementation([this](LogLevel level, const char* message) @@ -48,7 +46,7 @@ ADDON_STATUS CIptvSimpleAddon::Create() Logger::GetInstance().SetPrefix("pvr.iptvsimple"); - Logger::Log(LogLevel::LEVEL_INFO, "%s starting PVR client...", __func__); + Logger::Log(LogLevel::LEVEL_INFO, "%s starting IPTV Simple PVR client...", __func__); return ADDON_STATUS_OK; } @@ -62,7 +60,7 @@ ADDON_STATUS CIptvSimpleAddon::CreateInstance(const kodi::addon::IInstanceInfo& { if (instance.IsType(ADDON_INSTANCE_PVR)) { - IptvSimple* usedInstance = new IptvSimple(instance, m_settings); + IptvSimple* usedInstance = new IptvSimple(instance); if (!usedInstance->Initialise()) { delete usedInstance; diff --git a/src/addon.h b/src/addon.h index c964ca547..1d61bc7ab 100644 --- a/src/addon.h +++ b/src/addon.h @@ -12,7 +12,7 @@ #include #include -#include "iptvsimple/Settings.h" +#include "iptvsimple/AddonSettings.h" class IptvSimple; @@ -28,5 +28,5 @@ class ATTR_DLL_LOCAL CIptvSimpleAddon : public kodi::addon::CAddonBase private: std::unordered_map m_usedInstances; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; diff --git a/src/iptvsimple/AddonSettings.cpp b/src/iptvsimple/AddonSettings.cpp new file mode 100644 index 000000000..3ee03981f --- /dev/null +++ b/src/iptvsimple/AddonSettings.cpp @@ -0,0 +1,34 @@ +/* + * 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/FileUtils.h" +#include "utilities/Logger.h" + +#include "kodi/General.h" + +using namespace iptvsimple; +using namespace iptvsimple::utilities; + +AddonSettings::AddonSettings() +{ + ReadSettings(); +} + +void AddonSettings::ReadSettings() +{ + FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + CHANNEL_GROUPS_DIR, CHANNEL_GROUPS_ADDON_DATA_BASE_DIR, true); + + // Only instance settings with this add-on! +} + +ADDON_STATUS AddonSettings::SetSetting(const std::string& settingName, + const kodi::addon::CSettingValue& settingValue) +{ + return ADDON_STATUS_UNKNOWN; +} diff --git a/src/iptvsimple/AddonSettings.h b/src/iptvsimple/AddonSettings.h new file mode 100644 index 000000000..fb63a6138 --- /dev/null +++ b/src/iptvsimple/AddonSettings.h @@ -0,0 +1,99 @@ +/* + * 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 "utilities/Logger.h" + +#include + +#include "kodi/AddonBase.h" + +namespace iptvsimple +{ + static const std::string CHANNEL_GROUPS_DIR = "/channelGroups"; + static const std::string CHANNEL_GROUPS_ADDON_DATA_BASE_DIR = "special://userdata/addon_data/pvr.iptvsimple" + CHANNEL_GROUPS_DIR; + +/** + * Represents the current addon settings + */ +class AddonSettings +{ + public: + AddonSettings(); + + /** + * Set a value according to key definition in settings.xml + */ + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue); + + private: + AddonSettings(const AddonSettings&) = delete; + void operator=(const AddonSettings&) = delete; + + template + V SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue, T& currentValue, V returnValueIfChanged, V defaultReturnValue) + { + T newValue; + if (std::is_same::value) + newValue = static_cast(settingValue.GetFloat()); + else if (std::is_same::value) + newValue = static_cast(settingValue.GetBoolean()); + else if (std::is_same::value) + newValue = static_cast(settingValue.GetUInt()); + else + newValue = static_cast(settingValue.GetInt()); + + if (newValue != currentValue) + { + std::string formatString = "%s - Changed Setting '%s' from %d to %d"; + if (std::is_same::value) + formatString = "%s - Changed Setting '%s' from %f to %f"; + utilities::Logger::Log(utilities::LogLevel::LEVEL_INFO, formatString.c_str(), __FUNCTION__, settingName.c_str(), currentValue, newValue); + currentValue = newValue; + return returnValueIfChanged; + } + + return defaultReturnValue; + } + + template + V SetEnumSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue, T& currentValue, V returnValueIfChanged, V defaultReturnValue) + { + T newValue = settingValue.GetEnum(); + if (newValue != currentValue) + { + utilities::Logger::Log(utilities::LogLevel::LEVEL_INFO, "%s - Changed Setting '%s' from %d to %d", __FUNCTION__, settingName.c_str(), currentValue, newValue); + currentValue = newValue; + return returnValueIfChanged; + } + + return defaultReturnValue; + } + + template + V SetStringSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue, std::string& currentValue, V returnValueIfChanged, V defaultReturnValue) + { + const std::string strSettingValue = settingValue.GetString(); + + if (strSettingValue != currentValue) + { + utilities::Logger::Log(utilities::LogLevel::LEVEL_INFO, "%s - Changed Setting '%s' from '%s' to '%s'", __func__, settingName.c_str(), currentValue.c_str(), strSettingValue.c_str()); + currentValue = strSettingValue; + return returnValueIfChanged; + } + + return defaultReturnValue; + } + + /** + * Read all settings defined in settings.xml + */ + void ReadSettings(); +}; + +} // namespace iptvsimple diff --git a/src/iptvsimple/CatchupController.cpp b/src/iptvsimple/CatchupController.cpp index 87c16f5d7..9fa81f193 100644 --- a/src/iptvsimple/CatchupController.cpp +++ b/src/iptvsimple/CatchupController.cpp @@ -24,7 +24,7 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -CatchupController::CatchupController(Epg& epg, std::mutex* mutex, std::shared_ptr& settings) +CatchupController::CatchupController(Epg& epg, std::mutex* mutex, std::shared_ptr& settings) : m_epg(epg), m_mutex(mutex), m_settings(settings) {} void CatchupController::ProcessChannelForPlayback(const Channel& channel, std::map& catchupProperties) diff --git a/src/iptvsimple/CatchupController.h b/src/iptvsimple/CatchupController.h index 3f52ebf9c..423f29556 100644 --- a/src/iptvsimple/CatchupController.h +++ b/src/iptvsimple/CatchupController.h @@ -9,7 +9,7 @@ #include -#include "Settings.h" +#include "InstanceSettings.h" #include "data/Channel.h" #include "data/EpgEntry.h" #include "utilities/StreamUtils.h" @@ -27,7 +27,7 @@ namespace iptvsimple class CatchupController { public: - CatchupController(iptvsimple::Epg& epg, std::mutex* mutex, std::shared_ptr& settings); + CatchupController(iptvsimple::Epg& epg, std::mutex* mutex, std::shared_ptr& settings); void ProcessChannelForPlayback(const data::Channel& channel, std::map& catchupProperties); void ProcessEPGTagForTimeshiftedPlayback(const kodi::addon::PVREPGTag& epgTag, const data::Channel& channel, std::map& catchupProperties); @@ -76,6 +76,6 @@ namespace iptvsimple StreamManager m_streamManager; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/ChannelGroups.cpp b/src/iptvsimple/ChannelGroups.cpp index f76e4103b..5a446580c 100644 --- a/src/iptvsimple/ChannelGroups.cpp +++ b/src/iptvsimple/ChannelGroups.cpp @@ -15,7 +15,7 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -ChannelGroups::ChannelGroups(const Channels& channels, std::shared_ptr& settings) : m_channels(channels), m_settings(settings) {} +ChannelGroups::ChannelGroups(const Channels& channels, std::shared_ptr& settings) : m_channels(channels), m_settings(settings) {} bool ChannelGroups::Init() { diff --git a/src/iptvsimple/ChannelGroups.h b/src/iptvsimple/ChannelGroups.h index 71e831c11..d3113c5ce 100644 --- a/src/iptvsimple/ChannelGroups.h +++ b/src/iptvsimple/ChannelGroups.h @@ -8,7 +8,7 @@ #pragma once #include "Channels.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "data/ChannelGroup.h" #include @@ -22,7 +22,7 @@ namespace iptvsimple class ChannelGroups { public: - ChannelGroups(const iptvsimple::Channels& channels, std::shared_ptr& settings); + ChannelGroups(const iptvsimple::Channels& channels, std::shared_ptr& settings); int GetChannelGroupsAmount() const; PVR_ERROR GetChannelGroups(kodi::addon::PVRChannelGroupsResultSet& results, bool radio) const; @@ -43,6 +43,6 @@ namespace iptvsimple bool m_channelGroupsLoadFailed = false; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Channels.cpp b/src/iptvsimple/Channels.cpp index a9ccf9bd9..ce23fd0c2 100644 --- a/src/iptvsimple/Channels.cpp +++ b/src/iptvsimple/Channels.cpp @@ -20,7 +20,7 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -Channels::Channels(std::shared_ptr& settings) : m_settings(settings) +Channels::Channels(std::shared_ptr& settings) : m_settings(settings) { } diff --git a/src/iptvsimple/Channels.h b/src/iptvsimple/Channels.h index 371854bb8..748903613 100644 --- a/src/iptvsimple/Channels.h +++ b/src/iptvsimple/Channels.h @@ -7,7 +7,7 @@ #pragma once -#include "Settings.h" +#include "InstanceSettings.h" #include "data/Channel.h" #include @@ -28,7 +28,7 @@ namespace iptvsimple class Channels { public: - Channels(std::shared_ptr& settings); + Channels(std::shared_ptr& settings); bool Init(); @@ -54,6 +54,6 @@ namespace iptvsimple std::vector m_channels; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Epg.cpp b/src/iptvsimple/Epg.cpp index 32f250973..1db4e6a21 100644 --- a/src/iptvsimple/Epg.cpp +++ b/src/iptvsimple/Epg.cpp @@ -7,7 +7,6 @@ #include "Epg.h" -#include "Settings.h" #include "utilities/FileUtils.h" #include "utilities/Logger.h" #include "utilities/XMLUtils.h" @@ -25,7 +24,7 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; using namespace pugi; -Epg::Epg(kodi::addon::CInstancePVRClient* client, Channels& channels, Media& media, std::shared_ptr& settings) +Epg::Epg(kodi::addon::CInstancePVRClient* client, Channels& channels, Media& media, std::shared_ptr& settings) : m_lastStart(0), m_lastEnd(0), m_channels(channels), m_media(media), m_client(client), m_settings(settings) { FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + GENRE_DIR, GENRE_ADDON_DATA_BASE_DIR, true); @@ -158,7 +157,7 @@ bool Epg::GetXMLTVFileWithRetries(std::string& data) while (count < 3) // max 3 tries { - if ((bytesRead = FileUtils::GetCachedFileContents(m_settings, XMLTV_CACHE_FILENAME, m_xmltvLocation, data, useEPGCache)) != 0) + if ((bytesRead = FileUtils::GetCachedFileContents(m_settings, m_settings->GetXMLTVCacheFilename(), m_xmltvLocation, data, useEPGCache)) != 0) break; Logger::Log(LEVEL_ERROR, "%s - Unable to load EPG file '%s': file is missing or empty. :%dth try.", __FUNCTION__, m_xmltvLocation.c_str(), ++count); diff --git a/src/iptvsimple/Epg.h b/src/iptvsimple/Epg.h index a6bd9f76b..c4b0317ed 100644 --- a/src/iptvsimple/Epg.h +++ b/src/iptvsimple/Epg.h @@ -9,7 +9,7 @@ #include "Channels.h" #include "Media.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "data/ChannelEpg.h" #include "data/EpgEntry.h" #include "data/EpgGenre.h" @@ -35,10 +35,12 @@ namespace iptvsimple INVALID }; + class InstanceSettings; + class Epg { public: - Epg(kodi::addon::CInstancePVRClient* client, iptvsimple::Channels& channels, iptvsimple::Media& media, std::shared_ptr& settings); + Epg(kodi::addon::CInstancePVRClient* client, iptvsimple::Channels& channels, iptvsimple::Media& media, std::shared_ptr& settings); bool Init(int epgMaxPastDays, int epgMaxFutureDays); @@ -87,6 +89,6 @@ namespace iptvsimple kodi::addon::CInstancePVRClient* m_client; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Settings.cpp b/src/iptvsimple/InstanceSettings.cpp similarity index 69% rename from src/iptvsimple/Settings.cpp rename to src/iptvsimple/InstanceSettings.cpp index 5fcea8908..094234e9f 100644 --- a/src/iptvsimple/Settings.cpp +++ b/src/iptvsimple/InstanceSettings.cpp @@ -5,7 +5,7 @@ * See LICENSE.md for more information. */ -#include "Settings.h" +#include "InstanceSettings.h" #include "utilities/FileUtils.h" #include "utilities/XMLUtils.h" @@ -19,36 +19,38 @@ using namespace pugi; /*************************************************************************** * PVR settings **************************************************************************/ -void Settings::ReadFromAddon(const std::string& userPath, const std::string& clientPath) -{ - FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + CHANNEL_GROUPS_DIR, CHANNEL_GROUPS_ADDON_DATA_BASE_DIR, true); - m_userPath = userPath; - m_clientPath = clientPath; +InstanceSettings::InstanceSettings(kodi::addon::IAddonInstance& instance, const kodi::addon::IInstanceInfo& instanceInfo) + : m_instance(instance), m_instanceNumber(instanceInfo.GetNumber()) +{ + ReadSettings(); +} +void InstanceSettings::ReadSettings() +{ // M3U - m_m3uPathType = kodi::addon::GetSettingEnum("m3uPathType", PathType::REMOTE_PATH); - m_m3uPath = kodi::addon::GetSettingString("m3uPath"); - m_m3uUrl = kodi::addon::GetSettingString("m3uUrl"); - m_cacheM3U = kodi::addon::GetSettingBoolean("m3uCache"); - m_startChannelNumber = kodi::addon::GetSettingInt("startNum", 1); - m_numberChannelsByM3uOrderOnly = kodi::addon::GetSettingBoolean("numberByOrder", false); - m_m3uRefreshMode = kodi::addon::GetSettingEnum("m3uRefreshMode", RefreshMode::DISABLED); - m_m3uRefreshIntervalMins = kodi::addon::GetSettingInt("m3uRefreshIntervalMins", 60); - m_m3uRefreshHour = kodi::addon::GetSettingInt("m3uRefreshHour", 4); - m_defaultProviderName = kodi::addon::GetSettingString("defaultProviderName"); - m_enableProviderMappings = kodi::addon::GetSettingBoolean("enableProviderMappings", false); - m_providerMappingFile = kodi::addon::GetSettingString("providerMappingFile", DEFAULT_PROVIDER_NAME_MAP_FILE); + m_instance.CheckInstanceSettingEnum("m3uPathType", m_m3uPathType); + m_instance.CheckInstanceSettingString("m3uPath", m_m3uPath); + m_instance.CheckInstanceSettingString("m3uUrl", m_m3uUrl); + m_instance.CheckInstanceSettingBoolean("m3uCache", m_cacheM3U); + m_instance.CheckInstanceSettingInt("startNum", m_startChannelNumber); + m_instance.CheckInstanceSettingBoolean("numberByOrder", m_numberChannelsByM3uOrderOnly); + m_instance.CheckInstanceSettingEnum("m3uRefreshMode", m_m3uRefreshMode); + m_instance.CheckInstanceSettingInt("m3uRefreshIntervalMins", m_m3uRefreshIntervalMins); + m_instance.CheckInstanceSettingInt("m3uRefreshHour", m_m3uRefreshHour); + m_instance.CheckInstanceSettingString("defaultProviderName", m_defaultProviderName); + m_instance.CheckInstanceSettingBoolean("enableProviderMappings", m_enableProviderMappings); + m_instance.CheckInstanceSettingString("providerMappingFile", m_providerMappingFile); // Groups - m_allowTVChannelGroupsOnly = kodi::addon::GetSettingBoolean("tvChannelGroupsOnly", false); - m_tvChannelGroupMode = kodi::addon::GetSettingEnum("tvGroupMode", ChannelGroupMode::ALL_GROUPS); - m_numTVGroups = kodi::addon::GetSettingInt("numTvGroups", DEFAULT_NUM_GROUPS); - m_oneTVGroup = kodi::addon::GetSettingString("oneTvGroup"); - m_twoTVGroup = kodi::addon::GetSettingString("twoTvGroup"); - m_threeTVGroup = kodi::addon::GetSettingString("threeTvGroup"); - m_fourTVGroup = kodi::addon::GetSettingString("fourTvGroup"); - m_fiveTVGroup = kodi::addon::GetSettingString("fiveTvGroup"); + m_instance.CheckInstanceSettingBoolean("tvChannelGroupsOnly", m_allowTVChannelGroupsOnly); + m_instance.CheckInstanceSettingEnum("tvGroupMode", m_tvChannelGroupMode); + m_instance.CheckInstanceSettingInt("numTvGroups", m_numTVGroups); + m_instance.CheckInstanceSettingString("oneTvGroup", m_oneTVGroup); + m_instance.CheckInstanceSettingString("twoTvGroup", m_twoTVGroup); + m_instance.CheckInstanceSettingString("threeTvGroup", m_threeTVGroup); + m_instance.CheckInstanceSettingString("fourTvGroup", m_fourTVGroup); + m_instance.CheckInstanceSettingString("fiveTvGroup", m_fiveTVGroup); if (m_tvChannelGroupMode == ChannelGroupMode::SOME_GROUPS) { m_customTVChannelGroupNameList.clear(); @@ -64,18 +66,18 @@ void Settings::ReadFromAddon(const std::string& userPath, const std::string& cli if (!m_fiveTVGroup.empty() && m_numTVGroups >= 5) m_customTVChannelGroupNameList.emplace_back(m_fiveTVGroup); } - m_customTVGroupsFile = kodi::addon::GetSettingString("customTvGroupsFile", DEFAULT_CUSTOM_TV_GROUPS_FILE); + m_instance.CheckInstanceSettingString("customTvGroupsFile", m_customTVGroupsFile); if (m_tvChannelGroupMode == ChannelGroupMode::CUSTOM_GROUPS) LoadCustomChannelGroupFile(m_customTVGroupsFile, m_customTVChannelGroupNameList); - m_allowRadioChannelGroupsOnly = kodi::addon::GetSettingBoolean("radioChannelGroupsOnly", false); - m_radioChannelGroupMode = kodi::addon::GetSettingEnum("radioGroupMode", ChannelGroupMode::ALL_GROUPS); - m_numRadioGroups = kodi::addon::GetSettingInt("numRadioGroups", DEFAULT_NUM_GROUPS); - m_oneRadioGroup = kodi::addon::GetSettingString("oneRadioGroup"); - m_twoRadioGroup = kodi::addon::GetSettingString("twoRadioGroup"); - m_threeRadioGroup = kodi::addon::GetSettingString("threeRadioGroup"); - m_fourRadioGroup = kodi::addon::GetSettingString("fourRadioGroup"); - m_fiveRadioGroup = kodi::addon::GetSettingString("fiveRadioGroup"); + m_instance.CheckInstanceSettingBoolean("radioChannelGroupsOnly", m_allowRadioChannelGroupsOnly); + m_instance.CheckInstanceSettingEnum("radioGroupMode", m_radioChannelGroupMode); + m_instance.CheckInstanceSettingInt("numRadioGroups", m_numRadioGroups); + m_instance.CheckInstanceSettingString("oneRadioGroup", m_oneRadioGroup); + m_instance.CheckInstanceSettingString("twoRadioGroup", m_twoRadioGroup); + m_instance.CheckInstanceSettingString("threeRadioGroup", m_threeRadioGroup); + m_instance.CheckInstanceSettingString("fourRadioGroup", m_fourRadioGroup); + m_instance.CheckInstanceSettingString("fiveRadioGroup", m_fiveRadioGroup); if (m_radioChannelGroupMode == ChannelGroupMode::SOME_GROUPS) { m_customRadioChannelGroupNameList.clear(); @@ -91,83 +93,83 @@ void Settings::ReadFromAddon(const std::string& userPath, const std::string& cli if (!m_fiveRadioGroup.empty() && m_numRadioGroups >= 5) m_customRadioChannelGroupNameList.emplace_back(m_fiveRadioGroup); } - m_customRadioGroupsFile = kodi::addon::GetSettingString("customRadioGroupsFile", DEFAULT_CUSTOM_RADIO_GROUPS_FILE); + m_instance.CheckInstanceSettingString("customRadioGroupsFile", m_customRadioGroupsFile); if (m_radioChannelGroupMode == ChannelGroupMode::CUSTOM_GROUPS) LoadCustomChannelGroupFile(m_customRadioGroupsFile, m_customRadioChannelGroupNameList); // EPG - m_epgPathType = kodi::addon::GetSettingEnum("epgPathType", PathType::REMOTE_PATH); - m_epgPath = kodi::addon::GetSettingString("epgPath"); - m_epgUrl = kodi::addon::GetSettingString("epgUrl"); - m_cacheEPG = kodi::addon::GetSettingBoolean("epgCache", true); - m_epgTimeShiftHours = kodi::addon::GetSettingFloat("epgTimeShift", 0.0f); - m_tsOverride = kodi::addon::GetSettingBoolean("epgTSOverride", true); - m_ignoreCaseForEpgChannelIds = kodi::addon::GetSettingBoolean("epgIgnoreCaseForChannelIds", true); + m_instance.CheckInstanceSettingEnum("epgPathType", m_epgPathType); + m_instance.CheckInstanceSettingString("epgPath", m_epgPath); + m_instance.CheckInstanceSettingString("epgUrl", m_epgUrl); + m_instance.CheckInstanceSettingBoolean("epgCache", m_cacheEPG); + m_instance.CheckInstanceSettingFloat("epgTimeShift", m_epgTimeShiftHours); + m_instance.CheckInstanceSettingBoolean("epgTSOverride", m_tsOverride); + m_instance.CheckInstanceSettingBoolean("epgIgnoreCaseForChannelIds", m_ignoreCaseForEpgChannelIds); //Genres - m_useEpgGenreTextWhenMapping = kodi::addon::GetSettingBoolean("useEpgGenreText", false); - m_genresPathType = kodi::addon::GetSettingEnum("genresPathType", PathType::LOCAL_PATH); - m_genresPath = kodi::addon::GetSettingString("genresPath"); - m_genresUrl = kodi::addon::GetSettingString("genresUrl"); + m_instance.CheckInstanceSettingBoolean("useEpgGenreText", m_useEpgGenreTextWhenMapping); + m_instance.CheckInstanceSettingEnum("genresPathType", m_genresPathType); + m_instance.CheckInstanceSettingString("genresPath", m_genresPath); + m_instance.CheckInstanceSettingString("genresUrl", m_genresUrl); // Channel Logos - m_logoPathType = kodi::addon::GetSettingEnum("logoPathType", PathType::REMOTE_PATH); - m_logoPath = kodi::addon::GetSettingString("logoPath"); - m_logoBaseUrl = kodi::addon::GetSettingString("logoBaseUrl"); - m_epgLogosMode = kodi::addon::GetSettingEnum("logoFromEpg", EpgLogosMode::IGNORE_XMLTV); - m_useLocalLogosOnly = kodi::addon::GetSettingBoolean("useLogosLocalPathOnly", false); + m_instance.CheckInstanceSettingEnum("logoPathType", m_logoPathType); + m_instance.CheckInstanceSettingString("logoPath", m_logoPath); + m_instance.CheckInstanceSettingString("logoBaseUrl", m_logoBaseUrl); + m_instance.CheckInstanceSettingEnum("logoFromEpg", m_epgLogosMode); + m_instance.CheckInstanceSettingBoolean("useLogosLocalPathOnly", m_useLocalLogosOnly); // Media m_mediaEnabled - m_mediaEnabled = kodi::addon::GetSettingBoolean("mediaEnabled", true); - m_showVodAsRecordings = kodi::addon::GetSettingBoolean("mediaVODAsRecordings", true); - m_groupMediaByTitle = kodi::addon::GetSettingBoolean("mediaGroupByTitle", true); - m_groupMediaBySeason = kodi::addon::GetSettingBoolean("mediaGroupBySeason", true); - m_includeShowInfoInMediaTitle = kodi::addon::GetSettingBoolean("mediaTitleSeasonEpisode", false); + m_instance.CheckInstanceSettingBoolean("mediaEnabled", m_mediaEnabled); + m_instance.CheckInstanceSettingBoolean("mediaVODAsRecordings", m_showVodAsRecordings); + m_instance.CheckInstanceSettingBoolean("mediaGroupByTitle", m_groupMediaByTitle); + m_instance.CheckInstanceSettingBoolean("mediaGroupBySeason", m_groupMediaBySeason); + m_instance.CheckInstanceSettingBoolean("mediaTitleSeasonEpisode", m_includeShowInfoInMediaTitle); // Timeshift - m_timeshiftEnabled = kodi::addon::GetSettingBoolean("timeshiftEnabled", false); - m_timeshiftEnabledAll = kodi::addon::GetSettingBoolean("timeshiftEnabledAll", false); - m_timeshiftEnabledHttp = kodi::addon::GetSettingBoolean("timeshiftEnabledHttp", false); - m_timeshiftEnabledUdp = kodi::addon::GetSettingBoolean("timeshiftEnabledUdp", false); - m_timeshiftEnabledCustom = kodi::addon::GetSettingBoolean("timeshiftEnabledCustom", false); + m_instance.CheckInstanceSettingBoolean("timeshiftEnabled", m_timeshiftEnabled); + m_instance.CheckInstanceSettingBoolean("timeshiftEnabledAll", m_timeshiftEnabledAll); + m_instance.CheckInstanceSettingBoolean("timeshiftEnabledHttp", m_timeshiftEnabledHttp); + m_instance.CheckInstanceSettingBoolean("timeshiftEnabledUdp", m_timeshiftEnabledUdp); + m_instance.CheckInstanceSettingBoolean("timeshiftEnabledCustom", m_timeshiftEnabledCustom); // Catchup - m_catchupEnabled = kodi::addon::GetSettingBoolean("catchupEnabled", false); - m_catchupQueryFormat = kodi::addon::GetSettingString("catchupQueryFormat"); - m_catchupDays = kodi::addon::GetSettingInt("catchupDays", 5); - m_allChannelsCatchupMode = kodi::addon::GetSettingEnum("allChannelsCatchupMode", CatchupMode::DISABLED); - m_catchupOverrideMode = kodi::addon::GetSettingEnum("catchupOverrideMode", CatchupOverrideMode::WITHOUT_TAGS); - m_catchupCorrectionHours = kodi::addon::GetSettingFloat("catchupCorrection", 0.0f); - m_catchupPlayEpgAsLive = kodi::addon::GetSettingBoolean("catchupPlayEpgAsLive", false); - m_catchupWatchEpgBeginBufferMins = kodi::addon::GetSettingInt("catchupWatchEpgBeginBufferMins", 5); - m_catchupWatchEpgEndBufferMins = kodi::addon::GetSettingInt("catchupWatchEpgEndBufferMins", 15); - m_catchupOnlyOnFinishedProgrammes = kodi::addon::GetSettingBoolean("catchupOnlyOnFinishedProgrammes", false); + m_instance.CheckInstanceSettingBoolean("catchupEnabled", m_catchupEnabled); + m_instance.CheckInstanceSettingString("catchupQueryFormat", m_catchupQueryFormat); + m_instance.CheckInstanceSettingInt("catchupDays", m_catchupDays); + m_instance.CheckInstanceSettingEnum("allChannelsCatchupMode", m_allChannelsCatchupMode); + m_instance.CheckInstanceSettingEnum("catchupOverrideMode", m_catchupOverrideMode); + m_instance.CheckInstanceSettingFloat("catchupCorrection", m_catchupCorrectionHours); + m_instance.CheckInstanceSettingBoolean("catchupPlayEpgAsLive", m_catchupPlayEpgAsLive); + m_instance.CheckInstanceSettingInt("catchupWatchEpgBeginBufferMins", m_catchupWatchEpgBeginBufferMins); + m_instance.CheckInstanceSettingInt("catchupWatchEpgEndBufferMins", m_catchupWatchEpgEndBufferMins); + m_instance.CheckInstanceSettingBoolean("catchupOnlyOnFinishedProgrammes", m_catchupOnlyOnFinishedProgrammes); // Advanced - m_transformMulticastStreamUrls = kodi::addon::GetSettingBoolean("transformMulticastStreamUrls", false); - m_udpxyHost = kodi::addon::GetSettingString("udpxyHost"); - m_udpxyPort = kodi::addon::GetSettingInt("udpxyPort", DEFAULT_UDPXY_MULTICAST_RELAY_PORT); - m_useFFmpegReconnect = kodi::addon::GetSettingBoolean("useFFmpegReconnect"); - m_useInputstreamAdaptiveforHls = kodi::addon::GetSettingBoolean("useInputstreamAdaptiveforHls", false); - m_defaultUserAgent = kodi::addon::GetSettingString("defaultUserAgent"); - m_defaultInputstream = kodi::addon::GetSettingString("defaultInputstream"); - m_defaultMimeType = kodi::addon::GetSettingString("defaultMimeType"); + m_instance.CheckInstanceSettingBoolean("transformMulticastStreamUrls", m_transformMulticastStreamUrls); + m_instance.CheckInstanceSettingString("udpxyHost", m_udpxyHost); + m_instance.CheckInstanceSettingInt("udpxyPort", m_udpxyPort); + m_instance.CheckInstanceSettingBoolean("useFFmpegReconnect", m_useFFmpegReconnect); + m_instance.CheckInstanceSettingBoolean("useInputstreamAdaptiveforHls", m_useInputstreamAdaptiveforHls); + m_instance.CheckInstanceSettingString("defaultUserAgent", m_defaultUserAgent); + m_instance.CheckInstanceSettingString("defaultInputstream", m_defaultInputstream); + m_instance.CheckInstanceSettingString("defaultMimeType", m_defaultMimeType); } -void Settings::ReloadAddonSettings() +void InstanceSettings::ReloadAddonInstanceSettings() { - ReadFromAddon(m_userPath, m_clientPath); + ReadSettings(); } -ADDON_STATUS Settings::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +ADDON_STATUS InstanceSettings::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) { // reset cache and restart addon - std::string strFile = FileUtils::GetUserDataAddonFilePath(GetUserPath(), M3U_CACHE_FILENAME); + std::string strFile = FileUtils::GetUserDataAddonFilePath(GetUserPath(), GetM3UCacheFilename()); if (FileUtils::FileExists(strFile)) FileUtils::DeleteFile(strFile); - strFile = FileUtils::GetUserDataAddonFilePath(GetUserPath(), XMLTV_CACHE_FILENAME); + strFile = FileUtils::GetUserDataAddonFilePath(GetUserPath(), GetXMLTVCacheFilename()); if (FileUtils::FileExists(strFile)) FileUtils::DeleteFile(strFile); @@ -202,7 +204,7 @@ ADDON_STATUS Settings::SetSetting(const std::string& settingName, const kodi::ad else if (settingName == "tvGroupMode") return SetEnumSetting(settingName, settingValue, m_tvChannelGroupMode, ADDON_STATUS_OK, ADDON_STATUS_OK); else if (settingName == "numTvGroups") - return SetSetting(settingName, settingValue, m_numTVGroups, ADDON_STATUS_OK, ADDON_STATUS_OK); + return SetSetting(settingName, settingValue, m_numTVGroups, ADDON_STATUS_OK, ADDON_STATUS_OK); else if (settingName == "oneTvGroup") return SetStringSetting(settingName, settingValue, m_oneTVGroup, ADDON_STATUS_OK, ADDON_STATUS_OK); else if (settingName == "twoTvGroup") @@ -220,7 +222,7 @@ ADDON_STATUS Settings::SetSetting(const std::string& settingName, const kodi::ad else if (settingName == "radioGroupMode") return SetEnumSetting(settingName, settingValue, m_radioChannelGroupMode, ADDON_STATUS_OK, ADDON_STATUS_OK); else if (settingName == "numRadioGroups") - return SetSetting(settingName, settingValue, m_numRadioGroups, ADDON_STATUS_OK, ADDON_STATUS_OK); + return SetSetting(settingName, settingValue, m_numRadioGroups, ADDON_STATUS_OK, ADDON_STATUS_OK); else if (settingName == "oneRadioGroup") return SetStringSetting(settingName, settingValue, m_oneRadioGroup, ADDON_STATUS_OK, ADDON_STATUS_OK); else if (settingName == "twoRadioGroup") @@ -332,7 +334,7 @@ ADDON_STATUS Settings::SetSetting(const std::string& settingName, const kodi::ad return ADDON_STATUS_OK; } -bool Settings::LoadCustomChannelGroupFile(std::string& xmlFile, std::vector& channelGroupNameList) +bool InstanceSettings::LoadCustomChannelGroupFile(std::string& xmlFile, std::vector& channelGroupNameList) { channelGroupNameList.clear(); diff --git a/src/iptvsimple/Settings.h b/src/iptvsimple/InstanceSettings.h similarity index 95% rename from src/iptvsimple/Settings.h rename to src/iptvsimple/InstanceSettings.h index 06af4dcae..b5e9a8785 100644 --- a/src/iptvsimple/Settings.h +++ b/src/iptvsimple/InstanceSettings.h @@ -25,10 +25,8 @@ namespace iptvsimple static const int DEFAULT_UDPXY_MULTICAST_RELAY_PORT = 4022; static const int DEFAULT_NUM_GROUPS = 1; - static const std::string CHANNEL_GROUPS_DIR = "/channelGroups"; static const std::string DEFAULT_CUSTOM_TV_GROUPS_FILE = ADDON_DATA_BASE_DIR + "/channelGroups/customTVGroups-example.xml"; static const std::string DEFAULT_CUSTOM_RADIO_GROUPS_FILE = ADDON_DATA_BASE_DIR + "/channelGroups/customRadioGroups-example.xml"; - static const std::string CHANNEL_GROUPS_ADDON_DATA_BASE_DIR = ADDON_DATA_BASE_DIR + CHANNEL_GROUPS_DIR; enum class PathType : int // same type as addon settings @@ -69,20 +67,17 @@ namespace iptvsimple ALL_CHANNELS }; - class Settings + class InstanceSettings { public: - Settings() {}; + explicit InstanceSettings(kodi::addon::IAddonInstance& instance, const kodi::addon::IInstanceInfo& instanceInfo); - void ReadSettings(); ADDON_STATUS SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue); - void ReadFromAddon(const std::string& userPath, const std::string& clientPath); - void ReloadAddonSettings(); - ADDON_STATUS SetValue(const std::string& settingName, const kodi::addon::CSettingValue& settingValue); + void ReadSettings(); + void ReloadAddonInstanceSettings(); - const std::string& GetUserPath() const { return m_userPath; } - const std::string& GetClientPath() const { return m_clientPath; } + const std::string GetUserPath() const { return kodi::addon::GetUserPath(); } const std::string& GetM3ULocation() const { return m_m3uPathType == PathType::REMOTE_PATH ? m_m3uUrl : m_m3uPath; } const PathType& GetM3UPathType() const { return m_m3uPathType; } @@ -176,6 +171,9 @@ namespace iptvsimple std::vector& GetCustomTVChannelGroupNameList() { return m_customTVChannelGroupNameList; } std::vector& GetCustomRadioChannelGroupNameList() { return m_customRadioChannelGroupNameList; } + const std::string GetM3UCacheFilename() { return M3U_CACHE_FILENAME + "-" + std::to_string(m_instanceNumber); } + const std::string GetXMLTVCacheFilename() { return XMLTV_CACHE_FILENAME + "-" + std::to_string(m_instanceNumber); } + private: template @@ -235,9 +233,6 @@ namespace iptvsimple static bool LoadCustomChannelGroupFile(std::string& file, std::vector& channelGroupNameList); - std::string m_userPath; - std::string m_clientPath; - // M3U PathType m_m3uPathType = PathType::REMOTE_PATH; std::string m_m3uPath; @@ -255,7 +250,7 @@ namespace iptvsimple // Groups bool m_allowTVChannelGroupsOnly = false; ChannelGroupMode m_tvChannelGroupMode = ChannelGroupMode::ALL_GROUPS; - unsigned int m_numTVGroups = DEFAULT_NUM_GROUPS; + int m_numTVGroups = DEFAULT_NUM_GROUPS; std::string m_oneTVGroup = ""; std::string m_twoTVGroup = ""; std::string m_threeTVGroup = ""; @@ -264,7 +259,7 @@ namespace iptvsimple std::string m_customTVGroupsFile = ""; bool m_allowRadioChannelGroupsOnly = false; ChannelGroupMode m_radioChannelGroupMode = ChannelGroupMode::ALL_GROUPS; - unsigned int m_numRadioGroups = DEFAULT_NUM_GROUPS; + int m_numRadioGroups = DEFAULT_NUM_GROUPS; std::string m_oneRadioGroup = ""; std::string m_twoRadioGroup = ""; std::string m_threeRadioGroup = ""; @@ -334,5 +329,8 @@ namespace iptvsimple std::vector m_customRadioChannelGroupNameList; std::string m_tvgUrl; + + kodi::addon::IAddonInstance& m_instance; + int m_instanceNumber = 0; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Media.cpp b/src/iptvsimple/Media.cpp index f45656c68..4caeedf47 100644 --- a/src/iptvsimple/Media.cpp +++ b/src/iptvsimple/Media.cpp @@ -18,7 +18,7 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; using namespace kodi::tools; -Media::Media(std::shared_ptr& settings) : m_settings(settings) +Media::Media(std::shared_ptr& settings) : m_settings(settings) { } diff --git a/src/iptvsimple/Media.h b/src/iptvsimple/Media.h index 977800282..9743600d6 100644 --- a/src/iptvsimple/Media.h +++ b/src/iptvsimple/Media.h @@ -19,7 +19,7 @@ namespace iptvsimple class ATTR_DLL_LOCAL Media { public: - Media(std::shared_ptr& settings); + Media(std::shared_ptr& settings); void GetMedia(std::vector& kodiRecordings); int GetNumMedia() const; void Clear(); @@ -39,6 +39,6 @@ namespace iptvsimple bool m_haveMediaTypes = false; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/PlaylistLoader.cpp b/src/iptvsimple/PlaylistLoader.cpp index c80a97901..75e32a712 100644 --- a/src/iptvsimple/PlaylistLoader.cpp +++ b/src/iptvsimple/PlaylistLoader.cpp @@ -7,7 +7,7 @@ #include "PlaylistLoader.h" -#include "Settings.h" +#include "InstanceSettings.h" #include "utilities/FileUtils.h" #include "utilities/Logger.h" #include "utilities/WebUtils.h" @@ -28,7 +28,7 @@ using namespace iptvsimple::data; using namespace iptvsimple::utilities; PlaylistLoader::PlaylistLoader(kodi::addon::CInstancePVRClient* client, Channels& channels, - ChannelGroups& channelGroups, Providers& providers, Media& media, std::shared_ptr& settings) + ChannelGroups& channelGroups, Providers& providers, Media& media, std::shared_ptr& settings) : m_channelGroups(channelGroups), m_channels(channels), m_providers(providers), m_media(media), m_client(client), m_settings(settings) { } bool PlaylistLoader::Init() @@ -53,7 +53,7 @@ bool PlaylistLoader::LoadPlayList() bool useM3UCache = m_settings->GetM3URefreshMode() != RefreshMode::DISABLED ? false : m_settings->UseM3UCache(); std::string playlistContent; - if (!FileUtils::GetCachedFileContents(m_settings, M3U_CACHE_FILENAME, m_m3uLocation, playlistContent, useM3UCache)) + if (!FileUtils::GetCachedFileContents(m_settings, m_settings->GetM3UCacheFilename(), m_m3uLocation, playlistContent, useM3UCache)) { Logger::Log(LEVEL_ERROR, "%s - Unable to load playlist cache file '%s': file is missing or empty.", __FUNCTION__, m_m3uLocation.c_str()); return false; diff --git a/src/iptvsimple/PlaylistLoader.h b/src/iptvsimple/PlaylistLoader.h index d87b27ada..593c93ef8 100644 --- a/src/iptvsimple/PlaylistLoader.h +++ b/src/iptvsimple/PlaylistLoader.h @@ -11,7 +11,7 @@ #include "ChannelGroups.h" #include "Providers.h" #include "Media.h" -#include "Settings.h" +#include "InstanceSettings.h" #include #include @@ -66,7 +66,7 @@ namespace iptvsimple public: PlaylistLoader(kodi::addon::CInstancePVRClient* client, iptvsimple::Channels& channels, iptvsimple::ChannelGroups& channelGroups, iptvsimple::Providers& providers, - iptvsimple::Media& media, std::shared_ptr& setting); + iptvsimple::Media& media, std::shared_ptr& setting); bool Init(); @@ -91,6 +91,6 @@ namespace iptvsimple M3UHeaderStrings m_m3uHeaderStrings; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/Providers.cpp b/src/iptvsimple/Providers.cpp index 97c5eb4e5..9d784e193 100644 --- a/src/iptvsimple/Providers.cpp +++ b/src/iptvsimple/Providers.cpp @@ -22,7 +22,7 @@ using namespace iptvsimple::utilities; using namespace kodi::tools; using namespace pugi; -Providers::Providers(std::shared_ptr& settings) : m_settings(settings) +Providers::Providers(std::shared_ptr& settings) : m_settings(settings) { } diff --git a/src/iptvsimple/Providers.h b/src/iptvsimple/Providers.h index efae103ad..b1dc85670 100644 --- a/src/iptvsimple/Providers.h +++ b/src/iptvsimple/Providers.h @@ -10,7 +10,7 @@ #include "data/Provider.h" -#include "Settings.h" +#include "InstanceSettings.h" #include #include @@ -27,7 +27,7 @@ namespace iptvsimple class ATTR_DLL_LOCAL Providers { public: - Providers(std::shared_ptr& settings); + Providers(std::shared_ptr& settings); bool Init(); @@ -54,6 +54,6 @@ namespace iptvsimple std::unordered_map m_providerMappingsMap; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace iptvsimple diff --git a/src/iptvsimple/data/BaseEntry.h b/src/iptvsimple/data/BaseEntry.h index c30ef7b4b..d3228f410 100644 --- a/src/iptvsimple/data/BaseEntry.h +++ b/src/iptvsimple/data/BaseEntry.h @@ -9,7 +9,7 @@ #pragma once #include "EpgGenre.h" -#include "../Settings.h" +#include "../InstanceSettings.h" #include #include @@ -119,7 +119,7 @@ namespace iptvsimple bool m_new = false; bool m_premiere = false; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace data } //namespace iptvsimple diff --git a/src/iptvsimple/data/Channel.cpp b/src/iptvsimple/data/Channel.cpp index 97554f3aa..4f061fb83 100644 --- a/src/iptvsimple/data/Channel.cpp +++ b/src/iptvsimple/data/Channel.cpp @@ -7,7 +7,7 @@ #include "Channel.h" -#include "../Settings.h" +#include "../InstanceSettings.h" #include "../utilities/FileUtils.h" #include "../utilities/Logger.h" #include "../utilities/StreamUtils.h" diff --git a/src/iptvsimple/data/Channel.h b/src/iptvsimple/data/Channel.h index f7da62170..36447ca01 100644 --- a/src/iptvsimple/data/Channel.h +++ b/src/iptvsimple/data/Channel.h @@ -30,7 +30,7 @@ namespace iptvsimple constexpr int IGNORE_CATCHUP_DAYS = -1; - class Settings; + class InstanceSettings; namespace data { @@ -41,7 +41,7 @@ namespace iptvsimple public: static const std::string GetCatchupModeText(const CatchupMode& catchupMode); - Channel(std::shared_ptr& settings) : m_settings(settings) {}; + Channel(std::shared_ptr settings) : m_settings(settings) {}; Channel(const Channel &c) : m_radio(c.IsRadio()), m_uniqueId(c.GetUniqueId()), m_channelNumber(c.GetChannelNumber()), m_subChannelNumber(c.GetSubChannelNumber()), m_encryptionSystem(c.GetEncryptionSystem()), m_tvgShift(c.GetTvgShift()), m_channelName(c.GetChannelName()), @@ -51,7 +51,7 @@ namespace iptvsimple m_catchupSourceTerminates(c.CatchupSourceTerminates()), m_catchupGranularitySeconds(c.GetCatchupGranularitySeconds()), m_catchupCorrectionSecs(c.GetCatchupCorrectionSecs()), m_tvgId(c.GetTvgId()), m_tvgName(c.GetTvgName()), m_providerUniqueId(c.GetProviderUniqueId()), m_properties(c.GetProperties()), - m_inputStreamName(c.GetInputStreamName()) { m_settings = c.GetSettings(); }; + m_inputStreamName(c.GetInputStreamName()), m_settings(c.m_settings) {}; ~Channel() = default; bool IsRadio() const { return m_radio; } @@ -139,8 +139,6 @@ namespace iptvsimple bool ChannelTypeAllowsGroupsOnly() const; - const std::shared_ptr& GetSettings() const { return m_settings; } - private: void RemoveProperty(const std::string& propName); void TryToAddPropertyAsHeader(const std::string& propertyName, const std::string& headerName); @@ -175,7 +173,7 @@ namespace iptvsimple std::map m_properties; std::string m_inputStreamName; - std::shared_ptr m_settings; + std::shared_ptr m_settings; }; } //namespace data } //namespace iptvsimple diff --git a/src/iptvsimple/data/EpgEntry.cpp b/src/iptvsimple/data/EpgEntry.cpp index 2041b574d..e421b1ca9 100644 --- a/src/iptvsimple/data/EpgEntry.cpp +++ b/src/iptvsimple/data/EpgEntry.cpp @@ -7,7 +7,7 @@ #include "EpgEntry.h" -#include "../Settings.h" +#include "../InstanceSettings.h" #include "../utilities/TimeUtils.h" #include "../utilities/XMLUtils.h" diff --git a/src/iptvsimple/data/EpgEntry.h b/src/iptvsimple/data/EpgEntry.h index 1556e88d0..302fff0da 100644 --- a/src/iptvsimple/data/EpgEntry.h +++ b/src/iptvsimple/data/EpgEntry.h @@ -27,7 +27,7 @@ namespace iptvsimple { public: EpgEntry() {}; - EpgEntry(std::shared_ptr settings) + EpgEntry(std::shared_ptr settings) { m_settings = settings; }; diff --git a/src/iptvsimple/data/MediaEntry.cpp b/src/iptvsimple/data/MediaEntry.cpp index 510a3ab2e..bce21bbb6 100644 --- a/src/iptvsimple/data/MediaEntry.cpp +++ b/src/iptvsimple/data/MediaEntry.cpp @@ -8,7 +8,7 @@ #include "MediaEntry.h" -#include "../Settings.h" +#include "../InstanceSettings.h" #include #include @@ -134,7 +134,7 @@ std::string GetEpisodePrefix(int episodeNumber) return {}; } -std::string CreateTitle(const std::string& title, int seasonNumber, int episodeNumber, std::shared_ptr settings) +std::string CreateTitle(const std::string& title, int seasonNumber, int episodeNumber, std::shared_ptr settings) { std::string newTitle; diff --git a/src/iptvsimple/data/MediaEntry.h b/src/iptvsimple/data/MediaEntry.h index cb71f186d..b8fbe396d 100644 --- a/src/iptvsimple/data/MediaEntry.h +++ b/src/iptvsimple/data/MediaEntry.h @@ -23,7 +23,7 @@ namespace iptvsimple class ATTR_DLL_LOCAL MediaEntry : public BaseEntry { public: - MediaEntry(std::shared_ptr settings) + MediaEntry(std::shared_ptr settings) { m_settings = settings; }; diff --git a/src/iptvsimple/utilities/FileUtils.cpp b/src/iptvsimple/utilities/FileUtils.cpp index d90d2614d..05e2a3467 100644 --- a/src/iptvsimple/utilities/FileUtils.cpp +++ b/src/iptvsimple/utilities/FileUtils.cpp @@ -7,7 +7,7 @@ #include "FileUtils.h" -#include "../Settings.h" +#include "../InstanceSettings.h" #include #include @@ -169,7 +169,7 @@ bool FileUtils::XzDecompress(const std::string& compressedBytes, std::string& un return true; } -int FileUtils::GetCachedFileContents(std::shared_ptr& settings, +int FileUtils::GetCachedFileContents(std::shared_ptr& settings, const std::string& cachedName, const std::string& filePath, std::string& contents, const bool useCache /* false */) { diff --git a/src/iptvsimple/utilities/FileUtils.h b/src/iptvsimple/utilities/FileUtils.h index 4d856dfb4..1ce87523f 100644 --- a/src/iptvsimple/utilities/FileUtils.h +++ b/src/iptvsimple/utilities/FileUtils.h @@ -13,7 +13,7 @@ namespace iptvsimple { - class Settings; + class InstanceSettings; namespace utilities { @@ -27,7 +27,7 @@ namespace iptvsimple static int GetFileContents(const std::string& url, std::string& content); static bool GzipInflate(const std::string& compressedBytes, std::string& uncompressedBytes); static bool XzDecompress(const std::string& compressedBytes, std::string& uncompressedBytes); - static int GetCachedFileContents(std::shared_ptr& settings, + static int GetCachedFileContents(std::shared_ptr& settings, const std::string& cachedName, const std::string& filePath, std::string& content, const bool useCache = false); static bool FileExists(const std::string& file); diff --git a/src/iptvsimple/utilities/StreamUtils.cpp b/src/iptvsimple/utilities/StreamUtils.cpp index b43156ef2..c98e8b9f1 100644 --- a/src/iptvsimple/utilities/StreamUtils.cpp +++ b/src/iptvsimple/utilities/StreamUtils.cpp @@ -7,7 +7,7 @@ #include "StreamUtils.h" -#include "../Settings.h" +#include "../InstanceSettings.h" #include "FileUtils.h" #include "Logger.h" #include "WebUtils.h" @@ -20,7 +20,7 @@ using namespace iptvsimple; using namespace iptvsimple::data; using namespace iptvsimple::utilities; -void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings) +void StreamUtils::SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings) { if (ChannelSpecifiesInputstream(channel)) { @@ -148,7 +148,7 @@ bool StreamUtils::CheckInputstreamInstalledAndEnabled(const std::string& inputst return true; } -void StreamUtils::InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::shared_ptr& settings) +void StreamUtils::InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, bool isChannelURL, std::shared_ptr& settings) { // If there is no MIME type and no manifest type (BOTH!) set then potentially inspect the stream and set them if (!channel.HasMimeType() && !channel.GetProperty("inputstream.ffmpegdirect.manifest_type").empty()) @@ -182,7 +182,7 @@ void StreamUtils::SetFFmpegDirectManifestTypeStreamProperty(std::vector& settings) +std::string StreamUtils::GetEffectiveInputStreamName(const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings) { std::string inputStreamName = channel.GetInputStreamName(); @@ -301,7 +301,7 @@ bool StreamUtils::HasMimeType(const StreamType& streamType) return streamType != StreamType::OTHER_TYPE && streamType != StreamType::SMOOTH_STREAMING; } -std::string StreamUtils::GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings) +std::string StreamUtils::GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings) { std::string newStreamUrl = streamUrl; @@ -352,7 +352,7 @@ std::string StreamUtils::AddHeader(const std::string& headerTarget, const std::s return newHeaderTarget; } -bool StreamUtils::UseKodiInputstreams(const StreamType& streamType, std::shared_ptr& settings) +bool StreamUtils::UseKodiInputstreams(const StreamType& streamType, std::shared_ptr& settings) { return streamType == StreamType::OTHER_TYPE || streamType == StreamType::TS || streamType == StreamType::PLUGIN || (streamType == StreamType::HLS && !settings->UseInputstreamAdaptiveforHls()); diff --git a/src/iptvsimple/utilities/StreamUtils.h b/src/iptvsimple/utilities/StreamUtils.h index 4440b32e4..93115d1b3 100644 --- a/src/iptvsimple/utilities/StreamUtils.h +++ b/src/iptvsimple/utilities/StreamUtils.h @@ -17,7 +17,7 @@ namespace iptvsimple { - class Settings; + class InstanceSettings; namespace utilities { @@ -28,23 +28,23 @@ namespace iptvsimple class StreamUtils { public: - static void SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings); + static void SetAllStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::map& catchupProperties, std::shared_ptr& settings); static const StreamType GetStreamType(const std::string& url, const iptvsimple::data::Channel& channel); static const StreamType InspectStreamType(const std::string& url, const iptvsimple::data::Channel& channel); static const std::string GetManifestType(const StreamType& streamType); static const std::string GetMimeType(const StreamType& streamType); static bool HasMimeType(const StreamType& streamType); - static std::string GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings); + static std::string GetURLWithFFmpegReconnectOptions(const std::string& streamUrl, const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings); static std::string AddHeader(const std::string& headerTarget, const std::string& headerName, const std::string& headerValue, bool encodeHeaderValue); static std::string AddHeaderToStreamUrl(const std::string& streamUrl, const std::string& headerName, const std::string& headerValue); - static bool UseKodiInputstreams(const StreamType& streamType, std::shared_ptr& settings); + static bool UseKodiInputstreams(const StreamType& streamType, std::shared_ptr& settings); static bool ChannelSpecifiesInputstream(const iptvsimple::data::Channel& channe); static std::string GetUrlEncodedProtocolOptions(const std::string& protocolOptions); - static std::string GetEffectiveInputStreamName(const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings); + static std::string GetEffectiveInputStreamName(const StreamType& streamType, const iptvsimple::data::Channel& channel, std::shared_ptr& settings); private: static bool SupportsFFmpegReconnect(const StreamType& streamType, const iptvsimple::data::Channel& channel); - static void InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::shared_ptr& settings); + static void InspectAndSetFFmpegDirectStreamProperties(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamUrl, bool isChannelURL, std::shared_ptr& settings); static void SetFFmpegDirectManifestTypeStreamProperty(std::vector& properties, const iptvsimple::data::Channel& channel, const std::string& streamURL, const StreamType& streamType); static bool CheckInputstreamInstalledAndEnabled(const std::string& inputstreamName); From 64d28a9eea68d5e5be3812bebe9c9b75f9a535b2 Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Thu, 9 Feb 2023 22:39:56 +0000 Subject: [PATCH 3/4] Settings migration --- CMakeLists.txt | 2 + pvr.iptvsimple/resources/settings.xml | 387 +++++++++++++++++- src/addon.cpp | 8 + src/iptvsimple/AddonSettings.cpp | 7 + .../utilities/SettingsMigration.cpp | 189 +++++++++ src/iptvsimple/utilities/SettingsMigration.h | 46 +++ 6 files changed, 638 insertions(+), 1 deletion(-) create mode 100644 src/iptvsimple/utilities/SettingsMigration.cpp create mode 100644 src/iptvsimple/utilities/SettingsMigration.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c84ae0e7..521b1c3f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ set(IPTV_SOURCES src/addon.cpp src/iptvsimple/data/MediaEntry.cpp src/iptvsimple/utilities/FileUtils.cpp src/iptvsimple/utilities/Logger.cpp + src/iptvsimple/utilities/SettingsMigration.cpp src/iptvsimple/utilities/StreamUtils.cpp src/iptvsimple/utilities/WebUtils.cpp) @@ -68,6 +69,7 @@ set(IPTV_HEADERS src/addon.h src/iptvsimple/data/StreamEntry.h src/iptvsimple/utilities/FileUtils.h src/iptvsimple/utilities/Logger.h + src/iptvsimple/utilities/SettingsMigration.h src/iptvsimple/utilities/StreamUtils.h src/iptvsimple/utilities/TimeUtils.h src/iptvsimple/utilities/WebUtils.h diff --git a/pvr.iptvsimple/resources/settings.xml b/pvr.iptvsimple/resources/settings.xml index 58632c853..b64cab3f4 100644 --- a/pvr.iptvsimple/resources/settings.xml +++ b/pvr.iptvsimple/resources/settings.xml @@ -4,9 +4,394 @@ + settings definition to work. + + Note that empty default values still require an allowempty constraint --> + + 4 + 1 + + + 4 + + + true + + + + 4 + + + true + + + + 4 + true + + + 4 + 1 + + + 4 + false + + + + + 4 + 0 + + + 4 + 60 + + + 4 + 4 + + + + 4 + + + true + + + + 4 + false + + + 4 + special://userdata/addon_data/pvr.iptvsimple/providers/providerMappings.xml + + + + + 4 + 0 + + + 4 + 1 + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + special://userdata/addon_data/pvr.iptvsimple/channelGroups/customTVGroups-example.xml + + + 4 + false + + + + 4 + 0 + + + 4 + 1 + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + + + 4 + special://userdata/addon_data/pvr.iptvsimple/channelGroups/customRadioGroups-example.xml + + + 4 + false + + + + + 4 + 1 + + + 4 + + + true + + + + 4 + + + true + + + + 4 + true + + + 4 + 0 + + + 4 + false + + + 4 + true + + + + + 4 + false + + + 4 + 0 + + + 4 + special://userdata/addon_data/pvr.iptvsimple/genres/genreTextMappings/genres.xml + + + 4 + + + true + + + + + + 4 + 1 + + + 4 + + + true + + + + 4 + + + true + + + + 4 + false + + + 4 + 1 + + + + + 4 + true + + + 4 + true + + + 4 + true + + + 4 + false + + + 4 + true + + + + + 4 + false + + + 4 + true + + + 4 + true + + + 4 + true + + + 4 + false + + + + + 4 + false + + + 4 + + + true + + + + 4 + 5 + + + 4 + 0 + + + 4 + 0 + + + 4 + 0 + + + 4 + false + + + 4 + 5 + + + 4 + 15 + + + 4 + false + + + + + 4 + false + + + 4 + 127.0.0.1 + + + 4 + 4022 + + + 4 + true + + + 4 + false + + + 4 + + + true + + + + 4 + + + true + + + + 4 + + + true + + +
diff --git a/src/addon.cpp b/src/addon.cpp index f156728ce..07f10a0c2 100644 --- a/src/addon.cpp +++ b/src/addon.cpp @@ -7,6 +7,7 @@ #include "addon.h" #include "IptvSimple.h" +#include "iptvsimple/utilities/SettingsMigration.h" using namespace iptvsimple; using namespace iptvsimple::data; @@ -67,6 +68,13 @@ ADDON_STATUS CIptvSimpleAddon::CreateInstance(const kodi::addon::IInstanceInfo& return ADDON_STATUS_PERMANENT_FAILURE; } + // Try to migrate settings from a pre-multi-instance setup + if (SettingsMigration::MigrateSettings(*usedInstance)) + { + // Initial client operated on old/incomplete settings + delete usedInstance; + usedInstance = new IptvSimple(instance); + } hdl = usedInstance; // Store this instance also on this class, currently support Kodi only one diff --git a/src/iptvsimple/AddonSettings.cpp b/src/iptvsimple/AddonSettings.cpp index 3ee03981f..babdf27e8 100644 --- a/src/iptvsimple/AddonSettings.cpp +++ b/src/iptvsimple/AddonSettings.cpp @@ -9,6 +9,7 @@ #include "utilities/FileUtils.h" #include "utilities/Logger.h" +#include "utilities/SettingsMigration.h" #include "kodi/General.h" @@ -30,5 +31,11 @@ void AddonSettings::ReadSettings() ADDON_STATUS AddonSettings::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) { + if (SettingsMigration::IsMigrationSetting(settingName)) + { + // ignore settings from pre-multi-instance setup + return ADDON_STATUS_OK; + } + return ADDON_STATUS_UNKNOWN; } diff --git a/src/iptvsimple/utilities/SettingsMigration.cpp b/src/iptvsimple/utilities/SettingsMigration.cpp new file mode 100644 index 000000000..e9628422c --- /dev/null +++ b/src/iptvsimple/utilities/SettingsMigration.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2022 Team Kodi (https://kodi.tv) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#include "SettingsMigration.h" + +#include "kodi/General.h" + +#include +#include +#include + +using namespace iptvsimple; +using namespace iptvsimple::utilities; + +namespace +{ +// maps +const std::vector> stringMap = {{"m3uPath", ""}, + {"m3uUrl", ""}, + {"defaultProviderName", ""}, + {"providerMappingFile", "special://userdata/addon_data/pvr.iptvsimple/providers/providerMappings.xml"}, + {"onetvgroup", ""}, + {"twotvgroup", ""}, + {"threetvgroup", ""}, + {"fourtvgroup", ""}, + {"fivetvgroup", ""}, + {"customtvgroupsfile", "special://userdata/addon_data/pvr.iptvsimple/channelGroups/customTVGroups-example.xml"}, + {"oneradiogroup", ""}, + {"tworadiogroup", ""}, + {"threeradiogroup", ""}, + {"fourradiogroup", ""}, + {"fiveradiogroup", ""}, + {"customradiogroupsfile", "special://userdata/addon_data/pvr.iptvsimple/channelGroups/customRadioGroups-example.xml"}, + {"epgPath", ""}, + {"epgUrl", ""}, + {"genresPath", "special://userdata/addon_data/pvr.iptvsimple/genres/genreTextMappings/genres.xml"}, + {"genresUrl", ""}, + {"logoPath", ""}, + {"logoBaseUrl", ""}, + {"udpxyHost", "127.0.0.1"}, + {"defaultUserAgent", ""}, + {"defaultInputstream", ""}, + {"defaultMimeType", ""}}; + +const std::vector> intMap = {{"m3uPathType", 0}, + {"startNum", 1}, + {"m3uRefreshMode", 0}, + {"m3uRefreshIntervalMins", 60}, + {"m3uRefreshHour", 4}, + {"tvgroupmode", 0}, + {"numtvgroups", 1}, + {"radiogroupmode", 0}, + {"numradiogroups", 1}, + {"epgPathType", 1}, + {"genresPathType", 0}, + {"logoPathType", 1}, + {"logoFromEpg", 1}, + {"catchupDays", 5}, + {"allChannelsCatchupMode", 0}, + {"catchupWatchEpgBeginBufferMins", 5}, + {"catchupWatchEpgEndBufferMins", 15}, + {"udpxyPort", 4022}}; + +const std::vector> floatMap = {{"epgTimeShift", 0.0}, + {"catchupCorrection", 0.0}}; + +const std::vector> boolMap = {{"m3uCache", true}, + {"numberByOrder", false}, + {"enableProviderMappings", false}, + {"tvChannelGroupsOnly", false}, + {"radioChannelGroupsOnly", false}, + {"epgCache", true}, + {"epgTSOverride", false}, + {"epgIgnoreCaseForChannelIds", true}, + {"useEpgGenreText", false}, + {"useLogosLocalPathOnly", false}, + {"mediaEnabled", true}, + {"mediaGroupByTitle", true}, + {"mediaGroupBySeason", true}, + {"mediaTitleSeasonEpisode", false}, + {"mediaVODAsRecordings", true}, + {"timeshiftEnabled", false}, + {"timeshiftEnabledAll", true}, + {"timeshiftEnabledHttp", true}, + {"timeshiftEnabledUdp", true}, + {"timeshiftEnabledCustom", false}, + {"catchupEnabled", false}, + {"catchupPlayEpgAsLive", false}, + {"catchupOnlyOnFinishedProgrammes", false}, + {"transformMulticastStreamUrls", false}, + {"useFFmpegReconnect", true}, + {"useInputstreamAdaptiveforHls", false}}; + +} // unnamed namespace + +bool SettingsMigration::MigrateSettings(kodi::addon::IAddonInstance& target) +{ + std::string stringValue; + bool boolValue{false}; + int intValue{0}; + + if (target.CheckInstanceSettingString("kodi_addon_instance_name", stringValue) && + !stringValue.empty()) + { + // Instance already has valid instance settings + return false; + } + + // Read pre-multi-instance settings from settings.xml, transfer to instance settings + SettingsMigration mig(target); + + for (const auto& setting : stringMap) + mig.MigrateStringSetting(setting.first, setting.second); + + for (const auto& setting : intMap) + mig.MigrateIntSetting(setting.first, setting.second); + + for (const auto& setting : floatMap) + mig.MigrateFloatSetting(setting.first, setting.second); + + for (const auto& setting : boolMap) + mig.MigrateBoolSetting(setting.first, setting.second); + + if (mig.Changed()) + { + // Set a title for the new instance settings + std::string title = "Migrated Add-on Config"; + target.SetInstanceSettingString("kodi_addon_instance_name", title); + + return true; + } + return false; +} + +bool SettingsMigration::IsMigrationSetting(const std::string& key) +{ + return std::any_of(stringMap.cbegin(), stringMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(intMap.cbegin(), intMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(floatMap.cbegin(), floatMap.cend(), + [&key](const auto& entry) { return entry.first == key; }) || + std::any_of(boolMap.cbegin(), boolMap.cend(), + [&key](const auto& entry) { return entry.first == key; }); +} + +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::MigrateFloatSetting(const char* key, float defaultValue) +{ + float value; + if (kodi::addon::CheckSettingFloat(key, value) && value != defaultValue) + { + m_target.SetInstanceSettingFloat(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 --git a/src/iptvsimple/utilities/SettingsMigration.h b/src/iptvsimple/utilities/SettingsMigration.h new file mode 100644 index 000000000..aca076593 --- /dev/null +++ b/src/iptvsimple/utilities/SettingsMigration.h @@ -0,0 +1,46 @@ +/* + * 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 iptvsimple +{ +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 MigrateFloatSetting(const char* key, float defaultValue); + void MigrateBoolSetting(const char* key, bool defaultValue); + + bool Changed() const { return m_changed; } + + kodi::addon::IAddonInstance& m_target; + bool m_changed{false}; +}; + +} // namespace utilities +} // namespace iptvsimple From ebddcf0ab9ffad9482b200da59002093180702d9 Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Sun, 12 Feb 2023 14:19:16 +0000 Subject: [PATCH 4/4] changelog and version 21.1.0 --- pvr.iptvsimple/addon.xml.in | 2 +- pvr.iptvsimple/changelog.txt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pvr.iptvsimple/addon.xml.in b/pvr.iptvsimple/addon.xml.in index 80f90b58d..9e0801d78 100644 --- a/pvr.iptvsimple/addon.xml.in +++ b/pvr.iptvsimple/addon.xml.in @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ diff --git a/pvr.iptvsimple/changelog.txt b/pvr.iptvsimple/changelog.txt index a19dec82f..b756efed2 100644 --- a/pvr.iptvsimple/changelog.txt +++ b/pvr.iptvsimple/changelog.txt @@ -1,3 +1,6 @@ +v21.1.0 +- Add support for multiple instances each supporting their own M3U/XMLTV and settings + v20.7.0 - Add setting to make matching channel IDs and tvg-id's case sensitive