1 /* 2 * Copyright (C) 2012-2018 Team Kodi 3 * This file is part of Kodi - https://kodi.tv 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 * See LICENSES/README.md for more information. 7 */ 8 9 #pragma once 10 11 #include "XBDateTime.h" 12 #include "pvr/timers/PVRTimerType.h" 13 #include "threads/CriticalSection.h" 14 #include "utils/ISerializable.h" 15 16 #include <memory> 17 #include <string> 18 19 struct PVR_TIMER; 20 21 namespace PVR 22 { 23 class CPVRChannel; 24 class CPVREpgInfoTag; 25 26 enum class TimerOperationResult 27 { 28 OK = 0, 29 FAILED, 30 RECORDING // The timer was not deleted because it is currently recording (see DeleteTimer). 31 }; 32 33 class CPVRTimerInfoTag final : public ISerializable 34 { 35 public: 36 explicit CPVRTimerInfoTag(bool bRadio = false); 37 CPVRTimerInfoTag(const PVR_TIMER& timer, const std::shared_ptr<CPVRChannel>& channel, unsigned int iClientId); 38 39 bool operator ==(const CPVRTimerInfoTag& right) const; 40 bool operator !=(const CPVRTimerInfoTag& right) const; 41 42 void Serialize(CVariant& value) const override; 43 44 void UpdateSummary(); 45 46 std::string GetStatus(bool bRadio) const; 47 std::string GetTypeAsString() const; 48 49 static const int DEFAULT_PVRRECORD_INSTANTRECORDTIME = -1; 50 51 /*! 52 * @brief create a tag for an instant timer for a given channel 53 * @param channel is the channel the instant timer is to be created for 54 * @param iDuration is the duration for the instant timer, DEFAULT_PVRRECORD_INSTANTRECORDTIME denotes system default (setting value) 55 * @return the timer or null if timer could not be created 56 */ 57 static std::shared_ptr<CPVRTimerInfoTag> CreateInstantTimerTag(const std::shared_ptr<CPVRChannel>& channel, int iDuration = DEFAULT_PVRRECORD_INSTANTRECORDTIME); 58 59 /*! 60 * @brief create a tag for a timer for a given channel at given time for given duration 61 * @param channel is the channel the timer is to be created for 62 * @param start is the start time for the recording 63 * @param iDuration is the duration of the recording 64 * @return the timer or null if timer could not be created 65 */ 66 static std::shared_ptr<CPVRTimerInfoTag> CreateTimerTag(const std::shared_ptr<CPVRChannel>& channel, const CDateTime& start, int iDuration); 67 68 /*! 69 * @brief create a recording or reminder timer or timer rule for the given epg info tag. 70 * @param tag the epg info tag 71 * @param bCreateRule if true, create a timer rule, create a one shot timer otherwise 72 * @param bCreateReminder if true, create a reminder timer or rule, create a recording timer or rule otherwise 73 * @param bReadOnly whether the timer/rule is read only 74 * @return the timer or null if timer could not be created 75 */ 76 static std::shared_ptr<CPVRTimerInfoTag> CreateFromEpg( 77 const std::shared_ptr<CPVREpgInfoTag>& tag, 78 bool bCreateRule, 79 bool bCreateReminder, 80 bool bReadOnly = false); 81 82 /*! 83 * @brief create a timer or timer rule for the given epg info tag. 84 * @param tag the epg info tag 85 * @param bCreateRule if true, create a timer rule, create a one shot timer otherwise 86 * @return the timer or null if timer could not be created 87 */ 88 static std::shared_ptr<CPVRTimerInfoTag> CreateFromEpg(const std::shared_ptr<CPVREpgInfoTag>& tag, bool bCreateRule = false); 89 90 /*! 91 * @brief create a reminder timer for the given start date. 92 * @param start the start date 93 * @param iDuration the duration the reminder is valid 94 * @param parent If non-zero, the new timer will be made a child of the given timer rule 95 * @return the timer or null if timer could not be created 96 */ 97 static std::shared_ptr<CPVRTimerInfoTag> CreateReminderFromDate(const CDateTime& start, 98 int iDuration, 99 const std::shared_ptr<CPVRTimerInfoTag>& parent = std::shared_ptr<CPVRTimerInfoTag>()); 100 101 /*! 102 * @brief create a reminder timer for the given epg info tag. 103 * @param tag the epg info tag 104 * @param parent If non-zero, the new timer will be made a child of the given timer rule 105 * @return the timer or null if timer could not be created 106 */ 107 static std::shared_ptr<CPVRTimerInfoTag> CreateReminderFromEpg(const std::shared_ptr<CPVREpgInfoTag>& tag, 108 const std::shared_ptr<CPVRTimerInfoTag>& parent = std::shared_ptr<CPVRTimerInfoTag>()); 109 110 /*! 111 * @brief Associate the given epg tag with this timer. 112 * @param tag The epg tag to assign. 113 */ 114 void SetEpgInfoTag(const std::shared_ptr<CPVREpgInfoTag>& tag); 115 116 /*! 117 * @brief get the epg info tag associated with this timer, if any 118 * @param bCreate if true, try to find the epg tag if not yet set (lazy evaluation) 119 * @return the epg info tag associated with this timer or null if there is no tag 120 */ 121 std::shared_ptr<CPVREpgInfoTag> GetEpgInfoTag(bool bCreate = true) const; 122 123 std::string ChannelName() const; 124 std::string ChannelIcon() const; 125 126 /*! 127 * @brief Check whether this timer has an associated channel. 128 * @return True if this timer has a channel set, false otherwise. 129 */ 130 bool HasChannel() const; 131 132 /*! 133 * @brief Get the channel associated with this timer, if any. 134 * @return the channel or null if non is associated with this timer. 135 */ 136 std::shared_ptr<CPVRChannel> Channel() const; 137 138 /*! 139 * @brief updates this timer excluding the state of any children. 140 * @param tag A timer containing the data that shall be merged into this timer's data. 141 * @return true if the timer was updated successfully 142 */ 143 bool UpdateEntry(const std::shared_ptr<CPVRTimerInfoTag>& tag); 144 145 /*! 146 * @brief merge in the state of this child timer. 147 * @param childTimer The child timer 148 * @param bAdd If true, add child's data to parent's state, otherwise subtract. 149 * @return true if the child timer's state was merged successfully 150 */ 151 bool UpdateChildState(const std::shared_ptr<CPVRTimerInfoTag>& childTimer, bool bAdd); 152 153 /*! 154 * @brief reset the state of children related to this timer. 155 */ 156 void ResetChildState(); 157 IsActive()158 bool IsActive() const 159 { 160 return m_state == PVR_TIMER_STATE_SCHEDULED 161 || m_state == PVR_TIMER_STATE_RECORDING 162 || m_state == PVR_TIMER_STATE_CONFLICT_OK 163 || m_state == PVR_TIMER_STATE_CONFLICT_NOK 164 || m_state == PVR_TIMER_STATE_ERROR; 165 } 166 167 /*! 168 * @return True if this timer won't result in a recording because it is broken for some reason, false otherwise 169 */ IsBroken()170 bool IsBroken() const 171 { 172 return m_state == PVR_TIMER_STATE_CONFLICT_NOK 173 || m_state == PVR_TIMER_STATE_ERROR; 174 } 175 176 /*! 177 * @return True if this timer won't result in a recording because it is in conflict with another timer or live stream, false otherwise 178 */ HasConflict()179 bool HasConflict() const { return m_state == PVR_TIMER_STATE_CONFLICT_NOK; } 180 IsRecording()181 bool IsRecording() const { return m_state == PVR_TIMER_STATE_RECORDING; } 182 183 /*! 184 * @brief Checks whether this timer has a timer type. 185 * @return True if this timer has a timer type, false otherwise 186 */ HasTimerType()187 bool HasTimerType() const { return m_timerType.get() != NULL; } 188 189 /*! 190 * @brief Gets the type of this timer. 191 * @return the timer type or NULL if this tag has no timer type. 192 */ GetTimerType()193 const std::shared_ptr<CPVRTimerType> GetTimerType() const { return m_timerType; } 194 195 /*! 196 * @brief Sets the type of this timer. 197 * @param the new timer type. 198 */ 199 void SetTimerType(const std::shared_ptr<CPVRTimerType>& type); 200 201 /*! 202 * @brief Checks whether this is a timer rule (vs. one time timer). 203 * @return True if this is a timer rule, false otherwise. 204 */ IsTimerRule()205 bool IsTimerRule() const { return m_timerType && m_timerType->IsTimerRule(); } 206 207 /*! 208 * @brief Checks whether this is a reminder timer (vs. recording timer). 209 * @return True if this is a reminder timer, false otherwise. 210 */ IsReminder()211 bool IsReminder() const { return m_timerType && m_timerType->IsReminder(); } 212 213 /*! 214 * @brief Checks whether this is a manual (vs. epg-based) timer. 215 * @return True if this is a manual timer, false otherwise. 216 */ IsManual()217 bool IsManual() const { return m_timerType && m_timerType->IsManual(); } 218 219 /*! 220 * @brief Checks whether this is an epg-based (vs. manual) timer. 221 * @return True if this is an epg-Based timer, false otherwise. 222 */ IsEpgBased()223 bool IsEpgBased() const { return !IsManual(); } 224 225 static CDateTime ConvertUTCToLocalTime(const CDateTime& utc); 226 static CDateTime ConvertLocalTimeToUTC(const CDateTime& local); 227 228 CDateTime StartAsUTC() const; 229 CDateTime StartAsLocalTime() const; 230 void SetStartFromUTC(const CDateTime& start); 231 void SetStartFromLocalTime(const CDateTime& start); 232 233 CDateTime EndAsUTC() const; 234 CDateTime EndAsLocalTime() const; 235 void SetEndFromUTC(const CDateTime& end); 236 void SetEndFromLocalTime(const CDateTime& end); 237 238 /*! 239 * @brief Get the duration of this timer in seconds, excluding padding times. 240 * @return The duration. 241 */ 242 int GetDuration() const; 243 244 CDateTime FirstDayAsUTC() const; 245 CDateTime FirstDayAsLocalTime() const; 246 void SetFirstDayFromUTC(const CDateTime& firstDay); 247 void SetFirstDayFromLocalTime(const CDateTime& firstDay); 248 MarginStart()249 unsigned int MarginStart() const { return m_iMarginStart; } 250 251 /*! 252 * @brief Get the text for the notification. 253 */ 254 std::string GetNotificationText() const; 255 256 /*! 257 * @brief Get the text for the notification when a timer has been deleted 258 */ 259 std::string GetDeletedNotificationText() const; 260 261 const std::string& Title() const; 262 const std::string& Summary() const; 263 const std::string& Path() const; 264 265 /*! 266 * @brief The series link for this timer. 267 * @return The series link or empty string, if not available. 268 */ 269 const std::string& SeriesLink() const; 270 271 /*! 272 * @brief Get the UID of the epg event associated with this timer tag, if any. 273 * @return the UID or EPG_TAG_INVALID_UID. 274 */ UniqueBroadcastID()275 unsigned int UniqueBroadcastID() const { return m_iEpgUid; } 276 277 /*! 278 * @brief Add this timer to the backend, transferring all local data of this timer to the backend. 279 * @return True on success, false otherwise. 280 */ 281 bool AddToClient() const; 282 283 /*! 284 * @brief Delete this timer on the backend. 285 * @param bForce Control what to do in case the timer is currently recording. 286 * True to force to delete the timer, false to return TimerDeleteResult::RECORDING. 287 * @return The result. 288 */ 289 TimerOperationResult DeleteFromClient(bool bForce = false) const; 290 291 /*! 292 * @brief Update this timer on the backend, transferring all local data of this timer to the backend. 293 * @return True on success, false otherwise. 294 */ 295 bool UpdateOnClient(); 296 297 /*! 298 * @brief Persist this timer in the local database. 299 * @return True on success, false otherwise. 300 */ 301 bool Persist(); 302 303 /*! 304 * @brief Delete this timer from the local database. 305 * @return True on success, false otherwise. 306 */ 307 bool DeleteFromDatabase(); 308 309 /*! 310 * @brief Update the channel associated with this timer. 311 * @return the channel for the timer. Can be empty for epg based repeating timers (e.g. "match any channel" rules) 312 */ 313 std::shared_ptr<CPVRChannel> UpdateChannel(); 314 315 /*! 316 * @brief Return string representation for any possible combination of weekdays. 317 * @param iWeekdays weekdays as bit mask (0x01 = Mo, 0x02 = Tu, ...) 318 * @param bEpgBased context is an epg-based timer 319 * @param bLongMultiDaysFormat use long format. ("Mo-__-We-__-Fr-Sa-__" vs. "Mo-We-Fr-Sa") 320 * @return the weekdays string representation 321 */ 322 static std::string GetWeekdaysString(unsigned int iWeekdays, bool bEpgBased, bool bLongMultiDaysFormat); 323 324 /*! 325 * @brief For timers scheduled by a timer rule, return the id of the rule (aka the id of the "parent" of the timer). 326 * @return the id of the timer rule or PVR_TIMER_NO_PARENT in case the timer was not scheduled by a timer rule. 327 */ GetTimerRuleId()328 int GetTimerRuleId() const { return m_iParentClientIndex; } 329 330 /*! 331 * @brief Check, whether this timer is owned by a pvr client or by Kodi. 332 * @return True, if owned by a pvr client, false otherwise. 333 */ 334 bool IsOwnedByClient() const; 335 336 std::string m_strTitle; /*!< @brief name of this timer */ 337 std::string m_strEpgSearchString; /*!< @brief a epg data match string for epg-based timer rules. Format is backend-dependent, for example regexp */ 338 bool m_bFullTextEpgSearch = false; /*!< @brief indicates whether only epg episode title can be matched by the pvr backend or "more" (backend-dependent") data. */ 339 std::string m_strDirectory; /*!< @brief directory where the recording must be stored */ 340 std::string m_strSummary; /*!< @brief summary string with the time to show inside a GUI list */ 341 PVR_TIMER_STATE m_state = PVR_TIMER_STATE_SCHEDULED; /*!< @brief the state of this timer */ 342 int m_iClientId; /*!< @brief ID of the backend */ 343 int m_iClientIndex; /*!< @brief index number of the tag, given by the backend, PVR_TIMER_NO_CLIENT_INDEX for new */ 344 int m_iParentClientIndex; /*!< @brief for timers scheduled by a timer rule, the index number of the parent, given by the backend, PVR_TIMER_NO_PARENT for no parent */ 345 int m_iClientChannelUid; /*!< @brief channel uid */ 346 bool m_bStartAnyTime = false; /*!< @brief Ignore start date and time clock. Record at 'Any Time' */ 347 bool m_bEndAnyTime = false; /*!< @brief Ignore end date and time clock. Record at 'Any Time' */ 348 int m_iPriority; /*!< @brief priority of the timer */ 349 int m_iLifetime; /*!< @brief lifetime of the timer in days */ 350 int m_iMaxRecordings = 0; /*!< @brief (optional) backend setting for maximum number of recordings to keep*/ 351 unsigned int m_iWeekdays; /*!< @brief bit based store of weekdays for timer rules */ 352 unsigned int m_iPreventDupEpisodes; /*!< @brief only record new episodes for epg-based timer rules */ 353 unsigned int m_iRecordingGroup = 0; /*!< @brief (optional) if set, the addon/backend stores the recording to a group (sub-folder) */ 354 std::string m_strFileNameAndPath; /*!< @brief file name is only for reference */ 355 bool m_bIsRadio; /*!< @brief is radio channel if set */ 356 unsigned int m_iTimerId = 0; /*!< @brief id that won't change as long as Kodi is running */ 357 unsigned int m_iMarginStart; /*!< @brief (optional) if set, the backend starts the recording iMarginStart minutes before startTime. */ 358 unsigned int m_iMarginEnd; /*!< @brief (optional) if set, the backend ends the recording iMarginEnd minutes after endTime. */ 359 mutable unsigned int m_iEpgUid; /*!< id of epg event associated with this timer, EPG_TAG_INVALID_UID if none. */ 360 std::string m_strSeriesLink; /*!< series link */ 361 362 private: 363 CPVRTimerInfoTag(const CPVRTimerInfoTag& tag) = delete; 364 CPVRTimerInfoTag& operator=(const CPVRTimerInfoTag& orig) = delete; 365 366 std::string GetWeekdaysString() const; 367 void UpdateEpgInfoTag(); 368 369 static std::shared_ptr<CPVRTimerInfoTag> CreateFromDate(const std::shared_ptr<CPVRChannel>& channel, const CDateTime& start, int iDuration, bool bCreateReminder, bool bReadOnly); 370 371 mutable CCriticalSection m_critSection; 372 CDateTime m_StartTime; /*!< start time */ 373 CDateTime m_StopTime; /*!< stop time */ 374 CDateTime m_FirstDay; /*!< if it is a manual timer rule the first date it starts */ 375 std::shared_ptr<CPVRTimerType> m_timerType; /*!< the type of this timer */ 376 377 unsigned int m_iTVChildTimersActive = 0; 378 unsigned int m_iTVChildTimersConflictNOK = 0; 379 unsigned int m_iTVChildTimersRecording = 0; 380 unsigned int m_iTVChildTimersErrors = 0; 381 unsigned int m_iRadioChildTimersActive = 0; 382 unsigned int m_iRadioChildTimersConflictNOK = 0; 383 unsigned int m_iRadioChildTimersRecording = 0; 384 unsigned int m_iRadioChildTimersErrors = 0; 385 386 mutable std::shared_ptr<CPVREpgInfoTag> m_epgTag; /*!< epg info tag matching m_iEpgUid. */ 387 mutable std::shared_ptr<CPVRChannel> m_channel; 388 389 mutable bool m_bProbedEpgTag = false; 390 }; 391 } 392