Permalink
Browse files

Merge pull request #56 from jdembski/lastplayedpos

[vuplus] Add support for storing the last played position for recordings
  • Loading branch information...
2 parents ed77bf7 + 8555fa2 commit 388254a5e3327e151187012b2d0343558a1a0527 @opdenkamp committed Oct 10, 2012
View
2 addons/pvr.vuplus/addon/addon.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon
id="pvr.vuplus"
- version="0.3.2"
+ version="0.3.3"
name="VU+ / Enigma2 Client"
provider-name="Joerg Dembski">
<requires>
View
4 addons/pvr.vuplus/addon/changelog.txt
@@ -1,3 +1,7 @@
+0.3.3:
+- add: support for storing the last played positions for recordings. These will be stored in the file recordings.xml
+- fix: if the webinterface cannot be loaded, deactivate the addon
+
0.3.2:
- fix: continue to load channels even if we do not have any radio channels
View
178 addons/pvr.vuplus/src/VuData.cpp
@@ -603,6 +603,12 @@ bool Vu::Open()
m_bIsConnected = GetDeviceInfo();
+ if (!m_bIsConnected)
+ {
+ XBMC->Log(LOG_ERROR, "%s It seem's that the webinterface cannot be reached. Make sure that you set the correct configuration options in the addon settings!", __FUNCTION__);
+ return false;
+ }
+
LoadLocations();
LoadChannelData();
@@ -684,7 +690,6 @@ void *Vu::Process()
CLockObject lock(m_mutex);
m_started.Broadcast();
- //XBMC->Log(LOG_DEBUG, "%s - exiting", __FUNCTION__);
return NULL;
}
@@ -976,6 +981,8 @@ PVR_ERROR Vu::GetChannels(ADDON_HANDLE handle, bool bRadio)
Vu::~Vu()
{
+ StoreLastPlayedPositions();
+
StopThread();
m_channels.clear();
@@ -1389,6 +1396,9 @@ PVR_ERROR Vu::DeleteTimer(const PVR_TIMER &timer)
PVR_ERROR Vu::GetRecordings(ADDON_HANDLE handle)
{
+ if (m_iNumRecordings != 0)
+ StoreLastPlayedPositions();
+
m_iNumRecordings = 0;
m_recordings.clear();
@@ -1401,6 +1411,8 @@ PVR_ERROR Vu::GetRecordings(ADDON_HANDLE handle)
}
}
+ RestoreLastPlayedPositions();
+
return PVR_ERROR_NO_ERROR;
}
@@ -1453,6 +1465,8 @@ bool Vu::GetRecordingFromLocation(ADDON_HANDLE handle, CStdString strRecordingFo
int iTmp;
VuRecording recording;
+
+ recording.iLastPlayedPosition = 0;
if (XMLUtils::GetString(pNode, "e2servicereference", strTmp))
recording.strRecordingId = strTmp;
@@ -1858,3 +1872,165 @@ CStdString Vu::URLEncodeInline(const CStdString& str)
}
return quotedStr;
}
+
+int Vu::GetRecordingIndex(CStdString strStreamURL)
+{
+ for (unsigned int i = 0;i<m_recordings.size(); i++)
+ {
+ if (!strStreamURL.compare(m_recordings[i].strStreamURL))
+ return i;
+ }
+ return -1;
+}
+
+PVR_ERROR Vu::SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition)
+{
+ int iRecordId = GetRecordingIndex(recording.strStreamURL);
+
+ if (iRecordId == -1)
+ {
+ XBMC->Log(LOG_ERROR, "%s Could not set lastplayedposition for recording!", __FUNCTION__);
+ return PVR_ERROR_SERVER_ERROR;
+ }
+
+ m_recordings.at(iRecordId).iLastPlayedPosition = lastplayedposition;
+
+ return PVR_ERROR_NO_ERROR;
+}
+
+bool Vu::SetRecordingLastPlayedPosition(CStdString strStreamURL, int lastplayedposition)
+{
+ XBMC->Log(LOG_DEBUG, "%s Set lastplayedposition '%d' for recording '%s'", __FUNCTION__, lastplayedposition, strStreamURL.c_str());
+ int iRecordId = GetRecordingIndex(strStreamURL);
+
+ if (iRecordId == -1)
+ {
+ XBMC->Log(LOG_DEBUG, "%s Could not set lastplayedposition for recording!", __FUNCTION__);
+ return false;
+ }
+
+ m_recordings.at(iRecordId).iLastPlayedPosition = lastplayedposition;
+
+ return PVR_ERROR_NO_ERROR;
+}
+
+int Vu::GetRecordingLastPlayedPosition(const PVR_RECORDING &recording)
+{
+ int iRecordId = GetRecordingIndex(recording.strStreamURL);
+
+ if (iRecordId == -1)
+ {
+ XBMC->Log(LOG_ERROR, "%s Could not get lastplayedposition for recording!", __FUNCTION__);
+ return PVR_ERROR_SERVER_ERROR;
+ }
+
+ return m_recordings.at(iRecordId).iLastPlayedPosition;
+}
+
+bool Vu::StoreLastPlayedPositions()
+{
+ std::ofstream stream;
+
+ CStdString strFileName;
+ strFileName.Format("%srecordings.xml", g_strChannelDataPath.c_str());
+ stream.open(strFileName.c_str());
+
+ if(stream.fail())
+ {
+ return false;
+ }
+
+ stream << "<recordingsdata>\n";
+ stream << "\t<recordingslist>\n";
+ for (unsigned int iRecordingsPtr = 0; iRecordingsPtr < m_recordings.size(); iRecordingsPtr++)
+ {
+ VuRecording &recording = m_recordings.at(iRecordingsPtr);
+ stream << "\t\t<recording>\n";
+
+ CStdString strTmp = recording.strStreamURL;
+ Escape(strTmp, "&", "&amp;");
+ Escape(strTmp, "<", "&lt;");
+ Escape(strTmp, ">", "&gt;");
+
+ stream << "\t\t\t<streamurl>" << strTmp;
+ stream << "</streamurl>\n";
+
+ int i = recording.iLastPlayedPosition;
+
+ stream << "\t\t\t<lastplayedposition>" << i;
+ stream << "</lastplayedposition>\n";
+ stream << "\t\t</recording>\n";
+ }
+
+ stream << "\t</recordingslist>\n";
+
+ stream << "</recordingsdata>\n";
+ stream.close();
+
+ return true;
+}
+
+bool Vu::RestoreLastPlayedPositions()
+{
+ XBMC->Log(LOG_DEBUG, "%s Load recording data from file: '%srecordings.xml'", __FUNCTION__, g_strChannelDataPath.c_str());
+
+ CStdString strFileName;
+ strFileName.Format("%srecordings.xml", g_strChannelDataPath.c_str());
+
+ TiXmlDocument xmlDoc;
+ if (!xmlDoc.LoadFile(strFileName))
+ {
+ XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
+ return false;
+ }
+
+ XBMC->Log(LOG_DEBUG, "%s Parsing recording data.", __FUNCTION__);
+
+ TiXmlHandle hDoc(&xmlDoc);
+ TiXmlElement* pElem;
+ TiXmlHandle hRoot(0);
+
+ pElem = hDoc.FirstChildElement().Element();
+
+ if (!pElem)
+ {
+ XBMC->Log(LOG_DEBUG, "%s Could not find root element", __FUNCTION__);
+ return false;
+ }
+
+ hRoot = TiXmlHandle(pElem);
+
+ // Get the recordingslist
+ pElem = hRoot.FirstChild("recordingslist").Element();
+
+ if (!pElem)
+ {
+ XBMC->Log(LOG_DEBUG, "%s Could not find <recordingslist> element", __FUNCTION__);
+ return false;
+ }
+
+ TiXmlElement* pNode = pElem->FirstChildElement("recording");
+
+ if (!pNode)
+ {
+ XBMC->Log(LOG_DEBUG, "Could not find <recording> element");
+ return false;
+ }
+
+ for (; pNode != NULL; pNode = pNode->NextSiblingElement("recording"))
+ {
+ CStdString strTmp;
+ int iTmp;
+
+ if (!XMLUtils::GetInt(pNode, "lastplayedposition", iTmp))
+ continue;
+
+ if (!XMLUtils::GetString(pNode, "streamurl", strTmp))
+ continue;
+
+ SetRecordingLastPlayedPosition(strTmp, iTmp);
+ }
+
+ return true;
+}
+
View
9 addons/pvr.vuplus/src/VuData.h
@@ -142,6 +142,7 @@ struct VuRecording
std::string strRecordingId;
time_t startTime;
int iDuration;
+ int iLastPlayedPosition;
std::string strTitle;
std::string strStreamURL;
std::string strPlot;
@@ -169,17 +170,17 @@ class Vu : public PLATFORM::CThread
std::vector<VuRecording> m_recordings;
std::vector<VuChannelGroup> m_groups;
std::vector<std::string> m_locations;
-
bool m_bInitial;
unsigned int m_iClientIndexCounter;
PLATFORM::CMutex m_mutex;
PLATFORM::CCondition<bool> m_started;
-
// functions
void StoreChannelData();
void LoadChannelData();
+ bool StoreLastPlayedPositions();
+ bool RestoreLastPlayedPositions();
CStdString GetHttpXML(CStdString& url);
int GetChannelNumber(CStdString strServiceReference);
bool SendSimpleCommand(const CStdString& strCommandURL, CStdString& strResult, bool bIgnoreResult = false);
@@ -191,6 +192,7 @@ class Vu : public PLATFORM::CThread
std::vector<VuTimer> LoadTimers();
void TimerUpdates();
bool GetDeviceInfo();
+ int GetRecordingIndex(CStdString);
// helper functions
static long TimeStringToSeconds(const CStdString &timeString);
@@ -217,6 +219,9 @@ class Vu : public PLATFORM::CThread
int GetTimersAmount(void);
PVR_ERROR GetTimers(ADDON_HANDLE handle);
PVR_ERROR AddTimer(const PVR_TIMER &timer);
+ PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition);
+ bool SetRecordingLastPlayedPosition(CStdString strStreamURL, int lastplayedposition);
+ int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording);
PVR_ERROR UpdateTimer(const PVR_TIMER &timer);
PVR_ERROR DeleteTimer(const PVR_TIMER &timer);
bool GetRecordingFromLocation(ADDON_HANDLE handle, CStdString strRecordingFolder);
View
19 addons/pvr.vuplus/src/client.cpp
@@ -351,7 +351,7 @@ PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities)
pCapabilities->bSupportsChannelScan = false;
pCapabilities->bHandlesInputStream = true;
pCapabilities->bHandlesDemuxing = false;
- pCapabilities->bSupportsLastPlayedPosition = false;
+ pCapabilities->bSupportsLastPlayedPosition = true;
return PVR_ERROR_NO_ERROR;
}
@@ -543,6 +543,21 @@ const char * GetLiveStreamURL(const PVR_CHANNEL &channel)
return VuData->GetLiveStreamURL(channel);
}
+PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition)
+{
+ if (!VuData || !VuData->IsConnected())
+ return PVR_ERROR_SERVER_ERROR;
+
+ return VuData->SetRecordingLastPlayedPosition(recording, lastplayedposition);
+}
+
+int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording)
+{
+ if (!VuData || !VuData->IsConnected())
+ return -1;
+
+ return VuData->GetRecordingLastPlayedPosition(recording);
+}
/** UNUSED API FUNCTIONS */
PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS &signalStatus) { return PVR_ERROR_NO_ERROR; }
@@ -569,8 +584,6 @@ long long SeekLiveStream(long long iPosition, int iWhence /* = SEEK_SET */) { re
long long PositionLiveStream(void) { return -1; }
long long LengthLiveStream(void) { return -1; }
PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING &recording, int count) { return PVR_ERROR_NOT_IMPLEMENTED; }
-PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition) { return PVR_ERROR_NOT_IMPLEMENTED; }
-int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording) { return -1; }
unsigned int GetChannelSwitchDelay(void) { return 0; }
void PauseStream(bool bPaused) {}
bool CanPauseStream(void) { return false; }

0 comments on commit 388254a

Please sign in to comment.