mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-28 21:26:49 +00:00
Merge pull request #6853 from emveepee/addnextpvr
[le11] NextPVR: add new addon package
This commit is contained in:
commit
ecfb0581f2
2
packages/addons/service/nextpvr/changelog.txt
Normal file
2
packages/addons/service/nextpvr/changelog.txt
Normal file
@ -0,0 +1,2 @@
|
||||
100
|
||||
- Initial release
|
BIN
packages/addons/service/nextpvr/icon/icon.png
Normal file
BIN
packages/addons/service/nextpvr/icon/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
28
packages/addons/service/nextpvr/package.mk
Normal file
28
packages/addons/service/nextpvr/package.mk
Normal 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.0~Nexus"
|
||||
PKG_ADDON_VERSION="6.1.0"
|
||||
PKG_REV="100"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="prop."
|
||||
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"
|
||||
}
|
232
packages/addons/service/nextpvr/source/addon.py
Normal file
232
packages/addons/service/nextpvr/source/addon.py
Normal file
@ -0,0 +1,232 @@
|
||||
# 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))
|
||||
|
||||
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
|
@ -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
|
26
packages/addons/service/nextpvr/source/bin/nextpvr.start
Normal file
26
packages/addons/service/nextpvr/source/bin/nextpvr.start
Normal 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
|
16
packages/addons/service/nextpvr/source/default.py
Normal file
16
packages/addons/service/nextpvr/source/default.py
Normal 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()
|
@ -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 ""
|
@ -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>
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user