You've already forked RadioPlayer
mirror of
https://github.com/radio95-rnt/RadioPlayer.git
synced 2026-02-26 21:53:54 +01:00
updates
This commit is contained in:
@@ -3,19 +3,32 @@ class PlayerModule:
|
||||
Simple passive observer, this allows you to send the current track the your RDS encoder, or to your website
|
||||
"""
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
"""Tuple consists of the track path, to fade out, fade in, official, and args"""
|
||||
"""Tuple consists of the track path, to fade out, fade in, official, and args
|
||||
This is called every new playlist"""
|
||||
pass
|
||||
def on_new_track(self, index: int, track: str, to_fade_in: bool, to_fade_out: bool, official: bool):
|
||||
"""
|
||||
Called on every track including the ones added by the active modifier, you can check for that comparing the playlists[index] and the track
|
||||
"""
|
||||
pass
|
||||
def on_new_track(self, index: int, track: str, to_fade_in: bool, to_fade_out: bool, official: bool): pass
|
||||
class PlaylistModifierModule:
|
||||
"""
|
||||
Playlist modifier, this type of module allows you to shuffle, or put jingles into your playlist
|
||||
"""
|
||||
def modify(self, global_args: dict, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]): return playlist
|
||||
def modify(self, global_args: dict, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
"""
|
||||
global_args are playlist global args (see radioPlayer_playlist_file.txt)
|
||||
"""
|
||||
return playlist
|
||||
class PlaylistAdvisor:
|
||||
"""
|
||||
Only one of a playlist advisor can be loaded. This module picks the playlist file to play, this can be a scheduler or just a static file
|
||||
"""
|
||||
def advise(self, arguments: str | None) -> str: return "/path/to/playlist.txt"
|
||||
def advise(self, arguments: str | None) -> str:
|
||||
"""
|
||||
Arguments are the arguments passed to the program on startup
|
||||
"""
|
||||
return "/path/to/playlist.txt"
|
||||
def new_playlist(self) -> int:
|
||||
"""
|
||||
Whether to play a new playlist, if this is 1, then the player will refresh, if this is two then the player will refresh quietly
|
||||
@@ -25,5 +38,19 @@ class ActiveModifier:
|
||||
"""
|
||||
This changes the next song to be played live, which means that this picks the next song, not the playlist, but this is affected by the playlist
|
||||
"""
|
||||
def play(self, index:int, track: tuple[str, bool, bool, bool, dict[str, str]]) -> tuple[tuple[str, bool, bool, bool, dict[str, str]], bool] | tuple[None, None]: return track, False
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]): pass
|
||||
def arguments(self, arguments: str | None):
|
||||
"""
|
||||
Called at start up with the program arguments
|
||||
"""
|
||||
pass
|
||||
def play(self, index:int, track: tuple[str, bool, bool, bool, dict[str, str]]) -> tuple[tuple[str, bool, bool, bool, dict[str, str]], bool] | tuple[None, None]:
|
||||
"""
|
||||
Returns a tuple, in the first case where a is the track and b is a bool, b corresponds to whether to extend the playlist, set to true when adding content instead of replacing it
|
||||
When None, None is returned then that is treated as a skip, meaning the core will skip this song
|
||||
"""
|
||||
return track, False
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
"""
|
||||
Same behaviour as the basic module function
|
||||
"""
|
||||
pass
|
||||
@@ -17,6 +17,9 @@ class Module(ActiveModifier):
|
||||
self.playlist = None
|
||||
self.originals = []
|
||||
self.last_track = None
|
||||
self.limit_tracks = True
|
||||
def arguments(self, arguments: str | None):
|
||||
if arguments and arguments.startswith("list:"): self.limit_tracks = False
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
self.playlist = playlist
|
||||
def play(self, index: int, track: tuple[str, bool, bool, bool, dict[str, str]]):
|
||||
@@ -53,20 +56,21 @@ class Module(ActiveModifier):
|
||||
elif len(self.originals): self.last_track = self.originals.pop(0)
|
||||
else: self.last_track = track
|
||||
|
||||
last_track_duration = get_audio_duration(self.last_track[0])
|
||||
if last_track_duration and last_track_duration > 5*60:
|
||||
now = datetime.datetime.now()
|
||||
timestamp = now.timestamp() + last_track_duration
|
||||
future = datetime.datetime.fromtimestamp(timestamp)
|
||||
if now.hour < MORNING_START and future.hour > MORNING_START:
|
||||
logger.warning("Skipping track as it bleeds into the morning")
|
||||
return None, None
|
||||
elif now.hour < DAY_END and future.hour > DAY_END:
|
||||
logger.warning("Skipping track as it bleeds into the night")
|
||||
return None, None
|
||||
elif future.day > now.day: # late night goes mid day, as it starts at midnight
|
||||
logger.warning("Skipping track as it the next day")
|
||||
return None, None
|
||||
if self.limit_tracks:
|
||||
last_track_duration = get_audio_duration(self.last_track[0])
|
||||
if last_track_duration and last_track_duration > 5*60:
|
||||
now = datetime.datetime.now()
|
||||
timestamp = now.timestamp() + last_track_duration
|
||||
future = datetime.datetime.fromtimestamp(timestamp)
|
||||
if now.hour < MORNING_START and future.hour > MORNING_START:
|
||||
logger.warning("Skipping track as it bleeds into the morning")
|
||||
return None, None
|
||||
elif now.hour < DAY_END and future.hour > DAY_END:
|
||||
logger.warning("Skipping track as it bleeds into the night")
|
||||
return None, None
|
||||
elif future.day > now.day: # late night goes mid day, as it starts at midnight
|
||||
logger.warning("Skipping track as it the next day")
|
||||
return None, None
|
||||
|
||||
return self.last_track, False
|
||||
|
||||
|
||||
@@ -12,19 +12,32 @@ class PlayerModule:
|
||||
Simple passive observer, this allows you to send the current track the your RDS encoder, or to your website
|
||||
"""
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
"""Tuple consists of the track path, to fade out, fade in, official, and args"""
|
||||
"""Tuple consists of the track path, to fade out, fade in, official, and args
|
||||
This is called every new playlist"""
|
||||
pass
|
||||
def on_new_track(self, index: int, track: str, to_fade_in: bool, to_fade_out: bool, official: bool):
|
||||
"""
|
||||
Called on every track including the ones added by the active modifier, you can check for that comparing the playlists[index] and the track
|
||||
"""
|
||||
pass
|
||||
def on_new_track(self, index: int, track: str, to_fade_in: bool, to_fade_out: bool, official: bool): pass
|
||||
class PlaylistModifierModule:
|
||||
"""
|
||||
Playlist modifier, this type of module allows you to shuffle, or put jingles into your playlist
|
||||
"""
|
||||
def modify(self, global_args: dict, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]): return playlist
|
||||
def modify(self, global_args: dict, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
"""
|
||||
global_args are playlist global args (see radioPlayer_playlist_file.txt)
|
||||
"""
|
||||
return playlist
|
||||
class PlaylistAdvisor:
|
||||
"""
|
||||
Only one of a playlist advisor can be loaded. This module picks the playlist file to play, this can be a scheduler or just a static file
|
||||
"""
|
||||
def advise(self, arguments: str | None) -> str: return "/path/to/playlist.txt"
|
||||
def advise(self, arguments: str | None) -> str:
|
||||
"""
|
||||
Arguments are the arguments passed to the program on startup
|
||||
"""
|
||||
return "/path/to/playlist.txt"
|
||||
def new_playlist(self) -> int:
|
||||
"""
|
||||
Whether to play a new playlist, if this is 1, then the player will refresh, if this is two then the player will refresh quietly
|
||||
@@ -34,8 +47,22 @@ class ActiveModifier:
|
||||
"""
|
||||
This changes the next song to be played live, which means that this picks the next song, not the playlist, but this is affected by the playlist
|
||||
"""
|
||||
def play(self, index:int, track: tuple[str, bool, bool, bool, dict[str, str]]) -> tuple[tuple[str, bool, bool, bool, dict[str, str]], bool] | tuple[None, None]: return track, False
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]): pass
|
||||
def arguments(self, arguments: str | None):
|
||||
"""
|
||||
Called at start up with the program arguments
|
||||
"""
|
||||
pass
|
||||
def play(self, index:int, track: tuple[str, bool, bool, bool, dict[str, str]]) -> tuple[tuple[str, bool, bool, bool, dict[str, str]], bool] | tuple[None, None]:
|
||||
"""
|
||||
Returns a tuple, in the first case where a is the track and b is a bool, b corresponds to whether to extend the playlist, set to true when adding content instead of replacing it
|
||||
When None, None is returned then that is treated as a skip, meaning the core will skip this song
|
||||
"""
|
||||
return track, False
|
||||
def on_new_playlist(self, playlist: list[tuple[str, bool, bool, bool, dict[str, str]]]):
|
||||
"""
|
||||
Same behaviour as the basic module function
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
||||
[project]
|
||||
name = "radio-tools"
|
||||
version = "0.1"
|
||||
dependencies = []
|
||||
dependencies = ["log95", "unidecode", "libcache"]
|
||||
|
||||
[tool.setuptools]
|
||||
py-modules = ["radioPlaylist", "radioPlayer"]
|
||||
|
||||
@@ -206,7 +206,6 @@ def play_playlist(playlist_path):
|
||||
if track_tuple is None:
|
||||
song_i += 1
|
||||
continue
|
||||
logger.debug(repr(song_i), repr(old_track_tuple), repr(track_tuple), repr(old_track_tuple != track_tuple))
|
||||
if extend: max_iterator += 1
|
||||
else:
|
||||
extend = False
|
||||
@@ -294,6 +293,7 @@ def main():
|
||||
|
||||
try:
|
||||
arg = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else None
|
||||
if active_modifier: active_modifier.arguments(arg)
|
||||
while True:
|
||||
play_playlist(playlist_advisor.advise(arg))
|
||||
if exit_pending: exit()
|
||||
|
||||
Reference in New Issue
Block a user