From e7d245222ca858483ec869924f6aa57b985ab071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Tue, 12 May 2020 16:54:44 +0200 Subject: [PATCH] Implement refreshing logic (#9) * Automatically refreshes at a configurable interval * Doesn't refresh at every startup anymore, unless you have passed your interval * Postpone to restart Simple IPTV when watching TV * Allows to force a refresh from the settings Co-authored-by: Dag Wieers --- .gitignore | 13 ++++- .../resource.language.en_gb/strings.po | 44 ++++++++++++-- .../resource.language.nl_nl/strings.po | 46 +++++++++++++-- resources/lib/functions.py | 9 ++- resources/lib/kodiutils.py | 11 ++-- resources/lib/modules/addon.py | 58 ++++++++++++++++++- resources/lib/modules/iptvsimple.py | 16 ++++- resources/lib/service.py | 44 ++++++-------- resources/settings.xml | 15 +++-- 9 files changed, 203 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 5307635..c4126d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,24 @@ +# Temporary files *.pyc *.pyo .DS* +Thumbs.db +*~ +.cache + +# Files related to development .pylint_rc /.idea /.project /.pydevproject /.settings -Thumbs.db -*~ -.cache +/Pipfile +/Pipfile.lock +# Files related to testing .coverage .tox/ +# IPTV Manager output tests/userdata/playlist.m3u8 tests/userdata/epg.xml diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 6f95a95..7ecfc70 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -11,27 +11,63 @@ msgid "Are you sure you want to setup IPTV Simple for the use with IPTV Manager? msgstr "" msgctxt "#30701" -msgid "The configuration of IPTV Simple is completed!" +msgid "IPTV Simple is configured for use with IPTV Manager!" msgstr "" msgctxt "#30702" msgid "The configuration of IPTV Simple has failed. Please check the log files for more information." msgstr "" +msgctxt "#30703" +msgid "Detecting IPTV add-ons..." +msgstr "" + +msgctxt "#30704" +msgid "Fetching channels and guide of {addon}..." +msgstr "" + +msgctxt "#30705" +msgid "Updating channels and guide..." +msgstr "" + +msgctxt "#30706" +msgid "The channels and guide are updated successfully!" +msgstr "" + + ### SETTINGS msgctxt "#30800" -msgid "IPTV Simple" +msgid "Channels" msgstr "" msgctxt "#30801" -msgid "Configuration" +msgid "Refreshing" msgstr "" msgctxt "#30802" -msgid "Configure IPTV Simple automatically…" +msgid "Refresh interval [I](in hours)[/I]" msgstr "" msgctxt "#30803" +msgid "Refresh channels and guide now…" +msgstr "" + +msgctxt "#30820" +msgid "IPTV Simple" +msgstr "" + +msgctxt "#30821" +msgid "Configuration" +msgstr "" + +msgctxt "#30822" +msgid "Configure IPTV Simple automatically…" +msgstr "" + +msgctxt "#30823" msgid "Open IPTV Simple settings…" msgstr "" +msgctxt "#30824" +msgid "Automatically restart IPTV Simple to refresh the data" +msgstr "" diff --git a/resources/language/resource.language.nl_nl/strings.po b/resources/language/resource.language.nl_nl/strings.po index 2db7efe..1d84936 100644 --- a/resources/language/resource.language.nl_nl/strings.po +++ b/resources/language/resource.language.nl_nl/strings.po @@ -12,27 +12,63 @@ msgid "Are you sure you want to setup IPTV Simple for the use with IPTV Manager? msgstr "Bent u zeker om IPTV Simple in te stellen om te gebruiken met IPTV Manager? De bestaande configuratie van IPTV Simple zal worden overschreven." msgctxt "#30701" -msgid "The configuration of IPTV Simple is completed!" -msgstr "De configuratie van IPTV Simple is uitgevoerd!" +msgid "IPTV Simple is configured for use with IPTV Manager!" +msgstr "IPTV SImple is geconfigureerd om te gebruiken met IPTV Manager!" msgctxt "#30702" msgid "The configuration of IPTV Simple has failed. Please check the log files for more information." msgstr "De configuratie van IPTV Simple is mislukt. Gelieve de logbestanden te bekijken voor meer informatie." +msgctxt "#30703" +msgid "Detecting IPTV add-ons..." +msgstr "Detecteren van IPTV add-ons..." + +msgctxt "#30704" +msgid "Fetching channels and guide of {addon}..." +msgstr "Opvragen van kanalenlijst en gids van {addon}..." + +msgctxt "#30705" +msgid "Updating channels and guide..." +msgstr "Updaten van de kanalenlijst en de gids..." + +msgctxt "#30706" +msgid "The channels and guide are updated successfully!" +msgstr "De kanalenlijst en gids zijn sucessvol geüpdate." + + ### SETTINGS msgctxt "#30800" +msgid "Channels" +msgstr "Kanalen" + +msgctxt "#30801" +msgid "Refreshing" +msgstr "Verniewen" + +msgctxt "#30802" +msgid "Refresh interval [I](in hours)[/I]" +msgstr "Vernieuwsingsinterval [I](in uren)[/I]" + +msgctxt "#30803" +msgid "Refresh channels and guide now…" +msgstr "Vernieuw kanalenlijst en gids nu…" + +msgctxt "#30820" msgid "IPTV Simple" msgstr "IPTV Simple" -msgctxt "#30801" +msgctxt "#30821" msgid "Configuration" msgstr "Configuratie" -msgctxt "#30802" +msgctxt "#30822" msgid "Configure IPTV Simple automatically…" msgstr "Configureer IPTV Simple automatisch…" -msgctxt "#30803" +msgctxt "#30823" msgid "Open IPTV Simple settings…" msgstr "Open de IPTV Simple instellingen…" +msgctxt "#30824" +msgid "Automatically restart IPTV Simple to refresh the data" +msgstr "Herstart IPTV Simple automatisch om de data te vernieuwen" diff --git a/resources/lib/functions.py b/resources/lib/functions.py index 3a37b48..8eb1423 100644 --- a/resources/lib/functions.py +++ b/resources/lib/functions.py @@ -6,6 +6,7 @@ import logging from resources.lib import kodilogging, kodiutils +from resources.lib.modules.addon import Addon from resources.lib.modules.iptvsimple import IptvSimple kodilogging.config() @@ -21,10 +22,16 @@ def setup_iptv_simple(): else: kodiutils.ok_dialog(message=kodiutils.localize(30702)) # The configuration of IPTV Simple has failed! + # Open settings again + kodiutils.open_settings() + def refresh(): """ Refresh the channels and EPG """ - _LOGGER.debug('TODO: refresh') + Addon.refresh(True) + + # Open settings again + kodiutils.open_settings() def run(args): diff --git a/resources/lib/kodiutils.py b/resources/lib/kodiutils.py index 687b846..47d7e53 100644 --- a/resources/lib/kodiutils.py +++ b/resources/lib/kodiutils.py @@ -197,14 +197,11 @@ def get_setting_bool(key, default=None): def get_setting_int(key, default=None): """Get an add-on setting as integer""" + # ADDON.getSettingInt(key) doesn't work in Leia for settings without "number" try: - return ADDON.getSettingInt(key) - except (AttributeError, TypeError): # On Krypton or older, or when not an integer - value = get_setting(key, default) - try: - return int(value) - except ValueError: - return default + return int(get_setting(key, default)) + except ValueError: # Occurs when not an integer + return default except RuntimeError: # Occurs when the add-on is disabled return default diff --git a/resources/lib/modules/addon.py b/resources/lib/modules/addon.py index c535dbc..c852c7a 100644 --- a/resources/lib/modules/addon.py +++ b/resources/lib/modules/addon.py @@ -7,8 +7,10 @@ import logging import os import socket +import time from resources.lib import kodiutils +from resources.lib.modules.iptvsimple import IptvSimple _LOGGER = logging.getLogger(__name__) @@ -44,6 +46,60 @@ def __init__(self, addon_id, addon_obj, channels_uri, epg_uri): addon = kodiutils.get_addon(addon_id) self.addon_path = kodiutils.addon_path(addon) + @classmethod + def refresh(cls, show_progress=False): + """ Update channels and EPG data """ + channels = [] + epg = dict() + + if show_progress: + progress = kodiutils.progress(message=kodiutils.localize(30703)) # Detecting IPTV add-ons... + else: + progress = None + + addons = cls.get_iptv_addons() + + for index, addon in enumerate(addons): + _LOGGER.info('Updating IPTV data for %s...', addon.addon_id) + + if progress: + progress.update(int(100 * index / len(addons)), + kodiutils.localize(30704).format(addon=kodiutils.addon_name(addon.addon_obj))) # Fetching channels and guide of {addon}... + + # Fetch channels + channels.extend(addon.get_channels()) + if progress and progress.iscanceled(): + progress.close() + return + + # Fetch EPG data + epg.update(addon.get_epg()) + if progress and progress.iscanceled(): + progress.close() + return + + # Write files + if show_progress: + progress.update(100, kodiutils.localize(30705)) # Updating channels and guide... + + IptvSimple.write_playlist(channels) + IptvSimple.write_epg(epg) + + if kodiutils.get_setting_bool('iptv_simple_restart'): + if show_progress: + # Try to restart now. We will schedule it if the user is watching TV. + IptvSimple.restart(True) + else: + # Schedule a restart + IptvSimple.restart(False) + + # Update last_refreshed + kodiutils.set_setting_int('last_refreshed', int(time.time())) + + if show_progress: + progress.close() + kodiutils.ok_dialog(message=kodiutils.localize(30706)) # The channels and guide are updated successfully! + @staticmethod def get_iptv_addons(): """ Find add-ons that provide IPTV channel data """ @@ -151,7 +207,7 @@ def _get_data_from_addon(self, uri): # HTTP(S) path if uri.startswith(('http://', 'https://')): # TODO: implement requests to fetch data - return None + raise NotImplementedError # Local path addon = kodiutils.get_addon(self.addon_id) diff --git a/resources/lib/modules/iptvsimple.py b/resources/lib/modules/iptvsimple.py index 3c3458a..5050048 100644 --- a/resources/lib/modules/iptvsimple.py +++ b/resources/lib/modules/iptvsimple.py @@ -21,6 +21,9 @@ class IptvSimple: """ Helper class to setup IPTV Simple """ + + restart_required = False + def __init__(self): """ Init """ @@ -42,6 +45,7 @@ def setup(cls): output_dir = kodiutils.addon_profile() playlist_path = os.path.join(output_dir, IPTV_SIMPLE_PLAYLIST) epg_path = os.path.join(output_dir, IPTV_SIMPLE_EPG) + logo_path = '/' addon.setSetting('m3uPathType', '0') # Local path addon.setSetting('m3uPath', playlist_path) @@ -50,7 +54,7 @@ def setup(cls): addon.setSetting('epgPath', epg_path) addon.setSetting('logoPathType', '0') # Local path - addon.setSetting('logoPath', '/') + addon.setSetting('logoPath', logo_path) # Activate IPTV Simple cls._activate() @@ -58,8 +62,16 @@ def setup(cls): return True @classmethod - def restart(cls): + def restart(cls, force=False): """ Restart IPTV Simple """ + if not force and (kodiutils.get_cond_visibility('Pvr.IsPlayingTv') or kodiutils.get_cond_visibility('Pvr.IsPlayingRadio')): + # Don't restart when we are Playing TV or Radio + cls.restart_required = True + _LOGGER.info('Postponing restart of Simple IPTV since it is currently in use.') + return + + cls.restart_required = False + cls._deactivate() time.sleep(1) cls._activate() diff --git a/resources/lib/service.py b/resources/lib/service.py index 35bbb02..65dbd33 100644 --- a/resources/lib/service.py +++ b/resources/lib/service.py @@ -4,10 +4,11 @@ from __future__ import absolute_import, division, unicode_literals import logging +import time from xbmc import Monitor -from resources.lib import kodilogging +from resources.lib import kodilogging, kodiutils from resources.lib.modules.addon import Addon from resources.lib.modules.iptvsimple import IptvSimple @@ -20,43 +21,34 @@ class BackgroundService(Monitor): def __init__(self): Monitor.__init__(self) + self._restart_required = False def run(self): """ Background loop for maintenance tasks """ _LOGGER.debug('Service started') - # Do an initial update - # TODO: we have to schedule this somehow - self.update() - + # Service loop while not self.abortRequested(): + # Check if we need to do an update + if self._is_refresh_required(): + Addon.refresh() + + # Check if IPTV Simple needs to be restarted + if IptvSimple.restart_required: + IptvSimple.restart() + # Stop when abort requested - if self.waitForAbort(10): + if self.waitForAbort(30): break _LOGGER.debug('Service stopped') @staticmethod - def update(): - """ Update the channels and epg data """ - channels = [] - epg = dict() - - addons = Addon.get_iptv_addons() - for addon in addons: - _LOGGER.info('Updating IPTV data for %s...', addon.addon_id) - - # Fetch channels - channels.extend(addon.get_channels()) - - # Fetch EPG data - epg.update(addon.get_epg()) - - # Write files - IptvSimple.write_playlist(channels) - IptvSimple.write_epg(epg) - - IptvSimple.restart() + def _is_refresh_required(): + """ Returns if we should trigger an update based on the settings. """ + refresh_interval = kodiutils.get_setting_int('refresh_interval', 24) * 3600 + last_refreshed = kodiutils.get_setting_int('last_refreshed', 0) + return (last_refreshed + refresh_interval) <= time.time() def run(): diff --git a/resources/settings.xml b/resources/settings.xml index d057c6f..4c99ece 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -1,8 +1,15 @@ - - - - + + + + + + + + + + +