This commit is contained in:
deathbybandaid 2020-12-15 16:28:55 -05:00
parent 7d50331bfc
commit 1eb2720347
17 changed files with 397 additions and 122 deletions

View File

@ -19,6 +19,21 @@
"value": "None,blocks",
"config_file": false,
"config_web": false
},
"reverse_days": {
"value": -1,
"config_file": false,
"config_web": false
},
"forward_days": {
"value": 7,
"config_file": false,
"config_web": false
},
"block_size": {
"value": 1800,
"config_file": false,
"config_web": false
}
}
}

View File

@ -1,7 +1,7 @@
{
"logging":{
"level":{
"value": "WARNING",
"value": "INFO",
"config_file": true,
"config_web": true
}

View File

@ -44,7 +44,7 @@ def run(settings, logger, db, script_dir, fHDHR_web, origin, alternative_epg):
try:
print("HTTP Server Starting")
fhdhr.logger.info("HTTP Server Starting")
if settings.dict["main"]["thread_method"] in ["multiprocessing"]:
fhdhr_web = multiprocessing.Process(target=fhdhrweb.run)
elif settings.dict["main"]["thread_method"] in ["threading"]:
@ -52,8 +52,15 @@ def run(settings, logger, db, script_dir, fHDHR_web, origin, alternative_epg):
if settings.dict["main"]["thread_method"] in ["multiprocessing", "threading"]:
fhdhr_web.start()
# Perform some actions now that HTTP Server is running, but don't wait for response
# Hit EPG Update API URL without waiting
try:
fhdhr.web.session.get("%s/api/startup_tasks" % (fhdhr.api.base))
except fhdhr.web.exceptions.ReadTimeout:
pass
if settings.dict["fhdhr"]["discovery_address"]:
print("SSDP Server Starting")
fhdhr.logger.info("SSDP Server Starting")
if settings.dict["main"]["thread_method"] in ["multiprocessing"]:
fhdhr_ssdp = multiprocessing.Process(target=fhdhr.device.ssdp.run)
elif settings.dict["main"]["thread_method"] in ["threading"]:
@ -62,7 +69,7 @@ def run(settings, logger, db, script_dir, fHDHR_web, origin, alternative_epg):
fhdhr_ssdp.start()
if settings.dict["epg"]["method"]:
print("EPG Update Starting")
fhdhr.logger.info("EPG Update Starting")
if settings.dict["main"]["thread_method"] in ["multiprocessing"]:
fhdhr_epg = multiprocessing.Process(target=fhdhr.device.epg.run)
elif settings.dict["main"]["thread_method"] in ["threading"]:

View File

@ -1,7 +1,7 @@
import datetime
import time
from fHDHR.tools import hours_between_datetime
from fHDHR.tools import hours_between_datetime, humanized_time
from .channel import Channel
from .chan_ident import Channel_IDs
@ -20,9 +20,6 @@ class Channels():
self.list_update_time = None
self.get_db_channels()
haseverscanned = self.fhdhr.db.get_fhdhr_value("channels", "scanned_time")
if (self.fhdhr.config.dict["fhdhr"]["chanscan_on_start"] or not haseverscanned):
self.get_channels()
def get_channel_obj(self, keyfind, valfind):
if keyfind == "number":
@ -83,7 +80,10 @@ class Channels():
channel_dict_list = self.origin.get_channels()
self.fhdhr.logger.info("Found %s channels for %s." % (len(channel_dict_list), self.fhdhr.config.dict["main"]["servicename"]))
self.fhdhr.logger.info("Performing Channel Import, This can take some time, Please wait.")
newchan = 0
chan_scan_start = time.time()
for channel_info in channel_dict_list:
chan_existing = False
@ -99,6 +99,8 @@ class Channels():
self.list[channel_id] = channel_obj
newchan += 1
self.fhdhr.logger.info("Channel Import took %s" % humanized_time(time.time() - chan_scan_start))
if not newchan:
newchan = "no"
self.fhdhr.logger.info("Found %s NEW channels." % newchan)

View File

@ -31,7 +31,14 @@ class Channel_IDs():
if cnumber:
return cnumber
used_numbers = [existing_channel["number"] for existing_channel in existing_channel_info]
used_numbers = []
for existing_channel in existing_channel_info:
if existing_channel["subnumber"]:
number = "%s.%s" % (existing_channel["number"], existing_channel["subnumber"])
else:
number = existing_channel["number"]
used_numbers.append(number)
for i in range(1000, 2000):
if str(float(i)) not in used_numbers:
break

View File

@ -1,7 +1,6 @@
import os
import time
import datetime
from collections import OrderedDict
from .blocks import blocksEPG
@ -29,12 +28,8 @@ class EPG():
self.def_method = self.fhdhr.config.dict["epg"]["def_method"]
self.sleeptime = {}
for epg_method in self.epg_methods:
if epg_method in list(self.fhdhr.config.dict.keys()):
if "update_frequency" in list(self.fhdhr.config.dict[epg_method].keys()):
self.sleeptime[epg_method] = self.fhdhr.config.dict[epg_method]["update_frequency"]
if epg_method not in list(self.sleeptime.keys()):
self.sleeptime[epg_method] = self.fhdhr.config.dict["epg"]["update_frequency"]
for epg_method in list(self.epg_handling.keys()):
self.sleeptime[epg_method] = self.fhdhr.config.dict["epg"]["update_frequency"]
self.epg_update_url = "%s/api/epg?method=update" % (self.fhdhr.api.base)
@ -60,38 +55,28 @@ class EPG():
self.fhdhr.db.delete_fhdhr_value("epg_dict", method)
def whats_on_now(self, channel_number, method=None):
nowtime = datetime.datetime.utcnow()
def whats_on_now(self, channel_number, method=None, chan_obj=None, chan_dict=None):
nowtime = time.time()
epgdict = self.get_epg(method)
try:
listings = epgdict[channel_number]["listing"]
except KeyError:
listings = []
for listing in listings:
start_time = datetime.datetime.strptime(listing["time_start"], '%Y%m%d%H%M%S +0000')
end_time = datetime.datetime.strptime(listing["time_end"], '%Y%m%d%H%M%S +0000')
if start_time <= nowtime <= end_time:
for time_item in ["time_start", "time_end"]:
time_value = listing[time_item]
if str(time_value).endswith("+00:00"):
listing[time_item] = datetime.datetime.strptime(time_value, '%Y%m%d%H%M%S +00:00').timestamp()
elif str(time_value).endswith("+0000"):
listing[time_item] = datetime.datetime.strptime(time_value, '%Y%m%d%H%M%S +0000').timestamp()
else:
listing[time_item] = int(time_value)
if int(listing["time_start"]) <= nowtime <= int(listing["time_end"]):
epgitem = epgdict[channel_number].copy()
epgitem["listing"] = [listing]
return epgitem
epgitem = epgdict[channel_number].copy()
epgitem["listing"] = [{
"time_start": None,
"time_end": None,
"duration_minutes": None,
"thumbnail": None,
"title": "Unavailable",
"sub-title": "Unavailable",
"description": "Unavailable",
"rating": "N/A",
"episodetitle": None,
"releaseyear": None,
"genres": [],
"seasonnumber": None,
"episodenumber": None,
"isnew": False,
"id": None,
}]
epgitem["listing"] = [self.blocks.empty_listing(chan_obj=None, chan_dict=None)]
return epgitem
def whats_on_allchans(self, method=None):
@ -102,23 +87,26 @@ class EPG():
method not in self.fhdhr.config.dict["epg"]["valid_epg_methods"]):
method = "origin"
channel_guide_list = []
channel_guide_dict = {}
epgdict = self.get_epg(method)
if method in ["blocks", "origin", self.fhdhr.config.dict["main"]["dictpopname"]]:
epgdict = epgdict.copy()
for c in list(epgdict.keys()):
epgdict = epgdict.copy()
for c in list(epgdict.keys()):
if method in ["blocks", "origin", self.fhdhr.config.dict["main"]["dictpopname"]]:
chan_obj = self.channels.get_channel_obj("origin_id", epgdict[c]["id"])
epgdict[chan_obj.number] = epgdict.pop(c)
epgdict[chan_obj.number]["name"] = chan_obj.dict["name"]
epgdict[chan_obj.number]["callsign"] = chan_obj.dict["callsign"]
epgdict[chan_obj.number]["number"] = chan_obj.number
epgdict[chan_obj.number]["id"] = chan_obj.dict["origin_id"]
epgdict[chan_obj.number]["thumbnail"] = chan_obj.thumbnail
for channel_number in list(epgdict.keys()):
whatson = self.whats_on_now(channel_number, method)
channel_number = chan_obj.number
epgdict[channel_number] = epgdict.pop(c)
epgdict[channel_number]["name"] = chan_obj.dict["name"]
epgdict[channel_number]["callsign"] = chan_obj.dict["callsign"]
epgdict[channel_number]["number"] = chan_obj.number
epgdict[channel_number]["id"] = chan_obj.dict["origin_id"]
epgdict[channel_number]["thumbnail"] = chan_obj.thumbnail
else:
chan_obj = None
channel_number = c
whatson = self.whats_on_now(channel_number, method, chan_dict=epgdict, chan_obj=chan_obj)
if whatson:
channel_guide_list.append(whatson)
return channel_guide_list
channel_guide_dict[channel_number] = whatson
return channel_guide_dict
def get_epg(self, method=None):
@ -194,18 +182,108 @@ class EPG():
else:
programguide = self.epg_handling[method].update_epg()
programguide = OrderedDict(sorted(programguide.items()))
# Sort the channels
clean_prog_guide = {}
sorted_chan_list = sorted(list(programguide.keys()))
for cnum in sorted_chan_list:
if cnum not in list(clean_prog_guide.keys()):
clean_prog_guide[cnum] = programguide[cnum].copy()
programguide = clean_prog_guide.copy()
for cnum in programguide:
# sort the channel listings by time stamp
for cnum in list(programguide.keys()):
programguide[cnum]["listing"] = sorted(programguide[cnum]["listing"], key=lambda i: i['time_start'])
if method in ["blocks", "origin", self.fhdhr.config.dict["main"]["dictpopname"]]:
# Gernate Block periods for between EPG data, if missing
clean_prog_guide = {}
desired_start_time = (datetime.datetime.today() + datetime.timedelta(days=self.fhdhr.config.dict["epg"]["reverse_days"])).timestamp()
desired_end_time = (datetime.datetime.today() + datetime.timedelta(days=self.fhdhr.config.dict["epg"]["forward_days"])).timestamp()
for cnum in list(programguide.keys()):
if cnum not in list(clean_prog_guide.keys()):
clean_prog_guide[cnum] = programguide[cnum].copy()
clean_prog_guide[cnum]["listing"] = []
if method in ["blocks", "origin", self.fhdhr.config.dict["main"]["dictpopname"]]:
chan_obj = self.channels.get_channel_obj("origin_id", programguide[cnum]["id"])
else:
chan_obj = None
# Generate Blocks for Channels containing No Lisiings
if not len(programguide[cnum]["listing"]):
timestamps = self.blocks.timestamps_between(desired_start_time, desired_end_time)
clean_prog_dicts = self.blocks.empty_channel_epg(timestamps, chan_dict=programguide[cnum], chan_obj=chan_obj)
clean_prog_guide[cnum]["listing"].extend(clean_prog_dicts)
else:
# Clean Timetamps from old xmltv method to timestamps
progindex = 0
for program_item in programguide[cnum]["listing"]:
for time_item in ["time_start", "time_end"]:
time_value = programguide[cnum]["listing"][progindex][time_item]
if str(time_value).endswith("+00:00"):
programguide[cnum]["listing"][progindex][time_item] = datetime.datetime.strptime(time_value, '%Y%m%d%H%M%S +00:00').timestamp()
elif str(time_value).endswith("+0000"):
programguide[cnum]["listing"][progindex][time_item] = datetime.datetime.strptime(time_value, '%Y%m%d%H%M%S +0000').timestamp()
else:
programguide[cnum]["listing"][progindex][time_item] = int(time_value)
progindex += 1
# Generate time before the listing actually starts
first_prog_time = programguide[cnum]["listing"][0]['time_start']
if desired_start_time < first_prog_time:
timestamps = self.blocks.timestamps_between(desired_start_time, first_prog_time)
clean_prog_dicts = self.blocks.empty_channel_epg(timestamps, chan_dict=programguide[cnum], chan_obj=chan_obj)
clean_prog_guide[cnum]["listing"].extend(clean_prog_dicts)
# Generate time blocks between events if chunks of time are missing
progindex = 0
for program_item in programguide[cnum]["listing"]:
try:
nextprog_dict = programguide[cnum]["listing"][progindex + 1]
except IndexError:
nextprog_dict = None
if not nextprog_dict:
clean_prog_guide[cnum]["listing"].append(program_item)
else:
if nextprog_dict['time_start'] > program_item['time_end']:
timestamps = self.blocks.timestamps_between(program_item['time_end'], nextprog_dict['time_start'])
clean_prog_dicts = self.blocks.empty_channel_epg(timestamps, chan_dict=programguide[cnum], chan_obj=chan_obj)
clean_prog_guide[cnum]["listing"].extend(clean_prog_dicts)
else:
clean_prog_guide[cnum]["listing"].append(program_item)
progindex += 1
# Generate time after the listing actually ends
end_prog_time = programguide[cnum]["listing"][progindex]['time_end']
if desired_end_time > end_prog_time:
timestamps = self.blocks.timestamps_between(end_prog_time, desired_end_time)
clean_prog_dicts = self.blocks.empty_channel_epg(timestamps, chan_dict=programguide[cnum], chan_obj=chan_obj)
clean_prog_guide[cnum]["listing"].extend(clean_prog_dicts)
programguide = clean_prog_guide.copy()
# if a stock method, generate Blocks EPG for missing channels
if method in ["blocks", "origin", self.fhdhr.config.dict["main"]["dictpopname"]]:
timestamps = self.blocks.timestamps
for fhdhr_id in list(self.channels.list.keys()):
chan_obj = self.channels.list[fhdhr_id]
if str(chan_obj.number) not in list(programguide.keys()):
programguide[str(chan_obj.number)] = chan_obj.epgdict
clean_prog_dicts = self.blocks.empty_channel_epg(timestamps, chan_obj=chan_obj)
programguide[str(chan_obj.number)]["listing"].extend(clean_prog_dicts)
# Make Thumbnails for missing thumbnails
for cnum in list(programguide.keys()):
if not programguide[cnum]["thumbnail"]:
programguide[cnum]["thumbnail"] = "/api/images?method=generate&type=channel&message=%s" % programguide[cnum]["number"]
programguide[cnum]["listing"] = sorted(programguide[cnum]["listing"], key=lambda i: i['time_start'])
prog_index = 0
for program_item in programguide[cnum]["listing"]:
if not programguide[cnum]["listing"][prog_index]["thumbnail"]:
programguide[cnum]["listing"][prog_index]["thumbnail"] = programguide[cnum]["thumbnail"]
prog_index += 1
self.epgdict = programguide
self.fhdhr.db.set_fhdhr_value("epg_dict", method, programguide)
@ -213,12 +291,14 @@ class EPG():
self.fhdhr.logger.info("Wrote " + epgtypename + " EPG cache.")
def run(self):
for epg_method in self.epg_methods:
self.fhdhr.web.session.get(self.epg_update_url)
time.sleep(1800)
try:
while True:
for epg_method in self.epg_methods:
if time.time() >= (self.fhdhr.db.get_fhdhr_value("update_time", epg_method) + self.sleeptime[epg_method]):
last_update_time = self.fhdhr.db.get_fhdhr_value("update_time", epg_method)
if not last_update_time:
self.fhdhr.web.session.get(self.epg_update_url)
elif time.time() >= (last_update_time + self.sleeptime[epg_method]):
self.fhdhr.web.session.get(self.epg_update_url)
time.sleep(360)
except KeyboardInterrupt:

View File

@ -19,56 +19,99 @@ class blocksEPG():
if str(chan_obj.number) not in list(programguide.keys()):
programguide[str(chan_obj.number)] = chan_obj.epgdict
clean_prog_dicts = self.empty_channel_epg(timestamps, chan_obj)
clean_prog_dicts = self.empty_channel_epg(timestamps, chan_obj=chan_obj)
for clean_prog_dict in clean_prog_dicts:
programguide[str(chan_obj.number)]["listing"].append(clean_prog_dict)
return programguide
def get_content_thumbnail(self, content_id):
return "/api/images?method=generate&type=content&message=%s" % content_id
@property
def timestamps(self):
timestamps = []
todaydate = datetime.date.today()
for x in range(0, 6):
xdate = todaydate + datetime.timedelta(days=x)
xtdate = xdate + datetime.timedelta(days=1)
desired_start_time = (datetime.datetime.today() + datetime.timedelta(days=self.fhdhr.config.dict["epg"]["reverse_days"])).timestamp()
desired_end_time = (datetime.datetime.today() + datetime.timedelta(days=self.fhdhr.config.dict["epg"]["forward_days"])).timestamp()
return self.timestamps_between(desired_start_time, desired_end_time)
for hour in range(0, 24):
time_start = datetime.datetime.combine(xdate, datetime.time(hour, 0))
if hour + 1 < 24:
time_end = datetime.datetime.combine(xdate, datetime.time(hour + 1, 0))
else:
time_end = datetime.datetime.combine(xtdate, datetime.time(0, 0))
timestampdict = {
"time_start": str(time_start.strftime('%Y%m%d%H%M%S')) + " +0000",
"time_end": str(time_end.strftime('%Y%m%d%H%M%S')) + " +0000",
}
timestamps.append(timestampdict)
def timestamps_between(self, starttime, endtime):
timestamps = []
desired_blocksize = self.fhdhr.config.dict["epg"]["block_size"]
current_time = starttime
while (current_time + desired_blocksize) <= endtime:
timestampdict = {
"time_start": current_time,
"time_end": current_time + desired_blocksize,
}
timestamps.append(timestampdict)
current_time += desired_blocksize
if current_time < endtime:
timestampdict = {
"time_start": current_time,
"time_end": endtime
}
timestamps.append(timestampdict)
return timestamps
def empty_channel_epg(self, timestamps, chan_obj):
def single_channel_epg(self, timestampdict, chan_obj=None, chan_dict=None):
if chan_obj:
content_id = "%s_%s" % (chan_obj.dict["origin_id"], timestampdict['time_start'])
elif chan_dict:
content_id = "%s_%s" % (chan_dict["id"], timestampdict['time_start'])
clean_prog_dict = {
"time_start": timestampdict['time_start'],
"time_end": timestampdict['time_end'],
"duration_minutes": (timestampdict['time_end'] - timestampdict['time_start']) / 60,
"title": "Unavailable",
"sub-title": "Unavailable",
"description": "Unavailable",
"rating": "N/A",
"episodetitle": None,
"releaseyear": None,
"genres": [],
"seasonnumber": None,
"episodenumber": None,
"isnew": False,
"id": content_id,
}
if chan_obj:
clean_prog_dict["thumbnail"] = chan_obj.thumbnail
elif chan_dict:
clean_prog_dict["thumbnail"] = chan_dict["thumbnail"]
if not clean_prog_dict["thumbnail"]:
clean_prog_dict["thumbnail"] = "/api/images?method=generate&type=content&message=%s" % content_id
return clean_prog_dict
def empty_channel_epg(self, timestamps, chan_obj=None, chan_dict=None):
clean_prog_dicts = []
for timestamp in timestamps:
content_id = "%s_%s" % (chan_obj.dict["origin_id"], str(timestamp['time_start']).split(" ")[0])
clean_prog_dict = {
"time_start": timestamp['time_start'],
"time_end": timestamp['time_end'],
"duration_minutes": 60,
"thumbnail": chan_obj.dict["thumbnail"] or self.get_content_thumbnail(content_id),
"title": "Unavailable",
"sub-title": "Unavailable",
"description": "Unavailable",
"rating": "N/A",
"episodetitle": None,
"releaseyear": None,
"genres": [],
"seasonnumber": None,
"episodenumber": None,
"isnew": False,
"id": content_id,
}
for timestampdict in timestamps:
clean_prog_dict = self.single_channel_epg(timestampdict, chan_obj=chan_obj, chan_dict=chan_dict)
clean_prog_dicts.append(clean_prog_dict)
return clean_prog_dicts
def empty_listing(self, chan_obj=None, chan_dict=None):
clean_prog_dict = {
"time_start": None,
"time_end": None,
"duration_minutes": None,
"title": "Unavailable",
"sub-title": "Unavailable",
"description": "Unavailable",
"rating": "N/A",
"episodetitle": None,
"releaseyear": None,
"genres": [],
"seasonnumber": None,
"episodenumber": None,
"isnew": False,
"id": "Unavailable",
}
if chan_obj:
clean_prog_dict["thumbnail"] = chan_obj.thumbnail
elif chan_dict:
clean_prog_dict["thumbnail"] = chan_dict["thumbnail"]
if not clean_prog_dict["thumbnail"]:
clean_prog_dict["thumbnail"] = "/api/images?method=generate&type=content&message=Unavailable"
return clean_prog_dict

View File

@ -95,12 +95,17 @@ class Tuners():
if not stream_args["channelUri"]:
raise TunerError("806 - Tune Failed")
channelUri_headers = self.fhdhr.web.session.head(stream_args["channelUri"]).headers
stream_args["true_content_type"] = channelUri_headers['Content-Type']
if stream_args["true_content_type"].startswith(tuple(["application/", "text/"])):
if stream_args["channelUri"].startswith("udp://"):
stream_args["true_content_type"] = "video/mpeg"
stream_args["content_type"] = "video/mpeg"
else:
stream_args["content_type"] = stream_args["true_content_type"]
channelUri_headers = self.fhdhr.web.session.head(stream_args["channelUri"]).headers
stream_args["true_content_type"] = channelUri_headers['Content-Type']
if stream_args["true_content_type"].startswith(tuple(["application/", "text/"])):
stream_args["content_type"] = "video/mpeg"
else:
stream_args["content_type"] = stream_args["true_content_type"]
return stream_args

View File

@ -1,5 +1,6 @@
from .root_url import Root_URL
from .startup_tasks import Startup_Tasks
from .cluster import Cluster
from .settings import Settings
@ -19,6 +20,7 @@ class fHDHR_API():
self.fhdhr = fhdhr
self.root_url = Root_URL(fhdhr)
self.startup_tasks = Startup_Tasks(fhdhr)
self.cluster = Cluster(fhdhr)
self.settings = Settings(fhdhr)

View File

@ -0,0 +1,35 @@
class Startup_Tasks():
endpoints = ["/api/startup_tasks"]
endpoint_name = "api_startup_tasks"
endpoint_methods = ["GET", "POST"]
def __init__(self, fhdhr):
self.fhdhr = fhdhr
self.epg_update_url = "%s/api/epg?method=update" % (self.fhdhr.api.base)
self.channel_update_url = "%s/api/channels?method=scan" % (self.fhdhr.api.base)
def __call__(self, *args):
return self.get(*args)
def get(self, *args):
# Hit Channel Update API URL without waiting unless we've never scanned before
haseverscanned = self.fhdhr.db.get_fhdhr_value("channels", "scanned_time")
if not haseverscanned:
self.fhdhr.web.session.get(self.channel_update_url)
elif self.fhdhr.config.dict["fhdhr"]["chanscan_on_start"]:
try:
self.fhdhr.web.session.get(self.channel_update_url, timeout=0.0000000001)
except self.fhdhr.web.exceptions.ReadTimeout:
pass
# Hit EPG Update API URL without waiting
try:
self.fhdhr.web.session.get(self.epg_update_url, timeout=0.0000000001)
except self.fhdhr.web.exceptions.ReadTimeout:
pass
return "Success"

View File

@ -1,6 +1,7 @@
from flask import Response, request, redirect, abort, stream_with_context
import urllib.parse
import uuid
import json
from fHDHR.exceptions import TunerError
@ -116,6 +117,21 @@ class Tuners():
tuner = self.fhdhr.device.tuners.tuners[str(tuner_number)]
tuner.channel_scan()
elif method == "status":
if not tuner_number:
tuner_status = self.fhdhr.device.tuners.status()
elif str(tuner_number) in list(self.fhdhr.device.tuners.tuners.keys()):
tuner_status = self.fhdhr.device.tuners.tuners[str(tuner_number)].get_status()
else:
tuner_status = ["Invalid Tuner %s" % tuner_number]
tuner_status_json = json.dumps(tuner_status, indent=4)
return Response(status=200,
response=tuner_status_json,
mimetype='application/json')
else:
return "%s Invalid Method" % method

View File

@ -2,6 +2,7 @@ from flask import Response, request, redirect
import xml.etree.ElementTree
from io import BytesIO
import urllib.parse
import datetime
from fHDHR.tools import sub_el
@ -90,6 +91,18 @@ class xmlTV():
"""This method is called when creation of a full xmltv is not possible"""
return self.xmltv_file(self.xmltv_headers())
def timestamp_to_datetime(self, time_start, time_end):
xmltvtimetamps = {}
for time_item, time_value in zip(["time_start", "time_end"], [time_start, time_end]):
if str(time_value).endswith(tuple(["+0000", "+00:00"])):
xmltvtimetamps[time_item] = str(time_value)
else:
xmltvtimetamps[time_item] = str(datetime.datetime.fromtimestamp(time_value)) + " +0000"
return xmltvtimetamps
def create_xmltv(self, base_url, epgdict, source):
if not epgdict:
return self.xmltv_empty()
@ -129,9 +142,11 @@ class xmlTV():
for program in channel_listing:
xmltvtimetamps = self.timestamp_to_datetime(program['time_start'], program['time_end'])
prog_out = sub_el(out, 'programme',
start=program['time_start'],
stop=program['time_end'],
start=xmltvtimetamps['time_start'],
stop=xmltvtimetamps['time_end'],
channel=str(channelnum))
sub_el(prog_out, 'title', lang='en', text=program['title'])

View File

@ -24,4 +24,6 @@ class Channels_Editor_HTML():
channelslist.append(channel_dict)
channelslist = sorted(channelslist, key=lambda i: i['number'])
return render_template('channels_editor.html', request=request, fhdhr=self.fhdhr, channelslist=channelslist)

View File

@ -31,4 +31,6 @@ class Channels_HTML():
if channel_dict["enabled"]:
channels_dict["Enabled"] += 1
channelslist = sorted(channelslist, key=lambda i: i['number'])
return render_template('channels.html', request=request, fhdhr=self.fhdhr, channelslist=channelslist, channels_dict=channels_dict, list=list)

View File

@ -14,9 +14,28 @@ class Guide_HTML():
def __call__(self, *args):
return self.get(*args)
def number_sort(self, chan_dict):
for channel in list(chan_dict.keys()):
number = chan_dict[channel]["number"]
chan_dict[channel]["number"] = number.split(".")[0]
try:
chan_dict[channel]["subnumber"] = number.split(".")[1]
except IndexError:
chan_dict[channel]["subnumber"] = None
sorted_chan_list = sorted(list(chan_dict.keys()), key=lambda i: (int(chan_dict[i]['number']), int(chan_dict[i]['subnumber'] or 0)))
sorted_chan_dict = {}
for cnum in sorted_chan_list:
if cnum not in list(sorted_chan_dict.keys()):
sorted_chan_dict[cnum] = chan_dict[cnum].copy()
if sorted_chan_dict[cnum]["subnumber"]:
sorted_chan_dict[cnum]["number"] = "%s.%s" % (sorted_chan_dict[cnum]["number"], sorted_chan_dict[cnum]["subnumber"])
del sorted_chan_dict[cnum]["subnumber"]
chan_dict = sorted_chan_dict.copy()
return chan_dict
def get(self, *args):
nowtime = datetime.datetime.utcnow()
nowtime = datetime.datetime.utcnow().timestamp()
chan_guide_list = []
@ -25,24 +44,38 @@ class Guide_HTML():
if source not in epg_methods:
source = self.fhdhr.device.epg.def_method
for channel in self.fhdhr.device.epg.whats_on_allchans(source):
if channel["listing"][0]["time_end"]:
end_time = datetime.datetime.strptime(channel["listing"][0]["time_end"], '%Y%m%d%H%M%S +0000')
remaining_time = humanized_time(int((end_time - nowtime).total_seconds()))
whatson = self.fhdhr.device.epg.whats_on_allchans(source)
# Sort the channels
sorted_chan_guide = self.number_sort(whatson)
for channel in list(sorted_chan_guide.keys()):
if sorted_chan_guide[channel]["listing"][0]["time_end"]:
remaining_time = humanized_time(sorted_chan_guide[channel]["listing"][0]["time_end"] - nowtime)
else:
remaining_time = "N/A"
chan_dict = {
"name": channel["name"],
"number": channel["number"],
"chan_thumbnail": channel["thumbnail"],
"listing_title": channel["listing"][0]["title"],
"listing_thumbnail": channel["listing"][0]["thumbnail"],
"listing_description": channel["listing"][0]["description"],
"remaining_time": str(remaining_time)
"name": sorted_chan_guide[channel]["name"],
"number": sorted_chan_guide[channel]["number"],
"chan_thumbnail": sorted_chan_guide[channel]["thumbnail"],
"listing_title": sorted_chan_guide[channel]["listing"][0]["title"],
"listing_thumbnail": sorted_chan_guide[channel]["listing"][0]["thumbnail"],
"listing_description": sorted_chan_guide[channel]["listing"][0]["description"],
"listing_remaining_time": str(remaining_time)
}
for time_item in ["time_start", "time_end"]:
if not sorted_chan_guide[channel]["listing"][0][time_item]:
chan_dict["listing_%s" % time_item] = "N/A"
elif str(sorted_chan_guide[channel]["listing"][0][time_item]).endswith(tuple(["+0000", "+00:00"])):
chan_dict["listing_%s" % time_item] = str(sorted_chan_guide[channel]["listing"][0][time_item])
else:
chan_dict["listing_%s" % time_item] = str(datetime.datetime.fromtimestamp(sorted_chan_guide[channel]["listing"][0][time_item]))
if source in ["blocks", "origin", self.fhdhr.config.dict["main"]["dictpopname"]]:
chan_obj = self.fhdhr.device.channels.get_channel_obj("origin_id", channel["id"])
chan_obj = self.fhdhr.device.channels.get_channel_obj("origin_id", sorted_chan_guide[channel]["id"])
chan_dict["name"] = chan_obj.dict["name"]
chan_dict["number"] = chan_obj.number
@ -50,6 +83,13 @@ class Guide_HTML():
chan_dict["enabled"] = chan_obj.dict["enabled"]
chan_dict["play_url"] = chan_obj.play_url
chan_dict["listing_thumbnail"] = chan_dict["listing_thumbnail"] or chan_obj.thumbnail
else:
if not chan_dict["listing_thumbnail"]:
chan_dict["listing_thumbnail"] = chan_dict["chan_thumbnail"]
if not chan_dict["listing_thumbnail"]:
chan_dict["listing_thumbnail"] = "/api/images?method=generate&type=channel&message=%s" % chan_dict["number"]
chan_guide_list.append(chan_dict)
return render_template('guide.html', request=request, fhdhr=self.fhdhr, chan_guide_list=chan_guide_list, epg_methods=epg_methods, source=source)

View File

@ -21,6 +21,8 @@
<th>Content Title</th>
<th>Content Thumbnail</th>
<th>Content Description</th>
<th>Start Time (UTC)</th>
<th>End Time (UTC)</th>
<th>Content Remaining Time</th>
</tr>
@ -39,7 +41,9 @@
<td>{{ chan_dict["listing_title"] }}</td>
<td><img src="{{ chan_dict["listing_thumbnail"] }}" alt="{{ chan_dict["listing_title"] }}" width="100" height="100"></td>
<td>{{ chan_dict["listing_description"] }}</td>
<td>{{ chan_dict["remaining_time"] }}</td>
<td>{{ chan_dict["listing_time_start"] }}</td>
<td>{{ chan_dict["listing_time_end"] }}</td>
<td>{{ chan_dict["listing_remaining_time"] }}</td>
</tr>
{% endfor %}

View File

@ -13,8 +13,8 @@ class OriginEPG():
filtered_chan_dict = fhdhr_channels.origin.get_channel_dict(fhdhr_channels.origin.filtered_chan_list, "name", chan_obj.dict["origin_name"])
if str(chan_obj.dict["number"]) not in list(programguide.keys()):
programguide[str(chan_obj.dict["number"])] = chan_obj.epgdict
if str(chan_obj.number) not in list(programguide.keys()):
programguide[str(chan_obj.number)] = chan_obj.epgdict
if filtered_chan_dict["tvg"]["url"]:
print(filtered_chan_dict["tvg"]["url"])