Skip to content

Commit df08025

Browse files
authored
Ctmod: Add dwproton (#599)
As dawn.wine is a custom git site using Forgejo, overwrite fetch_releases & get_tool to prevent using fetch_project_release_data & fetch_project_releases which only support Github & Gitlab. Signed-off-by: hmtheboy154 <[email protected]>
1 parent 14bfe82 commit df08025

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# pupgui2 compatibility tools module
2+
# Dawn Winery's dwproton
3+
# Copyright (C) 2025 DavidoTek, partially based on AUNaseef's protonup
4+
5+
import os
6+
import requests
7+
8+
from PySide6.QtCore import QCoreApplication
9+
10+
from pupgui2.resources.ctmods.ctmod_00protonge import CtInstaller as GEProtonInstaller
11+
from pupgui2.util import extract_tar
12+
13+
CT_NAME = 'dwproton'
14+
CT_LAUNCHERS: list[str] = ['steam', 'lutris', 'heroicproton', 'bottles', 'advmode']
15+
CT_DESCRIPTION: dict[str, str] = {
16+
'en': QCoreApplication.instance().translate('ctmod_dwproton', '''Dawn Winery's custom Proton fork with fixes for various games :xdd:''',)
17+
}
18+
19+
class CtInstaller(GEProtonInstaller):
20+
21+
CT_URL = 'https://dawn.wine/api/v1/repos/dawn-winery/dwproton/releases'
22+
CT_INFO_URL = 'https://dawn.wine/dawn-winery/dwproton/releases/tag/'
23+
24+
def __init__(self, main_window=None):
25+
super().__init__(main_window)
26+
27+
# Reset the session to clear GitHub Auth headers from the base class
28+
self.rs = requests.Session()
29+
self.release_format = 'tar.xz'
30+
31+
def fetch_releases(self, count: int = 100, page: int = 1) -> list[str]:
32+
"""
33+
Manually fetch releases to bypass pupgui2's strict GitHub/GitLab check.
34+
"""
35+
try:
36+
params = {'limit': count, 'page': page}
37+
response = self.rs.get(self.CT_URL, params=params)
38+
response.raise_for_status()
39+
data = response.json()
40+
if isinstance(data, list):
41+
return [r['tag_name'] for r in data if 'tag_name' in r]
42+
return []
43+
except Exception as e:
44+
print(f"[{CT_NAME}] Error fetching releases: {e}")
45+
return []
46+
47+
def _get_dw_data(self, version: str, install_dir: str) -> tuple[dict | None, str | None]:
48+
"""
49+
Replacement for 'fetch_project_release_data'.
50+
Parses Gitea JSON to find the download link and checksum.
51+
"""
52+
try:
53+
# Construct Gitea API URL for specific tag
54+
url = f"{self.CT_URL}/tags/{version}"
55+
resp = self.rs.get(url)
56+
resp.raise_for_status()
57+
data = resp.json()
58+
59+
result = {
60+
'version': data.get('tag_name'),
61+
'download': None,
62+
'checksum': None,
63+
'size': 0
64+
}
65+
66+
# Loop through assets to find the .tar.xz and .sha512sum
67+
for asset in data.get('assets', []):
68+
name = asset.get('name', '')
69+
70+
# Found the main archive
71+
if name.endswith(self.release_format):
72+
result['download'] = asset.get('browser_download_url')
73+
result['size'] = asset.get('size')
74+
75+
# Found the checksum file
76+
elif name.endswith('.sha512sum'):
77+
result['checksum'] = asset.get('browser_download_url')
78+
79+
protondir = os.path.join(install_dir, result['version'])
80+
81+
return (result, protondir)
82+
except Exception as e:
83+
print(f"[{CT_NAME}] Failed to get data for {version}: {e}")
84+
return None
85+
86+
def get_tool(self, version, install_dir, temp_dir):
87+
"""
88+
Download and install the compatibility tool
89+
Return Type: bool
90+
"""
91+
92+
install_dir = self.get_extract_dir(install_dir)
93+
94+
# Get Data using our custom method
95+
data, protondir = self._get_dw_data(version, install_dir)
96+
if not data or not data['download']:
97+
return False
98+
99+
# Note: protondir is only used for checksums
100+
if not protondir or not os.path.exists(protondir):
101+
protondir = os.path.join(install_dir, 'Proton-' + data['version']) # Check if we have an older Proton-GE folder name
102+
103+
checksum_dir = f'{protondir}/sha512sum'
104+
source_checksum = self.rs.get(data['checksum']).text if 'checksum' in data else None
105+
local_checksum = open(checksum_dir).read() if os.path.exists(checksum_dir) else None
106+
107+
if os.path.exists(protondir):
108+
if local_checksum and source_checksum:
109+
if local_checksum in source_checksum:
110+
return False
111+
else:
112+
return False
113+
114+
proton_tar = os.path.join(temp_dir, data['download'].split('/')[-1])
115+
if not self.__download(url=data['download'], destination=proton_tar):
116+
return False
117+
118+
download_checksum = self.__sha512sum(proton_tar)
119+
if source_checksum and (download_checksum not in source_checksum):
120+
return False
121+
122+
if not extract_tar(proton_tar, install_dir, mode=self.release_format.split('.')[-1]):
123+
return False
124+
125+
if os.path.exists(checksum_dir):
126+
open(checksum_dir, 'w').write(download_checksum)
127+
128+
self.__set_download_progress_percent(100)
129+
130+
return True

0 commit comments

Comments
 (0)