mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-28 21:26:49 +00:00
NextPVR: add new addon package
NextPVR 6.1.1 for netcore 6.0
This commit is contained in:
parent
c73c0302e4
commit
722c84c87f
17
licenses/NextPVR.txt
Normal file
17
licenses/NextPVR.txt
Normal 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.
|
2
packages/addons/service/nextpvr/changelog.txt
Normal file
2
packages/addons/service/nextpvr/changelog.txt
Normal file
@ -0,0 +1,2 @@
|
||||
100
|
||||
- Initial commit
|
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.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"
|
||||
}
|
233
packages/addons/service/nextpvr/source/addon.py
Normal file
233
packages/addons/service/nextpvr/source/addon.py
Normal 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
|
@ -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