Skip to content

Commit 3cb8e78

Browse files
committed
auto update altstore source
1 parent c3869a3 commit 3cb8e78

4 files changed

Lines changed: 255 additions & 3 deletions

File tree

.github/workflows/build.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
steps:
2525
- uses: maxim-lobanov/setup-xcode@v1
2626
with:
27-
xcode-version: "16.4"
27+
xcode-version: "26.1"
2828
- name: Checkout
2929
uses: actions/checkout@v3
3030
with:
@@ -135,6 +135,15 @@ jobs:
135135
uses: actions/download-artifact@v4
136136
with:
137137
name: ${{ needs.package.outputs.artifact }}
138+
- name: Update AltStore source
139+
id: update_source
140+
env:
141+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
142+
NIGHTLY_LINK: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}
143+
commit_sha: ${{ env.COMMIT_SHA }}
144+
commit_msg: ${{ env.COMMIT_MSG }}
145+
run: |
146+
python update_json.py
138147
- name: Nightly Release
139148
uses: andelf/nightly-release@v1
140149
env:

OpenParsec/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
<key>CFBundlePackageType</key>
1616
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>1.0</string>
18+
<string>1.1.0</string>
1919
<key>CFBundleVersion</key>
20-
<string>1</string>
20+
<string>1.1.0</string>
2121
<key>GCSupportedGameControllers</key>
2222
<array>
2323
<dict>

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,21 @@ This project is still a major WIP, so apologies for the currently lackluster doc
66

77
Before building, make sure you have the Parsec SDK framework symlinked or copied to the `Frameworks` folder. Builds were tested on Xcode Version 12.5.
88

9+
## Downloads
10+
<a href="https://celloserenity.github.io/altdirect/?url=https://github.com/OpenParsec/OpenParsec/releases/download/nightly/apps_nightly.json" target="_blank">
11+
<img src="https://github.com/CelloSerenity/altdirect/blob/main/assets/png/AltSource_Blue.png?raw=true" alt="Add AltSource" width="200">
12+
</a>
13+
<a href="https://github.com/OpenParsec/OpenParsec/releases/download/nightly/OpenParsec.ipa" target="_blank">
14+
<img src="https://github.com/CelloSerenity/altdirect/blob/main/assets/png/Download_Blue.png?raw=true" alt="Download .ipa" width="200">
15+
</a>
16+
917
## Touch Control
1018
You can set the touch mode you want to use in settings. Touchpad mode and direct touch mode are supported.
1119

1220
When streaming, you can tap with 3 fingers to bring up the on-screen keyboard.
1321

22+
You can toggle if you want to use 2 fingers to scroll or zoom in the overlay menu.
23+
1424
## Mouse & keyboard
1525
USB mouse & keyboard are supported.
1626

update_json.py

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
import json
2+
import plistlib
3+
import re
4+
import requests
5+
import os
6+
from datetime import datetime
7+
8+
def prepare_description(text):
9+
text = re.sub('<[^<]+?>', '', text) # Remove HTML tags
10+
text = re.sub(r'#{1,6}\s?', '', text) # Remove markdown header tags
11+
text = re.sub(r'\*{2}', '', text) # Remove all occurrences of two consecutive asterisks
12+
text = re.sub(r'(?<=\r|\n)-', '•', text) # Only replace - with • if it is preceded by \r or \n
13+
text = re.sub(r'`', '"', text) # Replace ` with "
14+
text = re.sub(r'\r\n\r\n', '\r \n', text) # Replace \r\n\r\n with \r \n (avoid incorrect display of the description regarding paragraphs)
15+
return text
16+
17+
def fetch_latest_release(repo_url):
18+
api_url = f"https://api.github.com/repos/{repo_url}/releases"
19+
headers = {
20+
"Accept": "application/vnd.github+json",
21+
}
22+
try:
23+
response = requests.get(api_url, headers=headers)
24+
response.raise_for_status()
25+
release = response.json()
26+
return release
27+
except requests.RequestException as e:
28+
print(f"Error fetching releases: {e}")
29+
raise
30+
31+
def get_file_size(url):
32+
try:
33+
response = requests.head(url)
34+
response.raise_for_status()
35+
return int(response.headers.get('Content-Length', 0))
36+
except requests.RequestException as e:
37+
print(f"Error getting file size: {e}")
38+
return 194586
39+
40+
def update_json_file_release(json_file, latest_release):
41+
if isinstance(latest_release, list) and latest_release:
42+
latest_release = latest_release[0]
43+
else:
44+
print("Error getting latest release")
45+
return
46+
47+
try:
48+
with open(json_file, "r") as file:
49+
data = json.load(file)
50+
except json.JSONDecodeError as e:
51+
print(f"Error reading JSON file: {e}")
52+
data = {"apps": []}
53+
raise
54+
55+
app = data["apps"][0]
56+
57+
full_version = latest_release["tag_name"]
58+
tag = latest_release["tag_name"]
59+
version = re.search(r"(\d+\.\d+\.\d+)", full_version).group(1)
60+
version_date = latest_release["published_at"]
61+
date_obj = datetime.strptime(version_date, "%Y-%m-%dT%H:%M:%SZ")
62+
version_date = date_obj.strftime("%Y-%m-%d")
63+
64+
description = latest_release["body"]
65+
description = prepare_description(description)
66+
67+
assets = latest_release.get("assets", [])
68+
download_url = None
69+
size = None
70+
for asset in assets:
71+
if asset["name"] == f"OpenParsec.ipa":
72+
download_url = asset["browser_download_url"]
73+
size = asset["size"]
74+
break
75+
76+
if download_url is None or size is None:
77+
print("Error: IPA file not found in release assets.")
78+
return
79+
80+
version_entry = {
81+
"version": version,
82+
"date": version_date,
83+
"localizedDescription": description,
84+
"downloadURL": download_url,
85+
"size": size
86+
}
87+
88+
duplicate_entries = [item for item in app["versions"] if item["version"] == version]
89+
if duplicate_entries:
90+
app["versions"].remove(duplicate_entries[0])
91+
92+
app["versions"].insert(0, version_entry)
93+
94+
app.update({
95+
"version": version,
96+
"versionDate": version_date,
97+
"versionDescription": description,
98+
"downloadURL": download_url,
99+
"size": size
100+
})
101+
102+
if "news" not in data:
103+
data["news"] = []
104+
105+
news_identifier = f"release-{full_version}"
106+
date_string = date_obj.strftime("%d/%m/%y")
107+
news_entry = {
108+
"appID": "com.aigch.OpenParsec",
109+
"caption": f"Update of OpenParsec just got released!",
110+
"date": latest_release["published_at"],
111+
"identifier": news_identifier,
112+
"imageURL": "https://raw.githubusercontent.com/hugeBlack/OpenParsec/main/screenshots/release.png",
113+
"notify": True,
114+
"tintColor": "#0784FC",
115+
"title": f"{full_version} - OpenParsec {date_string}",
116+
"url": f"https://github.com/hugeBlack/OpenParsec/releases/tag/{tag}"
117+
}
118+
119+
news_entry_exists = any(item["identifier"] == news_identifier for item in data["news"])
120+
if not news_entry_exists:
121+
data["news"].append(news_entry)
122+
123+
try:
124+
with open(json_file, "w") as file:
125+
json.dump(data, file, indent=2)
126+
print("JSON file updated successfully.")
127+
except IOError as e:
128+
print(f"Error writing to JSON file: {e}")
129+
raise
130+
131+
def update_json_file_nightly(json_file, nightly_release):
132+
if isinstance(nightly_release, list) and nightly_release:
133+
nightly_release = next((item for item in nightly_release if item["tag_name"] == "nightly"), None)
134+
else:
135+
print("Error getting nightly release")
136+
return
137+
138+
try:
139+
with open(json_file, "r") as file:
140+
data = json.load(file)
141+
except json.JSONDecodeError as e:
142+
print(f"Error reading JSON file: {e}")
143+
data = {"apps": []}
144+
raise
145+
146+
app = data["apps"][0]
147+
148+
with open("Resources/Info.plist", 'rb') as infile:
149+
info_plist = plistlib.load(infile)
150+
full_version = info_plist["CFBundleVersion"]
151+
tag = nightly_release["tag_name"]
152+
version = re.search(r"(\d+\.\d+\.\d+)", full_version).group(1)
153+
version_date = nightly_release["published_at"]
154+
date_obj = datetime.strptime(version_date, "%Y-%m-%dT%H:%M:%SZ")
155+
version_date = date_obj.strftime("%Y-%m-%d")
156+
157+
nightly_link = os.environ.get("NIGHTLY_LINK", "")
158+
commit_sha = os.environ.get("commit_sha", "")[:7]
159+
commit_msg = os.environ.get("commit_msg", "").strip()
160+
161+
description = f"""\
162+
Nightly build from [{commit_sha}](https://github.com/hugeBlack/OpenParsec/commit/{commit_sha}):\
163+
{commit_msg}
164+
165+
This is a nightly release [created automatically with GitHub Actions workflow]({nightly_link}).
166+
"""
167+
description = prepare_description(description)
168+
169+
assets = nightly_release.get("assets", [])
170+
download_url = None
171+
size = None
172+
for asset in assets:
173+
if asset["name"] == f"OpenParsec.ipa":
174+
download_url = asset["browser_download_url"]
175+
size = asset["size"]
176+
break
177+
178+
if download_url is None or size is None:
179+
print("Error: IPA file not found in release assets.")
180+
return
181+
182+
version_entry = {
183+
"version": version,
184+
"date": version_date,
185+
"localizedDescription": description,
186+
"downloadURL": download_url,
187+
"size": size,
188+
"commit": commit_sha,
189+
"headline": commit_msg
190+
}
191+
192+
app["versions"].clear()
193+
app["versions"].append(version_entry)
194+
195+
app.update({
196+
"version": version,
197+
"versionDate": version_date,
198+
"versionDescription": description,
199+
"downloadURL": download_url,
200+
"size": size,
201+
"commit": commit_sha,
202+
"headline": commit_msg
203+
})
204+
205+
data["news"] = []
206+
207+
try:
208+
with open(json_file, "w") as file:
209+
json.dump(data, file, indent=2)
210+
print("JSON file updated successfully.")
211+
except IOError as e:
212+
print(f"Error writing to JSON file: {e}")
213+
raise
214+
215+
216+
def main():
217+
repo_url = "hugeBlack/OpenParsec"
218+
is_nightly = "NIGHTLY_LINK" in os.environ
219+
220+
try:
221+
fetched_data_latest = fetch_latest_release(repo_url)
222+
if is_nightly:
223+
json_file = "altstore.json"
224+
update_json_file_nightly(json_file, fetched_data_latest)
225+
else:
226+
json_file = "apps.json"
227+
update_json_file_release(json_file, fetched_data_latest)
228+
except Exception as e:
229+
print(f"An error occurred: {e}")
230+
raise
231+
232+
if __name__ == "__main__":
233+
main()

0 commit comments

Comments
 (0)