Work on after import dialogs

This commit is contained in:
GeoffreyCoulaud
2023-05-11 00:53:18 +02:00
parent 211c5d670b
commit 2b92417674
2 changed files with 116 additions and 63 deletions

View File

@@ -3,11 +3,11 @@ from pathlib import Path
from threading import Lock, Thread from threading import Lock, Thread
import requests import requests
from requests import HTTPError
from gi.repository import Adw, Gio, Gtk from gi.repository import Adw, Gio, Gtk
from .create_dialog import create_dialog
from .save_cover import resize_cover, save_cover from .save_cover import resize_cover, save_cover
from .steamgriddb import SGDBHelper, SGDBError from .steamgriddb import SGDBAuthError, SGDBHelper
class Importer: class Importer:
@@ -23,6 +23,8 @@ class Importer:
sources = None sources = None
# Internal values # Internal values
sgdb_error = None
sgdb_error_lock = None
source_threads = None source_threads = None
sgdb_threads = None sgdb_threads = None
progress_lock = None progress_lock = None
@@ -40,6 +42,7 @@ class Importer:
self.games_lock = Lock() self.games_lock = Lock()
self.progress_lock = Lock() self.progress_lock = Lock()
self.sgdb_threads_lock = Lock() self.sgdb_threads_lock = Lock()
self.sgdb_error_lock = Lock()
self.win = win self.win = win
@property @property
@@ -74,8 +77,51 @@ class Importer:
) )
self.import_dialog.present() self.import_dialog.present()
def close_dialog(self): def create_sgdb_error_dialog(self):
self.import_dialog.close() create_dialog(
self.win,
_("Couldn't Connect to SteamGridDB"),
str(self.sgdb_error),
"open_preferences",
_("Preferences"),
).connect("response", self.on_dialog_response, "sgdb")
def create_import_done_dialog(self):
games_no = len(self.games)
if games_no == 0:
create_dialog(
self.win,
_("No Games Found"),
_("No new games were found on your system."),
"open_preferences",
_("Preferences"),
).connect("response", self.on_dialog_response)
elif games_no == 1:
create_dialog(
self.win,
_("Game Imported"),
_("Successfully imported 1 game."),
).connect("response", self.on_dialog_response)
elif games_no > 1:
create_dialog(
self.win,
_("Games Imported"),
# The variable is the number of games
_("Successfully imported {} games.").format(games_no),
).connect("response", self.on_dialog_response)
def on_dialog_response(self, _widget, response, *args):
if response == "open_preferences":
page, expander_row, *_rest = args
self.win.get_application().on_preferences_action(
page_name=page, expander_row=expander_row
)
# HACK SGDB manager should be in charge of its error dialog
elif self.sgdb_error is not None:
self.create_sgdb_error_dialog()
self.sgdb_error = None
# TODO additional steam libraries tip
# (should be handled by the source somehow)
def update_progressbar(self): def update_progressbar(self):
self.progressbar.set_fraction(self.progress) self.progressbar.set_fraction(self.progress)
@@ -131,6 +177,7 @@ class ImporterThread(Thread):
thread.join() thread.join()
self.importer.import_dialog.close() self.importer.import_dialog.close()
self.importer.create_import_done_dialog()
class SourceThread(Thread): class SourceThread(Thread):
@@ -177,12 +224,10 @@ class SourceThread(Thread):
# Start sgdb lookup for game in another thread # Start sgdb lookup for game in another thread
# HACK move to a game manager # HACK move to a game manager
use_sgdb = self.win.schema.get_boolean("sgdb") sgdb_thread = SGDBThread(game, self.win, self.importer)
if use_sgdb and not game.blacklisted: with self.importer.sgdb_threads_lock:
sgdb_thread = SGDBThread(game, self.win, self.importer) self.importer.sgdb_threads.append(sgdb_thread)
with self.importer.sgdb_threads_lock: sgdb_thread.start()
self.importer.sgdb_threads.append(sgdb_thread)
sgdb_thread.start()
class SGDBThread(Thread): class SGDBThread(Thread):
@@ -198,8 +243,14 @@ class SGDBThread(Thread):
self.win = win self.win = win
self.importer = importer self.importer = importer
def run(self): def conditionnaly_fetch_cover(self):
"""Thread entry point""" use_sgdb = self.win.schema.get_boolean("sgdb")
if (
not use_sgdb
or self.game.blacklisted
or self.importer.sgdb_error is not None
):
return
# Check if we should query SGDB # Check if we should query SGDB
prefer_sgdb = self.win.schema.get_boolean("sgdb-prefer") prefer_sgdb = self.win.schema.get_boolean("sgdb-prefer")
@@ -216,26 +267,32 @@ class SGDBThread(Thread):
self.game.set_loading(1) self.game.set_loading(1)
# Add image from sgdb # SGDB request
sgdb = SGDBHelper(self.win) sgdb = SGDBHelper(self.win)
try: try:
sgdb_id = sgdb.get_game_id(self.game) sgdb_id = sgdb.get_game_id(self.game)
uri = sgdb.get_game_image_uri(sgdb_id, animated=prefer_animated) uri = sgdb.get_game_image_uri(sgdb_id, animated=prefer_animated)
response = requests.get(uri, timeout=5) response = requests.get(uri, timeout=5)
except HTTPError as _error: except SGDBAuthError as error:
# TODO handle http errors with self.importer.sgdb_error_lock:
pass if self.importer.sgdb_error is None:
except SGDBError as _error: self.importer.sgdb_error = error
# TODO handle SGDB API errors logging.error("SGDB Auth error occured")
pass return
else: except Exception as error: # pylint: disable=broad-exception-caught
tmp_file = Gio.File.new_tmp()[0] logging.warning("Non auth error in SGDB query", exc_info=error)
tmp_file_path = tmp_file.get_path() return
Path(tmp_file_path).write_bytes(response.content)
save_cover( # Image saving
self.win, self.game.game_id, resize_cover(self.win, tmp_file_path) 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, self.game.game_id, resize_cover(self.win, tmp_file_path))
self.game.set_loading(0) self.game.set_loading(0)
def run(self):
"""Thread entry point"""
self.conditionnaly_fetch_cover()
with self.importer.progress_lock: with self.importer.progress_lock:
self.importer.counts[self.game.source.id]["covers"] += 1 self.importer.counts[self.game.source.id]["covers"] += 1

View File

@@ -12,6 +12,18 @@ class SGDBError(Exception):
pass pass
class SGDBAuthError(SGDBError):
pass
class SGDBGameNotFoundError(SGDBError):
pass
class SGDBBadRequestError(SGDBError):
pass
class SGDBHelper: class SGDBHelper:
"""Helper class to make queries to SteamGridDB""" """Helper class to make queries to SteamGridDB"""
@@ -27,51 +39,35 @@ class SGDBHelper:
headers = {"Authorization": f"Bearer {key}"} headers = {"Authorization": f"Bearer {key}"}
return headers return headers
# TODO delegate that to the app
def create_exception_dialog(self, exception):
dialog = create_dialog(
self.win,
_("Couldn't Connect to SteamGridDB"),
exception,
"open_preferences",
_("Preferences"),
)
dialog.connect("response", self.on_exception_dialog_response)
# TODO same as create_exception_dialog
def on_exception_dialog_response(self, _widget, response):
if response == "open_preferences":
self.win.get_application().on_preferences_action(page_name="sgdb")
def get_game_id(self, game): def get_game_id(self, game):
"""Get grid results for a game. Can raise an exception.""" """Get grid results for a game. Can raise an exception."""
uri = f"{self.base_url}search/autocomplete/{game.name}"
# Request res = requests.get(uri, headers=self.auth_headers, timeout=5)
res = requests.get( match res.status_code:
f"{self.base_url}search/autocomplete/{game.name}", case 200:
headers=self.auth_headers, return res.json()["data"][0]["id"]
timeout=5, case 401:
) raise SGDBAuthError(res.json()["errors"][0])
if res.status_code == 200: case 404:
return res.json()["data"][0]["id"] raise SGDBGameNotFoundError(res.status_code)
case _:
# HTTP error res.raise_for_status()
res.raise_for_status()
# SGDB API error
res_json = res.json()
if "error" in tuple(res_json):
raise SGDBError(res_json["errors"])
raise SGDBError(res.status_code)
def get_image_uri(self, game_id, animated=False): def get_image_uri(self, game_id, animated=False):
"""Get the image for a SGDB game id""" """Get the image for a SGDB game id"""
uri = f"{self.base_url}grids/game/{game_id}?dimensions=600x900" uri = f"{self.base_url}grids/game/{game_id}?dimensions=600x900"
if animated: if animated:
uri += "&types=animated" uri += "&types=animated"
grid = requests.get(uri, headers=self.auth_headers, timeout=5) res = requests.get(uri, headers=self.auth_headers, timeout=5)
image_uri = grid.json()["data"][0]["url"] match res.status_code:
return image_uri case 200:
return res.json()["data"][0]["url"]
case 401:
raise SGDBAuthError(res.json()["errors"][0])
case 404:
raise SGDBGameNotFoundError(res.status_code)
case _:
res.raise_for_status()
# Current steps to save image for N games # Current steps to save image for N games