Compare commits

...

31 Commits

Author SHA1 Message Date
June Park
feb35d2b6e Update stable.yml
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 22:48:48 +09:00
June
3e941cfb0d attempt to fix long standing bug in bundle ids 2024-12-24 22:37:04 +09:00
June Park
931a34cf7d Update stable.yml
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 22:09:21 +09:00
June Park
43dc332329 Update pr.yml
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 22:08:52 +09:00
June Park
c8ae28003f Update nightly.yml
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 21:40:57 +09:00
June Park
cf32f25457 Use xcbeautify for nightlys
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 21:38:45 +09:00
June Park
fee5309b50 Merge pull request #803 from neoarz/patch-1
Update README.md
2024-12-24 21:10:16 +09:00
June Park
b8c7f51d94 Merge pull request #809 from SideStore/junepark678/feat/updatealtsign
Add entitlements and other things
2024-12-24 19:29:39 +09:00
June Park
d00ce2bc11 Update Package.resolved
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 18:08:51 +09:00
June Park
2402655e56 Update Package.resolved
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 18:04:24 +09:00
June Park
283f7a998a Update project.pbxproj
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 18:00:15 +09:00
June Park
2b355dbf8c Update AppManager.swift
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 17:56:40 +09:00
June
ead80e50f9 update altsign 2024-12-24 17:56:40 +09:00
June
71c53d81c2 work harder 2024-12-24 17:56:40 +09:00
June
8498f3df94 update again 2024-12-24 17:56:40 +09:00
June
faa1555294 update altsign again 2024-12-24 17:56:40 +09:00
June Park
110f70e34c cache harder
Signed-off-by: June Park <me@pythonplayer123.dev>
2024-12-24 16:39:59 +09:00
June
cd3b4c46b4 fixes 2024-12-24 15:15:23 +09:00
June
60a0657721 fix roxas 2024-12-24 14:37:41 +09:00
June
62c655c927 fix build 2024-12-24 14:33:50 +09:00
June
84b0f134b0 things 2024-12-24 14:29:50 +09:00
Rose
09902a3f71 Update StoreApp.swift
Signed-off-by: Rose <cool5tarXV@gmail.com>
2024-12-24 14:26:10 +09:00
Rose
3db004c733 added fix + todo
Signed-off-by: Rose <cool5tarXV@gmail.com>
2024-12-24 14:26:10 +09:00
June P
4a566d8823 fix altsign 2024-12-23 01:08:20 +09:00
June P
d37e033d35 Revert "Update AltSign to newer revision"
This reverts commit afca84a852.
2024-12-23 01:07:24 +09:00
June
afca84a852 Update AltSign to newer revision 2024-12-23 00:44:26 +09:00
neoarz
9e0c5dab1a Update README.md
discord link was expired

Signed-off-by: neoarz <164915254+neoarz@users.noreply.github.com>
2024-12-19 22:49:06 -05:00
Magesh K
77eaa2fb5a [dependencies]: updated Package.resolved to use latest commit for altsign 2024-12-12 20:52:09 +05:30
Magesh K
b81ba38d1c [settings]: refined style for last row in REFRESHING APPS section 2024-12-12 20:11:57 +05:30
Magesh K
d5a9050464 [settings]: Fix: siri shortcut missing from settings 2024-12-12 20:11:57 +05:30
Magesh K
3c99fe22d3 [fetch-prebuilt.sh]: force download when libs are missing locally and skip file is absent (#796)
* [fetch-prebuilt.sh] - retain checked-in files from minimuxer repo (assuming minimuxer repo was cloned)

* [fetch-prebuilt.sh]: force download when libs are missing locally and skip file is absent
2024-12-12 00:53:57 -05:00
11 changed files with 115 additions and 44 deletions

View File

@@ -27,6 +27,9 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: brew install ldid run: brew install ldid
- name: Install xcbeautify
run: brew install xcbeautify
- name: Cache .nightly-build-num - name: Cache .nightly-build-num
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
@@ -53,9 +56,12 @@ jobs:
with: with:
key: xcode-cache-deriveddata-${{ github.sha }} key: xcode-cache-deriveddata-${{ github.sha }}
restore-keys: xcode-cache-deriveddata- restore-keys: xcode-cache-deriveddata-
swiftpm-cache-key: xcode-cache-sourcedata-${{ github.sha }}
swiftpm-cache-restore-keys: |
xcode-cache-sourcedata-
- name: Build SideStore - name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]} run: NSUnbufferedIO=YES make build 2>&1 | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}
- name: Fakesign app - name: Fakesign app
run: make fakesign run: make fakesign

View File

@@ -46,7 +46,7 @@ jobs:
restore-keys: xcode-cache-deriveddata- restore-keys: xcode-cache-deriveddata-
- name: Build SideStore - name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]} run: NSUnbufferedIO=YES make build | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}
- name: Fakesign app - name: Fakesign app
run: make fakesign run: make fakesign

View File

@@ -3,6 +3,7 @@ on:
push: push:
tags: tags:
- '[0-9]+.[0-9]+.[0-9]+' # example: 1.0.0 - '[0-9]+.[0-9]+.[0-9]+' # example: 1.0.0
workflow_dispatch:
jobs: jobs:
build: build:
@@ -44,9 +45,12 @@ jobs:
with: with:
key: xcode-cache-deriveddata-${{ github.sha }} key: xcode-cache-deriveddata-${{ github.sha }}
restore-keys: xcode-cache-deriveddata- restore-keys: xcode-cache-deriveddata-
swiftpm-cache-key: xcode-cache-sourcedata-${{ github.sha }}
swiftpm-cache-restore-keys: |
xcode-cache-sourcedata-
- name: Build SideStore - name: Build SideStore
run: make build | xcpretty && exit ${PIPESTATUS[0]} run: NSUnbufferedIO=YES make build | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}
- name: Fakesign app - name: Fakesign app
run: make fakesign run: make fakesign

View File

@@ -7,7 +7,7 @@
"location" : "https://github.com/SideStore/AltSign", "location" : "https://github.com/SideStore/AltSign",
"state" : { "state" : {
"branch" : "master", "branch" : "master",
"revision" : "cc6189f0f7cd8e5bd24943af9322e0ff9420e9f4" "revision" : "4323ff794e600ce1759cb6ea57275e13b7ea72f2"
} }
}, },
{ {

View File

@@ -1141,7 +1141,7 @@ private extension AppManager
} }
} }
private func _install(_ app: AppProtocol, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext? = nil, additionalEntitlements: [ALTEntitlement: Any]? = nil, cacheApp: Bool = true, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> Progress private func _install(_ app: AppProtocol, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext? = nil, additionalEntitlements: [ALTEntitlement: Any] = [.increasedDebuggingMemoryLimit: ALTEntitlement.increasedDebuggingMemoryLimit, .increasedMemoryLimit: ALTEntitlement.increasedMemoryLimit, .extendedVirtualAddressing: ALTEntitlement.extendedVirtualAddressing], cacheApp: Bool = true, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> Progress
{ {
let progress = Progress.discreteProgress(totalUnitCount: 100) let progress = Progress.discreteProgress(totalUnitCount: 100)

View File

@@ -299,6 +299,19 @@ extension FetchProvisioningProfilesOperation
} }
} }
} }
catch ALTAppleAPIError.bundleIdentifierUnavailable {
ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) {res, err in
if let err = err {
return completionHandler(.failure(err))
}
guard let res = res else {return completionHandler(.failure(ALTError(.unknown)))}
for appid in res {
if appid.bundleIdentifier == bundleIdentifier {
completionHandler(.success(appid))
}
}
}
}
catch catch
{ {
completionHandler(.failure(error)) completionHandler(.failure(error))
@@ -363,7 +376,9 @@ extension FetchProvisioningProfilesOperation
} }
} }
if updateFeatures appID.entitlements = entitlements
if updateFeatures || true
{ {
let appID = appID.copy() as! ALTAppID let appID = appID.copy() as! ALTAppID
appID.features = features appID.features = features

View File

@@ -272,6 +272,34 @@
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/> <userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="amC-sE-8O0" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="546" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="amC-sE-8O0" id="GEO-2e-E4k">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Allow Siri To Refresh Apps…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c6K-fI-CVr">
<rect key="frame" x="30" y="15.5" width="228.5" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="c6K-fI-CVr" firstAttribute="centerY" secondItem="GEO-2e-E4k" secondAttribute="centerY" id="IGB-ox-RAM"/>
<constraint firstItem="c6K-fI-CVr" firstAttribute="leading" secondItem="GEO-2e-E4k" secondAttribute="leadingMargin" id="xoI-eB-1TH"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7PQ-AW-GcV" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="7PQ-AW-GcV" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="495" width="375" height="51"/> <rect key="frame" x="0.0" y="495" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
@@ -301,34 +329,6 @@
</tableViewCellContentView> </tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/> <edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="51" id="amC-sE-8O0" customClass="InsetGroupTableViewCell" customModule="SideStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="546" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="amC-sE-8O0" id="GEO-2e-E4k">
<rect key="frame" x="0.0" y="0.0" width="375" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Allow Siri To Refresh Apps…" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c6K-fI-CVr">
<rect key="frame" x="30" y="15.5" width="228.5" height="20.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="c6K-fI-CVr" firstAttribute="centerY" secondItem="GEO-2e-E4k" secondAttribute="centerY" id="IGB-ox-RAM"/>
<constraint firstItem="c6K-fI-CVr" firstAttribute="leading" secondItem="GEO-2e-E4k" secondAttribute="leadingMargin" id="xoI-eB-1TH"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<edgeInsets key="layoutMargins" top="8" left="30" bottom="8" right="30"/>
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="style"> <userDefinedRuntimeAttribute type="number" keyPath="style">
<integer key="value" value="3"/> <integer key="value" value="3"/>

View File

@@ -31,17 +31,18 @@ extension SettingsViewController
fileprivate enum AppRefreshRow: Int, CaseIterable fileprivate enum AppRefreshRow: Int, CaseIterable
{ {
case backgroundRefresh case backgroundRefresh
case noIdleTimeout case noIdleTimeout
case disableAppLimit
@available(iOS 14, *) @available(iOS 14, *)
case addToSiri case addToSiri
case disableAppLimit
static var allCases: [AppRefreshRow] { static var allCases: [AppRefreshRow] {
var c: [AppRefreshRow] = [.backgroundRefresh, .noIdleTimeout] var c: [AppRefreshRow] = [.backgroundRefresh, .noIdleTimeout]
guard #available(iOS 14, *) else { return c } guard #available(iOS 14, *) else { return c }
if !ProcessInfo().sparseRestorePatched { c.append(.disableAppLimit) }
c.append(.addToSiri) c.append(.addToSiri)
// conditional entries go at the last to preserve ordering
if !ProcessInfo().sparseRestorePatched { c.append(.disableAppLimit) }
return c return c
} }
} }
@@ -495,6 +496,13 @@ extension SettingsViewController
} }
} }
if let cell = cell as? InsetGroupTableViewCell,
indexPath.section == Section.appRefresh.rawValue,
indexPath.row == AppRefreshRow.allCases.count-1 // last row
{
cell.setValue(3, forKey: "style")
}
return cell return cell
} }

View File

@@ -240,7 +240,7 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
self.iconURL = try container.decode(URL.self, forKey: .iconURL) self.iconURL = try container.decode(URL.self, forKey: .iconURL)
self.screenshotURLs = try container.decodeIfPresent([URL].self, forKey: .screenshotURLs) ?? [] self.screenshotURLs = try container.decodeIfPresent([URL].self, forKey: .screenshotURLs) ?? []
let downloadURL = try container.decodeIfPresent(URL.self, forKey: .downloadURL) var downloadURL = try container.decodeIfPresent(URL.self, forKey: .downloadURL)
let platformURLs = try container.decodeIfPresent(PlatformURLs.self.self, forKey: .platformURLs) let platformURLs = try container.decodeIfPresent(PlatformURLs.self.self, forKey: .platformURLs)
if let platformURLs = platformURLs { if let platformURLs = platformURLs {
self.platformURLs = platformURLs self.platformURLs = platformURLs
@@ -255,7 +255,22 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
} else if let downloadURL = downloadURL { } else if let downloadURL = downloadURL {
self._downloadURL = downloadURL self._downloadURL = downloadURL
} else { } else {
throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.") let version = try container.decode(String.self, forKey: .version)
if let versions = try container.decodeIfPresent([AppVersion].self, forKey: .versions){
for ver in versions {
if ver.version == version {
self._downloadURL = ver.downloadURL
downloadURL = ver.downloadURL // not sure if this is needed
}
}
throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.")
} else {
throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.")
}
// else {
// throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.")
// }
} }
if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor) if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor)
@@ -275,6 +290,9 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable
if let versions = try container.decodeIfPresent([AppVersion].self, forKey: .versions) if let versions = try container.decodeIfPresent([AppVersion].self, forKey: .versions)
{ {
//TODO: Throw error if there isn't at least one version. //TODO: Throw error if there isn't at least one version.
if (versions.count == 0){
throw DecodingError.dataCorruptedError(forKey: .versions, in: container, debugDescription: "At least one version is required in key: versions")
}
for version in versions for version in versions
{ {

View File

@@ -44,16 +44,36 @@ check_for_update() {
LAST_FETCH=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $1'` LAST_FETCH=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $1'`
LAST_COMMIT=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $2'` LAST_COMMIT=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $2'`
# fetch if last fetch was over 1 hour ago # Check if required library files exist
if [[ $LAST_FETCH -lt $(expr $(date +%s) - 3600) ]] || [[ "$2" == "force" ]]; then FORCE_DOWNLOAD=false
if [ ! -f "$1/lib$1-sim.a" ] || [ ! -f "$1/lib$1-ios.a" ]; then
echo "Required libraries missing for $1, forcing download..."
FORCE_DOWNLOAD=true
fi
# Download if:
# 1. Libraries are missing (FORCE_DOWNLOAD), or
# 2. Last fetch was over 1 hour ago, or
# 3. Force flag was passed
if [ "$FORCE_DOWNLOAD" = true ] || [[ $LAST_FETCH -lt $(expr $(date +%s) - 3600) ]] || [[ "$2" == "force" ]]; then
echo "Checking $1 for update" echo "Checking $1 for update"
echo echo
LATEST_COMMIT=`curl https://api.github.com/repos/SideStore/$1/releases/latest | perl -n -e '/Commit: https:\\/\\/github\\.com\\/[^\\/]*\\/[^\\/]*\\/commit\\/([^"]*)/ && print $1'` LATEST_COMMIT=`curl https://api.github.com/repos/SideStore/$1/releases/latest | perl -n -e '/Commit: https:\\/\\/github\\.com\\/[^\\/]*\\/[^\\/]*\\/commit\\/([^"]*)/ && print $1'`
echo echo
echo "Last commit: $LAST_COMMIT" echo "Last commit: $LAST_COMMIT"
echo "Latest commit: $LATEST_COMMIT" echo "Latest commit: $LATEST_COMMIT"
NOT_UPTODATE=false
if [[ "$LAST_COMMIT" != "$LATEST_COMMIT" ]]; then if [[ "$LAST_COMMIT" != "$LATEST_COMMIT" ]]; then
echo "Found update, downloading binaries" echo "Found update on the remote: https://api.github.com/repos/SideStore/$1/releases/latest"
NOT_UPTODATE=true
fi
# Download if:
# 1. Libraries are missing (FORCE_DOWNLOAD), or
# 2. New commit is available
if [ "$FORCE_DOWNLOAD" = true ] || [ "$NOT_UPTODATE" = true ] ;then
echo "downloading binaries"
echo echo
wget -O "$1/lib$1-sim.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-sim.a" wget -O "$1/lib$1-sim.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-sim.a"
if [[ "$1" != "minimuxer" ]]; then if [[ "$1" != "minimuxer" ]]; then

View File

@@ -6,7 +6,7 @@
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com)
[![Nightly SideStore build](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml) [![Nightly SideStore build](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/nightly.yml)
[![.github/workflows/beta.yml](https://github.com/SideStore/SideStore/actions/workflows/beta.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/beta.yml) [![.github/workflows/beta.yml](https://github.com/SideStore/SideStore/actions/workflows/beta.yml/badge.svg)](https://github.com/SideStore/SideStore/actions/workflows/beta.yml)
[![Discord](https://img.shields.io/discord/949183273383395328?label=Discord)](https://discord.gg/sidestore-949183273383395328) [![Discord](https://img.shields.io/discord/949183273383395328?label=Discord)](https://discord.gg/sidestore)
![Alt](https://repobeats.axiom.co/api/embed/3a329ce95955690b9a9366f8d5598626a847d96c.svg "Repobeats analytics image") ![Alt](https://repobeats.axiom.co/api/embed/3a329ce95955690b9a9366f8d5598626a847d96c.svg "Repobeats analytics image")