diff --git a/modules/__init__.py b/modules/__init__.py index 8dd779e..9c111f9 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -26,7 +26,7 @@ class PlayerModule: Receive an IMC object """ pass - def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object) -> object: + def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object, broadcast: bool) -> object: pass class PlaylistModifierModule: """ @@ -57,7 +57,7 @@ class PlaylistAdvisor: Receive an IMC object """ pass - def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object) -> object: + def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object, broadcast: bool) -> object: pass class ActiveModifier: """ @@ -84,7 +84,7 @@ class ActiveModifier: Receive an IMC object """ pass - def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object) -> object: + def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object, broadcast: bool) -> object: pass class InterModuleCommunication: def __init__(self, advisor: PlaylistAdvisor, active_modifier: ActiveModifier | None, simple_modules: list[PlayerModule]) -> None: @@ -94,15 +94,15 @@ class InterModuleCommunication: self.names_modules: dict[str, PlaylistAdvisor | ActiveModifier | PlayerModule] = {} def broadcast(self, source: PlaylistAdvisor | ActiveModifier | PlayerModule, data: object) -> None: """ - Send data to all modules + Send data to all modules, other than ourself """ - self.advisor.imc_data(source, data) - if self.active_modifier: self.active_modifier.imc_data(source, data) - for module in self.simple_modules: module.imc_data(source, data) + if source is not self.advisor: self.advisor.imc_data(source, data, True) + if self.active_modifier and source is not self.active_modifier: self.active_modifier.imc_data(source, data, True) + for module in [f for f in self.simple_modules if f is not source]: module.imc_data(source, data, True) def register(self, module: PlaylistAdvisor | ActiveModifier | PlayerModule, name: str): if name in self.names_modules.keys(): return False self.names_modules[name] = module return True def send(self, source: PlaylistAdvisor | ActiveModifier | PlayerModule, name: str, data: object) -> object: if not name in self.names_modules.keys(): raise Exception - return self.names_modules[name].imc_data(source, data) \ No newline at end of file + return self.names_modules[name].imc_data(source, data, False) \ No newline at end of file diff --git a/modules/advisor.py b/modules/advisor.py index ca494d7..2be752e 100644 --- a/modules/advisor.py +++ b/modules/advisor.py @@ -110,7 +110,7 @@ class Module(PlaylistAdvisor): def imc(self, imc: InterModuleCommunication): self.class_imc = imc imc.register(self, "advisor") - def imc_data(self, source: PlayerModule | ActiveModifier | PlaylistAdvisor, data: object): + def imc_data(self, source: PlayerModule | ActiveModifier | PlaylistAdvisor, data: object, broadcast: bool): return self.custom_playlist advisor = Module() \ No newline at end of file diff --git a/modules/modules.txt b/modules/modules.txt index 9cc143f..edf9e7c 100644 --- a/modules/modules.txt +++ b/modules/modules.txt @@ -1,4 +1,4 @@ -Modules in the radio95 radio player are quite simple. +Modules in the radioPlayer are quite simple. First of all, ther are in total only 4 modules: - Observer (PlayerModule), this module is a passive observer, you can use this as a status api or to send the song metadata to your RDS encoder @@ -32,7 +32,7 @@ class PlayerModule: Receive an IMC object """ pass - def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object) -> object: + def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object, broadcast: bool) -> object: pass class PlaylistModifierModule: """ @@ -63,7 +63,7 @@ class PlaylistAdvisor: Receive an IMC object """ pass - def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object) -> object: + def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object, broadcast: bool) -> object: pass class ActiveModifier: """ @@ -90,7 +90,7 @@ class ActiveModifier: Receive an IMC object """ pass - def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object) -> object: + def imc_data(self, source: 'PlayerModule | ActiveModifier | PlaylistAdvisor', data: object, broadcast: bool) -> object: pass class InterModuleCommunication: def __init__(self, advisor: PlaylistAdvisor, active_modifier: ActiveModifier | None, simple_modules: list[PlayerModule]) -> None: @@ -100,18 +100,18 @@ class InterModuleCommunication: self.names_modules: dict[str, PlaylistAdvisor | ActiveModifier | PlayerModule] = {} def broadcast(self, source: PlaylistAdvisor | ActiveModifier | PlayerModule, data: object) -> None: """ - Send data to all modules + Send data to all modules, other than ourself """ - self.advisor.imc_data(source, data) - if self.active_modifier: self.active_modifier.imc_data(source, data) - for module in self.simple_modules: module.imc_data(source, data) + if source is not self.advisor: self.advisor.imc_data(source, data, True) + if self.active_modifier and source is not self.active_modifier: self.active_modifier.imc_data(source, data, True) + for module in [f for f in self.simple_modules if f is not source]: module.imc_data(source, data, True) def register(self, module: PlaylistAdvisor | ActiveModifier | PlayerModule, name: str): if name in self.names_modules.keys(): return False self.names_modules[name] = module return True def send(self, source: PlaylistAdvisor | ActiveModifier | PlayerModule, name: str, data: object) -> object: if not name in self.names_modules.keys(): raise Exception - return self.names_modules[name].imc_data(source, data) + return self.names_modules[name].imc_data(source, data, False) ``` Each module shall have a python script in the modules directory. Each of the modules need to define one or more global variables in order to be seen by the core: diff --git a/radioPlayer.py b/radioPlayer.py index 111e825..9b4fd5c 100644 --- a/radioPlayer.py +++ b/radioPlayer.py @@ -15,28 +15,6 @@ active_modifier: ActiveModifier | None = None MODULES_PACKAGE = "modules" MODULES_DIR = (Path(__file__).resolve().parent / MODULES_PACKAGE).resolve() -def print_wait(ttw: float, frequency: float, duration: float=-1, prefix: str="", bias: float = 0): - interval = 1.0 / frequency - elapsed = 0.0 - if duration == -1: duration = ttw - - def format_time(seconds): - hours = int(seconds // 3600) - minutes = int((seconds % 3600) // 60) - secs = int(seconds % 60) - return f"{hours:02d}:{minutes:02d}:{secs:02d}" - - try: - while elapsed < ttw: - print(f"{prefix}{format_time(elapsed+bias)} / {format_time(duration)}", end="\r", flush=True) - time.sleep(interval) - elapsed += interval - except Exception: - print() - raise - - print(f"{prefix}{format_time(ttw+bias)} / {format_time(duration)}") - logger_level = log95.log95Levels.DEBUG if DEBUG else log95.log95Levels.CRITICAL_ERROR logger = log95.log95("radioPlayer", logger_level) @@ -228,8 +206,28 @@ def play_playlist(playlist_path): ttw = pr.duration if track.fade_out: ttw -= cross_fade - if track.official: print_wait(ttw, 1, pr.duration, f"{track_name}: ") - else: time.sleep(ttw) + end_time = time.time() + ttw + loop_start = time.time() # Outside the loop + + def format_time(seconds): + hours = int(seconds // 3600) + minutes = int((seconds % 3600) // 60) + secs = int(seconds % 60) + return f"{hours:02d}:{minutes:02d}:{secs:02d}" + + while end_time >= time.time(): + start = time.time() + # do some module callback + + elapsed = time.time() - start + remaining_until_end = end_time - time.time() + total_uptime = time.time() - loop_start + + if track.official: print(f"{track_name}: {format_time(total_uptime)} / {format_time(pr.duration)}") + + if elapsed < 1 and remaining_until_end > 0: + sleep_duration = min(1 - elapsed, remaining_until_end) + time.sleep(sleep_duration) i += 1 if not extend: song_i += 1