diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/appveyor.yml kodi-pvr-sledovanitv-cz-4.4.0/appveyor.yml --- kodi-pvr-sledovanitv-cz-1.9.0/appveyor.yml 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/appveyor.yml 2021-01-09 22:45:25.000000000 +0000 @@ -1,6 +1,6 @@ version: BuildNr.{build} -image: Visual Studio 2015 +image: Visual Studio 2017 shallow_clone: true @@ -10,20 +10,20 @@ app_id: pvr.sledovanitv.cz matrix: - - GENERATOR: "Visual Studio 14" + - GENERATOR: "Visual Studio 15" CONFIG: Release - - GENERATOR: "Visual Studio 14 Win64" + - GENERATOR: "Visual Studio 15 Win64" CONFIG: Release - - GENERATOR: "Visual Studio 14 Win64" + - GENERATOR: "Visual Studio 15 Win64" CONFIG: Release - WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.16299.0" - - GENERATOR: "Visual Studio 14 ARM" + WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" + - GENERATOR: "Visual Studio 15 ARM" CONFIG: Release - WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.16299.0" + WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.17763.0" build_script: - cd .. - - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git + - git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git - cd %app_id% - mkdir build - cd build diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/CMakeLists.txt kodi-pvr-sledovanitv-cz-4.4.0/CMakeLists.txt --- kodi-pvr-sledovanitv-cz-1.9.0/CMakeLists.txt 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/CMakeLists.txt 2021-01-09 22:45:25.000000000 +0000 @@ -8,20 +8,15 @@ include_directories(${KODI_INCLUDE_DIR}/.. # Hack way with "/..", need bigger Kodi cmake rework to match right include ways ${JSONCPP_INCLUDE_DIRS}) -# workaround for windows & unneeded including of p8-platform/windows/dlfcn-win32.h from libXBMC_addon.h -if(WIN32) - find_package(p8-platform REQUIRED) - include_directories(${p8-platform_INCLUDE_DIRS}) -endif() set(DEPLIBS ${JSONCPP_LIBRARIES}) -set(SLEDOVANITV_SOURCES src/client.cpp +set(SLEDOVANITV_SOURCES src/ApiManager.cpp src/Data.cpp) -set(SLEDOVANITV_HEADERS src/client.h +set(SLEDOVANITV_HEADERS src/ApiManager.h src/CallLimiter.hh src/Data.h) @@ -31,7 +26,7 @@ endif() build_addon(pvr.sledovanitv.cz SLEDOVANITV DEPLIBS) -set_property(TARGET pvr.sledovanitv.cz PROPERTY CXX_STANDARD 11) +set_property(TARGET pvr.sledovanitv.cz PROPERTY CXX_STANDARD 14) set_property(TARGET pvr.sledovanitv.cz PROPERTY CXX_STANDARD_REQUIRED ON) include(CPack) diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/debian/changelog kodi-pvr-sledovanitv-cz-4.4.0/debian/changelog --- kodi-pvr-sledovanitv-cz-1.9.0/debian/changelog 2013-05-31 22:59:22.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/debian/changelog 2013-05-31 22:59:22.000000000 +0000 @@ -1,4 +1,4 @@ -kodi-pvr-sledovanitv-cz (1.9.0-1~focal) focal; urgency=low +kodi-pvr-sledovanitv-cz (4.4.0-1~focal) focal; urgency=low [ kodi ] * autogenerated dummy changelog diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/debian/compat kodi-pvr-sledovanitv-cz-4.4.0/debian/compat --- kodi-pvr-sledovanitv-cz-1.9.0/debian/compat 2013-05-31 22:59:22.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/debian/compat 2013-05-31 22:59:22.000000000 +0000 @@ -1 +1 @@ -8 +9 diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/debian/control kodi-pvr-sledovanitv-cz-4.4.0/debian/control --- kodi-pvr-sledovanitv-cz-1.9.0/debian/control 2013-05-31 22:59:22.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/debian/control 2013-05-31 22:59:22.000000000 +0000 @@ -3,7 +3,7 @@ Maintainer: Nobody Build-Depends: debhelper (>= 9.0.0), cmake, kodi-addon-dev, libjsoncpp-dev -Standards-Version: 3.9.5 +Standards-Version: 4.1.2 Section: libs Package: kodi-pvr-sledovanitv-cz diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/debian/kodi-pvr-hdhomerun.install kodi-pvr-sledovanitv-cz-4.4.0/debian/kodi-pvr-hdhomerun.install --- kodi-pvr-sledovanitv-cz-1.9.0/debian/kodi-pvr-hdhomerun.install 2013-05-31 22:59:22.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/debian/kodi-pvr-hdhomerun.install 2013-05-31 22:59:22.000000000 +0000 @@ -1,2 +1,2 @@ -usr/lib/*/addons/pvr.sledovanitv.cz/pvr.sledovanitv.cz.so* usr/lib/kodi/addons/pvr.sledovanitv.cz -usr/share/kodi/addons/pvr.sledovanitv.cz +usr/lib/* +usr/share/* diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/Jenkinsfile kodi-pvr-sledovanitv-cz-4.4.0/Jenkinsfile --- kodi-pvr-sledovanitv-cz-1.9.0/Jenkinsfile 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/Jenkinsfile 2021-01-09 22:45:25.000000000 +0000 @@ -1 +1 @@ -buildPlugin(version: "Leia") +buildPlugin(version: "Matrix") diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/pvr.sledovanitv.cz/addon.xml.in kodi-pvr-sledovanitv-cz-4.4.0/pvr.sledovanitv.cz/addon.xml.in --- kodi-pvr-sledovanitv-cz-1.9.0/pvr.sledovanitv.cz/addon.xml.in 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/pvr.sledovanitv.cz/addon.xml.in 2021-01-09 22:45:25.000000000 +0000 @@ -1,23 +1,25 @@ - @ADDON_DEPENDS@ + @ADDON_DEPENDS@ + + - Kodi's frontend for sledovanitv.cz, unofficial - Kodi frontend pro sledovanitv.cz, neoficiální - Kodi frontend pre sledovanitv.cz, neoficiálny - PVR Client for sledovanitv.cz. Supports stream of live TV/Radio, recordings and EPG. This client is not developed nor officially supported by sledovanitv.cz. - PVR klient pro službu sledovanitv.cz. Podporuje živé vysílání TV/rádia, nahrávky a EPG. Tento klient není vyvíjen ani oficiálne podporován ze strany sledovanitv.cz. - PVR klient pre službu sledovanitv.cz. Podporuje živé vysielanie TV/rádia, nahrávky a EPG. Tento klient nie je vyvíjaný ani oficiálne podporovaný zo strany sledovanitv.cz. - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. The authors are in no way responsible for failed playings, incorrect EPG times, wasted hours, or any other undesirable effects. - Tento program je rozšiřován v naději, že bude užitečný, avšak BEZ JAKÉKOLIV ZÁRUKY. Autoři nejsou žádným způsobem zodpovědní za selhání při nahrávání, neplatné časovače, ztracený čas, či jakékoliv jiné nežádoucí události... - Tento program je rozširovaný v nádeji, že bude užitočný, avšak BEZ AKEJKOĽVEK ZÁRUKY. Autori žiadnym spôsobom nenesú zodpovednosť za zlyhanie pri nahrávaní, neplatné časovače, stratený čas, či akékoľvek iné nežiadúce dopady... + Kodi's frontend for sledovanitv.cz, unofficial + Kodi frontend pro sledovanitv.cz, neoficiální + Kodi frontend pre sledovanitv.cz, neoficiálny + PVR Client for sledovanitv.cz. Supports stream of live TV/Radio, recordings and EPG. This client is not developed nor officially supported by sledovanitv.cz. + PVR klient pro službu sledovanitv.cz. Podporuje živé vysílání TV/rádia, nahrávky a EPG. Tento klient není vyvíjen ani oficiálne podporován ze strany sledovanitv.cz. + PVR klient pre službu sledovanitv.cz. Podporuje živé vysielanie TV/rádia, nahrávky a EPG. Tento klient nie je vyvíjaný ani oficiálne podporovaný zo strany sledovanitv.cz. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. The authors are in no way responsible for failed playings, incorrect EPG times, wasted hours, or any other undesirable effects. + Tento program je rozšiřován v naději, že bude užitečný, avšak BEZ JAKÉKOLIV ZÁRUKY. Autoři nejsou žádným způsobem zodpovědní za selhání při nahrávání, neplatné časovače, ztracený čas, či jakékoliv jiné nežádoucí události... + Tento program je rozširovaný v nádeji, že bude užitočný, avšak BEZ AKEJKOĽVEK ZÁRUKY. Autori žiadnym spôsobom nenesú zodpovednosť za zlyhanie pri nahrávaní, neplatné časovače, stratený čas, či akékoľvek iné nežiadúce dopady... @PLATFORM@ resources/logo.png diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/README.md kodi-pvr-sledovanitv-cz-4.4.0/README.md --- kodi-pvr-sledovanitv-cz-1.9.0/README.md 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/README.md 2021-01-09 22:45:25.000000000 +0000 @@ -2,15 +2,15 @@ [![Build status](https://ci.appveyor.com/api/projects/status/02qaoie8tcv4klnf/branch/master?svg=true)](https://ci.appveyor.com/project/palinek/pvr-sledovanitv-cz/branch/master) # sledovanitv.cz PVR -unofficial [sledovanitv.cz](https://sledovanitv.cz) PVR client addon for [Kodi](http://kodi.tv) +unofficial [sledovanitv.cz](https://sledovanitv.cz) PVR client addon for [Kodi](https://kodi.tv) (this client is not developed nor officially supported by sledovanitv.cz) ## Build instructions ### Linux -1. `git clone --branch Leia https://github.com/xbmc/xbmc.git` -2. `git clone --branch Leia https://github.com/palinek/pvr.sledovanitv.cz.git` +1. `git clone --branch master https://github.com/xbmc/xbmc.git` +2. `git clone https://github.com/palinek/pvr.sledovanitv.cz.git` 3. `cd pvr.sledovanitv.cz && mkdir build && cd build` 4. `cmake -DADDONS_TO_BUILD=pvr.sledovanitv.cz -DADDON_SRC_PREFIX=../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=xbmc/addons -DPACKAGE_ZIP=1 -DADDONS_DEFINITION_DIR="$(pwd)/../xbmc/cmake/addons/addons" ../../xbmc/cmake/addons` 5. `make` @@ -18,5 +18,5 @@ ##### Useful links -* [Kodi's PVR user support] (http://forum.kodi.tv/forumdisplay.php?fid=167) -* [Kodi's PVR development support] (http://forum.kodi.tv/forumdisplay.php?fid=136) +* [Kodi's PVR user support](https://forum.kodi.tv/forumdisplay.php?fid=167) +* [Kodi's PVR development support](https://forum.kodi.tv/forumdisplay.php?fid=136) diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/src/ApiManager.cpp kodi-pvr-sledovanitv-cz-4.4.0/src/ApiManager.cpp --- kodi-pvr-sledovanitv-cz-1.9.0/src/ApiManager.cpp 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/src/ApiManager.cpp 2021-01-09 22:45:25.000000000 +0000 @@ -51,9 +51,10 @@ #include #include -#include "client.h" #include "ApiManager.h" #include "picosha2.h" +#include "kodi/General.h" +#include "kodi/Filesystem.h" #include #include #include @@ -107,13 +108,13 @@ { std::string mac_addr; #if defined(TARGET_ANDROID) && __ANDROID_API__ < 24 - XBMC->Log(ADDON::LOG_NOTICE, "Can't get MAC address with target Android API < 24 (no getifaddrs() support)"); + kodi::Log(ADDON_LOG_INFO, "Can't get MAC address with target Android API < 24 (no getifaddrs() support)"); #endif #if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) || defined(TARGET_DARWIN) struct ifaddrs * addrs; if (0 != getifaddrs(&addrs)) { - XBMC->Log(ADDON::LOG_NOTICE, "While getting MAC address getifaddrs() failed, %s", strerror(errno)); + kodi::Log(ADDON_LOG_INFO, "While getting MAC address getifaddrs() failed, %s", strerror(errno)); return mac_addr; } std::unique_ptr if_addrs{addrs, &freeifaddrs}; @@ -169,7 +170,7 @@ } } else { - XBMC->Log(ADDON::LOG_NOTICE, "GetAdaptersAddresses failed..."); + kodi::Log(ADDON_LOG_INFO, "GetAdaptersAddresses failed..."); } #endif return mac_addr; @@ -193,7 +194,7 @@ , m_pinUnlocked{false} , m_sessionId{std::make_shared()} { - XBMC->Log(ADDON::LOG_NOTICE, "Loading ApiManager"); + kodi::Log(ADDON_LOG_INFO, "Loading ApiManager"); } std::string ApiManager::call(const std::string & urlPath, const ApiParams_t & paramsMap, bool putSessionVar) const @@ -212,17 +213,16 @@ url += "|User-Agent=okhttp%2F3.12.0"; std::string response; - void *fh = XBMC->OpenFile(url.c_str(), XFILE::READ_NO_CACHE); - if (fh) + kodi::vfs::CFile fh; + if (fh.OpenFile(url, ADDON_READ_NO_CACHE)) { char buffer[1024]; - while (int bytesRead = XBMC->ReadFile(fh, buffer, 1024)) + while (int bytesRead = fh.Read(buffer, 1024)) response.append(buffer, bytesRead); - XBMC->CloseFile(fh); } else { - XBMC->Log(ADDON::LOG_ERROR, "Cannot open url"); + kodi::Log(ADDON_LOG_ERROR, "Cannot open url"); } return response; @@ -245,11 +245,11 @@ { bool success = root.get("status", 0).asInt() == 1; if (!success) - XBMC->Log(ADDON::LOG_ERROR, "Error indicated in response. status: %d, error: %s", root.get("status", 0).asInt(), root.get("error", "").asString().c_str()); + kodi::Log(ADDON_LOG_ERROR, "Error indicated in response. status: %d, error: %s", root.get("status", 0).asInt(), root.get("error", "").asString().c_str()); return success; } - XBMC->Log(ADDON::LOG_ERROR, "Error parsing response. Response is: %*s, reader error: %s", std::min(response.size(), static_cast(1024)), response.c_str(), jsonReaderError.c_str()); + kodi::Log(ADDON_LOG_ERROR, "Error parsing response. Response is: %*s, reader error: %s", std::min(response.size(), static_cast(1024)), response.c_str(), jsonReaderError.c_str()); return false; } @@ -277,7 +277,7 @@ || (del_root.get("error", "").asString() == "no device") ) { - XBMC->Log(ADDON::LOG_NOTICE, "Previous pairing(deviceId:%s) deleted (or no such device)", old_dev_id.c_str()); + kodi::Log(ADDON_LOG_INFO, "Previous pairing(deviceId:%s) deleted (or no such device)", old_dev_id.c_str()); return true; } @@ -292,7 +292,7 @@ std::string macAddr = m_overridenMac.empty() ? get_mac_address() : m_overridenMac; if (macAddr.empty()) { - XBMC->Log(ADDON::LOG_NOTICE, "Unable to get MAC address, using a dummy for serial"); + kodi::Log(ADDON_LOG_INFO, "Unable to get MAC address, using a dummy for serial"); macAddr = "11223344"; } // compute SHA256 of string representation of MAC address @@ -340,7 +340,7 @@ m_deviceId = buf; m_password = passwd; - XBMC->Log(ADDON::LOG_DEBUG, "Device ID: %d, Password: %s", devId, passwd.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "Device ID: %d, Password: %s", devId, passwd.c_str()); const bool paired = !m_deviceId.empty() && !m_password.empty(); @@ -355,7 +355,7 @@ } else { - XBMC->Log(ADDON::LOG_ERROR, "Error in pairing response."); + kodi::Log(ADDON_LOG_ERROR, "Error in pairing response."); } return false; @@ -369,7 +369,7 @@ { if (!pairDevice(pairing_root)) { - XBMC->Log(ADDON::LOG_ERROR, "Cannot pair device"); + kodi::Log(ADDON_LOG_ERROR, "Cannot pair device"); return false; } } @@ -391,14 +391,14 @@ if (new_session_id.empty()) { - XBMC->Log(ADDON::LOG_ERROR, "Cannot perform device login"); + kodi::Log(ADDON_LOG_ERROR, "Cannot perform device login"); } else { - XBMC->Log(ADDON::LOG_NOTICE, "Device logged in. Session ID: %s", new_session_id.c_str()); + kodi::Log(ADDON_LOG_INFO, "Device logged in. Session ID: %s", new_session_id.c_str()); } } else if (response.empty()) { - XBMC->Log(ADDON::LOG_NOTICE, "No login response. Is something wrong with network or remote servers?"); + kodi::Log(ADDON_LOG_INFO, "No login response. Is something wrong with network or remote servers?"); // don't do anything, let the state as is to give it another try return false; } @@ -559,7 +559,7 @@ std::string ApiManager::buildQueryString(const ApiParams_t & paramMap, bool putSessionVar) const { - XBMC->Log(ADDON::LOG_DEBUG, "%s - size %d", __FUNCTION__, paramMap.size()); + kodi::Log(ADDON_LOG_DEBUG, "%s - size %d", __FUNCTION__, paramMap.size()); std::string strOut; for (const auto & param : paramMap) { @@ -583,18 +583,17 @@ std::string ApiManager::readPairFile() { - std::string url = GetUserFilePath(PAIR_FILE); + std::string url = kodi::GetBaseUserPath(PAIR_FILE); std::string strContent; - XBMC->Log(ADDON::LOG_DEBUG, "Openning file %s", url.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "Openning file %s", url.c_str()); - void* fileHandle = XBMC->OpenFile(url.c_str(), 0); - if (fileHandle) + kodi::vfs::CFile fileHandle; + if (fileHandle.OpenFile(url, 0)) { char buffer[1024]; - while (int bytesRead = XBMC->ReadFile(fileHandle, buffer, 1024)) + while (int bytesRead = fileHandle.Read(buffer, 1024)) strContent.append(buffer, bytesRead); - XBMC->CloseFile(fileHandle); } return strContent; @@ -602,16 +601,15 @@ void ApiManager::createPairFile(Json::Value & contentRoot) { - std::string url = GetUserFilePath(PAIR_FILE); + std::string url = kodi::GetBaseUserPath(PAIR_FILE); - void *fileHandle = XBMC->OpenFileForWrite(url.c_str(), true); - if (fileHandle) + kodi::vfs::CFile fileHandle; + if (fileHandle.OpenFileForWrite(url, true)) { std::ostringstream os; os << contentRoot; const std::string & content = os.str(); - XBMC->WriteFile(fileHandle, content.c_str(), content.length()); - XBMC->CloseFile(fileHandle); + fileHandle.Write(content.c_str(), content.length()); } } diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/src/ApiManager.h kodi-pvr-sledovanitv-cz-4.4.0/src/ApiManager.h --- kodi-pvr-sledovanitv-cz-1.9.0/src/ApiManager.h 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/src/ApiManager.h 2021-01-09 22:45:25.000000000 +0000 @@ -56,8 +56,9 @@ public: ApiManager(const std::string & userName , const std::string & userPassword - , const std::string & overridenMac - , const std::string & product); + , const std::string & overridenMac //!< device identifier (value for overriding the MAC address detection) + , const std::string & product //!< product identifier (value for overriding the hostname detection) + ); bool login(); bool pinUnlock(const std::string & pin); diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/src/client.cpp kodi-pvr-sledovanitv-cz-4.4.0/src/client.cpp --- kodi-pvr-sledovanitv-cz-1.9.0/src/client.cpp 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/src/client.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,662 +0,0 @@ -/* - * Copyright (c) 2018~now Palo Kisa - * - * Copyright (C) 2013 Anton Fedchin - * http://github.com/afedchin/xbmc-addon-iptvsimple/ - * - * Copyright (C) 2011 Pulse-Eight - * http://www.pulse-eight.com/ - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this addon; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "client.h" - -#include "Data.h" -#include "kodi/xbmc_pvr_dll.h" - -#include -#include - -using namespace ADDON; - -#ifdef TARGET_WINDOWS -#define snprintf _snprintf -#ifdef CreateDirectory -#undef CreateDirectory -#endif -#ifdef DeleteFile -#undef DeleteFile -#endif -#endif - - -ADDON_STATUS m_CurStatus = ADDON_STATUS_UNKNOWN; -static std::shared_ptr m_data; - -/* User adjustable settings are saved here. - * Default values are defined inside client.h - * and exported to the other source files. - */ -static std::string g_strUserPath = ""; -static std::string g_strClientPath = ""; -static int g_iEpgMaxDays = 0; - -std::unique_ptr XBMC; -std::unique_ptr PVR; -std::unique_ptr GUI; - -std::string PathCombine(const std::string &strPath, const std::string &strFileName) -{ - std::string strResult = strPath; - if (strResult.at(strResult.size() - 1) == '\\' || - strResult.at(strResult.size() - 1) == '/') - { - strResult.append(strFileName); - } - else - { - strResult.append("/"); - strResult.append(strFileName); - } - - return strResult; -} - -std::string GetClientFilePath(const std::string &strFileName) -{ - return PathCombine(g_strClientPath, strFileName); -} - -std::string GetUserFilePath(const std::string &strFileName) -{ - return PathCombine(g_strUserPath, strFileName); -} - -static void ReadSettings(sledovanitvcz::Configuration & cfg) -{ - char buffer[1024]; - - if (XBMC->GetSetting("userName", &buffer)) - { - cfg.userName = buffer; - } - - if (XBMC->GetSetting("password", &buffer)) - { - cfg.password = buffer; - } - - if (XBMC->GetSetting("deviceId", &buffer)) - { - cfg.deviceId = buffer; - } - - if (XBMC->GetSetting("productId", &buffer)) - { - cfg.productId = buffer; - } - - if (!XBMC->GetSetting("streamQuality", &cfg.streamQuality)) - { - cfg.streamQuality = 0; - } - - if (!XBMC->GetSetting("fullChannelEpgRefresh", &cfg.fullChannelEpgRefresh)) - { - cfg.fullChannelEpgRefresh = 24; - } - // make it seconds - cfg.fullChannelEpgRefresh *= 3600; - - if (!XBMC->GetSetting("loadingsRefresh", &cfg.loadingsRefresh)) - { - cfg.loadingsRefresh = 60; - } - - if (!XBMC->GetSetting("keepAliveDelay", &cfg.keepAliveDelay)) - { - cfg.loadingsRefresh = 20; - } - - if (!XBMC->GetSetting("epgCheckDelay", &cfg.epgCheckDelay)) - { - cfg.epgCheckDelay = 1; - } - // make it seconds - cfg.epgCheckDelay *= 60; - - if (!XBMC->GetSetting("useH265", &cfg.useH265)) - { - cfg.useH265 = false; - } - - if (!XBMC->GetSetting("useAdaptive", &cfg.useAdaptive)) - { - cfg.useAdaptive = false; - } - - if (!XBMC->GetSetting("showLockedChannels", &cfg.showLockedChannels)) - { - cfg.showLockedChannels = true; - } - - if (!XBMC->GetSetting("showLockedOnlyPin", &cfg.showLockedOnlyPin)) - { - cfg.showLockedOnlyPin = true; - } -} - -static PVR_ERROR FillStreamProperties(const sledovanitvcz::properties_t & props, PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount) -{ - if (*iPropertiesCount < props.size()) - return PVR_ERROR_INVALID_PARAMETERS; - - unsigned i = 0; - for (const auto & prop : props) - { - XBMC->Log(LOG_DEBUG, "%s properties[%s]=%s", __FUNCTION__, prop.first.c_str(), prop.second.c_str()); - strncpy(properties[i].strName, prop.first.c_str(), sizeof(properties[i].strName) - 1); - strncpy(properties[i].strValue, prop.second.c_str(), sizeof(properties[i].strValue) - 1); - ++i; - } - *iPropertiesCount = i; - - return PVR_ERROR_NO_ERROR; -} - -extern "C" { - -ADDON_STATUS ADDON_Create(void* hdl, void* props) -{ - if (!hdl || !props) - { - return ADDON_STATUS_UNKNOWN; - } - - PVR_PROPERTIES* pvrprops = (PVR_PROPERTIES*)props; - - XBMC.reset(new CHelper_libXBMC_addon); - if (!XBMC->RegisterMe(hdl)) - { - XBMC.reset(nullptr); - return ADDON_STATUS_PERMANENT_FAILURE; - } - - PVR.reset(new CHelper_libXBMC_pvr); - if (!PVR->RegisterMe(hdl)) - { - PVR.reset(nullptr); - XBMC.reset(nullptr); - return ADDON_STATUS_PERMANENT_FAILURE; - } - - GUI.reset(new CHelper_libKODI_guilib); - if (!GUI->RegisterMe(hdl)) - { - GUI.reset(nullptr); - return ADDON_STATUS_PERMANENT_FAILURE; - } - - XBMC->Log(LOG_DEBUG, "%s - Creating the %s", __FUNCTION__, GetBackendName()); - - m_CurStatus = ADDON_STATUS_UNKNOWN; - g_strUserPath = pvrprops->strUserPath; - g_strClientPath = pvrprops->strClientPath; - - if (!XBMC->DirectoryExists(g_strUserPath.c_str())) - { - XBMC->CreateDirectory(g_strUserPath.c_str()); - } - - sledovanitvcz::Configuration cfg; - ReadSettings(cfg); - cfg.epgMaxDays = pvrprops->iEpgMaxDays; - - std::atomic_store(&m_data, std::shared_ptr{nullptr}); // be sure that the previous one is deleted before new is constructed - std::atomic_store(&m_data, std::make_shared(std::move(cfg))); - m_CurStatus = ADDON_STATUS_OK; - - return m_CurStatus; -} - -ADDON_STATUS ADDON_GetStatus() -{ - return m_CurStatus; -} - -void ADDON_Destroy() -{ - std::atomic_store(&m_data, std::shared_ptr{nullptr}); - m_CurStatus = ADDON_STATUS_UNKNOWN; -} - -ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue) -{ - // just force our data to be re-created - return ADDON_STATUS_NEED_RESTART; -} - -void ADDON_Announce(const char *flag, const char *sender, const char *message, const void *data) -{ -} - -/*********************************************************** - * PVR Client AddOn specific public library functions - ***********************************************************/ -PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities) -{ - XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); - pCapabilities->bSupportsEPG = true; - pCapabilities->bSupportsTV = true; - pCapabilities->bSupportsRadio = true; - pCapabilities->bSupportsRecordings = true; - pCapabilities->bSupportsRecordingsUndelete = false; - pCapabilities->bSupportsTimers = true; - pCapabilities->bSupportsChannelGroups = true; - pCapabilities->bSupportsChannelScan = false; - pCapabilities->bSupportsChannelSettings = false; - pCapabilities->bHandlesInputStream = false; - pCapabilities->bHandlesDemuxing = false; - pCapabilities->bSupportsRecordingPlayCount = false; - pCapabilities->bSupportsLastPlayedPosition = false; - pCapabilities->bSupportsRecordingEdl = false; - pCapabilities->bSupportsRecordingsRename = false; - pCapabilities->bSupportsRecordingsLifetimeChange = false; - pCapabilities->bSupportsDescrambleInfo = false; - pCapabilities->iRecordingsLifetimesSize = 0; - - return PVR_ERROR_NO_ERROR; -} - -const char *GetBackendName(void) -{ - static const char *strBackendName = "PVR sledovanitv.cz (unofficial)"; - return strBackendName; -} - -const char *GetBackendVersion(void) -{ - static std::string strBackendVersion = ""; - return strBackendVersion.c_str(); -} - -const char *GetConnectionString(void) -{ - static std::string strConnectionString = "connected"; - return strConnectionString.c_str(); -} - -PVR_ERROR GetDriveSpace(long long *iTotal, long long *iUsed) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetDriveSpace(iTotal, iUsed); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetEPGForChannel(handle, channel, iStart, iEnd); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR SetEPGTimeFrame(int iDays) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->SetEPGTimeFrame(iDays); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR IsEPGTagPlayable(const EPG_TAG* tag, bool* bIsPlayable) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->IsEPGTagPlayable(tag, bIsPlayable); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR IsEPGTagRecordable(const EPG_TAG* tag, bool* bIsRecordable) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->IsEPGTagRecordable(tag, bIsRecordable); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR GetEPGTagStreamProperties(const EPG_TAG* tag, PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount) -{ - auto data = std::atomic_load(&m_data); - if (!tag || !properties || !iPropertiesCount || !data) - return PVR_ERROR_SERVER_ERROR; - - std::string stream_url, stream_type; - PVR_ERROR ret = data->GetEPGStreamUrl(tag, stream_url, stream_type); - if (PVR_ERROR_NO_ERROR != ret) - return ret; - - return FillStreamProperties(data->StreamProperties(stream_url, stream_type, false), properties, iPropertiesCount); -} - -int GetChannelsAmount(void) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetChannelsAmount(); - - return -1; -} - -PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetChannels(handle, bRadio); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR GetChannelStreamProperties(const PVR_CHANNEL* channel, PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount) -{ - auto data = std::atomic_load(&m_data); - if (!channel || !properties || !iPropertiesCount || !data) - return PVR_ERROR_SERVER_ERROR; - - std::string stream_url, stream_type; - PVR_ERROR ret = data->GetChannelStreamUrl(channel, stream_url, stream_type); - if (PVR_ERROR_NO_ERROR != ret) - return ret; - - return FillStreamProperties(data->StreamProperties(stream_url, stream_type, true), properties, iPropertiesCount); -} - -int GetChannelGroupsAmount(void) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetChannelGroupsAmount(); - - return -1; -} - -PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetChannelGroups(handle, bRadio); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetChannelGroupMembers(handle, group); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS &signalStatus) -{ - snprintf(signalStatus.strAdapterName, sizeof(signalStatus.strAdapterName), "sledovanitv.cz"); - snprintf(signalStatus.strAdapterStatus, sizeof(signalStatus.strAdapterStatus), "OK"); - - return PVR_ERROR_NO_ERROR; -} - -int GetRecordingsAmount(bool deleted) -{ - XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); - if (deleted) - return 0; - - auto data = std::atomic_load(&m_data); - if (data) - return data->GetRecordingsAmount(); - - return 0; -} - -PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted) -{ - XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); - if (deleted) - return PVR_ERROR_NO_ERROR; - - auto data = std::atomic_load(&m_data); - if (data) - return data->GetRecordings(handle); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR GetRecordingStreamProperties(const PVR_RECORDING* recording, PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount) -{ - auto data = std::atomic_load(&m_data); - if (!recording || !properties || !iPropertiesCount || !data) - return PVR_ERROR_SERVER_ERROR; - - std::string stream_url, stream_type; - PVR_ERROR ret = data->GetRecordingStreamUrl(recording->strRecordingId, stream_url, stream_type); - if (PVR_ERROR_NO_ERROR != ret) - return ret; - - return FillStreamProperties(data->StreamProperties(stream_url, stream_type, false), properties, iPropertiesCount); -} - -/** TIMER FUNCTIONS */ -int GetTimersAmount(void) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetTimersAmount(); - - return -1; -} - -PVR_ERROR GetTimers(ADDON_HANDLE handle) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->GetTimers(handle); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR GetTimerTypes(PVR_TIMER_TYPE types[], int *size) -{ - XBMC->Log(LOG_DEBUG, "%s - size: %d", __FUNCTION__, *size); - int pos = 0; - types[pos].iId = pos + 1; - types[pos].iAttributes = PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME; - types[pos].strDescription[0] = '\0'; // let Kodi generate the description - types[pos].iPrioritiesSize = 0; // no priorities needed - //types[pos].priorities - //types[pos].iPrioritiesDefault = 0; - types[pos].iLifetimesSize = 0; // no lifetime settings supported yet - //types[pos].lifetimes - //types[pos].iLifetimesDefault = 0; - types[pos].iPreventDuplicateEpisodesSize = 0; - //types[pos].preventDuplicateEpisodes - //types[pos].iPreventDuplicateEpisodesDefault = 0; - types[pos].iRecordingGroupSize = 0; - //types[pos].maxRecordings - //types[pos].iRecordingGroupDefault = 0; - types[pos].iMaxRecordingsSize = 0; - //types[pos].maxRecordings - //types[pos].iMaxRecordingsDefault = 0; - XBMC->Log(LOG_DEBUG, "%s - attributes: 0x%x", __FUNCTION__, types[pos].iAttributes); - - ++pos; - types[pos].iId = pos + 1; - types[pos].iAttributes = PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME; - types[pos].strDescription[0] = '\0'; // let Kodi generate the description - types[pos].iPrioritiesSize = 0; // no priorities needed - //types[pos].priorities - //types[pos].iPrioritiesDefault = 0; - types[pos].iLifetimesSize = 0; // no lifetime settings supported yet - //types[pos].lifetimes - //types[pos].iLifetimesDefault = 0; - types[pos].iPreventDuplicateEpisodesSize = 0; - //types[pos].preventDuplicateEpisodes - //types[pos].iPreventDuplicateEpisodesDefault = 0; - types[pos].iRecordingGroupSize = 0; - //types[pos].maxRecordings - //types[pos].iRecordingGroupDefault = 0; - types[pos].iMaxRecordingsSize = 0; - //types[pos].maxRecordings - //types[pos].iMaxRecordingsDefault = 0; - XBMC->Log(LOG_DEBUG, "%s - attributes: 0x%x", __FUNCTION__, types[pos].iAttributes); - - ++pos; - types[pos].iId = pos + 1; - types[pos].iAttributes = PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME; - types[pos].strDescription[0] = '\0'; // let Kodi generate the description - types[pos].iPrioritiesSize = 0; // no priorities needed - //types[pos].priorities - //types[pos].iPrioritiesDefault = 0; - types[pos].iLifetimesSize = 0; // no lifetime settings supported yet - //types[pos].lifetimes - //types[pos].iLifetimesDefault = 0; - types[pos].iPreventDuplicateEpisodesSize = 0; - //types[pos].preventDuplicateEpisodes - //types[pos].iPreventDuplicateEpisodesDefault = 0; - types[pos].iRecordingGroupSize = 0; - //types[pos].maxRecordings - //types[pos].iRecordingGroupDefault = 0; - types[pos].iMaxRecordingsSize = 0; - //types[pos].maxRecordings - //types[pos].iMaxRecordingsDefault = 0; - XBMC->Log(LOG_DEBUG, "%s - attributes: 0x%x", __FUNCTION__, types[pos].iAttributes); - - *size = pos + 1; - return PVR_ERROR_NO_ERROR; -} - -PVR_ERROR AddTimer(const PVR_TIMER &timer) -{ - XBMC->Log(LOG_DEBUG, "%s - type %d", __FUNCTION__, timer.iTimerType); - auto data = std::atomic_load(&m_data); - if (!data) - return PVR_ERROR_SERVER_ERROR; - - return data->AddTimer(timer); -} - -PVR_ERROR DeleteTimer(const PVR_TIMER &timer, bool bForceDelete) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->DeleteRecord(timer.iClientIndex); - - return PVR_ERROR_SERVER_ERROR; -} - -PVR_ERROR DeleteRecording(const PVR_RECORDING &recording) -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->DeleteRecord(recording.strRecordingId); - - return PVR_ERROR_SERVER_ERROR; -} - -bool CanSeekStream(void) -{ - return false; -} - -bool CanPauseStream(void) -{ - return false; -} - -bool IsTimeshifting(void) -{ - return false; -} - -bool IsRealTimeStream() -{ - auto data = std::atomic_load(&m_data); - if (data) - return data->CurrentStreamIsLive(); - - return false; -} - -const char *GetBackendHostname(void) -{ - return ""; -} - -/** UNUSED API FUNCTIONS */ -PVR_ERROR DialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR CallMenuHook(const PVR_MENUHOOK &menuhook, const PVR_MENUHOOK_DATA &item) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR DeleteChannel(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR RenameChannel(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR DialogChannelSettings(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR DialogAddChannel(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR OpenDialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; } -bool OpenRecordedStream(const PVR_RECORDING &recording) { return false; } -void CloseRecordedStream(void) {} -long long SeekRecordedStream(long long iPosition, int iWhence /* = SEEK_SET */) { return -1; } -long long LengthRecordedStream(void) { return -1; } -int ReadRecordedStream(unsigned char *pBuffer, unsigned int iBufferSize) { return 0; } -void DemuxReset(void) {} -void DemuxFlush(void) {} -bool OpenLiveStream(const PVR_CHANNEL &channel) { return false; } -void CloseLiveStream(void) {} -int ReadLiveStream(unsigned char *pBuffer, unsigned int iBufferSize) { return -1; } -long long SeekLiveStream(long long iPosition, int iWhence /* = SEEK_SET */) { return -1; } -long long LengthLiveStream(void) { return -1; } -PVR_ERROR RenameRecording(const PVR_RECORDING &recording) { return PVR_ERROR_NOT_IMPLEMENTED; } -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; } -PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY[], int*) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR UpdateTimer(const PVR_TIMER &timer) { return PVR_ERROR_NOT_IMPLEMENTED; } -void DemuxAbort(void) {} -DemuxPacket* DemuxRead(void) { return NULL; } -void PauseStream(bool bPaused) {} -bool SeekTime(double,bool,double*) { return false; } -void SetSpeed(int) {} -void OnSystemSleep() { } -void OnSystemWake() { } -void OnPowerSavingActivated() { } -void OnPowerSavingDeactivated() { } -PVR_ERROR GetDescrambleInfo(PVR_DESCRAMBLE_INFO*) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR SetRecordingLifetime(const PVR_RECORDING*) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES*) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR GetStreamTimes(PVR_STREAM_TIMES*) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR GetEPGTagEdl(const EPG_TAG* epgTag, PVR_EDL_ENTRY edl[], int *size) { return PVR_ERROR_NOT_IMPLEMENTED; } -PVR_ERROR GetStreamReadChunkSize(int* chunksize) { return PVR_ERROR_NOT_IMPLEMENTED; } - -} // extern "C" diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/src/client.h kodi-pvr-sledovanitv-cz-4.4.0/src/client.h --- kodi-pvr-sledovanitv-cz-1.9.0/src/client.h 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/src/client.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -#pragma once -/* - * Copyright (c) 2018~now Palo Kisa - * - * Copyright (C) 2013 Anton Fedchin - * http://github.com/afedchin/xbmc-addon-iptvsimple/ - * - * Copyright (C) 2011 Pulse-Eight - * http://www.pulse-eight.com/ - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this addon; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "kodi/libXBMC_addon.h" -#include "kodi/libXBMC_pvr.h" -#include "kodi/libKODI_guilib.h" -#include - -extern std::unique_ptr XBMC; -extern std::unique_ptr PVR; -extern std::unique_ptr GUI; - -extern std::string PathCombine(const std::string &strPath, const std::string &strFileName); -extern std::string GetClientFilePath(const std::string &strFileName); -extern std::string GetUserFilePath(const std::string &strFileName); diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/src/Data.cpp kodi-pvr-sledovanitv-cz-4.4.0/src/Data.cpp --- kodi-pvr-sledovanitv-cz-1.9.0/src/Data.cpp 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/src/Data.cpp 2021-01-09 22:45:25.000000000 +0000 @@ -36,6 +36,9 @@ #include "Data.h" #include "CallLimiter.hh" +#include "kodi/General.h" +#include "kodi/Filesystem.h" +#include "kodi/gui/dialogs/Numeric.h" #if defined(TARGET_WINDOWS) # define LOCALTIME_R(src, dst) localtime_s(dst, src) @@ -48,17 +51,6 @@ namespace sledovanitvcz { -template void strAssign(char (&dst)[N], const std::string & src) -{ - strncpy(dst, src.c_str(), N - 1); - dst[N - 1] = '\0'; // just to be sure -} - -static void xbmcStrFree(char * str) -{ - XBMC->FreeString(str); -} - static unsigned DiffBetweenUtcAndLocalTime(const time_t * when = nullptr, int * isdst = nullptr) { time_t tloc; @@ -87,7 +79,7 @@ return diff - (isdst > 0 ? 7200 : 3600); } -Data::Data(Configuration cfg) +Data::Data() : m_bKeepAlive{true} , m_bLoadRecordings{true} , m_bChannelsLoaded{false} @@ -100,24 +92,18 @@ , m_recordingRecordedDuration{0} , m_epgMinTime{time(nullptr)} , m_epgMaxTime{time(nullptr) + 3600} - , m_epgMaxDays{cfg.epgMaxDays} + , m_epgMaxFutureDays{EpgMaxFutureDays()} + , m_epgMaxPastDays{EpgMaxPastDays()} , m_bEGPLoaded{false} , m_iLastStart{0} , m_iLastEnd{0} - , m_streamQuality{static_cast(cfg.streamQuality)} - , m_fullChannelEpgRefresh{cfg.fullChannelEpgRefresh} - , m_loadingsRefresh{cfg.loadingsRefresh} - , m_keepAliveDelay{cfg.keepAliveDelay} - , m_epgCheckDelay{cfg.epgCheckDelay} - , m_useH265{cfg.useH265} - , m_useAdaptive{cfg.useAdaptive} - , m_showLockedChannels{cfg.showLockedChannels} - , m_showLockedOnlyPin{cfg.showLockedOnlyPin} - , m_currentStreamIsLive{false} - , m_manager{std::move(cfg.userName), std::move(cfg.password), std::move(cfg.deviceId), std::move(cfg.productId)} + , m_manager{kodi::GetSettingString("userName"), + kodi::GetSettingString("password"), + kodi::GetSettingString("deviceId"), + kodi::GetSettingString("productId")} { - SetEPGTimeFrame(m_epgMaxDays); + SetEPGMaxDays(m_epgMaxFutureDays, m_epgMaxPastDays); m_thread = std::thread{[this] { Process(); }}; } @@ -151,22 +137,23 @@ void Data::TriggerFullRefresh() { - XBMC->Log(ADDON::LOG_NOTICE, "%s triggering channels/EGP full refresh", __FUNCTION__); + kodi::Log(ADDON_LOG_INFO, "%s triggering channels/EGP full refresh", __FUNCTION__); m_iLastEnd = 0; m_iLastStart = 0; - int epg_max_days = 0; + int future_days = 0, past_days = 0; { std::lock_guard critical(m_mutex); - epg_max_days = m_epgMaxDays; + future_days = m_epgMaxFutureDays; + past_days = m_epgMaxPastDays; } - SetEPGTimeFrame(epg_max_days); + SetEPGMaxDays(future_days, past_days); LoadPlayList(); } bool Data::LoadEPGJob() { - XBMC->Log(ADDON::LOG_INFO, "%s will check if EGP loading needed", __FUNCTION__); + kodi::Log(ADDON_LOG_INFO, "%s will check if EGP loading needed", __FUNCTION__); time_t min_epg, max_epg; { std::lock_guard critical(m_mutex); @@ -211,7 +198,7 @@ epg = m_epg; } auto epg_copy = std::make_shared(); - XBMC->Log(ADDON::LOG_DEBUG, "%s min_epg=%s max_epg=%s", __FUNCTION__, ApiManager::formatTime(min_epg).c_str(), ApiManager::formatTime(max_epg).c_str()); + kodi::Log(ADDON_LOG_DEBUG, "%s min_epg=%s max_epg=%s", __FUNCTION__, ApiManager::formatTime(min_epg).c_str(), ApiManager::formatTime(max_epg).c_str()); for (const auto & epg_channel : *epg) { @@ -222,14 +209,16 @@ const EpgEntry & entry = entry_i->second; if (entry_i->second.startTime > max_epg || entry_i->second.endTime < min_epg) { - XBMC->Log(ADDON::LOG_DEBUG, "Removing TV show: %s - %s, start=%s end=%s", epg_channel.second.strName.c_str(), entry.strTitle.c_str() + kodi::Log(ADDON_LOG_DEBUG, "Removing TV show: %s - %s, start=%s end=%s", epg_channel.second.strName.c_str(), entry.strTitle.c_str() , ApiManager::formatTime(entry.startTime).c_str(), ApiManager::formatTime(entry.endTime).c_str()); // notify about the epg change...and delete it - EPG_TAG tag; - memset(&tag, 0, sizeof(EPG_TAG)); - tag.iUniqueBroadcastId = entry.iBroadcastId; - tag.iUniqueChannelId = entry.iChannelId; - PVR->EpgEventStateChange(&tag, EPG_EVENT_DELETED); + kodi::addon::PVREPGTag tag; + tag.SetSeriesNumber(EPG_TAG_INVALID_SERIES_EPISODE); + tag.SetEpisodeNumber(EPG_TAG_INVALID_SERIES_EPISODE); + tag.SetEpisodePartNumber(EPG_TAG_INVALID_SERIES_EPISODE); + tag.SetUniqueBroadcastId(entry.iBroadcastId); + tag.SetUniqueChannelId(entry.iChannelId); + EpgEventStateChange(tag, EPG_EVENT_DELETED); to_delete.push_back(entry_i->first); } @@ -270,7 +259,7 @@ if (!KeepAlive()) return; - XBMC->Log(ADDON::LOG_DEBUG, "keepAlive:: trigger"); + kodi::Log(ADDON_LOG_DEBUG, "keepAlive:: trigger"); if (!m_manager.keepAlive()) { LoginLoop(); @@ -285,9 +274,15 @@ if (0 >= login_delay) { if (m_manager.login()) + { + ConnectionStateChange("Connected", PVR_CONNECTION_STATE_CONNECTED, ""); should_try = false; + } else + { + ConnectionStateChange("Disconnected", PVR_CONNECTION_STATE_DISCONNECTED, ""); login_delay = 30; // try in 30 seconds + } } std::this_thread::sleep_for(std::chrono::seconds{1}); } @@ -301,7 +296,7 @@ void Data::Process(void) { - XBMC->Log(ADDON::LOG_DEBUG, "keepAlive:: thread started"); + kodi::Log(ADDON_LOG_DEBUG, "keepAlive:: thread started"); LoginLoop(); @@ -342,7 +337,7 @@ // do keep alive call once a time work_done |= keep_alive_job.Call(); } - XBMC->Log(ADDON::LOG_DEBUG, "keepAlive:: thread stopped"); + kodi::Log(ADDON_LOG_DEBUG, "keepAlive:: thread stopped"); } Data::~Data(void) @@ -352,7 +347,78 @@ m_bKeepAlive = false; } m_thread.join(); - XBMC->Log(ADDON::LOG_DEBUG, "%s destructed", __FUNCTION__); + kodi::Log(ADDON_LOG_DEBUG, "%s destructed", __FUNCTION__); +} + +ADDON_STATUS Data::Create() +{ + kodi::Log(ADDON_LOG_DEBUG, "%s - Creating the PVR sledovanitv.cz (unofficial)", __FUNCTION__); + + if (!kodi::vfs::DirectoryExists(UserPath())) + { + kodi::vfs::CreateDirectory(UserPath()); + } + + m_streamQuality = kodi::GetSettingEnum("streamQuality", ApiManager::SQ_DEFAULT); + m_fullChannelEpgRefresh = kodi::GetSettingInt("fullChannelEpgRefresh", 24) * 3600; // make it seconds + m_loadingsRefresh = kodi::GetSettingInt("loadingsRefresh", 60); + m_keepAliveDelay = kodi::GetSettingInt("keepAliveDelay", 20); + m_epgCheckDelay = kodi::GetSettingInt("epgCheckDelay", 1) * 60; // make it seconds + m_useH265 = kodi::GetSettingBoolean("useH265", false); + m_useAdaptive = kodi::GetSettingBoolean("useAdaptive", false); + m_showLockedChannels = kodi::GetSettingBoolean("showLockedChannels", true); + m_showLockedOnlyPin = kodi::GetSettingBoolean("showLockedOnlyPin", true); + + return ADDON_STATUS_OK; +} + +ADDON_STATUS Data::SetSetting(const std::string & settingName, const kodi::CSettingValue & settingValue) +{ + // just force our data to be re-created + return ADDON_STATUS_NEED_RESTART; +} + +PVR_ERROR Data::GetCapabilities(kodi::addon::PVRCapabilities& capabilities) +{ + kodi::Log(ADDON_LOG_DEBUG, "%s", __FUNCTION__); + + capabilities.SetSupportsEPG(true); + capabilities.SetSupportsTV(true); + capabilities.SetSupportsRadio(true); + capabilities.SetSupportsRecordings(true); + capabilities.SetSupportsRecordingsUndelete(false); + capabilities.SetSupportsTimers(true); + capabilities.SetSupportsChannelGroups(true); + capabilities.SetSupportsChannelScan(false); + capabilities.SetSupportsChannelSettings(false); + capabilities.SetHandlesInputStream(false); + capabilities.SetHandlesDemuxing(false); + capabilities.SetSupportsRecordingPlayCount(false); + capabilities.SetSupportsLastPlayedPosition(false); + capabilities.SetSupportsRecordingEdl(false); + capabilities.SetSupportsRecordingsRename(false); + capabilities.SetSupportsRecordingsLifetimeChange(false); + capabilities.SetSupportsDescrambleInfo(false); + + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetBackendName(std::string& name) +{ + name = "PVR sledovanitv.cz (unofficial)"; + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetBackendVersion(std::string& version) +{ + version = ""; + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetConnectionString(std::string& connection) +{ + connection = "connected"; + return PVR_ERROR_NO_ERROR; } bool Data::KeepAlive() @@ -364,7 +430,7 @@ bool Data::LoadEPG(time_t iStart, bool bSmallStep) { const int step = bSmallStep ? 3600 : 86400; - XBMC->Log(ADDON::LOG_DEBUG, "%s last start %s, start %s, last end %s, end %s", __FUNCTION__, ApiManager::formatTime(m_iLastStart).c_str() + kodi::Log(ADDON_LOG_DEBUG, "%s last start %s, start %s, last end %s, end %s", __FUNCTION__, ApiManager::formatTime(m_iLastStart).c_str() , ApiManager::formatTime(iStart).c_str(), ApiManager::formatTime(m_iLastEnd).c_str(), ApiManager::formatTime(iStart + step).c_str()); if (m_bEGPLoaded && m_iLastStart != 0 && iStart >= m_iLastStart && iStart + step <= m_iLastEnd) return false; @@ -373,7 +439,7 @@ if (!m_manager.getEpg(iStart, bSmallStep, std::string() /*ChannelsList()*/, root)) { - XBMC->Log(ADDON::LOG_NOTICE, "Cannot parse EPG data. EPG not loaded."); + kodi::Log(ADDON_LOG_INFO, "Cannot parse EPG data. EPG not loaded."); m_bEGPLoaded = true; return false; } @@ -430,24 +496,26 @@ iptventry.availableTimeshift = availability == "timeshift" || availability == "pvr"; iptventry.strRecordId = epgEntry["recordId"].asString(); - XBMC->Log(ADDON::LOG_DEBUG, "Loading TV show: %s - %s, start=%s(epoch=%llu)", strChId.c_str(), iptventry.strTitle.c_str() + kodi::Log(ADDON_LOG_DEBUG, "Loading TV show: %s - %s, start=%s(epoch=%llu)", strChId.c_str(), iptventry.strTitle.c_str() , epgEntry.get("startTime", "").asString().c_str(), static_cast(start_time)); // notify about the epg change...and store it - EPG_TAG tag; - memset(&tag, 0, sizeof(EPG_TAG)); - - tag.iUniqueBroadcastId = iptventry.iBroadcastId; - tag.iUniqueChannelId = iptventry.iChannelId; - tag.strTitle = strdup(iptventry.strTitle.c_str()); - tag.startTime = iptventry.startTime; - tag.endTime = iptventry.endTime; - tag.strPlotOutline = strdup(iptventry.strPlotOutline.c_str()); - tag.strPlot = strdup(iptventry.strPlot.c_str()); - tag.strIconPath = strdup(iptventry.strIconPath.c_str()); - tag.iGenreType = EPG_GENRE_USE_STRING; //iptventry.iGenreType; - tag.iGenreSubType = 0; //iptventry.iGenreSubType; - tag.strGenreDescription = strdup(iptventry.strGenreString.c_str()); + kodi::addon::PVREPGTag tag; + tag.SetSeriesNumber(EPG_TAG_INVALID_SERIES_EPISODE); + tag.SetEpisodeNumber(EPG_TAG_INVALID_SERIES_EPISODE); + tag.SetEpisodePartNumber(EPG_TAG_INVALID_SERIES_EPISODE); + + tag.SetUniqueBroadcastId(iptventry.iBroadcastId); + tag.SetUniqueChannelId(iptventry.iChannelId); + tag.SetTitle(iptventry.strTitle); + tag.SetStartTime(iptventry.startTime); + tag.SetEndTime(iptventry.endTime); + tag.SetPlotOutline(iptventry.strPlotOutline); + tag.SetPlot(iptventry.strPlot); + tag.SetIconPath(iptventry.strIconPath); + tag.SetGenreType(EPG_GENRE_USE_STRING); //iptventry.iGenreType; + tag.SetGenreSubType(0); //iptventry.iGenreSubType; + tag.SetGenreDescription(iptventry.strGenreString); auto result = epgChannel.epg.emplace(iptventry.startTime, iptventry); bool value_changed = !result.second; @@ -456,14 +524,7 @@ epgChannel.epg[iptventry.startTime] = std::move(iptventry); } - PVR->EpgEventStateChange(&tag, value_changed ? EPG_EVENT_UPDATED : EPG_EVENT_CREATED); - - free(const_cast(tag.strTitle)); - free(const_cast(tag.strPlotOutline)); - free(const_cast(tag.strPlot)); - free(const_cast(tag.strIconPath)); - free(const_cast(tag.strGenreDescription)); - + EpgEventStateChange(tag, value_changed ? EPG_EVENT_UPDATED : EPG_EVENT_CREATED); } } } @@ -475,7 +536,7 @@ } m_bEGPLoaded = true; - XBMC->Log(ADDON::LOG_NOTICE, "EPG Loaded."); + kodi::Log(ADDON_LOG_INFO, "EPG Loaded."); return true; } @@ -501,7 +562,7 @@ if (!m_manager.getPvr(root)) { - XBMC->Log(ADDON::LOG_NOTICE, "Cannot parse recordings."); + kodi::Log(ADDON_LOG_INFO, "Cannot parse recordings."); return false; } @@ -518,11 +579,10 @@ if (locked != "none") { //Note: std::make_unique is available from c++14 - std::unique_ptr loc{XBMC->GetLocalizedString(30201), &xbmcStrFree}; - directory = loc.get(); + directory = kodi::GetLocalizedString(30201); directory += " - "; directory += locked; - XBMC->Log(ADDON::LOG_NOTICE, "Timer/recording '%s' is locked(%s)", title.c_str(), locked.c_str()); + kodi::Log(ADDON_LOG_INFO, "Timer/recording '%s' is locked(%s)", title.c_str(), locked.c_str()); } std::string str_ch_id = record.get("channel", "").asString(); const auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [&str_ch_id] (const Channel & ch) { return ch.strId == str_ch_id; }); @@ -556,7 +616,7 @@ iptvrecording.strDirectory = std::move(directory); iptvrecording.bIsPinLocked = locked == "pin"; - XBMC->Log(ADDON::LOG_DEBUG, "Loading recording '%s'", iptvrecording.strTitle.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "Loading recording '%s'", iptvrecording.strTitle.c_str()); new_recordings->push_back(iptvrecording); } @@ -582,7 +642,7 @@ iptvtimer.iLifeTime = (ParseDateTime(record.get("expires", "").asString() + "00:00") - now) / 86400; iptvtimer.strDirectory = std::move(directory); - XBMC->Log(ADDON::LOG_DEBUG, "Loading timer '%s'", iptvtimer.strTitle.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "Loading timer '%s'", iptvtimer.strTitle.c_str()); new_timers->push_back(iptvtimer); } @@ -626,13 +686,13 @@ if (changed_r) { m_recordings = std::move(new_recordings); - PVR->TriggerRecordingUpdate(); + TriggerRecordingUpdate(); } if (changed_t) { m_timers = std::move(new_timers); - PVR->TriggerTimerUpdate(); + TriggerTimerUpdate(); } m_recordingAvailableDuration = available_duration; m_recordingRecordedDuration = recorded_duration; @@ -650,13 +710,13 @@ if (!m_manager.getPlaylist(m_streamQuality, m_useH265, m_useAdaptive, root)) { - XBMC->Log(ADDON::LOG_NOTICE, "Cannot get/parse playlist."); + kodi::Log(ADDON_LOG_INFO, "Cannot get/parse playlist."); return false; } /* std::string qualities = m_manager.getStreamQualities(); - XBMC->Log(ADDON::LOG_DEBUG, "Stream qualities: %s", qualities.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "Stream qualities: %s", qualities.c_str()); */ //channels @@ -670,7 +730,7 @@ { if (!m_showLockedChannels || (m_showLockedOnlyPin && locked != "pin")) { - XBMC->Log(ADDON::LOG_NOTICE, "Skipping locked(%s) channel#%u %s", locked.c_str(), i + 1, channel.get("name", "").asString().c_str()); + kodi::Log(ADDON_LOG_INFO, "Skipping locked(%s) channel#%u %s", locked.c_str(), i + 1, channel.get("name", "").asString().c_str()); continue; } } @@ -684,7 +744,7 @@ iptvchan.strStreamType = channel.get("streamType", "").asString(); iptvchan.iUniqueId = i + 1; iptvchan.iChannelNumber = i + 1; - XBMC->Log(ADDON::LOG_DEBUG, "Channel#%d %s, URL: %s", iptvchan.iUniqueId, iptvchan.strChannelName.c_str(), iptvchan.strStreamURL.c_str()); + kodi::Log(ADDON_LOG_DEBUG, "Channel#%d %s, URL: %s", iptvchan.iUniqueId, iptvchan.strChannelName.c_str(), iptvchan.strStreamURL.c_str()); iptvchan.strIconPath = channel.get("logoUrl", "").asString(); iptvchan.bIsRadio = channel.get("type", "").asString() != "tv"; iptvchan.bIsPinLocked = locked == "pin"; @@ -708,8 +768,8 @@ new_groups->push_back(std::move(group)); } - XBMC->Log(ADDON::LOG_NOTICE, "Loaded %d channels.", new_channels->size()); - XBMC->QueueNotification(ADDON::QUEUE_INFO, "%d channels loaded.", new_channels->size()); + kodi::Log(ADDON_LOG_INFO, "Loaded %d channels.", new_channels->size()); + kodi::QueueFormattedNotification(QUEUE_INFO, "%d channels loaded.", new_channels->size()); bool channels_loaded; @@ -722,14 +782,14 @@ m_waitCond.notify_all(); if (channels_loaded) { - PVR->TriggerChannelUpdate(); - PVR->TriggerChannelGroupsUpdate(); + TriggerChannelUpdate(); + TriggerChannelGroupsUpdate(); } return true; } -int Data::GetChannelsAmount(void) +PVR_ERROR Data::GetChannelsAmount(int& amount) { decltype (m_channels) channels; { @@ -737,12 +797,13 @@ channels = m_channels; } - return channels->size(); + amount = channels->size(); + return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetChannels(ADDON_HANDLE handle, bool bRadio) +PVR_ERROR Data::GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) { - XBMC->Log(ADDON::LOG_DEBUG, "%s %s", __FUNCTION__, bRadio ? "radio" : "tv"); + kodi::Log(ADDON_LOG_DEBUG, "%s %s", __FUNCTION__, radio ? "radio" : "tv"); WaitForChannels(); decltype (m_channels) channels; @@ -751,31 +812,24 @@ channels = m_channels; } - std::vector xbmc_channels; for (const auto & channel : *channels) { - if (channel.bIsRadio == bRadio) + if (channel.bIsRadio == radio) { - PVR_CHANNEL xbmcChannel; - memset(&xbmcChannel, 0, sizeof(PVR_CHANNEL)); + kodi::addon::PVRChannel kodiChannel; - xbmcChannel.iUniqueId = channel.iUniqueId; - xbmcChannel.bIsRadio = channel.bIsRadio; - xbmcChannel.iChannelNumber = channel.iChannelNumber; - strAssign(xbmcChannel.strChannelName, channel.strChannelName); - xbmcChannel.iEncryptionSystem = channel.iEncryptionSystem; - strAssign(xbmcChannel.strIconPath, channel.strIconPath); - xbmcChannel.bIsHidden = false; + kodiChannel.SetUniqueId(channel.iUniqueId); + kodiChannel.SetIsRadio(channel.bIsRadio); + kodiChannel.SetChannelNumber(channel.iChannelNumber); + kodiChannel.SetChannelName(channel.strChannelName); + kodiChannel.SetEncryptionSystem(channel.iEncryptionSystem); + kodiChannel.SetIconPath(channel.strIconPath); + kodiChannel.SetIsHidden(false); - xbmc_channels.push_back(std::move(xbmcChannel)); + results.Add(kodiChannel); } } - for (const auto & xbmcChannel : xbmc_channels) - { - PVR->TransferChannelEntry(handle, &xbmcChannel); - } - { std::lock_guard critical(m_mutex); m_bChannelsLoaded = true; @@ -783,7 +837,26 @@ return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetChannelStreamUrl(const PVR_CHANNEL* channel, std::string & streamUrl, std::string & streamType) +PVR_ERROR Data::GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, std::vector& properties) +{ + std::string streamUrl, streamType; + PVR_ERROR ret = GetChannelStreamUrl(channel, streamUrl, streamType); + if (PVR_ERROR_NO_ERROR != ret) + return ret; + + properties = StreamProperties(streamUrl, streamType, true); + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetSignalStatus(int channelUid, kodi::addon::PVRSignalStatus& signalStatus) +{ + signalStatus.SetAdapterName("sledovanitv.cz"); + signalStatus.SetAdapterStatus("OK"); + + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetChannelStreamUrl(const kodi::addon::PVRChannel& channel, std::string & streamUrl, std::string & streamType) { decltype (m_channels) channels; { @@ -791,10 +864,10 @@ channels = m_channels; } - auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [channel] (const Channel & c) { return c.iUniqueId == channel->iUniqueId; }); + auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [channel] (const Channel & c) { return c.iUniqueId == channel.GetUniqueId(); }); if (channels->cend() == channel_i) { - XBMC->Log(ADDON::LOG_NOTICE, "%s can't find channel %d", __FUNCTION__, channel->iUniqueId); + kodi::Log(ADDON_LOG_INFO, "%s can't find channel %d", __FUNCTION__, channel.GetUniqueId()); return PVR_ERROR_INVALID_PARAMETERS; } @@ -807,19 +880,20 @@ } -int Data::GetChannelGroupsAmount(void) +PVR_ERROR Data::GetChannelGroupsAmount(int& amount) { decltype (m_groups) groups; { std::lock_guard critical(m_mutex); groups = m_groups; } - return groups->size(); + amount = groups->size(); + return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetChannelGroups(ADDON_HANDLE handle, bool bRadio) +PVR_ERROR Data::GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) { - XBMC->Log(ADDON::LOG_DEBUG, "%s %s", __FUNCTION__, bRadio ? "radio" : "tv"); + kodi::Log(ADDON_LOG_DEBUG, "%s %s", __FUNCTION__, radio ? "radio" : "tv"); WaitForChannels(); decltype (m_groups) groups; @@ -828,32 +902,25 @@ groups = m_groups; } - std::vector xbmc_groups; for (const auto & group : *groups) { - if (group.bRadio == bRadio) + if (group.bRadio == radio) { - PVR_CHANNEL_GROUP xbmcGroup; - memset(&xbmcGroup, 0, sizeof(PVR_CHANNEL_GROUP)); + kodi::addon::PVRChannelGroup kodiGroup; - xbmcGroup.bIsRadio = bRadio; - strAssign(xbmcGroup.strGroupName, group.strGroupName); + kodiGroup.SetIsRadio(radio); + kodiGroup.SetGroupName(group.strGroupName); - xbmc_groups.push_back(std::move(xbmcGroup)); + results.Add(kodiGroup); } } - for (const auto & xbmcGroup : xbmc_groups) - { - PVR->TransferChannelGroup(handle, &xbmcGroup); - } - return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group) +PVR_ERROR Data::GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, kodi::addon::PVRChannelGroupMembersResultSet& results) { - XBMC->Log(ADDON::LOG_DEBUG, "%s %s", __FUNCTION__, group.strGroupName); + kodi::Log(ADDON_LOG_DEBUG, "%s %s", __FUNCTION__, group.GetGroupName().c_str()); WaitForChannels(); decltype (m_groups) groups; @@ -864,8 +931,8 @@ channels = m_channels; } - std::vector xbmc_group_members; - auto group_i = std::find_if(groups->cbegin(), groups->cend(), [&group] (ChannelGroup const & g) { return g.strGroupName == group.strGroupName; }); + std::vector kodi_group_members; + auto group_i = std::find_if(groups->cbegin(), groups->cend(), [&group] (ChannelGroup const & g) { return g.strGroupName == group.GetGroupName(); }); if (group_i != groups->cend()) { int order = 0; @@ -875,47 +942,46 @@ continue; const Channel &channel = (*channels)[member]; - PVR_CHANNEL_GROUP_MEMBER xbmcGroupMember; - memset(&xbmcGroupMember, 0, sizeof(PVR_CHANNEL_GROUP_MEMBER)); + kodi::addon::PVRChannelGroupMember kodiGroupMember; - strncpy(xbmcGroupMember.strGroupName, group.strGroupName, sizeof(xbmcGroupMember.strGroupName) - 1); - xbmcGroupMember.iChannelUniqueId = channel.iUniqueId; - xbmcGroupMember.iChannelNumber = ++order; + kodiGroupMember.SetGroupName(group.GetGroupName()); + kodiGroupMember.SetChannelUniqueId(channel.iUniqueId); + kodiGroupMember.SetChannelNumber(++order); - xbmc_group_members.push_back(std::move(xbmcGroupMember)); + kodi_group_members.push_back(std::move(kodiGroupMember)); } } - for (const auto & xbmcGroupMember : xbmc_group_members) + for (const auto & kodiGroupMember : kodi_group_members) { - PVR->TransferChannelGroupMember(handle, &xbmcGroupMember); + results.Add(kodiGroupMember); } return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd) +PVR_ERROR Data::GetEPGForChannel(int channelUid, time_t start, time_t end, kodi::addon::PVREPGTagsResultSet& results) { - XBMC->Log(ADDON::LOG_DEBUG, "%s %s, from=%s to=%s", __FUNCTION__, channel.strChannelName, ApiManager::formatTime(iStart).c_str(), ApiManager::formatTime(iEnd).c_str()); + kodi::Log(ADDON_LOG_DEBUG, "%s %i, from=%s to=%s", __FUNCTION__, channelUid, ApiManager::formatTime(start).c_str(), ApiManager::formatTime(end).c_str()); std::lock_guard critical(m_mutex); // Note: For future scheduled timers Kodi requests EPG (this function) with - // iStart & iEnd as given by the timer timespan. But we don't want to narrow + // start & end as given by the timer timespan. But we don't want to narrow // our EPG interval in such cases. - m_epgMinTime = iStart < m_epgMinTime ? iStart : m_epgMinTime; - m_epgMaxTime = iEnd > m_epgMaxTime ? iEnd : m_epgMaxTime; + m_epgMinTime = start < m_epgMinTime ? start : m_epgMinTime; + m_epgMaxTime = end > m_epgMaxTime ? end : m_epgMaxTime; return PVR_ERROR_NO_ERROR; } -static PVR_ERROR GetEPGData(const EPG_TAG* tag +static PVR_ERROR GetEPGData(const kodi::addon::PVREPGTag& tag , const channel_container_t * channels , const epg_container_t * epg , epg_entry_container_t::const_iterator & epg_i , bool * isChannelPinLocked = nullptr ) { - auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [tag] (const Channel & c) { return c.iUniqueId == tag->iUniqueChannelId; }); + auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [tag] (const Channel & c) { return c.iUniqueId == tag.GetUniqueChannelId(); }); if (channels->cend() == channel_i) { - XBMC->Log(ADDON::LOG_NOTICE, "%s can't find channel %d", __FUNCTION__, tag->iUniqueChannelId); + kodi::Log(ADDON_LOG_INFO, "%s can't find channel %d", __FUNCTION__, tag.GetUniqueChannelId()); return PVR_ERROR_INVALID_PARAMETERS; } if (isChannelPinLocked) @@ -923,15 +989,15 @@ auto ch_epg_i = epg->find(channel_i->strId); - if (epg->cend() == ch_epg_i || (epg_i = ch_epg_i->second.epg.find(tag->iUniqueBroadcastId)) == ch_epg_i->second.epg.cend()) + if (epg->cend() == ch_epg_i || (epg_i = ch_epg_i->second.epg.find(tag.GetUniqueBroadcastId())) == ch_epg_i->second.epg.cend()) { - XBMC->Log(ADDON::LOG_NOTICE, "%s can't find EPG data for channel %s, time %d", __FUNCTION__, channel_i->strId.c_str(), tag->iUniqueBroadcastId); + kodi::Log(ADDON_LOG_INFO, "%s can't find EPG data for channel %s, time %d", __FUNCTION__, channel_i->strId.c_str(), tag.GetUniqueBroadcastId()); return PVR_ERROR_INVALID_PARAMETERS; } return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::IsEPGTagPlayable(const EPG_TAG* tag, bool* bIsPlayable) const +PVR_ERROR Data::IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& isPlayable) { decltype (m_channels) channels; decltype (m_epg) epg; @@ -946,11 +1012,11 @@ if (PVR_ERROR_NO_ERROR != ret) return ret; - *bIsPlayable = epg_i->second.availableTimeshift && tag->startTime < time(nullptr); + isPlayable = epg_i->second.availableTimeshift && tag.GetStartTime() < time(nullptr); return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::IsEPGTagRecordable(const EPG_TAG* tag, bool* bIsRecordable) const +PVR_ERROR Data::IsEPGTagRecordable(const kodi::addon::PVREPGTag& tag, bool& isRecordable) { decltype (m_channels) channels; decltype (m_epg) epg; @@ -965,11 +1031,22 @@ if (PVR_ERROR_NO_ERROR != ret) return ret; - *bIsRecordable = epg_i->second.availableTimeshift && !RecordingExists(epg_i->second.strRecordId) && tag->startTime < time(nullptr); + isRecordable = epg_i->second.availableTimeshift && !RecordingExists(epg_i->second.strRecordId) && tag.GetStartTime() < time(nullptr); return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetEPGStreamUrl(const EPG_TAG* tag, std::string & streamUrl, std::string & streamType) +PVR_ERROR Data::GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& tag, std::vector& properties) +{ + std::string streamUrl, streamType; + PVR_ERROR ret = GetEPGStreamUrl(tag, streamUrl, streamType); + if (PVR_ERROR_NO_ERROR != ret) + return ret; + + properties = StreamProperties(streamUrl, streamType, false); + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetEPGStreamUrl(const kodi::addon::PVREPGTag& tag, std::string & streamUrl, std::string & streamType) { decltype (m_channels) channels; decltype (m_epg) epg; @@ -1001,14 +1078,25 @@ return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::SetEPGTimeFrame(int iDays) +PVR_ERROR Data::SetEPGMaxFutureDays(int iFutureDays) { - XBMC->Log(ADDON::LOG_DEBUG, "%s iDays=%d", __FUNCTION__, iDays); + return SetEPGMaxDays(iFutureDays, -1); +} + +PVR_ERROR Data::SetEPGMaxPastDays(int iPastDays) +{ + return SetEPGMaxDays(-1, iPastDays); +} + +PVR_ERROR Data::SetEPGMaxDays(int iFutureDays, int iPastDays) +{ + kodi::Log(ADDON_LOG_DEBUG, "%s iFutureDays=%d, iPastDays=%d", __FUNCTION__, iFutureDays, iPastDays); time_t now = time(nullptr); std::lock_guard critical(m_mutex); - m_epgMinTime = now; - m_epgMaxTime = now + iDays * 86400; - m_epgMaxDays = iDays; + m_epgMaxFutureDays = (iFutureDays == -1 ? m_epgMaxFutureDays : iFutureDays); + m_epgMaxPastDays = (iPastDays == -1 ? m_epgMaxPastDays : iPastDays); + m_epgMinTime = now - m_epgMaxPastDays * 86400; + m_epgMaxTime = now + m_epgMaxFutureDays * 86400; return PVR_ERROR_NO_ERROR; } @@ -1029,51 +1117,56 @@ return t - DiffBetweenPragueAndLocalTime(&t); } -int Data::GetRecordingsAmount() +PVR_ERROR Data::GetRecordingsAmount(bool deleted, int& amount) { decltype (m_recordings) recordings; { std::lock_guard critical(m_mutex); recordings = m_recordings; } - return recordings->size(); + amount = recordings->size(); + return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetRecordings(ADDON_HANDLE handle) +PVR_ERROR Data::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) { decltype (m_recordings) recordings; { std::lock_guard critical(m_mutex); recordings = m_recordings; } - std::vector xbmc_records; - auto insert_lambda = [&xbmc_records] (const Recording & rec) + auto insert_lambda = [&results] (const Recording & rec) { - PVR_RECORDING xbmcRecord; - memset(&xbmcRecord, 0, sizeof(PVR_RECORDING)); + kodi::addon::PVRRecording kodiRecord; - strAssign(xbmcRecord.strRecordingId, rec.strRecordId); - strAssign(xbmcRecord.strTitle, rec.strTitle); - strAssign(xbmcRecord.strDirectory, rec.strDirectory); - strAssign(xbmcRecord.strChannelName, rec.strChannelName); - xbmcRecord.recordingTime = rec.startTime; - strAssign(xbmcRecord.strPlotOutline, rec.strPlotOutline); - strAssign(xbmcRecord.strPlot, rec.strPlotOutline); - xbmcRecord.iDuration = rec.duration; - xbmcRecord.iLifetime = rec.iLifeTime; - xbmcRecord.iChannelUid = rec.iChannelUid; - xbmcRecord.channelType = rec.bRadio ? PVR_RECORDING_CHANNEL_TYPE_RADIO : PVR_RECORDING_CHANNEL_TYPE_TV; + kodiRecord.SetRecordingId(rec.strRecordId); + kodiRecord.SetTitle(rec.strTitle); + kodiRecord.SetDirectory(rec.strDirectory); + kodiRecord.SetChannelName(rec.strChannelName); + kodiRecord.SetRecordingTime(rec.startTime); + kodiRecord.SetPlotOutline(rec.strPlotOutline); + kodiRecord.SetPlot(rec.strPlotOutline); + kodiRecord.SetDuration(rec.duration); + kodiRecord.SetLifetime(rec.iLifeTime); + kodiRecord.SetChannelUid(rec.iChannelUid); + kodiRecord.SetChannelType(rec.bRadio ? PVR_RECORDING_CHANNEL_TYPE_RADIO : PVR_RECORDING_CHANNEL_TYPE_TV); - xbmc_records.push_back(std::move(xbmcRecord)); + results.Add(kodiRecord); }; std::for_each(recordings->cbegin(), recordings->cend(), insert_lambda); - for (const auto & xbmcRecord : xbmc_records) - { - PVR->TransferRecordingEntry(handle, &xbmcRecord); - } + return PVR_ERROR_NO_ERROR; +} +PVR_ERROR Data::GetRecordingStreamProperties(const kodi::addon::PVRRecording& recording, std::vector& properties) +{ + std::string streamUrl, streamType; + PVR_ERROR ret = GetRecordingStreamUrl(recording.GetRecordingId(), streamUrl, streamType); + if (PVR_ERROR_NO_ERROR != ret) + return ret; + + properties = StreamProperties(streamUrl, streamType, false); return PVR_ERROR_NO_ERROR; } @@ -1106,18 +1199,44 @@ return recordings->cend() != std::find_if(recordings->cbegin(), recordings->cend(), [&recordId] (const Recording & r) { return recordId == r.strRecordId; }); } -int Data::GetTimersAmount() +PVR_ERROR Data::GetTimerTypes(std::vector& types) +{ + kodi::Log(ADDON_LOG_DEBUG, "%s", __FUNCTION__); + + int id = 0; + kodi::addon::PVRTimerType type; + + type.SetId(++id); + type.SetAttributes(PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME); + kodi::Log(ADDON_LOG_DEBUG, "%s - id %i attributes: 0x%x", __FUNCTION__, id, type.GetAttributes()); + types.push_back(type); + + type.SetId(++id); + type.SetAttributes(PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME); + kodi::Log(ADDON_LOG_DEBUG, "%s - id %i attributes: 0x%x", __FUNCTION__, id, type.GetAttributes()); + types.push_back(type); + + type.SetId(++id); + type.SetAttributes(PVR_TIMER_TYPE_IS_REPEATING | PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME); + kodi::Log(ADDON_LOG_DEBUG, "%s - id %i attributes: 0x%x", __FUNCTION__, id, type.GetAttributes()); + types.push_back(type); + + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR Data::GetTimersAmount(int& amount) { decltype (m_timers) timers; { std::lock_guard critical(m_mutex); timers = m_timers; } - return timers->size(); + amount = timers->size(); + return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::GetTimers(ADDON_HANDLE handle) +PVR_ERROR Data::GetTimers(kodi::addon::PVRTimersResultSet& results) { decltype (m_timers) timers; { @@ -1125,34 +1244,28 @@ timers = m_timers; } - std::vector xbmc_timers; for (const auto & timer : *timers) { - PVR_TIMER xbmcTimer; - memset(&xbmcTimer, 0, sizeof(PVR_TIMER)); + kodi::addon::PVRTimer kodiTimer; - xbmcTimer.iClientIndex = timer.iClientIndex; - xbmcTimer.iClientChannelUid = timer.iClientChannelUid; - xbmcTimer.startTime = timer.startTime; - xbmcTimer.endTime = timer.endTime; - xbmcTimer.state = timer.state; - xbmcTimer.iTimerType = 1; // Note: this must match some type from GetTimerTypes() - xbmcTimer.iLifetime = timer.iLifeTime; - strAssign(xbmcTimer.strTitle, timer.strTitle); - strAssign(xbmcTimer.strSummary, timer.strSummary); - strAssign(xbmcTimer.strDirectory, timer.strDirectory); + kodiTimer.SetClientIndex(timer.iClientIndex); + kodiTimer.SetClientChannelUid(timer.iClientChannelUid); + kodiTimer.SetStartTime(timer.startTime); + kodiTimer.SetEndTime(timer.endTime); + kodiTimer.SetState(timer.state); + kodiTimer.SetTimerType(1); // Note: this must match some type from GetTimerTypes() + kodiTimer.SetLifetime(timer.iLifeTime); + kodiTimer.SetTitle(timer.strTitle); + kodiTimer.SetSummary(timer.strSummary); + kodiTimer.SetDirectory(timer.strDirectory); - xbmc_timers.push_back(std::move(xbmcTimer)); - } - for (const auto & xbmcTimer : xbmc_timers) - { - PVR->TransferTimerEntry(handle, &xbmcTimer); + results.Add(kodiTimer); } return PVR_ERROR_NO_ERROR; } -PVR_ERROR Data::AddTimer(const PVR_TIMER &timer) +PVR_ERROR Data::AddTimer(const kodi::addon::PVRTimer& timer) { decltype (m_channels) channels; decltype (m_epg) epg; @@ -1162,23 +1275,23 @@ epg = m_epg; } - const auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [&timer] (const Channel & ch) { return ch.iUniqueId == timer.iClientChannelUid; }); + const auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [&timer] (const Channel & ch) { return ch.iUniqueId == timer.GetClientChannelUid(); }); if (channel_i == channels->cend()) { - XBMC->Log(ADDON::LOG_ERROR, "%s - channel not found", __FUNCTION__); + kodi::Log(ADDON_LOG_ERROR, "%s - channel not found", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } const auto epg_channel_i = epg->find(channel_i->strId); if (epg_channel_i == epg->cend()) { - XBMC->Log(ADDON::LOG_ERROR, "%s - epg channel not found", __FUNCTION__); + kodi::Log(ADDON_LOG_ERROR, "%s - epg channel not found", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } - const auto epg_i = epg_channel_i->second.epg.find(timer.startTime); + const auto epg_i = epg_channel_i->second.epg.find(timer.GetStartTime()); if (epg_i == epg_channel_i->second.epg.cend()) { - XBMC->Log(ADDON::LOG_ERROR, "%s - event not found", __FUNCTION__); + kodi::Log(ADDON_LOG_ERROR, "%s - event not found", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } @@ -1189,7 +1302,7 @@ // update the record_id into EPG // Note: the m_epg/epg is read-only, so the keys must exist auto epg_copy = std::make_shared(*epg); - (*epg_copy)[channel_i->strId].epg[timer.startTime].strRecordId = record_id; + (*epg_copy)[channel_i->strId].epg[timer.GetStartTime()].strRecordId = record_id; { std::lock_guard critical(m_mutex); m_epg = epg_copy; @@ -1200,9 +1313,9 @@ return PVR_ERROR_SERVER_ERROR; } -PVR_ERROR Data::DeleteRecord(const std::string &strRecordId) +PVR_ERROR Data::DeleteRecording(const kodi::addon::PVRRecording& recording) { - if (m_manager.deleteRecord(strRecordId)) + if (m_manager.deleteRecord(recording.GetRecordingId())) { SetLoadRecordings(); return PVR_ERROR_NO_ERROR; @@ -1210,20 +1323,22 @@ return PVR_ERROR_SERVER_ERROR; } -PVR_ERROR Data::DeleteRecord(int iRecordId) +PVR_ERROR Data::DeleteTimer(const kodi::addon::PVRTimer& timer, bool forceDelete) { - std::ostringstream os; - os << iRecordId; - - return DeleteRecord(os.str()); + if (m_manager.deleteRecord(std::to_string((timer.GetClientIndex())))) + { + SetLoadRecordings(); + return PVR_ERROR_NO_ERROR; + } + return PVR_ERROR_SERVER_ERROR; } -PVR_ERROR Data::GetDriveSpace(long long *iTotal, long long *iUsed) +PVR_ERROR Data::GetDriveSpace(uint64_t& total, uint64_t& used) { { std::lock_guard critical(m_mutex); - *iTotal = m_recordingAvailableDuration; - *iUsed = m_recordingRecordedDuration; + total = m_recordingAvailableDuration; + used = m_recordingRecordedDuration; } return PVR_ERROR_NO_ERROR; } @@ -1233,27 +1348,20 @@ return m_manager.loggedIn(); } -properties_t Data::StreamProperties(const std::string & url, const std::string & streamType, bool isLive) +std::vector Data::StreamProperties(const std::string & url, const std::string & streamType, bool isLive) const { static const std::set ADAPTIVE_TYPES = {"mpd", "ism", "hls"}; - m_currentStreamIsLive = isLive; - - properties_t props; - props[PVR_STREAM_PROPERTY_STREAMURL] = url; + std::vector properties; + properties.emplace_back(PVR_STREAM_PROPERTY_STREAMURL, url); if (m_useAdaptive && 0 < ADAPTIVE_TYPES.count(streamType)) { - props[PVR_STREAM_PROPERTY_INPUTSTREAMADDON] = "inputstream.adaptive"; - props["inputstream.adaptive.manifest_type"] = streamType; + properties.emplace_back(PVR_STREAM_PROPERTY_INPUTSTREAM, "inputstream.adaptive"); + properties.emplace_back("inputstream.adaptive.manifest_type", streamType); } if (isLive) - props[PVR_STREAM_PROPERTY_ISREALTIMESTREAM] = "true"; - return props; -} - -bool Data::CurrentStreamIsLive() const -{ - return m_currentStreamIsLive; + properties.emplace_back(PVR_STREAM_PROPERTY_ISREALTIMESTREAM, "true"); + return properties; } std::string Data::ChannelsList() const @@ -1287,7 +1395,7 @@ std::string stream_type = "unknown"; auto channel_i = std::find_if(channels->cbegin(), channels->cend(), [&channelId] (const Channel & c) { return c.strId == channelId; }); if (channels->cend() == channel_i) - XBMC->Log(ADDON::LOG_NOTICE, "%s can't find channel %s", __FUNCTION__, channelId.c_str()); + kodi::Log(ADDON_LOG_INFO, "%s can't find channel %s", __FUNCTION__, channelId.c_str()); else stream_type = channel_i->strStreamType; return stream_type; @@ -1301,19 +1409,17 @@ if (!m_manager.pinUnlocked()) { //Note: std::make_unique is available from c++14 - std::unique_ptr loc{XBMC->GetLocalizedString(30202), &xbmcStrFree}; - char pin[32]; - pin[0] = 0; - if (GUI->Dialog_Numeric_ShowAndGetNumber(*pin, sizeof (pin), loc.get())) + std::string pin; + if (kodi::gui::dialogs::Numeric::ShowAndGetNumber(pin, kodi::GetLocalizedString(30202))) { if (!m_manager.pinUnlock(pin)) { - XBMC->Log(ADDON::LOG_ERROR, "PIN-unlocking failed"); + kodi::Log(ADDON_LOG_ERROR, "PIN-unlocking failed"); return false; } } else { - XBMC->Log(ADDON::LOG_ERROR, "PIN-entering cancelled"); + kodi::Log(ADDON_LOG_ERROR, "PIN-entering cancelled"); return false; } } @@ -1323,3 +1429,5 @@ } } // namespace sledovanitvcz + +ADDONCREATOR(sledovanitvcz::Data) diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/src/Data.h kodi-pvr-sledovanitv-cz-4.4.0/src/Data.h --- kodi-pvr-sledovanitv-cz-1.9.0/src/Data.h 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/src/Data.h 2021-01-09 22:45:25.000000000 +0000 @@ -28,7 +28,7 @@ #define sledovanitvcz_Data_h #include -#include "client.h" +#include "kodi/addon-instance/PVR.h" #include #include "ApiManager.h" #include @@ -136,54 +136,46 @@ typedef std::vector timer_container_t; typedef std::map properties_t; -struct Configuration -{ - std::string userName; - std::string password; - std::string deviceId; //!< device identifier (value for overriding the MAC address detection) - std::string productId; //!< product identifier (value for overriding the hostname detection) - int streamQuality; - int epgMaxDays; - unsigned fullChannelEpgRefresh; //!< delay (seconds) between full channel/EPG refresh - unsigned loadingsRefresh; //!< delay (seconds) between loadings refresh - unsigned keepAliveDelay; //!< delay (seconds) between keepalive calls - unsigned epgCheckDelay; //!< delay (seconds) between checking if EPG load is needed - bool useH265; //!< flag, if h265 codec should be requested - bool useAdaptive; //!< flag, if inpustream.adaptive (aka adaptive bitrate streaming) should be used/requested - bool showLockedChannels; //!< flag, if unavailable/locked channels should be presented - bool showLockedOnlyPin; //!< flag, if PIN-locked only channels should be presented -}; - -class Data +class ATTRIBUTE_HIDDEN Data : public kodi::addon::CAddonBase, + public kodi::addon::CInstancePVRClient { public: - Data(Configuration cfg); + Data(); virtual ~Data(void); - int GetChannelsAmount(void); - PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio); - PVR_ERROR GetChannelStreamUrl(const PVR_CHANNEL* channel, std::string & streamUrl, std::string & streamType); - PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd); - PVR_ERROR IsEPGTagPlayable(const EPG_TAG* tag, bool* bIsPlayable) const; - PVR_ERROR IsEPGTagRecordable(const EPG_TAG* tag, bool* bIsRecordable) const; - PVR_ERROR GetEPGStreamUrl(const EPG_TAG* tag, std::string & streamUrl, std::string & streamType); - PVR_ERROR SetEPGTimeFrame(int iDays); - int GetChannelGroupsAmount(void); - PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio); - PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group); - int GetRecordingsAmount(); - PVR_ERROR GetRecordings(ADDON_HANDLE handle); - PVR_ERROR GetRecordingStreamUrl(const std::string & recording, std::string & streamUrl, std::string & streamType); - void GetRecordingsUrls(); - int GetTimersAmount(); - PVR_ERROR GetTimers(ADDON_HANDLE handle); - PVR_ERROR AddTimer(const PVR_TIMER &timer); - PVR_ERROR DeleteRecord(const std::string &strRecordId); - PVR_ERROR DeleteRecord(int iRecordId); - PVR_ERROR GetDriveSpace(long long *iTotal, long long *iUsed); + ADDON_STATUS Create() override; + ADDON_STATUS SetSetting(const std::string & settingName, const kodi::CSettingValue & settingValue) override; + + PVR_ERROR GetCapabilities(kodi::addon::PVRCapabilities& capabilities) override; + PVR_ERROR GetBackendName(std::string& name) override; + PVR_ERROR GetBackendVersion(std::string& version) override; + PVR_ERROR GetConnectionString(std::string& connection) override; + + PVR_ERROR GetChannelsAmount(int& amount) override; + PVR_ERROR GetChannels(bool radio, kodi::addon::PVRChannelsResultSet& results) override; + PVR_ERROR GetChannelStreamProperties(const kodi::addon::PVRChannel& channel, std::vector& properties) override; + PVR_ERROR GetSignalStatus(int channelUid, kodi::addon::PVRSignalStatus& signalStatus) override; + PVR_ERROR GetEPGForChannel(int channelUid, time_t start, time_t end, kodi::addon::PVREPGTagsResultSet& results) override; + PVR_ERROR IsEPGTagPlayable(const kodi::addon::PVREPGTag& tag, bool& isPlayable) override; + PVR_ERROR IsEPGTagRecordable(const kodi::addon::PVREPGTag& tag, bool& isRecordable) override; + PVR_ERROR GetEPGTagStreamProperties(const kodi::addon::PVREPGTag& tag, std::vector& properties) override; + PVR_ERROR SetEPGMaxFutureDays(int iFutureDays) override; + PVR_ERROR SetEPGMaxPastDays(int iPastDays) override; + PVR_ERROR GetChannelGroupsAmount(int& amount) override; + PVR_ERROR GetChannelGroups(bool radio, kodi::addon::PVRChannelGroupsResultSet& results) override; + PVR_ERROR GetChannelGroupMembers(const kodi::addon::PVRChannelGroup& group, kodi::addon::PVRChannelGroupMembersResultSet& results) override; + PVR_ERROR GetRecordingsAmount(bool deleted, int& amount) override; + PVR_ERROR GetRecordings(bool deleted, kodi::addon::PVRRecordingsResultSet& results) override; + PVR_ERROR DeleteRecording(const kodi::addon::PVRRecording& recording) override; + PVR_ERROR GetRecordingStreamProperties(const kodi::addon::PVRRecording& recording, std::vector& properties) override; + PVR_ERROR GetTimerTypes(std::vector& types) override; + PVR_ERROR GetTimersAmount(int& amount) override; + PVR_ERROR GetTimers(kodi::addon::PVRTimersResultSet& results) override; + PVR_ERROR AddTimer(const kodi::addon::PVRTimer& timer) override; + PVR_ERROR DeleteTimer(const kodi::addon::PVRTimer& timer, bool forceDelete) override; + PVR_ERROR GetDriveSpace(uint64_t& total, uint64_t& used) override; + bool LoggedIn() const; - properties_t StreamProperties(const std::string & url, const std::string & streamType, bool isLive); - bool CurrentStreamIsLive() const; protected: static int ParseDateTime(std::string strDate); @@ -206,6 +198,11 @@ std::string ChannelsList() const; std::string ChannelStreamType(const std::string & channelId) const; bool PinCheckUnlock(bool isPinLocked); + std::vector StreamProperties(const std::string & url, const std::string & streamType, bool isLive) const; + PVR_ERROR GetChannelStreamUrl(const kodi::addon::PVRChannel& channel, std::string & streamUrl, std::string & streamType); + PVR_ERROR GetEPGStreamUrl(const kodi::addon::PVREPGTag& tag, std::string & streamUrl, std::string & streamType); + PVR_ERROR GetRecordingStreamUrl(const std::string & recording, std::string & streamUrl, std::string & streamType); + PVR_ERROR SetEPGMaxDays(int iFutureDays, int iPastDays); protected: void Process(void); @@ -228,24 +225,22 @@ long long m_recordingRecordedDuration; time_t m_epgMinTime; time_t m_epgMaxTime; - int m_epgMaxDays; + int m_epgMaxFutureDays; + int m_epgMaxPastDays; // data used only by "job" thread bool m_bEGPLoaded; time_t m_iLastStart; time_t m_iLastEnd; ApiManager::StreamQuality_t m_streamQuality; - unsigned m_fullChannelEpgRefresh; - unsigned m_loadingsRefresh; - unsigned m_keepAliveDelay; - unsigned m_epgCheckDelay; - bool m_useH265; - bool m_useAdaptive; - bool m_showLockedChannels; - bool m_showLockedOnlyPin; - - // data used only by client(kodi) calling thread - bool m_currentStreamIsLive; + unsigned m_fullChannelEpgRefresh; //!< delay (seconds) between full channel/EPG refresh + unsigned m_loadingsRefresh; //!< delay (seconds) between loadings refresh + unsigned m_keepAliveDelay; //!< delay (seconds) between keepalive calls + unsigned m_epgCheckDelay; //!< delay (seconds) between checking if EPG load is needed + bool m_useH265; //!< flag, if h265 codec should be requested + bool m_useAdaptive; //!< flag, if inpustream.adaptive (aka adaptive bitrate streaming) should be used/requested + bool m_showLockedChannels; //!< flag, if unavailable/locked channels should be presented + bool m_showLockedOnlyPin; //!< flag, if PIN-locked only channels should be presented ApiManager m_manager; }; diff -Nru kodi-pvr-sledovanitv-cz-1.9.0/.travis.yml kodi-pvr-sledovanitv-cz-4.4.0/.travis.yml --- kodi-pvr-sledovanitv-cz-1.9.0/.travis.yml 2020-10-22 10:39:40.000000000 +0000 +++ kodi-pvr-sledovanitv-cz-4.4.0/.travis.yml 2021-01-09 22:45:25.000000000 +0000 @@ -1,7 +1,7 @@ language: cpp # -# Define the build matrix +# Define the builds to get up to date versions of cmake and gcc # env: global: @@ -10,42 +10,45 @@ matrix: include: - os: linux - dist: trusty - addons: - apt: - sources: - - ubuntu-toolchain-r-test - update: true - packages: - - gcc-7 - - g++-7 + dist: bionic + sudo: required compiler: gcc - script: - - CC=gcc-7 CXX=g++-7 make - os: linux - dist: trusty - addons: - apt: - sources: - - ubuntu-toolchain-r-test - update: true - packages: - - gcc-7 - - g++-7 + dist: bionic + sudo: required compiler: clang + - os: linux + dist: bionic + sudo: required + compiler: gcc + env: DEBIAN_BUILD=true + - os: linux + dist: focal + sudo: required + compiler: gcc + env: DEBIAN_BUILD=true - os: osx + osx_image: xcode10.2 + +before_install: + - if [[ $DEBIAN_BUILD == true ]]; then sudo add-apt-repository -y ppa:team-xbmc/xbmc-nightly; fi + - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get update; fi + - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get install fakeroot; fi # # The addon source is automatically checked out in $TRAVIS_BUILD_DIR, # we'll put the Kodi source on the same level # before_script: - - cd $TRAVIS_BUILD_DIR/.. - - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git - - cd ${app_id} && mkdir build && cd build - - mkdir -p definition/${app_id} - - echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt - - if [ "$TRAVIS_OS_NAME" = osx ]; then export OPENSSL_ROOT_DIR='/usr/local/opt/openssl'; fi - - cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons + - if [[ $DEBIAN_BUILD != true ]]; then cd $TRAVIS_BUILD_DIR/..; fi + - if [[ $DEBIAN_BUILD != true ]]; then git clone --branch master --depth=1 https://github.com/xbmc/xbmc.git; fi + - if [[ $DEBIAN_BUILD != true ]]; then cd ${app_id} && mkdir build && cd build; fi + - if [[ $DEBIAN_BUILD != true ]]; then mkdir -p definition/${app_id}; fi + - if [[ $DEBIAN_BUILD != true ]]; then echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt; fi + - if [[ $DEBIAN_BUILD != true ]]; then cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons; fi + - if [[ $DEBIAN_BUILD == true ]]; then wget https://raw.githubusercontent.com/xbmc/xbmc/master/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh && chmod +x ./debian-addon-package-test.sh; fi + - if [[ $DEBIAN_BUILD == true ]]; then sudo apt-get build-dep $TRAVIS_BUILD_DIR; fi -script: make +script: + - if [[ $DEBIAN_BUILD != true ]]; then make; fi + - if [[ $DEBIAN_BUILD == true ]]; then ./debian-addon-package-test.sh $TRAVIS_BUILD_DIR; fi