rework project structure for more logical filenames and code separation
This commit is contained in:
parent
c603ab5c7c
commit
134d1a28a7
8 changed files with 258 additions and 228 deletions
23
mcg.py
Executable file
23
mcg.py
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""MPDCoverGrid is a client for the Music Player Daemon, focused on albums instead of single tracks."""
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from mcg.application import Application
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Set environment
|
||||||
|
srcdir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
if not os.environ.get('GSETTINGS_SCHEMA_DIR'):
|
||||||
|
os.environ['GSETTINGS_SCHEMA_DIR'] = os.path.join(srcdir, 'data')
|
||||||
|
|
||||||
|
# Start application
|
||||||
|
app = Application()
|
||||||
|
exit_status = app.run(sys.argv)
|
||||||
|
sys.exit(exit_status)
|
||||||
49
mcg/application.py
Normal file
49
mcg/application.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from gi.repository import Gio, Gtk, Gdk
|
||||||
|
|
||||||
|
from mcg import widgets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Application(Gtk.Application):
|
||||||
|
TITLE = "MPDCoverGrid (Gtk)"
|
||||||
|
SETTINGS_BASE_KEY = 'de.coderkun.mcg'
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Gtk.Application.__init__(self, application_id="de.coderkun.mcg-dev", flags=Gio.ApplicationFlags.FLAGS_NONE)
|
||||||
|
self._window = None
|
||||||
|
|
||||||
|
|
||||||
|
def do_startup(self):
|
||||||
|
Gtk.Application.do_startup(self)
|
||||||
|
self._settings = Gio.Settings.new(Application.SETTINGS_BASE_KEY)
|
||||||
|
self.load_css()
|
||||||
|
|
||||||
|
# Create builder to load UI
|
||||||
|
self._builder = Gtk.Builder()
|
||||||
|
self._builder.add_from_file('data/gtk.glade')
|
||||||
|
|
||||||
|
|
||||||
|
def do_activate(self):
|
||||||
|
Gtk.Application.do_activate(self)
|
||||||
|
if not self._window:
|
||||||
|
self._window = widgets.Window(self, self._builder, Application.TITLE, self._settings)
|
||||||
|
self._window.present()
|
||||||
|
|
||||||
|
|
||||||
|
def load_css(self):
|
||||||
|
styleProvider = Gtk.CssProvider()
|
||||||
|
styleProvider.load_from_file(Gio.File.new_for_path('data/mcg.css'))
|
||||||
|
Gtk.StyleContext.add_provider_for_screen(
|
||||||
|
Gdk.Screen.get_default(),
|
||||||
|
styleProvider,
|
||||||
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||||
|
)
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""MPDCoverGrid is a client for the Music Player Daemon, focused on albums instead of single tracks."""
|
|
||||||
|
|
||||||
__version__ = "0.4"
|
|
||||||
|
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
import glob
|
import glob
|
||||||
54
mcg/utils.py
Normal file
54
mcg/utils.py
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
import os
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from gi.repository import GdkPixbuf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Utils:
|
||||||
|
def load_cover(url):
|
||||||
|
if not url:
|
||||||
|
return None
|
||||||
|
if url.startswith('/'):
|
||||||
|
try:
|
||||||
|
return GdkPixbuf.Pixbuf.new_from_file(url)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
response = urllib.request.urlopen(url)
|
||||||
|
loader = GdkPixbuf.PixbufLoader()
|
||||||
|
loader.write(response.read())
|
||||||
|
loader.close()
|
||||||
|
return loader.get_pixbuf()
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def load_thumbnail(cache, album, size):
|
||||||
|
cache_url = cache.create_filename(album)
|
||||||
|
pixbuf = None
|
||||||
|
|
||||||
|
if os.path.isfile(cache_url):
|
||||||
|
try:
|
||||||
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(cache_url)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
else:
|
||||||
|
url = album.get_cover()
|
||||||
|
pixbuf = Utils.load_cover(url)
|
||||||
|
if pixbuf is not None:
|
||||||
|
pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.HYPER)
|
||||||
|
filetype = os.path.splitext(url)[1][1:]
|
||||||
|
if filetype == 'jpg':
|
||||||
|
filetype = 'jpeg'
|
||||||
|
pixbuf.savev(cache.create_filename(album), filetype, [], [])
|
||||||
|
return pixbuf
|
||||||
291
mcg/mcgGtk.py → mcg/widgets.py
Executable file → Normal file
291
mcg/mcgGtk.py → mcg/widgets.py
Executable file → Normal file
|
|
@ -1,13 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""MPDCoverGrid is a client for the Music Player Daemon, focused on albums instead of single tracks."""
|
|
||||||
|
|
||||||
__version__ = "0.6"
|
|
||||||
|
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
gi.require_version('Avahi', '0.6')
|
|
||||||
try:
|
try:
|
||||||
import keyring
|
import keyring
|
||||||
use_keyring = True
|
use_keyring = True
|
||||||
|
|
@ -15,22 +10,19 @@ except:
|
||||||
use_keyring = False
|
use_keyring = False
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import urllib
|
|
||||||
|
|
||||||
from gi.repository import Gio, Gtk, Gdk, GObject, GdkPixbuf, GLib
|
from gi.repository import Gtk, Gdk, GObject, GdkPixbuf, GLib
|
||||||
from gi.repository import Avahi
|
|
||||||
|
|
||||||
import mcg
|
from mcg import client
|
||||||
|
from mcg.utils import Utils
|
||||||
|
from mcg.zeroconf import ZeroconfProvider
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Application(Gtk.Application):
|
class Window():
|
||||||
TITLE = "MPDCoverGrid (Gtk)"
|
|
||||||
SETTINGS_BASE_KEY = 'de.coderkun.mcg'
|
|
||||||
SETTING_HOST = 'host'
|
SETTING_HOST = 'host'
|
||||||
SETTING_PORT = 'port'
|
SETTING_PORT = 'port'
|
||||||
SETTING_CONNECTED = 'connected'
|
SETTING_CONNECTED = 'connected'
|
||||||
|
|
@ -42,87 +34,6 @@ class Application(Gtk.Application):
|
||||||
SETTING_ITEM_SIZE = 'item-size'
|
SETTING_ITEM_SIZE = 'item-size'
|
||||||
SETTING_SORT_ORDER = 'sort-order'
|
SETTING_SORT_ORDER = 'sort-order'
|
||||||
SETTING_SORT_TYPE = 'sort-type'
|
SETTING_SORT_TYPE = 'sort-type'
|
||||||
KEYRING_SYSTEM = 'MPDCoverGrid (Gtk)'
|
|
||||||
KEYRING_USERNAME = 'mpd'
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
Gtk.Application.__init__(self, application_id="de.coderkun.mcg-dev", flags=Gio.ApplicationFlags.FLAGS_NONE)
|
|
||||||
self._window = None
|
|
||||||
|
|
||||||
|
|
||||||
def do_startup(self):
|
|
||||||
Gtk.Application.do_startup(self)
|
|
||||||
self._settings = Gio.Settings.new(Application.SETTINGS_BASE_KEY)
|
|
||||||
self.load_css()
|
|
||||||
|
|
||||||
# Create builder to load UI
|
|
||||||
self._builder = Gtk.Builder()
|
|
||||||
self._builder.add_from_file('data/gtk.glade')
|
|
||||||
|
|
||||||
|
|
||||||
def do_activate(self):
|
|
||||||
Gtk.Application.do_activate(self)
|
|
||||||
if not self._window:
|
|
||||||
self._window = Window(self, self._builder, Application.TITLE, self._settings)
|
|
||||||
self._window.present()
|
|
||||||
|
|
||||||
|
|
||||||
def load_css(self):
|
|
||||||
styleProvider = Gtk.CssProvider()
|
|
||||||
styleProvider.load_from_file(Gio.File.new_for_path('data/mcg.css'))
|
|
||||||
Gtk.StyleContext.add_provider_for_screen(
|
|
||||||
Gdk.Screen.get_default(),
|
|
||||||
styleProvider,
|
|
||||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def load_cover(url):
|
|
||||||
if not url:
|
|
||||||
return None
|
|
||||||
if url.startswith('/'):
|
|
||||||
try:
|
|
||||||
return GdkPixbuf.Pixbuf.new_from_file(url)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
response = urllib.request.urlopen(url)
|
|
||||||
loader = GdkPixbuf.PixbufLoader()
|
|
||||||
loader.write(response.read())
|
|
||||||
loader.close()
|
|
||||||
return loader.get_pixbuf()
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def load_thumbnail(cache, album, size):
|
|
||||||
cache_url = cache.create_filename(album)
|
|
||||||
pixbuf = None
|
|
||||||
|
|
||||||
if os.path.isfile(cache_url):
|
|
||||||
try:
|
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(cache_url)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
else:
|
|
||||||
url = album.get_cover()
|
|
||||||
pixbuf = Application.load_cover(url)
|
|
||||||
if pixbuf is not None:
|
|
||||||
pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.HYPER)
|
|
||||||
filetype = os.path.splitext(url)[1][1:]
|
|
||||||
if filetype == 'jpg':
|
|
||||||
filetype = 'jpeg'
|
|
||||||
pixbuf.savev(cache.create_filename(album), filetype, [], [])
|
|
||||||
return pixbuf
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Window():
|
|
||||||
_PANEL_INDEX_CONNECTION = 0
|
_PANEL_INDEX_CONNECTION = 0
|
||||||
_PANEL_INDEX_COVER = 1
|
_PANEL_INDEX_COVER = 1
|
||||||
_PANEL_INDEX_PLAYLIST = 2
|
_PANEL_INDEX_PLAYLIST = 2
|
||||||
|
|
@ -135,16 +46,16 @@ class Window():
|
||||||
self._appwindow.set_title(title)
|
self._appwindow.set_title(title)
|
||||||
self._settings = settings
|
self._settings = settings
|
||||||
self._panels = []
|
self._panels = []
|
||||||
self._mcg = mcg.Client()
|
self._mcg = client.Client()
|
||||||
self._logger = logging.getLogger(__name__)
|
self._logger = logging.getLogger(__name__)
|
||||||
self._logger.addHandler(logging.StreamHandler(stream=sys.stdout))
|
self._logger.addHandler(logging.StreamHandler(stream=sys.stdout))
|
||||||
self._logger.setLevel(logging.ERROR)
|
self._logger.setLevel(logging.ERROR)
|
||||||
logging.getLogger(mcg.__name__).addHandler(logging.StreamHandler(stream=sys.stdout))
|
logging.getLogger(client.__name__).addHandler(logging.StreamHandler(stream=sys.stdout))
|
||||||
logging.getLogger(mcg.__name__).setLevel(logging.ERROR)
|
logging.getLogger(client.__name__).setLevel(logging.ERROR)
|
||||||
#self._mcg.get_logger().addHandler(logging.StreamHandler(stream=sys.stdout))
|
#self._mcg.get_logger().addHandler(logging.StreamHandler(stream=sys.stdout))
|
||||||
#self._mcg.get_logger().setLevel(logging.ERROR)
|
#self._mcg.get_logger().setLevel(logging.ERROR)
|
||||||
self._size = self._settings.get_value(Application.SETTING_WINDOW_SIZE)
|
self._size = self._settings.get_value(Window.SETTING_WINDOW_SIZE)
|
||||||
self._maximized = self._settings.get_boolean(Application.SETTING_WINDOW_MAXIMIZED)
|
self._maximized = self._settings.get_boolean(Window.SETTING_WINDOW_MAXIMIZED)
|
||||||
self._fullscreened = False
|
self._fullscreened = False
|
||||||
|
|
||||||
# Panels
|
# Panels
|
||||||
|
|
@ -165,16 +76,16 @@ class Window():
|
||||||
|
|
||||||
# Properties
|
# Properties
|
||||||
self._header_bar.set_sensitive(False, False)
|
self._header_bar.set_sensitive(False, False)
|
||||||
self._panels[Window._PANEL_INDEX_CONNECTION].set_host(self._settings.get_string(Application.SETTING_HOST))
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_host(self._settings.get_string(Window.SETTING_HOST))
|
||||||
self._panels[Window._PANEL_INDEX_CONNECTION].set_port(self._settings.get_int(Application.SETTING_PORT))
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_port(self._settings.get_int(Window.SETTING_PORT))
|
||||||
if use_keyring:
|
if use_keyring:
|
||||||
self._panels[Window._PANEL_INDEX_CONNECTION].set_password(keyring.get_password(Application.KEYRING_SYSTEM, Application.KEYRING_USERNAME))
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_password(keyring.get_password(ZeroconfProvider.KEYRING_SYSTEM, ZeroconfProvider.KEYRING_USERNAME))
|
||||||
self._panels[Window._PANEL_INDEX_CONNECTION].set_image_dir(self._settings.get_string(Application.SETTING_IMAGE_DIR))
|
self._panels[Window._PANEL_INDEX_CONNECTION].set_image_dir(self._settings.get_string(Window.SETTING_IMAGE_DIR))
|
||||||
self._panels[Window._PANEL_INDEX_COVER].set_tracklist_size(self._settings.get_string(Application.SETTING_TRACKLIST_SIZE))
|
self._panels[Window._PANEL_INDEX_COVER].set_tracklist_size(self._settings.get_string(Window.SETTING_TRACKLIST_SIZE))
|
||||||
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
|
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(self._settings.get_int(Window.SETTING_ITEM_SIZE))
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Application.SETTING_ITEM_SIZE))
|
self._panels[Window._PANEL_INDEX_LIBRARY].set_item_size(self._settings.get_int(Window.SETTING_ITEM_SIZE))
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_order(self._settings.get_string(Application.SETTING_SORT_ORDER))
|
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_order(self._settings.get_string(Window.SETTING_SORT_ORDER))
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_type(self._settings.get_boolean(Application.SETTING_SORT_TYPE))
|
self._panels[Window._PANEL_INDEX_LIBRARY].set_sort_type(self._settings.get_boolean(Window.SETTING_SORT_TYPE))
|
||||||
|
|
||||||
# Signals
|
# Signals
|
||||||
self._header_bar.connect_signal(HeaderBar.SIGNAL_STACK_SWITCHED, self.on_header_bar_stack_switched)
|
self._header_bar.connect_signal(HeaderBar.SIGNAL_STACK_SWITCHED, self.on_header_bar_stack_switched)
|
||||||
|
|
@ -191,16 +102,16 @@ class Window():
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].connect_signal(LibraryPanel.SIGNAL_ITEM_SIZE_CHANGED, self.on_library_panel_item_size_changed)
|
self._panels[Window._PANEL_INDEX_LIBRARY].connect_signal(LibraryPanel.SIGNAL_ITEM_SIZE_CHANGED, self.on_library_panel_item_size_changed)
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].connect_signal(LibraryPanel.SIGNAL_SORT_ORDER_CHANGED, self.on_library_panel_sort_order_changed)
|
self._panels[Window._PANEL_INDEX_LIBRARY].connect_signal(LibraryPanel.SIGNAL_SORT_ORDER_CHANGED, self.on_library_panel_sort_order_changed)
|
||||||
self._panels[Window._PANEL_INDEX_LIBRARY].connect_signal(LibraryPanel.SIGNAL_SORT_TYPE_CHANGED, self.on_library_panel_sort_type_changed)
|
self._panels[Window._PANEL_INDEX_LIBRARY].connect_signal(LibraryPanel.SIGNAL_SORT_TYPE_CHANGED, self.on_library_panel_sort_type_changed)
|
||||||
self._mcg.connect_signal(mcg.Client.SIGNAL_CONNECTION, self.on_mcg_connect)
|
self._mcg.connect_signal(client.Client.SIGNAL_CONNECTION, self.on_mcg_connect)
|
||||||
self._mcg.connect_signal(mcg.Client.SIGNAL_STATUS, self.on_mcg_status)
|
self._mcg.connect_signal(client.Client.SIGNAL_STATUS, self.on_mcg_status)
|
||||||
self._mcg.connect_signal(mcg.Client.SIGNAL_LOAD_PLAYLIST, self.on_mcg_load_playlist)
|
self._mcg.connect_signal(client.Client.SIGNAL_LOAD_PLAYLIST, self.on_mcg_load_playlist)
|
||||||
self._mcg.connect_signal(mcg.Client.SIGNAL_LOAD_ALBUMS, self.on_mcg_load_albums)
|
self._mcg.connect_signal(client.Client.SIGNAL_LOAD_ALBUMS, self.on_mcg_load_albums)
|
||||||
self._mcg.connect_signal(mcg.Client.SIGNAL_ERROR, self.on_mcg_error)
|
self._mcg.connect_signal(client.Client.SIGNAL_ERROR, self.on_mcg_error)
|
||||||
self._settings.connect('changed::'+Application.SETTING_PANEL, self.on_settings_panel_changed)
|
self._settings.connect('changed::'+Window.SETTING_PANEL, self.on_settings_panel_changed)
|
||||||
self._settings.connect('changed::'+Application.SETTING_TRACKLIST_SIZE, self.on_settings_tracklist_size_changed)
|
self._settings.connect('changed::'+Window.SETTING_TRACKLIST_SIZE, self.on_settings_tracklist_size_changed)
|
||||||
self._settings.connect('changed::'+Application.SETTING_ITEM_SIZE, self.on_settings_item_size_changed)
|
self._settings.connect('changed::'+Window.SETTING_ITEM_SIZE, self.on_settings_item_size_changed)
|
||||||
self._settings.connect('changed::'+Application.SETTING_SORT_ORDER, self.on_settings_sort_order_changed)
|
self._settings.connect('changed::'+Window.SETTING_SORT_ORDER, self.on_settings_sort_order_changed)
|
||||||
self._settings.connect('changed::'+Application.SETTING_SORT_TYPE, self.on_settings_sort_type_changed)
|
self._settings.connect('changed::'+Window.SETTING_SORT_TYPE, self.on_settings_sort_type_changed)
|
||||||
handlers = {
|
handlers = {
|
||||||
'on_appwindow_size_allocate': self.on_resize,
|
'on_appwindow_size_allocate': self.on_resize,
|
||||||
'on_appwindow_window_state_event': self.on_state,
|
'on_appwindow_window_state_event': self.on_state,
|
||||||
|
|
@ -220,7 +131,7 @@ class Window():
|
||||||
self._appwindow.maximize()
|
self._appwindow.maximize()
|
||||||
self._appwindow.show_all()
|
self._appwindow.show_all()
|
||||||
self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION].get())
|
self._stack.set_visible_child(self._panels[Window._PANEL_INDEX_CONNECTION].get())
|
||||||
if self._settings.get_boolean(Application.SETTING_CONNECTED):
|
if self._settings.get_boolean(Window.SETTING_CONNECTED):
|
||||||
self._connect()
|
self._connect()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -237,11 +148,11 @@ class Window():
|
||||||
def on_state(self, widget, state):
|
def on_state(self, widget, state):
|
||||||
self._maximized = (state.new_window_state & Gdk.WindowState.MAXIMIZED > 0)
|
self._maximized = (state.new_window_state & Gdk.WindowState.MAXIMIZED > 0)
|
||||||
self._fullscreen((state.new_window_state & Gdk.WindowState.FULLSCREEN > 0))
|
self._fullscreen((state.new_window_state & Gdk.WindowState.FULLSCREEN > 0))
|
||||||
self._settings.set_boolean(Application.SETTING_WINDOW_MAXIMIZED, self._maximized)
|
self._settings.set_boolean(Window.SETTING_WINDOW_MAXIMIZED, self._maximized)
|
||||||
|
|
||||||
|
|
||||||
def on_destroy(self, window):
|
def on_destroy(self, window):
|
||||||
self._settings.set_value(Application.SETTING_WINDOW_SIZE, GLib.Variant('ai', list(self._size)))
|
self._settings.set_value(Window.SETTING_WINDOW_SIZE, GLib.Variant('ai', list(self._size)))
|
||||||
|
|
||||||
|
|
||||||
# HeaderBar callbacks
|
# HeaderBar callbacks
|
||||||
|
|
@ -267,15 +178,15 @@ class Window():
|
||||||
# Panel callbacks
|
# Panel callbacks
|
||||||
|
|
||||||
def on_connection_panel_connection_changed(self, host, port, password, image_dir):
|
def on_connection_panel_connection_changed(self, host, port, password, image_dir):
|
||||||
self._settings.set_string(Application.SETTING_HOST, host)
|
self._settings.set_string(Window.SETTING_HOST, host)
|
||||||
self._settings.set_int(Application.SETTING_PORT, port)
|
self._settings.set_int(Window.SETTING_PORT, port)
|
||||||
if use_keyring:
|
if use_keyring:
|
||||||
if password:
|
if password:
|
||||||
keyring.set_password(Application.KEYRING_SYSTEM, Application.KEYRING_USERNAME, password)
|
keyring.set_password(ZeroconfProvider.KEYRING_SYSTEM, ZeroconfProvider.KEYRING_USERNAME, password)
|
||||||
else:
|
else:
|
||||||
if keyring.get_password(Application.KEYRING_SYSTEM, Application.KEYRING_USERNAME):
|
if keyring.get_password(ZeroconfProvider.KEYRING_SYSTEM, ZeroconfProvider.KEYRING_USERNAME):
|
||||||
keyring.delete_password(Application.KEYRING_SYSTEM, Application.KEYRING_USERNAME)
|
keyring.delete_password(ZeroconfProvider.KEYRING_SYSTEM, ZeroconfProvider.KEYRING_USERNAME)
|
||||||
self._settings.set_string(Application.SETTING_IMAGE_DIR, image_dir)
|
self._settings.set_string(Window.SETTING_IMAGE_DIR, image_dir)
|
||||||
|
|
||||||
|
|
||||||
def on_playlist_panel_clear_playlist(self):
|
def on_playlist_panel_clear_playlist(self):
|
||||||
|
|
@ -290,7 +201,7 @@ class Window():
|
||||||
|
|
||||||
|
|
||||||
def on_cover_panel_tracklist_size_changed(self, size):
|
def on_cover_panel_tracklist_size_changed(self, size):
|
||||||
self._settings.set_string(Application.SETTING_TRACKLIST_SIZE, size)
|
self._settings.set_string(Window.SETTING_TRACKLIST_SIZE, size)
|
||||||
|
|
||||||
|
|
||||||
def on_cover_panel_set_song(self, pos, time):
|
def on_cover_panel_set_song(self, pos, time):
|
||||||
|
|
@ -307,15 +218,15 @@ class Window():
|
||||||
|
|
||||||
def on_library_panel_item_size_changed(self, size):
|
def on_library_panel_item_size_changed(self, size):
|
||||||
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(size)
|
self._panels[Window._PANEL_INDEX_PLAYLIST].set_item_size(size)
|
||||||
self._settings.set_int(Application.SETTING_ITEM_SIZE, self._panels[Window._PANEL_INDEX_LIBRARY].get_item_size())
|
self._settings.set_int(Window.SETTING_ITEM_SIZE, self._panels[Window._PANEL_INDEX_LIBRARY].get_item_size())
|
||||||
|
|
||||||
|
|
||||||
def on_library_panel_sort_order_changed(self, sort_order):
|
def on_library_panel_sort_order_changed(self, sort_order):
|
||||||
self._settings.set_string(Application.SETTING_SORT_ORDER, self._panels[Window._PANEL_INDEX_LIBRARY].get_sort_order())
|
self._settings.set_string(Window.SETTING_SORT_ORDER, self._panels[Window._PANEL_INDEX_LIBRARY].get_sort_order())
|
||||||
|
|
||||||
|
|
||||||
def on_library_panel_sort_type_changed(self, sort_type):
|
def on_library_panel_sort_type_changed(self, sort_type):
|
||||||
self._settings.set_boolean(Application.SETTING_SORT_TYPE, self._panels[Window._PANEL_INDEX_LIBRARY].get_sort_type())
|
self._settings.set_boolean(Window.SETTING_SORT_TYPE, self._panels[Window._PANEL_INDEX_LIBRARY].get_sort_type())
|
||||||
|
|
||||||
|
|
||||||
# MCG callbacks
|
# MCG callbacks
|
||||||
|
|
@ -398,20 +309,20 @@ class Window():
|
||||||
self._header_bar.set_sensitive(False, True)
|
self._header_bar.set_sensitive(False, True)
|
||||||
if self._mcg.is_connected():
|
if self._mcg.is_connected():
|
||||||
self._mcg.disconnect()
|
self._mcg.disconnect()
|
||||||
self._settings.set_boolean(Application.SETTING_CONNECTED, False)
|
self._settings.set_boolean(Window.SETTING_CONNECTED, False)
|
||||||
else:
|
else:
|
||||||
host = connection_panel.get_host()
|
host = connection_panel.get_host()
|
||||||
port = connection_panel.get_port()
|
port = connection_panel.get_port()
|
||||||
password = connection_panel.get_password()
|
password = connection_panel.get_password()
|
||||||
image_dir = connection_panel.get_image_dir()
|
image_dir = connection_panel.get_image_dir()
|
||||||
self._mcg.connect(host, port, password, image_dir)
|
self._mcg.connect(host, port, password, image_dir)
|
||||||
self._settings.set_boolean(Application.SETTING_CONNECTED, True)
|
self._settings.set_boolean(Window.SETTING_CONNECTED, True)
|
||||||
|
|
||||||
|
|
||||||
def _connect_connected(self):
|
def _connect_connected(self):
|
||||||
self._header_bar.connected()
|
self._header_bar.connected()
|
||||||
self._header_bar.set_sensitive(True, False)
|
self._header_bar.set_sensitive(True, False)
|
||||||
self._stack.set_visible_child(self._panels[self._settings.get_int(Application.SETTING_PANEL)].get())
|
self._stack.set_visible_child(self._panels[self._settings.get_int(Window.SETTING_PANEL)].get())
|
||||||
|
|
||||||
|
|
||||||
def _connect_disconnected(self):
|
def _connect_disconnected(self):
|
||||||
|
|
@ -439,7 +350,7 @@ class Window():
|
||||||
panels = [panel.get() for panel in self._panels]
|
panels = [panel.get() for panel in self._panels]
|
||||||
panel_index_selected = panels.index(self._stack.get_visible_child())
|
panel_index_selected = panels.index(self._stack.get_visible_child())
|
||||||
if panel_index_selected > 0:
|
if panel_index_selected > 0:
|
||||||
self._settings.set_int(Application.SETTING_PANEL, panel_index_selected)
|
self._settings.set_int(Window.SETTING_PANEL, panel_index_selected)
|
||||||
|
|
||||||
|
|
||||||
def _set_visible_toolbar(self):
|
def _set_visible_toolbar(self):
|
||||||
|
|
@ -455,7 +366,7 @@ class Window():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HeaderBar(mcg.Base):
|
class HeaderBar(client.Base):
|
||||||
SIGNAL_STACK_SWITCHED = 'stack-switched'
|
SIGNAL_STACK_SWITCHED = 'stack-switched'
|
||||||
SIGNAL_CONNECT = 'on_headerbar-connection_active_notify'
|
SIGNAL_CONNECT = 'on_headerbar-connection_active_notify'
|
||||||
SIGNAL_PLAYPAUSE = 'on_headerbar-playpause_toggled'
|
SIGNAL_PLAYPAUSE = 'on_headerbar-playpause_toggled'
|
||||||
|
|
@ -463,7 +374,7 @@ class HeaderBar(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, builder):
|
def __init__(self, builder):
|
||||||
mcg.Base.__init__(self)
|
client.Base.__init__(self)
|
||||||
|
|
||||||
self._buttons = {}
|
self._buttons = {}
|
||||||
self._changing_volume = False
|
self._changing_volume = False
|
||||||
|
|
@ -625,12 +536,12 @@ class InfoBar():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionPanel(mcg.Base):
|
class ConnectionPanel(client.Base):
|
||||||
SIGNAL_CONNECTION_CHANGED = 'connection-changed'
|
SIGNAL_CONNECTION_CHANGED = 'connection-changed'
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, builder):
|
def __init__(self, builder):
|
||||||
mcg.Base.__init__(self)
|
client.Base.__init__(self)
|
||||||
self._services = Gtk.ListStore(str, str, int)
|
self._services = Gtk.ListStore(str, str, int)
|
||||||
self._profile = None
|
self._profile = None
|
||||||
|
|
||||||
|
|
@ -752,7 +663,7 @@ class ConnectionPanel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CoverPanel(mcg.Base):
|
class CoverPanel(client.Base):
|
||||||
SIGNAL_TOGGLE_FULLSCREEN = 'toggle-fullscreen'
|
SIGNAL_TOGGLE_FULLSCREEN = 'toggle-fullscreen'
|
||||||
SIGNAL_TRACKLIST_SIZE_CHANGED = 'tracklist-size-changed'
|
SIGNAL_TRACKLIST_SIZE_CHANGED = 'tracklist-size-changed'
|
||||||
SIGNAL_SET_SONG = 'set-song'
|
SIGNAL_SET_SONG = 'set-song'
|
||||||
|
|
@ -762,7 +673,7 @@ class CoverPanel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, builder):
|
def __init__(self, builder):
|
||||||
mcg.Base.__init__(self)
|
client.Base.__init__(self)
|
||||||
|
|
||||||
self._current_album = None
|
self._current_album = None
|
||||||
self._cover_pixbuf = None
|
self._cover_pixbuf = None
|
||||||
|
|
@ -937,7 +848,7 @@ class CoverPanel(mcg.Base):
|
||||||
url = album.get_cover()
|
url = album.get_cover()
|
||||||
if url is not None and url is not "":
|
if url is not None and url is not "":
|
||||||
# Load image and draw it
|
# Load image and draw it
|
||||||
self._cover_pixbuf = Application.load_cover(url)
|
self._cover_pixbuf = Utils.load_cover(url)
|
||||||
self._resize_image()
|
self._resize_image()
|
||||||
else:
|
else:
|
||||||
# Reset image
|
# Reset image
|
||||||
|
|
@ -1023,12 +934,12 @@ class CoverPanel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PlaylistPanel(mcg.Base):
|
class PlaylistPanel(client.Base):
|
||||||
SIGNAL_CLEAR_PLAYLIST = 'clear-playlist'
|
SIGNAL_CLEAR_PLAYLIST = 'clear-playlist'
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, builder):
|
def __init__(self, builder):
|
||||||
mcg.Base.__init__(self)
|
client.Base.__init__(self)
|
||||||
self._host = None
|
self._host = None
|
||||||
self._item_size = 150
|
self._item_size = 150
|
||||||
self._playlist = None
|
self._playlist = None
|
||||||
|
|
@ -1148,12 +1059,12 @@ class PlaylistPanel(mcg.Base):
|
||||||
self._playlist_grid_model.clear()
|
self._playlist_grid_model.clear()
|
||||||
GObject.idle_add(self._playlist_grid.set_item_padding, size / 100)
|
GObject.idle_add(self._playlist_grid.set_item_padding, size / 100)
|
||||||
|
|
||||||
cache = mcg.MCGCache(host, size)
|
cache = client.MCGCache(host, size)
|
||||||
for album in playlist:
|
for album in playlist:
|
||||||
pixbuf = None
|
pixbuf = None
|
||||||
if album.get_cover() is not None:
|
if album.get_cover() is not None:
|
||||||
try:
|
try:
|
||||||
pixbuf = Application.load_thumbnail(cache, album, size)
|
pixbuf = Utils.load_thumbnail(cache, album, size)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
if pixbuf is None:
|
if pixbuf is None:
|
||||||
|
|
@ -1191,7 +1102,7 @@ class PlaylistPanel(mcg.Base):
|
||||||
url = album.get_cover()
|
url = album.get_cover()
|
||||||
if url is not None and url is not "":
|
if url is not None and url is not "":
|
||||||
# Load image and draw it
|
# Load image and draw it
|
||||||
self._standalone_pixbuf = Application.load_cover(url)
|
self._standalone_pixbuf = Utils.load_cover(url)
|
||||||
self._resize_standalone_image()
|
self._resize_standalone_image()
|
||||||
else:
|
else:
|
||||||
# Reset image
|
# Reset image
|
||||||
|
|
@ -1234,7 +1145,7 @@ class PlaylistPanel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LibraryPanel(mcg.Base):
|
class LibraryPanel(client.Base):
|
||||||
SIGNAL_UPDATE = 'update'
|
SIGNAL_UPDATE = 'update'
|
||||||
SIGNAL_PLAY = 'play'
|
SIGNAL_PLAY = 'play'
|
||||||
SIGNAL_ITEM_SIZE_CHANGED = 'item-size-changed'
|
SIGNAL_ITEM_SIZE_CHANGED = 'item-size-changed'
|
||||||
|
|
@ -1243,13 +1154,13 @@ class LibraryPanel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, builder):
|
def __init__(self, builder):
|
||||||
mcg.Base.__init__(self)
|
client.Base.__init__(self)
|
||||||
self._buttons = {}
|
self._buttons = {}
|
||||||
self._albums = None
|
self._albums = None
|
||||||
self._host = "localhost"
|
self._host = "localhost"
|
||||||
self._filter_string = ""
|
self._filter_string = ""
|
||||||
self._item_size = 150
|
self._item_size = 150
|
||||||
self._sort_order = mcg.MCGAlbum.SORT_BY_YEAR
|
self._sort_order = client.MCGAlbum.SORT_BY_YEAR
|
||||||
self._sort_type = Gtk.SortType.DESCENDING
|
self._sort_type = Gtk.SortType.DESCENDING
|
||||||
self._grid_pixbufs = {}
|
self._grid_pixbufs = {}
|
||||||
self._old_ranges = {}
|
self._old_ranges = {}
|
||||||
|
|
@ -1277,9 +1188,9 @@ class LibraryPanel(mcg.Base):
|
||||||
# Toolbar menu
|
# Toolbar menu
|
||||||
self._toolbar_search_bar = builder.get_object('library-toolbar-search')
|
self._toolbar_search_bar = builder.get_object('library-toolbar-search')
|
||||||
self._toolbar_sort_buttons = {
|
self._toolbar_sort_buttons = {
|
||||||
mcg.MCGAlbum.SORT_BY_ARTIST: builder.get_object('library-toolbar-sort-artist'),
|
client.MCGAlbum.SORT_BY_ARTIST: builder.get_object('library-toolbar-sort-artist'),
|
||||||
mcg.MCGAlbum.SORT_BY_TITLE: builder.get_object('library-toolbar-sort-title'),
|
client.MCGAlbum.SORT_BY_TITLE: builder.get_object('library-toolbar-sort-title'),
|
||||||
mcg.MCGAlbum.SORT_BY_YEAR: builder.get_object('library-toolbar-sort-year')
|
client.MCGAlbum.SORT_BY_YEAR: builder.get_object('library-toolbar-sort-year')
|
||||||
}
|
}
|
||||||
self._toolbar_sort_order_button = builder.get_object('library-toolbar-sort-order')
|
self._toolbar_sort_order_button = builder.get_object('library-toolbar-sort-order')
|
||||||
self._grid_scale = builder.get_object('library-toolbar-scale')
|
self._grid_scale = builder.get_object('library-toolbar-scale')
|
||||||
|
|
@ -1482,7 +1393,7 @@ class LibraryPanel(mcg.Base):
|
||||||
|
|
||||||
if hash1 == "" or hash2 == "":
|
if hash1 == "" or hash2 == "":
|
||||||
return
|
return
|
||||||
return mcg.MCGAlbum.compare(self._albums[hash1], self._albums[hash2], criterion)
|
return client.MCGAlbum.compare(self._albums[hash1], self._albums[hash2], criterion)
|
||||||
|
|
||||||
|
|
||||||
def stop_threads(self):
|
def stop_threads(self):
|
||||||
|
|
@ -1508,13 +1419,13 @@ class LibraryPanel(mcg.Base):
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
n = len(albums)
|
n = len(albums)
|
||||||
cache = mcg.MCGCache(host, size)
|
cache = client.MCGCache(host, size)
|
||||||
self._grid_pixbufs.clear()
|
self._grid_pixbufs.clear()
|
||||||
for hash in albums.keys():
|
for hash in albums.keys():
|
||||||
album = albums[hash]
|
album = albums[hash]
|
||||||
pixbuf = None
|
pixbuf = None
|
||||||
try:
|
try:
|
||||||
pixbuf = Application.load_thumbnail(cache, album, size)
|
pixbuf = Utils.load_thumbnail(cache, album, size)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
if pixbuf is None:
|
if pixbuf is None:
|
||||||
|
|
@ -1610,7 +1521,7 @@ class LibraryPanel(mcg.Base):
|
||||||
url = album.get_cover()
|
url = album.get_cover()
|
||||||
if url is not None and url is not "":
|
if url is not None and url is not "":
|
||||||
# Load image and draw it
|
# Load image and draw it
|
||||||
self._standalone_pixbuf = Application.load_cover(url)
|
self._standalone_pixbuf = Utils.load_cover(url)
|
||||||
self._resize_standalone_image()
|
self._resize_standalone_image()
|
||||||
else:
|
else:
|
||||||
# Reset image
|
# Reset image
|
||||||
|
|
@ -1648,12 +1559,12 @@ class LibraryPanel(mcg.Base):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class StackSwitcher(mcg.Base):
|
class StackSwitcher(client.Base):
|
||||||
SIGNAL_STACK_SWITCHED = 'stack-switched'
|
SIGNAL_STACK_SWITCHED = 'stack-switched'
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, builder):
|
def __init__(self, builder):
|
||||||
mcg.Base.__init__(self)
|
client.Base.__init__(self)
|
||||||
|
|
||||||
self._temp_button = None
|
self._temp_button = None
|
||||||
self._stack_switcher = builder.get_object('header-panelswitcher')
|
self._stack_switcher = builder.get_object('header-panelswitcher')
|
||||||
|
|
@ -1672,65 +1583,3 @@ class StackSwitcher(mcg.Base):
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return self._stack_switcher
|
return self._stack_switcher
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ZeroconfProvider(mcg.Base):
|
|
||||||
SIGNAL_SERVICE_NEW = 'service-new'
|
|
||||||
TYPE = '_mpd._tcp'
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
mcg.Base.__init__(self)
|
|
||||||
self._service_resolvers = []
|
|
||||||
self._services = {}
|
|
||||||
self._logger = logging.getLogger(__name__)
|
|
||||||
# Client
|
|
||||||
self._client = Avahi.Client(flags=0,)
|
|
||||||
self._logger.info("avahi info")
|
|
||||||
self._logger.warning("avahi warning")
|
|
||||||
self._logger.error("avahi error")
|
|
||||||
try:
|
|
||||||
self._client.start()
|
|
||||||
# Browser
|
|
||||||
self._service_browser = Avahi.ServiceBrowser(domain='local', flags=0, interface=-1, protocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, type=ZeroconfProvider.TYPE)
|
|
||||||
self._service_browser.connect('new_service', self.on_new_service)
|
|
||||||
self._service_browser.attach(self._client)
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.info(e)
|
|
||||||
|
|
||||||
|
|
||||||
def on_new_service(self, browser, interface, protocol, name, type, domain, flags):
|
|
||||||
#if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL):
|
|
||||||
service_resolver = Avahi.ServiceResolver(interface=interface, protocol=protocol, name=name, type=type, domain=domain, aprotocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, flags=0,)
|
|
||||||
service_resolver.connect('found', self.on_found)
|
|
||||||
service_resolver.connect('failure', self.on_failure)
|
|
||||||
service_resolver.attach(self._client)
|
|
||||||
self._service_resolvers.append(service_resolver)
|
|
||||||
|
|
||||||
|
|
||||||
def on_found(self, resolver, interface, protocol, name, type, domain, host, date, port, *args):
|
|
||||||
if (host, port) not in self._services.keys():
|
|
||||||
service = (name,host,port)
|
|
||||||
self._services[(host,port)] = service
|
|
||||||
self._callback(ZeroconfProvider.SIGNAL_SERVICE_NEW, service)
|
|
||||||
|
|
||||||
|
|
||||||
def on_failure(self, resolver, date):
|
|
||||||
if resolver in self._service_resolvers:
|
|
||||||
self._service_resolvers.remove(resolver)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Set environment
|
|
||||||
srcdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
||||||
if not os.environ.get('GSETTINGS_SCHEMA_DIR'):
|
|
||||||
os.environ['GSETTINGS_SCHEMA_DIR'] = os.path.join(srcdir, 'data')
|
|
||||||
|
|
||||||
# Start application
|
|
||||||
app = Application()
|
|
||||||
exit_status = app.run(sys.argv)
|
|
||||||
sys.exit(exit_status)
|
|
||||||
57
mcg/zeroconf.py
Normal file
57
mcg/zeroconf.py
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
import gi
|
||||||
|
gi.require_version('Avahi', '0.6')
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from gi.repository import Avahi
|
||||||
|
|
||||||
|
from mcg import client
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ZeroconfProvider(client.Base):
|
||||||
|
KEYRING_SYSTEM = 'MPDCoverGrid'
|
||||||
|
KEYRING_USERNAME = 'mpd'
|
||||||
|
SIGNAL_SERVICE_NEW = 'service-new'
|
||||||
|
TYPE = '_mpd._tcp'
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
client.Base.__init__(self)
|
||||||
|
self._service_resolvers = []
|
||||||
|
self._services = {}
|
||||||
|
self._logger = logging.getLogger(__name__)
|
||||||
|
# Client
|
||||||
|
self._client = Avahi.Client(flags=0,)
|
||||||
|
try:
|
||||||
|
self._client.start()
|
||||||
|
# Browser
|
||||||
|
self._service_browser = Avahi.ServiceBrowser(domain='local', flags=0, interface=-1, protocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, type=ZeroconfProvider.TYPE)
|
||||||
|
self._service_browser.connect('new_service', self.on_new_service)
|
||||||
|
self._service_browser.attach(self._client)
|
||||||
|
except Exception as e:
|
||||||
|
self._logger.info(e)
|
||||||
|
|
||||||
|
|
||||||
|
def on_new_service(self, browser, interface, protocol, name, type, domain, flags):
|
||||||
|
#if not (flags & Avahi.LookupResultFlags.GA_LOOKUP_RESULT_LOCAL):
|
||||||
|
service_resolver = Avahi.ServiceResolver(interface=interface, protocol=protocol, name=name, type=type, domain=domain, aprotocol=Avahi.Protocol.GA_PROTOCOL_UNSPEC, flags=0,)
|
||||||
|
service_resolver.connect('found', self.on_found)
|
||||||
|
service_resolver.connect('failure', self.on_failure)
|
||||||
|
service_resolver.attach(self._client)
|
||||||
|
self._service_resolvers.append(service_resolver)
|
||||||
|
|
||||||
|
|
||||||
|
def on_found(self, resolver, interface, protocol, name, type, domain, host, date, port, *args):
|
||||||
|
if (host, port) not in self._services.keys():
|
||||||
|
service = (name,host,port)
|
||||||
|
self._services[(host,port)] = service
|
||||||
|
self._callback(ZeroconfProvider.SIGNAL_SERVICE_NEW, service)
|
||||||
|
|
||||||
|
|
||||||
|
def on_failure(self, resolver, date):
|
||||||
|
if resolver in self._service_resolvers:
|
||||||
|
self._service_resolvers.remove(resolver)
|
||||||
8
setup.py
8
setup.py
|
|
@ -8,8 +8,8 @@ from setuptools import setup
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = "MPD Cover Grid",
|
name = "MPDCoverGrid",
|
||||||
version = "0.4",
|
version = "0.6",
|
||||||
description = "MPDCoverGrid is a client for the Music Player Daemon, focused on albums instead of single tracks.",
|
description = "MPDCoverGrid is a client for the Music Player Daemon, focused on albums instead of single tracks.",
|
||||||
url = "http://www.coderkun.de/codes/mcg",
|
url = "http://www.coderkun.de/codes/mcg",
|
||||||
author = "coderkun",
|
author = "coderkun",
|
||||||
|
|
@ -27,12 +27,14 @@ setup(
|
||||||
},
|
},
|
||||||
entry_points = {
|
entry_points = {
|
||||||
"gui_scripts": [
|
"gui_scripts": [
|
||||||
"frontend = mcgGtk:main"
|
"frontend = mcg:main"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
data_files = [
|
data_files = [
|
||||||
"data/MPDCoverGridGTK.desktop",
|
"data/MPDCoverGridGTK.desktop",
|
||||||
"data/gschemas.compiled",
|
"data/gschemas.compiled",
|
||||||
|
"data/gtk.glade",
|
||||||
|
"data/mcg.css",
|
||||||
"data/noise-texture.png"
|
"data/noise-texture.png"
|
||||||
],
|
],
|
||||||
classifiers = [
|
classifiers = [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue