diff --git a/fHDHR/device/epg/__init__.py b/fHDHR/device/epg/__init__.py index d52b732..f7fd1c4 100644 --- a/fHDHR/device/epg/__init__.py +++ b/fHDHR/device/epg/__init__.py @@ -2,6 +2,8 @@ import os import time import datetime +from fHDHR.tools import channel_sort + from .blocks import blocksEPG @@ -120,17 +122,12 @@ class EPG(): method not in self.fhdhr.config.dict["epg"]["valid_epg_methods"]): method = "origin" - if method not in list(self.epgdict.keys()): + if method in list(self.epgdict.keys()): + return self.epgdict[method] - epgdict = self.fhdhr.db.get_fhdhr_value("epg_dict", method) or None - if not epgdict: - self.update(method) - self.epgdict[method] = self.fhdhr.db.get_fhdhr_value("epg_dict", method) or {} - else: - self.epgdict[method] = epgdict - return self.epgdict[method] - else: - return self.epgdict[method] + self.update(method) + self.epgdict[method] = self.fhdhr.db.get_fhdhr_value("epg_dict", method) or {} + return self.epgdict[method] def get_thumbnail(self, itemtype, itemid): if itemtype == "channel": @@ -186,14 +183,6 @@ class EPG(): else: programguide = self.epg_handling[method].update_epg() - # 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() - # 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']) @@ -289,7 +278,13 @@ class EPG(): programguide[cnum]["listing"][prog_index]["thumbnail"] = programguide[cnum]["thumbnail"] prog_index += 1 - self.epgdict = programguide + # Sort the channels + sorted_channel_list = channel_sort(list(programguide.keys())) + sorted_chan_guide = {} + for channel in sorted_channel_list: + sorted_chan_guide[channel] = programguide[channel] + + self.epgdict[method] = sorted_chan_guide self.fhdhr.db.set_fhdhr_value("epg_dict", method, programguide) self.fhdhr.db.set_fhdhr_value("update_time", method, time.time()) self.fhdhr.logger.info("Wrote " + epgtypename + " EPG cache.") diff --git a/fHDHR/tools/__init__.py b/fHDHR/tools/__init__.py index 306db02..383ce49 100644 --- a/fHDHR/tools/__init__.py +++ b/fHDHR/tools/__init__.py @@ -8,6 +8,19 @@ UNARY_OPS = (ast.UAdd, ast.USub) BINARY_OPS = (ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod) +def channel_sort(channel_list): + """Take a list of channel number strings and sort the Numbers and SubNumbers""" + chan_dict_list_split = {} + for number in channel_list: + try: + subnumber = number.split(".")[1] + except IndexError: + subnumber = None + prinumber = number.split(".")[0] + chan_dict_list_split[number] = {"number": prinumber, "subnumber": subnumber} + return sorted(chan_dict_list_split, key=lambda i: (int(chan_dict_list_split[i]['number']), int(chan_dict_list_split[i]['subnumber'] or 0))) + + def is_docker(): path = "/proc/self/cgroup" if not os.path.isfile(path): diff --git a/fHDHR_web/api/channels.py b/fHDHR_web/api/channels.py index 4b8813e..946245a 100644 --- a/fHDHR_web/api/channels.py +++ b/fHDHR_web/api/channels.py @@ -2,6 +2,8 @@ from flask import request, redirect, Response, abort import urllib.parse import json +from fHDHR.tools import channel_sort + class Channels(): endpoints = ["/api/channels"] @@ -20,14 +22,21 @@ class Channels(): redirect_url = request.args.get('redirect', default=None, type=str) if method == "get": - channels_info = [] + channels_info = {} for fhdhr_id in [x["id"] for x in self.fhdhr.device.channels.get_channels()]: channel_obj = self.fhdhr.device.channels.list[fhdhr_id] channel_dict = channel_obj.dict.copy() channel_dict["play_url"] = channel_obj.play_url channel_dict["stream_url"] = channel_obj.stream_url - channels_info.append(channel_dict) - channels_info_json = json.dumps(channels_info, indent=4) + channels_info[channel_obj.number] = channel_dict + + # Sort the channels + sorted_channel_list = channel_sort(list(channels_info.keys())) + sorted_chan_guide = [] + for channel in sorted_channel_list: + sorted_chan_guide.append(channels_info[channel]) + + channels_info_json = json.dumps(sorted_chan_guide, indent=4) return Response(status=200, response=channels_info_json, diff --git a/fHDHR_web/api/m3u.py b/fHDHR_web/api/m3u.py index 5c87468..f018cde 100644 --- a/fHDHR_web/api/m3u.py +++ b/fHDHR_web/api/m3u.py @@ -2,6 +2,8 @@ from flask import Response, request, redirect import urllib.parse from io import StringIO +from fHDHR.tools import channel_sort + class M3U(): endpoints = ["/api/m3u", "/api/channels.m3u"] @@ -56,6 +58,7 @@ class M3U(): else: return "Invalid Channel" + channels_info = {} for channel_obj in channel_items: if self.fhdhr.config.dict["epg"]["images"] == "proxy" or not channel_obj.thumbnail: @@ -64,18 +67,31 @@ class M3U(): else: logourl = channel_obj.thumbnail - fakefile.write( - "%s\n" % ( - RECORD_MARKER + ":0" + " " + - "channelID=\"" + str(channel_obj.dict['origin_id']) + "\" " + - "tvg-chno=\"" + str(channel_obj.dict['number']) + "\" " + - "tvg-name=\"" + str(channel_obj.dict['name']) + "\" " + - "tvg-id=\"" + str(channel_obj.dict['number']) + "\" " + - "tvg-logo=\"" + logourl + "\" " + - "group-title=\"" + self.fhdhr.config.dict["fhdhr"]["friendlyname"] + "\"," + str(channel_obj.dict['name'])) - ) + channels_info[channel_obj.number] = { + "channelID": str(channel_obj.dict['origin_id']), + "tvg-chno": str(channel_obj.number), + "tvg-name": str(channel_obj.dict['name']), + "tvg-id": str(channel_obj.number), + "tvg-logo": logourl, + "group-title": self.fhdhr.config.dict["fhdhr"]["friendlyname"], + "group-titleb": str(channel_obj.dict['name']), + "stream_url": "%s%s" % (base_url, channel_obj.stream_url) + } - fakefile.write("%s%s\n" % (base_url, channel_obj.stream_url)) + # Sort the channels + sorted_channel_list = channel_sort(list(channels_info.keys())) + sorted_chan_guide = [] + for channel in sorted_channel_list: + sorted_chan_guide.append(channels_info[channel]) + + for channel_item_dict in sorted_chan_guide: + m3ustring = "%s:0 " % (RECORD_MARKER) + for chan_key in list(channel_item_dict.keys()): + if not chan_key.startswith(tuple(["group-title", "stream_url"])): + m3ustring += "%s=\"%s\" " % (chan_key, channel_item_dict[chan_key]) + m3ustring += "group-title=\"%s\"%s\n" % (channel_item_dict["group-title"], channel_item_dict["group-titleb"]) + m3ustring += "%s\n" % channel_item_dict["stream_url"] + fakefile.write(m3ustring) channels_m3u = fakefile.getvalue() diff --git a/fHDHR_web/hdhr/lineup_json.py b/fHDHR_web/hdhr/lineup_json.py index fae562d..4e6d089 100644 --- a/fHDHR_web/hdhr/lineup_json.py +++ b/fHDHR_web/hdhr/lineup_json.py @@ -1,6 +1,8 @@ from flask import Response, request import json +from fHDHR.tools import channel_sort + class Lineup_JSON(): endpoints = ["/lineup.json", "/hdhr/lineup.json"] @@ -18,7 +20,7 @@ class Lineup_JSON(): show = request.args.get('show', default="all", type=str) - jsonlineup = [] + channelslist = {} for fhdhr_id in [x["id"] for x in self.fhdhr.device.channels.get_channels()]: channel_obj = self.fhdhr.device.channels.list[fhdhr_id] if channel_obj.enabled or show == "found": @@ -28,9 +30,16 @@ class Lineup_JSON(): lineup_dict["Enabled"] = 1 elif show == "found" and not channel_obj.enabled: lineup_dict["Enabled"] = 0 - jsonlineup.append(lineup_dict) - lineup_json = json.dumps(jsonlineup, indent=4) + channelslist[channel_obj.number] = lineup_dict + + # Sort the channels + sorted_channel_list = channel_sort(list(channelslist.keys())) + sorted_chan_guide = [] + for channel in sorted_channel_list: + sorted_chan_guide.append(channelslist[channel]) + + lineup_json = json.dumps(sorted_chan_guide, indent=4) return Response(status=200, response=lineup_json, diff --git a/fHDHR_web/hdhr/lineup_xml.py b/fHDHR_web/hdhr/lineup_xml.py index e52d9a3..7c434f2 100644 --- a/fHDHR_web/hdhr/lineup_xml.py +++ b/fHDHR_web/hdhr/lineup_xml.py @@ -2,7 +2,7 @@ from flask import Response, request from io import BytesIO import xml.etree.ElementTree -from fHDHR.tools import sub_el +from fHDHR.tools import channel_sort, sub_el class Lineup_XML(): @@ -21,19 +21,30 @@ class Lineup_XML(): show = request.args.get('show', default="all", type=str) - out = xml.etree.ElementTree.Element('Lineup') + channelslist = {} for fhdhr_id in [x["id"] for x in self.fhdhr.device.channels.get_channels()]: channel_obj = self.fhdhr.device.channels.list[fhdhr_id] if channel_obj.enabled or show == "found": - program_out = sub_el(out, 'Program') lineup_dict = channel_obj.lineup_dict - lineup_dict["URL"] = base_url + lineup_dict["URL"] + lineup_dict["URL"] = "%s%s" % (base_url, lineup_dict["URL"]) if show == "found" and channel_obj.enabled: lineup_dict["Enabled"] = 1 elif show == "found" and not channel_obj.enabled: lineup_dict["Enabled"] = 0 - for key in list(lineup_dict.keys()): - sub_el(program_out, str(key), str(lineup_dict[key])) + + channelslist[channel_obj.number] = lineup_dict + + # Sort the channels + sorted_channel_list = channel_sort(list(channelslist.keys())) + sorted_chan_guide = [] + for channel in sorted_channel_list: + sorted_chan_guide.append(channelslist[channel]) + + out = xml.etree.ElementTree.Element('Lineup') + for lineup_dict in sorted_chan_guide: + program_out = sub_el(out, 'Program') + for key in list(lineup_dict.keys()): + sub_el(program_out, str(key), str(lineup_dict[key])) fakefile = BytesIO() fakefile.write(b'\n') diff --git a/fHDHR_web/pages/channels_editor.py b/fHDHR_web/pages/channels_editor.py index ea8906f..5555b8e 100644 --- a/fHDHR_web/pages/channels_editor.py +++ b/fHDHR_web/pages/channels_editor.py @@ -1,5 +1,7 @@ from flask import request, render_template, session +from fHDHR.tools import channel_sort + class Channels_Editor_HTML(): endpoints = ["/channels_editor", "/channels_editor.html"] @@ -13,7 +15,7 @@ class Channels_Editor_HTML(): def get(self, *args): - channelslist = [] + channelslist = {} for fhdhr_id in [x["id"] for x in self.fhdhr.device.channels.get_channels()]: channel_obj = self.fhdhr.device.channels.list[fhdhr_id] channel_dict = channel_obj.dict.copy() @@ -22,8 +24,12 @@ class Channels_Editor_HTML(): channel_dict["chan_thumbnail"] = channel_obj.thumbnail channel_dict["play_url"] = channel_obj.play_url - channelslist.append(channel_dict) + channelslist[channel_dict["number"]] = channel_dict - channelslist = sorted(channelslist, key=lambda i: i['number']) + # Sort the channels + sorted_channel_list = channel_sort(list(channelslist.keys())) + sorted_chan_guide = [] + for channel in sorted_channel_list: + sorted_chan_guide.append(channelslist[channel]) - return render_template('channels_editor.html', session=session, request=request, fhdhr=self.fhdhr, channelslist=channelslist) + return render_template('channels_editor.html', session=session, request=request, fhdhr=self.fhdhr, channelslist=sorted_chan_guide, list=list) diff --git a/fHDHR_web/pages/channels_html.py b/fHDHR_web/pages/channels_html.py index 13de699..4115829 100644 --- a/fHDHR_web/pages/channels_html.py +++ b/fHDHR_web/pages/channels_html.py @@ -1,5 +1,7 @@ from flask import request, render_template, session +from fHDHR.tools import channel_sort + class Channels_HTML(): endpoints = ["/channels", "/channels.html"] @@ -18,7 +20,7 @@ class Channels_HTML(): "Enabled": 0 } - channelslist = [] + channelslist = {} for fhdhr_id in [x["id"] for x in self.fhdhr.device.channels.get_channels()]: channel_obj = self.fhdhr.device.channels.list[fhdhr_id] channel_dict = channel_obj.dict.copy() @@ -27,10 +29,14 @@ class Channels_HTML(): channel_dict["chan_thumbnail"] = channel_obj.thumbnail channel_dict["play_url"] = channel_obj.play_url - channelslist.append(channel_dict) + channelslist[channel_dict["number"]] = channel_dict if channel_dict["enabled"]: channels_dict["Enabled"] += 1 - channelslist = sorted(channelslist, key=lambda i: i['number']) + # Sort the channels + sorted_channel_list = channel_sort(list(channelslist.keys())) + sorted_chan_guide = [] + for channel in sorted_channel_list: + sorted_chan_guide.append(channelslist[channel]) - return render_template('channels.html', session=session, request=request, fhdhr=self.fhdhr, channelslist=channelslist, channels_dict=channels_dict, list=list) + return render_template('channels.html', session=session, request=request, fhdhr=self.fhdhr, channelslist=sorted_chan_guide, channels_dict=channels_dict, list=list) diff --git a/fHDHR_web/pages/guide_html.py b/fHDHR_web/pages/guide_html.py index 4f1b6ec..630b748 100644 --- a/fHDHR_web/pages/guide_html.py +++ b/fHDHR_web/pages/guide_html.py @@ -1,7 +1,7 @@ from flask import request, render_template, session import datetime -from fHDHR.tools import humanized_time +from fHDHR.tools import humanized_time, channel_sort class Guide_HTML(): @@ -14,25 +14,6 @@ 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().timestamp() @@ -47,7 +28,10 @@ class Guide_HTML(): whatson = self.fhdhr.device.epg.whats_on_allchans(source) # Sort the channels - sorted_chan_guide = self.number_sort(whatson) + sorted_channel_list = channel_sort(list(whatson.keys())) + sorted_chan_guide = {} + for channel in sorted_channel_list: + sorted_chan_guide[channel] = whatson[channel] for channel in list(sorted_chan_guide.keys()): if sorted_chan_guide[channel]["listing"][0]["time_end"]: