1 /*
2  *  Copyright (C) 2005-2021 Team Kodi (https://kodi.tv)
3  *
4  *  SPDX-License-Identifier: GPL-2.0-or-later
5  *  See LICENSE.md for more information.
6  */
7 
8 #pragma once
9 
10 #include "data/Channel.h"
11 #include "utilities/Logger.h"
12 
13 #include <string>
14 #include <type_traits>
15 
16 #include <kodi/AddonBase.h>
17 
18 namespace iptvsimple
19 {
20   static const std::string M3U_CACHE_FILENAME = "iptv.m3u.cache";
21   static const std::string XMLTV_CACHE_FILENAME = "xmltv.xml.cache";
22   static const std::string ADDON_DATA_BASE_DIR = "special://userdata/addon_data/pvr.iptvsimple";
23   static const std::string DEFAULT_GENRE_TEXT_MAP_FILE = ADDON_DATA_BASE_DIR + "/genres/genreTextMappings/genres.xml";
24   static const int DEFAULT_UDPXY_MULTICAST_RELAY_PORT = 4022;
25 
26   static const int DEFAULT_NUM_GROUPS = 1;
27   static const std::string CHANNEL_GROUPS_DIR = "/channelGroups";
28   static const std::string DEFAULT_CUSTOM_TV_GROUPS_FILE = ADDON_DATA_BASE_DIR + "/channelGroups/customTVGroups-example.xml";
29   static const std::string DEFAULT_CUSTOM_RADIO_GROUPS_FILE = ADDON_DATA_BASE_DIR + "/channelGroups/customRadioGroups-example.xml";
30   static const std::string CHANNEL_GROUPS_ADDON_DATA_BASE_DIR = ADDON_DATA_BASE_DIR + CHANNEL_GROUPS_DIR;
31 
32   enum class PathType
33     : int // same type as addon settings
34   {
35     LOCAL_PATH = 0,
36     REMOTE_PATH
37   };
38 
39   enum class RefreshMode
40     : int // same type as addon settings
41   {
42     DISABLED = 0,
43     REPEATED_REFRESH,
44     ONCE_PER_DAY
45   };
46 
47   enum class ChannelGroupMode
48     : int // same type as addon settings
49   {
50     ALL_GROUPS = 0,
51     SOME_GROUPS,
52     CUSTOM_GROUPS
53   };
54 
55   enum class EpgLogosMode
56     : int // same type as addon settings
57   {
58     IGNORE_XMLTV = 0,
59     PREFER_M3U,
60     PREFER_XMLTV
61   };
62 
63   enum class CatchupOverrideMode
64     : int // same type as addon settings
65   {
66     WITHOUT_TAGS = 0,
67     WITH_TAGS,
68     ALL_CHANNELS
69   };
70 
71   class Settings
72   {
73   public:
74     /**
75      * Singleton getter for the instance
76      */
GetInstance()77     static Settings& GetInstance()
78     {
79       static Settings settings;
80       return settings;
81     }
82 
83     void ReadFromAddon(const std::string& userPath, const std::string& clientPath);
84     void ReloadAddonSettings();
85     ADDON_STATUS SetValue(const std::string& settingName, const kodi::CSettingValue& settingValue);
86 
GetUserPath()87     const std::string& GetUserPath() const { return m_userPath; }
GetClientPath()88     const std::string& GetClientPath() const { return m_clientPath; }
89 
GetM3ULocation()90     const std::string& GetM3ULocation() const { return m_m3uPathType == PathType::REMOTE_PATH ? m_m3uUrl : m_m3uPath; }
GetM3UPathType()91     const PathType& GetM3UPathType() const { return m_m3uPathType; }
GetM3UPath()92     const std::string& GetM3UPath() const { return m_m3uPath; }
GetM3UUrl()93     const std::string& GetM3UUrl() const { return m_m3uUrl; }
UseM3UCache()94     bool UseM3UCache() const { return m_m3uPathType == PathType::REMOTE_PATH ? m_cacheM3U : false; }
GetStartChannelNumber()95     int GetStartChannelNumber() const { return m_startChannelNumber; }
NumberChannelsByM3uOrderOnly()96     bool NumberChannelsByM3uOrderOnly() const { return m_numberChannelsByM3uOrderOnly; }
GetM3URefreshMode()97     const RefreshMode& GetM3URefreshMode() const { return m_m3uRefreshMode; }
GetM3URefreshIntervalMins()98     int GetM3URefreshIntervalMins() const { return m_m3uRefreshIntervalMins; }
GetM3URefreshHour()99     int GetM3URefreshHour() const { return m_m3uRefreshHour; }
AllowTVChannelGroupsOnly()100     bool AllowTVChannelGroupsOnly() const { return m_allowTVChannelGroupsOnly; }
GetTVChannelGroupMode()101     const ChannelGroupMode& GetTVChannelGroupMode() const { return m_tvChannelGroupMode; }
GetCustomTVGroupsFile()102     const std::string& GetCustomTVGroupsFile() const { return m_customTVGroupsFile; }
AllowRadioChannelGroupsOnly()103     bool AllowRadioChannelGroupsOnly() const { return m_allowRadioChannelGroupsOnly; }
GetRadioChannelGroupMode()104     const ChannelGroupMode& GetRadioChannelGroupMode() const { return m_radioChannelGroupMode; }
GetCustomRadioGroupsFile()105     const std::string& GetCustomRadioGroupsFile() const { return m_customRadioGroupsFile; }
106 
GetEpgLocation()107     const std::string& GetEpgLocation() const
108     {
109       const std::string& epgLocation = m_epgPathType == PathType::REMOTE_PATH ? m_epgUrl : m_epgPath;
110       return epgLocation.empty() ? m_tvgUrl : epgLocation;
111     }
GetEpgPathType()112     const PathType& GetEpgPathType() const { return m_epgPathType; }
GetEpgPath()113     const std::string& GetEpgPath() const { return m_epgPath; }
GetEpgUrl()114     const std::string& GetEpgUrl() const { return m_epgUrl; }
UseEPGCache()115     bool UseEPGCache() const { return m_epgPathType == PathType::REMOTE_PATH ? m_cacheEPG : false; }
GetEpgTimeshiftHours()116     float GetEpgTimeshiftHours() const { return m_epgTimeShiftHours; }
GetEpgTimeshiftSecs()117     int GetEpgTimeshiftSecs() const { return static_cast<int>(m_epgTimeShiftHours * 60 * 60); }
GetTsOverride()118     bool GetTsOverride() const { return m_tsOverride; }
AlwaysLoadEPGData()119     bool AlwaysLoadEPGData() const { return m_epgLogosMode == EpgLogosMode::PREFER_XMLTV || IsCatchupEnabled(); }
120 
GetGenresLocation()121     const std::string& GetGenresLocation() const { return m_genresPathType == PathType::REMOTE_PATH ? m_genresUrl : m_genresPath; }
UseEpgGenreTextWhenMapping()122     bool UseEpgGenreTextWhenMapping() const { return m_useEpgGenreTextWhenMapping; }
GetGenresPathType()123     const PathType& GetGenresPathType() const { return m_genresPathType; }
GetGenresPath()124     const std::string& GetGenresPath() const { return m_genresPath; }
GetGenresUrl()125     const std::string& GetGenresUrl() const { return m_genresUrl; }
126 
GetLogoLocation()127     const std::string& GetLogoLocation() const { return m_logoPathType == PathType::REMOTE_PATH ? m_logoBaseUrl : m_logoPath; }
GetLogoPathType()128     const PathType& GetLogoPathType() const { return m_logoPathType; }
GetLogoPath()129     const std::string& GetLogoPath() const { return m_logoPath; }
GetLogoBaseUrl()130     const std::string& GetLogoBaseUrl() const { return m_logoBaseUrl; }
GetEpgLogosMode()131     const EpgLogosMode& GetEpgLogosMode() const { return m_epgLogosMode; }
UseLocalLogosOnlyIgnoreM3U()132     bool UseLocalLogosOnlyIgnoreM3U() const { return m_useLocalLogosOnly; }
133 
IsTimeshiftEnabled()134     bool IsTimeshiftEnabled() const { return m_timeshiftEnabled; }
IsTimeshiftEnabledAll()135     bool IsTimeshiftEnabledAll() const { return m_timeshiftEnabledAll; }
IsTimeshiftEnabledHttp()136     bool IsTimeshiftEnabledHttp() const { return m_timeshiftEnabledHttp; }
IsTimeshiftEnabledUdp()137     bool IsTimeshiftEnabledUdp() const { return m_timeshiftEnabledUdp; }
AlwaysEnableTimeshiftModeIfMissing()138     bool AlwaysEnableTimeshiftModeIfMissing() const { return m_timeshiftEnabledCustom; }
139 
IsCatchupEnabled()140     bool IsCatchupEnabled() const { return m_catchupEnabled; }
GetCatchupQueryFormat()141     const std::string& GetCatchupQueryFormat() const { return m_catchupQueryFormat; }
GetCatchupDays()142     int GetCatchupDays() const { return m_catchupDays; }
GetCatchupDaysInSeconds()143     time_t GetCatchupDaysInSeconds() const { return static_cast<time_t>(m_catchupDays) * 24 * 60 * 60; }
GetAllChannelsCatchupMode()144     const CatchupMode& GetAllChannelsCatchupMode() const { return m_allChannelsCatchupMode; }
GetCatchupOverrideMode()145     const CatchupOverrideMode& GetCatchupOverrideMode() const { return m_catchupOverrideMode; }
GetCatchupCorrectionHours()146     float GetCatchupCorrectionHours() const { return m_catchupCorrectionHours; }
GetCatchupCorrectionSecs()147     int GetCatchupCorrectionSecs() const { return static_cast<int>(m_catchupCorrectionHours * 60 * 60); }
CatchupPlayEpgAsLive()148     bool CatchupPlayEpgAsLive() const { return m_catchupPlayEpgAsLive; }
GetCatchupWatchEpgBeginBufferMins()149     int GetCatchupWatchEpgBeginBufferMins() const { return m_catchupWatchEpgBeginBufferMins; }
GetCatchupWatchEpgBeginBufferSecs()150     time_t GetCatchupWatchEpgBeginBufferSecs() const { return static_cast<time_t>(m_catchupWatchEpgBeginBufferMins) * 60; }
GetCatchupWatchEpgEndBufferMins()151     int GetCatchupWatchEpgEndBufferMins() const { return m_catchupWatchEpgEndBufferMins; }
GetCatchupWatchEpgEndBufferSecs()152     time_t GetCatchupWatchEpgEndBufferSecs() const { return static_cast<time_t>(m_catchupWatchEpgEndBufferMins) * 60; }
CatchupOnlyOnFinishedProgrammes()153     bool CatchupOnlyOnFinishedProgrammes() const { return m_catchupOnlyOnFinishedProgrammes; }
154 
TransformMulticastStreamUrls()155     bool TransformMulticastStreamUrls() const { return m_transformMulticastStreamUrls; }
GetUdpxyHost()156     const std::string& GetUdpxyHost() const { return m_udpxyHost; }
GetUdpxyPort()157     int GetUdpxyPort() const { return m_udpxyPort; }
UseFFmpegReconnect()158     bool UseFFmpegReconnect() const { return m_useFFmpegReconnect; }
UseInputstreamAdaptiveforHls()159     bool UseInputstreamAdaptiveforHls() const { return m_useInputstreamAdaptiveforHls; }
GetDefaultUserAgent()160     const std::string& GetDefaultUserAgent() const { return m_defaultUserAgent; }
GetDefaultInputstream()161     const std::string& GetDefaultInputstream() const { return m_defaultInputstream; }
GetDefaultMimeType()162     const std::string& GetDefaultMimeType() const { return m_defaultMimeType; }
163 
GetTvgUrl()164     const std::string& GetTvgUrl() const { return m_tvgUrl; }
SetTvgUrl(const std::string & tvgUrl)165     void SetTvgUrl(const std::string& tvgUrl) { m_tvgUrl = tvgUrl; }
166 
GetCustomTVChannelGroupNameList()167     std::vector<std::string>& GetCustomTVChannelGroupNameList() { return m_customTVChannelGroupNameList; }
GetCustomRadioChannelGroupNameList()168     std::vector<std::string>& GetCustomRadioChannelGroupNameList() { return m_customRadioChannelGroupNameList; }
169 
170   private:
171     Settings() = default;
172 
173     Settings(Settings const&) = delete;
174     void operator=(Settings const&) = delete;
175 
176     template<typename T, typename V>
SetSetting(const std::string & settingName,const kodi::CSettingValue & settingValue,T & currentValue,V returnValueIfChanged,V defaultReturnValue)177     V SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue, T& currentValue, V returnValueIfChanged, V defaultReturnValue)
178     {
179       T newValue;
180       if (std::is_same<T, float>::value)
181         newValue = static_cast<T>(settingValue.GetFloat());
182       else if (std::is_same<T, bool>::value)
183         newValue = static_cast<T>(settingValue.GetBoolean());
184       else if (std::is_same<T, unsigned int>::value)
185         newValue = static_cast<T>(settingValue.GetUInt());
186       else
187         newValue = static_cast<T>(settingValue.GetInt());
188 
189       if (newValue != currentValue)
190       {
191         std::string formatString = "%s - Changed Setting '%s' from %d to %d";
192         if (std::is_same<T, float>::value)
193           formatString = "%s - Changed Setting '%s' from %f to %f";
194         utilities::Logger::Log(utilities::LogLevel::LEVEL_INFO, formatString.c_str(), __FUNCTION__, settingName.c_str(), currentValue, newValue);
195         currentValue = newValue;
196         return returnValueIfChanged;
197       }
198 
199       return defaultReturnValue;
200     }
201 
202     template<typename T, typename V>
SetEnumSetting(const std::string & settingName,const kodi::CSettingValue & settingValue,T & currentValue,V returnValueIfChanged,V defaultReturnValue)203     V SetEnumSetting(const std::string& settingName, const kodi::CSettingValue& settingValue, T& currentValue, V returnValueIfChanged, V defaultReturnValue)
204     {
205       T newValue = settingValue.GetEnum<T>();
206       if (newValue != currentValue)
207       {
208         utilities::Logger::Log(utilities::LogLevel::LEVEL_INFO, "%s - Changed Setting '%s' from %d to %d", __FUNCTION__, settingName.c_str(), currentValue, newValue);
209         currentValue = newValue;
210         return returnValueIfChanged;
211       }
212 
213       return defaultReturnValue;
214     }
215 
216     template<typename V>
SetStringSetting(const std::string & settingName,const kodi::CSettingValue & settingValue,std::string & currentValue,V returnValueIfChanged,V defaultReturnValue)217     V SetStringSetting(const std::string& settingName, const kodi::CSettingValue& settingValue, std::string& currentValue, V returnValueIfChanged, V defaultReturnValue)
218     {
219       const std::string strSettingValue = settingValue.GetString();
220 
221       if (strSettingValue != currentValue)
222       {
223         utilities::Logger::Log(utilities::LogLevel::LEVEL_INFO, "%s - Changed Setting '%s' from '%s' to '%s'", __FUNCTION__, settingName.c_str(), currentValue.c_str(), strSettingValue.c_str());
224         currentValue = strSettingValue;
225         return returnValueIfChanged;
226       }
227 
228       return defaultReturnValue;
229     }
230 
231     static bool LoadCustomChannelGroupFile(std::string& file, std::vector<std::string>& channelGroupNameList);
232 
233     std::string m_userPath;
234     std::string m_clientPath;
235 
236     // M3U
237     PathType m_m3uPathType = PathType::REMOTE_PATH;
238     std::string m_m3uPath;
239     std::string m_m3uUrl;
240     bool m_cacheM3U = false;
241     int m_startChannelNumber = 1;
242     bool m_numberChannelsByM3uOrderOnly = false;
243     RefreshMode m_m3uRefreshMode = RefreshMode::DISABLED;
244     int m_m3uRefreshIntervalMins = 60;
245     int m_m3uRefreshHour = 4;
246     bool m_allowTVChannelGroupsOnly = false;
247     ChannelGroupMode m_tvChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
248     unsigned int m_numTVGroups = DEFAULT_NUM_GROUPS;
249     std::string m_oneTVGroup = "";
250     std::string m_twoTVGroup = "";
251     std::string m_threeTVGroup = "";
252     std::string m_fourTVGroup = "";
253     std::string m_fiveTVGroup = "";
254     std::string m_customTVGroupsFile = "";
255     bool m_allowRadioChannelGroupsOnly = false;
256     ChannelGroupMode m_radioChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
257     unsigned int m_numRadioGroups = DEFAULT_NUM_GROUPS;
258     std::string m_oneRadioGroup = "";
259     std::string m_twoRadioGroup = "";
260     std::string m_threeRadioGroup = "";
261     std::string m_fourRadioGroup = "";
262     std::string m_fiveRadioGroup = "";
263     std::string m_customRadioGroupsFile = "";
264 
265     // EPG
266     PathType m_epgPathType = PathType::REMOTE_PATH;
267     std::string m_epgPath;
268     std::string m_epgUrl;
269     bool m_cacheEPG = false;
270     float m_epgTimeShiftHours = 0;
271     bool m_tsOverride = true;
272 
273     // Genres
274     bool m_useEpgGenreTextWhenMapping = false;
275     PathType m_genresPathType = PathType::LOCAL_PATH;
276     std::string m_genresPath;
277     std::string m_genresUrl;
278 
279     // Channel Logos
280     PathType m_logoPathType = PathType::REMOTE_PATH;
281     std::string m_logoPath;
282     std::string m_logoBaseUrl;
283     EpgLogosMode m_epgLogosMode = EpgLogosMode::IGNORE_XMLTV;
284     bool m_useLocalLogosOnly = false;
285 
286     // Timeshift
287     bool m_timeshiftEnabled = false;
288     bool m_timeshiftEnabledAll = false;
289     bool m_timeshiftEnabledHttp = false;
290     bool m_timeshiftEnabledUdp = false;
291     bool m_timeshiftEnabledCustom = false;
292 
293     // Catchup
294     bool m_catchupEnabled = false;
295     std::string m_catchupQueryFormat;
296     int m_catchupDays = 3;
297     CatchupMode m_allChannelsCatchupMode = CatchupMode::DISABLED;
298     CatchupOverrideMode m_catchupOverrideMode = CatchupOverrideMode::WITHOUT_TAGS;
299     float m_catchupCorrectionHours = 0;
300     bool m_catchupPlayEpgAsLive = false;
301     int m_catchupWatchEpgBeginBufferMins = 5;
302     int m_catchupWatchEpgEndBufferMins = 15;
303     bool m_catchupOnlyOnFinishedProgrammes = false;
304 
305     // Advanced
306     bool m_transformMulticastStreamUrls = false;
307     std::string m_udpxyHost;
308     int m_udpxyPort = DEFAULT_UDPXY_MULTICAST_RELAY_PORT;
309     bool m_useFFmpegReconnect = true;
310     bool m_useInputstreamAdaptiveforHls = false;
311     std::string m_defaultUserAgent;
312     std::string m_defaultInputstream;
313     std::string m_defaultMimeType;
314 
315     std::vector<std::string> m_customTVChannelGroupNameList;
316     std::vector<std::string> m_customRadioChannelGroupNameList;
317 
318     std::string m_tvgUrl;
319   };
320 } //namespace iptvsimple
321