github update notice
Some checks are pending
Build and Release IPA / Build IPA and Mac Catalyst (push) Waiting to run

This commit is contained in:
cranci1 2024-12-29 11:05:03 +01:00
parent 6cd4df40b9
commit 0891e7a2c6
5 changed files with 220 additions and 6 deletions

View file

@ -40,6 +40,7 @@
132417D92D1328B900B4F2D2 /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417D82D1328B900B4F2D2 /* VideoPlayerView.swift */; };
1352BA712D1ABC30000A9AF9 /* URLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1352BA702D1ABC30000A9AF9 /* URLSession.swift */; };
13B3A4B22D1477F100BCC0D5 /* StorageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13B3A4B12D1477F100BCC0D5 /* StorageSettingsView.swift */; };
13C9821F2D2152B1007A0132 /* GitHubRelease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C9821E2D2152B1007A0132 /* GitHubRelease.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -77,6 +78,7 @@
1352BA6F2D1AB113000A9AF9 /* Sora.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Sora.entitlements; sourceTree = "<group>"; };
1352BA702D1ABC30000A9AF9 /* URLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSession.swift; sourceTree = "<group>"; };
13B3A4B12D1477F100BCC0D5 /* StorageSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageSettingsView.swift; sourceTree = "<group>"; };
13C9821E2D2152B1007A0132 /* GitHubRelease.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GitHubRelease.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -152,6 +154,7 @@
132417912D1319E800B4F2D2 /* Utils */ = {
isa = PBXGroup;
children = (
13C9821D2D2152A0007A0132 /* GitHub */,
1308CFBA2D19843E004CD38C /* CustomPlayer */,
132417922D1319E800B4F2D2 /* Miru */,
132417942D1319E800B4F2D2 /* Extensions */,
@ -276,6 +279,14 @@
path = EpisodesCell;
sourceTree = "<group>";
};
13C9821D2D2152A0007A0132 /* GitHub */ = {
isa = PBXGroup;
children = (
13C9821E2D2152B1007A0132 /* GitHubRelease.swift */,
);
path = GitHub;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -381,6 +392,7 @@
1324179E2D1319E800B4F2D2 /* MiruDataStruct.swift in Sources */,
1308CFBE2D19844D004CD38C /* MusicProgressSlider.swift in Sources */,
132417D52D13240200B4F2D2 /* EpisodeCell.swift in Sources */,
13C9821F2D2152B1007A0132 /* GitHubRelease.swift in Sources */,
1352BA712D1ABC30000A9AF9 /* URLSession.swift in Sources */,
132417A02D1319E800B4F2D2 /* HistoryManager.swift in Sources */,
);
@ -528,7 +540,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = me.cranci.Sora;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -561,7 +573,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = me.cranci.Sora;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;

View file

@ -29,6 +29,84 @@ struct ContentView: View {
Label("Settings", systemImage: "gearshape")
}
}
.onAppear {
checkForUpdate()
}
}
func checkForUpdate() {
fetchLatestRelease { release in
guard let release = release else { return }
let latestVersion = release.tagName
let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0"
if latestVersion.compare(currentVersion, options: .numeric) == .orderedDescending {
DispatchQueue.main.async {
showUpdateAlert(release: release)
}
}
}
}
func fetchLatestRelease(completion: @escaping (GitHubRelease?) -> Void) {
let url = URL(string: "https://api.github.com/repos/cranci1/Sora/releases/latest")!
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
completion(nil)
return
}
let release = try? JSONDecoder().decode(GitHubRelease.self, from: data)
completion(release)
}.resume()
}
func showUpdateAlert(release: GitHubRelease) {
let alert = UIAlertController(title: "Update Available", message: "A new version (\(release.tagName)) is available. Would you like to update Sora?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Update", style: .default, handler: { _ in
self.showInstallOptionsAlert(release: release)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = windowScene.windows.first?.rootViewController {
rootViewController.present(alert, animated: true, completion: nil)
}
}
func showInstallOptionsAlert(release: GitHubRelease) {
let installAlert = UIAlertController(title: "Install Update", message: "Choose an installation method:", preferredStyle: .alert)
let downloadUrl = release.assets.first?.browserDownloadUrl ?? ""
installAlert.addAction(UIAlertAction(title: "Install in AltStore", style: .default, handler: { _ in
if let url = URL(string: "altstore://install?url=\(downloadUrl)") {
UIApplication.shared.open(url)
}
}))
installAlert.addAction(UIAlertAction(title: "Install in Sidestore", style: .default, handler: { _ in
if let url = URL(string: "sidestore://install?url=\(downloadUrl)") {
UIApplication.shared.open(url)
}
}))
installAlert.addAction(UIAlertAction(title: "Open in Safari", style: .default, handler: { _ in
if let url = URL(string: downloadUrl) {
UIApplication.shared.open(url)
}
}))
installAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = windowScene.windows.first?.rootViewController {
rootViewController.present(installAlert, animated: true, completion: nil)
}
}
}

View file

@ -15,9 +15,9 @@
</array>
</dict>
</array>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,124 @@
//
// GitHubRelease.swift
// Sora
//
// Created by Francesco on 29/12/24.
//
import Foundation
struct GitHubRelease: Codable {
let url: String
let assetsUrl: String
let uploadUrl: String
let htmlUrl: String
let id: Int
let author: Author
let nodeId: String
let tagName: String
let targetCommitish: String
let name: String
let draft: Bool
let prerelease: Bool
let createdAt: String
let publishedAt: String
let assets: [Asset]
let tarballUrl: String
let zipballUrl: String
let body: String
enum CodingKeys: String, CodingKey {
case url
case assetsUrl = "assets_url"
case uploadUrl = "upload_url"
case htmlUrl = "html_url"
case id
case author
case nodeId = "node_id"
case tagName = "tag_name"
case targetCommitish = "target_commitish"
case name
case draft
case prerelease
case createdAt = "created_at"
case publishedAt = "published_at"
case assets
case tarballUrl = "tarball_url"
case zipballUrl = "zipball_url"
case body
}
struct Author: Codable {
let login: String
let id: Int
let nodeId: String
let avatarUrl: String
let gravatarId: String
let url: String
let htmlUrl: String
let followersUrl: String
let followingUrl: String
let gistsUrl: String
let starredUrl: String
let subscriptionsUrl: String
let organizationsUrl: String
let reposUrl: String
let eventsUrl: String
let receivedEventsUrl: String
let type: String
let siteAdmin: Bool
enum CodingKeys: String, CodingKey {
case login
case id
case nodeId = "node_id"
case avatarUrl = "avatar_url"
case gravatarId = "gravatar_id"
case url
case htmlUrl = "html_url"
case followersUrl = "followers_url"
case followingUrl = "following_url"
case gistsUrl = "gists_url"
case starredUrl = "starred_url"
case subscriptionsUrl = "subscriptions_url"
case organizationsUrl = "organizations_url"
case reposUrl = "repos_url"
case eventsUrl = "events_url"
case receivedEventsUrl = "received_events_url"
case type
case siteAdmin = "site_admin"
}
}
struct Asset: Codable {
let url: String
let id: Int
let nodeId: String
let name: String
let label: String?
let uploader: Author
let contentType: String
let state: String
let size: Int
let downloadCount: Int
let createdAt: String
let updatedAt: String
let browserDownloadUrl: String
enum CodingKeys: String, CodingKey {
case url
case id
case nodeId = "node_id"
case name
case label
case uploader
case contentType = "content_type"
case state
case size
case downloadCount = "download_count"
case createdAt = "created_at"
case updatedAt = "updated_at"
case browserDownloadUrl = "browser_download_url"
}
}
}