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