Files
sublime-music/libremsonic/app.py
2019-06-22 14:45:38 -06:00

171 lines
5.8 KiB
Python

import os
from typing import Callable
import mpv
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gio, Gtk, GLib, Gdk
from .ui.main import MainWindow
from .ui.configure_servers import ConfigureServersDialog
from .state_manager import ApplicationState
from .cache_manager import CacheManager
class LibremsonicApp(Gtk.Application):
def __init__(self, *args, **kwargs):
super().__init__(
*args,
application_id="com.sumnerevans.libremsonic",
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
**kwargs,
)
self.window = None
self.state = ApplicationState()
# Specify Command Line Options
self.add_main_option(
'config', ord('c'), GLib.OptionFlags.NONE, GLib.OptionArg.FILENAME,
'Specify a configuration file. Defaults to ~/.config/libremsonic/config.json',
None)
self.player = mpv.MPV(pause=True)
@self.player.property_observer('time-pos')
def time_observer(_name, value):
# TODO handle this
# self.window.player_controls.update_scrubber
pass
# Handle command line option parsing.
def do_command_line(self, command_line):
options = command_line.get_options_dict()
# Config File
config_file = options.lookup_value('config')
if config_file:
config_file = config_file.get_bytestring().decode('utf-8')
else:
# Default to ~/.config/libremsonic.
config_folder = (os.environ.get('XDG_CONFIG_HOME')
or os.path.expanduser('~/.config'))
config_folder = os.path.join(config_folder, 'libremsonic')
config_file = os.path.join(config_folder, 'config.yaml')
self.state.config_file = config_file
# Have to do this or else the application doesn't work. Not entirely
# sure why, but C-bindings...
self.activate()
return 0
def do_startup(self):
Gtk.Application.do_startup(self)
def add_action(name: str, fn):
"""Registers an action with the application."""
action = Gio.SimpleAction.new(name, None)
action.connect('activate', fn)
self.add_action(action)
# Add action for menu items.
add_action('configure-servers', self.on_configure_servers)
# Add actions for player controls
add_action('play-pause', self.on_play_pause)
add_action('next-track', self.on_next_track)
add_action('prev-track', self.on_prev_track)
add_action('repeat-press', self.on_repeat_press)
add_action('shuffle-press', self.on_shuffle_press)
def do_activate(self):
# We only allow a single window and raise any existing ones
if not self.window:
# Windows are associated with the application when the last one is
# closed the application shuts down.
self.window = MainWindow(application=self, title="LibremSonic")
# Configure the CSS provider so that we can style elements on the
# window.
css_provider = Gtk.CssProvider()
css_provider.load_from_path(
os.path.join(os.path.dirname(__file__), 'ui/app_styles.css'))
context = Gtk.StyleContext()
screen = Gdk.Screen.get_default()
context.add_provider_for_screen(screen, css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
self.window.stack.connect('notify::visible-child',
self.on_stack_change)
# Display the window.
self.window.show_all()
self.window.present()
# Load the configuration and update the UI with the curent server, if
# it exists.
self.state.load_config()
# If there is no current server, show the dialog to select a server.
if self.state.config.current_server is None:
self.show_configure_servers_dialog()
else:
self.on_connected_server_changed(
None,
self.state.config.current_server,
)
# ########## ACTION HANDLERS ########## #
def on_configure_servers(self, action, param):
self.show_configure_servers_dialog()
def on_play_pause(self, action, param):
self.player.command('cycle', 'pause')
self.state.playing = not self.state.playing
self.update_window()
def on_next_track(self, action, params):
self.player.playlist_next()
def on_prev_track(self, action, params):
self.player.playlist_prev()
def on_repeat_press(self, action, params):
print('repeat press')
def on_shuffle_press(self, action, params):
print('shuffle press')
def on_server_list_changed(self, action, servers):
self.state.config.servers = servers
self.state.save_config()
def on_connected_server_changed(self, action, current_server):
self.state.config.current_server = current_server
self.state.save_config()
self.state.cache_manager = CacheManager(
self.state.config.servers[self.state.config.current_server])
# Update the window according to the new server configuration.
self.update_window()
def on_stack_change(self, stack, child):
self.update_window()
# ########## HELPER METHODS ########## #
def show_configure_servers_dialog(self):
"""Show the Connect to Server dialog."""
dialog = ConfigureServersDialog(self.window, self.state.config)
dialog.connect('server-list-changed', self.on_server_list_changed)
dialog.connect('connected-server-changed',
self.on_connected_server_changed)
dialog.run()
dialog.destroy()
def update_window(self):
self.window.update(self.state)