From 7a040e262411f480660b53f175290546b777b03f Mon Sep 17 00:00:00 2001 From: Race666 Date: Tue, 8 Jun 2021 14:31:54 +0200 Subject: [PATCH 01/11] Add an autosave feature. State can saved frequently --- mopidy_autoplay/__init__.py | 5 +++++ mopidy_autoplay/ext.conf | 4 ++++ mopidy_autoplay/frontend.py | 28 +++++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/mopidy_autoplay/__init__.py b/mopidy_autoplay/__init__.py index cbafcd4..9aeacc9 100644 --- a/mopidy_autoplay/__init__.py +++ b/mopidy_autoplay/__init__.py @@ -92,6 +92,11 @@ def get_config_schema(self): # mute = True|False|"auto") schema['mixer.mute'] = AutoValue(config.Boolean) + # Save state frequently. Value in seconds. + schema['autosave.enabled'] = AutoValue(config.Boolean) + schema['autosave.interval'] = AutoValue( + config.Integer, minimum=10, maximum=86400) + return schema def setup(self, registry): diff --git a/mopidy_autoplay/ext.conf b/mopidy_autoplay/ext.conf index 222d577..58f14af 100644 --- a/mopidy_autoplay/ext.conf +++ b/mopidy_autoplay/ext.conf @@ -21,3 +21,7 @@ playback.time_position = auto # Mixer (volume = [0..100]; mute = on|off|true|false) mixer.volume = auto mixer.mute = auto + +# Auto safe interval. Min value = 10, Max value 86400 (1 day). Be aware a to small interval can damaged your SD Card. +autosave.enabled = false +autosave.interval = 60 diff --git a/mopidy_autoplay/frontend.py b/mopidy_autoplay/frontend.py index fdf2e2c..ef423b0 100755 --- a/mopidy_autoplay/frontend.py +++ b/mopidy_autoplay/frontend.py @@ -9,7 +9,7 @@ import glob import json import pykka - +import threading from mopidy import core from . import Extension, Recollection @@ -36,7 +36,11 @@ def __init__(self, config, core): logger.debug( "Use '%s' as statefile.", self.statefile) - + self._autosave_enabled = self.config['autosave.enabled'] + self._autosave_interval = self.config['autosave.interval'] + self._autosave_thread = None + logger.debug("Read autosave_interval = %d",self._autosave_interval) + # The frontend implementation def on_start(self): # noqa: D401 @@ -44,17 +48,35 @@ def on_start(self): # noqa: D401 logger.debug("on_start()") state = self.read_state(self.statefile) + if state: self.restore_state(state) + if self._autosave_enabled == True: + # Start timer thread + logger.debug("Start autosave thread timer %d sec",self._autosave_interval) + self._autosave_thread=threading.Timer(self._autosave_interval, self.on_timer) + self._autosave_thread.start() + else: + logger.debug("Autosave disabled") def on_stop(self): # noqa: D401 """Called, when the extension is stopped.""" logger.debug("on_stop()") - + if isinstance(self._autosave_thread,threading.Timer): + # Stop timer thread before saving state to prevent a raise condition + logger.debug("Stop autosave thread") + self._autosave_thread.cancel() state = self.store_state() self.write_state(state, self.statefile) # Helper functions + def on_timer(self): + logger.info("Autosave state") + state = self.store_state() + self.write_state(state, self.statefile) + # Start next timer thread + self._autosave_thread=threading.Timer(self._autosave_interval, self.on_timer) + self._autosave_thread.start() def _get_config(self, state, controller, option): """ From 0c70b2fdedb1e3ddb9f0139f60efa5ce296507b7 Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 11:00:55 +0200 Subject: [PATCH 02/11] Update __init__.py interval -> events --- mopidy_autoplay/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mopidy_autoplay/__init__.py b/mopidy_autoplay/__init__.py index 9aeacc9..1f08c45 100644 --- a/mopidy_autoplay/__init__.py +++ b/mopidy_autoplay/__init__.py @@ -92,10 +92,9 @@ def get_config_schema(self): # mute = True|False|"auto") schema['mixer.mute'] = AutoValue(config.Boolean) - # Save state frequently. Value in seconds. + # Save state on events schema['autosave.enabled'] = AutoValue(config.Boolean) - schema['autosave.interval'] = AutoValue( - config.Integer, minimum=10, maximum=86400) + schema['autosave.events'] = AutoValue(config.List) return schema From 6d6ee1f84c882adfedaa0044be559e89b7ffe61c Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 11:02:53 +0200 Subject: [PATCH 03/11] Update frontend.py first approach interval -> events --- mopidy_autoplay/frontend.py | 60 +++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/mopidy_autoplay/frontend.py b/mopidy_autoplay/frontend.py index ef423b0..5348a98 100755 --- a/mopidy_autoplay/frontend.py +++ b/mopidy_autoplay/frontend.py @@ -36,10 +36,9 @@ def __init__(self, config, core): logger.debug( "Use '%s' as statefile.", self.statefile) - self._autosave_enabled = self.config['autosave.enabled'] - self._autosave_interval = self.config['autosave.interval'] - self._autosave_thread = None - logger.debug("Read autosave_interval = %d",self._autosave_interval) + + self._autosave_enabled = self.config['autosave.enabled'] + self._autosave_eventlist = self.config['autosave.events'] # The frontend implementation @@ -51,33 +50,48 @@ def on_start(self): # noqa: D401 if state: self.restore_state(state) - if self._autosave_enabled == True: - # Start timer thread - logger.debug("Start autosave thread timer %d sec",self._autosave_interval) - self._autosave_thread=threading.Timer(self._autosave_interval, self.on_timer) - self._autosave_thread.start() - else: - logger.debug("Autosave disabled") def on_stop(self): # noqa: D401 """Called, when the extension is stopped.""" logger.debug("on_stop()") - if isinstance(self._autosave_thread,threading.Timer): - # Stop timer thread before saving state to prevent a raise condition - logger.debug("Stop autosave thread") - self._autosave_thread.cancel() - state = self.store_state() - self.write_state(state, self.statefile) - # Helper functions - def on_timer(self): - logger.info("Autosave state") state = self.store_state() self.write_state(state, self.statefile) - # Start next timer thread - self._autosave_thread=threading.Timer(self._autosave_interval, self.on_timer) - self._autosave_thread.start() + def autosave_state(self,save_event): + logger.debug("Autosave ({0})".format(save_event)) + state = self.store_state() + self.write_state(state, self.statefile) + + def track_playback_started(self, tl_track): + if self._autosave_enabled != True: + return + logger.debug("{0}: {1}".format("track_playback_started",str(tl_track))) + if "track_playback_started" in self._autosave_eventlist: + self.autosave_state("track_playback_started") + + def playback_state_changed(self,old_state, new_state): + if self._autosave_enabled != True: + return + logger.debug("{0}: {1} -> {2}".format("playback_state_changed",str(old_state),str(new_state))) + if "playback_state_changed" in self._autosave_eventlist: + self.autosave_state("playback_state_changed") + + def tracklist_changed(self): + if self._autosave_enabled != True: + return + logger.debug("{0}".format("tracklist_changed")) + if "tracklist_changed" in self._autosave_eventlist: + self.autosave_state("tracklist_changed") + + def stream_title_changed(self,title): + if self._autosave_enabled != True: + return + logger.debug("{0}: {1}".format("stream_title_changed",title)) + if "stream_title_changed" in self._autosave_eventlist: + self.autosave_state("stream_title_changed") + + def _get_config(self, state, controller, option): """ Return the configuration from `config` and `state`. From 454b60d5aced0ae45af265c01754d2be986148cf Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 11:04:49 +0200 Subject: [PATCH 04/11] Update ext.conf interval -> events --- mopidy_autoplay/ext.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy_autoplay/ext.conf b/mopidy_autoplay/ext.conf index 58f14af..828a245 100644 --- a/mopidy_autoplay/ext.conf +++ b/mopidy_autoplay/ext.conf @@ -22,6 +22,6 @@ playback.time_position = auto mixer.volume = auto mixer.mute = auto -# Auto safe interval. Min value = 10, Max value 86400 (1 day). Be aware a to small interval can damaged your SD Card. +# Auto safe on events. Possibe events: track_playback_started , playback_state_changed, tracklist_changed, stream_title_changed autosave.enabled = false -autosave.interval = 60 +autosave.events = track_playback_started,playback_state_changed From dc62bd65063f9e45042fcb276ee273a858bb23d4 Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 14:42:05 +0200 Subject: [PATCH 05/11] Update __init__.py Individual events -> on_event --- mopidy_autoplay/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mopidy_autoplay/__init__.py b/mopidy_autoplay/__init__.py index 1f08c45..e0ab745 100644 --- a/mopidy_autoplay/__init__.py +++ b/mopidy_autoplay/__init__.py @@ -93,8 +93,7 @@ def get_config_schema(self): schema['mixer.mute'] = AutoValue(config.Boolean) # Save state on events - schema['autosave.enabled'] = AutoValue(config.Boolean) - schema['autosave.events'] = AutoValue(config.List) + schema['autosave_events'] = AutoValue(config.List,optional=True) return schema From e64707d4a76292e4b42096a53614a60d63e0711e Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 14:43:02 +0200 Subject: [PATCH 06/11] Update ext.conf Individual events -> on_event --- mopidy_autoplay/ext.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mopidy_autoplay/ext.conf b/mopidy_autoplay/ext.conf index 828a245..2dce823 100644 --- a/mopidy_autoplay/ext.conf +++ b/mopidy_autoplay/ext.conf @@ -22,6 +22,6 @@ playback.time_position = auto mixer.volume = auto mixer.mute = auto -# Auto safe on events. Possibe events: track_playback_started , playback_state_changed, tracklist_changed, stream_title_changed -autosave.enabled = false -autosave.events = track_playback_started,playback_state_changed +# Auto safe on events. See https://docs.mopidy.com/en/latest/api/core/#core-events for possible events +# autosave_events = track_playback_started,playback_state_changed +autosave_events = From 513a379b788375397a29b26b2f1bc7c5e3ebb1b1 Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 14:45:16 +0200 Subject: [PATCH 07/11] Update frontend.py Individual events -> on_event --- mopidy_autoplay/frontend.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/mopidy_autoplay/frontend.py b/mopidy_autoplay/frontend.py index 5348a98..b2d2de7 100755 --- a/mopidy_autoplay/frontend.py +++ b/mopidy_autoplay/frontend.py @@ -9,7 +9,7 @@ import glob import json import pykka -import threading +import datetime from mopidy import core from . import Extension, Recollection @@ -37,8 +37,15 @@ def __init__(self, config, core): "Use '%s' as statefile.", self.statefile) - self._autosave_enabled = self.config['autosave.enabled'] - self._autosave_eventlist = self.config['autosave.events'] + if len(self.config['autosave_events']) >= 1: + logger.info("Autosave enabled") + self._autosave_eventlist = self.config['autosave_events'] + self._autosave_enabled = True + else: + self._autosave_enabled = False + + self._autosave_min_save_frequency=60 + self._autosave_lastsave_datetime=datetime.datetime.now() # The frontend implementation @@ -58,10 +65,27 @@ def on_stop(self): # noqa: D401 state = self.store_state() self.write_state(state, self.statefile) + def on_event(self, event, **kwargs): + # if event == "IRButtonPressed": + # logger.debug("Button pressed: " + str(kwargs)) + # if kwargs['button'] == "power": + # logger.debug('on_event: calls toggle disco') + # self.displayRenderer.toggleDisco() + logger.info("Event %s args: %s",str(event),str(kwargs)) + if self._autosave_enabled == True: + if str(event) in self._autosave_eventlist: + self.autosave_state(event) + return CoreListener.on_event(self, event, **kwargs) + def autosave_state(self,save_event): - logger.debug("Autosave ({0})".format(save_event)) + current_time=datetime.datetime.now() + if (current_time-self._autosave_lastsave_datetime).seconds < self._autosave_min_save_frequency: + logger.info("Skip autosave") + return + logger.info("Autosave ({0})".format(save_event)) state = self.store_state() self.write_state(state, self.statefile) + self._autosave_lastsave_datetime=current_time def track_playback_started(self, tl_track): if self._autosave_enabled != True: From 18b6b7d19f6ec8d24bde1c5ae07479bc755b480c Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 14:46:51 +0200 Subject: [PATCH 08/11] Update frontend.py Individual events -> on_event --- mopidy_autoplay/frontend.py | 38 ++----------------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/mopidy_autoplay/frontend.py b/mopidy_autoplay/frontend.py index b2d2de7..2daf5d5 100755 --- a/mopidy_autoplay/frontend.py +++ b/mopidy_autoplay/frontend.py @@ -66,12 +66,7 @@ def on_stop(self): # noqa: D401 self.write_state(state, self.statefile) def on_event(self, event, **kwargs): - # if event == "IRButtonPressed": - # logger.debug("Button pressed: " + str(kwargs)) - # if kwargs['button'] == "power": - # logger.debug('on_event: calls toggle disco') - # self.displayRenderer.toggleDisco() - logger.info("Event %s args: %s",str(event),str(kwargs)) + logger.debug("Event %s args: %s",str(event),str(kwargs)) if self._autosave_enabled == True: if str(event) in self._autosave_eventlist: self.autosave_state(event) @@ -80,41 +75,12 @@ def on_event(self, event, **kwargs): def autosave_state(self,save_event): current_time=datetime.datetime.now() if (current_time-self._autosave_lastsave_datetime).seconds < self._autosave_min_save_frequency: - logger.info("Skip autosave") + logger.debug("Skip autosave") return logger.info("Autosave ({0})".format(save_event)) state = self.store_state() self.write_state(state, self.statefile) self._autosave_lastsave_datetime=current_time - - def track_playback_started(self, tl_track): - if self._autosave_enabled != True: - return - logger.debug("{0}: {1}".format("track_playback_started",str(tl_track))) - if "track_playback_started" in self._autosave_eventlist: - self.autosave_state("track_playback_started") - - def playback_state_changed(self,old_state, new_state): - if self._autosave_enabled != True: - return - logger.debug("{0}: {1} -> {2}".format("playback_state_changed",str(old_state),str(new_state))) - if "playback_state_changed" in self._autosave_eventlist: - self.autosave_state("playback_state_changed") - - def tracklist_changed(self): - if self._autosave_enabled != True: - return - logger.debug("{0}".format("tracklist_changed")) - if "tracklist_changed" in self._autosave_eventlist: - self.autosave_state("tracklist_changed") - - def stream_title_changed(self,title): - if self._autosave_enabled != True: - return - logger.debug("{0}: {1}".format("stream_title_changed",title)) - if "stream_title_changed" in self._autosave_eventlist: - self.autosave_state("stream_title_changed") - def _get_config(self, state, controller, option): """ From e8ce2a1be905c9f6ac99ccf987114ce377a4eb68 Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 16:07:18 +0200 Subject: [PATCH 09/11] Update __init__.py Parameter autosave_min_interval added, compact code. --- mopidy_autoplay/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mopidy_autoplay/__init__.py b/mopidy_autoplay/__init__.py index e0ab745..85c0459 100644 --- a/mopidy_autoplay/__init__.py +++ b/mopidy_autoplay/__init__.py @@ -94,6 +94,8 @@ def get_config_schema(self): # Save state on events schema['autosave_events'] = AutoValue(config.List,optional=True) + schema['autosave_min_interval'] = AutoValue( + config.Integer, minimum=10) return schema From b92eb36c4fda08fe147bcffa73268c9cda26f4ad Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 16:07:42 +0200 Subject: [PATCH 10/11] Update ext.conf Parameter autosave_min_interval added, compact code. --- mopidy_autoplay/ext.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mopidy_autoplay/ext.conf b/mopidy_autoplay/ext.conf index 2dce823..de13aa5 100644 --- a/mopidy_autoplay/ext.conf +++ b/mopidy_autoplay/ext.conf @@ -23,5 +23,6 @@ mixer.volume = auto mixer.mute = auto # Auto safe on events. See https://docs.mopidy.com/en/latest/api/core/#core-events for possible events -# autosave_events = track_playback_started,playback_state_changed +# autosave_events = track_playback_started autosave_events = +autosave_min_interval = 60 From 43bfb1be917a9f0f7fe2a14ce52c3b45246ac14d Mon Sep 17 00:00:00 2001 From: Race666 Date: Wed, 9 Jun 2021 16:09:29 +0200 Subject: [PATCH 11/11] Update frontend.py Parameter autosave_min_interval added, compact code. --- mopidy_autoplay/frontend.py | 39 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/mopidy_autoplay/frontend.py b/mopidy_autoplay/frontend.py index 2daf5d5..80714e2 100755 --- a/mopidy_autoplay/frontend.py +++ b/mopidy_autoplay/frontend.py @@ -9,7 +9,7 @@ import glob import json import pykka -import datetime +import time from mopidy import core from . import Extension, Recollection @@ -36,17 +36,7 @@ def __init__(self, config, core): logger.debug( "Use '%s' as statefile.", self.statefile) - - if len(self.config['autosave_events']) >= 1: - logger.info("Autosave enabled") - self._autosave_eventlist = self.config['autosave_events'] - self._autosave_enabled = True - else: - self._autosave_enabled = False - - self._autosave_min_save_frequency=60 - self._autosave_lastsave_datetime=datetime.datetime.now() - + self._last_autosave = time.time() # The frontend implementation def on_start(self): # noqa: D401 @@ -66,21 +56,16 @@ def on_stop(self): # noqa: D401 self.write_state(state, self.statefile) def on_event(self, event, **kwargs): - logger.debug("Event %s args: %s",str(event),str(kwargs)) - if self._autosave_enabled == True: - if str(event) in self._autosave_eventlist: - self.autosave_state(event) - return CoreListener.on_event(self, event, **kwargs) - - def autosave_state(self,save_event): - current_time=datetime.datetime.now() - if (current_time-self._autosave_lastsave_datetime).seconds < self._autosave_min_save_frequency: - logger.debug("Skip autosave") - return - logger.info("Autosave ({0})".format(save_event)) - state = self.store_state() - self.write_state(state, self.statefile) - self._autosave_lastsave_datetime=current_time + logger.debug("Event %s args: %s",event,str(kwargs)) + if event in self.config['autosave_events']: + now = time.time() + if (now - self._last_autosave) < self.config['autosave_min_interval']: + logger.info("Skip autosave") + else: + logger.info("Autosave ({0})".format(event)) + state = self.store_state() + self.write_state(state, self.statefile) + self._last_autosave = now def _get_config(self, state, controller, option): """