mirror of
https://github.com/fHDHR/fHDHR_NextPVR.git
synced 2025-12-06 17:26:57 -05:00
Merge pull request #9 from deathbybandaid/dev
Replicate changes in the Locast repo
This commit is contained in:
commit
63590a1d9a
24
data/internal_config/fakehdhr.ini
Normal file
24
data/internal_config/fakehdhr.ini
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[main]
|
||||||
|
uuid = fHDHR_None
|
||||||
|
cache_dir = fHDHR_None
|
||||||
|
|
||||||
|
[empty]
|
||||||
|
epg_update_frequency = 43200
|
||||||
|
|
||||||
|
[fakehdhr]
|
||||||
|
address = 0.0.0.0
|
||||||
|
port = 5004
|
||||||
|
discovery_address = 0.0.0.0
|
||||||
|
|
||||||
|
[ffmpeg]
|
||||||
|
ffmpeg_path = ffmpeg
|
||||||
|
bytes_per_read = 1152000
|
||||||
|
|
||||||
|
[direct_stream]
|
||||||
|
chunksize = 1048576
|
||||||
|
|
||||||
|
[dev]
|
||||||
|
reporting_model = HDHR4-2DT
|
||||||
|
reporting_firmware_name = hdhomerun4_dvbt
|
||||||
|
reporting_firmware_ver = 20150826
|
||||||
|
reporting_tuner_type = Antenna
|
||||||
35
data/internal_config/serviceconf.ini
Normal file
35
data/internal_config/serviceconf.ini
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[main]
|
||||||
|
servicename = NextPVR
|
||||||
|
dictpopname = nextpvr
|
||||||
|
credentials = pin
|
||||||
|
reponame = FakeHDHR_NextPVR
|
||||||
|
|
||||||
|
[fakehdhr]
|
||||||
|
friendlyname = fHDHR-NextPVR
|
||||||
|
stream_type = direct
|
||||||
|
epg_method = proxy
|
||||||
|
tuner_count = 4
|
||||||
|
|
||||||
|
[nextpvr]
|
||||||
|
address = localhost
|
||||||
|
port = 8866
|
||||||
|
ssl = fHDHR_False
|
||||||
|
pin = fHDHR_None
|
||||||
|
weight = 300
|
||||||
|
sidfile = fHDHR_None
|
||||||
|
epg_update_frequency = 43200
|
||||||
|
|
||||||
|
[zap2it]
|
||||||
|
delay = 5
|
||||||
|
postalcode = fHDHR_None
|
||||||
|
affiliate_id = gapzap
|
||||||
|
country = USA
|
||||||
|
device = -
|
||||||
|
headendid = lineupId
|
||||||
|
isoverride = True
|
||||||
|
languagecode = en
|
||||||
|
pref =
|
||||||
|
timespan = 6
|
||||||
|
timezone =
|
||||||
|
userid = -
|
||||||
|
epg_update_frequency = 43200
|
||||||
@ -2,11 +2,9 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import json
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from . import zap2it
|
from . import epgtypes
|
||||||
from . import emptyepg
|
|
||||||
|
|
||||||
|
|
||||||
def sub_el(parent, name, text=None, **kwargs):
|
def sub_el(parent, name, text=None, **kwargs):
|
||||||
@ -26,40 +24,20 @@ class EPGhandler():
|
|||||||
|
|
||||||
def __init__(self, config, serviceproxy):
|
def __init__(self, config, serviceproxy):
|
||||||
self.config = config.config
|
self.config = config.config
|
||||||
self.serviceproxy = serviceproxy
|
self.epgtypes = epgtypes.EPGTypes(config, serviceproxy)
|
||||||
self.zapepg = zap2it.ZapEPG(config)
|
|
||||||
self.emptyepg = emptyepg.EmptyEPG(config)
|
|
||||||
|
|
||||||
self.epg_cache = None
|
|
||||||
|
|
||||||
def get_epg(self):
|
|
||||||
if self.config["fakehdhr"]["epg_method"] == "empty":
|
|
||||||
epgdict = self.emptyepg.EmptyEPG()
|
|
||||||
elif self.config["fakehdhr"]["epg_method"] == "proxy":
|
|
||||||
epgdict = self.serviceproxy.epg_cache_open()
|
|
||||||
elif self.config["fakehdhr"]["epg_method"] == "zap2it":
|
|
||||||
epgdict = self.zapepg.epg_cache_open()
|
|
||||||
return epgdict
|
|
||||||
|
|
||||||
def epg_cache_open(self):
|
|
||||||
epg_cache = None
|
|
||||||
if os.path.isfile(self.empty_cache_file):
|
|
||||||
with open(self.empty_cache_file, 'r') as epgfile:
|
|
||||||
epg_cache = json.load(epgfile)
|
|
||||||
return epg_cache
|
|
||||||
|
|
||||||
def get_xmltv(self, base_url):
|
def get_xmltv(self, base_url):
|
||||||
epgdict = self.get_epg()
|
epgdict = self.epgtypes.get_epg()
|
||||||
if not epgdict:
|
if not epgdict:
|
||||||
return self.dummyxml()
|
return self.dummyxml()
|
||||||
|
|
||||||
epg_method = self.config["fakehdhr"]["epg_method"]
|
epg_method = self.config["fakehdhr"]["epg_method"]
|
||||||
|
|
||||||
out = ET.Element('tv')
|
out = ET.Element('tv')
|
||||||
out.set('source-info-url', 'NextPVR')
|
out.set('source-info-url', self.config["fakehdhr"]["friendlyname"])
|
||||||
out.set('source-info-name', 'NextPVR')
|
out.set('source-info-name', self.config["main"]["servicename"])
|
||||||
out.set('generator-info-name', 'FAKEHDHR')
|
out.set('generator-info-name', 'FAKEHDHR')
|
||||||
out.set('generator-info-url', 'FAKEHDHR/FakeHDHR_NextPVR')
|
out.set('generator-info-url', 'FAKEHDHR/' + self.config["main"]["reponame"])
|
||||||
|
|
||||||
for c in list(epgdict.keys()):
|
for c in list(epgdict.keys()):
|
||||||
|
|
||||||
@ -76,16 +54,10 @@ class EPGhandler():
|
|||||||
sub_el(c_out, 'display-name', text=epgdict[c]['name'])
|
sub_el(c_out, 'display-name', text=epgdict[c]['name'])
|
||||||
|
|
||||||
if epgdict[c]["thumbnail"] is not None:
|
if epgdict[c]["thumbnail"] is not None:
|
||||||
if epg_method == "empty":
|
channel_thumbnail = self.epgtypes.thumb_url(epg_method, "channel", base_url, str(epgdict[c]['thumbnail']))
|
||||||
sub_el(c_out, 'icon', src=("http://" + str(base_url) + str(epgdict[c]['thumbnail'])))
|
sub_el(c_out, 'icon', src=(str(channel_thumbnail)))
|
||||||
elif epg_method == "proxy":
|
|
||||||
sub_el(c_out, 'icon', src=("http://" + str(base_url) + str(epgdict[c]['thumbnail'])))
|
|
||||||
elif epg_method == "zap2it":
|
|
||||||
sub_el(c_out, 'icon', src=(str(epgdict[c]['thumbnail'])))
|
|
||||||
else:
|
|
||||||
sub_el(c_out, 'icon', src=(str(epgdict[c]['thumbnail'])))
|
|
||||||
else:
|
else:
|
||||||
sub_el(c_out, 'icon', src=("http://" + str(base_url) + "/images?source=empty&type=channel&id=empty"))
|
sub_el(c_out, 'icon', src=("http://" + str(base_url) + "/images?source=empty&type=channel&id=" + c['number']))
|
||||||
|
|
||||||
for progitem in list(epgdict.keys()):
|
for progitem in list(epgdict.keys()):
|
||||||
|
|
||||||
@ -102,12 +74,7 @@ class EPGhandler():
|
|||||||
|
|
||||||
sub_el(prog_out, 'desc', lang='en', text=program['description'])
|
sub_el(prog_out, 'desc', lang='en', text=program['description'])
|
||||||
|
|
||||||
if ('movie' in program["genres"] or 'Movie' in program["genres"]) and program['releaseyear']:
|
sub_el(prog_out, 'sub-title', lang='en', text='Movie: ' + program['sub-title'])
|
||||||
sub_el(prog_out, 'sub-title', lang='en', text='Movie: ' + program['releaseyear'])
|
|
||||||
elif 'episodetitle' in program.keys():
|
|
||||||
sub_el(prog_out, 'sub-title', lang='en', text=program['episodetitle'])
|
|
||||||
else:
|
|
||||||
sub_el(prog_out, 'sub-title', lang='en', text='Movie: ' + program['sub-title'])
|
|
||||||
|
|
||||||
sub_el(prog_out, 'length', units='minutes', text=str(int(program['duration_minutes'])))
|
sub_el(prog_out, 'length', units='minutes', text=str(int(program['duration_minutes'])))
|
||||||
|
|
||||||
@ -128,16 +95,10 @@ class EPGhandler():
|
|||||||
text='S%02dE%02d' % (s_, e_))
|
text='S%02dE%02d' % (s_, e_))
|
||||||
|
|
||||||
if program["thumbnail"] is not None:
|
if program["thumbnail"] is not None:
|
||||||
if epg_method == "empty":
|
content_thumbnail = self.epgtypes.thumb_url(epg_method, "content", base_url, str(epgdict[c]['thumbnail']))
|
||||||
sub_el(prog_out, 'icon', src=("http://" + str(base_url) + str(program['thumbnail'])))
|
sub_el(prog_out, 'icon', src=(str(content_thumbnail)))
|
||||||
elif epg_method == "proxy":
|
|
||||||
sub_el(prog_out, 'icon', src=("http://" + str(base_url) + str(program['thumbnail'])))
|
|
||||||
elif epg_method == "zap2it":
|
|
||||||
sub_el(prog_out, 'icon', src=(str(program['thumbnail'])))
|
|
||||||
else:
|
|
||||||
sub_el(prog_out, 'icon', src=(str(program['thumbnail'])))
|
|
||||||
else:
|
else:
|
||||||
sub_el(prog_out, 'icon', src=("http://" + str(base_url) + "/images?source=empty&type=content&id=empty"))
|
sub_el(prog_out, 'icon', src=("http://" + str(base_url) + "/images?source=empty&type=content&id=" + program['title']))
|
||||||
|
|
||||||
if program['rating']:
|
if program['rating']:
|
||||||
rating_out = sub_el(prog_out, 'rating', system="MPAA")
|
rating_out = sub_el(prog_out, 'rating', system="MPAA")
|
||||||
@ -153,38 +114,25 @@ class EPGhandler():
|
|||||||
|
|
||||||
def dummyxml(self):
|
def dummyxml(self):
|
||||||
out = ET.Element('tv')
|
out = ET.Element('tv')
|
||||||
out.set('source-info-url', 'NextPVR')
|
out.set('source-info-url', self.config["fakehdhr"]["friendlyname"])
|
||||||
out.set('source-info-name', 'NextPVR')
|
out.set('source-info-name', self.config["main"]["servicename"])
|
||||||
out.set('generator-info-name', 'FAKEHDHR')
|
out.set('generator-info-name', 'FAKEHDHR')
|
||||||
out.set('generator-info-url', 'FAKEHDHR/FakeHDHR_NextPVR')
|
out.set('generator-info-url', 'FAKEHDHR/' + self.config["main"]["reponame"])
|
||||||
|
|
||||||
fakefile = BytesIO()
|
fakefile = BytesIO()
|
||||||
fakefile.write(b'<?xml version="1.0" encoding="UTF-8"?>\n')
|
fakefile.write(b'<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||||
fakefile.write(ET.tostring(out, encoding='UTF-8'))
|
fakefile.write(ET.tostring(out, encoding='UTF-8'))
|
||||||
return fakefile.getvalue()
|
return fakefile.getvalue()
|
||||||
|
|
||||||
def update(self):
|
|
||||||
if self.config["fakehdhr"]["epg_method"] == "empty":
|
|
||||||
self.emptyepg.update_epg()
|
|
||||||
elif self.config["fakehdhr"]["epg_method"] == "proxy":
|
|
||||||
self.serviceproxy.update_epg()
|
|
||||||
elif self.config["fakehdhr"]["epg_method"] == "zap2it":
|
|
||||||
self.zapepg.update_epg()
|
|
||||||
|
|
||||||
|
|
||||||
def epgServerProcess(config, epghandling):
|
def epgServerProcess(config, epghandling):
|
||||||
|
|
||||||
if config.config["fakehdhr"]["epg_method"] == "empty":
|
sleeptime = int(config.config[config.config["fakehdhr"]["epg_method"]]["epg_update_frequency"])
|
||||||
sleeptime = config.config["main"]["empty_epg_update_frequency"]
|
|
||||||
elif config.config["fakehdhr"]["epg_method"] == "proxy":
|
|
||||||
sleeptime = config.config["nextpvr"]["epg_update_frequency"]
|
|
||||||
elif config.config["fakehdhr"]["epg_method"] == "zap2it":
|
|
||||||
sleeptime = config.config["zap2xml"]["epg_update_frequency"]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
epghandling.update()
|
epghandling.epgtypes.update()
|
||||||
time.sleep(sleeptime)
|
time.sleep(sleeptime)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
28
epghandler/epgtypes/__init__.py
Normal file
28
epghandler/epgtypes/__init__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from . import zap2it
|
||||||
|
from . import empty
|
||||||
|
|
||||||
|
|
||||||
|
class EPGTypes():
|
||||||
|
|
||||||
|
def __init__(self, config, serviceproxy):
|
||||||
|
self.config = config.config
|
||||||
|
self.proxy = serviceproxy
|
||||||
|
self.zap2it = zap2it.ZapEPG(config, serviceproxy)
|
||||||
|
self.empty = empty.EmptyEPG(config, serviceproxy)
|
||||||
|
|
||||||
|
def get_epg(self):
|
||||||
|
method_to_call = getattr(self, self.config["fakehdhr"]["epg_method"])
|
||||||
|
func_to_call = getattr(method_to_call, 'epg_cache_open')
|
||||||
|
epgdict = func_to_call()
|
||||||
|
return epgdict
|
||||||
|
|
||||||
|
def thumb_url(self, epg_method, thumb_type, base_url, thumbnail):
|
||||||
|
method_to_call = getattr(self, self.config["fakehdhr"]["epg_method"])
|
||||||
|
func_to_call = getattr(method_to_call, 'thumb_url')
|
||||||
|
thumbnail = func_to_call(thumb_type, base_url, thumbnail)
|
||||||
|
return thumbnail
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
method_to_call = getattr(self, self.config["fakehdhr"]["epg_method"])
|
||||||
|
func_to_call = getattr(method_to_call, 'update_epg')
|
||||||
|
func_to_call()
|
||||||
@ -5,15 +5,16 @@ import datetime
|
|||||||
|
|
||||||
class EmptyEPG():
|
class EmptyEPG():
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config, serviceproxy):
|
||||||
|
|
||||||
self.config = config.config
|
self.config = config.config
|
||||||
|
self.serviceproxy = serviceproxy
|
||||||
|
|
||||||
self.postalcode = None
|
self.postalcode = None
|
||||||
|
|
||||||
self.epg_cache = None
|
self.epg_cache = None
|
||||||
self.cache_dir = config.config["main"]["empty_cache"]
|
self.cache_dir = config.config["empty"]["empty_cache"]
|
||||||
self.epg_cache_file = config.config["main"]["empty_cache_file"]
|
self.epg_cache_file = config.config["empty"]["empty_cache_file"]
|
||||||
self.epg_cache = self.epg_cache_open()
|
self.epg_cache = self.epg_cache_open()
|
||||||
|
|
||||||
def epg_cache_open(self):
|
def epg_cache_open(self):
|
||||||
@ -23,6 +24,12 @@ class EmptyEPG():
|
|||||||
epg_cache = json.load(epgfile)
|
epg_cache = json.load(epgfile)
|
||||||
return epg_cache
|
return epg_cache
|
||||||
|
|
||||||
|
def thumb_url(self, thumb_type, base_url, thumbnail):
|
||||||
|
if thumb_type == "channel":
|
||||||
|
return "http://" + str(base_url) + str(thumbnail)
|
||||||
|
elif thumb_type == "content":
|
||||||
|
return "http://" + str(base_url) + str(thumbnail)
|
||||||
|
|
||||||
def update_epg(self):
|
def update_epg(self):
|
||||||
print('Updating Empty EPG cache file.')
|
print('Updating Empty EPG cache file.')
|
||||||
|
|
||||||
@ -79,7 +86,7 @@ class EmptyEPG():
|
|||||||
programguide[str(c["number"])]["listing"].append(clean_prog_dict)
|
programguide[str(c["number"])]["listing"].append(clean_prog_dict)
|
||||||
|
|
||||||
self.epg_cache = programguide
|
self.epg_cache = programguide
|
||||||
with open(self.empty_cache_file, 'w') as epgfile:
|
with open(self.epg_cache_file, 'w') as epgfile:
|
||||||
epgfile.write(json.dumps(programguide, indent=4))
|
epgfile.write(json.dumps(programguide, indent=4))
|
||||||
print('Wrote updated Empty EPG cache file.')
|
print('Wrote updated Empty EPG cache file.')
|
||||||
return programguide
|
return programguide
|
||||||
@ -34,19 +34,20 @@ def xmldictmaker(inputdict, req_items, list_items=[], str_items=[]):
|
|||||||
|
|
||||||
class ZapEPG():
|
class ZapEPG():
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config, serviceproxy):
|
||||||
|
|
||||||
self.config = config.config
|
self.config = config.config
|
||||||
|
self.serviceproxy = serviceproxy
|
||||||
|
|
||||||
self.postalcode = None
|
self.postalcode = None
|
||||||
|
|
||||||
self.epg_cache = None
|
self.epg_cache = None
|
||||||
self.cache_dir = config.config["main"]["zap_web_cache"]
|
self.cache_dir = config.config["main"]["zap_web_cache"]
|
||||||
self.epg_cache_file = config.config["zap2xml"]["epg_cache"]
|
self.epg_cache_file = config.config["zap2it"]["epg_cache"]
|
||||||
self.epg_cache = self.epg_cache_open()
|
self.epg_cache = self.epg_cache_open()
|
||||||
|
|
||||||
def get_location(self):
|
def get_location(self):
|
||||||
self.postalcode = self.config["zap2xml"]["postalcode"]
|
self.postalcode = self.config["zap2it"]["postalcode"]
|
||||||
if self.postalcode:
|
if self.postalcode:
|
||||||
url = 'http://ipinfo.io/json'
|
url = 'http://ipinfo.io/json'
|
||||||
response = urllib.request.urlopen(url)
|
response = urllib.request.urlopen(url)
|
||||||
@ -60,6 +61,12 @@ class ZapEPG():
|
|||||||
epg_cache = json.load(epgfile)
|
epg_cache = json.load(epgfile)
|
||||||
return epg_cache
|
return epg_cache
|
||||||
|
|
||||||
|
def thumb_url(self, thumb_type, base_url, thumbnail):
|
||||||
|
if thumb_type == "channel":
|
||||||
|
return thumbnail
|
||||||
|
elif thumb_type == "content":
|
||||||
|
return thumbnail
|
||||||
|
|
||||||
def get_cached(self, cache_key, delay, url):
|
def get_cached(self, cache_key, delay, url):
|
||||||
cache_path = self.cache_dir.joinpath(cache_key)
|
cache_path = self.cache_dir.joinpath(cache_key)
|
||||||
if cache_path.is_file():
|
if cache_path.is_file():
|
||||||
@ -83,6 +90,7 @@ class ZapEPG():
|
|||||||
raise
|
raise
|
||||||
with open(cache_path, 'wb') as f:
|
with open(cache_path, 'wb') as f:
|
||||||
f.write(result)
|
f.write(result)
|
||||||
|
time.sleep(int(delay))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def remove_stale_cache(self, todaydate):
|
def remove_stale_cache(self, todaydate):
|
||||||
@ -106,26 +114,26 @@ class ZapEPG():
|
|||||||
|
|
||||||
# Start time parameter is now rounded down to nearest `zap_timespan`, in s.
|
# Start time parameter is now rounded down to nearest `zap_timespan`, in s.
|
||||||
zap_time = time.mktime(time.localtime())
|
zap_time = time.mktime(time.localtime())
|
||||||
zap_time_window = int(self.config["zap2xml"]["timespan"]) * 3600
|
zap_time_window = int(self.config["zap2it"]["timespan"]) * 3600
|
||||||
zap_time = int(zap_time - (zap_time % zap_time_window))
|
zap_time = int(zap_time - (zap_time % zap_time_window))
|
||||||
|
|
||||||
# Fetch data in `zap_timespan` chunks.
|
# Fetch data in `zap_timespan` chunks.
|
||||||
for i in range(int(7 * 24 / int(self.config["zap2xml"]["timespan"]))):
|
for i in range(int(7 * 24 / int(self.config["zap2it"]["timespan"]))):
|
||||||
i_time = zap_time + (i * zap_time_window)
|
i_time = zap_time + (i * zap_time_window)
|
||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'aid': self.config["zap2xml"]['affiliate_id'],
|
'aid': self.config["zap2it"]['affiliate_id'],
|
||||||
'country': self.config["zap2xml"]['country'],
|
'country': self.config["zap2it"]['country'],
|
||||||
'device': self.config["zap2xml"]['device'],
|
'device': self.config["zap2it"]['device'],
|
||||||
'headendId': self.config["zap2xml"]['headendid'],
|
'headendId': self.config["zap2it"]['headendid'],
|
||||||
'isoverride': "true",
|
'isoverride': "true",
|
||||||
'languagecode': self.config["zap2xml"]['languagecode'],
|
'languagecode': self.config["zap2it"]['languagecode'],
|
||||||
'pref': 'm,p',
|
'pref': 'm,p',
|
||||||
'timespan': self.config["zap2xml"]['timespan'],
|
'timespan': self.config["zap2it"]['timespan'],
|
||||||
'timezone': self.config["zap2xml"]['timezone'],
|
'timezone': self.config["zap2it"]['timezone'],
|
||||||
'userId': self.config["zap2xml"]['userid'],
|
'userId': self.config["zap2it"]['userid'],
|
||||||
'postalCode': self.postalcode,
|
'postalCode': self.postalcode,
|
||||||
'lineupId': '%s-%s-DEFAULT' % (self.config["zap2xml"]['country'], self.config["zap2xml"]['device']),
|
'lineupId': '%s-%s-DEFAULT' % (self.config["zap2it"]['country'], self.config["zap2it"]['device']),
|
||||||
'time': i_time,
|
'time': i_time,
|
||||||
'Activity_ID': 1,
|
'Activity_ID': 1,
|
||||||
'FromPage': "TV%20Guide",
|
'FromPage': "TV%20Guide",
|
||||||
@ -134,7 +142,7 @@ class ZapEPG():
|
|||||||
url = 'https://tvlistings.zap2it.com/api/grid?'
|
url = 'https://tvlistings.zap2it.com/api/grid?'
|
||||||
url += urllib.parse.urlencode(parameters)
|
url += urllib.parse.urlencode(parameters)
|
||||||
|
|
||||||
result = self.get_cached(str(i_time), self.config["zap2xml"]['delay'], url)
|
result = self.get_cached(str(i_time), self.config["zap2it"]['delay'], url)
|
||||||
d = json.loads(result)
|
d = json.loads(result)
|
||||||
|
|
||||||
for c in d['channels']:
|
for c in d['channels']:
|
||||||
@ -7,6 +7,7 @@ import json
|
|||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import threading
|
||||||
import PIL.Image
|
import PIL.Image
|
||||||
import PIL.ImageDraw
|
import PIL.ImageDraw
|
||||||
import PIL.ImageFont
|
import PIL.ImageFont
|
||||||
@ -31,14 +32,38 @@ class HDHR_Hub():
|
|||||||
epghandling = None
|
epghandling = None
|
||||||
station_scan = False
|
station_scan = False
|
||||||
station_list = []
|
station_list = []
|
||||||
|
http = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.tuner_lock = threading.Lock()
|
||||||
|
self.tuners = 0
|
||||||
|
|
||||||
|
def hubprep(self, config, serviceproxy, epghandling):
|
||||||
|
self.config = config.config
|
||||||
|
self.max_tuners = int(self.config["fakehdhr"]["tuner_count"])
|
||||||
self.station_scan = False
|
self.station_scan = False
|
||||||
|
self.serviceproxy = serviceproxy
|
||||||
|
self.epghandling = epghandling
|
||||||
|
|
||||||
|
def tuner_usage(self, number):
|
||||||
|
self.tuner_lock.acquire()
|
||||||
|
self.tuners += number
|
||||||
|
if self.tuners < 0:
|
||||||
|
self.tuners = 0
|
||||||
|
elif self.tuners > self.max_tuners:
|
||||||
|
self.tuners = self.max_tuners
|
||||||
|
self.tuner_lock.release()
|
||||||
|
|
||||||
|
def get_tuner(self):
|
||||||
|
if self.tuners <= self.max_tuners:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def get_xmltv(self, base_url):
|
def get_xmltv(self, base_url):
|
||||||
return self.epghandling.get_xmltv(base_url)
|
return self.epghandling.get_xmltv(base_url)
|
||||||
|
|
||||||
def get_image(self, req_args):
|
def get_image(self, req_args):
|
||||||
|
|
||||||
imageid = req_args["id"]
|
imageid = req_args["id"]
|
||||||
|
|
||||||
if req_args["source"] == "proxy":
|
if req_args["source"] == "proxy":
|
||||||
@ -247,67 +272,77 @@ class HDHR_HTTP_Server():
|
|||||||
|
|
||||||
@app.route('/watch', methods=['GET'])
|
@app.route('/watch', methods=['GET'])
|
||||||
def watch():
|
def watch():
|
||||||
if 'method' in list(request.args.keys()):
|
|
||||||
if 'channel' in list(request.args.keys()):
|
|
||||||
|
|
||||||
channelUri = hdhr.serviceproxy.get_channel_stream(str(request.args["channel"]))
|
if 'method' in list(request.args.keys()) and 'channel' in list(request.args.keys()):
|
||||||
if not channelUri:
|
|
||||||
abort(404)
|
|
||||||
|
|
||||||
if request.args["method"] == "direct":
|
method = str(request.args["method"])
|
||||||
duration = request.args.get('duration', default=0, type=int)
|
channel_id = str(request.args["channel"])
|
||||||
|
|
||||||
if not duration == 0:
|
tuner = hdhr.get_tuner()
|
||||||
duration += time.time()
|
if not tuner:
|
||||||
|
abort(503)
|
||||||
|
|
||||||
req = requests.get(channelUri, stream=True)
|
channelUri = hdhr.serviceproxy.get_channel_stream(channel_id)
|
||||||
|
|
||||||
def generate():
|
if method == "direct":
|
||||||
try:
|
duration = request.args.get('duration', default=0, type=int)
|
||||||
yield ''
|
|
||||||
for chunk in req.iter_content(chunk_size=hdhr.config["direct_stream"]['chunksize']):
|
|
||||||
if not duration == 0 and not time.time() < duration:
|
|
||||||
req.close()
|
|
||||||
break
|
|
||||||
yield chunk
|
|
||||||
except GeneratorExit:
|
|
||||||
req.close()
|
|
||||||
print("Connection Closed.")
|
|
||||||
|
|
||||||
return Response(generate(), content_type=req.headers['content-type'], direct_passthrough=True)
|
if not duration == 0:
|
||||||
|
duration += time.time()
|
||||||
|
|
||||||
if request.args["method"] == "ffmpeg":
|
req = requests.get(channelUri, stream=True)
|
||||||
|
hdhr.tuner_usage(1)
|
||||||
|
|
||||||
ffmpeg_command = [hdhr.config["ffmpeg"]["ffmpeg_path"],
|
def generate():
|
||||||
"-i", channelUri,
|
try:
|
||||||
"-c", "copy",
|
yield ''
|
||||||
"-f", "mpegts",
|
for chunk in req.iter_content(chunk_size=int(hdhr.config["direct_stream"]['chunksize'])):
|
||||||
"-nostats", "-hide_banner",
|
if not duration == 0 and not time.time() < duration:
|
||||||
"-loglevel", "warning",
|
req.close()
|
||||||
"pipe:stdout"
|
hdhr.tuner_usage(-1)
|
||||||
]
|
break
|
||||||
|
yield chunk
|
||||||
|
except GeneratorExit:
|
||||||
|
req.close()
|
||||||
|
print("Connection Closed.")
|
||||||
|
hdhr.tuner_usage(-1)
|
||||||
|
|
||||||
ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE)
|
return Response(generate(), content_type=req.headers['content-type'], direct_passthrough=True)
|
||||||
|
|
||||||
def generate():
|
elif method == "ffmpeg":
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
videoData = ffmpeg_proc.stdout.read(int(hdhr.config["ffmpeg"]["bytes_per_read"]))
|
|
||||||
if not videoData:
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
yield videoData
|
|
||||||
except Exception as e:
|
|
||||||
ffmpeg_proc.terminate()
|
|
||||||
ffmpeg_proc.communicate()
|
|
||||||
print("Connection Closed: " + str(e))
|
|
||||||
except GeneratorExit:
|
|
||||||
ffmpeg_proc.terminate()
|
|
||||||
ffmpeg_proc.communicate()
|
|
||||||
print("Connection Closed.")
|
|
||||||
|
|
||||||
return Response(stream_with_context(generate()), mimetype="audio/mpeg")
|
ffmpeg_command = [hdhr.config["ffmpeg"]["ffmpeg_path"],
|
||||||
abort(404)
|
"-i", channelUri,
|
||||||
|
"-c", "copy",
|
||||||
|
"-f", "mpegts",
|
||||||
|
"-nostats", "-hide_banner",
|
||||||
|
"-loglevel", "warning",
|
||||||
|
"pipe:stdout"
|
||||||
|
]
|
||||||
|
|
||||||
|
ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE)
|
||||||
|
hdhr.tuner_usage(1)
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
videoData = ffmpeg_proc.stdout.read(int(hdhr.config["ffmpeg"]["bytes_per_read"]))
|
||||||
|
if not videoData:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
yield videoData
|
||||||
|
except Exception as e:
|
||||||
|
ffmpeg_proc.terminate()
|
||||||
|
ffmpeg_proc.communicate()
|
||||||
|
print("Connection Closed: " + str(e))
|
||||||
|
hdhr.tuner_usage(-1)
|
||||||
|
except GeneratorExit:
|
||||||
|
ffmpeg_proc.terminate()
|
||||||
|
ffmpeg_proc.communicate()
|
||||||
|
print("Connection Closed.")
|
||||||
|
hdhr.tuner_usage(-1)
|
||||||
|
|
||||||
|
return Response(stream_with_context(generate()), mimetype="audio/mpeg")
|
||||||
|
|
||||||
@app.route('/lineup.post', methods=['POST'])
|
@app.route('/lineup.post', methods=['POST'])
|
||||||
def lineup_post():
|
def lineup_post():
|
||||||
@ -334,17 +369,17 @@ class HDHR_HTTP_Server():
|
|||||||
self.config = config.config
|
self.config = config.config
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
http = WSGIServer((
|
self.http = WSGIServer((
|
||||||
self.config["fakehdhr"]["address"],
|
self.config["fakehdhr"]["address"],
|
||||||
int(self.config["fakehdhr"]["port"])
|
int(self.config["fakehdhr"]["port"])
|
||||||
), self.app.wsgi_app)
|
), self.app.wsgi_app)
|
||||||
http.serve_forever()
|
try:
|
||||||
|
self.http.serve_forever()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.http.stop()
|
||||||
|
|
||||||
|
|
||||||
def interface_start(config, serviceproxy, epghandling):
|
def interface_start(config, serviceproxy, epghandling):
|
||||||
hdhr.config = config.config
|
hdhr.hubprep(config, serviceproxy, epghandling)
|
||||||
hdhr.station_scan = False
|
|
||||||
hdhr.serviceproxy = serviceproxy
|
|
||||||
hdhr.epghandling = epghandling
|
|
||||||
fakhdhrserver = HDHR_HTTP_Server(config)
|
fakhdhrserver = HDHR_HTTP_Server(config)
|
||||||
fakhdhrserver.run()
|
fakhdhrserver.run()
|
||||||
|
|||||||
@ -17,67 +17,16 @@ class HDHRConfig():
|
|||||||
config_handler = configparser.ConfigParser()
|
config_handler = configparser.ConfigParser()
|
||||||
script_dir = None
|
script_dir = None
|
||||||
|
|
||||||
config = {
|
config = {}
|
||||||
"main": {
|
|
||||||
'uuid': None,
|
|
||||||
"cache_dir": None,
|
|
||||||
"empty_epg_update_frequency": 43200,
|
|
||||||
},
|
|
||||||
"nextpvr": {
|
|
||||||
"address": "localhost",
|
|
||||||
"port": 8866,
|
|
||||||
"ssl": False,
|
|
||||||
"pin": None,
|
|
||||||
"weight": 300, # subscription priority
|
|
||||||
"sidfile": None,
|
|
||||||
"epg_update_frequency": 43200,
|
|
||||||
},
|
|
||||||
"fakehdhr": {
|
|
||||||
"address": "0.0.0.0",
|
|
||||||
"port": 5004,
|
|
||||||
"discovery_address": "0.0.0.0",
|
|
||||||
"tuner_count": 4, # number of tuners in tvh
|
|
||||||
"concurrent_listeners": 10,
|
|
||||||
"friendlyname": "fHDHR-NextPVR",
|
|
||||||
"stream_type": "direct",
|
|
||||||
"epg_method": "proxy",
|
|
||||||
"font": None,
|
|
||||||
},
|
|
||||||
"zap2xml": {
|
|
||||||
"delay": 5,
|
|
||||||
"postalcode": None,
|
|
||||||
"affiliate_id": 'gapzap',
|
|
||||||
"country": 'USA',
|
|
||||||
"device": '-',
|
|
||||||
"headendid": "lineupId",
|
|
||||||
"isoverride": True,
|
|
||||||
"languagecode": 'en',
|
|
||||||
"pref": "",
|
|
||||||
"timespan": 6,
|
|
||||||
"timezone": "",
|
|
||||||
"userid": "-",
|
|
||||||
"epg_update_frequency": 43200,
|
|
||||||
},
|
|
||||||
"ffmpeg": {
|
|
||||||
'ffmpeg_path': "ffmpeg",
|
|
||||||
'bytes_per_read': '1152000',
|
|
||||||
"font": None,
|
|
||||||
},
|
|
||||||
"direct_stream": {
|
|
||||||
'chunksize': 1024*1024 # usually you don't need to edit this
|
|
||||||
},
|
|
||||||
"dev": {
|
|
||||||
'reporting_model': 'HDHR4-2DT',
|
|
||||||
'reporting_firmware_name': 'hdhomerun4_dvbt',
|
|
||||||
'reporting_firmware_ver': '20150826',
|
|
||||||
'reporting_tuner_type': "Antenna",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, script_dir, args):
|
def __init__(self, script_dir, args):
|
||||||
self.get_config_path(script_dir, args)
|
self.get_config_path(script_dir, args)
|
||||||
|
self.import_default_config(script_dir)
|
||||||
|
self.import_service_config(script_dir)
|
||||||
self.import_config()
|
self.import_config()
|
||||||
self.config_adjustments(script_dir)
|
self.critical_config(script_dir)
|
||||||
|
self.config_adjustments_this()
|
||||||
|
self.config_adjustments()
|
||||||
|
|
||||||
def get_config_path(self, script_dir, args):
|
def get_config_path(self, script_dir, args):
|
||||||
if args.cfg:
|
if args.cfg:
|
||||||
@ -95,6 +44,42 @@ class HDHRConfig():
|
|||||||
for (each_key, each_val) in self.config_handler.items(each_section):
|
for (each_key, each_val) in self.config_handler.items(each_section):
|
||||||
self.config[each_section.lower()][each_key.lower()] = each_val
|
self.config[each_section.lower()][each_key.lower()] = each_val
|
||||||
|
|
||||||
|
def import_default_config(self, script_dir):
|
||||||
|
config_handler = configparser.ConfigParser()
|
||||||
|
data_dir = pathlib.Path(script_dir).joinpath('data')
|
||||||
|
internal_config_dir = pathlib.Path(data_dir).joinpath('internal_config')
|
||||||
|
serviceconf = pathlib.Path(internal_config_dir).joinpath('fakehdhr.ini')
|
||||||
|
config_handler.read(serviceconf)
|
||||||
|
for each_section in config_handler.sections():
|
||||||
|
if each_section not in list(self.config.keys()):
|
||||||
|
self.config[each_section] = {}
|
||||||
|
for (each_key, each_val) in config_handler.items(each_section):
|
||||||
|
if each_val == "fHDHR_None":
|
||||||
|
each_val = None
|
||||||
|
elif each_val == "fHDHR_True":
|
||||||
|
each_val = True
|
||||||
|
elif each_val == "fHDHR_False":
|
||||||
|
each_val = False
|
||||||
|
self.config[each_section.lower()][each_key.lower()] = each_val
|
||||||
|
|
||||||
|
def import_service_config(self, script_dir):
|
||||||
|
config_handler = configparser.ConfigParser()
|
||||||
|
data_dir = pathlib.Path(script_dir).joinpath('data')
|
||||||
|
internal_config_dir = pathlib.Path(data_dir).joinpath('internal_config')
|
||||||
|
serviceconf = pathlib.Path(internal_config_dir).joinpath('serviceconf.ini')
|
||||||
|
config_handler.read(serviceconf)
|
||||||
|
for each_section in config_handler.sections():
|
||||||
|
if each_section not in list(self.config.keys()):
|
||||||
|
self.config[each_section] = {}
|
||||||
|
for (each_key, each_val) in config_handler.items(each_section):
|
||||||
|
if each_val == "fHDHR_None":
|
||||||
|
each_val = None
|
||||||
|
elif each_val == "fHDHR_True":
|
||||||
|
each_val = True
|
||||||
|
elif each_val == "fHDHR_False":
|
||||||
|
each_val = False
|
||||||
|
self.config[each_section.lower()][each_key.lower()] = each_val
|
||||||
|
|
||||||
def write(self, section, key, value):
|
def write(self, section, key, value):
|
||||||
self.config[section][key] = value
|
self.config[section][key] = value
|
||||||
self.config_handler.set(section, key, value)
|
self.config_handler.set(section, key, value)
|
||||||
@ -102,7 +87,7 @@ class HDHRConfig():
|
|||||||
with open(self.config_file, 'w') as config_file:
|
with open(self.config_file, 'w') as config_file:
|
||||||
self.config_handler.write(config_file)
|
self.config_handler.write(config_file)
|
||||||
|
|
||||||
def config_adjustments(self, script_dir):
|
def critical_config(self, script_dir):
|
||||||
|
|
||||||
self.config["main"]["script_dir"] = script_dir
|
self.config["main"]["script_dir"] = script_dir
|
||||||
|
|
||||||
@ -120,41 +105,17 @@ class HDHRConfig():
|
|||||||
clean_exit()
|
clean_exit()
|
||||||
cache_dir = self.config["main"]["cache_dir"]
|
cache_dir = self.config["main"]["cache_dir"]
|
||||||
|
|
||||||
if not self.config["nextpvr"]["pin"]:
|
|
||||||
print("NextPVR Login Credentials Missing. Exiting...")
|
|
||||||
clean_exit()
|
|
||||||
|
|
||||||
empty_cache = pathlib.Path(cache_dir).joinpath('empty_cache')
|
empty_cache = pathlib.Path(cache_dir).joinpath('empty_cache')
|
||||||
self.config["main"]["empty_cache"] = empty_cache
|
self.config["empty"]["empty_cache"] = empty_cache
|
||||||
if not empty_cache.is_dir():
|
if not empty_cache.is_dir():
|
||||||
empty_cache.mkdir()
|
empty_cache.mkdir()
|
||||||
self.config["main"]["empty_cache_file"] = pathlib.Path(empty_cache).joinpath('epg.json')
|
self.config["empty"]["empty_cache_file"] = pathlib.Path(empty_cache).joinpath('epg.json')
|
||||||
|
|
||||||
nextpvr_cache = pathlib.Path(cache_dir).joinpath('nextpvr')
|
|
||||||
self.config["main"]["nextpvr_cache"] = nextpvr_cache
|
|
||||||
if not nextpvr_cache.is_dir():
|
|
||||||
nextpvr_cache.mkdir()
|
|
||||||
self.config["nextpvr"]["sidfile"] = pathlib.Path(nextpvr_cache).joinpath('sid.txt')
|
|
||||||
self.config["nextpvr"]["epg_cache"] = pathlib.Path(nextpvr_cache).joinpath('epg.json')
|
|
||||||
|
|
||||||
zap_cache = pathlib.Path(cache_dir).joinpath('zap2it')
|
|
||||||
self.config["main"]["zap_cache"] = zap_cache
|
|
||||||
if not zap_cache.is_dir():
|
|
||||||
zap_cache.mkdir()
|
|
||||||
self.config["zap2xml"]["epg_cache"] = pathlib.Path(zap_cache).joinpath('epg.json')
|
|
||||||
zap_web_cache = pathlib.Path(zap_cache).joinpath('zap_web_cache')
|
|
||||||
self.config["main"]["zap_web_cache"] = zap_web_cache
|
|
||||||
if not zap_web_cache.is_dir():
|
|
||||||
zap_web_cache.mkdir()
|
|
||||||
|
|
||||||
www_dir = pathlib.Path(data_dir).joinpath('www')
|
www_dir = pathlib.Path(data_dir).joinpath('www')
|
||||||
self.config["main"]["www_dir"] = www_dir
|
self.config["main"]["www_dir"] = www_dir
|
||||||
self.config["main"]["favicon"] = pathlib.Path(www_dir).joinpath('favicon.ico')
|
self.config["main"]["favicon"] = pathlib.Path(www_dir).joinpath('favicon.ico')
|
||||||
|
|
||||||
www_image_dir = pathlib.Path(www_dir).joinpath('images')
|
def config_adjustments(self):
|
||||||
self.config["main"]["www_image_dir"] = www_image_dir
|
|
||||||
self.config["main"]["image_def_channel"] = pathlib.Path(www_image_dir).joinpath("default-channel-thumb.png")
|
|
||||||
self.config["main"]["image_def_content"] = pathlib.Path(www_image_dir).joinpath("default-content-thumb.png")
|
|
||||||
|
|
||||||
# generate UUID here for when we are not using docker
|
# generate UUID here for when we are not using docker
|
||||||
if self.config["main"]["uuid"] is None:
|
if self.config["main"]["uuid"] is None:
|
||||||
@ -165,6 +126,52 @@ class HDHRConfig():
|
|||||||
self.write('main', 'uuid', self.config["main"]["uuid"])
|
self.write('main', 'uuid', self.config["main"]["uuid"])
|
||||||
print("UUID set to: " + self.config["main"]["uuid"] + "...")
|
print("UUID set to: " + self.config["main"]["uuid"] + "...")
|
||||||
|
|
||||||
|
if not self.config["fakehdhr"]["discovery_address"]:
|
||||||
|
if self.config["fakehdhr"]["address"] != "0.0.0.0":
|
||||||
|
self.config["fakehdhr"]["discovery_address"] = self.config["fakehdhr"]["address"]
|
||||||
|
|
||||||
print("Server is set to run on " +
|
print("Server is set to run on " +
|
||||||
str(self.config["fakehdhr"]["address"]) + ":" +
|
str(self.config["fakehdhr"]["address"]) + ":" +
|
||||||
str(self.config["fakehdhr"]["port"]))
|
str(self.config["fakehdhr"]["port"]))
|
||||||
|
|
||||||
|
def config_adjustments_this(self):
|
||||||
|
self.config["proxy"] = self.config.pop(self.config["main"]["dictpopname"])
|
||||||
|
self.config_adjustments_proxy()
|
||||||
|
self.config_adjustments_zap2it()
|
||||||
|
|
||||||
|
def config_adjustments_proxy(self):
|
||||||
|
cache_dir = self.config["main"]["cache_dir"]
|
||||||
|
|
||||||
|
credentials_list = self.config["main"]["credentials"].split(",")
|
||||||
|
creds_missing = False
|
||||||
|
if len(credentials_list):
|
||||||
|
for cred_item in credentials_list:
|
||||||
|
if not self.config["proxy"][cred_item]:
|
||||||
|
creds_missing = True
|
||||||
|
if creds_missing:
|
||||||
|
print(self.config["main"]["servicename"] + " Login Credentials Missing. Exiting...")
|
||||||
|
clean_exit()
|
||||||
|
|
||||||
|
proxy_cache = pathlib.Path(cache_dir).joinpath('proxy')
|
||||||
|
self.config["main"]["proxy_cache"] = proxy_cache
|
||||||
|
if not proxy_cache.is_dir():
|
||||||
|
proxy_cache.mkdir()
|
||||||
|
self.config["proxy"]["sidfile"] = pathlib.Path(proxy_cache).joinpath('sid.txt')
|
||||||
|
self.config["proxy"]["epg_cache"] = pathlib.Path(proxy_cache).joinpath('epg.json')
|
||||||
|
proxy_web_cache = pathlib.Path(proxy_cache).joinpath('proxy_web_cache')
|
||||||
|
self.config["main"]["proxy_web_cache"] = proxy_web_cache
|
||||||
|
if not proxy_web_cache.is_dir():
|
||||||
|
proxy_web_cache.mkdir()
|
||||||
|
|
||||||
|
def config_adjustments_zap2it(self):
|
||||||
|
cache_dir = self.config["main"]["cache_dir"]
|
||||||
|
|
||||||
|
zap_cache = pathlib.Path(cache_dir).joinpath('zap2it')
|
||||||
|
self.config["main"]["zap_cache"] = zap_cache
|
||||||
|
if not zap_cache.is_dir():
|
||||||
|
zap_cache.mkdir()
|
||||||
|
self.config["zap2it"]["epg_cache"] = pathlib.Path(zap_cache).joinpath('epg.json')
|
||||||
|
zap_web_cache = pathlib.Path(zap_cache).joinpath('zap_web_cache')
|
||||||
|
self.config["main"]["zap_web_cache"] = zap_web_cache
|
||||||
|
if not zap_web_cache.is_dir():
|
||||||
|
zap_web_cache.mkdir()
|
||||||
|
|||||||
17
main.py
17
main.py
@ -55,11 +55,20 @@ if __name__ == '__main__':
|
|||||||
fhdhrServer = Process(target=fakehdhr.interface_start, args=(config, serviceproxy, epghandling))
|
fhdhrServer = Process(target=fakehdhr.interface_start, args=(config, serviceproxy, epghandling))
|
||||||
fhdhrServer.start()
|
fhdhrServer.start()
|
||||||
|
|
||||||
print("Starting SSDP server...")
|
if (config.config["fakehdhr"]["discovery_address"] and
|
||||||
ssdpServer = Process(target=ssdpserver.ssdpServerProcess, args=(config,))
|
config.config["fakehdhr"]["discovery_address"] != "0.0.0.0"):
|
||||||
ssdpServer.daemon = True
|
print("Starting SSDP server...")
|
||||||
ssdpServer.start()
|
ssdpServer = Process(target=ssdpserver.ssdpServerProcess, args=(config,))
|
||||||
|
ssdpServer.daemon = True
|
||||||
|
ssdpServer.start()
|
||||||
|
else:
|
||||||
|
ssdpServer = None
|
||||||
|
print("Not Starting SSDP server...")
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print('^C received, shutting down the server')
|
print('^C received, shutting down the server')
|
||||||
|
epgServer.terminate()
|
||||||
|
fhdhrServer.terminate()
|
||||||
|
if ssdpServer:
|
||||||
|
ssdpServer.terminate()
|
||||||
clean_exit()
|
clean_exit()
|
||||||
|
|||||||
@ -35,12 +35,12 @@ class NextPVR_Auth():
|
|||||||
sidfile = None
|
sidfile = None
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.sidfile = config.config["nextpvr"]["sidfile"]
|
self.sidfile = config.config["proxy"]["sidfile"]
|
||||||
self.config["npvrPIN"] = config.config["nextpvr"]["pin"]
|
self.config["npvrPIN"] = config.config["proxy"]["pin"]
|
||||||
self.config["npvrURL"] = ('%s%s:%s' %
|
self.config["npvrURL"] = ('%s%s:%s' %
|
||||||
("https://" if config.config["nextpvr"]["ssl"] else "http://",
|
("https://" if config.config["proxy"]["ssl"] else "http://",
|
||||||
config.config["nextpvr"]["address"],
|
config.config["proxy"]["address"],
|
||||||
str(config.config["nextpvr"]["port"]),
|
str(config.config["proxy"]["port"]),
|
||||||
))
|
))
|
||||||
|
|
||||||
def _check_sid(self):
|
def _check_sid(self):
|
||||||
@ -100,7 +100,7 @@ class proxyserviceFetcher():
|
|||||||
self.config = config.config
|
self.config = config.config
|
||||||
|
|
||||||
self.epg_cache = None
|
self.epg_cache = None
|
||||||
self.epg_cache_file = config.config["nextpvr"]["epg_cache"]
|
self.epg_cache_file = config.config["proxy"]["epg_cache"]
|
||||||
|
|
||||||
self.servicename = "NextPVRProxy"
|
self.servicename = "NextPVRProxy"
|
||||||
|
|
||||||
@ -118,6 +118,12 @@ class proxyserviceFetcher():
|
|||||||
epg_cache = json.load(epgfile)
|
epg_cache = json.load(epgfile)
|
||||||
return epg_cache
|
return epg_cache
|
||||||
|
|
||||||
|
def thumb_url(self, thumb_type, base_url, thumbnail):
|
||||||
|
if thumb_type == "channel":
|
||||||
|
return "http://" + str(base_url) + str(thumbnail)
|
||||||
|
elif thumb_type == "content":
|
||||||
|
return "http://" + str(base_url) + str(thumbnail)
|
||||||
|
|
||||||
def url_assembler(self):
|
def url_assembler(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -125,9 +131,9 @@ class proxyserviceFetcher():
|
|||||||
self.auth._check_sid()
|
self.auth._check_sid()
|
||||||
|
|
||||||
url = ('%s%s:%s/service?method=channel.list&sid=%s' %
|
url = ('%s%s:%s/service?method=channel.list&sid=%s' %
|
||||||
("https://" if self.config["nextpvr"]["ssl"] else "http://",
|
("https://" if self.config["proxy"]["ssl"] else "http://",
|
||||||
self.config["nextpvr"]["address"],
|
self.config["proxy"]["address"],
|
||||||
str(self.config["nextpvr"]["port"]),
|
str(self.config["proxy"]["port"]),
|
||||||
self.auth.config['sid']
|
self.auth.config['sid']
|
||||||
))
|
))
|
||||||
|
|
||||||
@ -183,9 +189,9 @@ class proxyserviceFetcher():
|
|||||||
|
|
||||||
def get_channel_stream(self, id):
|
def get_channel_stream(self, id):
|
||||||
url = ('%s%s:%s/live?channel=%s&client=%s' %
|
url = ('%s%s:%s/live?channel=%s&client=%s' %
|
||||||
("https://" if self.config["nextpvr"]["ssl"] else "http://",
|
("https://" if self.config["proxy"]["ssl"] else "http://",
|
||||||
self.config["nextpvr"]["address"],
|
self.config["proxy"]["address"],
|
||||||
str(self.config["nextpvr"]["port"]),
|
str(self.config["proxy"]["port"]),
|
||||||
str(id),
|
str(id),
|
||||||
str(id),
|
str(id),
|
||||||
))
|
))
|
||||||
@ -195,9 +201,9 @@ class proxyserviceFetcher():
|
|||||||
streamdict = {}
|
streamdict = {}
|
||||||
for c in self.get_channels():
|
for c in self.get_channels():
|
||||||
url = ('%s%s:%s/live?channel=%s&client=%s' %
|
url = ('%s%s:%s/live?channel=%s&client=%s' %
|
||||||
("https://" if self.config["nextpvr"]["ssl"] else "http://",
|
("https://" if self.config["proxy"]["ssl"] else "http://",
|
||||||
self.config["nextpvr"]["address"],
|
self.config["proxy"]["address"],
|
||||||
str(self.config["nextpvr"]["port"]),
|
str(self.config["proxy"]["port"]),
|
||||||
str(c["number"]),
|
str(c["number"]),
|
||||||
str(c["number"]),
|
str(c["number"]),
|
||||||
))
|
))
|
||||||
@ -206,9 +212,9 @@ class proxyserviceFetcher():
|
|||||||
|
|
||||||
def get_channel_thumbnail(self, channel_id):
|
def get_channel_thumbnail(self, channel_id):
|
||||||
channel_thumb_url = ("%s%s:%s/service?method=channel.icon&channel_id=%s" %
|
channel_thumb_url = ("%s%s:%s/service?method=channel.icon&channel_id=%s" %
|
||||||
("https://" if self.config["nextpvr"]["ssl"] else "http://",
|
("https://" if self.config["proxy"]["ssl"] else "http://",
|
||||||
self.config["nextpvr"]["address"],
|
self.config["proxy"]["address"],
|
||||||
str(self.config["nextpvr"]["port"]),
|
str(self.config["proxy"]["port"]),
|
||||||
str(channel_id)
|
str(channel_id)
|
||||||
))
|
))
|
||||||
return channel_thumb_url
|
return channel_thumb_url
|
||||||
@ -216,9 +222,9 @@ class proxyserviceFetcher():
|
|||||||
def get_content_thumbnail(self, content_id):
|
def get_content_thumbnail(self, content_id):
|
||||||
self.auth._check_sid()
|
self.auth._check_sid()
|
||||||
item_thumb_url = ("%s%s:%s/service?method=channel.show.artwork&sid=%s&event_id=%s" %
|
item_thumb_url = ("%s%s:%s/service?method=channel.show.artwork&sid=%s&event_id=%s" %
|
||||||
("https://" if self.config["nextpvr"]["ssl"] else "http://",
|
("https://" if self.config["proxy"]["ssl"] else "http://",
|
||||||
self.config["nextpvr"]["address"],
|
self.config["proxy"]["address"],
|
||||||
str(self.config["nextpvr"]["port"]),
|
str(self.config["proxy"]["port"]),
|
||||||
self.auth.config['sid'],
|
self.auth.config['sid'],
|
||||||
str(content_id)
|
str(content_id)
|
||||||
))
|
))
|
||||||
@ -246,9 +252,9 @@ class proxyserviceFetcher():
|
|||||||
}
|
}
|
||||||
|
|
||||||
epg_url = ('%s%s:%s/service?method=channel.listings&channel_id=%s' %
|
epg_url = ('%s%s:%s/service?method=channel.listings&channel_id=%s' %
|
||||||
("https://" if self.config["nextpvr"]["ssl"] else "http://",
|
("https://" if self.config["proxy"]["ssl"] else "http://",
|
||||||
self.config["nextpvr"]["address"],
|
self.config["proxy"]["address"],
|
||||||
str(self.config["nextpvr"]["port"]),
|
str(self.config["proxy"]["port"]),
|
||||||
str(cdict["id"]),
|
str(cdict["id"]),
|
||||||
))
|
))
|
||||||
epg_req = urllib.request.urlopen(epg_url)
|
epg_req = urllib.request.urlopen(epg_url)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user