Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

[PVR] support for fetching timers and recordings via json-rpc #4198

Closed
wants to merge 4 commits into from

8 participants

@opdenkamp
Collaborator

requested in http://forum.xbmc.org/showthread.php?tid=186072

ping @t-nelson @montellese @joethefox

just compile tested, i'll leave the actual testing up to you ;-)

@opdenkamp opdenkamp added the PVR label
@opdenkamp
Collaborator

jenkins build this please

@t-nelson
Collaborator

loop checks for

!item && it != m_recordings.end()

Ah, missed it in the mess of STLisms. :)

We await word from the Kiwi.

@t-nelson

Am I sensing a bit of C&P? :)

Collaborator

ofc :)

@t-nelson

Seems reasonable. @jmarshallnz are you opposed to consideration for Gotham? With @Montellese's approval, ofc.

@da-anda

given you initialized m_iLastId as 0 you'd have a recording with ID 0 as well. Not sure if 0 is a good value for an ID, so I'd rather change it to ++m_iLastId. Also using m_iLastId++ would end in m_iLastId to not reflect the actual last used ID but last ID +1 unless C++ is handling this stuff differently than any other programming language I know.

Collaborator

I consider '0' as valid identifier really, but i don't mind starting with 1 instead. i'll have a look at it in the evening

Collaborator

as long as we don't store the value in the DB 0 is ofc valid, but who knows, maybe we start caching those identifiers in the local db for G+1 to speed up startup. I just like to be prepared for the future. But aside from 0 or not, m_iLastId doesn't currently hold the last used ID but the next free ID, and at least that should be changed.

Collaborator

sure sure ;-)

@da-anda

same as with my comment in the other commit, you should probably change it to ++m_iLastId (also in line 290 further down)

@joethefox

tested. compiles fine but at the moment it returns "method not found". Seems that also xbmc/interfaces/json-rpc/ServiceDescription.h , xbmc/interfaces/json-rpc/methods.json and xbmc/interfaces/json-rpc/types.json need to be updated according to the new methods/types.

ServiceDescription.h and addons/xbmc.json/addon.xml need a version update, could be 6.13.6.

@da-anda
Collaborator

@joethefox correct, those changes are missing

@opdenkamp
Collaborator

right, looks like it indeed. i don't know the json-rpc code really, i just added what the other methods were doing :) i'll add it to this PR and change @da-anda's cosmetics.

@Montellese Montellese commented on the diff
xbmc/FileItem.cpp
@@ -227,6 +227,8 @@
m_strLabel2 = record.m_strPlot;
FillInMimeType(false);
+
+ SetProperty("recordingid", record.m_iRecordingId);
@Montellese Owner

While this (and the same logic for the constructor taking a CPVRTimerInfoTag) should work with JSON-RPC I'd prefer the way this works for video, music, epg etc i.e. CPVRRecording and CPVRTimerInfoTag implement the ISerializable interface and expose all their properties through that method which is then called by JSON-RPC to serialize the retrieved values. It prevents unnecessary cluttering of the properties map in CFileItem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese
Owner

As mentioned this requires the definition of the methods in the JSON schema API description. I can do that (and the changes to CPVRRecording and CPVRTimerInfoTag if you want me to.

I can't test the results however since I don't have a PVR backend/setup.

@MartijnKaijser MartijnKaijser added this to the Pending for inclusion milestone
@Tolriq

@Montellese You can just add demo pvr addons, it does works well with any platform and integrate well with JSON without the need for real PVR things.

If last time changes are allowed, would I'd be allowed to propose a PR to add some filtering to PVR.GetBroadcasts ? To allow returning only current or future items for faster answer.
And if possible a query for full data (IE without the filter on channel), since current API is quite slow and limited for efficient use :( Doing 300+ queries to display now playing on channels is bad :(

@opdenkamp
Collaborator

I'll have a look at it tonight, but I'm also fine with you doing the changes, since I don't really know JSON-RPC and was just being a c+p monkey, so we don't end up with only a half working implementation.

@topfs2
Collaborator

@Tolriq This discussion is a bit off topic but anyways, It would be up to the release managers. Since the feature exist and you would mostly provide performance increase they might be reluctant. However they might be swaded (just don't overpress your point, if they say no its no). That being said, the feature sounds valid and if the implementation is fine I'd be surprised if we couldn't include it for G+1

@Tolriq

This is a PR for new pvr things with an ask for include in Gotham ;) So I try to ask for another one to have json pvr really usable in Gotham ;)

My point will not change on the fact I will only PR after validation and not before :)

@topfs2
Collaborator
@Tolriq

Yes I'm sadly aware that validating a concept or the need for a feature before coding is so horrible to the Team :(
(Since I obviously do not ask for discussion on code content before submitting code ...)

Perhaps one day this will change and we can see more devs helping on Xbmc code :)
Not everyone can afford to loose time on something that whatever how it's coded will be refused after :)

Anyway if one day this change you know where to find me.

@da-anda
Collaborator

@Tolriq we can give an answer if your suggestion in general is feasable for XBMC or not, but this won't be a guarantee that it'll be merged. It's still possible that devs don't like the way you implemented it and thus demand for changes or will deny it in favor of an entirely different approach your PR gave the inspiration for.
Also we can't tell you if it would make it into Gotham without a PR, because this depends on the code impact it has and it's possible side-effects. Highly self-contained code properly splitted into separate commits would increase the chances though.

To me your suggestions in general sound sane, but I'm not a dev, nor did I have a look at current implementation. Also fetching all PVR data in one go might not be the best solution - depending on the load it will cause (think about low power devices like the RasPi). So lazy loading of the data on your end in configurable junk sizes (like 10/50/100/... items in one go) might be preferred.
If you like to discuss further I suggest to move the discussion to the forum to not spam every dev.

@Tolriq

@da-anda I do understand your remarks and fight for that :)

But perhaps you missed http://forum.xbmc.org/showthread.php?tid=166398 but I'd like to continue to discuss this furthermore if some of the team does jump in this simple discussion I try to open since lots of months :)

As a side last remark about lazy loading, this is the goal of limits in JSON part and if I go with allowing getting all data limits would be added too since it's the only way to go with on rpi :) (Cf my accepted PR for Files.GetDirectory for example).

@t-nelson
@t-nelson

Where are we at on this? Just need the header/json thingy updated?

@Montellese
Owner

Yeah but I didn't have the time yet. Maybe tonight.

@Montellese
Owner

As promised, see #4246.

@t-nelson

Closing in favor of #4246

@t-nelson t-nelson closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
6 xbmc/FileItem.cpp
@@ -227,6 +227,8 @@ CFileItem::CFileItem(const CPVRRecording& record)
m_strLabel2 = record.m_strPlot;
FillInMimeType(false);
+
+ SetProperty("recordingid", record.m_iRecordingId);
@Montellese Owner

While this (and the same logic for the constructor taking a CPVRTimerInfoTag) should work with JSON-RPC I'd prefer the way this works for video, music, epg etc i.e. CPVRRecording and CPVRTimerInfoTag implement the ISerializable interface and expose all their properties through that method which is then called by JSON-RPC to serialize the retrieved values. It prevents unnecessary cluttering of the properties map in CFileItem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
@@ -252,6 +254,10 @@ CFileItem::CFileItem(const CPVRTimerInfoTag& timer)
SetIconImage(timer.ChannelIcon());
FillInMimeType(false);
+
+ SetProperty("timerclient", timer.m_iClientId);
+ SetProperty("timerclientid", timer.m_iClientIndex);
+ SetProperty("timerid", timer.m_iTimerId);
}
CFileItem::CFileItem(const CArtist& artist)
View
4 xbmc/interfaces/json-rpc/JSONServiceDescription.cpp
@@ -171,6 +171,10 @@ JsonRpcMethodMap CJSONServiceDescription::m_methodMaps[] = {
{ "PVR.GetChannelDetails", CPVROperations::GetChannelDetails },
{ "PVR.GetBroadcasts", CPVROperations::GetBroadcasts },
{ "PVR.GetBroadcastDetails", CPVROperations::GetBroadcastDetails },
+ { "PVR.GetTimers", CPVROperations::GetTimers },
+ { "PVR.GetTimerDetails", CPVROperations::GetTimerDetails },
+ { "PVR.GetRecordings", CPVROperations::GetRecordings },
+ { "PVR.GetRecordingDetails", CPVROperations::GetRecordingDetails },
{ "PVR.Record", CPVROperations::Record },
{ "PVR.Scan", CPVROperations::Scan },
View
72 xbmc/interfaces/json-rpc/PVROperations.cpp
@@ -27,6 +27,8 @@
#include "pvr/channels/PVRChannel.h"
#include "pvr/timers/PVRTimers.h"
#include "pvr/timers/PVRTimerInfoTag.h"
+#include "pvr/recordings/PVRRecordings.h"
+#include "pvr/timers/PVRTimers.h"
#include "epg/Epg.h"
#include "epg/EpgContainer.h"
@@ -300,3 +302,73 @@ void CPVROperations::FillChannelGroupDetails(const CPVRChannelGroupPtr &channelG
result = object;
}
}
+
+JSONRPC_STATUS CPVROperations::GetTimers(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ if (!g_PVRManager.IsStarted())
+ return FailedToExecute;
+
+ CPVRTimers* timers = g_PVRTimers;
+ if (!timers)
+ return FailedToExecute;
+
+ CFileItemList timerList;
+ timers->GetAll(timerList);
+
+ HandleFileItemList("timerid", false, "timers", timerList, parameterObject, result, true);
+
+ return OK;
+}
+
+JSONRPC_STATUS CPVROperations::GetTimerDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ if (!g_PVRManager.IsStarted())
+ return FailedToExecute;
+
+ CPVRTimers* timers = g_PVRTimers;
+ if (!timers)
+ return FailedToExecute;
+
+ CPVRTimerInfoTagPtr timer = timers->GetById((int)parameterObject["timerid"].asInteger());
+ if (!timer)
+ return InvalidParams;
+
+ HandleFileItem("timerid", false, "timerdetails", CFileItemPtr(new CFileItem(*timer)), parameterObject, parameterObject["properties"], result, false);
+
+ return OK;
+}
+
+JSONRPC_STATUS CPVROperations::GetRecordings(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ if (!g_PVRManager.IsStarted())
+ return FailedToExecute;
+
+ CPVRRecordings* recordings = g_PVRRecordings;
+ if (!recordings)
+ return FailedToExecute;
+
+ CFileItemList recordingsList;
+ recordings->GetAll(recordingsList);
+
+ HandleFileItemList("recordingid", true, "recordings", recordingsList, parameterObject, result, true);
+
+ return OK;
+}
+
+JSONRPC_STATUS CPVROperations::GetRecordingDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ if (!g_PVRManager.IsStarted())
+ return FailedToExecute;
+
+ CPVRRecordings* recordings = g_PVRRecordings;
+ if (!recordings)
+ return FailedToExecute;
+
+ CFileItemPtr recording = recordings->GetById((int)parameterObject["recordingid"].asInteger());
+ if (!recording)
+ return InvalidParams;
+
+ HandleFileItem("recordingid", false, "recordingdetails", recording, parameterObject, parameterObject["properties"], result, false);
+
+ return OK;
+}
View
4 xbmc/interfaces/json-rpc/PVROperations.h
@@ -35,6 +35,10 @@ namespace JSONRPC
static JSONRPC_STATUS GetChannelDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
static JSONRPC_STATUS GetBroadcasts(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
static JSONRPC_STATUS GetBroadcastDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+ static JSONRPC_STATUS GetTimers(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+ static JSONRPC_STATUS GetTimerDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+ static JSONRPC_STATUS GetRecordings(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
+ static JSONRPC_STATUS GetRecordingDetails(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
static JSONRPC_STATUS Record(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
static JSONRPC_STATUS Scan(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result);
View
1  xbmc/pvr/recordings/PVRRecording.h
@@ -55,6 +55,7 @@ namespace PVR
CStdString m_strIconPath; /*!< icon path */
CStdString m_strThumbnailPath; /*!< thumbnail path */
CStdString m_strFanartPath; /*!< fanart path */
+ unsigned m_iRecordingId; /*!< id that won't change while xbmc is running */
CPVRRecording(void);
CPVRRecording(const PVR_RECORDING &recording, unsigned int iClientId);
View
17 xbmc/pvr/recordings/PVRRecordings.cpp
@@ -39,7 +39,8 @@
using namespace PVR;
CPVRRecordings::CPVRRecordings(void) :
- m_bIsUpdating(false)
+ m_bIsUpdating(false),
+ m_iLastId(0)
{
}
@@ -456,6 +457,19 @@ void CPVRRecordings::GetAll(CFileItemList &items)
}
}
+CFileItemPtr CPVRRecordings::GetById(unsigned int iId) const
+{
+ CFileItemPtr item;
+ CSingleLock lock(m_critSection);
+ for (std::vector<CPVRRecording *>::const_iterator it = m_recordings.begin(); !item && it != m_recordings.end(); ++it)
+ {
+ if (iId == (*it)->m_iRecordingId)
+ item = CFileItemPtr(new CFileItem(*it));
+ }
+
+ return item;
+}
+
CFileItemPtr CPVRRecordings::GetByPath(const CStdString &path)
{
CURL url(path);
@@ -510,6 +524,7 @@ void CPVRRecordings::UpdateEntry(const CPVRRecording &tag)
{
CPVRRecording *newTag = new CPVRRecording();
newTag->Update(tag);
+ newTag->m_iRecordingId = m_iLastId++;
m_recordings.push_back(newTag);
}
}
View
2  xbmc/pvr/recordings/PVRRecordings.h
@@ -35,6 +35,7 @@ namespace PVR
CCriticalSection m_critSection;
bool m_bIsUpdating;
std::vector<CPVRRecording *> m_recordings;
+ unsigned int m_iLastId;
virtual void UpdateFromClients(void);
virtual CStdString TrimSlashes(const CStdString &strOrig) const;
@@ -71,6 +72,7 @@ namespace PVR
CFileItemPtr GetByPath(const CStdString &path);
void SetPlayCount(const CFileItem &item, int iPlayCount);
void GetAll(CFileItemList &items);
+ CFileItemPtr GetById(unsigned int iId) const;
bool HasAllRecordingsPathExtension(const CStdString &strDirectory);
};
View
1  xbmc/pvr/timers/PVRTimerInfoTag.h
@@ -173,6 +173,7 @@ namespace PVR
CStdString m_strFileNameAndPath; /*!< @brief filename is only for reference */
int m_iChannelNumber; /*!< @brief integer value of the channel number */
bool m_bIsRadio; /*!< @brief is radio channel if set */
+ unsigned int m_iTimerId; /*!< @brief id that won't change as long as XBMC is running */
CPVRChannelPtr m_channel;
unsigned int m_iMarginStart; /*!< @brief (optional) if set, the backend starts the recording iMarginStart minutes before startTime. */
View
32 xbmc/pvr/timers/PVRTimers.cpp
@@ -41,6 +41,7 @@ using namespace EPG;
CPVRTimers::CPVRTimers(void)
{
m_bIsUpdating = false;
+ m_iLastId = 0;
}
CPVRTimers::~CPVRTimers(void)
@@ -151,6 +152,7 @@ bool CPVRTimers::UpdateEntries(const CPVRTimers &timers)
addEntry = itr->second;
}
+ newTimer->m_iTimerId = m_iLastId++;
addEntry->push_back(newTimer);
UpdateEpgEvent(newTimer);
bChanged = true;
@@ -285,6 +287,7 @@ bool CPVRTimers::UpdateFromClient(const CPVRTimerInfoTag &timer)
{
addEntry = itr->second;
}
+ tag->m_iTimerId = m_iLastId++;
addEntry->push_back(tag);
}
@@ -741,3 +744,32 @@ void CPVRTimers::UpdateChannels(void)
(*timerIt)->UpdateChannel();
}
}
+
+void CPVRTimers::GetAll(CFileItemList& items) const
+{
+ CFileItemPtr item;
+ CSingleLock lock(m_critSection);
+ for (map<CDateTime, vector<CPVRTimerInfoTagPtr>* >::const_iterator it = m_tags.begin(); it != m_tags.end(); it++)
+ {
+ for (vector<CPVRTimerInfoTagPtr>::const_iterator timerIt = it->second->begin(); timerIt != it->second->end(); timerIt++)
+ {
+ item.reset(new CFileItem(**timerIt));
+ items.Add(item);
+ }
+ }
+}
+
+CPVRTimerInfoTagPtr CPVRTimers::GetById(unsigned int iTimerId) const
+{
+ CPVRTimerInfoTagPtr item;
+ CSingleLock lock(m_critSection);
+ for (map<CDateTime, vector<CPVRTimerInfoTagPtr>* >::const_iterator it = m_tags.begin(); !item && it != m_tags.end(); it++)
+ {
+ for (vector<CPVRTimerInfoTagPtr>::const_iterator timerIt = it->second->begin(); !item && timerIt != it->second->end(); timerIt++)
+ {
+ if ((*timerIt)->m_iTimerId == iTimerId)
+ item = *timerIt;
+ }
+ }
+ return item;
+}
View
14 xbmc/pvr/timers/PVRTimers.h
@@ -68,6 +68,12 @@ namespace PVR
std::vector<CFileItemPtr> GetActiveTimers(void) const;
/*!
+ * Get all timers
+ * @param items The list to add the timers to
+ */
+ void GetAll(CFileItemList& items) const;
+
+ /*!
* @return True when there is at least one timer that is active (states scheduled or recording), false otherwise.
*/
bool HasActiveTimers(void) const;
@@ -166,6 +172,13 @@ namespace PVR
void Notify(const Observable &obs, const ObservableMessage msg);
+ /*!
+ * Get a timer tag given it's unique ID
+ * @param iTimerId The ID to find
+ * @return The tag, or an empty one when not found
+ */
+ CPVRTimerInfoTagPtr GetById(unsigned int iTimerId) const;
+
private:
void Unload(void);
void UpdateEpgEvent(CPVRTimerInfoTagPtr timer);
@@ -175,5 +188,6 @@ namespace PVR
CCriticalSection m_critSection;
bool m_bIsUpdating;
std::map<CDateTime, std::vector<CPVRTimerInfoTagPtr>* > m_tags;
+ unsigned int m_iLastId;
};
}
Something went wrong with that request. Please try again.