diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0bd4733..70e0b15 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,11 +53,25 @@ jobs: hdiutil create -volname rtaudio -srcfolder dmg_temp -ov -format UDZO rtaudio.dmg rm -rf dmg_temp + - name: Download and extract Sparkle + run: | + cd /tmp + curl -L https://github.com/sparkle-project/Sparkle/releases/download/2.9.0/Sparkle-2.9.0.tar.xz | tar xJ + + - name: Generate Sparkle appcast + run: | + echo "${{ secrets.SPARKLE_PRIVATE_KEY }}" | /tmp/bin/generate_appcast \ + --ed-key-file - \ + -o appcast.xml \ + ./rtaudio.dmg + - name: Upload artifact uses: actions/upload-artifact@v4 with: name: rtaudio-release - path: rtaudio.dmg + path: | + rtaudio.dmg + appcast.xml retention-days: 1 release: @@ -87,6 +101,17 @@ jobs: # expose short SHA for use in the release name/tag echo "short_sha=$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_OUTPUT + - name: Push appcast to rtaudio-updater repo + run: | + git clone https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository_owner }}/rtaudio-updater.git updater + cp artifacts/appcast.xml updater/appcast.xml + cd updater + git config user.email "action@github.com" + git config user.name "GitHub Action" + git add appcast.xml + git commit -m "Update appcast for release-${{ steps.commit_msg.outputs.short_sha }}" || true + git push + - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: @@ -95,4 +120,6 @@ jobs: target_commitish: ${{ github.sha }} name: "🔖 Release #${{ steps.commit_msg.outputs.short_sha }}" body: ${{ steps.commit_msg.outputs.msg }} - files: artifacts/rtaudio.dmg + files: | + artifacts/rtaudio.dmg + artifacts/appcast.xml diff --git a/rtaudio.xcodeproj/project.pbxproj b/rtaudio.xcodeproj/project.pbxproj index a2ce719..ad41185 100644 --- a/rtaudio.xcodeproj/project.pbxproj +++ b/rtaudio.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 264F33942F64499800C1E2AB /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 264F33932F64499800C1E2AB /* Sparkle */; }; 266C88832F605EEB00139B20 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 266C88822F605EEB00139B20 /* Accelerate.framework */; }; /* End PBXBuildFile section */ @@ -42,6 +43,7 @@ buildActionMask = 2147483647; files = ( 266C88832F605EEB00139B20 /* Accelerate.framework in Frameworks */, + 264F33942F64499800C1E2AB /* Sparkle in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -93,6 +95,7 @@ ); name = rtaudio; packageProductDependencies = ( + 264F33932F64499800C1E2AB /* Sparkle */, ); productName = rtaudio; productReference = 266C88662F605B8600139B20 /* rtaudio.app */; @@ -123,6 +126,9 @@ ); mainGroup = 266C885D2F605B8600139B20; minimizedProjectReferenceProxies = 1; + packageReferences = ( + 264F33922F64499800C1E2AB /* XCRemoteSwiftPackageReference "Sparkle" */, + ); preferredProjectObjectVersion = 77; productRefGroup = 266C88672F605B8600139B20 /* Products */; projectDirPath = ""; @@ -399,6 +405,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 264F33922F64499800C1E2AB /* XCRemoteSwiftPackageReference "Sparkle" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sparkle-project/Sparkle"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.9.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 264F33932F64499800C1E2AB /* Sparkle */ = { + isa = XCSwiftPackageProductDependency; + package = 264F33922F64499800C1E2AB /* XCRemoteSwiftPackageReference "Sparkle" */; + productName = Sparkle; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 266C885E2F605B8600139B20 /* Project object */; } diff --git a/rtaudio.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/rtaudio.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..6e450d9 --- /dev/null +++ b/rtaudio.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "e721da7f9826abdffcb6185e886155efa2514bd6234475f1afa893e29eb258d6", + "pins" : [ + { + "identity" : "sparkle", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sparkle-project/Sparkle", + "state" : { + "revision" : "21d8df80440b1ca3b65fa82e40782f1e5a9e6ba2", + "version" : "2.9.0" + } + } + ], + "version" : 3 +} diff --git a/rtaudio/AppDelegate.swift b/rtaudio/AppDelegate.swift index 353d2ee..2466fe6 100644 --- a/rtaudio/AppDelegate.swift +++ b/rtaudio/AppDelegate.swift @@ -9,6 +9,7 @@ import AVFAudio import Cocoa internal import MetalKit import simd +import Sparkle func getAppleMusicArtwork() -> NSImage? { let script = """ @@ -164,6 +165,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { var panel: NSPanel! let audioTap = AudioTap() var metalView: WaveformMTKView! + private var updaterController: SPUStandardUpdaterController! let width: CGFloat = 135 let height: CGFloat = 60 @@ -186,7 +188,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { app.run() } + @objc func checkForUpdates() { + updaterController.checkForUpdates(nil) + } + func applicationDidFinishLaunching(_ notification: Notification) { + updaterController = SPUStandardUpdaterController( + startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil) // Create the actual app panel panel = NSPanel( contentRect: NSRect(x: 0, y: 0, width: width, height: height), diff --git a/rtaudio/Info.plist b/rtaudio/Info.plist index 3f9f95f..479816f 100644 --- a/rtaudio/Info.plist +++ b/rtaudio/Info.plist @@ -6,5 +6,10 @@ NSAudioCaptureUsageDescription This app needs to capture system audio for displaying the waveform. + SUFeedURL + + https://raw.githubusercontent.com/ZephyrCodesStuff/rtaudio-updater/refs/heads/main/appcast.xml + SUPublicEDKey + cqFRi1a5mwPMBGu47gW01S0FwPsQJapmeHQuq4cnXL0= \ No newline at end of file diff --git a/rtaudio/Views/WaveformMTKView.swift b/rtaudio/Views/WaveformMTKView.swift index 2b328cb..26df63e 100644 --- a/rtaudio/Views/WaveformMTKView.swift +++ b/rtaudio/Views/WaveformMTKView.swift @@ -156,6 +156,15 @@ class WaveformMTKView: NSView, CAMetalDisplayLinkDelegate { resetItem.target = NSApp.delegate menu.addItem(resetItem) + menu.addItem(NSMenuItem.separator()) + let updateItem = NSMenuItem( + title: "Check for Updates...", + action: #selector(AppDelegate.checkForUpdates), + keyEquivalent: "" + ) + updateItem.target = NSApp.delegate + menu.addItem(updateItem) + menu.addItem(NSMenuItem.separator()) menu.addItem( NSMenuItem(