NextPVR: add new addon package

NextPVR 6.1.1 for netcore 6.0
This commit is contained in:
emveepee 2022-10-15 16:23:29 -04:00
parent c73c0302e4
commit 722c84c87f
11 changed files with 634 additions and 0 deletions

17
licenses/NextPVR.txt Normal file
View File

@ -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.

View File

@ -0,0 +1,2 @@
100
- Initial commit

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -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"
}

View File

@ -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

View File

@ -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/<TranscodeHLS>default<\/TranscodeHLS>/<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/<RecordingDirectory>C:\\Users\\Public\\Videos\\<\/RecordingDirectory>/<RecordingDirectory>\/storage\/tvshows\/<\/RecordingDirectory>/' ${ADDON_DIR}/nextpvr-bin/data/Config-master-dont-edit.xml
sed -i 's/<LiveTVBufferDirectory>C:\\Users\\Public\\Videos\\<\/LiveTVBufferDirectory>/<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

View File

@ -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

View File

@ -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()

View File

@ -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 ""

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings version="1">
<section id="service.nextpvr">
<category id="download" label="30001">
<group id="0">
<setting id="scantable" type="action" label="30038" help="30037">
<level>0</level>
<data>RunScript(service.nextpvr, getscantables)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
<setting id="update" type="action" label="30002" help="30003">
<level>2</level>
<data>RunScript(service.nextpvr, updategeneric)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
</group>
</category>
<category id="control" label="30004">
<group id="0">
<setting id="waitfor" type="integer" label="30049" help="30050">
<level>1</level>
<default>5</default>
<constraints>
<minimum>5</minimum>
<step>1</step>
<maximum>60</maximum>
</constraints>
<control type="slider" format="integer">
<popup>false</popup>
</control>
</setting>
<setting id="updateepg" type="action" label="30005" help="30006">
<level>1</level>
<data>RunScript(service.nextpvr, updateepg)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
<setting id="updatem3u" type="action" label="30007" help="30008">
<level>3</level>
<data>RunScript(service.nextpvr, updatem3u)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
<setting id="rescan" type="action" label="30013" help="30014">
<level>2</level>
<data>RunScript(service.nextpvr, rescan)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
<setting id="transcode" type="action" label="30009" help="30010">
<level>3</level>
<data>RunScript(service.nextpvr, transcode)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
<setting id="defaults" type="action" label="30044" help="30045">
<level>3</level>
<data>RunScript(service.nextpvr, defaults)</data>
<control type="button" format="action">
<close>false</close>
</control>
</setting>
<setting id="satiprtsp" type="integer" label="30047" help="30048">
<level>1</level>
<default>554</default>
<control type="edit" format="integer">
<heading>30047</heading>
</control>
</setting>
</group>
</category>
</section>
</settings>

View File

@ -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