Work on importer / SGDB integration

This commit is contained in:
GeoffreyCoulaud
2023-05-18 16:18:31 +02:00
parent ee80c2c552
commit 0c6c0ea467
3 changed files with 83 additions and 48 deletions

View File

@@ -60,7 +60,7 @@ class Game(Gtk.Box):
blacklisted = None
game_cover = None
def __init__(self, data, **kwargs):
def __init__(self, win, data, allow_side_effects=False, **kwargs):
super().__init__(**kwargs)
self.win = shared.win
@@ -69,6 +69,7 @@ class Game(Gtk.Box):
self.update_values(data)
if allow_side_effects:
self.win.games[self.game_id] = self
self.set_play_icon()
@@ -77,7 +78,6 @@ class Game(Gtk.Box):
self.add_controller(self.event_contoller_motion)
self.event_contoller_motion.connect("enter", self.toggle_play, False)
self.event_contoller_motion.connect("leave", self.toggle_play, None, None)
self.cover_button.connect("clicked", self.main_button_clicked, False)
self.play_button.connect("clicked", self.main_button_clicked, True)

View File

@@ -1,12 +1,10 @@
import logging
from pathlib import Path
import requests
from requests import HTTPError
from gi.repository import Adw, Gio, Gtk
from .create_dialog import create_dialog
from .save_cover import resize_cover, save_cover
from .steamgriddb import SGDBAuthError, SGDBHelper
from .steamgriddb import SGDBAuthError, SGDBError, SGDBHelper
class Importer:
@@ -25,11 +23,12 @@ class Importer:
n_sgdb_tasks_created = 0
n_sgdb_tasks_done = 0
sgdb_cancellable = None
sgdb_error = None
errors = None
def __init__(self, win):
self.win = win
self.sources = set()
self.errors = []
@property
def n_tasks_created(self):
@@ -123,10 +122,13 @@ class Importer:
)
continue
# TODO make sources return games AND avoid duplicates
game_id = game.game_id
if game.game_id in self.win.games and not self.win.games[game_id].removed:
# Avoid duplicates
gid = game.game_id
if gid in self.win.games and not self.win.games[gid].removed:
continue
# Register game
self.win.games[gid] = game
game.save()
self.n_games_added += 1
@@ -148,49 +150,16 @@ class Importer:
def sgdb_task_thread_func(self, _task, _obj, data, cancellable):
"""SGDB query code"""
game, *_rest = data
use_sgdb = self.win.schema.get_boolean("sgdb")
if not use_sgdb or game.blacklisted:
return
# Check if we should query SGDB
prefer_sgdb = self.win.schema.get_boolean("sgdb-prefer")
prefer_animated = self.win.schema.get_boolean("sgdb-animated")
image_trunk = self.win.covers_dir / game.game_id
still = image_trunk.with_suffix(".tiff")
animated = image_trunk.with_suffix(".gif")
# Breaking down the condition
is_missing = not still.is_file() and not animated.is_file()
is_not_best = not animated.is_file() and prefer_animated
if not (is_missing or is_not_best or prefer_sgdb):
return
game.set_loading(1)
# SGDB request
sgdb = SGDBHelper(self.win)
try:
sgdb_id = sgdb.get_game_id(game)
uri = sgdb.get_game_image_uri(sgdb_id, animated=prefer_animated)
response = requests.get(uri, timeout=5)
sgdb.conditionaly_update_cover(game)
except SGDBAuthError as error:
# On auth error, cancel all present and future SGDB tasks for this import
self.sgdb_error = error
logging.error("SGDB Auth error occured", exc_info=error)
cancellable.cancel()
return
except Exception as error: # pylint: disable=broad-exception-caught
logging.warning("Non auth error in SGDB query", exc_info=error)
return
# Image saving
tmp_file = Gio.File.new_tmp()[0]
tmp_file_path = tmp_file.get_path()
Path(tmp_file_path).write_bytes(response.content)
save_cover(self.win, game.game_id, resize_cover(self.win, tmp_file_path))
self.errors.append(error)
except (HTTPError, SGDBError) as error:
self.errors.append(error)
def sgdb_task_callback(self, _obj, _result, data):
"""SGDB query callback"""

View File

@@ -1,6 +1,8 @@
from pathlib import Path
import logging
import requests
from requests import HTTPError
from gi.repository import Gio
from . import shared
@@ -24,6 +26,10 @@ class SGDBBadRequestError(SGDBError):
pass
class SGDBNoImageFoundError(SGDBError):
pass
class SGDBHelper:
"""Helper class to make queries to SteamGridDB"""
@@ -69,6 +75,66 @@ class SGDBHelper:
case _:
res.raise_for_status()
def conditionaly_update_cover(self, game):
"""Update the game's cover if appropriate"""
# Obvious skips
use_sgdb = self.win.schema.get_boolean("sgdb")
if not use_sgdb or game.blacklisted:
return
image_trunk = self.win.covers_dir / game.game_id
still = image_trunk.with_suffix(".tiff")
uri_kwargs = image_trunk.with_suffix(".gif")
prefer_sgdb = self.win.schema.get_boolean("sgdb-prefer")
# Do nothing if file present and not prefer SGDB
if not prefer_sgdb and (still.is_file() or uri_kwargs.is_file()):
return
# Get ID for the game
try:
sgdb_id = self.get_game_id(game)
except (HTTPError, SGDBError) as error:
logging.warning(
"Error while getting SGDB ID for %s", game.name, exc_info=error
)
raise error
# Build different SGDB options to try
image_uri_kwargs_sets = [{"animated": False}]
if self.win.schema.get_boolean("sgdb-animated"):
image_uri_kwargs_sets.insert(0, {"animated": True})
# Download covers
for uri_kwargs in image_uri_kwargs_sets:
try:
uri = self.get_game_image_uri(sgdb_id, **uri_kwargs)
response = requests.get(uri, timeout=5)
tmp_file = Gio.File.new_tmp()[0]
tmp_file_path = tmp_file.get_path()
Path(tmp_file_path).write_bytes(response.content)
save_cover(
self.win, game.game_id, resize_cover(self.win, tmp_file_path)
)
except SGDBAuthError as error:
# Let caller handle auth errors
raise error
except (HTTPError, SGDBError) as error:
logging.warning("Error while getting image", exc_info=error)
continue
else:
# Stop as soon as one is finished
return
# No image was added
logging.warning(
'No matching image found for game "%s" (SGDB ID %d)',
game.name,
sgdb_id,
)
raise SGDBNoImageFoundError()
# Current steps to save image for N games
# Create a task for every game