Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions MediaAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, Adw
from gi.repository import Gtk, Adw, Gio, GLib
import globals as gl

from PIL import Image, ImageEnhance
import os
Expand Down Expand Up @@ -39,13 +40,26 @@ def get_config_rows(self) -> "list[Adw.PreferencesRow]":
self.label_toggle = Adw.SwitchRow(title=self.plugin_base.lm.get("actions.media-action.show-name-switch.label"), subtitle=self.plugin_base.lm.get("actions.media-action.show-name-switch.subtitle"))
self.thumbnail_toggle = Adw.SwitchRow(title=self.plugin_base.lm.get("actions.media-action.show-thumbnail-switch.label"), subtitle=self.plugin_base.lm.get("actions.media-action.show-thumbnail-switch.subtitle"))

self.idle_icon_row = Adw.ActionRow(
title=self.plugin_base.lm.get("actions.media-action.idle-icon.label"),
)
self.choose_idle_icon_button = Gtk.Button.new_from_icon_name("document-open-symbolic")
self.choose_idle_icon_button.set_valign(Gtk.Align.CENTER)
self.idle_icon_row.add_suffix(self.choose_idle_icon_button)

self.clear_idle_icon_button = Gtk.Button.new_from_icon_name("edit-clear-symbolic")
self.clear_idle_icon_button.set_valign(Gtk.Align.CENTER)
self.idle_icon_row.add_suffix(self.clear_idle_icon_button)

self.load_config_defaults()

self.player_selector.connect("notify::selected-item", self.on_change_player)
self.label_toggle.connect("notify::active", self.on_toggle_label)
self.thumbnail_toggle.connect("notify::active", self.on_toggle_thumbnail)
self.choose_idle_icon_button.connect("clicked", self.on_choose_idle_icon_clicked)
self.clear_idle_icon_button.connect("clicked", self.on_clear_idle_icon)

return [self.player_selector, self.label_toggle, self.thumbnail_toggle]
return [self.player_selector, self.label_toggle, self.thumbnail_toggle, self.idle_icon_row]

## Custom methods
def load_config_defaults(self):
Expand All @@ -55,10 +69,12 @@ def load_config_defaults(self):

show_label = settings.setdefault("show_label", True)
show_thumbnail = settings.setdefault("show_thumbnail", True)
idle_icon = settings.setdefault("idle_icon", "")

# Update ui
self.label_toggle.set_active(show_label)
self.thumbnail_toggle.set_active(show_thumbnail)
self.update_idle_icon_ui(idle_icon)
self.update_player_selector()

def update_player_selector(self):
Expand Down Expand Up @@ -143,6 +159,52 @@ def on_toggle_thumbnail(self, switch, *args):
# Update image
self.on_tick()

def update_idle_icon_ui(self, path):
if path and os.path.isfile(path):
filename = os.path.basename(path)
self.idle_icon_row.set_subtitle(filename)
self.clear_idle_icon_button.set_sensitive(True)
else:
default_text = self.plugin_base.lm.get("actions.media-action.idle-icon.default-subtitle")
self.idle_icon_row.set_subtitle("None" if default_text is None else default_text)
self.clear_idle_icon_button.set_sensitive(False)

def on_choose_idle_icon_clicked(self, button):
settings = self.get_settings()
current_val = settings.get("idle_icon", "") if settings else ""

def on_select_callback(path):
if not path:
return
settings = self.get_settings()
if settings is not None:
settings["idle_icon"] = path
self.set_settings(settings)
self.update_idle_icon_ui(path)
self.on_tick()

GLib.idle_add(gl.app.let_user_select_asset, current_val, on_select_callback)

def on_clear_idle_icon(self, button):
settings = self.get_settings()
if settings is not None:
settings["idle_icon"] = ""
self.set_settings(settings)
self.update_idle_icon_ui("")
self.on_tick()

def get_idle_icon(self) -> Image.Image | None:
settings = self.get_settings()
if settings is None:
return None
idle_icon_path = settings.get("idle_icon", "")
if idle_icon_path and os.path.isfile(idle_icon_path):
try:
return Image.open(idle_icon_path)
except Exception as e:
pass
return None

def generate_image(self, icon:Image.Image = None, background:Image.Image=None, valign: float = 0, halign: float = 0, size: float = 1):
if background is None:
background = Image.new("RGBA", (self.deck_controller.deck.key_image_format()["size"]), (0, 0, 0, 0))
Expand Down
6 changes: 5 additions & 1 deletion locales/de_DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,9 @@
"settings.composite-timeout.label": "Composite-Timeout",
"settings.composite-timeout.subtitle": "Verzögerung vor dem Zusammensetzen von Miniaturbildern (ms)",
"settings.log-level.label": "Log-Ebene",
"settings.log-level.subtitle": "Kontrollen Sie die Ausführlichkeit der Plugin-Protokollierung"
"settings.log-level.subtitle": "Kontrollen Sie die Ausführlichkeit der Plugin-Protokollierung",
"actions.media-action.idle-icon.label": "Inaktives Icon",
"actions.media-action.idle-icon.subtitle": "Icon, das angezeigt wird, wenn keine Medien abgespielt werden",
"actions.media-action.idle-icon.dialog-title": "Inaktives Icon auswählen",
"actions.media-action.idle-icon.default-subtitle": "Keines"
}
6 changes: 5 additions & 1 deletion locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@
"settings.composite-timeout.label": "Composite Timeout",
"settings.composite-timeout.subtitle": "Delay before compositing thumbnails (ms)",
"settings.log-level.label": "Log Level",
"settings.log-level.subtitle": "Control the verbosity of plugin logging"
"settings.log-level.subtitle": "Control the verbosity of plugin logging",
"actions.media-action.idle-icon.label": "Idle Icon",
"actions.media-action.idle-icon.subtitle": "Icon to show when no media is playing",
"actions.media-action.idle-icon.dialog-title": "Select Idle Icon",
"actions.media-action.idle-icon.default-subtitle": "None"
}
80 changes: 64 additions & 16 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ def update_image(self):
if status == None:
if self.current_status == None:
self.current_status = "Playing"
idle_image = self.get_idle_icon()
if idle_image is not None:
self.set_media(image=idle_image, size=size, valign=valign)
return
image = Image.open(icon_path)
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(0.6)
Expand Down Expand Up @@ -145,6 +149,10 @@ def update_image(self):
if status == None:
if self.current_status == None:
self.current_status = "Playing"
idle_image = self.get_idle_icon()
if idle_image is not None:
self.set_media(image=idle_image, size=size, valign=valign)
return
image = Image.open(icon_path)
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(0.6)
Expand Down Expand Up @@ -229,6 +237,10 @@ def update_image(self):
if status == None:
if self.current_status == None:
self.current_status = "Playing"
idle_image = self.get_idle_icon()
if idle_image is not None:
self.set_media(image=idle_image, size=size, valign=valign)
return
file_path = file[self.current_status]
image = Image.open(file_path)
enhancer = ImageEnhance.Brightness(image)
Expand Down Expand Up @@ -290,6 +302,10 @@ def update_image(self):

image = Image.open(os.path.join(self.plugin_base.PATH, "assets", "next.png"))
if status == None:
idle_image = self.get_idle_icon()
if idle_image is not None:
self.set_media(image=idle_image, size=size, valign=valign)
return
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(0.6)

Expand Down Expand Up @@ -338,6 +354,10 @@ def update_image(self):

image = Image.open(os.path.join(self.plugin_base.PATH, "assets", "previous.png"))
if status == None:
idle_image = self.get_idle_icon()
if idle_image is not None:
self.set_media(image=idle_image, size=size, valign=valign)
return
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(0.6)

Expand Down Expand Up @@ -366,27 +386,47 @@ def on_tick(self):
self.update_image()

def update_image(self):
status = self.plugin_base.mc.status(self.get_player_name())
if isinstance(status, list):
status = status[0]

if status == None:
self.set_top_label("", font_size=12)
self.set_center_label("", font_size=12)
self.set_bottom_label("", font_size=12)

idle_image = self.get_idle_icon()
if idle_image is not None:
self.set_media(image=idle_image)
else:
self.set_media(image=Image.new("RGBA", (256, 256), (255, 255, 255, 0)))
return

title = self.plugin_base.mc.title(self.get_player_name())
artist = self.plugin_base.mc.artist(self.get_player_name())

if title is not None:
title = self.shorten_label(title[0], 10)
if title is not None:
if artist is not None:
artist = self.shorten_label(artist[0], 10)

if self.get_settings() is None:
return

self.set_top_label(str(title), font_size=12)
self.set_center_label(self.get_settings().get("seperator_text", "--"), font_size=12)
self.set_bottom_label(str(artist), font_size=12)
self.set_top_label(str(title) if title is not None else "", font_size=12)
self.set_center_label(self.get_settings().get("seperator_text", "--") if (title is not None or artist is not None) else "", font_size=12)
self.set_bottom_label(str(artist) if artist is not None else "", font_size=12)

## Thumbnail
thumbnail = None
if self.get_settings().setdefault("show_thumbnail", True):
thumbnail = self.plugin_base.mc.thumbnail(self.get_player_name())
if thumbnail == None:
thumbnail = Image.new("RGBA", (256, 256), (255, 255, 255, 0))
idle_image = self.get_idle_icon()
if idle_image is not None:
thumbnail = idle_image
else:
thumbnail = Image.new("RGBA", (256, 256), (255, 255, 255, 0))
elif isinstance(thumbnail, list):
if thumbnail[0] == None:
return
Expand Down Expand Up @@ -832,6 +872,10 @@ def get_config_rows(self) -> "list[Adw.PreferencesRow]":
self.size_mode_selector.connect("notify::selected", self.on_change_size_mode)

rows.append(self.size_mode_selector) # type: ignore[arg-type]

if hasattr(self, "idle_icon_row") and self.idle_icon_row is not None:
rows.append(self.idle_icon_row)

return rows

def load_size_mode_default(self):
Expand Down Expand Up @@ -905,17 +949,21 @@ def update_image(self):

if thumbnail_path is None:
self.last_thumbnail_path = None
self.restore_original_background()
return

# Load thumbnail image
try:
thumbnail = Image.open(thumbnail_path)
except (OSError, ValueError) as e:
log.error(f"Failed to load thumbnail image from {thumbnail_path}: {e}")
self.last_thumbnail_path = None
self.restore_original_background()
return
idle_image = self.get_idle_icon()
if idle_image is not None:
thumbnail = idle_image
else:
self.restore_original_background()
return
else:
# Load thumbnail image
try:
thumbnail = Image.open(thumbnail_path)
except (OSError, ValueError) as e:
log.error(f"Failed to load thumbnail image from {thumbnail_path}: {e}")
self.last_thumbnail_path = None
self.restore_original_background()
return

# Track thumbnail path, background path, and position
self.last_thumbnail_path = thumbnail_path
Expand Down