diff --git a/pvr.waipu/addon.xml.in b/pvr.waipu/addon.xml.in index b21f92d..ef32b4c 100644 --- a/pvr.waipu/addon.xml.in +++ b/pvr.waipu/addon.xml.in @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ @@ -30,6 +30,7 @@ resources/screenshots/screenshot-02.jpg +- 1.4.0 Implement Video on Demand channels - 1.3.3 Fix: hide recordable option for items in the past - 1.3.2 Add inputstream.adaptive to dependencies; Fix translation IDs; Show record option only if available - 1.3.1 Add channel groups: display favorites diff --git a/src/WaipuData.cpp b/src/WaipuData.cpp index 8445d49..d67f2ae 100644 --- a/src/WaipuData.cpp +++ b/src/WaipuData.cpp @@ -419,12 +419,16 @@ bool WaipuData::LoadChannelData(void) m_user_channels.end()) continue; + bool tvfuse = false; // check if user has hidden this channel if (channel.HasMember("properties") && channel["properties"].IsArray()) { bool skipChannel = false; for (auto& prop : channel["properties"].GetArray()) + { skipChannel |= (prop.GetString() == string("UserSetHidden")); + tvfuse |= (prop.GetString() == string("tvfuse")); + } if (skipChannel) continue; } @@ -434,6 +438,9 @@ bool WaipuData::LoadChannelData(void) waipu_channel.iChannelNumber = i; // position XBMC->Log(LOG_DEBUG, "[channel] channelnr(pos): %i;", waipu_channel.iChannelNumber); + waipu_channel.tvfuse = tvfuse; + XBMC->Log(LOG_DEBUG, "[channel] tvfuse: %i;", waipu_channel.tvfuse); + waipu_channel.waipuID = waipuid; // waipu[id] XBMC->Log(LOG_DEBUG, "[channel] waipuid: %s;", waipu_channel.waipuID.c_str()); @@ -692,6 +699,14 @@ PVR_ERROR WaipuData::GetEPGForChannel(ADDON_HANDLE handle, tag.iUniqueChannelId = myChannel.iUniqueId; epgEntry.iUniqueChannelId = myChannel.iUniqueId; + // add streamUrlProvider if it is video on demand + if (myChannel.tvfuse && epgData.HasMember("streamUrlProvider") && !epgData["streamUrlProvider"].IsNull()) + { + string streamUrlProvider = epgData["streamUrlProvider"].GetString(); + XBMC->Log(LOG_DEBUG, "[epg] streamUrlProvider: %s;", streamUrlProvider.c_str()); + epgEntry.streamUrlProvider = streamUrlProvider; + } + // is recordable bool isRecordable = !epgData["recordingForbidden"].GetBool(); XBMC->Log(LOG_DEBUG, "[epg] recordable: %i;", isRecordable); @@ -954,6 +969,43 @@ std::string WaipuData::GetRecordingURL(const PVR_RECORDING& recording, const str return ""; } +string WaipuData::GetEPGTagURL(const EPG_TAG& tag, const string& protocol) +{ + ApiLogin(); + + for (const auto& epgEntry : m_epgEntries) + { + if (epgEntry.iUniqueChannelId != tag.iUniqueChannelId) + continue; + if (epgEntry.iUniqueBroadcastId != tag.iUniqueBroadcastId) + continue; + + string url = epgEntry.streamUrlProvider; + XBMC->Log(LOG_DEBUG, "play epgTAG -> %s", tag.strTitle); + XBMC->Log(LOG_DEBUG, "play url -> %s", url.c_str()); + + string tag_resp = HttpGet(url); + XBMC->Log(LOG_DEBUG, "tag resp -> %s", tag_resp.c_str()); + + Document tagDoc; + tagDoc.Parse(tag_resp.c_str()); + if (tagDoc.GetParseError()) + { + XBMC->Log(LOG_ERROR, "[getEPGTagURL] ERROR: error while parsing json"); + return ""; + } + XBMC->Log(LOG_DEBUG, "[tag] streams"); + // check if streams there + if (tagDoc.HasMember("player") && tagDoc["player"].HasMember("mpd")) + { + string mpdUrl = tagDoc["player"]["mpd"].GetString(); + XBMC->Log(LOG_DEBUG, "mpd url -> %s", mpdUrl.c_str()); + return mpdUrl; + } + } + return ""; +} + PVR_ERROR WaipuData::DeleteRecording(const PVR_RECORDING& recording) { if (ApiLogin()) @@ -1161,3 +1213,17 @@ PVR_ERROR WaipuData::IsEPGTagRecordable(const EPG_TAG* tag, bool* bIsRecordable) *bIsRecordable = false; return PVR_ERROR_NO_ERROR; } + +PVR_ERROR WaipuData::IsEPGTagPlayable(const EPG_TAG* tag, bool* bIsPlayable) +{ + for (const auto& channel : m_channels) + { + if (channel.iUniqueId != tag->iUniqueChannelId) + continue; + *bIsPlayable = channel.tvfuse; + return PVR_ERROR_NO_ERROR; + } + + *bIsPlayable = false; + return PVR_ERROR_NO_ERROR; +} diff --git a/src/WaipuData.h b/src/WaipuData.h index 0f3ba94..c71d8fe 100644 --- a/src/WaipuData.h +++ b/src/WaipuData.h @@ -57,6 +57,7 @@ struct WaipuChannel string strChannelName; //waipu[displayName] string strIconPath; // waipu[links][rel=iconlargehd] string strStreamURL; // waipu[links][rel=livePlayout] + bool tvfuse; // tvfuse is on demand channel }; struct WaipuChannelGroup @@ -70,6 +71,7 @@ struct WaipuEPGEntry int iUniqueBroadcastId; int iUniqueChannelId; bool isRecordable; + string streamUrlProvider; }; class WaipuData @@ -92,6 +94,7 @@ class WaipuData int GetRecordingsAmount(bool bDeleted); PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool bDeleted); std::string GetRecordingURL(const PVR_RECORDING& recording, const string& protocol); + std::string GetEPGTagURL(const EPG_TAG& tag, const string& protocol); PVR_ERROR DeleteRecording(const PVR_RECORDING& recording); int GetTimersAmount(void); @@ -102,6 +105,7 @@ class WaipuData std::string GetLicense(void); WAIPU_LOGIN_STATUS GetLoginStatus(void); PVR_ERROR IsEPGTagRecordable(const EPG_TAG* tag, bool* bIsRecordable); + PVR_ERROR IsEPGTagPlayable(const EPG_TAG* tag, bool* bIsPlayable); protected: string HttpGet(const string& url); diff --git a/src/client.cpp b/src/client.cpp index 55e85c9..d96d191 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -263,13 +263,14 @@ extern "C" return PVR_ERROR_SERVER_ERROR; } - PVR_ERROR IsEPGTagPlayable(const EPG_TAG*, bool* bIsPlayable) + PVR_ERROR IsEPGTagPlayable(const EPG_TAG* tag, bool* bIsPlayable) { - /** - *bIsPlayable = true; - return PVR_ERROR_NO_ERROR; - **/ - return PVR_ERROR_NOT_IMPLEMENTED; + if (m_data) + { + return m_data->IsEPGTagPlayable(tag, bIsPlayable); + } + + return PVR_ERROR_FAILED; } int GetChannelsAmount(void) @@ -482,8 +483,20 @@ extern "C" PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount) { - return PVR_ERROR_NOT_IMPLEMENTED; + XBMC->Log(LOG_DEBUG, "[EPG TAG] play it..."); + + string strUrl = m_data->GetEPGTagURL(*tag, protocol); + if (strUrl.empty()) + { + return PVR_ERROR_FAILED; + } + *iPropertiesCount = 0; + setStreamProperties(properties, iPropertiesCount, strUrl); + setStreamProperty(properties, iPropertiesCount, PVR_STREAM_PROPERTY_ISREALTIMESTREAM, "true"); + + return PVR_ERROR_NO_ERROR; } + PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA&) { return PVR_ERROR_NOT_IMPLEMENTED;