Added change_settings and refresh_players to the players, still need to hook up UI

This commit is contained in:
Sumner Evans
2020-06-28 12:08:47 -06:00
parent 4aa883b10f
commit 3efffe8b4f
5 changed files with 101 additions and 27 deletions

View File

@@ -617,7 +617,7 @@ class SublimeMusicApp(Gtk.Application):
if confirm_dialog.run() == Gtk.ResponseType.YES:
assert self.app_config.cache_location
provider_dir = self.app_config.cache_location.joinpath(provider.id)
shutil.rmtree(str(provider_dir))
shutil.rmtree(str(provider_dir), ignore_errors=True)
del self.app_config.providers[provider.id]
confirm_dialog.destroy()

View File

@@ -99,7 +99,7 @@ class Player(abc.ABC):
def get_configuration_options() -> Dict[str, Union[Type, Tuple[str, ...]]]:
"""
:returns: a dictionary of configuration key -> type of the option or tuple of
options (for a dropdown menu)
options (for a dropdown menu).
"""
@abc.abstractmethod
@@ -114,7 +114,27 @@ class Player(abc.ABC):
"""
Initialize the player.
:param config: A dictionary of configuration key -> configuration value
:param config: A dictionary of configuration key -> configuration value.
"""
@abc.abstractmethod
def change_settings(self, config: Dict[str, Union[str, int, bool]]):
"""
This function is called when the player settings are changed (normally this
happens when the user changes the settings in the UI).
:param config: A dictionary of configuration key -> configuration value.
"""
@abc.abstractmethod
def refresh_players(self):
"""
This function is called when the user requests the player list to be refreshed
in the UI.
This function should call the ``player_device_change_callback`` with the delta
events to indicate changes to the UI. If there is no reason to refresh (for
example, the MPV player), then this function can do nothing.
"""
@abc.abstractmethod

View File

@@ -6,7 +6,7 @@ import multiprocessing
import os
import socket
from datetime import timedelta
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, Union
from typing import Any, Callable, cast, Dict, Optional, Set, Tuple, Type, Union
from urllib.parse import urlparse
from uuid import UUID
@@ -65,37 +65,74 @@ class ChromecastPlayer(Player):
player_device_change_callback: Callable[[PlayerDeviceEvent], None],
config: Dict[str, Union[str, int, bool]],
):
self.server_process = None
self.config = config
self.server_process: Optional[multiprocessing.Process] = None
self.on_timepos_change = on_timepos_change
self.on_track_end = on_track_end
self.on_player_event = on_player_event
self.player_device_change_callback = player_device_change_callback
self.change_settings(config)
if chromecast_imported:
self._chromecasts: Dict[UUID, pychromecast.Chromecast] = {}
self._current_chromecast: Optional[pychromecast.Chromecast] = None
self.get_chromecasts_job = None
self.refresh_players()
def chromecast_discovered_callback(self, chromecast: Any):
chromecast = cast(pychromecast.Chromecast, chromecast)
self._chromecasts[chromecast.device.uuid] = chromecast
self.player_device_change_callback(
PlayerDeviceEvent(
PlayerDeviceEvent.Delta.ADD,
type(self),
str(chromecast.device.uuid),
chromecast.device.friendly_name,
)
)
def change_settings(self, config: Dict[str, Union[str, int, bool]]):
if not chromecast_imported:
return
self.config = config
if bottle_imported and self.config.get(SERVE_FILES_KEY):
# TODO (#222): should have a mechanism to update this. Maybe it should be
# determined every time we try and play a song.
# Try and terminate the existing process if it exists.
if self.server_process is not None:
try:
self.server_process.terminate()
except Exception:
pass
self.server_process = multiprocessing.Process(
target=self._run_server_process,
args=("0.0.0.0", self.config.get(LAN_PORT_KEY)),
)
self.server_process.start()
if chromecast_imported:
self._chromecasts: Dict[UUID, pychromecast.Chromecast] = {}
self._current_chromecast: Optional[pychromecast.Chromecast] = None
def refresh_players(self):
if not chromecast_imported:
return
def discovered_callback(chromecast: pychromecast.Chromecast):
self._chromecasts[chromecast.device.uuid] = chromecast
player_device_change_callback(
PlayerDeviceEvent(
PlayerDeviceEvent.Delta.ADD,
type(self),
str(chromecast.device.uuid),
chromecast.device.friendly_name,
)
if self.get_chromecasts_job is not None:
pychromecast.discovery.stop_discovery(self.get_chromecasts_job)
for id_, chromecast in self._chromecasts.items():
self.player_device_change_callback(
PlayerDeviceEvent(
PlayerDeviceEvent.Delta.REMOVE,
type(self),
id_,
chromecast.device.friendly_name,
)
)
pychromecast.get_chromecasts(blocking=False, callback=discovered_callback)
self._chromecasts = {}
self.get_chromecasts_job = pychromecast.get_chromecasts(
blocking=False, callback=self.chromecast_discovered_callback
)
def set_current_device_id(self, device_id: str):
self._current_chromecast = self._chromecasts[UUID(device_id)]

View File

@@ -66,7 +66,16 @@ class PlayerManager:
for player_type in PlayerManager.available_player_types
}
has_done_one_retrieval = multiprocessing.Value("b", False)
def change_settings(
self, config: Dict[str, Dict[str, Union[Type, Tuple[str, ...]]]],
):
self.config = config
for player_type, player in self.players.items():
player.change_settings(config.get(player_type.name))
def refresh_players(self):
for player in self.players.values():
player.refresh_players()
def shutdown(self):
for p in self.players.values():

View File

@@ -38,11 +38,7 @@ class MPVPlayer(Player):
):
self.mpv = mpv.MPV()
self.mpv.audio_client_name = "sublime-music"
self.mpv.replaygain = {
"Disabled": "no",
"Track": "track",
"Album": "album",
}.get(cast(str, config.get(REPLAY_GAIN_KEY, "Disabled")), "no")
self.change_settings(config)
@self.mpv.property_observer("time-pos")
def time_observer(_, value: Optional[float]):
@@ -72,6 +68,18 @@ class MPVPlayer(Player):
)
)
def change_settings(self, config: Dict[str, Union[str, int, bool]]):
self.config = config
self.mpv.replaygain = {
"Disabled": "no",
"Track": "track",
"Album": "album",
}.get(cast(str, config.get(REPLAY_GAIN_KEY, "Disabled")), "no")
def refresh_players(self):
# Don't do anything
pass
def set_current_device_id(self, device_id: str):
# Don't do anything beacuse it should always be the "this device" ID.
pass