new: dev: initialize the GTK client #11
This commit is contained in:
108
gtk-client/mineseeker/assets.py
Normal file
108
gtk-client/mineseeker/assets.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
This file is part of the SplendidBear Websites' projects.
|
||||
|
||||
Copyright (c) 2026 @ www.splendidbear.org
|
||||
|
||||
For the full copyright and license information, please view the LICENSE
|
||||
file that was distributed with this source code.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import logging
|
||||
|
||||
import gi
|
||||
gi.require_version("GdkPixbuf", "2.0")
|
||||
gi.require_version("Gst", "1.0")
|
||||
from gi.repository import GdkPixbuf, Gst
|
||||
|
||||
from mineseeker import config
|
||||
from mineseeker.api import client
|
||||
from mineseeker.constants import IMAGE_NAMES, SOUND_NAMES
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Image cache { filename: GdkPixbuf.Pixbuf }
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_images: dict[str, GdkPixbuf.Pixbuf] = {}
|
||||
|
||||
|
||||
def load_images(cell_size: int = 40) -> None:
|
||||
"""
|
||||
Fetch all game images from the server and cache them as GdkPixbuf.Pixbuf.
|
||||
Call once at startup (blocking; run in a thread if you want a splash screen).
|
||||
"""
|
||||
for name in IMAGE_NAMES:
|
||||
url = f"{config.BASE_URL}/images/{name}"
|
||||
try:
|
||||
resp = client.get_session().get(url, timeout=10)
|
||||
resp.raise_for_status()
|
||||
loader = GdkPixbuf.PixbufLoader()
|
||||
loader.write(resp.content)
|
||||
loader.close()
|
||||
pixbuf = loader.get_pixbuf()
|
||||
# Scale to the cell size used by the grid widget
|
||||
pixbuf = pixbuf.scale_simple(cell_size, cell_size, GdkPixbuf.InterpType.BILINEAR)
|
||||
_images[name] = pixbuf
|
||||
except Exception as exc:
|
||||
log.warning("Could not load image %s: %s", name, exc)
|
||||
|
||||
|
||||
def get_image(name: str) -> GdkPixbuf.Pixbuf | None:
|
||||
"""Return a cached Pixbuf by filename, or None if not loaded."""
|
||||
return _images.get(name)
|
||||
|
||||
|
||||
def get_image_or_fallback(name: str, fallback: str) -> GdkPixbuf.Pixbuf | None:
|
||||
return _images.get(name) or _images.get(fallback)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sound — via GStreamer playbin
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_sounds: dict[str, str] = {} # { key: URI }
|
||||
|
||||
|
||||
def load_sounds() -> None:
|
||||
"""
|
||||
Build the URI map for the six game sound effects.
|
||||
GStreamer will stream them on-demand from the server.
|
||||
"""
|
||||
Gst.init(None)
|
||||
for filename in SOUND_NAMES:
|
||||
key = filename.split(".")[0] # "click", "bomb", etc.
|
||||
_sounds[key] = f"{config.BASE_URL}/sound/{filename}"
|
||||
|
||||
|
||||
def play_sound(key: str) -> None:
|
||||
"""
|
||||
Play a sound by key ("click", "mine", "warning", "bomb", "won", "starting").
|
||||
Each call spawns a fresh GStreamer playbin — fire-and-forget.
|
||||
"""
|
||||
uri = _sounds.get(key)
|
||||
if not uri:
|
||||
return
|
||||
try:
|
||||
player = Gst.ElementFactory.make("playbin", None)
|
||||
if player is None:
|
||||
return
|
||||
player.set_property("uri", uri)
|
||||
player.set_state(Gst.State.PLAYING)
|
||||
|
||||
# Connect to bus to clean up after playback
|
||||
bus = player.get_bus()
|
||||
bus.add_signal_watch()
|
||||
|
||||
def _on_message(bus, msg, player=player):
|
||||
if msg.type in (Gst.MessageType.EOS, Gst.MessageType.ERROR):
|
||||
player.set_state(Gst.State.NULL)
|
||||
bus.remove_signal_watch()
|
||||
return True
|
||||
|
||||
bus.connect("message", _on_message)
|
||||
except Exception as exc:
|
||||
log.debug("Sound play failed (%s): %s", key, exc)
|
||||
Reference in New Issue
Block a user