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 /*
12  * DESCRIPTION:
13  *
14  * CPVRRecordingInfoTag is part of the Kodi PVR system to support recording entrys,
15  * stored on a other Backend like VDR or MythTV.
16  *
17  * The recording information tag holds data about name, length, recording time
18  * and so on of recorded stream stored on the backend.
19  *
20  * The filename string is used to by the PVRManager and passed to VideoPlayer
21  * to stream data from the backend to Kodi.
22  *
23  * It is a also CVideoInfoTag and some of his variables must be set!
24  *
25  */
26 
27 #include "XBDateTime.h"
28 #include "threads/CriticalSection.h"
29 #include "threads/SystemClock.h"
30 #include "video/Bookmark.h"
31 #include "video/VideoInfoTag.h"
32 
33 #include <memory>
34 #include <string>
35 #include <vector>
36 
37 class CVideoDatabase;
38 
39 struct PVR_EDL_ENTRY;
40 struct PVR_RECORDING;
41 
42 namespace PVR
43 {
44   class CPVRChannel;
45   class CPVRClient;
46   class CPVRTimerInfoTag;
47 
48   /*!
49    * @brief Representation of a CPVRRecording unique ID.
50    */
51   class CPVRRecordingUid final
52   {
53   public:
54     int m_iClientId; /*!< ID of the backend */
55     std::string m_strRecordingId; /*!< unique ID of the recording on the client */
56 
57     CPVRRecordingUid(int iClientId, const std::string& strRecordingId);
58 
59     bool operator >(const CPVRRecordingUid& right) const;
60     bool operator <(const CPVRRecordingUid& right) const;
61     bool operator ==(const CPVRRecordingUid& right) const;
62     bool operator !=(const CPVRRecordingUid& right) const;
63   };
64 
65   class CPVRRecording final : public CVideoInfoTag
66   {
67   public:
68     int m_iClientId; /*!< ID of the backend */
69     std::string m_strRecordingId; /*!< unique ID of the recording on the client */
70     std::string m_strChannelName; /*!< name of the channel this was recorded from */
71     int m_iPriority; /*!< priority of this recording */
72     int m_iLifetime; /*!< lifetime of this recording */
73     std::string m_strDirectory; /*!< directory of this recording on the client */
74     std::string m_strIconPath; /*!< icon path */
75     std::string m_strThumbnailPath; /*!< thumbnail path */
76     std::string m_strFanartPath; /*!< fanart path */
77     unsigned m_iRecordingId; /*!< id that won't change while xbmc is running */
78 
79     CPVRRecording();
80     CPVRRecording(const PVR_RECORDING& recording, unsigned int iClientId);
81 
82   private:
83     CPVRRecording(const CPVRRecording& tag) = delete;
84     CPVRRecording& operator =(const CPVRRecording& other) = delete;
85 
86   public:
87     bool operator ==(const CPVRRecording& right) const;
88     bool operator !=(const CPVRRecording& right) const;
89 
90     void Serialize(CVariant& value) const override;
91 
92     // ISortable implementation
93     void ToSortable(SortItem& sortable, Field field) const override;
94 
95     /*!
96      * @brief Reset this tag to it's initial state.
97      */
98     void Reset();
99 
100     /*!
101      * @brief Delete this recording on the client (if supported).
102      * @return True if it was deleted successfully, false otherwise.
103      */
104     bool Delete();
105 
106     /*!
107      * @brief Undelete this recording on the client (if supported).
108      * @return True if it was undeleted successfully, false otherwise.
109      */
110     bool Undelete();
111 
112     /*!
113      * @brief Rename this recording on the client (if supported).
114      * @param strNewName The new name.
115      * @return True if it was renamed successfully, false otherwise.
116      */
117     bool Rename(const std::string& strNewName);
118 
119     /*!
120      * @brief Set this recording's play count. The value will be transferred to the backend if it supports server-side play counts.
121      * @param count play count.
122      * @return True if play count was set successfully, false otherwise.
123      */
124     bool SetPlayCount(int count) override;
125 
126     /*!
127      * @brief Increment this recording's play count. The value will be transferred to the backend if it supports server-side play counts.
128      * @return True if play count was increased successfully, false otherwise.
129      */
130     bool IncrementPlayCount() override;
131 
132     /*!
133      * @brief Set this recording's play count without transferring the value to the backend, even if it supports server-side play counts.
134      * @param count play count.
135      * @return True if play count was set successfully, false otherwise.
136      */
SetLocalPlayCount(int count)137     bool SetLocalPlayCount(int count) { return CVideoInfoTag::SetPlayCount(count); }
138 
139    /*!
140      * @brief Get this recording's local play count. The value will not be obtained from the backend, even if it supports server-side play counts.
141      * @return the play count.
142      */
GetLocalPlayCount()143     int GetLocalPlayCount() const { return CVideoInfoTag::GetPlayCount(); }
144 
145     /*!
146      * @brief Set this recording's resume point. The value will be transferred to the backend if it supports server-side resume points.
147      * @param resumePoint resume point.
148      * @return True if resume point was set successfully, false otherwise.
149      */
150     bool SetResumePoint(const CBookmark& resumePoint) override;
151 
152     /*!
153      * @brief Set this recording's resume point. The value will be transferred to the backend if it supports server-side resume points.
154      * @param timeInSeconds the time of the resume point
155      * @param totalTimeInSeconds the total time of the video
156      * @param playerState the player state
157      * @return True if resume point was set successfully, false otherwise.
158      */
159     bool SetResumePoint(double timeInSeconds, double totalTimeInSeconds, const std::string& playerState = "") override;
160 
161     /*!
162      * @brief Get this recording's resume point. The value will be obtained from the backend if it supports server-side resume points.
163      * @return the resume point.
164      */
165     CBookmark GetResumePoint() const override;
166 
167     /*!
168      * @brief Update this recording's size. The value will be obtained from the backend if it supports server-side size retrieval.
169      * @return true if the the updated value is differnt, false otherwise.
170      */
171     bool UpdateRecordingSize();
172 
173     /*!
174      * @brief Get this recording's local resume point. The value will not be obtained from the backend even if it supports server-side resume points.
175      * @return the resume point.
176      */
GetLocalResumePoint()177     CBookmark GetLocalResumePoint() const { return CVideoInfoTag::GetResumePoint(); }
178 
179     /*!
180      * @brief Retrieve the edit decision list (EDL) of a recording on the backend.
181      * @return The edit decision list (empty on error)
182      */
183     std::vector<PVR_EDL_ENTRY> GetEdl() const;
184 
185     /*!
186      * @brief Get the resume point and play count from the database if the
187      * client doesn't handle it itself.
188      * @param db The database to read the data from.
189      * @param client The client this recording belongs to.
190      */
191     void UpdateMetadata(CVideoDatabase& db, const CPVRClient& client);
192 
193     /*!
194      * @brief Update this tag with the contents of the given tag.
195      * @param tag The new tag info.
196      * @param client The client this recording belongs to.
197      */
198     void Update(const CPVRRecording& tag, const CPVRClient& client);
199 
200     /*!
201      * @brief Retrieve the recording start as UTC time
202      * @return the recording start time
203      */
RecordingTimeAsUTC()204     const CDateTime& RecordingTimeAsUTC() const { return m_recordingTime; }
205 
206     /*!
207      * @brief Retrieve the recording start as local time
208      * @return the recording start time
209      */
210     const CDateTime& RecordingTimeAsLocalTime() const;
211 
212     /*!
213      * @brief Retrieve the recording end as UTC time
214      * @return the recording end time
215      */
216     CDateTime EndTimeAsUTC() const;
217 
218     /*!
219      * @brief Retrieve the recording end as local time
220      * @return the recording end time
221      */
222     CDateTime EndTimeAsLocalTime() const;
223 
224     /*!
225      * @brief Check whether this recording has an expiration time
226      * @return True if the recording has an expiration time, false otherwise
227      */
HasExpirationTime()228     bool HasExpirationTime() const { return m_iLifetime > 0; }
229 
230     /*!
231      * @brief Retrieve the recording expiration time as local time
232      * @return the recording expiration time
233      */
234     CDateTime ExpirationTimeAsLocalTime() const;
235 
236     /*!
237      * @brief Check whether this recording will immediately expire if the given lifetime value would be set
238      * @param iLifetime The lifetime value to check
239      * @return True if the recording would immediately expire, false otherwiese
240      */
241     bool WillBeExpiredWithNewLifetime(int iLifetime) const;
242 
243     /*!
244      * @brief Retrieve the recording title from the URL path
245      * @param url the URL for the recording
246      * @return Title of the recording
247      */
248     static std::string GetTitleFromURL(const std::string& url);
249 
250     /*!
251      * @brief If deleted but can be undeleted it is true
252      */
IsDeleted()253     bool IsDeleted() const { return m_bIsDeleted; }
254 
255     /*!
256      * @brief Check whether this is a tv or radio recording
257      * @return true if this is a radio recording, false if this is a tv recording
258      */
IsRadio()259     bool IsRadio() const { return m_bRadio; }
260 
261     /*!
262      * @return Broadcast id of the EPG event associated with this recording or EPG_TAG_INVALID_UID
263      */
BroadcastUid()264     unsigned int BroadcastUid() const { return m_iEpgEventId; }
265 
266     /*!
267      * @return Get the channel on which this recording is/was running
268      * @note Only works if the recording has a channel uid provided by the add-on
269      */
270     std::shared_ptr<CPVRChannel> Channel() const;
271 
272     /*!
273      * @brief Get the uid of the channel on which this recording is/was running
274      * @return the uid of the channel or PVR_CHANNEL_INVALID_UID
275      */
276     int ChannelUid() const;
277 
278     /*!
279      * @brief the identifier of the client that serves this recording
280      * @return the client identifier
281      */
282     int ClientID() const;
283 
284     /*!
285      * @brief Retrieve the recording Episode Name
286      * @note Returns an empty string if no Episode Name was provided by the PVR client
287      */
EpisodeName()288     std::string EpisodeName() const { return m_strShowTitle; }
289 
290     /*!
291      * @brief check whether this recording is currently in progress
292      * @return true if the recording is in progress, false otherwise
293      */
294     bool IsInProgress() const;
295 
296     /*!
297      * @brief return the timer for an in-progress recording, if any
298      * @return the timer if the recording is in progress, nullptr otherwise
299      */
300     std::shared_ptr<CPVRTimerInfoTag> GetRecordingTimer() const;
301 
302     /*!
303     * @brief set the genre for this recording.
304     * @param iGenreType The genre type ID. If set to EPG_GENRE_USE_STRING, set genre to the value provided with strGenre. Otherwise, compile the genre string from the values given by iGenreType and iGenreSubType
305     * @param iGenreSubType The genre subtype ID
306     * @param strGenre The genre
307     */
308    void SetGenre(int iGenreType, int iGenreSubType, const std::string& strGenre);
309 
310     /*!
311      * @brief Get the genre type ID of this recording.
312      * @return The genre type ID.
313      */
GenreType()314     int GenreType() const { return m_iGenreType; }
315 
316     /*!
317      * @brief Get the genre subtype ID of this recording.
318      * @return The genre subtype ID.
319      */
GenreSubType()320     int GenreSubType() const { return m_iGenreSubType; }
321 
322     /*!
323      * @brief Get the genre as human readable string.
324      * @return The genre.
325      */
Genre()326     const std::vector<std::string> Genre() const { return m_genre; }
327 
328     /*!
329      * @brief Get the genre(s) of this recording as formatted string.
330      * @return The genres label.
331      */
332    const std::string GetGenresLabel() const;
333 
334    /*!
335     * @brief Get the first air date of this recording.
336     * @return The first air date.
337     */
338    CDateTime FirstAired() const;
339 
340    /*!
341     * @brief Get the premiere year of this recording.
342     * @return The premiere year
343     */
344    int GetYear() const override;
345 
346    /*!
347     * @brief Set the premiere year of this recording.
348     * @param year The premiere year
349     */
350    void SetYear(int year) override;
351 
352    /*!
353     * @brief Check if the premiere year of this recording is valid
354     * @return True if the recording has as valid premiere date, false otherwise
355     */
356    bool HasYear() const override;
357 
358    /*!
359     * @brief Check whether this recording will be flagged as new.
360     * @return True if this recording will be flagged as new, false otherwise
361     */
362    bool IsNew() const;
363 
364    /*!
365     * @brief Check whether this recording will be flagged as a premiere.
366     * @return True if this recording will be flagged as a premiere, false otherwise
367     */
368    bool IsPremiere() const;
369 
370    /*!
371     * @brief Check whether this recording will be flagged as a finale.
372     * @return True if this recording will be flagged as a finale, false otherwise
373     */
374    bool IsFinale() const;
375 
376    /*!
377     * @brief Check whether this recording will be flagged as live.
378     * @return True if this recording will be flagged as live, false otherwise
379     */
380    bool IsLive() const;
381 
382    /*!
383     * @brief Return the flags (PVR_RECORDING_FLAG_*) of this recording as a bitfield.
384     * @return the flags.
385     */
Flags()386    unsigned int Flags() const { return m_iFlags; }
387 
388    /*!
389     * @brief Return the size of this recording in bytes.
390     * @return the size in bytes.
391     */
392    int64_t GetSizeInBytes() const;
393 
394     /*!
395      * @brief Mark a recording as dirty/clean.
396      * @param bDirty true to mark as dirty, false to mark as clean.
397      */
SetDirty(bool bDirty)398     void SetDirty(bool bDirty) { m_bDirty = bDirty; }
399 
400     /*!
401      * @brief Return whether the recording is marked dirty.
402      * @return true if dirty, false otherwise.
403      */
IsDirty()404     bool IsDirty() const { return m_bDirty; }
405 
406   private:
407     void UpdatePath();
408 
409     CDateTime m_recordingTime; /*!< start time of the recording */
410     bool m_bGotMetaData;
411     bool m_bIsDeleted; /*!< set if entry is a deleted recording which can be undelete */
412     unsigned int m_iEpgEventId; /*!< epg broadcast id associated with this recording */
413     int m_iChannelUid; /*!< channel uid associated with this recording */
414     bool m_bRadio; /*!< radio or tv recording */
415     int m_iGenreType = 0; /*!< genre type */
416     int m_iGenreSubType = 0; /*!< genre subtype */
417     mutable XbmcThreads::EndTime m_resumePointRefetchTimeout;
418     unsigned int m_iFlags = 0; /*!< the flags applicable to this recording */
419     mutable XbmcThreads::EndTime m_recordingSizeRefetchTimeout;
420     int64_t m_sizeInBytes = 0; /*!< the size of the recording in bytes */
421     bool m_bDirty = false;
422 
423     mutable CCriticalSection m_critSection;
424   };
425 }
426