Add AltStore Source Support (#416)

* add altstore source

* rename altstore source
This commit is contained in:
boa
2025-06-24 19:46:22 +08:00
committed by GitHub
parent 85baac657a
commit 838d5c9c3e
3 changed files with 289 additions and 0 deletions

76
.github/workflows/update_alt_store.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: Update AltStore Source
on:
workflow_run:
workflows: ["Build ALL"]
types: [completed]
workflow_dispatch:
jobs:
update-source:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Record job start time
id: job_start_time
run: echo "start_time=$(date +%s)" >> $GITHUB_OUTPUT
- name: Update AltStore source
id: update_source
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python update_alt_store.py
git config --global user.name 'GitHub Action'
git config --global user.email 'action@github.com'
git add alt_store.json
if git diff --staged --quiet; then
echo "changes=false" >> $GITHUB_OUTPUT
else
git commit -m "Updated source with latest release"
git push
echo "changes=true" >> $GITHUB_OUTPUT
fi
- name: Calculate job duration
id: duration
if: always()
run: |
end_time=$(date +%s)
duration=$((end_time - ${{ steps.job_start_time.outputs.start_time }}))
echo "duration=$duration seconds" >> $GITHUB_OUTPUT
- name: Create job summary
run: |
if [[ "${{ steps.update_source.outputs.changes }}" == "true" ]]; then
echo "## Update Altstore Source Summary 🚀" >> $GITHUB_STEP_SUMMARY
echo "✅ Changes Detected and Applied" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The alt_store.json file has been updated with the latest release information." >> $GITHUB_STEP_SUMMARY
else
echo "## Update Altstore Source Summary 🚀" >> $GITHUB_STEP_SUMMARY
echo "🔍 No Changes Detected" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The alt_store.json file is up to date. No changes were necessary." >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "🕐 Execution Time" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "This job took ${{ steps.duration.outputs.duration }} to complete." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "📆 Next Scheduled Run" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The next scheduled run will be tomorrow at midnight UTC." >> $GITHUB_STEP_SUMMARY

63
alt_store.json Normal file
View File

@@ -0,0 +1,63 @@
{
"name": "Venera",
"identifier": "com.github.wgh136.venera.source",
"website": "https://github.com/venera-app/venera",
"subtitle": "Venera official AltStore Source.",
"description": "This is the official AltStore Source for Venera.\n\n A comic reader that supports reading local and network comics",
"tintColor": "#0784FC",
"iconURL": "https://raw.githubusercontent.com/venera-app/venera/master/assets/app_icon.png",
"apps": [
{
"beta": false,
"name": "Venera",
"bundleIdentifier": "com.github.wgh136.venera",
"developerName": "wgh136",
"subtitle": "A comic reader that supports reading local and network comics",
"version": "1.4.5",
"versionDate": "2025-06-18",
"versionDescription": "1. Fixed an abnormal single image height issue when \"imagesPerPage > 1\". 379 \r\n2. Fixed an invalid page calculation issue when \"showSingleImageOnFirstPage\" is enabled. \r\n3. Fixed an issue with incorrect reading history when displaying a single image on the first page. \r\n4. Fixed abnormal history recording when pages are not flipped. 392 \r\n5. Fixed an issue where the download task would stop after exiting the reader. 387 \r\n6. Fixed a \"RangeError\" when translating tags. 356 \r\n7. Reset the current folder to null on the favorites page if the folder is invalid. 389 \r\n8. Fixed various issues when using a custom download path on Android. 400 \r\n9. Set the initial chapter to the first downloaded chapter if no history exists when starting to read a local comic. 405 \r\n10. Removed the config file repository URL from the app.",
"downloadURL": "https://github.com/venera-app/venera/releases/download/v1.4.5/venera-ios-1.4.5%2B145.ipa",
"localizedDescription": "A comic reader that supports reading local and network comics",
"iconURL": "https://raw.githubusercontent.com/venera-app/venera/master/assets/app_icon.png",
"tintColor": "#0784FC",
"category": "utilities",
"size": 14960268,
"appPermissions": {
"entitlements": [
"application-identifier",
"com.apple.security.application-groups",
"get-task-allow",
"keychain-access-groups",
"com.apple.developer.kernel.extended-virtual-addressing",
"com.apple.developer.kernel.increased-memory-limit",
"com.apple.developer.healthkit.background-delivery"
],
"privacy": {
"NSFaceIDUsageDescription": "The guest app is requesting for this permission.",
"NSPhotoLibraryAddUsageDescription": "The guest app is requesting for this permission."
}
},
"versions": [
{
"version": "1.4.5",
"date": "2025-06-18",
"localizedDescription": "1. Fixed an abnormal single image height issue when \"imagesPerPage > 1\". 379 \r\n2. Fixed an invalid page calculation issue when \"showSingleImageOnFirstPage\" is enabled. \r\n3. Fixed an issue with incorrect reading history when displaying a single image on the first page. \r\n4. Fixed abnormal history recording when pages are not flipped. 392 \r\n5. Fixed an issue where the download task would stop after exiting the reader. 387 \r\n6. Fixed a \"RangeError\" when translating tags. 356 \r\n7. Reset the current folder to null on the favorites page if the folder is invalid. 389 \r\n8. Fixed various issues when using a custom download path on Android. 400 \r\n9. Set the initial chapter to the first downloaded chapter if no history exists when starting to read a local comic. 405 \r\n10. Removed the config file repository URL from the app.",
"downloadURL": "https://github.com/venera-app/venera/releases/download/v1.4.5/venera-ios-1.4.5%2B145.ipa",
"size": 14960268
}
]
}
],
"news": [
{
"appID": "com.github.wgh136.venera",
"caption": "Update of Venera just got released!",
"date": "2025-06-18T09:02:01Z",
"identifier": "release-v1.4.5",
"notify": true,
"tintColor": "#0784FC",
"title": "v1.4.5 - Venera 18/06/25",
"url": "https://github.com/venera-app/venera/releases/tag/v1.4.5"
}
]
}

150
update_alt_store.py Normal file
View File

@@ -0,0 +1,150 @@
import json
import plistlib
import re
import requests
import os
from datetime import datetime
def prepare_description(text):
text = re.sub('<[^<]+?>', '', text) # Remove HTML tags
text = re.sub(r'#{1,6}\s?', '', text) # Remove markdown header tags
text = re.sub(r'\*{2}', '', text) # Remove all occurrences of two consecutive asterisks
text = re.sub(r'(?<=\r|\n)-', '', text) # Only replace - with • if it is preceded by \r or \n
text = re.sub(r'`', '"', text) # Replace ` with "
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)
return text
def fetch_latest_release(repo_url):
api_url = f"https://api.github.com/repos/{repo_url}/releases"
headers = {
"Accept": "application/vnd.github+json",
}
try:
response = requests.get(api_url, headers=headers)
response.raise_for_status()
release = response.json()
return release
except requests.RequestException as e:
print(f"Error fetching releases: {e}")
raise
def get_file_size(url):
try:
response = requests.head(url)
response.raise_for_status()
return int(response.headers.get('Content-Length', 0))
except requests.RequestException as e:
print(f"Error getting file size: {e}")
return 194586
def update_json_file_release(json_file, latest_release):
if isinstance(latest_release, list) and latest_release:
latest_release = latest_release[0]
else:
print("Error getting latest release")
return
try:
with open(json_file, "r") as file:
data = json.load(file)
except json.JSONDecodeError as e:
print(f"Error reading JSON file: {e}")
data = {"apps": []}
raise
app = data["apps"][0]
full_version = latest_release["tag_name"]
tag = latest_release["tag_name"]
# Extract version like 1.4.5 from tag, which may be like 'v1.4.5'
version_match = re.search(r"(\d+\.\d+\.\d+)", full_version)
if version_match:
version = version_match.group(1)
else:
print("Error: Could not parse version from tag_name.")
return
version_date = latest_release["published_at"]
date_obj = datetime.strptime(version_date, "%Y-%m-%dT%H:%M:%SZ")
version_date = date_obj.strftime("%Y-%m-%d")
description = latest_release["body"]
description = prepare_description(description)
assets = latest_release.get("assets", [])
download_url = None
size = None
for asset in assets:
# venera-ios-1.4.5+145.ipa
if asset["name"] == f"venera-ios-{version}+{version.replace('.', '')}.ipa":
download_url = asset["browser_download_url"]
size = asset["size"]
break
if download_url is None or size is None:
print("Error: IPA file not found in release assets.")
return
version_entry = {
"version": version,
"date": version_date,
"localizedDescription": description,
"downloadURL": download_url,
"size": size
}
duplicate_entries = [item for item in app["versions"] if item["version"] == version]
if duplicate_entries:
app["versions"].remove(duplicate_entries[0])
app["versions"].insert(0, version_entry)
app.update({
"version": version,
"versionDate": version_date,
"versionDescription": description,
"downloadURL": download_url,
"size": size
})
if "news" not in data:
data["news"] = []
news_identifier = f"release-{full_version}"
date_string = date_obj.strftime("%d/%m/%y")
news_entry = {
"appID": "com.github.wgh136.venera",
"caption": f"Update of Venera just got released!",
"date": latest_release["published_at"],
"identifier": news_identifier,
"notify": True,
"tintColor": "#0784FC",
"title": f"{full_version} - Venera {date_string}",
"url": f"https://github.com/venera-app/venera/releases/tag/{tag}"
}
news_entry_exists = any(item["identifier"] == news_identifier for item in data["news"])
if not news_entry_exists:
data["news"].append(news_entry)
try:
with open(json_file, "w") as file:
json.dump(data, file, indent=2)
print("JSON file updated successfully.")
except IOError as e:
print(f"Error writing to JSON file: {e}")
raise
def main():
repo_url = "venera-app/venera"
is_nightly = "NIGHTLY_LINK" in os.environ
try:
fetched_data_latest = fetch_latest_release(repo_url)
json_file = "alt_store.json"
update_json_file_release(json_file, fetched_data_latest)
except Exception as e:
print(f"An error occurred: {e}")
raise
if __name__ == "__main__":
main()