diff --git a/sublime/adapters/manager.py b/sublime/adapters/manager.py index 6ec196a..ec67e70 100644 --- a/sublime/adapters/manager.py +++ b/sublime/adapters/manager.py @@ -51,6 +51,7 @@ from .api_objects import ( ) from .filesystem import FilesystemAdapter from .subsonic import SubsonicAdapter +from ..util import resolve_path REQUEST_DELAY: Optional[Tuple[float, float]] = None if delay_str := os.environ.get("REQUEST_DELAY"): @@ -816,9 +817,7 @@ class AdapterManager: force: bool = False, allow_download: bool = True, ) -> Result[str]: - existing_filename = str( - Path(__file__).parent.joinpath("images/default-album-art.png") - ) + existing_filename = str(resolve_path("adapters/images/default-album-art.png")) if ( not AdapterManager._ground_truth_can_do("get_cover_art_uri") or not cover_art_id diff --git a/sublime/adapters/subsonic/adapter.py b/sublime/adapters/subsonic/adapter.py index b348726..7183053 100644 --- a/sublime/adapters/subsonic/adapter.py +++ b/sublime/adapters/subsonic/adapter.py @@ -27,6 +27,8 @@ import requests import semver from gi.repository import Gtk +from sublime.util import resolve_path + from .api_objects import Directory, Response from .. import ( Adapter, @@ -85,7 +87,7 @@ class SubsonicAdapter(Adapter): name="Subsonic", description="Connect to a Subsonic-compatible server", icon_basename="subsonic", - icon_dir=Path(__file__).parent.joinpath("icons"), + icon_dir=resolve_path("adapters/subsonic/icons"), ) @staticmethod diff --git a/sublime/app.py b/sublime/app.py index 37ec1f8..f3d3f71 100644 --- a/sublime/app.py +++ b/sublime/app.py @@ -48,6 +48,7 @@ from .players import PlayerDeviceEvent, PlayerEvent, PlayerManager from .ui.configure_provider import ConfigureProviderDialog from .ui.main import MainWindow from .ui.state import RepeatType, UIState +from .util import resolve_path class SublimeMusicApp(Gtk.Application): @@ -131,10 +132,7 @@ class SublimeMusicApp(Gtk.Application): if icon_dir := adapter.get_ui_info().icon_dir: default_icon_theme.append_search_path(str(icon_dir)) - icon_dirs = [ - Path(__file__).parent.joinpath("ui", "icons"), - Path(__file__).parent.joinpath("adapters", "icons"), - ] + icon_dirs = [resolve_path("ui/icons"), resolve_path("adapters/icons")] for icon_dir in icon_dirs: default_icon_theme.append_search_path(str(icon_dir)) @@ -145,9 +143,7 @@ class SublimeMusicApp(Gtk.Application): # 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") - ) + css_provider.load_from_path(str(resolve_path("ui/app_styles.css"))) context = Gtk.StyleContext() screen = Gdk.Screen.get_default() context.add_provider_for_screen( diff --git a/sublime/dbus/manager.py b/sublime/dbus/manager.py index faf211f..169a358 100644 --- a/sublime/dbus/manager.py +++ b/sublime/dbus/manager.py @@ -1,6 +1,5 @@ import functools import logging -import os import re from collections import defaultdict from datetime import timedelta @@ -9,10 +8,11 @@ from typing import Any, Callable, DefaultDict, Dict, List, Match, Optional, Tupl from deepdiff import DeepDiff from gi.repository import Gio, GLib -from sublime.adapters import AdapterManager, CacheMissError -from sublime.config import AppConfiguration -from sublime.players import PlayerManager -from sublime.ui.state import RepeatType +from ..adapters import AdapterManager, CacheMissError +from ..config import AppConfiguration +from ..players import PlayerManager +from ..ui.state import RepeatType +from ..util import resolve_path def dbus_propagate(param_self: Any = None) -> Callable: @@ -70,9 +70,7 @@ class DBusManager: "org.mpris.MediaPlayer2.TrackList.xml", ] for spec in specs: - spec_path = os.path.join( - os.path.dirname(__file__), f"mpris_specs/{spec}", - ) + spec_path = resolve_path(f"dbus/mpris_specs/{spec}") with open(spec_path) as f: node_info = Gio.DBusNodeInfo.new_for_xml(f.read()) diff --git a/sublime/ui/player_controls.py b/sublime/ui/player_controls.py index 521516b..4109918 100644 --- a/sublime/ui/player_controls.py +++ b/sublime/ui/player_controls.py @@ -7,12 +7,13 @@ from typing import Any, Callable, Dict, Optional, Set, Tuple from gi.repository import Gdk, GdkPixbuf, GLib, GObject, Gtk, Pango -from sublime.adapters import AdapterManager, Result, SongCacheStatus -from sublime.adapters.api_objects import Song -from sublime.config import AppConfiguration -from sublime.ui import util -from sublime.ui.common import IconButton, IconToggleButton, SpinnerImage -from sublime.ui.state import RepeatType +from . import util +from .common import IconButton, IconToggleButton, SpinnerImage +from .state import RepeatType +from ..adapters import AdapterManager, Result, SongCacheStatus +from ..adapters.api_objects import Song +from ..config import AppConfiguration +from ..util import resolve_path class PlayerControls(Gtk.ActionBar): @@ -759,7 +760,7 @@ class PlayerControls(Gtk.ActionBar): # If this is the playing song, then overlay the play icon. if model.get_value(tree_iter, 3): play_overlay_pixbuf = GdkPixbuf.Pixbuf.new_from_file( - str(Path(__file__).parent.joinpath("images/play-queue-play.png")) + str(resolve_path("ui/images/play-queue-play.png")) ) play_overlay_pixbuf.composite( diff --git a/sublime/util.py b/sublime/util.py new file mode 100644 index 0000000..91f6309 --- /dev/null +++ b/sublime/util.py @@ -0,0 +1,14 @@ +from pathlib import Path +from typing import Union + + +def resolve_path(*joinpath_args: Union[str, Path]) -> Path: + roots = (Path(__file__).parent, Path("/usr/share/sublime-music")) + for root in roots: + if fullpath := root.joinpath(*joinpath_args).resolve(): + return fullpath + + raise FileNotFoundError( + f"{Path(*joinpath_args)} could not be found in any of the following " + "directories: {', '.join(roots)}" + )