mirror of
https://github.com/radio95-rnt/RadioPlayer.git
synced 2026-07-31 00:09:16 +02:00
move stuff to .playlist
This commit is contained in:
+43
-48
@@ -32,9 +32,7 @@ class ABC_ProcessManager(abc.ABC):
|
|||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def wait_all(self, timeout: float | None = None) -> None: ...
|
def wait_all(self, timeout: float | None = None) -> None: ...
|
||||||
class BaseIMCModule:
|
class BaseIMCModule:
|
||||||
"""
|
"""This is not a module to be used but rather a placeholder IMC api to be used in other modules"""
|
||||||
This is not a module to be used but rather a placeholder IMC api to be used in other modules
|
|
||||||
"""
|
|
||||||
def imc(self, imc: 'InterModuleCommunication') -> None:
|
def imc(self, imc: 'InterModuleCommunication') -> None:
|
||||||
"""
|
"""
|
||||||
Receive an IMC object
|
Receive an IMC object
|
||||||
@@ -64,8 +62,7 @@ class ProcmanCommunicator(BaseIMCModule):
|
|||||||
elif int(op) == 2:
|
elif int(op) == 2:
|
||||||
self.procman.stop_all(data.get("timeout", None))
|
self.procman.stop_all(data.get("timeout", None))
|
||||||
return {"op": 2}
|
return {"op": 2}
|
||||||
elif int(op) == 3:
|
elif int(op) == 3: raise NotImplementedError("This feature was removed.")
|
||||||
raise NotImplementedError("This feature was removed.")
|
|
||||||
elif int(op) == 4:
|
elif int(op) == 4:
|
||||||
return {"op": 4, "arg": self.procman.anything_playing()}
|
return {"op": 4, "arg": self.procman.anything_playing()}
|
||||||
elif int(op) == 5:
|
elif int(op) == 5:
|
||||||
@@ -73,16 +70,12 @@ class ProcmanCommunicator(BaseIMCModule):
|
|||||||
else: return
|
else: return
|
||||||
|
|
||||||
class PlayerModule(BaseIMCModule):
|
class PlayerModule(BaseIMCModule):
|
||||||
"""
|
"""Simple passive observer, this allows you to send the current track the your RDS encoder, or to your website"""
|
||||||
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[Track], global_args: dict[str, str]) -> None:
|
def on_new_playlist(self, playlist: list[Track], global_args: dict[str, str]) -> None:
|
||||||
"""This is called every new playlist"""
|
"""This is called every new playlist"""
|
||||||
pass
|
pass
|
||||||
def on_new_track(self, index: int, track: Track, next_track: Track | None) -> None:
|
def on_new_track(self, index: int, track: Track, next_track: Track | None) -> None:
|
||||||
"""
|
"""Called on every track including the ones added by the active modifier, you can check for that comparing the playlists[index] and the track"""
|
||||||
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
|
pass
|
||||||
def progress(self, index: int, track: Track, elapsed: float, total: float, real_total: float) -> None:
|
def progress(self, index: int, track: Track, elapsed: float, total: float, real_total: float) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -92,14 +85,10 @@ class PlayerModule(BaseIMCModule):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""
|
"""Ran while shutting down"""
|
||||||
Ran while shutting down
|
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
class PlaylistModifierModule:
|
class PlaylistModifierModule:
|
||||||
"""
|
"""Playlist modifier, this type of module allows you to shuffle, or put jingles into your playlist"""
|
||||||
Playlist modifier, this type of module allows you to shuffle, or put jingles into your playlist
|
|
||||||
"""
|
|
||||||
def modify(self, global_args: dict, playlist: list[Track]) -> list[Track] | None:
|
def modify(self, global_args: dict, playlist: list[Track]) -> list[Track] | None:
|
||||||
"""
|
"""
|
||||||
global_args are playlist global args (see radioPlayer_playlist_file.txt)
|
global_args are playlist global args (see radioPlayer_playlist_file.txt)
|
||||||
@@ -107,27 +96,17 @@ class PlaylistModifierModule:
|
|||||||
return playlist
|
return playlist
|
||||||
# No IMC, as we only run on new playlists
|
# No IMC, as we only run on new playlists
|
||||||
class PlaylistAdvisor(BaseIMCModule):
|
class PlaylistAdvisor(BaseIMCModule):
|
||||||
"""
|
"""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"""
|
||||||
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) -> Path | None:
|
def advise(self, arguments: str | None) -> Path | None:
|
||||||
"""
|
"""Arguments are the arguments passed to the program on startup"""
|
||||||
Arguments are the arguments passed to the program on startup
|
|
||||||
"""
|
|
||||||
return Path("/path/to/playlist.txt")
|
return Path("/path/to/playlist.txt")
|
||||||
def new_playlist(self) -> bool:
|
def new_playlist(self) -> bool:
|
||||||
"""
|
"""Whether to play a new playlist, if this is True, then the player will refresh and fetch a new playlist, calling advise"""
|
||||||
Whether to play a new playlist, if this is True, then the player will refresh and fetch a new playlist, calling advise
|
|
||||||
"""
|
|
||||||
return False
|
return False
|
||||||
class ActiveModifier(BaseIMCModule):
|
class ActiveModifier(BaseIMCModule):
|
||||||
"""
|
"""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"""
|
||||||
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 arguments(self, arguments: str | None) -> None:
|
def arguments(self, arguments: str | None) -> None:
|
||||||
"""
|
"""Called at start up with the program arguments"""
|
||||||
Called at start up with the program arguments
|
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
def play(self, index: int, track: Track | None, next_track: Track | None) -> tuple[tuple[Track | None, Track | None], bool | None]:
|
def play(self, index: int, track: Track | None, next_track: Track | None) -> tuple[tuple[Track | None, Track | None], bool | None]:
|
||||||
"""
|
"""
|
||||||
@@ -137,9 +116,7 @@ class ActiveModifier(BaseIMCModule):
|
|||||||
"""
|
"""
|
||||||
return (track, None), False
|
return (track, None), False
|
||||||
def on_new_playlist(self, playlist: list[Track], global_args: dict[str, str]) -> None:
|
def on_new_playlist(self, playlist: list[Track], global_args: dict[str, str]) -> None:
|
||||||
"""
|
"""Same behaviour as the basic module function"""
|
||||||
Same behaviour as the basic module function
|
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
class InterModuleCommunication:
|
class InterModuleCommunication:
|
||||||
def __init__(self, modules: Sequence[BaseIMCModule | None]) -> None:
|
def __init__(self, modules: Sequence[BaseIMCModule | None]) -> None:
|
||||||
@@ -147,31 +124,24 @@ class InterModuleCommunication:
|
|||||||
self.names_modules: dict[str, BaseIMCModule] = {}
|
self.names_modules: dict[str, BaseIMCModule] = {}
|
||||||
[module.imc(self) for module in modules if module]
|
[module.imc(self) for module in modules if module]
|
||||||
def broadcast(self, source: BaseIMCModule, data: object) -> None:
|
def broadcast(self, source: BaseIMCModule, data: object) -> None:
|
||||||
"""
|
"""Send data to all modules, other than ourself"""
|
||||||
Send data to all modules, other than ourself
|
|
||||||
"""
|
|
||||||
source_name = next((k for k, v in self.names_modules.items() if v is source), None)
|
source_name = next((k for k, v in self.names_modules.items() if v is source), None)
|
||||||
for module in [f for f in self.modules if (f is not source) and f]: module.imc_data(source, source_name, data, True)
|
for module in [f for f in self.modules if (f is not source) and f]: module.imc_data(source, source_name, data, True)
|
||||||
def register(self, module: BaseIMCModule, name: str) -> bool:
|
def register(self, module: BaseIMCModule, name: str) -> bool:
|
||||||
"""
|
"""Register our module with a name, so we can be sent data via the send function"""
|
||||||
Register our module with a name, so we can be sent data via the send function
|
|
||||||
"""
|
|
||||||
if name in self.names_modules.keys(): return False
|
if name in self.names_modules.keys(): return False
|
||||||
self.names_modules[name] = module
|
self.names_modules[name] = module
|
||||||
return True
|
return True
|
||||||
def send(self, source: BaseIMCModule, name: str, data: object, aggresive: bool = True) -> object:
|
def send(self, source: BaseIMCModule, name: str, data: object, aggressive: bool = True) -> object:
|
||||||
"""
|
"""Sends the data to a named module, and return its response"""
|
||||||
Sends the data to a named module, and return its response
|
|
||||||
"""
|
|
||||||
if not name in self.names_modules.keys():
|
if not name in self.names_modules.keys():
|
||||||
if aggresive: raise ModuleNotFoundError("No such module")
|
if aggressive: raise ModuleNotFoundError("No such module")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.names_modules[name].imc_data(source, next((k for k, v in self.names_modules.items() if v is source), None), data, False)
|
return self.names_modules[name].imc_data(source, next((k for k, v in self.names_modules.items() if v is source), None), data, False)
|
||||||
|
|
||||||
class PlaylistParser:
|
class PlaylistParser:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None: pass
|
||||||
pass
|
|
||||||
def parse(self, playlist_path: Path) -> tuple[dict[str, str], list[tuple[list[str], dict[str, str]]]]:
|
def parse(self, playlist_path: Path) -> tuple[dict[str, str], list[tuple[list[str], dict[str, str]]]]:
|
||||||
"""
|
"""
|
||||||
This should return the following information:
|
This should return the following information:
|
||||||
@@ -181,3 +151,28 @@ class PlaylistParser:
|
|||||||
and a dictionary of str:str consistent of the arguments which affect the files given
|
and a dictionary of str:str consistent of the arguments which affect the files given
|
||||||
"""
|
"""
|
||||||
return {}, []
|
return {}, []
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <https://unlicense.org>
|
||||||
@@ -11,3 +11,28 @@ class Module(PlaylistModifierModule):
|
|||||||
else: out.append(track)
|
else: out.append(track)
|
||||||
return out
|
return out
|
||||||
playlistmod = (Module(),1)
|
playlistmod = (Module(),1)
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <https://unlicense.org>
|
||||||
+13
-3
@@ -49,6 +49,16 @@ class Module2(PlayerModule):
|
|||||||
if self.secondary and (random.randint(1,3) == 1): jingle = random.choice(self.secondary)
|
if self.secondary and (random.randint(1,3) == 1): jingle = random.choice(self.secondary)
|
||||||
return self._imc.send(self, "activemod", {"action": "add_to_toplay", "songs": [f"!{jingle}"], "top": bool(data)})
|
return self._imc.send(self, "activemod", {"action": "add_to_toplay", "songs": [f"!{jingle}"], "top": bool(data)})
|
||||||
|
|
||||||
options = Path("/home/user/Jingiel.mp3"), [Path("/home/user/jing2.opus"), Path("/home/user/Jing3.opus"), Path("/home/user/jing4.opus")]
|
master: Path | None = None
|
||||||
module = Module2(*options)
|
jingles: list[Path] = []
|
||||||
playlistmod = Module(*options)
|
for file in Path("/home/user/mixes/.playlist/jingle").iterdir():
|
||||||
|
if not file.is_file(): continue
|
||||||
|
name, ext = file.name.rsplit('.', 1)
|
||||||
|
if name.lower() == "master":
|
||||||
|
master = file
|
||||||
|
continue
|
||||||
|
jingles.append(file)
|
||||||
|
if not master: master = jingles.pop(0)
|
||||||
|
|
||||||
|
module = Module2(master, jingles)
|
||||||
|
playlistmod = Module(master, jingles)
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ def load_dict_from_custom_format(file_path: str | Path) -> dict[str, str]:
|
|||||||
|
|
||||||
class Module(PlayerModule):
|
class Module(PlayerModule):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.logger = log95.log95("PlayCnt", output=_log_out)
|
self.logger = log95.log95("PlayCnt", output=_log_out) # That sounds bad...
|
||||||
self.file = Path(__file__, "..", "..", "play_counter").resolve()
|
self.file = Path("/home/user/mixes/.playlist/count.txt").resolve()
|
||||||
self.counts: dict[str, int] = {}
|
self.counts: dict[str, int] = {}
|
||||||
loaded = load_dict_from_custom_format(self.file)
|
loaded = load_dict_from_custom_format(self.file)
|
||||||
for k, v in loaded.items():
|
for k, v in loaded.items():
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class PopularitySorterModule(PlaylistModifierModule):
|
|||||||
"""
|
"""
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.logger = log95.log95("PopSort", output=_log_out)
|
self.logger = log95.log95("PopSort", output=_log_out)
|
||||||
self.play_counts_file = Path(__file__, "..", "..", "play_counter").resolve()
|
self.play_counts_file = Path("/home/user/mixes/.playlist/count.txt").resolve()
|
||||||
|
|
||||||
def modify(self, global_args: dict, playlist: list[Track]) -> list[Track]:
|
def modify(self, global_args: dict, playlist: list[Track]) -> list[Track]:
|
||||||
self.logger.info("Applying popularity-based sorting to the playlist...")
|
self.logger.info("Applying popularity-based sorting to the playlist...")
|
||||||
@@ -41,8 +41,7 @@ class PopularitySorterModule(PlaylistModifierModule):
|
|||||||
|
|
||||||
sorted_by_play_count = sorted(play_counts.items(), key=lambda item: item[1], reverse=True)
|
sorted_by_play_count = sorted(play_counts.items(), key=lambda item: item[1], reverse=True)
|
||||||
|
|
||||||
SORT_LEN = 100
|
SORT_LEN = len(playlist) // 3
|
||||||
if len(playlist) >= SORT_LEN:
|
|
||||||
top_paths = {path for path, count in sorted_by_play_count[:SORT_LEN]}
|
top_paths = {path for path, count in sorted_by_play_count[:SORT_LEN]}
|
||||||
least_top_paths = {path for path, count in sorted_by_play_count[-SORT_LEN:]}
|
least_top_paths = {path for path, count in sorted_by_play_count[-SORT_LEN:]}
|
||||||
for a,b in zip(top_paths, least_top_paths):
|
for a,b in zip(top_paths, least_top_paths):
|
||||||
@@ -56,8 +55,7 @@ class PopularitySorterModule(PlaylistModifierModule):
|
|||||||
if not b_track.official: continue
|
if not b_track.official: continue
|
||||||
if b_track.path == b: break
|
if b_track.path == b: break
|
||||||
if not b_track: continue
|
if not b_track: continue
|
||||||
if a_i < b_i:
|
if a_i < b_i: playlist[a_i], playlist[b_i] = playlist[b_i], playlist[a_i]
|
||||||
playlist[a_i], playlist[b_i] = playlist[b_i], playlist[a_i]
|
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(playlist) - 1:
|
while i < len(playlist) - 1:
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ class PlaintextParser(PlaylistParser):
|
|||||||
if "=" in arg:
|
if "=" in arg:
|
||||||
key, val = arg.split("=", 1)
|
key, val = arg.split("=", 1)
|
||||||
arguments[key] = val
|
arguments[key] = val
|
||||||
else:
|
else: arguments[arg] = True
|
||||||
arguments[arg] = True
|
|
||||||
else:
|
else:
|
||||||
line, args = line.split("|", 1)
|
line, args = line.split("|", 1)
|
||||||
args = args.split(";")
|
args = args.split(";")
|
||||||
@@ -49,8 +48,7 @@ class PlaintextParser(PlaylistParser):
|
|||||||
if "=" in arg:
|
if "=" in arg:
|
||||||
key, val = arg.split("=", 1)
|
key, val = arg.split("=", 1)
|
||||||
arguments[key] = val
|
arguments[key] = val
|
||||||
else:
|
else: arguments[arg] = True
|
||||||
arguments[arg] = True
|
|
||||||
out.append(([f for f in glob.glob(line) if Path(f).is_file()], arguments))
|
out.append(([f for f in glob.glob(line) if Path(f).is_file()], arguments))
|
||||||
return global_arguments, out
|
return global_arguments, out
|
||||||
|
|
||||||
|
|||||||
@@ -16,3 +16,28 @@ class Module(PlayerModule):
|
|||||||
if next_track: logger.info("Next up:", next_track.path.name)
|
if next_track: logger.info("Next up:", next_track.path.name)
|
||||||
|
|
||||||
module = Module()
|
module = Module()
|
||||||
|
|
||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# For more information, please refer to <https://unlicense.org>
|
||||||
+5
-11
@@ -20,7 +20,7 @@ async def ws_handler(websocket: ServerConnection, shared_data: dict, imc_q: mult
|
|||||||
"progress": json.loads(shared_data.get("progress", "{}")),
|
"progress": json.loads(shared_data.get("progress", "{}")),
|
||||||
"dirs": {"files": [i.name for i in list(MAIN_PATH_DIR.iterdir()) if i.is_file()], "dirs": [i.name for i in list(MAIN_PATH_DIR.iterdir()) if i.is_dir()], "base": str(MAIN_PATH_DIR)}
|
"dirs": {"files": [i.name for i in list(MAIN_PATH_DIR.iterdir()) if i.is_file()], "dirs": [i.name for i in list(MAIN_PATH_DIR.iterdir()) if i.is_dir()], "base": str(MAIN_PATH_DIR)}
|
||||||
}
|
}
|
||||||
except Exception: initial = {"playlist": [], "track": {}, "progress": {}}
|
except Exception: initial = {"playlist": [], "track": {}, "progress": {}, "dirs": {"files": [], "dirs": [], "base": ""}}
|
||||||
await websocket.send(json.dumps({"event": "state", "data": initial}))
|
await websocket.send(json.dumps({"event": "state", "data": initial}))
|
||||||
|
|
||||||
async for raw in websocket:
|
async for raw in websocket:
|
||||||
@@ -66,13 +66,7 @@ async def ws_handler(websocket: ServerConnection, shared_data: dict, imc_q: mult
|
|||||||
else:
|
else:
|
||||||
await websocket.send(json.dumps({"data": result, "event": "toplay"})) # Yes, this is not an accident
|
await websocket.send(json.dumps({"data": result, "event": "toplay"})) # Yes, this is not an accident
|
||||||
await asyncio.get_event_loop().run_in_executor(None, ws_q.put, {"data": result, "event": "toplay"})
|
await asyncio.get_event_loop().run_in_executor(None, ws_q.put, {"data": result, "event": "toplay"})
|
||||||
elif action == "skip_next":
|
elif action == "skip_next" or action == "skipc":
|
||||||
result = await get_imc("activemod", msg)
|
|
||||||
if result is None: await websocket.send(json.dumps({"error": "timeout", "code": 504}))
|
|
||||||
else:
|
|
||||||
await websocket.send(json.dumps({"data": result, "event": action}))
|
|
||||||
await asyncio.get_event_loop().run_in_executor(None, ws_q.put, {"data": result, "event": action}) # broadcast
|
|
||||||
elif action == "skipc":
|
|
||||||
result = await get_imc("activemod", msg)
|
result = await get_imc("activemod", msg)
|
||||||
if result is None: await websocket.send(json.dumps({"error": "timeout", "code": 504}))
|
if result is None: await websocket.send(json.dumps({"error": "timeout", "code": 504}))
|
||||||
else:
|
else:
|
||||||
@@ -261,12 +255,12 @@ class Module(PlayerModule):
|
|||||||
try: self.ws_q.put(None)
|
try: self.ws_q.put(None)
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
self.ipc_thread.join(timeout=2)
|
self.ipc_thread.join(timeout=1)
|
||||||
self.ws_process.join(timeout=3)
|
self.ws_process.join(timeout=1)
|
||||||
|
|
||||||
if self.ws_process.is_alive():
|
if self.ws_process.is_alive():
|
||||||
self.ws_process.terminate()
|
self.ws_process.terminate()
|
||||||
self.ws_process.join(timeout=2)
|
self.ws_process.join(timeout=1)
|
||||||
|
|
||||||
if self.ws_process.is_alive():
|
if self.ws_process.is_alive():
|
||||||
self.ws_process.kill()
|
self.ws_process.kill()
|
||||||
|
|||||||
Reference in New Issue
Block a user