diff --git a/pvr.hdhomerun/addon.xml.in b/pvr.hdhomerun/addon.xml.in index 2fcfcde..d63bc10 100644 --- a/pvr.hdhomerun/addon.xml.in +++ b/pvr.hdhomerun/addon.xml.in @@ -1,7 +1,7 @@ @ADDON_DEPENDS@ diff --git a/pvr.hdhomerun/changelog.txt b/pvr.hdhomerun/changelog.txt index 589dcd9..f2d860a 100644 --- a/pvr.hdhomerun/changelog.txt +++ b/pvr.hdhomerun/changelog.txt @@ -1,3 +1,6 @@ +v20.3.0 +- Add Use HTTP discovery setting + v20.2.1 - Change name to make add-on easier to find in UI diff --git a/pvr.hdhomerun/resources/language/resource.language.en_gb/strings.po b/pvr.hdhomerun/resources/language/resource.language.en_gb/strings.po index 37d8c20..7ecddfa 100644 --- a/pvr.hdhomerun/resources/language/resource.language.en_gb/strings.po +++ b/pvr.hdhomerun/resources/language/resource.language.en_gb/strings.po @@ -43,3 +43,7 @@ msgstr "" msgctxt "#32005" msgid "Mark new show" msgstr "" + +msgctxt "#32006" +msgid "Use HTTP discovery" +msgstr "" diff --git a/pvr.hdhomerun/resources/settings.xml b/pvr.hdhomerun/resources/settings.xml index ac7fab8..a11c85a 100644 --- a/pvr.hdhomerun/resources/settings.xml +++ b/pvr.hdhomerun/resources/settings.xml @@ -23,6 +23,11 @@ true + + 0 + false + + diff --git a/src/HDHomeRunTuners.cpp b/src/HDHomeRunTuners.cpp index fc28d97..0e1f1ff 100644 --- a/src/HDHomeRunTuners.cpp +++ b/src/HDHomeRunTuners.cpp @@ -116,13 +116,69 @@ PVR_ERROR HDHomeRunTuners::OnSystemWake() return PVR_ERROR_NO_ERROR; } +int HDHomeRunTuners::DiscoverTunersViaHttp(struct hdhomerun_discover_device_t* tuners, + int maxtuners) +{ + int numtuners = 0; + + std::string strJson, jsonReaderError; + Json::CharReaderBuilder jsonReaderBuilder; + std::unique_ptr const jsonReader(jsonReaderBuilder.newCharReader()); + + // This API may be removed by the provider in the future without notice; treat an inability + // to access this URL as if there were no tuners discovered. Update() will then attempt + // a normal broadcast discovery and try to find the user's tuner devices that way + if (GetFileContents("https://api.hdhomerun.com/discover", strJson)) + { + Json::Value devices; + if (jsonReader->parse(strJson.c_str(), strJson.c_str() + strJson.size(), &devices, + &jsonReaderError) && + devices.type() == Json::arrayValue) + { + for (const auto& device : devices) + { + // Tuners are identified by the presence of a DeviceID value in the JSON; + // this also applies to devices that have both tuners and a storage engine (DVR) + if (!device["DeviceID"].isNull() && !device["LocalIP"].isNull()) + { + std::string ipstring = device["LocalIP"].asString(); + if (ipstring.length() > 0) + { + uint32_t ip = ntohl(inet_addr(ipstring.c_str())); + numtuners += hdhomerun_discover_find_devices_custom_v2( + ip, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, &tuners[numtuners], + maxtuners - numtuners); + } + } + + if (numtuners == maxtuners) + break; + } + } + } + + return numtuners; +} + bool HDHomeRunTuners::Update(int nMode) { // // Discover // struct hdhomerun_discover_device_t foundDevices[16] = {}; - int nTunerCount = hdhomerun_discover_find_devices_custom_v2(0, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, foundDevices, 16); + int nTunerCount = 0; + + // Attempt tuner discovery via HTTP first if the user has it enabled. The provider may + // remove the ability for this method to work in the future without notice, so ensure + // that normal discovery is treated as a fall-through case rather than making these + // methods mutually exclusive + + if (SettingsType::Get().GetHttpDiscovery()) + nTunerCount = DiscoverTunersViaHttp(foundDevices, 16); + + if (nTunerCount <= 0) + nTunerCount = hdhomerun_discover_find_devices_custom_v2( + 0, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, foundDevices, 16); if (nTunerCount <= 0) return false; diff --git a/src/HDHomeRunTuners.h b/src/HDHomeRunTuners.h index 22b0270..8b1177c 100644 --- a/src/HDHomeRunTuners.h +++ b/src/HDHomeRunTuners.h @@ -87,6 +87,9 @@ class ATTR_DLL_LOCAL HDHomeRunTuners std::string GetChannelStreamURL(const kodi::addon::PVRChannel& channel); unsigned int PvrCalculateUniqueId(const std::string& str); + + int DiscoverTunersViaHttp(struct hdhomerun_discover_device_t* tuners, int maxtuners); + std::vector m_Tuners; std::atomic m_running = {false}; std::thread m_thread; diff --git a/src/Settings.cpp b/src/Settings.cpp index ab6cf02..bc40590 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -21,6 +21,7 @@ bool SettingsType::ReadSettings() bHideDuplicateChannels = kodi::addon::GetSettingBoolean("hide_duplicate", true); bMarkNew = kodi::addon::GetSettingBoolean("mark_new", true); bDebug = kodi::addon::GetSettingBoolean("debug", false); + bHttpDiscovery = kodi::addon::GetSettingBoolean("http_discovery", false); return true; } @@ -42,6 +43,11 @@ ADDON_STATUS SettingsType::SetSetting(const std::string& settingName, bMarkNew = settingValue.GetBoolean(); else if (settingName == "debug") bDebug = settingValue.GetBoolean(); + else if (settingName == "http_discovery") + { + bHttpDiscovery = settingValue.GetBoolean(); + return ADDON_STATUS_NEED_RESTART; + } return ADDON_STATUS_OK; } diff --git a/src/Settings.h b/src/Settings.h index 9861bd2..636ff15 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -23,6 +23,7 @@ class ATTR_DLL_LOCAL SettingsType bool GetHideDuplicateChannels() const { return bHideDuplicateChannels; } bool GetDebug() const { return bDebug; } bool GetMarkNew() const { return bMarkNew; } + bool GetHttpDiscovery() const { return bHttpDiscovery; } private: SettingsType() = default; @@ -31,4 +32,5 @@ class ATTR_DLL_LOCAL SettingsType bool bHideDuplicateChannels = true; bool bDebug = false; bool bMarkNew = false; + bool bHttpDiscovery = false; };