diff --git a/pvr.eon/addon.xml.in b/pvr.eon/addon.xml.in index 0ea929f..4581693 100644 --- a/pvr.eon/addon.xml.in +++ b/pvr.eon/addon.xml.in @@ -1,12 +1,11 @@ @ADDON_DEPENDS@ - diff --git a/pvr.eon/changelog.txt b/pvr.eon/changelog.txt index 14083d2..20cff3b 100644 --- a/pvr.eon/changelog.txt +++ b/pvr.eon/changelog.txt @@ -20,3 +20,5 @@ v21.7.4 - Exploit some more EPG data (live, age, seasons, episodes) v21.7.5 - Fix startup with empty credentials and web +v20.7.6 + - Try to fix armv7a diff --git a/src/Globals.h b/src/Globals.h index 0d052db..c1ce54b 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -15,13 +15,6 @@ static const std::string EON_USER_AGENT = std::string("Kodi/") static const std::string GLOBAL_URL = "global.united.cloud/"; static const std::string BROKER_URL = "https://broker." + GLOBAL_URL; static const std::string PLAYER = "m3u8"; - -static const std::string CLIENT_ID_WEB = "b8d9ade4-1093-46a7-a4f7-0e47be463c10"; -static const std::string CLIENT_SECRET_WEB = "1w4dmww87x1e9l89essqvc81pidrqsa0li1rva23"; - -static const std::string CLIENT_ID_ATV = "5a3e24b8-70cd-4958-b716-af9ce053e594"; -static const std::string CLIENT_SECRET_ATV = "aazy6orsi9elhhs17e47lfb4palgszw6igf4y26z"; - static const std::string SS_DOMAIN = "TBA"; static const std::string SS_USER = "webscuser"; static const std::string SS_SECRET = "k4md93!k334f3"; @@ -38,3 +31,57 @@ static const std::string CONN_TYPE_WIFI = "WI_FI"; static const std::string CONN_TYPE_ETHERNET= "ETHERNET"; static const std::string CONN_TYPE_MOBILE = "MOBILE"; static const std::string CONN_TYPE_BROWSER = "BROWSER"; + +struct EonParameter +{ + std::string api_prefix; + std::string api_selector; + std::string device_type; + std::string device_name; + std::string device_model; + std::string device_platform; + std::string device_mac; + std::string client_sw_version; + std::string client_sw_build; + std::string system_sw; + std::string system_version; + std::string user_agent; + std::string client_id; + std::string client_secret; +}; + +static const EonParameter EonParameters[2] = {{ + //Web Client + "web", + "be", + "web_linux_chrome", + "", + "Chrome 116", + "web", + "", + "", + "", + "Linux", + "x86_64", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", + "b8d9ade4-1093-46a7-a4f7-0e47be463c10", + "1w4dmww87x1e9l89essqvc81pidrqsa0li1rva23" + }, + { + //Android TV + "android-tv", + "af31", + "Android 11", + "Android TV 30", + "SHIELD Android TV", + "android_tv", + "", + "8.1.3", + "8.1.35906", + "Android", + "11", + "Mozilla/5.0 (Linux; Android 11; SHIELD Android TV Build/RQ1A.210105.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.196 Mobile Safari/537.36; XDKAndroidWebView/3.0.1/XDKWebView NVIDIA NVIDIA/mdarcy/mdarcy:11/RQ1A.210105.003/7825230_3167.5736:user/release-keys NVIDIA AndroidTV 1.00A_ATV SHIELD Android TV Android/11 ExoPlayer ((1.00A_ATV::1.14.1::androidtv::)", + "5a3e24b8-70cd-4958-b716-af9ce053e594", + "aazy6orsi9elhhs17e47lfb4palgszw6igf4y26z" + } + }; diff --git a/src/PVREon.cpp b/src/PVREon.cpp index d26a760..9591f85 100644 --- a/src/PVREon.cpp +++ b/src/PVREon.cpp @@ -144,13 +144,9 @@ bool CPVREon::GetPostJson(const std::string& url, const std::string& body, rapid doc.Parse(result.c_str()); if ((doc.GetParseError()) || (statusCode != 200 && statusCode != 206)) { - kodi::Log(ADDON_LOG_ERROR, "Failed to get JSON %s status code: %i", url.c_str(), statusCode); - if (!body.empty()) { - kodi::Log(ADDON_LOG_ERROR, "Body was %s", body.c_str()); - } - if (result.empty()) { - kodi::Log(ADDON_LOG_ERROR, "Empty result returned"); - } else { + kodi::Log(ADDON_LOG_ERROR, "Failed to get JSON for URL %s and body %s. Status code: %i", url.c_str(), body.c_str(), statusCode); + if (!doc.GetParseError()) + { kodi::Log(ADDON_LOG_ERROR, "Result is: %s", result.c_str()); if (doc.HasMember("error") && doc.HasMember("errorMessage")) { @@ -273,7 +269,7 @@ bool CPVREon::GetCDNInfo() const rapidjson::Value& baseApi = cdnItem["domains"]["baseApi"]; - cdn.baseApi = Utils::JsonStringOrEmpty(baseApi, EonParameters[m_params].api_selector.c_str()); + cdn.baseApi = Utils::JsonStringOrEmpty(baseApi, EonParameters[m_platform].api_selector.c_str()); m_cdns.emplace_back(cdn); } @@ -315,25 +311,25 @@ bool CPVREon::GetDeviceFromSerial() { std::string postData; - if (m_settings->GetPlatform() == PLATFORM_ANDROIDTV) { - postData = "{\"deviceName\":\"" + EonParameters[m_params].device_name + - "\",\"deviceType\":\"" + EonParameters[m_params].device_type + - "\",\"modelName\":\"" + EonParameters[m_params].device_model + - "\",\"platform\":\"" + EonParameters[m_params].device_platform + + if (m_platform == PLATFORM_ANDROIDTV) { + postData = "{\"deviceName\":\"" + EonParameters[m_platform].device_name + + "\",\"deviceType\":\"" + EonParameters[m_platform].device_type + + "\",\"modelName\":\"" + EonParameters[m_platform].device_model + + "\",\"platform\":\"" + EonParameters[m_platform].device_platform + "\",\"serial\":\"" + m_device_serial + - "\",\"clientSwVersion\":\"" + EonParameters[m_params].client_sw_version + - "\",\"clientSwBuild\":\"" + EonParameters[m_params].client_sw_build + - "\",\"systemSwVersion\":{\"name\":\"" + EonParameters[m_params].system_sw + - "\",\"version\":\"" + EonParameters[m_params].system_version + + "\",\"clientSwVersion\":\"" + EonParameters[m_platform].client_sw_version + + "\",\"clientSwBuild\":\"" + EonParameters[m_platform].client_sw_build + + "\",\"systemSwVersion\":{\"name\":\"" + EonParameters[m_platform].system_sw + + "\",\"version\":\"" + EonParameters[m_platform].system_version + "\"},\"fcmToken\":\"\"}"; //TODO: implement parameter fcmToken... } else { - postData = "{\"deviceName\":\"\",\"deviceType\":\"" + EonParameters[m_params].device_type + - "\",\"modelName\":\"" + EonParameters[m_params].device_model + - "\",\"platform\":\"" + EonParameters[m_params].device_platform + + postData = "{\"deviceName\":\"\",\"deviceType\":\"" + EonParameters[m_platform].device_type + + "\",\"modelName\":\"" + EonParameters[m_platform].device_model + + "\",\"platform\":\"" + EonParameters[m_platform].device_platform + "\",\"serial\":\"" + m_device_serial + - "\",\"clientSwVersion\":\"\",\"systemSwVersion\":{\"name\":\"" + EonParameters[m_params].system_sw + - "\",\"version\":\"" + EonParameters[m_params].system_version + "\"}}"; + "\",\"clientSwVersion\":\"\",\"systemSwVersion\":{\"name\":\"" + EonParameters[m_platform].system_sw + + "\",\"version\":\"" + EonParameters[m_platform].system_version + "\"}}"; } std::string url = m_api + "v1/devices"; @@ -523,7 +519,7 @@ CPVREon::CPVREon() : m_settings->Load(); m_httpClient = new HttpClient(m_settings); - m_params = m_settings->GetPlatform(); + m_platform = m_settings->GetPlatform(); m_support_web = "API_NOT_SET_YET"; m_httpClient->SetSupportApi(m_support_web); @@ -533,11 +529,11 @@ CPVREon::CPVREon() : std::string cdn_identifier = GetBrandIdentifier(); kodi::Log(ADDON_LOG_DEBUG, "CDN Identifier: %s", cdn_identifier.c_str()); std::string baseApi = GetBaseApi(cdn_identifier); - m_api = "https://api-" + EonParameters[m_params].api_prefix + "." + baseApi + "/"; - m_images_api = "https://images-" + EonParameters[m_params].api_prefix + "." + baseApi + "/"; + m_api = "https://api-" + EonParameters[m_platform].api_prefix + "." + baseApi + "/"; + m_images_api = "https://images-" + EonParameters[m_platform].api_prefix + "." + baseApi + "/"; } else { - m_api = "https://api-" + EonParameters[m_params].api_prefix + "." + GLOBAL_URL; - m_images_api = "https://images-" + EonParameters[m_params].api_prefix + "." + GLOBAL_URL; + m_api = "https://api-" + EonParameters[m_platform].api_prefix + "." + GLOBAL_URL; + m_images_api = "https://images-" + EonParameters[m_platform].api_prefix + "." + GLOBAL_URL; } m_httpClient->SetApi(m_api); kodi::Log(ADDON_LOG_DEBUG, "API set to: %s", m_api.c_str()); @@ -768,14 +764,13 @@ bool CPVREon::HandleSession(bool start, int cid, int epg_id) void CPVREon::SetStreamProperties(std::vector& properties, const std::string& url, - const bool& realtime, const bool& playTimeshiftBuffer, const bool& isLive, - const int& starttime, const int& endtime) + const bool& realtime, const bool& playTimeshiftBuffer, const bool& isLive/*, + time_t starttime, time_t endtime*/) { kodi::Log(ADDON_LOG_DEBUG, "[PLAY STREAM] url: %s", url.c_str()); properties.emplace_back(PVR_STREAM_PROPERTY_STREAMURL, url); properties.emplace_back(PVR_STREAM_PROPERTY_ISREALTIMESTREAM, realtime ? "true" : "false"); - properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/x-mpegURL"); int inputstream = m_settings->GetInputstream(); @@ -791,8 +786,11 @@ void CPVREon::SetStreamProperties(std::vector& p properties.emplace_back("inputstream.adaptive.manifest_type", "hls"); // properties.emplace_back("inputstream.adaptive.original_audio_language", "bs"); // properties.emplace_back("inputstream.adaptive.stream_selection_type", "adaptive"); - properties.emplace_back("inputstream.adaptive.stream_selection_type", "manual-osd"); - properties.emplace_back("inputstream.adaptive.manifest_headers", "User-Agent=" + EonParameters[m_params].user_agent); + // properties.emplace_back("inputstream.adaptive.stream_selection_type", "manual-osd"); + properties.emplace_back("inputstream.adaptive.stream_selection_type", "fixed-res"); + properties.emplace_back("inputstream.adaptive.chooser_resolution_max", "4K"); + //properties.emplace_back("inputstream.adaptive.stream_selection_type", "fixed-res"); + properties.emplace_back("inputstream.adaptive.manifest_headers", "User-Agent=" + EonParameters[m_platform].user_agent); // properties.emplace_back("inputstream.adaptive.manifest_update_parameter", "full"); } else if (inputstream == INPUTSTREAM_FFMPEGDIRECT) { @@ -817,9 +815,9 @@ void CPVREon::SetStreamProperties(std::vector& p } else { kodi::Log(ADDON_LOG_DEBUG, "Unknown inputstream detected"); } + properties.emplace_back(PVR_STREAM_PROPERTY_MIMETYPE, "application/x-mpegURL"); } - PVR_ERROR CPVREon::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) { capabilities.SetSupportsEPG(true); @@ -913,10 +911,10 @@ PVR_ERROR CPVREon::GetEPGForChannel(int channelUid, tag.SetUniqueChannelId(channelUid); tag.SetTitle(Utils::JsonStringOrEmpty(epgItem,"title")); tag.SetOriginalTitle(Utils::JsonStringOrEmpty(epgItem,"originalTitle")); - int64_t starttime = Utils::JsonInt64OrZero(epgItem,"startTime") / 1000; - int64_t endtime = Utils::JsonInt64OrZero(epgItem,"endTime") / 1000; - tag.SetStartTime((int)starttime); - tag.SetEndTime((int)endtime); + time_t starttime = (time_t) (Utils::JsonInt64OrZero(epgItem,"startTime") / 1000); + time_t endtime = (time_t) (Utils::JsonInt64OrZero(epgItem,"endTime") / 1000); + tag.SetStartTime(starttime); + tag.SetEndTime(endtime); tag.SetPlot(Utils::JsonStringOrEmpty(epgItem,"shortDescription")); int seasonNumber = Utils::JsonIntOrZero(epgItem,"seasonNumber"); if (seasonNumber != 0) @@ -993,7 +991,7 @@ PVR_ERROR CPVREon::GetEPGTagStreamProperties( { if (channel.iUniqueId == tag.GetUniqueChannelId()) { - return GetStreamProperties(channel, properties, tag.GetStartTime(), tag.GetEndTime(), false); + return GetStreamProperties(channel, properties, tag.GetStartTime(), /*tag.GetEndTime(),*/ false); } } return PVR_ERROR_NO_ERROR; @@ -1049,7 +1047,7 @@ PVR_ERROR CPVREon::GetChannels(bool bRadio, kodi::addon::PVRChannelsResultSet& r } PVR_ERROR CPVREon::GetStreamProperties( - const EonChannel& channel, std::vector& properties, const int& starttime, const int& endtime, const bool& isLive) + const EonChannel& channel, std::vector& properties, time_t starttime,/* time_t endtime,*/ const bool& isLive) { kodi::Log(ADDON_LOG_DEBUG, "function call: [%s]", __FUNCTION__); std::string streaming_profile = "hp7000"; @@ -1080,7 +1078,7 @@ PVR_ERROR CPVREon::GetStreamProperties( std::string plain_aes; - if (m_settings->GetPlatform() == PLATFORM_ANDROIDTV) { + if (m_platform == PLATFORM_ANDROIDTV) { plain_aes = "channel=" + channel.publishingPoints[0].publishingPoint + ";" + "stream=" + streaming_profile + ";" + "sp=" + m_service_provider + ";" + @@ -1098,7 +1096,7 @@ PVR_ERROR CPVREon::GetStreamProperties( "session=" + m_session_id + ";" + "maxvbr=" + std::to_string(rndbitrate); if (!isLive) { - plain_aes = plain_aes + ";t=" + std::to_string(starttime) + "000;"; + plain_aes = plain_aes + ";t=" + std::to_string((int) starttime) + "000;"; } } else { plain_aes = "channel=" + channel.publishingPoints[0].publishingPoint + ";" + @@ -1113,7 +1111,7 @@ PVR_ERROR CPVREon::GetStreamProperties( "ctime=" + GetTime() + ";" + "conn=" + CONN_TYPE_BROWSER + ";"; if (!isLive) { - plain_aes = plain_aes + "t=" + std::to_string(starttime) + "000;"; + plain_aes = plain_aes + "t=" + std::to_string((int) starttime) + "000;"; } plain_aes = plain_aes + "aa=" + (channel.aaEnabled ? "true" : "false"); } @@ -1138,20 +1136,23 @@ PVR_ERROR CPVREon::GetStreamProperties( std::string enc_url = "https://" + currentServer.hostname + "/stream?i=" + urlsafeencode(base64_encode(iv_str.c_str(), iv_str.length())) + "&a=" + urlsafeencode(base64_encode(enc_str.c_str(), enc_str.length())); - if (m_settings->GetPlatform() == PLATFORM_ANDROIDTV) { + if (m_platform == PLATFORM_ANDROIDTV) { enc_url = enc_url + "&lang=eng"; } enc_url = enc_url + "&sp=" + m_service_provider + "&u=" + m_settings->GetEonStreamUser() + "&player=" + PLAYER + "&session=" + m_session_id; - if (m_settings->GetPlatform() != PLATFORM_ANDROIDTV) { + if (m_platform != PLATFORM_ANDROIDTV) { enc_url = enc_url + "&sig=" + channel.sig; } kodi::Log(ADDON_LOG_DEBUG, "Encrypted Stream URL -> %s", enc_url.c_str()); - SetStreamProperties(properties, enc_url, true, false, isLive, starttime, endtime); + SetStreamProperties(properties, enc_url, true, false, isLive/*, starttime, endtime*/); + + for (auto& prop : properties) + kodi::Log(ADDON_LOG_DEBUG, "Name: %s Value: %s", prop.GetName().c_str(), prop.GetValue().c_str()); return PVR_ERROR_NO_ERROR; } @@ -1163,7 +1164,7 @@ PVR_ERROR CPVREon::GetChannelStreamProperties( EonChannel addonChannel; if (GetChannel(channel, addonChannel)) { if (addonChannel.subscribed) { - return GetStreamProperties(addonChannel, properties, 0, 0, true); + return GetStreamProperties(addonChannel, properties, 0,/* 0,*/ true); } kodi::Log(ADDON_LOG_DEBUG, "Channel not subscribed"); return PVR_ERROR_SERVER_ERROR; @@ -1311,7 +1312,7 @@ bool CPVREon::GetServer(bool isLive, EonServer& myServer) servers = m_timeshift_servers; } int target_server = 2; - if (m_settings->GetPlatform() == PLATFORM_ANDROIDTV) { + if (m_platform == PLATFORM_ANDROIDTV) { target_server = 3; } int count = 0; diff --git a/src/PVREon.h b/src/PVREon.h index a9ab60f..10ef3d1 100644 --- a/src/PVREon.h +++ b/src/PVREon.h @@ -106,54 +106,6 @@ struct EonCDN bool isDefault; }; -struct EonParameter -{ - std::string api_prefix; - std::string api_selector; - std::string device_type; - std::string device_name; - std::string device_model; - std::string device_platform; - std::string device_mac; - std::string client_sw_version; - std::string client_sw_build; - std::string system_sw; - std::string system_version; - std::string user_agent; -}; - -EonParameter EonParameters[2] = {{ - //Web Client - "web", - "be", - "web_linux_chrome", - "", - "Chrome 116", - "web", - "", - "", - "", - "Linux", - "x86_64", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" - }, - { - //Android TV - "android-tv", - "af31", - "Android 11", - "Android TV 30", - "SHIELD Android TV", - "android_tv", - "", - "8.1.3", - "8.1.35906", - "Android", - "11", - "Mozilla/5.0 (Linux; Android 11; SHIELD Android TV Build/RQ1A.210105.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.196 Mobile Safari/537.36; XDKAndroidWebView/3.0.1/XDKWebView NVIDIA NVIDIA/mdarcy/mdarcy:11/RQ1A.210105.003/7825230_3167.5736:user/release-keys NVIDIA AndroidTV 1.00A_ATV SHIELD Android TV Android/11 ExoPlayer ((1.00A_ATV::1.14.1::androidtv::)" - } - }; - class ATTR_DLL_LOCAL CPVREon : public kodi::addon::CAddonBase, public kodi::addon::CInstancePVRClient { @@ -210,12 +162,12 @@ class ATTR_DLL_LOCAL CPVREon : public kodi::addon::CAddonBase, void SetStreamProperties(std::vector& properties, const std::string& url, - const bool& realtime, const bool& playTimeshiftBuffer, const bool& isLive, - const int& starttime, const int& endtime); + const bool& realtime, const bool& playTimeshiftBuffer, const bool& isLive /*, + time_t starttime, time_t endtime*/); PVR_ERROR GetStreamProperties( const EonChannel& channel, - std::vector& properties, const int& starttime, const int& endtime, const bool& isLive); + std::vector& properties, time_t starttime,/* time_t endtime, */const bool& isLive); std::vector m_channels; std::vector m_live_servers; @@ -246,7 +198,7 @@ class ATTR_DLL_LOCAL CPVREon : public kodi::addon::CAddonBase, std::string m_api; std::string m_images_api; - int m_params; + int m_platform; // std::string m_ss_refresh; // int m_active_profile_id; diff --git a/src/http/HttpClient.cpp b/src/http/HttpClient.cpp index b62331d..03a1580 100644 --- a/src/http/HttpClient.cpp +++ b/src/http/HttpClient.cpp @@ -27,7 +27,7 @@ bool HttpClient::RefreshGenericToken() std::string url = BROKER_URL + "oauth/token?grant_type=client_credentials"; std::string postData = "{}"; - std::string basic_token = client_id + ":" + client_secret; + std::string basic_token = EonParameters[m_platform].client_id + ":" + EonParameters[m_platform].client_secret; // Copy input data to a buffer that will be encrypted // Botan::secure_vector bt(basic_token.data(), basic_token.data() + basic_token.length()); // std::string test1 = base64_encode(basic_token.c_str(), basic_token.length()); @@ -187,7 +187,7 @@ bool HttpClient::RefreshToken() int statusCode; - std::string basic_token = client_id + ":" + client_secret; + std::string basic_token = EonParameters[m_platform].client_id + ":" + EonParameters[m_platform].client_secret; curl_auth.AddHeader("Authorization", "Basic " + base64_encode(basic_token.c_str(), basic_token.length())); std::string content_auth = HttpRequestToCurl(curl_auth, "POST", url, postData, statusCode); @@ -222,6 +222,8 @@ bool HttpClient::RefreshToken() HttpClient::HttpClient(CSettings* settings): m_settings(settings) { + m_platform = m_settings->GetPlatform(); + /* if (m_settings->GetPlatform() == 1) { client_id = CLIENT_ID_ATV; client_secret = CLIENT_SECRET_ATV; @@ -229,6 +231,7 @@ HttpClient::HttpClient(CSettings* settings): client_id = CLIENT_ID_WEB; client_secret = CLIENT_SECRET_WEB; } + */ } HttpClient::~HttpClient() @@ -331,7 +334,7 @@ std::string HttpClient::HttpRequest(const std::string& action, const std::string if (!access_token.empty()) { curl.AddHeader("Authorization", "bearer " + access_token); } else { - std::string basic_token = client_id + ":" + client_secret; + std::string basic_token = EonParameters[m_platform].client_id + ":" + EonParameters[m_platform].client_secret; curl.AddHeader("Authorization", "Basic " + base64_encode(basic_token.c_str(), basic_token.length())); } } diff --git a/src/http/HttpClient.h b/src/http/HttpClient.h index 7436247..8139a64 100644 --- a/src/http/HttpClient.h +++ b/src/http/HttpClient.h @@ -33,8 +33,11 @@ class HttpClient std::string m_uuid; std::string m_api; std::string m_supportApi; + int m_platform; + /* std::string client_id; std::string client_secret; + */ CSettings* m_settings; HttpStatusCodeHandler *m_statusCodeHandler = nullptr; };