Work on after import dialogs
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user