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 #include "PVROperations.h"
10
11 #include "ServiceBroker.h"
12 #include "pvr/PVRManager.h"
13 #include "pvr/PVRPlaybackState.h"
14 #include "pvr/addons/PVRClients.h"
15 #include "pvr/channels/PVRChannel.h"
16 #include "pvr/channels/PVRChannelGroups.h"
17 #include "pvr/channels/PVRChannelGroupsContainer.h"
18 #include "pvr/epg/Epg.h"
19 #include "pvr/epg/EpgContainer.h"
20 #include "pvr/epg/EpgInfoTag.h"
21 #include "pvr/guilib/PVRGUIActions.h"
22 #include "pvr/recordings/PVRRecordings.h"
23 #include "pvr/timers/PVRTimerInfoTag.h"
24 #include "pvr/timers/PVRTimers.h"
25 #include "utils/Variant.h"
26
27 using namespace JSONRPC;
28 using namespace PVR;
29 using namespace KODI::MESSAGING;
30
GetProperties(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)31 JSONRPC_STATUS CPVROperations::GetProperties(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
32 {
33 if (!CServiceBroker::GetPVRManager().IsStarted())
34 return FailedToExecute;
35
36 CVariant properties = CVariant(CVariant::VariantTypeObject);
37 for (unsigned int index = 0; index < parameterObject["properties"].size(); index++)
38 {
39 std::string propertyName = parameterObject["properties"][index].asString();
40 CVariant property;
41 JSONRPC_STATUS ret;
42 if ((ret = GetPropertyValue(propertyName, property)) != OK)
43 return ret;
44
45 properties[propertyName] = property;
46 }
47
48 result = properties;
49
50 return OK;
51 }
52
GetChannelGroups(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)53 JSONRPC_STATUS CPVROperations::GetChannelGroups(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
54 {
55 if (!CServiceBroker::GetPVRManager().IsStarted())
56 return FailedToExecute;
57
58 std::shared_ptr<CPVRChannelGroupsContainer> channelGroupContainer = CServiceBroker::GetPVRManager().ChannelGroups();
59 if (!channelGroupContainer)
60 return FailedToExecute;
61
62 CPVRChannelGroups *channelGroups = channelGroupContainer->Get(parameterObject["channeltype"].asString().compare("radio") == 0);
63 if (channelGroups == NULL)
64 return FailedToExecute;
65
66 int start, end;
67
68 std::vector<std::shared_ptr<CPVRChannelGroup>> groupList = channelGroups->GetMembers(true);
69 HandleLimits(parameterObject, result, groupList.size(), start, end);
70 for (int index = start; index < end; index++)
71 FillChannelGroupDetails(groupList.at(index), parameterObject, result["channelgroups"], true);
72
73 return OK;
74 }
75
GetChannelGroupDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)76 JSONRPC_STATUS CPVROperations::GetChannelGroupDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
77 {
78 if (!CServiceBroker::GetPVRManager().IsStarted())
79 return FailedToExecute;
80
81 std::shared_ptr<CPVRChannelGroupsContainer> channelGroupContainer = CServiceBroker::GetPVRManager().ChannelGroups();
82 if (!channelGroupContainer)
83 return FailedToExecute;
84
85 std::shared_ptr<CPVRChannelGroup> channelGroup;
86 CVariant id = parameterObject["channelgroupid"];
87 if (id.isInteger())
88 channelGroup = channelGroupContainer->GetByIdFromAll((int)id.asInteger());
89 else if (id.isString())
90 channelGroup = channelGroupContainer->GetGroupAll(id.asString() == "allradio");
91
92 if (channelGroup == NULL)
93 return InvalidParams;
94
95 FillChannelGroupDetails(channelGroup, parameterObject, result["channelgroupdetails"], false);
96
97 return OK;
98 }
99
GetChannels(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)100 JSONRPC_STATUS CPVROperations::GetChannels(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
101 {
102 if (!CServiceBroker::GetPVRManager().IsStarted())
103 return FailedToExecute;
104
105 std::shared_ptr<CPVRChannelGroupsContainer> channelGroupContainer = CServiceBroker::GetPVRManager().ChannelGroups();
106 if (!channelGroupContainer)
107 return FailedToExecute;
108
109 std::shared_ptr<CPVRChannelGroup> channelGroup;
110 CVariant id = parameterObject["channelgroupid"];
111 if (id.isInteger())
112 channelGroup = channelGroupContainer->GetByIdFromAll((int)id.asInteger());
113 else if (id.isString())
114 channelGroup = channelGroupContainer->GetGroupAll(id.asString() == "allradio");
115
116 if (channelGroup == NULL)
117 return InvalidParams;
118
119 CFileItemList channels;
120 const std::vector<std::shared_ptr<PVRChannelGroupMember>> groupMembers = channelGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE);
121 for (const auto& groupMember : groupMembers)
122 {
123 channels.Add(std::make_shared<CFileItem>(groupMember->channel));
124 }
125
126 HandleFileItemList("channelid", false, "channels", channels, parameterObject, result, true);
127
128 return OK;
129 }
130
GetChannelDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)131 JSONRPC_STATUS CPVROperations::GetChannelDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
132 {
133 if (!CServiceBroker::GetPVRManager().IsStarted())
134 return FailedToExecute;
135
136 std::shared_ptr<CPVRChannelGroupsContainer> channelGroupContainer = CServiceBroker::GetPVRManager().ChannelGroups();
137 if (!channelGroupContainer)
138 return FailedToExecute;
139
140 std::shared_ptr<CPVRChannel> channel = channelGroupContainer->GetChannelById((int)parameterObject["channelid"].asInteger());
141 if (channel == NULL)
142 return InvalidParams;
143
144 HandleFileItem("channelid", false, "channeldetails", CFileItemPtr(new CFileItem(channel)), parameterObject, parameterObject["properties"], result, false);
145
146 return OK;
147 }
148
GetClients(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)149 JSONRPC_STATUS CPVROperations::GetClients(const std::string& method,
150 ITransportLayer* transport,
151 IClient* client,
152 const CVariant& parameterObject,
153 CVariant& result)
154 {
155 if (!CServiceBroker::GetPVRManager().IsStarted())
156 return FailedToExecute;
157
158 int start, end;
159
160 auto clientInfos = CServiceBroker::GetPVRManager().Clients()->GetEnabledClientInfos();
161 HandleLimits(parameterObject, result, clientInfos.size(), start, end);
162 for (int index = start; index < end; index++)
163 result["clients"].append(clientInfos[index]);
164
165 return OK;
166 }
167
GetBroadcasts(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)168 JSONRPC_STATUS CPVROperations::GetBroadcasts(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
169 {
170 if (!CServiceBroker::GetPVRManager().IsStarted())
171 return FailedToExecute;
172
173 std::shared_ptr<CPVRChannelGroupsContainer> channelGroupContainer = CServiceBroker::GetPVRManager().ChannelGroups();
174 if (!channelGroupContainer)
175 return FailedToExecute;
176
177 std::shared_ptr<CPVRChannel> channel = channelGroupContainer->GetChannelById((int)parameterObject["channelid"].asInteger());
178 if (channel == NULL)
179 return InvalidParams;
180
181 std::shared_ptr<CPVREpg> channelEpg = channel->GetEPG();
182 if (!channelEpg)
183 return InternalError;
184
185 CFileItemList programFull;
186
187 const std::vector<std::shared_ptr<CPVREpgInfoTag>> tags = channelEpg->GetTags();
188 for (const auto& tag : tags)
189 {
190 programFull.Add(std::make_shared<CFileItem>(tag));
191 }
192
193 HandleFileItemList("broadcastid", false, "broadcasts", programFull, parameterObject, result, programFull.Size(), true);
194
195 return OK;
196 }
197
GetBroadcastDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)198 JSONRPC_STATUS CPVROperations::GetBroadcastDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
199 {
200 if (!CServiceBroker::GetPVRManager().IsStarted())
201 return FailedToExecute;
202
203 const std::shared_ptr<CPVREpgInfoTag> epgTag =
204 CServiceBroker::GetPVRManager().EpgContainer().GetTagByDatabaseId(
205 parameterObject["broadcastid"].asInteger());
206
207 if (!epgTag)
208 return InvalidParams;
209
210 HandleFileItem("broadcastid", false, "broadcastdetails", CFileItemPtr(new CFileItem(epgTag)), parameterObject, parameterObject["properties"], result, false);
211
212 return OK;
213 }
214
GetBroadcastIsPlayable(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)215 JSONRPC_STATUS CPVROperations::GetBroadcastIsPlayable(const std::string& method,
216 ITransportLayer* transport,
217 IClient* client,
218 const CVariant& parameterObject,
219 CVariant& result)
220 {
221 if (!CServiceBroker::GetPVRManager().IsStarted())
222 return FailedToExecute;
223
224 const std::shared_ptr<CPVREpgInfoTag> epgTag =
225 CServiceBroker::GetPVRManager().EpgContainer().GetTagByDatabaseId(
226 parameterObject["broadcastid"].asInteger());
227
228 if (!epgTag)
229 return InvalidParams;
230
231 result = epgTag->IsPlayable();
232
233 return OK;
234 }
235
Record(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)236 JSONRPC_STATUS CPVROperations::Record(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
237 {
238 if (!CServiceBroker::GetPVRManager().IsStarted())
239 return FailedToExecute;
240
241 std::shared_ptr<CPVRChannel> pChannel;
242 CVariant channel = parameterObject["channel"];
243 if (channel.isString() && channel.asString() == "current")
244 {
245 pChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
246 if (!pChannel)
247 return InternalError;
248 }
249 else if (channel.isInteger())
250 {
251 std::shared_ptr<CPVRChannelGroupsContainer> channelGroupContainer = CServiceBroker::GetPVRManager().ChannelGroups();
252 if (!channelGroupContainer)
253 return FailedToExecute;
254
255 pChannel = channelGroupContainer->GetChannelById((int)channel.asInteger());
256 }
257 else
258 return InvalidParams;
259
260 if (pChannel == NULL)
261 return InvalidParams;
262 else if (!pChannel->CanRecord())
263 return FailedToExecute;
264
265 CVariant record = parameterObject["record"];
266 bool bIsRecording = CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*pChannel);
267 bool toggle = true;
268 if (record.isBoolean() && record.asBoolean() == bIsRecording)
269 toggle = false;
270
271 if (toggle)
272 {
273 if (!CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(pChannel, !bIsRecording))
274 return FailedToExecute;
275 }
276
277 return ACK;
278 }
279
Scan(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)280 JSONRPC_STATUS CPVROperations::Scan(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
281 {
282 if (!CServiceBroker::GetPVRManager().IsStarted())
283 return FailedToExecute;
284
285 if (parameterObject.isMember("clientid"))
286 {
287 if (CServiceBroker::GetPVRManager().GUIActions()->StartChannelScan(
288 parameterObject["clientid"].asInteger()))
289 return ACK;
290 }
291 else
292 {
293 if (CServiceBroker::GetPVRManager().GUIActions()->StartChannelScan())
294 return ACK;
295 }
296
297 return FailedToExecute;
298 }
299
GetPropertyValue(const std::string & property,CVariant & result)300 JSONRPC_STATUS CPVROperations::GetPropertyValue(const std::string &property, CVariant &result)
301 {
302 bool started = CServiceBroker::GetPVRManager().IsStarted();
303
304 if (property == "available")
305 result = started;
306 else if (property == "recording")
307 {
308 if (started)
309 result = CServiceBroker::GetPVRManager().PlaybackState()->IsRecording();
310 else
311 result = false;
312 }
313 else if (property == "scanning")
314 {
315 if (started)
316 result = CServiceBroker::GetPVRManager().GUIActions()->IsRunningChannelScan();
317 else
318 result = false;
319 }
320 else
321 return InvalidParams;
322
323 return OK;
324 }
325
FillChannelGroupDetails(const std::shared_ptr<CPVRChannelGroup> & channelGroup,const CVariant & parameterObject,CVariant & result,bool append)326 void CPVROperations::FillChannelGroupDetails(const std::shared_ptr<CPVRChannelGroup> &channelGroup, const CVariant ¶meterObject, CVariant &result, bool append /* = false */)
327 {
328 if (channelGroup == NULL)
329 return;
330
331 CVariant object(CVariant::VariantTypeObject);
332 object["channelgroupid"] = channelGroup->GroupID();
333 object["channeltype"] = channelGroup->IsRadio() ? "radio" : "tv";
334 object["label"] = channelGroup->GroupName();
335
336 if (append)
337 result.append(object);
338 else
339 {
340 CFileItemList channels;
341 const std::vector<std::shared_ptr<PVRChannelGroupMember>> groupMembers = channelGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE);
342 for (const auto& groupMember : groupMembers)
343 {
344 channels.Add(std::make_shared<CFileItem>(groupMember->channel));
345 }
346
347 object["channels"] = CVariant(CVariant::VariantTypeArray);
348 HandleFileItemList("channelid", false, "channels", channels, parameterObject["channels"], object, false);
349
350 result = object;
351 }
352 }
353
GetTimers(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)354 JSONRPC_STATUS CPVROperations::GetTimers(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
355 {
356 if (!CServiceBroker::GetPVRManager().IsStarted())
357 return FailedToExecute;
358
359 std::shared_ptr<CPVRTimers> timers = CServiceBroker::GetPVRManager().Timers();
360 if (!timers)
361 return FailedToExecute;
362
363 CFileItemList timerList;
364 const std::vector<std::shared_ptr<CPVRTimerInfoTag>> tags = timers->GetAll();
365 for (const auto& timer : tags)
366 {
367 timerList.Add(std::make_shared<CFileItem>(timer));
368 }
369
370 HandleFileItemList("timerid", false, "timers", timerList, parameterObject, result, true);
371
372 return OK;
373 }
374
GetTimerDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)375 JSONRPC_STATUS CPVROperations::GetTimerDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
376 {
377 if (!CServiceBroker::GetPVRManager().IsStarted())
378 return FailedToExecute;
379
380 std::shared_ptr<CPVRTimers> timers = CServiceBroker::GetPVRManager().Timers();
381 if (!timers)
382 return FailedToExecute;
383
384 std::shared_ptr<CPVRTimerInfoTag> timer = timers->GetById((int)parameterObject["timerid"].asInteger());
385 if (!timer)
386 return InvalidParams;
387
388 HandleFileItem("timerid", false, "timerdetails", CFileItemPtr(new CFileItem(timer)), parameterObject, parameterObject["properties"], result, false);
389
390 return OK;
391 }
392
AddTimer(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)393 JSONRPC_STATUS CPVROperations::AddTimer(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
394 {
395 if (!CServiceBroker::GetPVRManager().IsStarted())
396 return FailedToExecute;
397
398 const std::shared_ptr<CPVREpgInfoTag> epgTag =
399 CServiceBroker::GetPVRManager().EpgContainer().GetTagByDatabaseId(
400 parameterObject["broadcastid"].asInteger());
401
402 if (!epgTag)
403 return InvalidParams;
404
405 if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag))
406 return InvalidParams;
407
408 const std::shared_ptr<CPVRTimerInfoTag> newTimer =
409 CPVRTimerInfoTag::CreateFromEpg(epgTag, parameterObject["timerrule"].asBoolean(false),
410 parameterObject["reminder"].asBoolean(false));
411 if (newTimer)
412 {
413 if (CServiceBroker::GetPVRManager().GUIActions()->AddTimer(newTimer))
414 return ACK;
415 }
416 return FailedToExecute;
417 }
418
419
DeleteTimer(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)420 JSONRPC_STATUS CPVROperations::DeleteTimer(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
421 {
422 if (!CServiceBroker::GetPVRManager().IsStarted())
423 return FailedToExecute;
424
425 std::shared_ptr<CPVRTimers> timers = CServiceBroker::GetPVRManager().Timers();
426 if (!timers)
427 return FailedToExecute;
428
429 std::shared_ptr<CPVRTimerInfoTag> timer = timers->GetById(parameterObject["timerid"].asInteger());
430 if (!timer)
431 return InvalidParams;
432
433 if (timers->DeleteTimer(timer, timer->IsRecording(), false) == TimerOperationResult::OK)
434 return ACK;
435
436 return FailedToExecute;
437 }
438
ToggleTimer(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)439 JSONRPC_STATUS CPVROperations::ToggleTimer(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
440 {
441 if (!CServiceBroker::GetPVRManager().IsStarted())
442 return FailedToExecute;
443
444 const std::shared_ptr<CPVREpgInfoTag> epgTag =
445 CServiceBroker::GetPVRManager().EpgContainer().GetTagByDatabaseId(
446 parameterObject["broadcastid"].asInteger());
447
448 if (!epgTag)
449 return InvalidParams;
450
451 bool timerrule = parameterObject["timerrule"].asBoolean(false);
452 bool sentOkay = false;
453 std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag);
454 if (timer)
455 {
456 if (timerrule)
457 timer = CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer);
458
459 if (timer)
460 sentOkay = (CServiceBroker::GetPVRManager().Timers()->DeleteTimer(timer, timer->IsRecording(), false) == TimerOperationResult::OK);
461 }
462 else
463 {
464 timer = CPVRTimerInfoTag::CreateFromEpg(epgTag, timerrule);
465 if (!timer)
466 return InvalidParams;
467
468 sentOkay = CServiceBroker::GetPVRManager().GUIActions()->AddTimer(timer);
469 }
470
471 if (sentOkay)
472 return ACK;
473
474 return FailedToExecute;
475 }
476
GetRecordings(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)477 JSONRPC_STATUS CPVROperations::GetRecordings(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
478 {
479 if (!CServiceBroker::GetPVRManager().IsStarted())
480 return FailedToExecute;
481
482 std::shared_ptr<CPVRRecordings> recordings = CServiceBroker::GetPVRManager().Recordings();
483 if (!recordings)
484 return FailedToExecute;
485
486 CFileItemList recordingsList;
487 const std::vector<std::shared_ptr<CPVRRecording>> recs = recordings->GetAll();
488 for (const auto& recording : recs)
489 {
490 recordingsList.Add(std::make_shared<CFileItem>(recording));
491 }
492
493 HandleFileItemList("recordingid", true, "recordings", recordingsList, parameterObject, result, true);
494
495 return OK;
496 }
497
GetRecordingDetails(const std::string & method,ITransportLayer * transport,IClient * client,const CVariant & parameterObject,CVariant & result)498 JSONRPC_STATUS CPVROperations::GetRecordingDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
499 {
500 if (!CServiceBroker::GetPVRManager().IsStarted())
501 return FailedToExecute;
502
503 std::shared_ptr<CPVRRecordings> recordings = CServiceBroker::GetPVRManager().Recordings();
504 if (!recordings)
505 return FailedToExecute;
506
507 const std::shared_ptr<CPVRRecording> recording = recordings->GetById(static_cast<int>(parameterObject["recordingid"].asInteger()));
508 if (!recording)
509 return InvalidParams;
510
511 HandleFileItem("recordingid", true, "recordingdetails", std::make_shared<CFileItem>(recording), parameterObject, parameterObject["properties"], result, false);
512
513 return OK;
514 }
515