1
0
Fork 0
mirror of synced 2024-06-26 10:11:19 +12:00

Add protondb grades and option to disable it

This commit is contained in:
Dummerle 2021-05-21 13:09:26 +02:00
parent d50ccc6e55
commit 2e148aebff
8 changed files with 248 additions and 212 deletions

View file

@ -7,9 +7,15 @@ from rare.utils import singleton
def main():
parser = ArgumentParser()
parser.add_argument("-V", "--version", action="store_true")
parser.add_argument("-S", "--silent", action="store_true")
parser.add_argument("--offline", action="store_true")
parser.add_argument("-V", "--version", action="store_true", help="Shows version and exits")
parser.add_argument("-S", "--silent", action="store_true",
help="Launch Rare in background. Open it from System Tray Icon")
parser.add_argument("--offline", action="store_true", help="Launch Rare in offline mode")
if os.name != "nt":
parser.add_argument("--disable-protondb", action="store_true", dest="disable_protondb",
help="Do not download and check data from ProtonDB. Disable it, if you don't need grades")
parser.add_argument("--enable-protondb", action="store_true", dest="enable_protondb",
help="Enable ProtonDB data, after disabled")
subparsers = parser.add_subparsers(title="Commands", dest="subparser")
launch_parser = subparsers.add_parser("launch")

View file

@ -60,6 +60,11 @@ class App(QApplication):
self.setOrganizationName("Rare")
settings = QSettings()
if args.disable_protondb:
settings.setValue("disable_protondb", True)
if args.enable_protondb:
settings.remove("disable_protondb")
# Translator
self.translator = QTranslator()
lang = settings.value("language", get_lang(), type=str)

View file

@ -1,31 +1,69 @@
import json
import os
from logging import getLogger
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QDialog, QLabel, QProgressBar, QVBoxLayout
from PyQt5.QtCore import QThread, pyqtSignal, QSettings
from PyQt5.QtWidgets import QDialog
from requests.exceptions import ConnectionError
from custom_legendary.core import LegendaryCore
from rare.components.dialogs.login import LoginDialog
from rare.utils.utils import download_images, check_grades
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
from rare.utils import steam_grades
from rare.utils.utils import download_images
logger = getLogger("Login")
class LaunchThread(QThread):
class ImageThread(QThread):
download_progess = pyqtSignal(int)
action = pyqtSignal(str)
def __init__(self, core: LegendaryCore, parent=None):
super(LaunchThread, self).__init__(parent)
super(ImageThread, self).__init__(parent)
self.core = core
def run(self):
self.action.emit("Login")
self.action.emit(self.tr("Downloading Images"))
download_images(self.download_progess, self.core)
#self.action.emit(self.tr("Read data from ProtonDB"))
#check_grades(self.core, self.download_progess)
self.action.emit("finish")
self.download_progess.emit(100)
class SteamThread(QThread):
progress = pyqtSignal(int)
action = pyqtSignal(str)
def __init__(self, core: LegendaryCore, parent):
super(SteamThread, self).__init__(parent)
self.core = core
def run(self) -> None:
gamelist = self.core.get_game_list(True)
if not os.path.exists(os.path.expanduser("~/.cache/rare/game_list.json")):
self.action.emit(self.tr("Getting data from ProtonDB"))
steam_grades.upgrade_all([(i.app_title, i.app_name) for i in gamelist], self.progress)
self.progress.emit(99)
self.action.emit(self.tr("Checking Games for data"))
grades = json.load(open(os.path.expanduser("~/.cache/rare/game_list.json")))
ids = json.load(open(os.path.expanduser("~/.cache/rare/steam_ids.json")))
for game in gamelist:
if not grades.get(game.app_name):
steam_id = steam_grades.get_steam_id(game.app_title, ids)
grade = steam_grades.get_grade(steam_id)
grades[game.app_name] = {
"steam_id": steam_id,
"grade": grade
}
if not grades[game.app_name].get("steam_id"):
grades[game.app_name]["steam_id"] = steam_grades.get_steam_id(game.app_title)
if not grades[game.app_name].get("grade"):
grades[game.app_name]["grade"] = steam_grades.get_grade(game.app_title)
with open(os.path.expanduser("~/.cache/rare/game_list.json"), "w") as f:
f.write(json.dumps(grades))
f.close()
self.action.emit("Ready")
self.progress.emit(100)
class LoginThread(QThread):
@ -52,11 +90,17 @@ class LoginThread(QThread):
self.start_app.emit(True)
class LaunchDialog(QDialog):
class LaunchDialog(QDialog, Ui_LaunchDialog):
start_app = pyqtSignal(bool)
finished = False
def __init__(self, core: LegendaryCore, offline):
super(LaunchDialog, self).__init__()
self.setupUi(self)
if os.name == "nt":
self.finished = True
self.steam_info.setVisible(False)
self.steam_prog_bar.setVisible(False)
self.core = core
if not offline:
self.login_thread = LoginThread(core)
@ -64,18 +108,7 @@ class LaunchDialog(QDialog):
self.login_thread.start_app.connect(self.launch)
self.login_thread.start()
self.title = QLabel("<h3>" + self.tr("Launching Rare") + "</h3>")
self.info_pb = QProgressBar()
self.info_text = QLabel(self.tr("Logging in"))
self.layout = QVBoxLayout()
self.layout.addWidget(self.title)
self.layout.addWidget(self.info_pb)
self.layout.addWidget(self.info_text)
self.setLayout(self.layout)
if offline:
else:
self.launch(offline)
def login(self):
@ -88,20 +121,40 @@ class LaunchDialog(QDialog):
def launch(self, offline=False):
# self.core = core
if not os.path.exists(p := os.path.expanduser("~/.cache/rare/images")):
os.makedirs(p)
self.offline = offline
self.info_text.setText(self.tr("Downloading Images"))
self.thread = LaunchThread(self.core, self)
self.thread.download_progess.connect(self.update_pb)
self.thread.action.connect(self.info)
self.thread.start()
def update_pb(self, i: int):
self.info_pb.setValue(i)
if not offline:
def info(self, text: str):
if text == "finish":
self.info_text.setText(self.tr("Starting..."))
self.info_pb.setValue(100)
self.image_info.setText(self.tr("Downloading Images"))
self.img_thread = ImageThread(self.core, self)
self.img_thread.download_progess.connect(self.update_image_progbar)
self.img_thread.finished.connect(self.finish)
self.img_thread.start()
# not disabled and not windows
if (not QSettings().value("disable_protondb", False, bool)) and (not os.name == "nt"):
self.steam_thread = SteamThread(self.core, self)
self.steam_thread.progress.connect(self.update_steam_prog_bar)
self.steam_thread.action.connect(lambda x: self.steam_info.setText(x))
self.steam_thread.finished.connect(self.finish)
self.steam_thread.start()
else:
self.finished = True
self.steam_info.setVisible(False)
self.steam_prog_bar.setVisible(False)
def update_steam_prog_bar(self, value):
self.steam_prog_bar.setValue(value)
def update_image_progbar(self, i: int):
self.image_prog_bar.setValue(i)
def finish(self):
if self.finished:
self.image_info.setText(self.tr("Starting..."))
self.image_prog_bar.setValue(100)
self.steam_prog_bar.setValue(100)
self.start_app.emit(self.offline)
else:
self.info_text.setText(text)
self.finished = True

View file

@ -63,8 +63,6 @@ class GameInfo(QWidget, Ui_GameInfo):
verify_game = pyqtSignal(str)
verify_threads = {}
grade_table = json.load(open(os.path.expanduser("~/.cache/rare/game_list.json")))
def __init__(self, core: LegendaryCore, parent):
super(GameInfo, self).__init__(parent=parent)
self.setupUi(self)
@ -74,7 +72,10 @@ class GameInfo(QWidget, Ui_GameInfo):
"bronze": self.tr("Bronze"),
"fail": self.tr("Could not get grade from ProtonDB"),
"pending": "Not enough reports"}
if os.path.exists(p := os.path.expanduser("~/.cache/rare/game_list.json")):
self.grade_table = json.load(open(p))
else:
self.grade_table = {}
self.widget = QWidget()
self.core = core
if os.name == "nt":
@ -155,7 +156,7 @@ class GameInfo(QWidget, Ui_GameInfo):
self.install_size.setText(get_size(self.igame.install_size))
self.install_path.setText(self.igame.install_path)
if os.name != "nt":
if os.name != "nt" and self.grade_table:
try:
grade = self.ratings.get(self.grade_table[app_name].get("grade"))
except KeyError:

View file

@ -56,7 +56,11 @@ class UninstalledInfo(QWidget):
def __init__(self, core: LegendaryCore, parent):
super(UninstalledInfo, self).__init__(parent=parent)
self.layout = QVBoxLayout()
self.grade_table = json.load(open(os.path.expanduser("~/.cache/rare/game_list.json")))
if os.path.exists(p := os.path.expanduser("~/.cache/rare/game_list.json")):
self.grade_table = json.load(open(p))
else:
self.grade_table = {}
self.ratings = {"platinum": self.tr("Platinum"),
"gold": self.tr("Gold"),
@ -82,9 +86,9 @@ class UninstalledInfo(QWidget):
self.app_name = QLabel("Error")
self.right_layout.addWidget(self.app_name)
self.rating = QLabel("Rating: Error")
self.right_layout.addWidget(self.rating)
if os.name != "nt":
self.rating = QLabel("Rating: Error")
self.right_layout.addWidget(self.rating)
self.install_button = QPushButton(self.tr("Install"))
self.install_button.setFixedWidth(300)
@ -124,11 +128,12 @@ class UninstalledInfo(QWidget):
self.image.setPixmap(pixmap)
self.version.setText(self.game.asset_info.build_version)
try:
rating = self.grade_table[app_name]["grade"]
except KeyError:
rating = "fail"
if rating not in ["fail", "pending"]:
self.rating.setText(self.tr("Rating from ProtonDB: ") + self.ratings[rating])
else:
self.rating.setText(self.ratings[rating])
if self.grade_table and (not os.name == "nt"):
try:
rating = self.grade_table[app_name]["grade"]
except KeyError:
rating = "fail"
if rating not in ["fail", "pending"]:
self.rating.setText(self.tr("Rating from ProtonDB: ") + self.ratings[rating])
else:
self.rating.setText(self.ratings[rating])

View file

@ -1,132 +0,0 @@
import logging
import os
import requests
import json
from datetime import date
replace_chars = ",;.:-_ "
file = os.path.expanduser("~/.cache/rare/game_list.json")
url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"
def get_id(game_name):
global file
if check_time() == 1:
upgrade_content()
text = open(file, 'r')
game_list = json.load(text)
return game_list[game_name.lower()]
def download_ids():
response = requests.get(url)
with open(os.path.expanduser("~/.cache/rare/steam_ids.json"), "w") as f:
f.write(response.text)
f.close()
def upgrade_content(games: list, status_signal): # this function uploads the ids database, aka game_list.json
global url
global file
response = requests.get(url)
with open(os.path.expanduser("~/.cache/rare/steam_ids.json"), "w") as f:
f.write(response.text)
f.close()
content = json.loads(response.text)
game_list = {} # {CrabEA: {id: 1234, grade: platinum}, ..}
steam_games = {}
for i in content["applist"]["apps"]:
name: str = i["name"].lower()
for c in replace_chars:
name = name.replace(c, "")
name = name.encode("ascii", "ignore").decode("ascii", "ignore")
steam_games[name] = i["appid"]
for i in games:
if i.app_title.lower() in steam_games.keys():
game_list[i.app_name] = {}
game_list[i.app_name]["id"] = steam_games[i.app_title.lower()]
continue
else:
app_title = i.app_title.lower()
app_title = app_title.encode("ascii", "ignore").decode("ascii", "ignore")
for c in replace_chars:
app_title = app_title.replace(c, "")
if app_title in steam_games.keys():
game_list[i.app_name] = {}
game_list[i.app_name]["id"] = steam_games[app_title]
else:
for game in steam_games:
if app_title.startswith(game):
game_list[i.app_name] = {}
game_list[i.app_name]["id"] = steam_games[game]
for i, game in enumerate(game_list):
try:
grade = get_grade(game_list[game]["id"])
except json.decoder.JSONDecodeError as e:
logging.error(str(e))
game_list[game]["grade"] = "fail"
print(game) # debug
else:
game_list[game]["grade"] = grade
status_signal.emit(50 + i/len(game_list)*50)
# print(game_list)
# for game in content['applist']['apps']:
# game_list[game['name'].lower()] = game['appid']
# uploding date on json
today = date.today()
game_list['data'] = {}
for i in "ymd":
game_list["data"][i] = today.strftime('%' + i)
table = open(file, 'w')
json.dump(game_list, table)
table.close()
def check_time(): # this function check if it's time to update
global file
text = open(file, 'r')
json_table = json.load(text)
text.close()
today = date.today()
day = 0 # it controls how many days it's necessary for an update
for i in 'ymd':
if i == 'd':
day = 7
else:
day = 0
if int(today.strftime('%' + i)) > int(json_table['data'][i]) + day:
return 1
else:
return 0
# you should iniciate the module with the game's steam code
def get_grade(steam_code):
steam_code = str(steam_code)
url = 'https://www.protondb.com/api/v1/reports/summaries/'
res = requests.get(url + steam_code + '.json')
text = res.text
lista = json.loads(text)
# print(lista['tier']) # just for debug pourpouses!!!
return lista['tier']
def id(game_name):
return get_grade(get_id(game_name))

116
rare/utils/steam_grades.py Normal file
View file

@ -0,0 +1,116 @@
import difflib
import json
import os
from datetime import date
import requests
from PyQt5.QtCore import pyqtSignal
replace_chars = ",;.:-_ "
file = os.path.expanduser("~/.cache/rare/game_list.json")
url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"
# you should iniciate the module with the game's steam code
def get_grade(steam_code):
if steam_code == 0:
return "fail"
steam_code = str(steam_code)
url = 'https://www.protondb.com/api/v1/reports/summaries/'
res = requests.get(url + steam_code + '.json')
try:
lista = json.loads(res.text)
except json.decoder.JSONDecodeError:
return "fail"
return lista['tier']
def load_json() -> dict:
if not os.path.exists(p := os.path.expanduser("~/.cache/rare/steam_ids.json")):
response = requests.get(url)
steam_ids = json.loads(response.text)["applist"]["apps"]
ids = {}
for game in steam_ids:
ids[game["name"]] = game["appid"]
with open(os.path.expanduser(p), "w") as f:
f.write(json.dumps(ids))
f.close()
return ids
else:
return json.loads(open(os.path.expanduser("~/.cache/rare/steam_ids.json"), "r").read())
def upgrade_all(games, progress: pyqtSignal = None):
ids = load_json()
data = {}
for i, (title, app_name) in enumerate(games):
title = title.replace("Early Access", "").replace("Experimental", "").strip()
data[app_name] = {}
steam_id = get_steam_id(title, ids)
data[app_name] = {
"steam_id": steam_id,
"grade": get_grade(steam_id)}
if progress:
progress.emit(int(i / len(games) * 100))
with open(os.path.expanduser("~/.cache/rare/game_list.json"), "w") as f:
f.write(json.dumps(data))
f.close()
def get_steam_id(title: str, json_data=None):
title = title.replace("Early Access", "").replace("Experimental", "").strip()
if not json_data:
if not os.path.exists(p := os.path.expanduser("~/.cache/rare/steam_ids.json")):
response = requests.get(url)
ids = {}
steam_ids = json.loads(response.text)["applist"]["apps"]
for game in steam_ids:
ids[game["name"]] = game["appid"]
with open(os.path.expanduser(p), "w") as f:
f.write(json.dumps(steam_ids))
f.close()
else:
ids = json.loads(open(os.path.expanduser("~/.cache/rare/steam_ids.json"), "r").read())
else:
ids = json_data
steam_name = difflib.get_close_matches(title, ids.keys(), n=1)
if steam_name:
return ids[steam_name[0]]
else:
return 0
# print(x)
# for game in steam_ids:
# num = difflib.SequenceMatcher(None, game["name"], title).ratio()
# if num > most_similar[2] and num > 0.5:
# most_similar = (game["appid"], game["name"], num)
# print(time.time()-t)
# name = difflib.get_close_matches(steam_ids.keys(), title)
# return most_similar
def check_time(): # this function check if it's time to update
global file
text = open(file, 'r')
json_table = json.load(text)
text.close()
today = date.today()
day = 0 # it controls how many days it's necessary for an update
for i in 'ymd':
if i == 'd':
day = 7
else:
day = 0
if int(today.strftime('%' + i)) > int(json_table['data'][i]) + day:
return 1
else:
return 0

View file

@ -8,15 +8,12 @@ import requests
from PIL import Image, UnidentifiedImageError
from PyQt5.QtCore import pyqtSignal, QLocale, QSettings
from PyQt5.QtGui import QPalette, QColor
from rare import style_path
from rare.utils.id import upgrade_content, check_time, download_ids
# Windows
if os.name == "nt":
from win32com.client import Dispatch
from rare import lang_path, __version__, style_path
from rare import lang_path, style_path
from custom_legendary.core import LegendaryCore
logger = getLogger("Utils")
@ -42,22 +39,7 @@ def download_images(signal: pyqtSignal, core: LegendaryCore):
except json.decoder.JSONDecodeError:
shutil.rmtree(f"{IMAGE_DIR}/{game.app_name}")
download_image(game)
signal.emit(i/len(game_list)*50)
def check_grades(core: LegendaryCore, signal):
games = core.get_game_list(True)
# upgrade_content(games, signal)
if not os.path.exists("~/.cache/rare/steam_ids.json"):
download_ids()
game_table = json.loads(open(os.path.expanduser("~/.cache/rare/game_list.json")).read())
for game in games:
if game.app_name not in game_table.keys():
# TODO: Find id from method; Not upgrade all
game_table[game.app_name] = {"grade": "pending", "id": "1234"}
json.dump(game_table, open(os.path.expanduser("~/.cache/rare/game_list.json"), "w"))
signal.emit(i / len(game_list) * 100)
def download_image(game, force=False):
@ -88,7 +70,7 @@ def download_image(game, force=False):
f.write(requests.get(url).content)
try:
img = Image.open(f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png")
img = img.resize((200, int(200*4/3)))
img = img.resize((200, int(200 * 4 / 3)))
img.save(f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png")
except UnidentifiedImageError as e:
logger.warning(e)
@ -103,7 +85,7 @@ def download_image(game, force=False):
bg = Image.open(f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxTall.png")
uninstalledArt = bg.convert('L')
uninstalledArt = uninstalledArt.resize((200, int(200*4/3)))
uninstalledArt = uninstalledArt.resize((200, int(200 * 4 / 3)))
uninstalledArt.save(f'{IMAGE_DIR}/{game.app_name}/UninstalledArt.png')
elif os.path.isfile(f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png"):
bg: Image.Image = Image.open(f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png")
@ -292,9 +274,9 @@ def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop"):
shortcut.WorkingDirectory = os.getcwd()
# Icon
if not os.path.exists(icon+".ico"):
img = Image.open(icon+".png")
img.save(icon+".ico")
if not os.path.exists(icon + ".ico"):
img = Image.open(icon + ".png")
img.save(icon + ".ico")
logger.info("Create Icon")
shortcut.IconLocation = os.path.join(icon + ".ico")
shortcut.save()