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/channels/PVRChannelNumber.h"
13 #include "pvr/channels/PVRChannelsPath.h"
14 #include "settings/lib/ISettingCallback.h"
15 #include "utils/EventStream.h"
16 
17 #include <map>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 struct PVR_CHANNEL_GROUP;
24 
25 namespace PVR
26 {
27 #define PVR_GROUP_TYPE_DEFAULT      0
28 #define PVR_GROUP_TYPE_INTERNAL     1
29 #define PVR_GROUP_TYPE_USER_DEFINED 2
30 
31   enum class PVREvent;
32 
33   class CPVRChannel;
34   class CPVREpgInfoTag;
35 
36   struct PVRChannelGroupMember
37   {
38     PVRChannelGroupMember() = default;
39 
PVRChannelGroupMemberPVRChannelGroupMember40     PVRChannelGroupMember(const std::shared_ptr<CPVRChannel>& _channel,
41                           const CPVRChannelNumber& _channelNumber,
42                           int _iClientPriority,
43                           int _iOrder,
44                           const CPVRChannelNumber& _clientChannelNumber)
45       : channel(_channel),
46         channelNumber(_channelNumber),
47         clientChannelNumber(_clientChannelNumber),
48         iClientPriority(_iClientPriority),
49         iOrder(_iOrder)
50     {
51     }
52 
53     std::shared_ptr<CPVRChannel> channel;
54     CPVRChannelNumber channelNumber; // the channel number this channel has in the group
55     CPVRChannelNumber clientChannelNumber; // the client channel number this channel has in the group
56     int iClientPriority = 0;
57     int iOrder = 0; // The value denoting the order of this member in the group
58   };
59 
60   enum EpgDateType
61   {
62     EPG_FIRST_DATE = 0,
63     EPG_LAST_DATE = 1
64   };
65 
66   enum RenumberMode
67   {
68     NORMAL = 0,
69     IGNORE_NUMBERING_FROM_ONE = 1
70   };
71 
72   class CPVRChannelGroup : public ISettingCallback
73   {
74     friend class CPVRChannelGroupInternal;
75     friend class CPVRDatabase;
76 
77   public:
78     static const int INVALID_GROUP_ID = -1;
79 
80     /*!
81      * @brief Create a new channel group instance.
82      * @param path The channel group path.
83      * @param iGroupId The database ID of this group or INVALID_GROUP_ID if the group was not yet stored in the database.
84      * @param allChannelsGroup The channel group containing all TV or radio channels.
85      */
86     CPVRChannelGroup(const CPVRChannelsPath& path,
87                      int iGroupId = INVALID_GROUP_ID,
88                      const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup = {});
89 
90     /*!
91      * @brief Create a new channel group instance from a channel group provided by an add-on.
92      * @param group The channel group provided by the add-on.
93      * @param allChannelsGroup The channel group containing all TV or radio channels.
94      */
95     CPVRChannelGroup(const PVR_CHANNEL_GROUP& group, const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup);
96 
97     ~CPVRChannelGroup() override;
98 
99     bool operator ==(const CPVRChannelGroup& right) const;
100     bool operator !=(const CPVRChannelGroup& right) const;
101 
102     /**
103      * Empty group member
104      */
105     static std::shared_ptr<PVRChannelGroupMember> EmptyMember;
106 
107     /*!
108      * @brief Query the events available for CEventStream
109      */
Events()110     CEventStream<PVREvent>& Events() { return m_events; }
111 
112     /*!
113      * @brief Load the channels from the database.
114      * @param channelsToRemove Returns the channels to be removed from all groups, if any
115      * @return True when loaded successfully, false otherwise.
116      */
117     virtual bool Load(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
118 
119     /*!
120      * @return The amount of group members
121      */
122     size_t Size() const;
123 
124     /*!
125      * @brief Refresh the channel list from the clients.
126      * @param channelsToRemove Returns the channels to be removed from all groups, if any
127      */
128     virtual bool Update(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
129 
130     /*!
131      * @brief Get the path of this group.
132      * @return the path.
133      */
134     const CPVRChannelsPath& GetPath() const;
135 
136     /*!
137      * @brief Set the path of this group.
138      * @param the path.
139      */
140     void SetPath(const CPVRChannelsPath& path);
141 
142     /*!
143      * @brief Change the channelnumber of a group. Used by CGUIDialogPVRChannelManager. Call SortByChannelNumber() and Renumber() after all changes are done.
144      * @param channel The channel to change the channel number for.
145      * @param channelNumber The new channel number.
146      */
147     bool SetChannelNumber(const std::shared_ptr<CPVRChannel>& channel, const CPVRChannelNumber& channelNumber);
148 
149     /*!
150      * @brief Remove a channel from this container.
151      * @param channel The channel to remove.
152      * @return True if the channel was found and removed, false otherwise.
153      */
154     virtual bool RemoveFromGroup(const std::shared_ptr<CPVRChannel>& channel);
155 
156     /*!
157      * @brief Add a channel to this container.
158      * @param channel The channel to add.
159      * @param channelNumber The channel number of the channel to add. Use empty channel number if it's to be generated.
160      * @param iOrder The value denoting the order of this member in the group, 0 if unknown and needs to be generated
161      * @param bUseBackendChannelNumbers True, if channelNumber contains a backend channel number.
162      * @param clientChannelNumber The client channel number of the channel to add. (optional)
163      * @return True if the channel was added, false otherwise.
164      */
165     virtual bool AddToGroup(const std::shared_ptr<CPVRChannel>& channel, const CPVRChannelNumber& channelNumber, int iOrder, bool bUseBackendChannelNumbers, const CPVRChannelNumber& clientChannelNumber = {});
166 
167     /*!
168      * @brief Append a channel to this container.
169      * @param channel The channel to append.
170      * @return True if the channel was appended, false otherwise.
171      */
172     virtual bool AppendToGroup(const std::shared_ptr<CPVRChannel>& channel);
173 
174     /*!
175      * @brief Change the name of this group.
176      * @param strGroupName The new group name.
177      */
178     void SetGroupName(const std::string& strGroupName);
179 
180     /*!
181      * @brief Persist changed or new data.
182      * @return True if the channel was persisted, false otherwise.
183      */
184     bool Persist();
185 
186     /*!
187      * @brief Check whether a channel is in this container.
188      * @param channel The channel to find.
189      * @return True if the channel was found, false otherwise.
190      */
191     virtual bool IsGroupMember(const std::shared_ptr<CPVRChannel>& channel) const;
192 
193     /*!
194      * @brief Check whether a channel is in this container.
195      * @param iChannelId The db id of the channel to find.
196      * @return True if the channel was found, false otherwise.
197      */
198     virtual bool IsGroupMember(int iChannelId) const;
199 
200     /*!
201      * @brief Check if this group is the internal group containing all channels.
202      * @return True if it's the internal group, false otherwise.
203      */
IsInternalGroup()204     virtual bool IsInternalGroup() const { return m_iGroupType == PVR_GROUP_TYPE_INTERNAL; }
205 
206     /*!
207      * @brief True if this group holds radio channels, false if it holds TV channels.
208      * @return True if this group holds radio channels, false if it holds TV channels.
209      */
210     bool IsRadio() const;
211 
212     /*!
213      * @brief True if sorting should be prevented when adding/updating channels to the group.
214      * @return True if sorting should be prevented when adding/updating channels to the group.
215      */
216     bool PreventSortAndRenumber() const;
217 
218     /*!
219      * @brief The database ID of this group.
220      * @return The database ID of this group.
221      */
222     int GroupID() const;
223 
224     /*!
225      * @brief Set the database ID of this group.
226      * @param iGroupId The new database ID.
227      */
228     void SetGroupID(int iGroupId);
229 
230     /*!
231      * @brief Set the type of this group.
232      * @param the new type for this group.
233      */
234     void SetGroupType(int iGroupType);
235 
236     /*!
237      * @brief Return the type of this group.
238      */
239     int GroupType() const;
240 
241     /*!
242      * @return Time group has been watched last.
243      */
244     time_t LastWatched() const;
245 
246     /*!
247      * @brief Last time group has been watched
248      * @param iLastWatched The new value.
249      * @return True if something changed, false otherwise.
250      */
251     bool SetLastWatched(time_t iLastWatched);
252 
253     /*!
254      * @return Time in milliseconds from epoch this group was last opened.
255      */
256     uint64_t LastOpened() const;
257 
258     /*!
259      * @brief Set the time in milliseconds from epoch this group was last opened.
260      * @param iLastOpened The new value.
261      * @return True if something changed, false otherwise.
262      */
263     bool SetLastOpened(uint64_t iLastOpened);
264 
265     /*!
266      * @brief Set if sorting and renumbering should happen after adding/updating channels to group.
267      * @param bPreventSortAndRenumber The new sorting and renumbering prevention value for this group.
268      */
269     void SetPreventSortAndRenumber(bool bPreventSortAndRenumber = true);
270 
271     /*!
272      * @brief The name of this group.
273      * @return The name of this group.
274      */
275     std::string GroupName() const;
276 
277     /*! @name Sort methods
278      */
279     //@{
280 
281     /*!
282      * @brief Sort the group.
283      */
284     void Sort();
285 
286     /*!
287      * @brief Sort the group and fix up channel numbers.
288      * @return True when numbering changed, false otherwise
289      */
290     bool SortAndRenumber();
291 
292     /*!
293      * @brief Remove invalid channels and updates the channel numbers.
294      * @param mode the numbering mode to use
295      * @return True if something changed, false otherwise.
296      */
297     bool Renumber(RenumberMode mode = NORMAL);
298 
299     //@}
300 
301     void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override;
302 
303     /*!
304      * @brief Get a channel given it's EPG ID.
305      * @param iEpgID The channel EPG ID.
306      * @return The channel or NULL if it wasn't found.
307      */
308     std::shared_ptr<CPVRChannel> GetByChannelEpgID(int iEpgID) const;
309 
310     /*!
311      * @brief Get the channel that was played last.
312      * @param iCurrentChannel The channelid of the current channel that is playing, or -1 if none
313      * @return The requested channel or nullptr.
314      */
315     std::shared_ptr<CPVRChannel> GetLastPlayedChannel(int iCurrentChannel = -1) const;
316 
317     /*!
318      * @brief Get a channel given it's active channel number
319      * @param channelNumber The channel number.
320      * @return The channel or nullptr if it wasn't found.
321      */
322     std::shared_ptr<CPVRChannel> GetByChannelNumber(const CPVRChannelNumber& channelNumber) const;
323 
324     /*!
325      * @brief Get the channel number in this group of the given channel.
326      * @param channel The channel to get the channel number for.
327      * @return The channel number in this group.
328      */
329     CPVRChannelNumber GetChannelNumber(const std::shared_ptr<CPVRChannel>& channel) const;
330 
331     /*!
332      * @brief Get the client channel number in this group of the given channel.
333      * @param channel The channel to get the channel number for.
334      * @return The client channel number in this group.
335      */
336     CPVRChannelNumber GetClientChannelNumber(const std::shared_ptr<CPVRChannel>& channel) const;
337 
338     /*!
339      * @brief Get the next channel in this group.
340      * @param channel The current channel.
341      * @return The channel or nullptr if it wasn't found.
342      */
343     std::shared_ptr<CPVRChannel> GetNextChannel(const std::shared_ptr<CPVRChannel>& channel) const;
344 
345     /*!
346      * @brief Get the previous channel in this group.
347      * @param channel The current channel.
348      * @return The channel or nullptr if it wasn't found.
349      */
350     std::shared_ptr<CPVRChannel> GetPreviousChannel(const std::shared_ptr<CPVRChannel>& channel) const;
351 
352     /*!
353      * @brief Get a channel given it's channel ID.
354      * @param iChannelID The channel ID.
355      * @return The channel or NULL if it wasn't found.
356      */
357     std::shared_ptr<CPVRChannel> GetByChannelID(int iChannelID) const;
358 
359     enum class Include
360     {
361       ALL,
362       ONLY_HIDDEN,
363       ONLY_VISIBLE
364     };
365 
366     /*!
367      * @brief Get the current members of this group
368      * @param eFilter A filter to apply.
369      * @return The group members
370      */
371     std::vector<std::shared_ptr<PVRChannelGroupMember>> GetMembers(Include eFilter = Include::ALL) const;
372 
373     /*!
374      * @brief Get the list of active channel numbers in a group.
375      * @param channelNumbers The list to store the numbers in.
376      */
377     void GetChannelNumbers(std::vector<std::string>& channelNumbers) const;
378 
379     /*!
380      * @brief The amount of hidden channels in this container.
381      * @return The amount of hidden channels in this container.
382      */
GetNumHiddenChannels()383     virtual size_t GetNumHiddenChannels() const { return 0; }
384 
385     /*!
386      * @brief Does this container holds channels.
387      * @return True if there is at least one channel in this container, otherwise false.
388      */
389     bool HasChannels() const;
390 
391     /*!
392      * @return True if there is at least one channel in this group with changes that haven't been persisted, false otherwise.
393      */
394     bool HasChangedChannels() const;
395 
396     /*!
397      * @return True if there is at least one new channel in this group that hasn't been persisted, false otherwise.
398      */
399     bool HasNewChannels() const;
400 
401     /*!
402      * @return True if anything changed in this group that hasn't been persisted, false otherwise.
403      */
404     bool HasChanges() const;
405 
406     /*!
407      * @brief Create an EPG table for each channel.
408      * @brief bForce Create the tables, even if they already have been created before.
409      * @return True if all tables were created successfully, false otherwise.
410      */
411     virtual bool CreateChannelEpgs(bool bForce = false);
412 
413     /*!
414      * @brief Get the start time of the first entry.
415      * @return The start time.
416      */
417     CDateTime GetFirstEPGDate() const;
418 
419     /*!
420      * @brief Get the end time of the last entry.
421      * @return The end time.
422      */
423     CDateTime GetLastEPGDate() const;
424 
425     /*!
426      * @brief Update a channel group member with given data.
427      * @param storageId The storage id of the channel.
428      * @param strChannelName The channel name to set.
429      * @param strIconPath The icon path to set.
430      * @param iEPGSource The EPG id.
431      * @param iChannelNumber The channel number to set.
432      * @param bHidden Set/Remove hidden flag for the channel group member identified by storage id.
433      * @param bEPGEnabled Set/Remove EPG enabled flag for the channel group member identified by storage id.
434      * @param bParentalLocked Set/Remove parental locked flag for the channel group member identified by storage id.
435      * @param bUserSetIcon Set/Remove user set icon flag for the channel group member identified by storage id.
436      * @return True on success, false otherwise.
437      */
438     bool UpdateChannel(const std::pair<int, int>& storageId,
439                        const std::string& strChannelName,
440                        const std::string& strIconPath,
441                        int iEPGSource,
442                        int iChannelNumber,
443                        bool bHidden,
444                        bool bEPGEnabled,
445                        bool bParentalLocked,
446                        bool bUserSetIcon);
447 
448     /*!
449      * @brief Get a channel given the channel number on the client.
450      * @param iUniqueChannelId The unique channel id on the client.
451      * @param iClientID The ID of the client.
452      * @return The channel or NULL if it wasn't found.
453      */
454     std::shared_ptr<CPVRChannel> GetByUniqueID(int iUniqueChannelId, int iClientID) const;
455 
456     /*!
457      * @brief Get a channel group member given its storage id.
458      * @param id The storage id (a pair of client id and unique channel id).
459      * @return A reference to the group member or an empty group member if it wasn't found.
460      */
461     std::shared_ptr<PVRChannelGroupMember>& GetByUniqueID(const std::pair<int, int>& id);
462     const std::shared_ptr<PVRChannelGroupMember>& GetByUniqueID(const std::pair<int, int>& id) const;
463 
464     bool SetHidden(bool bHidden);
465     bool IsHidden() const;
466 
467     int GetPosition() const;
468     void SetPosition(int iPosition);
469 
470     /*!
471      * @brief Check, whether data for a given pvr client are currently valid. For instance, data
472      * can be invalid because the client's backend was offline when data was last queried.
473      * @param iClientId The id of the client.
474      * @return True, if data is currently valid, false otherwise.
475      */
476     bool HasValidDataFromClient(int iClientId) const;
477 
478     /*!
479      * @brief For each channel and its corresponding epg channel data update the order from the group members
480      */
481     void UpdateClientOrder();
482 
483     /*!
484      * @brief For each channel and its corresponding epg channel data update the channel number from the group members
485      */
486     void UpdateChannelNumbers();
487 
488     /*!
489      * @brief Update whether or not this group is currently selected
490      * @param isSelectedGroup whether or not this group is the currently selected group.
491      */
SetSelectedGroup(bool isSelectedGroup)492     void SetSelectedGroup(bool isSelectedGroup) { m_bIsSelectedGroup = isSelectedGroup; }
493 
494     /*!
495      * @brief Update the channel numbers according to the all channels group and publish event.
496      * @return True, if a channel number was changed, false otherwise.
497      */
498     bool UpdateChannelNumbersFromAllChannelsGroup();
499 
500   protected:
501     /*!
502      * @brief Init class
503      */
504     void OnInit();
505 
506     /*!
507      * @brief Load the channels stored in the database.
508      * @param bCompress If true, compress the database after storing the channels.
509      * @return The amount of channels that were added.
510      */
511     virtual int LoadFromDb(bool bCompress = false);
512 
513     /*!
514      * @brief Update the current channel list with the given list.
515      *
516      * Update the current channel list with the given list.
517      * Only the new channels will be present in the passed list after this call.
518      *
519      * @param channels The channels to use to update this list.
520      * @param channelsToRemove Returns the channels to be removed from all groups, if any
521      * @return True if everything went well, false otherwise.
522      */
523     virtual bool UpdateGroupEntries(const CPVRChannelGroup& channels, std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
524 
525     /*!
526      * @brief Add new channels to this group; update data.
527      * @param channels The new channels to use for this group.
528      * @param bUseBackendChannelNumbers True, if channel numbers from backends shall be used.
529      * @return True if everything went well, false otherwise.
530      */
531     virtual bool AddAndUpdateChannels(const CPVRChannelGroup& channels, bool bUseBackendChannelNumbers);
532 
533     /*!
534      * @brief Remove deleted channels from this group.
535      * @param channels The new channels to use for this group.
536      * @return The removed channels.
537      */
538     virtual std::vector<std::shared_ptr<CPVRChannel>> RemoveDeletedChannels(const CPVRChannelGroup& channels);
539 
540     /*!
541      * @brief Clear this channel list.
542      */
543     void Unload();
544 
545     /*!
546      * @brief Load the channels from the clients.
547      * @return True when loaded successfully, false otherwise.
548      */
549     virtual bool LoadFromClients();
550 
551     /*!
552      * @brief Sort the current channel list by client channel number.
553      */
554     void SortByClientChannelNumber();
555 
556     /*!
557      * @brief Sort the current channel list by channel number.
558      */
559     void SortByChannelNumber();
560 
561     /*!
562      * @brief Update the priority for all members of all channel groups.
563      */
564     bool UpdateClientPriorities();
565 
566     int m_iGroupType = PVR_GROUP_TYPE_DEFAULT; /*!< The type of this group */
567     int m_iGroupId = INVALID_GROUP_ID; /*!< The ID of this group in the database */
568     bool m_bLoaded = false; /*!< True if this container is loaded, false otherwise */
569     bool m_bChanged = false; /*!< true if anything changed in this group that hasn't been persisted, false otherwise */
570     bool m_bUsingBackendChannelOrder = false; /*!< true to use the channel order from backends, false otherwise */
571     bool m_bUsingBackendChannelNumbers = false; /*!< true to use the channel numbers from 1 backend, false otherwise */
572     bool m_bPreventSortAndRenumber = false; /*!< true when sorting and renumbering should not be done after adding/updating channels to the group */
573     time_t m_iLastWatched = 0; /*!< last time group has been watched */
574     uint64_t m_iLastOpened = 0; /*!< time in milliseconds from epoch this group was last opened */
575     bool m_bHidden = false; /*!< true if this group is hidden, false otherwise */
576     int m_iPosition = 0; /*!< the position of this group within the group list */
577     std::vector<std::shared_ptr<PVRChannelGroupMember>> m_sortedMembers; /*!< members sorted by channel number */
578     std::map<std::pair<int, int>, std::shared_ptr<PVRChannelGroupMember>> m_members; /*!< members with key clientid+uniqueid */
579     mutable CCriticalSection m_critSection;
580     std::vector<int> m_failedClients;
581     CEventSource<PVREvent> m_events;
582     bool m_bIsSelectedGroup = false; /*!< Whether or not this group is currently selected */
583     bool m_bStartGroupChannelNumbersFromOne = false; /*!< true if we start group channel numbers from one when not using backend channel numbers, false otherwise */
584     bool m_bSyncChannelGroups = false; /*!< true if channel groups should be synced with the backend, false otherwise */
585 
586   private:
587     CDateTime GetEPGDate(EpgDateType epgDateType) const;
588 
589     std::shared_ptr<CPVRChannelGroup> m_allChannelsGroup;
590     CPVRChannelsPath m_path;
591   };
592 }
593