From 722c84c87f0901beefa0dc70fab55a9ba9bdcd5a Mon Sep 17 00:00:00 2001 From: emveepee Date: Sat, 15 Oct 2022 16:23:29 -0400 Subject: [PATCH] NextPVR: add new addon package NextPVR 6.1.1 for netcore 6.0 --- licenses/NextPVR.txt | 17 ++ packages/addons/service/nextpvr/changelog.txt | 2 + packages/addons/service/nextpvr/icon/icon.png | Bin 0 -> 37713 bytes packages/addons/service/nextpvr/package.mk | 28 +++ .../addons/service/nextpvr/source/addon.py | 233 ++++++++++++++++++ .../nextpvr/source/bin/nextpvr-downloader | 76 ++++++ .../service/nextpvr/source/bin/nextpvr.start | 26 ++ .../addons/service/nextpvr/source/default.py | 16 ++ .../resources/Language/English/strings.po | 142 +++++++++++ .../nextpvr/source/resources/settings.xml | 81 ++++++ .../source/system.d/service.nextpvr.service | 13 + 11 files changed, 634 insertions(+) create mode 100644 licenses/NextPVR.txt create mode 100644 packages/addons/service/nextpvr/changelog.txt create mode 100644 packages/addons/service/nextpvr/icon/icon.png create mode 100644 packages/addons/service/nextpvr/package.mk create mode 100644 packages/addons/service/nextpvr/source/addon.py create mode 100644 packages/addons/service/nextpvr/source/bin/nextpvr-downloader create mode 100644 packages/addons/service/nextpvr/source/bin/nextpvr.start create mode 100644 packages/addons/service/nextpvr/source/default.py create mode 100644 packages/addons/service/nextpvr/source/resources/Language/English/strings.po create mode 100644 packages/addons/service/nextpvr/source/resources/settings.xml create mode 100644 packages/addons/service/nextpvr/source/system.d/service.nextpvr.service diff --git a/licenses/NextPVR.txt b/licenses/NextPVR.txt new file mode 100644 index 0000000000..8e3c67bd49 --- /dev/null +++ b/licenses/NextPVR.txt @@ -0,0 +1,17 @@ +Software License Agreement for NextPVR + +IMPORTANT- PLEASE READ CAREFULLY BEFORE USING THIS SOFTWARE: THIS LICENSE AGREEMENT FOR NextPVR ("LICENSE AGREEMENT") IS A LEGAL AGREEMENT BETWEEN YOU (EITHER ON BEHALF OF YOURSELF AS AN INDIVIDUAL OR ON BEHALF OF AN ENTITY AS ITS AUTHORIZED REPRESENTATIVE) AND PINSTRIPE LIMITED. FOR THE NextPVR SOFTWARE ("SOFTWARE"). THIS LICENSE AGREEMENT FOR NextPVR SUPERSEDES PREVIOUS VERSIONS. BY INSTALLING THE SOFTWARE (AS DEFINED BELOW), COPYING OR OTHERWISE USING THE SOFTWARE YOU AGREE TO BE BOUND BY ALL OF THE TERMS OF THIS END USER LICENSE AGREEMENT REGARDING YOUR USE OF THE SOFTWARE. IF YOU DO NOT AGREE TO THE TERMS OF THIS LICENSE AGREEMENT, UNINSTALL THE SOFTWARE, AND DO NOT COPY OR OTHERWISE USE THE SOFTWARE. + +GRANT OF LICENSE: Subject to the following terms, PINSTRIPE LIMITED hereby grants you a non-exclusive, perpetual, non-transferable license to install and to use the NextPVR software ("Software") for personal, non-commercial use. You may copy the Software for back-up or archival purposes. + +LICENSE RESTRICTIONS: You may not: (i) reverse engineer, decompile, or disassemble the Software; (ii) modify, or create derivative works based upon, the Software in whole or in part; (iii) distribute copies of the Software; (iv) remove any proprietary notices or labels on the Software; or (v) resell, lease, rent, transfer, sublicense, or otherwise transfer rights to the Software. You agree that the NextPVR software will not be used for commercial purposes without full written permission. Any such forbidden use shall immediately terminate your license to the software. + +TITLE: You agree that no title to the intellectual property in the Software is transferred to you. Title, ownership, rights, and intellectual property rights in and to the Software shall remain in PINSTRIPE LIMITED. + +UPDATES: From time to time, PINSTRIPE LIMITED may make updates to the Software generally available. You may download and install these software updates released by PINSTRIPE LIMITED. All updates to the Software shall be governed by this Agreement, unless other license terms are provided with the update. Under the Software's default configuration, if you are connected to the Internet, the Software is enabled by default to query latest version of Software and display if updates are available. You may choose to switch this version check off and not use it. + +TECHNICAL SUPPORT: Technical support for the software, as made available by PINSTRIPE LIMITED, is available on the web site at: http://www.nextpvr.com + +DISCLAIMER OF WARRANTY: The Software is provided to you at minimal charge. ACCORDINGLY, YOU AGREE THAT PINSTRIPE LIMITED HAS MADE NO EXPRESS WARRANTIES, ORAL OR WRITTEN, TO YOU REGARDING THE SOFTWARE AND THAT THE SOFTWARE IS BEING PROVIDED TO YOU "AS IS" WITHOUT WARRANTY OF ANY KIND. PINSTRIPE LIMITED DISCLAIMS ANY AND ALL OTHER WARRANTIES, WHETHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF NONINFRINGEMENT OF THIRD PARTY RIGHTS, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. PINSTRIPE LIMITED SHALL NOT BE LIABLE FOR INDIRECT, INCIDENTAL, SPECIAL, COVER, RELIANCE, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF ANTICIPATED PROFIT) ARISING FROM ANY CAUSE UNDER OR RELATED TO THIS AGREEMENT. + +LIMITATION OF LIABILITY: You must assume the entire risk of using the program. IN NO EVENT SHALL PINSTRIPE LIMITED BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST PROFITS, LOST SAVINGS, OR OTHER INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND ARISING OUT OF THE USE OF THE PINSTRIPE LIMITED SOFTWARE, EVEN IF PINSTRIPE LIMITED HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO EVENT WILL PINSTRIPE LIMITED'S LIABILITY FOR ANY CLAIM, WHETHER IN CONTRACT, TORT, OR ANY OTHER THEORY OF LIABILITY, EXCEED THE LICENSE FEE PAID BY YOU, PROVIDED, HOWEVER, IF THE RELEVANT SOFTWARE WAS PROVIDED TO YOU AT NO CHARGE YOU AGREE PINSTRIPE LIMITED SHALL NOT BE LIABLE TO YOU FOR ANY DAMAGES. THIS LIMITATION SHALL APPLY TO CLAIMS OF PERSONAL INJURY TO THE EXTENT PERMITTED BY LAW. diff --git a/packages/addons/service/nextpvr/changelog.txt b/packages/addons/service/nextpvr/changelog.txt new file mode 100644 index 0000000000..f2fb51e77c --- /dev/null +++ b/packages/addons/service/nextpvr/changelog.txt @@ -0,0 +1,2 @@ +100 +- Initial commit diff --git a/packages/addons/service/nextpvr/icon/icon.png b/packages/addons/service/nextpvr/icon/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ebc1f8b5212db9ebd4f44b45b1a3e3d4b2fcb360 GIT binary patch literal 37713 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 aw>IcJs_7_IFW3Tpzg)fbbJ=CrNB;$hu5va2 literal 0 HcmV?d00001 diff --git a/packages/addons/service/nextpvr/package.mk b/packages/addons/service/nextpvr/package.mk new file mode 100644 index 0000000000..8f033643f7 --- /dev/null +++ b/packages/addons/service/nextpvr/package.mk @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="nextpvr" +PKG_VERSION="6.1.1~Matrix" +PKG_ADDON_VERSION="6.1.1" +PKG_REV="100" +PKG_ARCH="any" +PKG_LICENSE="NextPVR" +PKG_SITE="https://nextpvr.com" +PKG_DEPENDS_TARGET="toolchain" +PKG_SECTION="service" +PKG_SHORTDESC="NextPVR Server" +PKG_LONGDESC="NextPVR is a personal video recorder application. It allows to watch or record live TV, provides great features like series recordings and web scheduling." +PKG_TOOLCHAIN="manual" + +PKG_IS_ADDON="yes" +PKG_ADDON_NAME="NextPVR Server" +PKG_ADDON_TYPE="xbmc.service.library" +PKG_ADDON_REQUIRES="tools.ffmpeg-tools:0.0.0 tools.dotnet-runtime:0.0.0 script.module.requests:0.0.0" + +addon() { + : +} + +post_install_addon() { + sed -e "s/@NEXTPVR_VERSION@/${PKG_ADDON_VERSION}/g" -i "${INSTALL}/bin/nextpvr-downloader" +} diff --git a/packages/addons/service/nextpvr/source/addon.py b/packages/addons/service/nextpvr/source/addon.py new file mode 100644 index 0000000000..e2aa59d41d --- /dev/null +++ b/packages/addons/service/nextpvr/source/addon.py @@ -0,0 +1,233 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2022-present Team LibreELEC (https://libreelec.tv) + +import urllib.request, urllib.parse, urllib.error, os, zipfile +from urllib.error import URLError +import urllib.parse as urlparse +import requests +import json +import subprocess + +from urllib.parse import parse_qs +import xbmc, xbmcvfs, xbmcgui, xbmcaddon +import shutil +import sys +import xml.etree.ElementTree as ET + +temp = xbmcvfs.translatePath('special://temp') + +ADDON_NAME = xbmcaddon.Addon().getAddonInfo('name') +LS = xbmcaddon.Addon().getLocalizedString + +# Ignore isbn tables +SCANTABLES = ['atsc', 'dvb-c', 'dvb-s', 'dvb-t'] +GENERIC_URL = 'https://nextpvr.com/stable/linux/NPVR.zip' + +class Controller(): + + def __init__(self): + pass + + def downloadScanTable(self): + # Taken from TVHeadend Addon + try: + url = 'https://github.com/tvheadend/dtv-scan-tables/archive/tvheadend.zip' + archive = os.path.join(temp, 'dtv_scantables.zip') + temp_folder = os.path.join(temp, 'dtv-scan-tables-tvheadend') + dest_folder = os.path.join(xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('path')), 'dtv-scan-tables') + + xbmcgui.Dialog().notification(ADDON_NAME, LS(30042), xbmcgui.NOTIFICATION_INFO) + urllib.request.urlretrieve(url, archive) + zip = zipfile.ZipFile(archive) + if zip.testzip() is not None: raise zipfile.BadZipfile + + if os.path.exists(temp_folder): shutil.rmtree(temp_folder) + if os.path.exists(dest_folder): shutil.rmtree(dest_folder) + + xbmcgui.Dialog().notification(ADDON_NAME, LS(30043), xbmcgui.NOTIFICATION_INFO) + for idx, folder in enumerate(SCANTABLES): + for z in zip.filelist: + if folder in z.filename: zip.extract(z.filename, temp) + + for folder in SCANTABLES: + shutil.copytree(os.path.join(temp_folder, folder), os.path.join(dest_folder, folder)) + if os.path.exists(temp_folder): shutil.rmtree(temp_folder) + os.remove(archive) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30039), xbmcgui.NOTIFICATION_INFO) + except URLError as e: + xbmc.log('Could not download file: %s' % e.reason, xbmc.LOGERROR) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30040), xbmcgui.NOTIFICATION_ERROR) + except zipfile.BadZipfile: + xbmc.log('Could not extract files from zip, bad zipfile', xbmc.LOGERROR) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30041), xbmcgui.NOTIFICATION_ERROR) + + def updateNextPVR(self): + try: + dest_folder = os.path.join(xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('path')), 'nextpvr-bin') + archive = os.path.join(temp, 'NPVR.zip') + xbmcgui.Dialog().notification(ADDON_NAME, LS(30011), xbmcgui.NOTIFICATION_INFO) + urllib.request.urlretrieve(GENERIC_URL, archive) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30012), xbmcgui.NOTIFICATION_INFO) + zip = zipfile.ZipFile(archive) + if zip.testzip() is not None: raise zipfile.BadZipfile + zip.close() + command = 'unzip -o {0} -d {1} > /dev/null'.format(archive, dest_folder) + xbmc.log('Running: %s' % command, xbmc.LOGDEBUG) + os.system(command) + os.remove(archive) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30039), xbmcgui.NOTIFICATION_INFO) + xbmc.log('NPVR.zip installed', xbmc.LOGDEBUG) + if xbmcgui.Dialog().yesno("NextPVR Server", LS(30020)): + self.id = xbmcaddon.Addon().getAddonInfo('id') + subprocess.call(['systemctl', 'restart', self.id]) + + except URLError as e: + xbmc.log('Could not download file: %s' % e.reason, xbmc.LOGERROR) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30040), xbmcgui.NOTIFICATION_ERROR) + except zipfile.BadZipfile: + xbmc.log('Could not extract files from zip, bad zipfile', xbmc.LOGERROR) + xbmcgui.Dialog().notification(ADDON_NAME, LS(30041), xbmcgui.NOTIFICATION_ERROR) + + def sessionLogin(self): + self.session = requests.session() + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' + } + response = self.session.get(self.url, headers=headers) + parsed = urlparse.urlparse(response.url) + salt = parse_qs(parsed.query)['salt'][0] + if self.hashedPassword == None: + passwordHash = self.hashMe(self.password) + else: + passwordHash = self.hashedPassword + combined = self.hashMe(salt + ':' + self.username + ':' + passwordHash) + response = self.session.get(self.url + 'login.html?hash='+combined) + if response.status_code != 200 and response.status_code != 302 : + print(response.text, response.status_code) + sys.exit() + for cookie in self.session.cookies: + self.session.cookies[cookie.name] = cookie.value + + def doSessionRequest5(self, method, isJSON = True): + xbmc.log(method, xbmc.LOGDEBUG) + retval = False + getResult = None + url = self.url + 'service?method=' + method + try: + request = self.session.get(url, headers={"Accept" : "application/json"}) + getResult = json.loads(request.text) + if request.status_code == 200 : + if 'stat' in getResult: + retval = getResult['stat'] == 'ok' + else: + retval = True + else: + xbmc.log(getResult, xbmc.LOGERROR) + + except Exception as e: + xbmc.log(str(e), xbmc.LOGERROR) + + return retval, getResult + + def hashMe (self, thedata): + import hashlib + h = hashlib.md5() + h.update(thedata.encode('utf-8')) + return h.hexdigest() + + def loginNextPVR(self): + base = os.path.join(xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')), 'config/config.xml') + tree = ET.parse(base) + root = tree.getroot() + child = root.find("WebServer") + self.port = child.find('Port').text + self.username = child.find('Username').text + self.hashedPIN = child.find('PinMD5').text + self.hashedPassword = child.find('Password').text.lower() + self.ip = '127.0.0.1' + self.url = 'http://{}:{}/'.format(self.ip, self.port) + self.sessionLogin() + + + def showMessage(self, message): + xbmc.log(message, xbmc.LOGDEBUG) + xbmcgui.Dialog().notification(ADDON_NAME, message, xbmcgui.NOTIFICATION_INFO) + + + def updateEpg(self): + self.loginNextPVR() + self.doSessionRequest5('system.epg.update') + self.doSessionRequest5('session.logout') + self.showMessage(LS(30015)) + + def updateM3u(self): + self.loginNextPVR() + self.doSessionRequest5('setting.m3u.update') + self.doSessionRequest5('session.logout') + self.showMessage(LS(30016)) + + def rescanDevices(self): + self.loginNextPVR() + self.doSessionRequest5('setting.devices&refresh=true') + self.doSessionRequest5('session.logout') + self.showMessage(LS(30017)) + + def transcodeHLS(self): + base = os.path.join(xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')), 'config/config.xml') + tree = ET.parse(base) + parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True)) + tree = ET.parse(base, parser=parser) + root = tree.getroot() + parent = root.find("WebServer") + child = parent.find('TranscodeHLS') + if child.text == 'default': + child.text = '-y [ANALYZE_DURATION] [SEEK] -i [SOURCE] -map_metadata -1 -threads [THREADS] -ignore_unknown -map 0:v:0? [PREFERRED_LANGUAGE] -map 0:a:[AUDIO_STREAM] -map -0:s -vcodec copy -acodec aac -ac 2 -c:s copy -hls_time [SEGMENT_DURATION] -start_number 0 -hls_list_size [SEGMENT_COUNT] -y [TARGET]' + else: + child.text = 'default' + tree.write(base, encoding='utf-8') + + if child.text == 'default': + self.showMessage(LS(30018)) + else: + self.showMessage(LS(30019)) + + def resetWebCredentials(self): + rewrite = False + base = os.path.join(xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile')), 'config/config.xml') + tree = ET.parse(base) + parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True)) + tree = ET.parse(base, parser=parser) + root = tree.getroot() + parent = root.find("WebServer") + child = parent.find('Username') + if child.text != 'admin': + child.text = 'admin' + rewrite = True + child = parent.find('Password') + if child.text != '5f4dcc3b5aa765d61d8327deb882cf99': + child.text = '5f4dcc3b5aa765d61d8327deb882cf99' + rewrite = True + if rewrite: + tree.write(base, encoding='utf-8') + self.showMessage(LS(30046)) + + +if __name__ == '__main__': + option = Controller() + try: + if sys.argv[1] == 'getscantables': + option.downloadScanTable() + elif sys.argv[1] == 'updategeneric': + option.updateNextPVR() + elif sys.argv[1] == 'updateepg': + option.updateEpg() + elif sys.argv[1] == 'transcode': + option.transcodeHLS() + elif sys.argv[1] == 'updatem3u': + option.updateM3u() + elif sys.argv[1] == 'rescan': + option.rescanDevices() + elif sys.argv[1] == 'defaults': + option.resetWebCredentials() + except IndexError: + pass diff --git a/packages/addons/service/nextpvr/source/bin/nextpvr-downloader b/packages/addons/service/nextpvr/source/bin/nextpvr-downloader new file mode 100644 index 0000000000..803538469f --- /dev/null +++ b/packages/addons/service/nextpvr/source/bin/nextpvr-downloader @@ -0,0 +1,76 @@ +#!/bin/bash + +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) + +. /etc/profile +oe_setup_addon service.nextpvr + +ICON="${ADDON_DIR}/resources/icon.png" +CONTROL_FILE="/tmp/curl.nextpvr.done" +DATA_FILE="/tmp/curl.nextpvr.data" +NEXTPVR_FILE="NPVR-@NEXTPVR_VERSION@.zip" + +# check for enough free disk space +if [ $(df . | awk 'END {print $4}') -lt 400000 ]; then + kodi-send --action="Notification(Not enough disk space, at least 400MB are required,30000,${ICON})" >/dev/null + exit 0 +fi + +# remove install status and folders +if [ -f ${ADDON_DIR}/extract.ok ]; then + rm ${ADDON_DIR}/extract.ok +fi + +if [ -d ${ADDON_DIR}/nextpvr-bin ]; then + rm -rf ${ADDON_DIR}/nextpvr-bin +fi + +if [ -d ${ADDON_DIR}/tmp_download ]; then + rm -rf ${ADDON_DIR}/tmp_download +fi + +# create tmp download dir +mkdir -p ${ADDON_DIR}/tmp_download +cd ${ADDON_DIR}/tmp_download + +echo "Downloading NextPVR" + +# download NextPVR +rm -f ${CONTROL_FILE} ${DATA_FILE} +( + curl -# -O -C - https://nextpvr.com/stable/linux/${NEXTPVR_FILE} 2>${DATA_FILE} + touch ${CONTROL_FILE} +) | + while [ : ]; do + [ -f ${DATA_FILE} ] && prog="$(tr '\r' '\n' <${DATA_FILE} | tail -n 1 | sed -r 's/^[# ]+/#/;s/^[^0-9]*//g')" || prog= + kodi-send --action="Notification(Downloading NextPVR,\"${prog:-0.0%}\",3000,${ICON})" >/dev/null + [ -f ${CONTROL_FILE} ] && break + sleep 4 + done + +rm -f ${CONTROL_FILE} ${DATA_FILE} + +# check for failed download +if [ ! -f ${NEXTPVR_FILE} ]; then + kodi-send --action="Notification(Download NextPVR failed,${ICON})" + exit 1 +fi + +# extract NextPVR +kodi-send --action="Notification(Extracting NextPVR,starting,1000,${ICON})" >/dev/null +mkdir -p ${ADDON_DIR}/nextpvr-bin +unzip ${NEXTPVR_FILE} -d ${ADDON_DIR}/nextpvr-bin >/dev/null + +if [ "$(uname -m)" != "x86_64" ]; then + sed -i 's/default<\/TranscodeHLS>/-y [ANALYZE_DURATION] [SEEK] -i [SOURCE] -map_metadata -1 -threads [THREADS] -ignore_unknown -map 0:v:0? [PREFERRED_LANGUAGE] -map 0:a:[AUDIO_STREAM] -map -0:s -vcodec copy -acodec aac -ac 2 -c:s copy -hls_time [SEGMENT_DURATION] -start_number 0 -hls_list_size [SEGMENT_COUNT] -y [TARGET]<\/TranscodeHLS>/' ${ADDON_DIR}/nextpvr-bin/data/Config-master-dont-edit.xml +fi +sed -i 's/C:\\Users\\Public\\Videos\\<\/RecordingDirectory>/\/storage\/tvshows\/<\/RecordingDirectory>/' ${ADDON_DIR}/nextpvr-bin/data/Config-master-dont-edit.xml +sed -i 's/C:\\Users\\Public\\Videos\\<\/LiveTVBufferDirectory>/\/tmp\/<\/LiveTVBufferDirectory>/' ${ADDON_DIR}/nextpvr-bin/data/Config-master-dont-edit.xml +find ${ADDON_DIR}/nextpvr-bin/DeviceHost -name DeviceHostLinux -exec chmod 755 {} \; + +# cleanup +cd ${ADDON_DIR} +rm -rf ${ADDON_DIR}/tmp_download +touch ${ADDON_DIR}/extract.ok +kodi-send --action="Notification(Extracting NextPVR,finished,1000,${ICON})" >/dev/null diff --git a/packages/addons/service/nextpvr/source/bin/nextpvr.start b/packages/addons/service/nextpvr/source/bin/nextpvr.start new file mode 100644 index 0000000000..ec63d336db --- /dev/null +++ b/packages/addons/service/nextpvr/source/bin/nextpvr.start @@ -0,0 +1,26 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) + +. /etc/profile +oe_setup_addon service.nextpvr + +# check if nextpvr-server is already successful installed +if [ ! -f "${ADDON_DIR}/extract.ok" ]; then + cd ${ADDON_DIR} + nextpvr-downloader +fi + +export NEXTPVR_DATADIR_USERDATA=${ADDON_HOME}/config/ +export NEXTPVR_DVBDIR=${ADDON_DIR}/dtv-scan-tables/ + +export SATIP_RTSP_PORT=$satiprtsp + +read -d. uptime < /proc/uptime +startdelay=$((waitfor-uptime)) +if [ $startdelay -gt 0 ]; then + sleep $startdelay +fi + +cd ${ADDON_DIR}/nextpvr-bin +exec dotnet ${ADDON_DIR}/nextpvr-bin/NextPVRServer.dll >/dev/null diff --git a/packages/addons/service/nextpvr/source/default.py b/packages/addons/service/nextpvr/source/default.py new file mode 100644 index 0000000000..5119bb652c --- /dev/null +++ b/packages/addons/service/nextpvr/source/default.py @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) + +import xbmc +import xbmcaddon + +class Monitor(xbmc.Monitor): + + def __init__(self, *args, **kwargs): + xbmc.Monitor.__init__(self) + + def onSettingsChanged(self): + pass + +if __name__ == "__main__": + Monitor().waitForAbort() diff --git a/packages/addons/service/nextpvr/source/resources/Language/English/strings.po b/packages/addons/service/nextpvr/source/resources/Language/English/strings.po new file mode 100644 index 0000000000..498927074f --- /dev/null +++ b/packages/addons/service/nextpvr/source/resources/Language/English/strings.po @@ -0,0 +1,142 @@ +# Kodi Media Center language file +# Addon Name: nextpvr +# Addon id: service.nextpvr +# Addon Provider: Team LibreELEC +msgid "" +msgstr "" + +msgctxt "#30001" +msgid "Download" +msgstr "" + +msgctxt "#30002" +msgid "Download current Linux NPVR.zip" +msgstr "" + +msgctxt "#30003" +msgid "Check the NextPVR forum before updating" +msgstr "" + +msgctxt "#30004" +msgid "Manage Server" +msgstr "" + +msgctxt "#30005" +msgid "Update guide" +msgstr "" + +msgctxt "#30006" +msgid "Start an unscheduled EPG update" +msgstr "" + +msgctxt "#30007" +msgid "Update IPTV m3u source" +msgstr "" + +msgctxt "#30008" +msgid "Rescan m3u file(s) and update URLs" +msgstr "" + +msgctxt "#30009" +msgid "Toggle custom HLS transcoding with default" +msgstr "" + +msgctxt "#30010" +msgid "Change HLS transcoding mode, default will not work on all platforms" +msgstr "" + +msgctxt "#30011" +msgid "Download NPVR.zip" +msgstr "" + +msgctxt "#30012" +msgid "Extract NPVR.zip" +msgstr "" + +msgctxt "#30013" +msgid "Rescan tuning devices" +msgstr "" + +msgctxt "#30014" +msgid "Rescan for tuner changes after start-up" +msgstr "" + +msgctxt "#30015" +msgid "Update EPG started" +msgstr "" + +msgctxt "#30016" +msgid "Update m3u started" +msgstr "" + +msgctxt "#30017" +msgid "Device refresh started" +msgstr "" + +msgctxt "#30018" +msgid "Transcode set to default" +msgstr "" + +msgctxt "#30019" +msgid "Transcode set to custom" +msgstr "" + +msgctxt "#30020" +msgid "Restart server now" +msgstr "" + +msgctxt "#30037" +msgid "Install the frequency scanning table for digital devices" +msgstr "" + +msgctxt "#30038" +msgid "Download and install Scan-Tables" +msgstr "" + +msgctxt "#30039" +msgid "Download completed and installed" +msgstr "" + +msgctxt "#30040" +msgid "Could not download zip file" +msgstr "" + +msgctxt "#30041" +msgid "Could not extract zip file" +msgstr "" + +msgctxt "#30042" +msgid "Download Scan-Tables" +msgstr "" + +msgctxt "#30043" +msgid "Extract Scan-Tables" +msgstr "" + +msgctxt "#30044" +msgid "Reset web server credentials" +msgstr "" + +msgctxt "#30045" +msgid "Reset to defaults Username: admin Password: password" +msgstr "" + +msgctxt "#30046" +msgid "Set Username: admin Password: password" +msgstr "" + +msgctxt "#30047" +msgid "SAT>IP RTSP port" +msgstr "" + +msgctxt "#30048" +msgid "Default is 554 - TVHeadend uses 9983" +msgstr "" + +msgctxt "#30049" +msgid "Startup uptime wait" +msgstr "" + +msgctxt "#30050" +msgid "Delay service launch on boot to specified uptime (seconds)" +msgstr "" diff --git a/packages/addons/service/nextpvr/source/resources/settings.xml b/packages/addons/service/nextpvr/source/resources/settings.xml new file mode 100644 index 0000000000..03ad6c7d86 --- /dev/null +++ b/packages/addons/service/nextpvr/source/resources/settings.xml @@ -0,0 +1,81 @@ + + +
+ + + + 0 + RunScript(service.nextpvr, getscantables) + + false + + + + 2 + RunScript(service.nextpvr, updategeneric) + + false + + + + + + + + 1 + 5 + + 5 + 1 + 60 + + + false + + + + 1 + RunScript(service.nextpvr, updateepg) + + false + + + + 3 + RunScript(service.nextpvr, updatem3u) + + false + + + + 2 + RunScript(service.nextpvr, rescan) + + false + + + + 3 + RunScript(service.nextpvr, transcode) + + false + + + + 3 + RunScript(service.nextpvr, defaults) + + false + + + + 1 + 554 + + 30047 + + + + +
+
diff --git a/packages/addons/service/nextpvr/source/system.d/service.nextpvr.service b/packages/addons/service/nextpvr/source/system.d/service.nextpvr.service new file mode 100644 index 0000000000..3603ac3558 --- /dev/null +++ b/packages/addons/service/nextpvr/source/system.d/service.nextpvr.service @@ -0,0 +1,13 @@ +[Unit] +Description=NextPVR Server +Documentation=https://nextpvr.com +Wants=multi-user.target +After=multi-user.target + +[Service] +SyslogIdentifier=%N +ExecStart=/bin/sh /storage/.kodi/addons/%N/bin/nextpvr.start +Restart=always + +[Install] +WantedBy=multi-user.target