feat: add download badges to release page

This commit is contained in:
zarzet committed 2026-01-09 17:25:01 +07:00
1 parent 3b79b4f1ca
commit cbc8fdcb0c
2 files changed
+112 -47

No files matched your search

+52 -47
View File
@@ -3,13 +3,13 @@ name: Release
on: on:
push: push:
tags: tags:
- 'v*' - "v*"
workflow_dispatch: workflow_dispatch:
inputs: inputs:
version: version:
description: 'Version tag (e.g., v1.0.0)' description: "Version tag (e.g., v1.0.0)"
required: true required: true
default: 'v1.0.0' default: "v1.0.0"
jobs: jobs:
# Get version first (quick job) # Get version first (quick job)
@@ -28,7 +28,7 @@ jobs:
VERSION="${GITHUB_REF#refs/tags/}" VERSION="${GITHUB_REF#refs/tags/}"
fi fi
echo "version=$VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT
# Check if version contains -preview, -beta, -rc, or -alpha (NOT -hotfix) # Check if version contains -preview, -beta, -rc, or -alpha (NOT -hotfix)
VERSION_LOWER=$(echo "$VERSION" | tr '[:upper:]' '[:lower:]') VERSION_LOWER=$(echo "$VERSION" | tr '[:upper:]' '[:lower:]')
if [[ "$VERSION_LOWER" == *"-preview"* ]] || [[ "$VERSION_LOWER" == *"-beta"* ]] || [[ "$VERSION_LOWER" == *"-rc"* ]] || [[ "$VERSION_LOWER" == *"-alpha"* ]]; then if [[ "$VERSION_LOWER" == *"-preview"* ]] || [[ "$VERSION_LOWER" == *"-beta"* ]] || [[ "$VERSION_LOWER" == *"-rc"* ]] || [[ "$VERSION_LOWER" == *"-alpha"* ]]; then
@@ -43,7 +43,7 @@ jobs:
build-android: build-android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: get-version needs: get-version
steps: steps:
- name: Free disk space - name: Free disk space
run: | run: |
@@ -65,13 +65,13 @@ jobs:
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: "temurin"
java-version: '17' java-version: "17"
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.21' go-version: "1.21"
cache-dependency-path: go_backend/go.sum cache-dependency-path: go_backend/go.sum
# Cache Gradle for faster builds # Cache Gradle for faster builds
@@ -89,13 +89,13 @@ jobs:
# Use pre-installed Android SDK on GitHub runners # Use pre-installed Android SDK on GitHub runners
echo "ANDROID_HOME=$ANDROID_HOME" echo "ANDROID_HOME=$ANDROID_HOME"
echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT" echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT"
# Accept licenses # Accept licenses
yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || true yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses || true
# Install NDK (required for gomobile) # Install NDK (required for gomobile)
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;25.2.9519653" "platforms;android-34" "build-tools;34.0.0" $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;25.2.9519653" "platforms;android-34" "build-tools;34.0.0"
# Set NDK path # Set NDK path
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/25.2.9519653" >> $GITHUB_ENV echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/25.2.9519653" >> $GITHUB_ENV
@@ -115,7 +115,7 @@ jobs:
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@v2
with: with:
channel: 'stable' channel: "stable"
cache: true cache: true
- name: Get Flutter dependencies - name: Get Flutter dependencies
@@ -164,8 +164,8 @@ jobs:
build-ios: build-ios:
runs-on: macos-latest runs-on: macos-latest
needs: get-version # Only depends on version, NOT android build! needs: get-version # Only depends on version, NOT android build!
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -173,7 +173,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.21' go-version: "1.21"
cache-dependency-path: go_backend/go.sum cache-dependency-path: go_backend/go.sum
# Cache CocoaPods # Cache CocoaPods
@@ -201,51 +201,51 @@ jobs:
run: | run: |
ls -la ios/Frameworks/ ls -la ios/Frameworks/
ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1) ls -la ios/Frameworks/Gobackend.xcframework/ || (echo "ERROR: XCFramework not found!" && exit 1)
- name: Add XCFramework to Xcode project - name: Add XCFramework to Xcode project
run: | run: |
# Install xcodeproj gem for modifying Xcode project # Install xcodeproj gem for modifying Xcode project
sudo gem install xcodeproj sudo gem install xcodeproj
# Create Ruby script to add framework # Create Ruby script to add framework
cat > add_framework.rb << 'EOF' cat > add_framework.rb << 'EOF'
require 'xcodeproj' require 'xcodeproj'
project_path = 'ios/Runner.xcodeproj' project_path = 'ios/Runner.xcodeproj'
project = Xcodeproj::Project.open(project_path) project = Xcodeproj::Project.open(project_path)
# Get the main target # Get the main target
target = project.targets.find { |t| t.name == 'Runner' } target = project.targets.find { |t| t.name == 'Runner' }
# Get or create Frameworks group # Get or create Frameworks group
frameworks_group = project.main_group.find_subpath('Frameworks', true) frameworks_group = project.main_group.find_subpath('Frameworks', true)
frameworks_group ||= project.main_group.new_group('Frameworks') frameworks_group ||= project.main_group.new_group('Frameworks')
# Add XCFramework reference # Add XCFramework reference
framework_path = 'Frameworks/Gobackend.xcframework' framework_path = 'Frameworks/Gobackend.xcframework'
framework_ref = frameworks_group.new_file(framework_path, :project) framework_ref = frameworks_group.new_file(framework_path, :project)
# Add to frameworks build phase # Add to frameworks build phase
frameworks_build_phase = target.frameworks_build_phase frameworks_build_phase = target.frameworks_build_phase
frameworks_build_phase.add_file_reference(framework_ref) frameworks_build_phase.add_file_reference(framework_ref)
# Add to embed frameworks build phase # Add to embed frameworks build phase
embed_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase) && p.name == 'Embed Frameworks' } embed_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase) && p.name == 'Embed Frameworks' }
if embed_phase if embed_phase
build_file = embed_phase.add_file_reference(framework_ref) build_file = embed_phase.add_file_reference(framework_ref)
build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy', 'RemoveHeadersOnCopy'] } build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy', 'RemoveHeadersOnCopy'] }
end end
project.save project.save
puts "Successfully added Gobackend.xcframework to Xcode project" puts "Successfully added Gobackend.xcframework to Xcode project"
EOF EOF
ruby add_framework.rb ruby add_framework.rb
- name: Setup Flutter - name: Setup Flutter
uses: subosito/flutter-action@v2 uses: subosito/flutter-action@v2
with: with:
channel: 'stable' channel: "stable"
cache: true cache: true
# Swap pubspec for iOS build (includes ffmpeg_kit_flutter) # Swap pubspec for iOS build (includes ffmpeg_kit_flutter)
@@ -275,7 +275,7 @@ jobs:
run: | run: |
# Build Flutter iOS without codesigning # Build Flutter iOS without codesigning
flutter build ios --release --no-codesign --config-only flutter build ios --release --no-codesign --config-only
# Use xcodebuild with code signing disabled # Use xcodebuild with code signing disabled
cd ios cd ios
xcodebuild -workspace Runner.xcworkspace \ xcodebuild -workspace Runner.xcworkspace \
@@ -300,7 +300,7 @@ jobs:
# Use absolute path to avoid relative path issues # Use absolute path to avoid relative path issues
zip -r $GITHUB_WORKSPACE/build/ios/ipa/SpotiFLAC-${VERSION}-ios-unsigned.ipa Payload zip -r $GITHUB_WORKSPACE/build/ios/ipa/SpotiFLAC-${VERSION}-ios-unsigned.ipa Payload
rm -rf Payload rm -rf Payload
- name: Verify IPA created - name: Verify IPA created
run: | run: |
ls -la build/ios/ipa/ ls -la build/ios/ipa/
@@ -321,7 +321,7 @@ jobs:
needs: [get-version, build-android, build-ios] needs: [get-version, build-android, build-ios]
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -331,13 +331,13 @@ jobs:
run: | run: |
VERSION=${{ needs.get-version.outputs.version }} VERSION=${{ needs.get-version.outputs.version }}
VERSION_NUM=${VERSION#v} # Remove 'v' prefix VERSION_NUM=${VERSION#v} # Remove 'v' prefix
echo "Looking for version: $VERSION_NUM" echo "Looking for version: $VERSION_NUM"
# Extract changelog section for this version using sed # Extract changelog section for this version using sed
# Find the line with version, then print until next version header or end # Find the line with version, then print until next version header or end
CHANGELOG=$(sed -n "/^## \[$VERSION_NUM\]/,/^## \[/{ /^## \[$VERSION_NUM\]/d; /^## \[/d; p; }" CHANGELOG.md) CHANGELOG=$(sed -n "/^## \[$VERSION_NUM\]/,/^## \[/{ /^## \[$VERSION_NUM\]/d; /^## \[/d; p; }" CHANGELOG.md)
# If no changelog found, use default message # If no changelog found, use default message
if [ -z "$CHANGELOG" ]; then if [ -z "$CHANGELOG" ]; then
echo "No changelog found for version $VERSION_NUM" echo "No changelog found for version $VERSION_NUM"
@@ -345,7 +345,7 @@ jobs:
else else
echo "Found changelog content" echo "Found changelog content"
fi fi
# Save to file for multiline support # Save to file for multiline support
echo "$CHANGELOG" > /tmp/changelog.txt echo "$CHANGELOG" > /tmp/changelog.txt
echo "Extracted changelog:" echo "Extracted changelog:"
@@ -367,32 +367,37 @@ jobs:
run: | run: |
VERSION=${{ needs.get-version.outputs.version }} VERSION=${{ needs.get-version.outputs.version }}
cat > /tmp/release_body.txt << 'HEADER' cat > /tmp/release_body.txt << 'HEADER'
## SpotiFLAC $VERSION
Download Spotify tracks in FLAC quality from Tidal, Qobuz & Amazon Music.
### What's New ### What's New
HEADER HEADER
# Replace $VERSION in header
sed -i "s/\$VERSION/$VERSION/g" /tmp/release_body.txt
cat /tmp/changelog.txt >> /tmp/release_body.txt cat /tmp/changelog.txt >> /tmp/release_body.txt
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
cat >> /tmp/release_body.txt << FOOTER cat >> /tmp/release_body.txt << FOOTER
--- ---
### Downloads ### Downloads
- **Android (arm64)**: \`SpotiFLAC-${VERSION}-arm64.apk\` (recommended)
- **Android (arm32)**: \`SpotiFLAC-${VERSION}-arm32.apk\` (older devices) #### Android
![Android arm64 Downloads](https://img.shields.io/github/downloads/${REPO_OWNER}/${REPO_NAME}/${VERSION}/SpotiFLAC-${VERSION}-arm64.apk?style=for-the-badge&logo=android&label=arm64&color=3DDC84)
![Android arm32 Downloads](https://img.shields.io/github/downloads/${REPO_OWNER}/${REPO_NAME}/${VERSION}/SpotiFLAC-${VERSION}-arm32.apk?style=for-the-badge&logo=android&label=arm32&color=3DDC84)
- **arm64**: \`SpotiFLAC-${VERSION}-arm64.apk\` (recommended for modern devices)
- **arm32**: \`SpotiFLAC-${VERSION}-arm32.apk\` (older devices)
#### iOS
![iOS Downloads](https://img.shields.io/github/downloads/${REPO_OWNER}/${REPO_NAME}/${VERSION}/SpotiFLAC-${VERSION}-ios-unsigned.ipa?style=for-the-badge&logo=apple&label=iOS&color=0078D6)
- **iOS**: \`SpotiFLAC-${VERSION}-ios-unsigned.ipa\` (sideload required) - **iOS**: \`SpotiFLAC-${VERSION}-ios-unsigned.ipa\` (sideload required)
### Installation ### Installation
**Android**: Enable "Install from unknown sources" and install the APK **Android**: Enable "Install from unknown sources" and install the APK
**iOS**: Use AltStore, Sideloadly, or similar tools to sideload the IPA **iOS**: Use AltStore, Sideloadly, or similar tools to sideload the IPA
FOOTER FOOTER
echo "Release body:" echo "Release body:"
cat /tmp/release_body.txt cat /tmp/release_body.txt
+60
View File
@@ -181,6 +181,66 @@ import Gobackend // Import Go framework
GobackendCleanupConnections() GobackendCleanupConnections()
return nil return nil
case "searchDeezerAll":
let args = call.arguments as! [String: Any]
let query = args["query"] as! String
let trackLimit = args["track_limit"] as? Int ?? 15
let artistLimit = args["artist_limit"] as? Int ?? 3
let response = GobackendSearchDeezerAll(query, Int(trackLimit), Int(artistLimit), &error)
if let error = error { throw error }
return response
case "getDeezerMetadata":
let args = call.arguments as! [String: Any]
let resourceType = args["resource_type"] as! String
let resourceId = args["resource_id"] as! String
let response = GobackendGetDeezerMetadata(resourceType, resourceId, &error)
if let error = error { throw error }
return response
case "parseDeezerUrl":
let args = call.arguments as! [String: Any]
let url = args["url"] as! String
let response = GobackendParseDeezerUrl(url, &error)
if let error = error { throw error }
return response
case "searchDeezerByISRC":
let args = call.arguments as! [String: Any]
let isrc = args["isrc"] as! String
let response = GobackendSearchDeezerByISRC(isrc, &error)
if let error = error { throw error }
return response
case "convertSpotifyToDeezer":
let args = call.arguments as! [String: Any]
let resourceType = args["resource_type"] as! String
let spotifyId = args["spotify_id"] as! String
let response = GobackendConvertSpotifyToDeezer(resourceType, spotifyId, &error)
if let error = error { throw error }
return response
case "getSpotifyMetadataWithFallback":
let args = call.arguments as! [String: Any]
let url = args["url"] as! String
let response = GobackendGetSpotifyMetadataWithFallback(url, &error)
if let error = error { throw error }
return response
case "preWarmTrackCache":
let args = call.arguments as! [String: Any]
let tracksJson = args["tracks"] as! String
GobackendPreWarmTrackCache(tracksJson)
return nil
case "getTrackCacheSize":
let response = GobackendGetTrackCacheSize()
return response
case "clearTrackCache":
GobackendClearTrackCache()
return nil
default: default:
throw NSError( throw NSError(
domain: "SpotiFLAC", domain: "SpotiFLAC",