Added change_settings and refresh_players to the players, still need to hook up UI
This commit is contained in:
@@ -617,7 +617,7 @@ class SublimeMusicApp(Gtk.Application):
|
|||||||
if confirm_dialog.run() == Gtk.ResponseType.YES:
|
if confirm_dialog.run() == Gtk.ResponseType.YES:
|
||||||
assert self.app_config.cache_location
|
assert self.app_config.cache_location
|
||||||
provider_dir = self.app_config.cache_location.joinpath(provider.id)
|
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]
|
del self.app_config.providers[provider.id]
|
||||||
|
|
||||||
confirm_dialog.destroy()
|
confirm_dialog.destroy()
|
||||||
|
@@ -99,7 +99,7 @@ class Player(abc.ABC):
|
|||||||
def get_configuration_options() -> Dict[str, Union[Type, Tuple[str, ...]]]:
|
def get_configuration_options() -> Dict[str, Union[Type, Tuple[str, ...]]]:
|
||||||
"""
|
"""
|
||||||
:returns: a dictionary of configuration key -> type of the option or tuple of
|
: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
|
@abc.abstractmethod
|
||||||
@@ -114,7 +114,27 @@ class Player(abc.ABC):
|
|||||||
"""
|
"""
|
||||||
Initialize the player.
|
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
|
@abc.abstractmethod
|
||||||
|
@@ -6,7 +6,7 @@ import multiprocessing
|
|||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
from datetime import timedelta
|
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 urllib.parse import urlparse
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
@@ -65,37 +65,74 @@ class ChromecastPlayer(Player):
|
|||||||
player_device_change_callback: Callable[[PlayerDeviceEvent], None],
|
player_device_change_callback: Callable[[PlayerDeviceEvent], None],
|
||||||
config: Dict[str, Union[str, int, bool]],
|
config: Dict[str, Union[str, int, bool]],
|
||||||
):
|
):
|
||||||
self.server_process = None
|
self.server_process: Optional[multiprocessing.Process] = None
|
||||||
self.config = config
|
|
||||||
self.on_timepos_change = on_timepos_change
|
self.on_timepos_change = on_timepos_change
|
||||||
self.on_track_end = on_track_end
|
self.on_track_end = on_track_end
|
||||||
self.on_player_event = on_player_event
|
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):
|
if bottle_imported and self.config.get(SERVE_FILES_KEY):
|
||||||
# TODO (#222): should have a mechanism to update this. Maybe it should be
|
# Try and terminate the existing process if it exists.
|
||||||
# determined every time we try and play a song.
|
if self.server_process is not None:
|
||||||
|
try:
|
||||||
|
self.server_process.terminate()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
self.server_process = multiprocessing.Process(
|
self.server_process = multiprocessing.Process(
|
||||||
target=self._run_server_process,
|
target=self._run_server_process,
|
||||||
args=("0.0.0.0", self.config.get(LAN_PORT_KEY)),
|
args=("0.0.0.0", self.config.get(LAN_PORT_KEY)),
|
||||||
)
|
)
|
||||||
self.server_process.start()
|
self.server_process.start()
|
||||||
|
|
||||||
if chromecast_imported:
|
def refresh_players(self):
|
||||||
self._chromecasts: Dict[UUID, pychromecast.Chromecast] = {}
|
if not chromecast_imported:
|
||||||
self._current_chromecast: Optional[pychromecast.Chromecast] = None
|
return
|
||||||
|
|
||||||
def discovered_callback(chromecast: pychromecast.Chromecast):
|
if self.get_chromecasts_job is not None:
|
||||||
self._chromecasts[chromecast.device.uuid] = chromecast
|
pychromecast.discovery.stop_discovery(self.get_chromecasts_job)
|
||||||
player_device_change_callback(
|
|
||||||
PlayerDeviceEvent(
|
for id_, chromecast in self._chromecasts.items():
|
||||||
PlayerDeviceEvent.Delta.ADD,
|
self.player_device_change_callback(
|
||||||
type(self),
|
PlayerDeviceEvent(
|
||||||
str(chromecast.device.uuid),
|
PlayerDeviceEvent.Delta.REMOVE,
|
||||||
chromecast.device.friendly_name,
|
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):
|
def set_current_device_id(self, device_id: str):
|
||||||
self._current_chromecast = self._chromecasts[UUID(device_id)]
|
self._current_chromecast = self._chromecasts[UUID(device_id)]
|
||||||
|
@@ -66,7 +66,16 @@ class PlayerManager:
|
|||||||
for player_type in PlayerManager.available_player_types
|
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):
|
def shutdown(self):
|
||||||
for p in self.players.values():
|
for p in self.players.values():
|
||||||
|
@@ -38,11 +38,7 @@ class MPVPlayer(Player):
|
|||||||
):
|
):
|
||||||
self.mpv = mpv.MPV()
|
self.mpv = mpv.MPV()
|
||||||
self.mpv.audio_client_name = "sublime-music"
|
self.mpv.audio_client_name = "sublime-music"
|
||||||
self.mpv.replaygain = {
|
self.change_settings(config)
|
||||||
"Disabled": "no",
|
|
||||||
"Track": "track",
|
|
||||||
"Album": "album",
|
|
||||||
}.get(cast(str, config.get(REPLAY_GAIN_KEY, "Disabled")), "no")
|
|
||||||
|
|
||||||
@self.mpv.property_observer("time-pos")
|
@self.mpv.property_observer("time-pos")
|
||||||
def time_observer(_, value: Optional[float]):
|
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):
|
def set_current_device_id(self, device_id: str):
|
||||||
# Don't do anything beacuse it should always be the "this device" ID.
|
# Don't do anything beacuse it should always be the "this device" ID.
|
||||||
pass
|
pass
|
||||||
|
Reference in New Issue
Block a user