1
0
mirror of https://github.com/lutris/lutris synced 2024-07-01 06:34:26 +00:00

Compare commits

...

6 Commits

Author SHA1 Message Date
tobil4sk
66ea0082a8
Merge efc446d139 into 5ac77b3fee 2024-06-27 21:19:25 +10:00
Daniel Johnson
5ac77b3fee Also enable multiple auto-generated installers for Itch.IO, just like GOG! 2024-06-26 20:07:25 -04:00
Daniel Johnson
9cd311e9da Enable GOG service to offer more than once auto-generated installer, when GOG has multiple platforms we support.
This way the user can select between Linux or Wine builds of a game.

Resolve #5391
2024-06-26 19:47:14 -04:00
Daniel Johnson
1c1a79c660 Also filter DLCs according to the runner and OS 2024-06-26 17:19:51 -04:00
Tobiasz Laskowski
efc446d139
Add fullscreen, force align, no gui ruffle options 2024-05-23 21:39:16 +01:00
Tobiasz Laskowski
703b4ffde0
Update ruffle version 2024-05-23 21:21:21 +01:00
4 changed files with 120 additions and 29 deletions

View File

@ -4,7 +4,7 @@ import os
import shutil
from gettext import gettext as _
from pathlib import Path
from typing import List
from typing import Any, Dict, List
from gi.repository import Gio
@ -179,10 +179,17 @@ class BaseService:
def get_update_installers(self, db_game):
return []
def generate_installer(self, db_game):
def generate_installer(self, db_game: Dict[str, Any]) -> Dict[str, Any]:
"""Used to generate an installer from the data returned from the services"""
return {}
def generate_installers(self, db_game: Dict[str, Any]) -> List[dict]:
"""Used to generate a list of installers to choose from, from the data returned from the services
By default this is just the installer from generate_installer(), and if overridden to return
more than one, then generate_installer must be overridden ti pick a default installer."""
installer = self.generate_installer(db_game)
return [installer] if installer else []
def install_from_api(self, db_game, appid=None):
"""Install a game, using the API or generate_installer() to obtain the installer."""
if not appid:
@ -193,7 +200,7 @@ class BaseService:
raise error # bounce any error off the backstop
if not service_installers:
service_installers = [self.generate_installer(db_game)]
service_installers = self.generate_installers(db_game)
application = Gio.Application.get_default()
application.show_installer_window(service_installers, service=self, appid=appid)
@ -298,11 +305,12 @@ class BaseService:
if existing_game:
logger.debug("Found existing game, aborting install")
return None, None, existing_game
installer = self.generate_installer(db_game) if not update else None
if installer:
installers = self.generate_installers(db_game) if not update else []
if installers:
if service_installers:
installer["version"] = installer["version"] + " (auto-generated)"
service_installers.append(installer)
for installer in installers:
installer["version"] = installer["version"] + " (auto-generated)"
service_installers.extend(installers)
if not service_installers:
logger.error("No installer found for %s", db_game)
return

View File

@ -5,7 +5,7 @@ import os
import time
from collections import defaultdict
from gettext import gettext as _
from typing import List, Optional
from typing import Any, Dict, List, Optional
from urllib.parse import parse_qsl, urlencode, urlparse
from lxml import etree
@ -15,6 +15,7 @@ from lutris.exceptions import AuthenticationError, UnavailableGameError
from lutris.installer import AUTO_ELF_EXE, AUTO_WIN32_EXE
from lutris.installer.installer_file import InstallerFile
from lutris.installer.installer_file_collection import InstallerFileCollection
from lutris.runners import get_runner_human_name
from lutris.services.base import SERVICE_LOGIN, OnlineService
from lutris.services.service_game import ServiceGame
from lutris.services.service_media import ServiceMedia
@ -90,6 +91,8 @@ class GOGService(OnlineService):
token_path = os.path.join(settings.CACHE_DIR, ".gog.token")
cache_path = os.path.join(settings.CACHE_DIR, "gog-library.json")
runner_to_os_dict = {"wine": "windows", "linux": "linux"}
def __init__(self):
super().__init__()
@ -349,11 +352,10 @@ class GOGService(OnlineService):
"""Return available installers for a GOG game"""
# Filter out Mac installers
gog_installers = [installer for installer in downloads.get("installers", []) if installer["os"] != "mac"]
available_platforms = {installer["os"] for installer in gog_installers}
filter_os = self.runner_to_os_dict.get(runner)
# If it's a Linux game, also filter out Windows games
if "linux" in available_platforms:
filter_os = "windows" if runner == "linux" else "linux"
gog_installers = [installer for installer in gog_installers if installer["os"] != filter_os]
if filter_os:
gog_installers = [installer for installer in gog_installers if installer["os"] == filter_os]
return [
installer
for installer in gog_installers
@ -363,9 +365,7 @@ class GOGService(OnlineService):
def get_update_versions(self, gog_id: str, runner_name: Optional[str]):
"""Return updates available for a game, keyed by patch version"""
runner_to_os_dict = {"wine": "windows", "linux": "linux"}
filter_os = runner_to_os_dict.get(runner_name) if runner_name else None
filter_os = self.runner_to_os_dict.get(runner_name) if runner_name else None
games_detail = self.get_game_details(gog_id)
patches = games_detail["downloads"]["patches"]
@ -541,21 +541,46 @@ class GOGService(OnlineService):
with open(file_path, encoding="utf-8") as checksum_file:
checksum_content = checksum_file.read()
root_elem = etree.fromstring(checksum_content)
return (root_elem.attrib["name"], root_elem.attrib["md5"])
return root_elem.attrib["name"], root_elem.attrib["md5"]
def generate_installer(self, db_game):
def generate_installer(self, db_game: Dict[str, Any]) -> Dict[str, Any]:
details = json.loads(db_game["details"])
platforms = [platform.lower() for platform, is_supported in details["worksOn"].items() if is_supported]
system_config = {}
slug = details["slug"]
platforms = [platform.casefold() for platform, is_supported in details["worksOn"].items() if is_supported]
if "linux" in platforms:
runner = "linux"
return self._generate_installer(slug, "linux", db_game)
else:
return self._generate_installer(slug, "wine", db_game)
def generate_installers(self, db_game: Dict[str, Any]) -> List[dict]:
details = json.loads(db_game["details"])
slug = details["slug"]
platforms = [platform.casefold() for platform, is_supported in details["worksOn"].items() if is_supported]
installers = []
if "linux" in platforms:
installers.append(self._generate_installer(slug, "linux", db_game))
if "windows" in platforms:
installers.append(self._generate_installer(slug, "wine", db_game))
if len(installers) > 1:
for installer in installers:
runner_human_name = get_runner_human_name(installer["runner"])
installer["version"] += " " + (runner_human_name or installer["runner"])
return installers
def _generate_installer(self, slug: str, runner: str, db_game: Dict[str, Any]) -> Dict[str, Any]:
system_config = {}
if runner == "linux":
game_config = {"exe": AUTO_ELF_EXE}
script = [
{"extract": {"file": "goginstaller", "format": "zip", "dst": "$CACHE"}},
{"merge": {"src": "$CACHE/data/noarch", "dst": "$GAMEDIR"}},
]
else:
runner = "wine"
game_config = {"exe": AUTO_WIN32_EXE}
script = [
{"autosetup_gog_game": "goginstaller"},
@ -563,7 +588,7 @@ class GOGService(OnlineService):
return {
"name": db_game["name"],
"version": "GOG",
"slug": details["slug"],
"slug": slug,
"game_slug": self.get_installed_slug(db_game),
"runner": runner,
"gogid": db_game["appid"],
@ -587,6 +612,9 @@ class GOGService(OnlineService):
def get_dlc_installers(self, db_game):
"""Return all available DLC installers for game"""
appid = db_game["service_id"]
runner_name = db_game.get("runner")
filter_os = self.runner_to_os_dict.get(runner_name) if runner_name else None
dlcs = self.get_game_dlcs(appid)
@ -601,8 +629,13 @@ class GOGService(OnlineService):
]
for file in installfiles:
file_os = file["os"].casefold()
if filter_os and file_os and filter_os != file_os:
continue
# supports linux
if file["os"].casefold() == "linux":
if file_os == "linux":
runner = "linux"
script = [
{"extract": {"dst": "$CACHE/GOG", "file": dlc_id, "format": "zip"}},

View File

@ -12,6 +12,7 @@ from lutris.database import games as games_db
from lutris.exceptions import UnavailableGameError
from lutris.installer import AUTO_ELF_EXE, AUTO_WIN32_EXE
from lutris.installer.installer_file import InstallerFile
from lutris.runners import get_runner_human_name
from lutris.services.base import SERVICE_LOGIN, OnlineService
from lutris.services.service_game import ServiceGame
from lutris.services.service_media import ServiceMedia
@ -340,23 +341,49 @@ class ItchIoService(OnlineService):
def get_installed_slug(self, db_game):
return db_game["slug"]
def generate_installer(self, db_game):
def generate_installer(self, db_game: Dict[str, Any]) -> Dict[str, Any]:
"""Auto generate installer for itch.io game"""
details = json.loads(db_game["details"])
if "p_linux" in details["traits"]:
runner = "linux"
return self._generate_installer("linux", db_game)
elif "p_windows" in details["traits"]:
return self._generate_installer("wine", db_game)
logger.warning("No supported platforms found")
return {}
def generate_installers(self, db_game: Dict[str, Any]) -> List[dict]:
"""Auto generate installer for itch.io game"""
details = json.loads(db_game["details"])
installers = []
if "p_linux" in details["traits"]:
installers.append(self._generate_installer("linux", db_game))
if "p_windows" in details["traits"]:
installers.append(self._generate_installer("wine", db_game))
if len(installers) > 1:
for installer in installers:
runner_human_name = get_runner_human_name(installer["runner"])
installer["version"] += " " + (runner_human_name or installer["runner"])
return installers
def _generate_installer(self, runner, db_game: Dict[str, Any]) -> Dict[str, Any]:
if runner == "linux":
game_config = {"exe": AUTO_ELF_EXE}
script = [
{"extract": {"file": "itchupload", "dst": "$CACHE"}},
{"merge": {"src": "$CACHE", "dst": "$GAMEDIR"}},
]
elif "p_windows" in details["traits"]:
runner = "wine"
elif runner == "wine":
game_config = {"exe": AUTO_WIN32_EXE}
script = [{"task": {"name": "create_prefix"}}, {"install_or_extract": "itchupload"}]
else:
logger.warning("No supported platforms found")
logger.warning(f"'{runner}' is not a supported runner for itchio")
return {}
return {

View File

@ -3,7 +3,7 @@
"description": "Emulates Flash games",
"platforms": ["Flash"],
"runner_executable": "ruffle/ruffle",
"download_url": "https://github.com/ruffle-rs/ruffle/releases/download/nightly-2023-10-14/ruffle-nightly-2023_10_14-linux-x86_64.tar.gz",
"download_url": "https://github.com/ruffle-rs/ruffle/releases/download/nightly-2024-05-22/ruffle-nightly-2024_05_22-linux-x86_64.tar.gz",
"game_options": [
{
"option": "main_file",
@ -13,6 +13,20 @@
}
],
"runner_options": [
{
"option": "fullscreen",
"type": "bool",
"default": true,
"label": "Fullscreen",
"argument": "--fullscreen"
},
{
"option": "force_align",
"type": "bool",
"label": "Force align",
"argument": "--force-align",
"help": "Prevent movies from changing the stage alignment"
},
{
"option": "graphics",
"type": "choice",
@ -43,6 +57,15 @@
"type": "string",
"label": "Proxy",
"argument": "--proxy"
},
{
"option": "no_gui",
"type": "bool",
"default": true,
"label": "No GUI",
"advanced": true,
"argument": "--no-gui",
"help": "Hides the menu bar (the bar at the top of the window)"
}
]
}