mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-11-04 10:13:59 +00:00
feat(packaging): Flathub, AUR, WinGet and Chocolatey publishing
- Flatpak manifest (GNOME 51, libvlc built from source) installing from a new portable spotube-linux-<version>-<arch>.tar.xz, shared with the AUR package - Release workflow builds and attaches the Linux tarballs for x86_64 and aarch64 - Package files are JMustache templates rendered by :composeApp:renderPackaging<Target> with the version, release asset checksums and git-cliff release notes; the metainfo release history is generated - Publish workflow (workflow_dispatch, release tag input) renders once and pushes to Flathub, the AUR, WinGet (PR from team-spotube/winget-pkgs) and Chocolatey - Chocolatey and WinGet updated for the NSIS installer
This commit is contained in:
parent
79d47c1d87
commit
8ab9463c9a
274
.github/workflows/spotube-publish-binary.yml
vendored
Normal file
274
.github/workflows/spotube-publish-binary.yml
vendored
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
name: Publish
|
||||||
|
|
||||||
|
# Publishes an existing GitHub release (made by spotube-release-binary.yml) to the package managers.
|
||||||
|
# The `render` job checks out the release tag, downloads its assets and renders packaging/<target> with
|
||||||
|
# Gradle (:composeApp:renderPackaging<Target>: version, checksums, git-cliff release notes). The publish
|
||||||
|
# jobs only push what it rendered.
|
||||||
|
#
|
||||||
|
# Secrets:
|
||||||
|
# FLATHUB_TOKEN PAT with push access to team-spotube/org.spotube.spotube
|
||||||
|
# AUR_USERNAME, AUR_EMAIL, AUR_SSH_PRIVATE_KEY AUR account that maintains spotube-bin
|
||||||
|
# WINGET_TOKEN classic PAT (public_repo) that can push to team-spotube/winget-pkgs and open PRs
|
||||||
|
# CHOCO_API_KEY chocolatey.org API key
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: Release tag to publish (vX.Y.Z)
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
jobs:
|
||||||
|
description: Jobs to run (flathub,aur,winget,chocolatey)
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: flathub,aur,winget,chocolatey
|
||||||
|
aur_pkgrel:
|
||||||
|
description: AUR pkgrel (bump to re-release the same version)
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: '1'
|
||||||
|
dry_run:
|
||||||
|
description: Dry run (render the packages, push nothing)
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
TAG: ${{ inputs.tag }}
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
render:
|
||||||
|
name: Render packages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.version.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Validate tag and find release
|
||||||
|
id: version
|
||||||
|
env:
|
||||||
|
DRY_RUN: ${{ inputs.dry_run }}
|
||||||
|
run: |
|
||||||
|
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "::error::tag must look like vX.Y.Z, got '$TAG'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
is_draft=$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json isDraft --jq .isDraft)
|
||||||
|
# The packages download from the public release URLs, which a draft doesn't have yet
|
||||||
|
if [ "$is_draft" = "true" ] && [ "$DRY_RUN" != "true" ]; then
|
||||||
|
echo "::error::release $TAG is still a draft; publish it first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# Full history: git-cliff builds the release notes from it
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.tag }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up JDK 21
|
||||||
|
uses: actions/setup-java@v6
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 21
|
||||||
|
|
||||||
|
# Configuring :composeApp runs cargo (Gobley)
|
||||||
|
- name: Set up Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Set up Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v6
|
||||||
|
|
||||||
|
- name: Install git-cliff
|
||||||
|
uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: git-cliff
|
||||||
|
|
||||||
|
- name: Download release assets
|
||||||
|
run: |
|
||||||
|
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir release-assets \
|
||||||
|
--pattern 'spotube-linux-*.tar.xz' --pattern 'Spotube-windows-x86_64-setup.exe'
|
||||||
|
|
||||||
|
- name: Render packages
|
||||||
|
env:
|
||||||
|
PKGREL: ${{ inputs.aur_pkgrel }}
|
||||||
|
run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
./gradlew :composeApp:renderPackagingFlatpak :composeApp:renderPackagingAur \
|
||||||
|
:composeApp:renderPackagingWinget :composeApp:renderPackagingChocolatey \
|
||||||
|
-Pnightly=false -Ppkgrel="$PKGREL" -PpackagingArtifactsDir=release-assets
|
||||||
|
for f in composeApp/build/packaging/{flatpak/*.yml,aur/PKGBUILD,winget/*.yaml,chocolatey/*.nuspec}; do
|
||||||
|
echo "::group::$f"
|
||||||
|
cat "$f"
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Upload rendered packages
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: packaging
|
||||||
|
path: |
|
||||||
|
composeApp/build/packaging/flatpak
|
||||||
|
composeApp/build/packaging/aur
|
||||||
|
composeApp/build/packaging/winget
|
||||||
|
composeApp/build/packaging/chocolatey
|
||||||
|
|
||||||
|
# Chocolatey embeds the installer in the package
|
||||||
|
- name: Upload Windows installer
|
||||||
|
if: contains(inputs.jobs, 'chocolatey')
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: windows-installer
|
||||||
|
path: release-assets/Spotube-windows-x86_64-setup.exe
|
||||||
|
|
||||||
|
flathub:
|
||||||
|
name: Flathub
|
||||||
|
needs: render
|
||||||
|
if: contains(inputs.jobs, 'flathub')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.render.outputs.version }}
|
||||||
|
FLATHUB_REPO: team-spotube/org.spotube.spotube
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: packaging
|
||||||
|
path: packaging
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
repository: ${{ env.FLATHUB_REPO }}
|
||||||
|
token: ${{ secrets.FLATHUB_TOKEN }}
|
||||||
|
path: flathub
|
||||||
|
|
||||||
|
- name: Commit
|
||||||
|
working-directory: flathub
|
||||||
|
run: |
|
||||||
|
cp ../packaging/flatpak/org.spotube.spotube.yml .
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git switch -c "update-$VERSION"
|
||||||
|
git add org.spotube.spotube.yml
|
||||||
|
git diff --cached
|
||||||
|
git commit -m "Update to $VERSION"
|
||||||
|
|
||||||
|
- name: Push and open PR
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
working-directory: flathub
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.FLATHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
git push -u origin "update-$VERSION"
|
||||||
|
gh pr create --repo "$FLATHUB_REPO" --head "update-$VERSION" \
|
||||||
|
--title "Update to $VERSION" \
|
||||||
|
--body "Release notes: https://github.com/$GITHUB_REPOSITORY/releases/tag/$TAG"
|
||||||
|
|
||||||
|
aur:
|
||||||
|
name: AUR
|
||||||
|
needs: render
|
||||||
|
if: contains(inputs.jobs, 'aur')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: packaging
|
||||||
|
path: packaging
|
||||||
|
|
||||||
|
- name: Publish to AUR
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
uses: KSXGitHub/github-actions-deploy-aur@v4.2.0
|
||||||
|
with:
|
||||||
|
pkgname: spotube-bin
|
||||||
|
pkgbuild: packaging/aur/PKGBUILD
|
||||||
|
commit_username: ${{ secrets.AUR_USERNAME }}
|
||||||
|
commit_email: ${{ secrets.AUR_EMAIL }}
|
||||||
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
commit_message: Update to ${{ needs.render.outputs.version }}-${{ inputs.aur_pkgrel }}
|
||||||
|
|
||||||
|
winget:
|
||||||
|
name: WinGet
|
||||||
|
needs: render
|
||||||
|
if: contains(inputs.jobs, 'winget')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.render.outputs.version }}
|
||||||
|
FORK: team-spotube/winget-pkgs
|
||||||
|
MANIFEST_DIR: manifests/k/KRTirtho/Spotube
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: packaging
|
||||||
|
path: packaging
|
||||||
|
|
||||||
|
- name: Sync fork with upstream
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.WINGET_TOKEN }}
|
||||||
|
run: gh repo sync "$FORK" --source microsoft/winget-pkgs --branch master
|
||||||
|
|
||||||
|
# winget-pkgs is huge: only fetch this package's directory
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
with:
|
||||||
|
repository: ${{ env.FORK }}
|
||||||
|
ref: master
|
||||||
|
token: ${{ secrets.WINGET_TOKEN }}
|
||||||
|
path: winget-pkgs
|
||||||
|
sparse-checkout: ${{ env.MANIFEST_DIR }}
|
||||||
|
|
||||||
|
- name: Push and open PR
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
working-directory: winget-pkgs
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.WINGET_TOKEN }}
|
||||||
|
run: |
|
||||||
|
branch="KRTirtho.Spotube-$VERSION"
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git switch -c "$branch"
|
||||||
|
mkdir -p "$MANIFEST_DIR/$VERSION"
|
||||||
|
cp ../packaging/winget/*.yaml "$MANIFEST_DIR/$VERSION/"
|
||||||
|
git add "$MANIFEST_DIR/$VERSION"
|
||||||
|
git commit -m "New version: KRTirtho.Spotube version $VERSION"
|
||||||
|
git push -u origin "$branch"
|
||||||
|
gh pr create --repo microsoft/winget-pkgs --base master --head "${FORK%%/*}:$branch" \
|
||||||
|
--title "New version: KRTirtho.Spotube version $VERSION" \
|
||||||
|
--body "Release notes: https://github.com/$GITHUB_REPOSITORY/releases/tag/$TAG"
|
||||||
|
|
||||||
|
chocolatey:
|
||||||
|
name: Chocolatey
|
||||||
|
needs: render
|
||||||
|
if: contains(inputs.jobs, 'chocolatey')
|
||||||
|
runs-on: windows-latest
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.render.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: packaging
|
||||||
|
path: packaging
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: windows-installer
|
||||||
|
path: packaging/chocolatey/tools
|
||||||
|
|
||||||
|
- name: Pack
|
||||||
|
run: choco pack packaging/chocolatey/spotube.nuspec --outputdirectory dist
|
||||||
|
|
||||||
|
- name: Upload package
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: chocolatey-nupkg
|
||||||
|
path: dist/*.nupkg
|
||||||
|
|
||||||
|
- name: Publish to Chocolatey
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
env:
|
||||||
|
CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }}
|
||||||
|
run: choco push "dist/spotube.$env:VERSION.nupkg" --source https://push.chocolatey.org/ --api-key "$env:CHOCO_API_KEY"
|
||||||
58
.github/workflows/spotube-release-binary.yml
vendored
58
.github/workflows/spotube-release-binary.yml
vendored
@ -155,7 +155,10 @@ jobs:
|
|||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
# Full history: the metainfo's release notes come from git-cliff
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download maven local
|
- name: Download maven local
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
@ -196,6 +199,30 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew :composeApp:packageGraalvmDeb :composeApp:packageGraalvmRpm -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
|
run: ./gradlew :composeApp:packageGraalvmDeb :composeApp:packageGraalvmRpm -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
|
||||||
|
|
||||||
|
# Portable tarball the AUR and Flathub packages install from. Like deb/rpm it uses the system's VLC,
|
||||||
|
# GTK and WebKitGTK, so it is packed from the distributable before the AppImage build replaces it
|
||||||
|
- name: Install git-cliff
|
||||||
|
uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: git-cliff
|
||||||
|
|
||||||
|
- name: Package Linux tarball
|
||||||
|
run: |
|
||||||
|
if [ "${{ inputs.release_type }}" = "nightly" ]; then
|
||||||
|
VERSION=nightly
|
||||||
|
else
|
||||||
|
VERSION=$(./gradlew -q :composeApp:printVersion)
|
||||||
|
fi
|
||||||
|
# Desktop entry + metainfo, with the release history from git-cliff
|
||||||
|
./gradlew :composeApp:renderPackagingLinux -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
|
||||||
|
packaging/package-linux-tarball.sh "$VERSION" "${{ inputs.release_type }}" .
|
||||||
|
|
||||||
|
- name: Upload tarball
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: linux-tarball
|
||||||
|
path: spotube-linux-*-x86_64.tar.xz
|
||||||
|
|
||||||
# Only the AppImage bundles VLC, GTK and WebKitGTK; deb/rpm depend on the distro packages
|
# Only the AppImage bundles VLC, GTK and WebKitGTK; deb/rpm depend on the distro packages
|
||||||
- name: Package Linux AppImage
|
- name: Package Linux AppImage
|
||||||
env:
|
env:
|
||||||
@ -241,7 +268,10 @@ jobs:
|
|||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-24.04-arm
|
||||||
steps:
|
steps:
|
||||||
|
# Full history: the metainfo's release notes come from git-cliff
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
# The arm64 runner image ships without an Android SDK/NDK, but :composeApp configuration needs both
|
# The arm64 runner image ships without an Android SDK/NDK, but :composeApp configuration needs both
|
||||||
# (Gobley's cargo plugin resolves the NDK directory for the Android Rust targets)
|
# (Gobley's cargo plugin resolves the NDK directory for the Android Rust targets)
|
||||||
@ -289,6 +319,30 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew :composeApp:packageGraalvmDeb :composeApp:packageGraalvmRpm -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
|
run: ./gradlew :composeApp:packageGraalvmDeb :composeApp:packageGraalvmRpm -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
|
||||||
|
|
||||||
|
# Portable tarball the AUR and Flathub packages install from. Like deb/rpm it uses the system's VLC,
|
||||||
|
# GTK and WebKitGTK, so it is packed from the distributable before the AppImage build replaces it
|
||||||
|
- name: Install git-cliff
|
||||||
|
uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: git-cliff
|
||||||
|
|
||||||
|
- name: Package Linux tarball
|
||||||
|
run: |
|
||||||
|
if [ "${{ inputs.release_type }}" = "nightly" ]; then
|
||||||
|
VERSION=nightly
|
||||||
|
else
|
||||||
|
VERSION=$(./gradlew -q :composeApp:printVersion)
|
||||||
|
fi
|
||||||
|
# Desktop entry + metainfo, with the release history from git-cliff
|
||||||
|
./gradlew :composeApp:renderPackagingLinux -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
|
||||||
|
packaging/package-linux-tarball.sh "$VERSION" "${{ inputs.release_type }}" .
|
||||||
|
|
||||||
|
- name: Upload tarball
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: linux-tarball-arm64
|
||||||
|
path: spotube-linux-*-aarch64.tar.xz
|
||||||
|
|
||||||
# Only the AppImage bundles VLC, GTK and WebKitGTK; deb/rpm depend on the distro packages
|
# Only the AppImage bundles VLC, GTK and WebKitGTK; deb/rpm depend on the distro packages
|
||||||
- name: Package Linux AppImage
|
- name: Package Linux AppImage
|
||||||
env:
|
env:
|
||||||
@ -507,7 +561,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "## Downloads" > release-notes.md
|
echo "## Downloads" > release-notes.md
|
||||||
echo "" >> release-notes.md
|
echo "" >> release-notes.md
|
||||||
for dir in android-apk linux-deb linux-rpm linux-appimage linux-deb-arm64 linux-rpm-arm64 linux-appimage-arm64 windows-exe macos-dmg; do
|
for dir in android-apk linux-deb linux-rpm linux-appimage linux-tarball linux-deb-arm64 linux-rpm-arm64 linux-appimage-arm64 linux-tarball-arm64 windows-exe macos-dmg; do
|
||||||
if [ -d "$dir" ]; then
|
if [ -d "$dir" ]; then
|
||||||
echo "### $dir" >> release-notes.md
|
echo "### $dir" >> release-notes.md
|
||||||
for f in "$dir"/*; do
|
for f in "$dir"/*; do
|
||||||
@ -540,8 +594,10 @@ jobs:
|
|||||||
linux-deb/*.deb
|
linux-deb/*.deb
|
||||||
linux-rpm/*.rpm
|
linux-rpm/*.rpm
|
||||||
linux-appimage/*.AppImage
|
linux-appimage/*.AppImage
|
||||||
|
linux-tarball/*.tar.xz
|
||||||
linux-deb-arm64/*.deb
|
linux-deb-arm64/*.deb
|
||||||
linux-rpm-arm64/*.rpm
|
linux-rpm-arm64/*.rpm
|
||||||
linux-appimage-arm64/*.AppImage
|
linux-appimage-arm64/*.AppImage
|
||||||
|
linux-tarball-arm64/*.tar.xz
|
||||||
windows-exe/*.exe
|
windows-exe/*.exe
|
||||||
macos-dmg/*.dmg
|
macos-dmg/*.dmg
|
||||||
|
|||||||
@ -66,6 +66,12 @@
|
|||||||
- **Android signing**: decodes `secrets.KEYSTORE` (base64) → `composeApp/upload-keystore.jks`, writes signing config into `local.properties` from secrets.
|
- **Android signing**: decodes `secrets.KEYSTORE` (base64) → `composeApp/upload-keystore.jks`, writes signing config into `local.properties` from secrets.
|
||||||
- `create-release` job (depends on all builds) uses `softprops/action-gh-release@v2` to create the GitHub release with all artifacts attached.
|
- `create-release` job (depends on all builds) uses `softprops/action-gh-release@v2` to create the GitHub release with all artifacts attached.
|
||||||
|
|
||||||
|
## Package managers (`packaging/`, `.github/workflows/spotube-publish-binary.yml`)
|
||||||
|
- `packaging/<target>` (`linux`, `aur`, `flatpak`, `winget`, `chocolatey`) holds JMustache templates (`*.mustache`) plus files copied as is. `:composeApp:renderPackaging<Target>` renders them into `composeApp/build/packaging/<target>` (`RenderPackagingTask` in buildSrc documents the template data). Never hand-write versions, checksums or release notes into these files.
|
||||||
|
- Checksums come from release assets in `-PpackagingArtifactsDir=<dir>`; a template using a missing value fails the render. Release notes come from `git-cliff --context` with `cliff.toml` (`GitCliffContextTask`): needs `git-cliff` on the PATH and full git history. `gradle.properties` defaults to `nightly=true`, which leaves commits unreleased: pass `-Pnightly=false` for a stable render.
|
||||||
|
- `packaging/package-linux-tarball.sh` packs `spotube-linux-<version>-<arch>.tar.xz` (the AUR and Flathub source) from the GraalVM distributable and the rendered `linux` dir; the release workflow builds it before the AppImage step.
|
||||||
|
- The publish workflow (`workflow_dispatch`, input `tag`) renders once, then pushes to Flathub (`team-spotube/org.spotube.spotube`), the AUR (`spotube-bin`), WinGet (PR from `team-spotube/winget-pkgs`) and Chocolatey.
|
||||||
|
|
||||||
## OpenCode Agent MCP Execution Directives
|
## OpenCode Agent MCP Execution Directives
|
||||||
|
|
||||||
### 1. Code Discovery & Context Search
|
### 1. Code Discovery & Context Search
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// Build logic for the Linux AppImage bundle (see DownloadLinuxGtkBundleTask). Lives in buildSrc so the IDE
|
// Build logic: the Linux AppImage bundle (DownloadLinuxGtkBundleTask) and the package manager manifests
|
||||||
// resolves it; an `apply(from = ...)` script plugin gets no Kotlin classpath in Android Studio.
|
// (GitCliffContextTask, RenderPackagingTask). Lives in buildSrc so the IDE resolves it; an
|
||||||
|
// `apply(from = ...)` script plugin gets no Kotlin classpath in Android Studio.
|
||||||
plugins {
|
plugins {
|
||||||
`kotlin-dsl`
|
`kotlin-dsl`
|
||||||
}
|
}
|
||||||
@ -7,3 +8,7 @@ plugins {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.jmustache)
|
||||||
|
}
|
||||||
|
|||||||
8
buildSrc/settings.gradle.kts
Normal file
8
buildSrc/settings.gradle.kts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Shares the root version catalog (gradle/libs.versions.toml) with the build logic
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
versionCatalogs {
|
||||||
|
create("libs") {
|
||||||
|
from(files("../gradle/libs.versions.toml"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Writes git-cliff's changelog context (every release with its parsed, grouped commits) as JSON, using
|
||||||
|
// the repository's cliff.toml. RenderPackagingTask turns it into release notes for the package manifests.
|
||||||
|
// Needs `git-cliff` on the PATH and the full git history (CI: `fetch-depth: 0`).
|
||||||
|
|
||||||
|
package org.spotube.gradle
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.GradleException
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
|
import org.gradle.api.file.RegularFileProperty
|
||||||
|
import org.gradle.api.provider.Property
|
||||||
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.gradle.api.tasks.InputFile
|
||||||
|
import org.gradle.api.tasks.Internal
|
||||||
|
import org.gradle.api.tasks.Optional
|
||||||
|
import org.gradle.api.tasks.OutputFile
|
||||||
|
import org.gradle.api.tasks.PathSensitive
|
||||||
|
import org.gradle.api.tasks.PathSensitivity
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import org.gradle.process.ExecOperations
|
||||||
|
import org.gradle.work.DisableCachingByDefault
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@DisableCachingByDefault(because = "Reads the git history, which is not a declared input")
|
||||||
|
abstract class GitCliffContextTask @Inject constructor(private val execOperations: ExecOperations) : DefaultTask() {
|
||||||
|
@get:Input
|
||||||
|
abstract val executable: Property<String>
|
||||||
|
|
||||||
|
@get:InputFile
|
||||||
|
@get:PathSensitive(PathSensitivity.NONE)
|
||||||
|
abstract val configFile: RegularFileProperty
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
|
abstract val repositoryDir: DirectoryProperty
|
||||||
|
|
||||||
|
/** Tag for the commits since the last release (`--tag`); unset leaves them unreleased (nightlies). */
|
||||||
|
@get:Input
|
||||||
|
@get:Optional
|
||||||
|
abstract val tag: Property<String>
|
||||||
|
|
||||||
|
@get:OutputFile
|
||||||
|
abstract val outputFile: RegularFileProperty
|
||||||
|
|
||||||
|
init {
|
||||||
|
group = "distribution"
|
||||||
|
description = "Writes the git-cliff changelog context (releases and their commits) as JSON."
|
||||||
|
executable.convention("git-cliff")
|
||||||
|
// New commits and tags change the result without touching any declared input
|
||||||
|
outputs.upToDateWhen { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun run() {
|
||||||
|
val output = outputFile.get().asFile
|
||||||
|
output.parentFile.mkdirs()
|
||||||
|
val args = buildList {
|
||||||
|
add(executable.get())
|
||||||
|
addAll(listOf("--config", configFile.get().asFile.absolutePath, "--context"))
|
||||||
|
tag.orNull?.let { addAll(listOf("--tag", it)) }
|
||||||
|
addAll(listOf("--output", output.absolutePath))
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
execOperations.exec {
|
||||||
|
workingDir = repositoryDir.get().asFile
|
||||||
|
commandLine(args)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw GradleException(
|
||||||
|
"Running git-cliff failed (${args.joinToString(" ")}). Install it from https://git-cliff.org " +
|
||||||
|
"and make sure the full git history is available.",
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Renders one package manager's directory (packaging/<target>) into the build dir: `*.mustache` files are
|
||||||
|
// rendered with JMustache (suffix dropped), everything else is copied as is.
|
||||||
|
//
|
||||||
|
// Template data:
|
||||||
|
// version, tag, pkgrel, repositoryUrl
|
||||||
|
// artifacts.<key>.{fileName, url, sha256, sha256Upper} release assets found in artifactsDir
|
||||||
|
// release.{version, date, url, groups, notes} the release being packaged
|
||||||
|
// releases tagged releases, newest first (metainfo)
|
||||||
|
// groups[].{title, entries[].text} changelog grouped like cliff.toml
|
||||||
|
// #indent2 / #indent4 indent a multi-line block (YAML block scalars)
|
||||||
|
//
|
||||||
|
// Missing variables fail the render, so a manifest never ships with an empty checksum or version.
|
||||||
|
// HTML/XML escaping is on for .xml and .nuspec output only.
|
||||||
|
|
||||||
|
package org.spotube.gradle
|
||||||
|
|
||||||
|
import com.samskivert.mustache.Mustache
|
||||||
|
import com.samskivert.mustache.MustacheException
|
||||||
|
import groovy.json.JsonSlurper
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.GradleException
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
|
import org.gradle.api.file.RegularFileProperty
|
||||||
|
import org.gradle.api.provider.MapProperty
|
||||||
|
import org.gradle.api.provider.Property
|
||||||
|
import org.gradle.api.tasks.CacheableTask
|
||||||
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.gradle.api.tasks.InputDirectory
|
||||||
|
import org.gradle.api.tasks.InputFile
|
||||||
|
import org.gradle.api.tasks.Internal
|
||||||
|
import org.gradle.api.tasks.Optional
|
||||||
|
import org.gradle.api.tasks.OutputDirectory
|
||||||
|
import org.gradle.api.tasks.PathSensitive
|
||||||
|
import org.gradle.api.tasks.PathSensitivity
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import java.io.File
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.ZoneOffset
|
||||||
|
|
||||||
|
@CacheableTask
|
||||||
|
abstract class RenderPackagingTask : DefaultTask() {
|
||||||
|
@get:InputDirectory
|
||||||
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
abstract val templateDir: DirectoryProperty
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
abstract val version: Property<String>
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
abstract val pkgrel: Property<String>
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
abstract val repositoryUrl: Property<String>
|
||||||
|
|
||||||
|
/** Release assets by template key, e.g. `linuxX86_64` -> `spotube-linux-6.0.0-x86_64.tar.xz`. */
|
||||||
|
@get:Input
|
||||||
|
abstract val artifactNames: MapProperty<String, String>
|
||||||
|
|
||||||
|
/** Directory holding the downloaded release assets; only needed by templates that use `artifacts`. */
|
||||||
|
@get:Internal
|
||||||
|
abstract val artifactsDir: DirectoryProperty
|
||||||
|
|
||||||
|
/** The release assets that exist in [artifactsDir]; their checksums are part of the output. */
|
||||||
|
@get:Input
|
||||||
|
protected val artifactChecksums: Map<String, String>
|
||||||
|
get() = artifactFiles().mapValues { (_, file) -> sha256(file) }
|
||||||
|
|
||||||
|
/** git-cliff `--context` output (GitCliffContextTask). */
|
||||||
|
@get:InputFile
|
||||||
|
@get:Optional
|
||||||
|
@get:PathSensitive(PathSensitivity.NONE)
|
||||||
|
abstract val changelogContext: RegularFileProperty
|
||||||
|
|
||||||
|
/** How many tagged releases `releases` lists. */
|
||||||
|
@get:Input
|
||||||
|
abstract val maxReleases: Property<Int>
|
||||||
|
|
||||||
|
@get:OutputDirectory
|
||||||
|
abstract val outputDir: DirectoryProperty
|
||||||
|
|
||||||
|
init {
|
||||||
|
group = "distribution"
|
||||||
|
pkgrel.convention("1")
|
||||||
|
maxReleases.convention(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun render() {
|
||||||
|
val source = templateDir.get().asFile
|
||||||
|
val target = outputDir.get().asFile
|
||||||
|
target.deleteRecursively()
|
||||||
|
target.mkdirs()
|
||||||
|
|
||||||
|
val data = templateData()
|
||||||
|
source.walkTopDown().filter { it.isFile }.forEach { file ->
|
||||||
|
val relative = file.relativeTo(source).path
|
||||||
|
if (!relative.endsWith(TEMPLATE_SUFFIX)) {
|
||||||
|
file.copyTo(target.resolve(relative), overwrite = true)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
val output = target.resolve(relative.removeSuffix(TEMPLATE_SUFFIX))
|
||||||
|
val compiler = Mustache.compiler()
|
||||||
|
.escapeHTML(output.extension in XML_EXTENSIONS)
|
||||||
|
.emptyStringIsFalse(true)
|
||||||
|
.zeroIsFalse(true)
|
||||||
|
val rendered = try {
|
||||||
|
compiler.compile(file.readText()).execute(data)
|
||||||
|
} catch (e: MustacheException) {
|
||||||
|
throw GradleException(
|
||||||
|
"Rendering $relative failed: ${e.message?.trimEnd('.')}. Templates that use `artifacts` need " +
|
||||||
|
"-PpackagingArtifactsDir=<dir with the release assets>.",
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
output.parentFile.mkdirs()
|
||||||
|
output.writeText(rendered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun templateData(): Map<String, Any> {
|
||||||
|
val version = version.get()
|
||||||
|
val tag = "v$version"
|
||||||
|
val repositoryUrl = repositoryUrl.get()
|
||||||
|
val downloadUrl = "$repositoryUrl/releases/download/$tag"
|
||||||
|
|
||||||
|
val artifacts = artifactFiles().mapValues { (_, file) ->
|
||||||
|
val sha256 = sha256(file)
|
||||||
|
mapOf(
|
||||||
|
"fileName" to file.name,
|
||||||
|
"url" to "$downloadUrl/${file.name}",
|
||||||
|
"sha256" to sha256,
|
||||||
|
"sha256Upper" to sha256.uppercase(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val changelog = changelogContext.orNull?.asFile?.let(::readChangelog).orEmpty()
|
||||||
|
val tagged = changelog.filter { it.version != null }.sortedByDescending { it.timestamp }
|
||||||
|
// The release being packaged; nightlies have no tag, so they get the unreleased commits
|
||||||
|
val current = changelog.firstOrNull { it.version == tag }
|
||||||
|
?: changelog.firstOrNull { it.version == null }
|
||||||
|
?: ChangelogRelease(tag, Instant.now().epochSecond, emptyList())
|
||||||
|
|
||||||
|
return mapOf(
|
||||||
|
"version" to version,
|
||||||
|
"tag" to tag,
|
||||||
|
"pkgrel" to pkgrel.get(),
|
||||||
|
"repositoryUrl" to repositoryUrl,
|
||||||
|
"artifacts" to artifacts,
|
||||||
|
"release" to releaseData(current, version, repositoryUrl),
|
||||||
|
"releases" to tagged.take(maxReleases.get()).map {
|
||||||
|
releaseData(it, it.version!!.removePrefix("v"), repositoryUrl)
|
||||||
|
},
|
||||||
|
"indent2" to indent(2),
|
||||||
|
"indent4" to indent(4),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun artifactFiles(): Map<String, File> {
|
||||||
|
val dir = artifactsDir.orNull?.asFile ?: return emptyMap()
|
||||||
|
return artifactNames.get()
|
||||||
|
.mapValues { (_, name) -> dir.resolve(name) }
|
||||||
|
.filterValues { it.isFile }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun releaseData(release: ChangelogRelease, version: String, repositoryUrl: String): Map<String, Any> {
|
||||||
|
val groups = release.commits
|
||||||
|
.groupBy { it.group }
|
||||||
|
.toSortedMap()
|
||||||
|
.map { (group, commits) ->
|
||||||
|
mapOf(
|
||||||
|
// cliff.toml orders groups with an HTML comment prefix: "<!-- 0 -->Features"
|
||||||
|
"title" to group.replace(HTML_COMMENT, "").trim(),
|
||||||
|
"entries" to commits.map { mapOf("text" to it.text) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val notes = groups.joinToString("\n\n") { group ->
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val entries = group["entries"] as List<Map<String, String>>
|
||||||
|
"${group["title"]}\n" + entries.joinToString("\n") { "- ${it["text"]}" }
|
||||||
|
}
|
||||||
|
return mapOf(
|
||||||
|
"version" to version,
|
||||||
|
"date" to LocalDate.ofInstant(Instant.ofEpochSecond(release.timestamp), ZoneOffset.UTC).toString(),
|
||||||
|
"url" to "$repositoryUrl/releases/tag/v$version",
|
||||||
|
"groups" to groups,
|
||||||
|
"notes" to notes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun readChangelog(file: File): List<ChangelogRelease> {
|
||||||
|
val releases = JsonSlurper().parse(file) as List<Map<String, Any?>>
|
||||||
|
return releases.map { release ->
|
||||||
|
val commits = (release["commits"] as List<Map<String, Any?>>).mapNotNull { commit ->
|
||||||
|
val group = commit["group"] as String? ?: return@mapNotNull null
|
||||||
|
val message = (commit["message"] as String).plainText().replaceFirstChar { it.uppercase() }
|
||||||
|
val scope = commit["scope"] as String?
|
||||||
|
val breaking = commit["breaking"] == true
|
||||||
|
val text = buildString {
|
||||||
|
if (breaking) append("Breaking: ")
|
||||||
|
if (scope != null) append("$scope: ")
|
||||||
|
append(message)
|
||||||
|
}
|
||||||
|
ChangelogCommit(group, text)
|
||||||
|
}
|
||||||
|
ChangelogRelease(
|
||||||
|
version = release["version"] as String?,
|
||||||
|
timestamp = (release["timestamp"] as Number?)?.toLong() ?: Instant.now().epochSecond,
|
||||||
|
commits = commits,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class ChangelogRelease(val version: String?, val timestamp: Long, val commits: List<ChangelogCommit>)
|
||||||
|
|
||||||
|
private data class ChangelogCommit(val group: String, val text: String)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val TEMPLATE_SUFFIX = ".mustache"
|
||||||
|
val XML_EXTENSIONS = setOf("xml", "nuspec")
|
||||||
|
val HTML_COMMENT = Regex("<!--.*?-->")
|
||||||
|
val MARKDOWN_LINK = Regex("""\[([^\]]+)]\([^)]+\)""")
|
||||||
|
|
||||||
|
// cliff.toml's commit preprocessors turn issue numbers into Markdown links
|
||||||
|
fun String.plainText() = replace(MARKDOWN_LINK, "$1").replace("**", "").trim()
|
||||||
|
|
||||||
|
fun indent(spaces: Int) = Mustache.Lambda { fragment, out ->
|
||||||
|
val prefix = " ".repeat(spaces)
|
||||||
|
out.write(fragment.execute().lines().joinToString("\n") { if (it.isEmpty()) it else prefix + it })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sha256(file: File): String {
|
||||||
|
val digest = MessageDigest.getInstance("SHA-256")
|
||||||
|
file.inputStream().use { input ->
|
||||||
|
val buffer = ByteArray(1 shl 16)
|
||||||
|
while (true) {
|
||||||
|
val read = input.read(buffer)
|
||||||
|
if (read < 0) break
|
||||||
|
digest.update(buffer, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return digest.digest().joinToString("") { "%02x".format(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,6 +25,8 @@ import org.jetbrains.compose.reload.gradle.ComposeHotRun
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
import org.gradle.api.tasks.Copy
|
import org.gradle.api.tasks.Copy
|
||||||
import org.spotube.gradle.DownloadLinuxGtkBundleTask
|
import org.spotube.gradle.DownloadLinuxGtkBundleTask
|
||||||
|
import org.spotube.gradle.GitCliffContextTask
|
||||||
|
import org.spotube.gradle.RenderPackagingTask
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
|
||||||
@ -76,6 +78,37 @@ tasks.register("printVersion") {
|
|||||||
val appVersion = appVersionName
|
val appVersion = appVersionName
|
||||||
doLast { println(appVersion) }
|
doLast { println(appVersion) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Package manager manifests: packaging/<target> rendered into build/packaging/<target> with the version, the
|
||||||
|
// release assets' checksums (-PpackagingArtifactsDir=<dir>) and the git-cliff changelog. See RenderPackagingTask.
|
||||||
|
val gitCliffContext = tasks.register<GitCliffContextTask>("gitCliffContext") {
|
||||||
|
configFile.set(rootProject.layout.projectDirectory.file("cliff.toml"))
|
||||||
|
repositoryDir.set(rootProject.layout.projectDirectory)
|
||||||
|
// Nightlies are not a release: their commits stay unreleased
|
||||||
|
if (!isNightly) tag.set("v$appVersionName")
|
||||||
|
outputFile.set(layout.buildDirectory.file("packaging/changelog-context.json"))
|
||||||
|
}
|
||||||
|
val packagingRootDir = rootProject.layout.projectDirectory
|
||||||
|
val packagingArtifactsDir = packagingRootDir.dir(providers.gradleProperty("packagingArtifactsDir"))
|
||||||
|
listOf("linux", "aur", "flatpak", "winget", "chocolatey").forEach { target ->
|
||||||
|
tasks.register<RenderPackagingTask>("renderPackaging${target.replaceFirstChar { it.uppercase() }}") {
|
||||||
|
description = "Renders packaging/$target into build/packaging/$target."
|
||||||
|
templateDir.set(packagingRootDir.dir("packaging/$target"))
|
||||||
|
version.set(appVersionName)
|
||||||
|
pkgrel.set(providers.gradleProperty("pkgrel").orElse("1"))
|
||||||
|
repositoryUrl.set(appRepositoryUrl)
|
||||||
|
artifactNames.set(
|
||||||
|
mapOf(
|
||||||
|
"linuxX86_64" to "spotube-linux-$appVersionName-x86_64.tar.xz",
|
||||||
|
"linuxAarch64" to "spotube-linux-$appVersionName-aarch64.tar.xz",
|
||||||
|
"windowsX64" to "Spotube-windows-x86_64-setup.exe",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
artifactsDir.set(packagingArtifactsDir)
|
||||||
|
changelogContext.set(gitCliffContext.flatMap { it.outputFile })
|
||||||
|
outputDir.set(layout.buildDirectory.dir("packaging/$target"))
|
||||||
|
}
|
||||||
|
}
|
||||||
val githubRepositoryPath = repositoryUrl.removePrefix("https://github.com/")
|
val githubRepositoryPath = repositoryUrl.removePrefix("https://github.com/")
|
||||||
val latestReleaseApiUrl = "https://api.github.com/repos/$githubRepositoryPath/releases/latest"
|
val latestReleaseApiUrl = "https://api.github.com/repos/$githubRepositoryPath/releases/latest"
|
||||||
val generatedAppInfoDir = layout.buildDirectory.dir("generated/appBuildInfo/commonMain/kotlin")
|
val generatedAppInfoDir = layout.buildDirectory.dir("generated/appBuildInfo/commonMain/kotlin")
|
||||||
|
|||||||
@ -77,8 +77,11 @@ vanniktechMavenPublish = "0.37.0"
|
|||||||
uniffi = "0.3.7"
|
uniffi = "0.3.7"
|
||||||
kotlinx-atomicfu = "0.33.0"
|
kotlinx-atomicfu = "0.33.0"
|
||||||
mokkery = "3.3.0"
|
mokkery = "3.3.0"
|
||||||
|
jmustache = "1.16"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
# buildSrc: renders the package manager manifests in packaging/
|
||||||
|
jmustache = { module = "com.samskivert:jmustache", version.ref = "jmustache" }
|
||||||
appdirs = { module = "net.harawata:appdirs", version.ref = "appdirs" }
|
appdirs = { module = "net.harawata:appdirs", version.ref = "appdirs" }
|
||||||
cache4k = { module = "io.github.reactivecircus.cache4k:cache4k", version.ref = "cache4k" }
|
cache4k = { module = "io.github.reactivecircus.cache4k:cache4k", version.ref = "cache4k" }
|
||||||
androidx-car-app = { module = "androidx.car.app:app", version.ref = "carApp" }
|
androidx-car-app = { module = "androidx.car.app:app", version.ref = "carApp" }
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
pkgbase = spotube-bin
|
|
||||||
pkgdesc = Open source Music client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!
|
|
||||||
pkgver = 4.0.0
|
|
||||||
pkgrel = 1
|
|
||||||
url = https://spotube.org
|
|
||||||
arch = x86_64
|
|
||||||
license = AGPL-3.0-or-later
|
|
||||||
depends = mpv
|
|
||||||
depends = libappindicator-gtk3
|
|
||||||
depends = libsecret
|
|
||||||
depends = jsoncpp
|
|
||||||
depends = libnotify
|
|
||||||
depends = xdg-user-dirs
|
|
||||||
depends = webkit2gtk-4.1
|
|
||||||
optdepends = yt-dlp-git
|
|
||||||
source = https://github.com/team-spotube/spotube/releases/download/v3.7.1/spotube-linux-3.7.1-x86_64.tar.xz
|
|
||||||
md5sums = 475b1ae9b08f27743a4d4749391ae3db
|
|
||||||
|
|
||||||
pkgname = spotube-bin
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
# Maintainer: Kingkor Roy Tirtho <krtirho@gmail.com>
|
|
||||||
pkgname=spotube-bin
|
|
||||||
pkgver=%{{SPOTUBE_VERSION}}%
|
|
||||||
pkgrel=%{{PKGREL}}%
|
|
||||||
epoch=
|
|
||||||
pkgdesc="Open source Music client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!"
|
|
||||||
arch=(x86_64)
|
|
||||||
url="https://spotube.org"
|
|
||||||
license=('AGPL-3.0-or-later')
|
|
||||||
groups=()
|
|
||||||
depends=('mpv' 'libappindicator-gtk3' 'libsecret' 'jsoncpp' 'libnotify' 'xdg-user-dirs' 'webkit2gtk-4.1')
|
|
||||||
makedepends=()
|
|
||||||
checkdepends=()
|
|
||||||
optdepends=('yt-dlp-git')
|
|
||||||
provides=()
|
|
||||||
conflicts=()
|
|
||||||
replaces=()
|
|
||||||
backup=()
|
|
||||||
options=()
|
|
||||||
install=
|
|
||||||
changelog=
|
|
||||||
source=("https://github.com/team-spotube/spotube/releases/download/v${pkgver}/spotube-linux-${pkgver}-x86_64.tar.xz")
|
|
||||||
noextract=()
|
|
||||||
md5sums=(%{{LINUX_MD5}}%)
|
|
||||||
validpgpkeys=()
|
|
||||||
|
|
||||||
package() {
|
|
||||||
install -dm755 "${pkgdir}/usr/share/icons/spotube"
|
|
||||||
install -dm755 "${pkgdir}/usr/share/applications"
|
|
||||||
install -dm755 "${pkgdir}/usr/share/appdata"
|
|
||||||
install -dm755 "${pkgdir}/usr/share/${pkgname}"
|
|
||||||
install -dm755 "${pkgdir}/usr/bin"
|
|
||||||
|
|
||||||
mv ./spotube.desktop "${pkgdir}/usr/share/applications"
|
|
||||||
mv ./spotube-logo.png "${pkgdir}/usr/share/icons/spotube/"
|
|
||||||
mv ./com.github.KRTirtho.Spotube.appdata.xml "${pkgdir}/usr/share/appdata/spotube.appdata.xml"
|
|
||||||
cp -ra ./data ./lib ./spotube "${pkgdir}/usr/share/${pkgname}"
|
|
||||||
sed -i 's|com.github.KRTirtho.Spotube|spotube|' "${pkgdir}/usr/share/appdata/spotube.appdata.xml"
|
|
||||||
ln -s "/usr/share/${pkgname}/spotube" "${pkgdir}/usr/bin/spotube"
|
|
||||||
}
|
|
||||||
32
packaging/aur/PKGBUILD.mustache
Normal file
32
packaging/aur/PKGBUILD.mustache
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Maintainer: Kingkor Roy Tirtho <krtirho@gmail.com>
|
||||||
|
pkgname=spotube-bin
|
||||||
|
pkgver={{version}}
|
||||||
|
pkgrel={{pkgrel}}
|
||||||
|
pkgdesc="Open source, plugin powered music streaming client"
|
||||||
|
arch=(x86_64 aarch64)
|
||||||
|
url="https://spotube.org"
|
||||||
|
license=('AGPL-3.0-or-later')
|
||||||
|
# libvlc + plugins for playback (FFmpeg demux/decode, GnuTLS for HTTPS streams, PulseAudio/PipeWire output),
|
||||||
|
# WebKitGTK 4.1 for the webview, and the X11/GL/ALSA libraries the AWT/Skiko natives link
|
||||||
|
depends=(
|
||||||
|
'libvlc' 'vlc-plugins-base' 'vlc-plugin-ffmpeg' 'vlc-plugin-gnutls' 'vlc-plugin-pulse'
|
||||||
|
'webkit2gtk-4.1' 'gtk3' 'glib2' 'dbus' 'alsa-lib' 'libglvnd' 'fontconfig' 'freetype2'
|
||||||
|
'libx11' 'libxext' 'libxi' 'libxrender' 'libxtst' 'zlib'
|
||||||
|
)
|
||||||
|
provides=('spotube')
|
||||||
|
conflicts=('spotube')
|
||||||
|
options=('!strip' '!debug')
|
||||||
|
source_x86_64=("https://github.com/team-spotube/spotube/releases/download/v${pkgver}/spotube-linux-${pkgver}-x86_64.tar.xz")
|
||||||
|
source_aarch64=("https://github.com/team-spotube/spotube/releases/download/v${pkgver}/spotube-linux-${pkgver}-aarch64.tar.xz")
|
||||||
|
sha256sums_x86_64=('{{artifacts.linuxX86_64.sha256}}')
|
||||||
|
sha256sums_aarch64=('{{artifacts.linuxAarch64.sha256}}')
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "spotube-linux-${pkgver}-${CARCH}"
|
||||||
|
|
||||||
|
install -dm755 "${pkgdir}/opt" "${pkgdir}/usr/bin" "${pkgdir}/usr/share"
|
||||||
|
cp -a app "${pkgdir}/opt/spotube"
|
||||||
|
cp -a share/. "${pkgdir}/usr/share/"
|
||||||
|
ln -s /opt/spotube/spotube "${pkgdir}/usr/bin/spotube"
|
||||||
|
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||||
|
}
|
||||||
@ -1,55 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter
|
|
||||||
enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. -->
|
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
|
||||||
<metadata>
|
|
||||||
<!-- == PACKAGE SPECIFIC SECTION == -->
|
|
||||||
<id>spotube</id>
|
|
||||||
<version>%{{SPOTUBE_VERSION}}%</version>
|
|
||||||
<packageSourceUrl>https://github.com/team-spotube/spotube/tree/master/choco-struct</packageSourceUrl>
|
|
||||||
<owners>Kingkor Roy Tirtho</owners>
|
|
||||||
<!-- ============================== -->
|
|
||||||
|
|
||||||
<!-- == SOFTWARE SPECIFIC SECTION == -->
|
|
||||||
<title>spotube (Install)</title>
|
|
||||||
<authors>Kingkor Roy Tirtho</authors>
|
|
||||||
<projectUrl>https://spotube.org</projectUrl>
|
|
||||||
<iconUrl>
|
|
||||||
https://rawcdn.githack.com/team-spotube/spotube/7edb0bb834eb18c05551e30a891720a6abf53dbe/assets/branding/spotube-logo.png</iconUrl>
|
|
||||||
<copyright>2022 Spotube</copyright>
|
|
||||||
<!-- If there is a license Url available, it is required for the community feed -->
|
|
||||||
<licenseUrl>https://github.com/team-spotube/spotube/blob/master/LICENSE</licenseUrl>
|
|
||||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
|
||||||
<projectSourceUrl>https://github.com/team-spotube/spotube</projectSourceUrl>
|
|
||||||
<docsUrl>https://spotube.org</docsUrl>
|
|
||||||
<bugTrackerUrl>https://github.com/team-spotube/spotube/issues/new</bugTrackerUrl>
|
|
||||||
<tags>spotube music audio youtube flutter</tags>
|
|
||||||
<summary>🎧 Open source music client that doesn't require Premium nor uses Electron! Available
|
|
||||||
for both desktop & mobile! </summary>
|
|
||||||
<description>
|
|
||||||
Spotube is a Flutter based lightweight music client. It utilizes the power
|
|
||||||
of music metadata providers & Youtube's public API & creates a hazardless, performant
|
|
||||||
& resource
|
|
||||||
friendly User Experience
|
|
||||||
|
|
||||||
# Features
|
|
||||||
- Open source/libre software
|
|
||||||
- Anonymous/guest login
|
|
||||||
- Cross platform support
|
|
||||||
- No telemetry, diagnostics or user data collection
|
|
||||||
- Lightweight & resource-friendly
|
|
||||||
- Native performance (Thanks to Flutter+Skia)
|
|
||||||
- Playback control is done locally instead of on the server
|
|
||||||
- Small size & less data usage
|
|
||||||
- No ads since it uses all public & free APIs (It is still recommended
|
|
||||||
to support the creators by watching/liking/subscribing to the artists' YouTube channels or
|
|
||||||
liking their tracks on different music platforms.)
|
|
||||||
- Time synced lyrics
|
|
||||||
- Downloadable tracks
|
|
||||||
</description>
|
|
||||||
<releaseNotes>https://github.com/team-spotube/spotube/releases/tag/v%{{SPOTUBE_VERSION}}%</releaseNotes>
|
|
||||||
</metadata>
|
|
||||||
<files>
|
|
||||||
<file src="tools\**" target="tools" />
|
|
||||||
</files>
|
|
||||||
</package>
|
|
||||||
48
packaging/chocolatey/spotube.nuspec.mustache
Normal file
48
packaging/chocolatey/spotube.nuspec.mustache
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter
|
||||||
|
enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. -->
|
||||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||||
|
<metadata>
|
||||||
|
<!-- == PACKAGE SPECIFIC SECTION == -->
|
||||||
|
<id>spotube</id>
|
||||||
|
<version>{{version}}</version>
|
||||||
|
<packageSourceUrl>https://github.com/team-spotube/spotube/tree/master/packaging/chocolatey</packageSourceUrl>
|
||||||
|
<owners>Kingkor Roy Tirtho</owners>
|
||||||
|
<!-- ============================== -->
|
||||||
|
|
||||||
|
<!-- == SOFTWARE SPECIFIC SECTION == -->
|
||||||
|
<title>spotube (Install)</title>
|
||||||
|
<authors>Team Spotube</authors>
|
||||||
|
<projectUrl>https://spotube.org</projectUrl>
|
||||||
|
<iconUrl>
|
||||||
|
https://rawcdn.githack.com/team-spotube/spotube/69a310c78f5ceaf4eab7dfee98f187d38211c9ba/assets/branding/spotube-logo.png</iconUrl>
|
||||||
|
<copyright>2026 Kingkor Roy Tirtho and Spotube Contributors</copyright>
|
||||||
|
<!-- If there is a license Url available, it is required for the community feed -->
|
||||||
|
<licenseUrl>https://github.com/team-spotube/spotube/blob/master/LICENSE</licenseUrl>
|
||||||
|
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||||
|
<projectSourceUrl>https://github.com/team-spotube/spotube</projectSourceUrl>
|
||||||
|
<docsUrl>https://spotube.org</docsUrl>
|
||||||
|
<bugTrackerUrl>https://github.com/team-spotube/spotube/issues/new</bugTrackerUrl>
|
||||||
|
<tags>spotube music audio music-player streaming lyrics plugins foss</tags>
|
||||||
|
<summary>Open source, plugin powered music streaming client</summary>
|
||||||
|
<description>
|
||||||
|
A cross-platform, extensible, open source music streaming platform. Bring your own music
|
||||||
|
metadata, playlists and audio sources with plugins made by the community or by yourself.
|
||||||
|
|
||||||
|
# Features
|
||||||
|
- Plugin powered: supports any platform or custom music service through plugins
|
||||||
|
- Community driven plugins for popular platforms, or create your own
|
||||||
|
- Freely downloadable tracks with tagged metadata
|
||||||
|
- Time synced lyrics regardless of plugin support
|
||||||
|
- No telemetry, diagnostics or user data collection
|
||||||
|
- Small size, low data usage and native performance
|
||||||
|
- Open source/libre software
|
||||||
|
</description>
|
||||||
|
<releaseNotes>{{release.url}}
|
||||||
|
|
||||||
|
{{release.notes}}</releaseNotes>
|
||||||
|
</metadata>
|
||||||
|
<files>
|
||||||
|
<file src="tools\**" target="tools" />
|
||||||
|
</files>
|
||||||
|
</package>
|
||||||
@ -7,17 +7,17 @@ in verifying that this package's contents are trustworthy.
|
|||||||
Please go to releases page
|
Please go to releases page
|
||||||
https://github.com/team-spotube/spotube/releases
|
https://github.com/team-spotube/spotube/releases
|
||||||
|
|
||||||
Download same version as this choco package (example for v%{{SPOTUBE_VERSION}}%)
|
Download same version as this choco package (v{{version}})
|
||||||
https://github.com/team-spotube/spotube/releases/tag/v%{{SPOTUBE_VERSION}}%
|
https://github.com/team-spotube/spotube/releases/tag/v{{version}}
|
||||||
|
|
||||||
1. get hashes. Run:
|
1. get hashes. Run:
|
||||||
powershell -command Get-FileHash tools\Spotube-windows-x86_64-setup.exe
|
powershell -command Get-FileHash tools\Spotube-windows-x86_64-setup.exe
|
||||||
|
|
||||||
2. The checksums should match the following:
|
2. The checksums should match the following:
|
||||||
---
|
---
|
||||||
Version Hashes for v%{{SPOTUBE_VERSION}}%
|
Version Hashes for v{{version}}
|
||||||
|
|
||||||
|
|
||||||
Algorithm Hash Path
|
Algorithm Hash Path
|
||||||
--------- ---- ----
|
--------- ---- ----
|
||||||
SHA256 %{{WIN_SHA256}}% tools\Spotube-windows-x86_64-setup.exe
|
SHA256 {{artifacts.windowsX64.sha256Upper}} tools\Spotube-windows-x86_64-setup.exe
|
||||||
@ -5,13 +5,15 @@ $fileLocation = Join-Path $toolsDir 'Spotube-windows-x86_64-setup.exe'
|
|||||||
|
|
||||||
$packageArgs = @{
|
$packageArgs = @{
|
||||||
packageName = $env:ChocolateyPackageName
|
packageName = $env:ChocolateyPackageName
|
||||||
unzipLocation = $toolsDir
|
fileType = 'exe'
|
||||||
fileType = 'exe' #only one of these: exe, msi, msu
|
|
||||||
file = $fileLocation
|
file = $fileLocation
|
||||||
|
|
||||||
softwareName = 'spotube*' #part or all of the Display Name as you see it in Programs and Features. It should be enough to be unique
|
softwareName = 'Spotube*'
|
||||||
silentArgs = '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-' # Inno Setup
|
silentArgs = '/S' # NSIS (electron-builder one-click, per-user)
|
||||||
validExitCodes= @(0)
|
validExitCodes= @(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
Install-ChocolateyInstallPackage @packageArgs
|
Install-ChocolateyInstallPackage @packageArgs
|
||||||
|
|
||||||
|
# The installer was only needed to install; don't keep a copy in the package directory
|
||||||
|
Remove-Item $fileLocation -Force -ErrorAction SilentlyContinue
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
$ErrorActionPreference = 'Stop'; # stop on all errors
|
$ErrorActionPreference = 'Stop'; # stop on all errors
|
||||||
$packageArgs = @{
|
$packageArgs = @{
|
||||||
packageName = $env:ChocolateyPackageName
|
packageName = $env:ChocolateyPackageName
|
||||||
softwareName = 'spotube*'
|
softwareName = 'Spotube*'
|
||||||
fileType = 'exe'
|
fileType = 'exe'
|
||||||
validExitCodes= @(0, 3010, 1605, 1614, 1641)
|
validExitCodes= @(0)
|
||||||
silentArgs = '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-' # Inno Setup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[array]$key = Get-UninstallRegistryKey -SoftwareName $packageArgs['softwareName']
|
[array]$key = Get-UninstallRegistryKey -SoftwareName $packageArgs['softwareName']
|
||||||
|
|
||||||
if ($key.Count -eq 1) {
|
if ($key.Count -eq 1) {
|
||||||
$key | % {
|
$key | % {
|
||||||
$packageArgs['file'] = "$($_.UninstallString)" #NOTE: You may need to split this if it contains spaces, see below
|
# electron-builder writes UninstallString as "<dir>\Uninstall Spotube.exe" /currentuser
|
||||||
|
if ($_.UninstallString -match '^\s*"([^"]+)"\s*(.*)$') {
|
||||||
|
$packageArgs['file'] = $Matches[1]
|
||||||
|
$packageArgs['silentArgs'] = "$($Matches[2]) /S".Trim()
|
||||||
|
} else {
|
||||||
|
$packageArgs['file'] = $_.UninstallString
|
||||||
|
$packageArgs['silentArgs'] = '/S'
|
||||||
|
}
|
||||||
|
|
||||||
Uninstall-ChocolateyPackage @packageArgs
|
Uninstall-ChocolateyPackage @packageArgs
|
||||||
}
|
}
|
||||||
|
|||||||
112
packaging/flatpak/org.spotube.spotube.yml.mustache
Normal file
112
packaging/flatpak/org.spotube.spotube.yml.mustache
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
id: org.spotube.spotube
|
||||||
|
# GTK 3 and WebKitGTK 4.1 (the webview) come from the GNOME runtime
|
||||||
|
runtime: org.gnome.Platform
|
||||||
|
runtime-version: '51'
|
||||||
|
sdk: org.gnome.Sdk
|
||||||
|
command: spotube
|
||||||
|
|
||||||
|
finish-args:
|
||||||
|
- --share=ipc
|
||||||
|
- --share=network
|
||||||
|
# Compose renders through AWT/Skiko, which needs X11 (XWayland on Wayland sessions)
|
||||||
|
- --socket=x11
|
||||||
|
- --socket=pulseaudio
|
||||||
|
- --device=dri
|
||||||
|
# Downloaded tracks go to ~/Downloads/Spotube; local tracks are scanned from ~/Music and ~/Downloads
|
||||||
|
- --filesystem=xdg-download
|
||||||
|
- --filesystem=xdg-music:ro
|
||||||
|
# Tray icon (StatusNotifierItem)
|
||||||
|
- --talk-name=org.kde.StatusNotifierWatcher
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
- /include
|
||||||
|
- /lib/pkgconfig
|
||||||
|
- /share/man
|
||||||
|
- /share/doc
|
||||||
|
- '*.la'
|
||||||
|
- '*.a'
|
||||||
|
|
||||||
|
modules:
|
||||||
|
# libvlc for vlcj (the audio player). Audio only: no video outputs, UI or Lua; decoding and demuxing
|
||||||
|
# go through the runtime's FFmpeg (proprietary codecs come from the auto-installed codecs-extra extension).
|
||||||
|
- name: vlc
|
||||||
|
build-options:
|
||||||
|
env:
|
||||||
|
# configure looks for a c99/c11 wrapper for its build-time tools
|
||||||
|
BUILDCC: gcc -std=gnu11
|
||||||
|
config-opts:
|
||||||
|
- --disable-vlc
|
||||||
|
- --disable-qt
|
||||||
|
- --disable-skins2
|
||||||
|
- --disable-ncurses
|
||||||
|
- --disable-lua
|
||||||
|
- --disable-a52
|
||||||
|
- --disable-dbus
|
||||||
|
- --disable-xcb
|
||||||
|
- --disable-xvideo
|
||||||
|
- --disable-wayland
|
||||||
|
- --disable-vdpau
|
||||||
|
- --disable-libva
|
||||||
|
- --disable-gles2
|
||||||
|
- --disable-sdl-image
|
||||||
|
- --disable-chromecast
|
||||||
|
- --disable-udev
|
||||||
|
- --disable-v4l2
|
||||||
|
- --disable-dc1394
|
||||||
|
- --disable-dv1394
|
||||||
|
- --disable-linsys
|
||||||
|
- --disable-dvbpsi
|
||||||
|
- --disable-bluray
|
||||||
|
- --disable-dvdread
|
||||||
|
- --disable-dvdnav
|
||||||
|
- --disable-vcd
|
||||||
|
- --disable-libcddb
|
||||||
|
- --disable-screen
|
||||||
|
- --disable-addonmanagermodules
|
||||||
|
- --disable-update-check
|
||||||
|
cleanup:
|
||||||
|
- /share/applications
|
||||||
|
- /share/icons
|
||||||
|
- /share/kde4
|
||||||
|
- /share/metainfo
|
||||||
|
- /share/solid
|
||||||
|
- /share/vlc
|
||||||
|
sources:
|
||||||
|
- type: archive
|
||||||
|
url: https://download.videolan.org/pub/videolan/vlc/3.0.24/vlc-3.0.24.tar.xz
|
||||||
|
sha256: e7cab503d1d7d5849b89d2cf0e1ee60d0ef6d012407791b644b9cfc0cc225fdf
|
||||||
|
x-checker-data:
|
||||||
|
type: anitya
|
||||||
|
project-id: 6504
|
||||||
|
stable-only: true
|
||||||
|
versions: {<: '4.0'}
|
||||||
|
url-template: https://download.videolan.org/pub/videolan/vlc/$version/vlc-$version.tar.xz
|
||||||
|
|
||||||
|
# The GraalVM native image, repackaged from the release tarball (packaging/package-linux-tarball.sh)
|
||||||
|
- name: spotube
|
||||||
|
buildsystem: simple
|
||||||
|
build-commands:
|
||||||
|
- cp -a app ${FLATPAK_DEST}/lib/spotube
|
||||||
|
- install -d ${FLATPAK_DEST}/bin
|
||||||
|
- ln -s ../lib/spotube/spotube ${FLATPAK_DEST}/bin/spotube
|
||||||
|
- cp -a share/. ${FLATPAK_DEST}/share/
|
||||||
|
sources:
|
||||||
|
- type: archive
|
||||||
|
only-arches: [x86_64]
|
||||||
|
url: {{artifacts.linuxX86_64.url}}
|
||||||
|
sha256: {{artifacts.linuxX86_64.sha256}}
|
||||||
|
x-checker-data:
|
||||||
|
type: json
|
||||||
|
url: https://api.github.com/repos/team-spotube/spotube/releases/latest
|
||||||
|
version-query: .tag_name | sub("^v"; "")
|
||||||
|
url-query: '"https://github.com/team-spotube/spotube/releases/download/v" + $version + "/spotube-linux-" + $version + "-x86_64.tar.xz"'
|
||||||
|
is-main-source: true
|
||||||
|
- type: archive
|
||||||
|
only-arches: [aarch64]
|
||||||
|
url: {{artifacts.linuxAarch64.url}}
|
||||||
|
sha256: {{artifacts.linuxAarch64.sha256}}
|
||||||
|
x-checker-data:
|
||||||
|
type: json
|
||||||
|
url: https://api.github.com/repos/team-spotube/spotube/releases/latest
|
||||||
|
version-query: .tag_name | sub("^v"; "")
|
||||||
|
url-query: '"https://github.com/team-spotube/spotube/releases/download/v" + $version + "/spotube-linux-" + $version + "-aarch64.tar.xz"'
|
||||||
12
packaging/linux/org.spotube.spotube.desktop
Normal file
12
packaging/linux/org.spotube.spotube.desktop
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Spotube
|
||||||
|
GenericName=Music Player
|
||||||
|
Comment=Open source, plugin powered music streaming client
|
||||||
|
Exec=spotube %U
|
||||||
|
Icon=org.spotube.spotube
|
||||||
|
Terminal=false
|
||||||
|
Categories=AudioVideo;Audio;Music;Player;
|
||||||
|
Keywords=music;streaming;player;audio;lyrics;playlist;
|
||||||
|
StartupNotify=true
|
||||||
|
StartupWMClass=org-spotube-spotube-MainKt
|
||||||
99
packaging/linux/org.spotube.spotube.metainfo.xml.mustache
Normal file
99
packaging/linux/org.spotube.spotube.metainfo.xml.mustache
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop-application">
|
||||||
|
<id>org.spotube.spotube</id>
|
||||||
|
<!-- The Flutter-era app shipped on Flathub as com.github.KRTirtho.Spotube -->
|
||||||
|
<provides>
|
||||||
|
<id>com.github.KRTirtho.Spotube</id>
|
||||||
|
</provides>
|
||||||
|
<replaces>
|
||||||
|
<id>com.github.KRTirtho.Spotube</id>
|
||||||
|
</replaces>
|
||||||
|
|
||||||
|
<name>Spotube</name>
|
||||||
|
<summary>Plugin powered, open source music streaming client</summary>
|
||||||
|
<developer id="org.spotube">
|
||||||
|
<name>Team Spotube</name>
|
||||||
|
</developer>
|
||||||
|
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>AGPL-3.0-or-later</project_license>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
A cross-platform, extensible, open source music streaming platform. Bring your own music
|
||||||
|
metadata, playlists and audio sources with plugins made by the community or by yourself.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Plugin powered: supports any platform or custom music service through plugins</li>
|
||||||
|
<li>Community driven plugins for popular platforms, or create your own</li>
|
||||||
|
<li>Freely downloadable tracks with tagged metadata</li>
|
||||||
|
<li>Time synced lyrics regardless of plugin support</li>
|
||||||
|
<li>No telemetry, diagnostics or user data collection</li>
|
||||||
|
<li>Small size, low data usage and native performance</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<launchable type="desktop-id">org.spotube.spotube.desktop</launchable>
|
||||||
|
|
||||||
|
<categories>
|
||||||
|
<category>AudioVideo</category>
|
||||||
|
<category>Audio</category>
|
||||||
|
<category>Music</category>
|
||||||
|
</categories>
|
||||||
|
<keywords>
|
||||||
|
<keyword>music</keyword>
|
||||||
|
<keyword>streaming</keyword>
|
||||||
|
<keyword>player</keyword>
|
||||||
|
<keyword>lyrics</keyword>
|
||||||
|
</keywords>
|
||||||
|
|
||||||
|
<url type="homepage">https://spotube.org</url>
|
||||||
|
<url type="bugtracker">https://github.com/team-spotube/spotube/issues</url>
|
||||||
|
<url type="vcs-browser">https://github.com/team-spotube/spotube</url>
|
||||||
|
<url type="donation">https://opencollective.com/spotube</url>
|
||||||
|
<url type="contribute">https://github.com/team-spotube/spotube/blob/master/CONTRIBUTION.md</url>
|
||||||
|
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default">
|
||||||
|
<caption>Spotube on the desktop</caption>
|
||||||
|
<image>https://raw.githubusercontent.com/team-spotube/spotube/master/assets/branding/spotube-screenshot.png</image>
|
||||||
|
</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
|
||||||
|
<branding>
|
||||||
|
<color type="primary" scheme_preference="light">#84b2ff</color>
|
||||||
|
<color type="primary" scheme_preference="dark">#01185c</color>
|
||||||
|
</branding>
|
||||||
|
|
||||||
|
<content_rating type="oars-1.1" />
|
||||||
|
|
||||||
|
<requires>
|
||||||
|
<display_length compare="ge">360</display_length>
|
||||||
|
</requires>
|
||||||
|
<supports>
|
||||||
|
<control>pointing</control>
|
||||||
|
<control>keyboard</control>
|
||||||
|
<control>touch</control>
|
||||||
|
</supports>
|
||||||
|
|
||||||
|
<!-- Generated from the git-cliff changelog (RenderPackagingTask) -->
|
||||||
|
<releases>
|
||||||
|
{{#releases}}
|
||||||
|
<release version="{{version}}" date="{{date}}">
|
||||||
|
<url type="details">{{url}}</url>
|
||||||
|
{{#notes}}
|
||||||
|
<description>
|
||||||
|
{{#groups}}
|
||||||
|
<p>{{title}}</p>
|
||||||
|
<ul>
|
||||||
|
{{#entries}}
|
||||||
|
<li>{{text}}</li>
|
||||||
|
{{/entries}}
|
||||||
|
</ul>
|
||||||
|
{{/groups}}
|
||||||
|
</description>
|
||||||
|
{{/notes}}
|
||||||
|
</release>
|
||||||
|
{{/releases}}
|
||||||
|
</releases>
|
||||||
|
</component>
|
||||||
67
packaging/package-linux-tarball.sh
Executable file
67
packaging/package-linux-tarball.sh
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Packs the GraalVM native distributable into spotube-linux-<version>-<arch>.tar.xz, the
|
||||||
|
# portable tarball the AUR (spotube-bin) and Flathub (org.spotube.spotube) packages install from.
|
||||||
|
#
|
||||||
|
# Run after `:composeApp:createGraalvmNativeDistributable` WITHOUT -PappImage=true (the tarball uses the
|
||||||
|
# system's or the Flatpak runtime's VLC, GTK 3 and WebKitGTK, like the deb/rpm) and
|
||||||
|
# `:composeApp:renderPackagingLinux` (desktop entry + metainfo with the release notes).
|
||||||
|
#
|
||||||
|
# Usage: packaging/package-linux-tarball.sh <version> [stable|nightly] [out-dir]
|
||||||
|
#
|
||||||
|
# Layout:
|
||||||
|
# spotube-linux-<version>-<arch>/
|
||||||
|
# app/ binary + the JDK/Skiko libraries it loads
|
||||||
|
# share/applications/org.spotube.spotube.desktop
|
||||||
|
# share/metainfo/org.spotube.spotube.metainfo.xml
|
||||||
|
# share/icons/hicolor/512x512/apps/org.spotube.spotube.png
|
||||||
|
# LICENSE
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
version="${1:?usage: $0 <version> [stable|nightly] [out-dir]}"
|
||||||
|
channel="${2:-stable}"
|
||||||
|
out_dir="${3:-.}"
|
||||||
|
|
||||||
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
app_dir="${SPOTUBE_APP_DIR:-$root/composeApp/build/compose/binaries/main/graalvm-app/org.spotube.spotube}"
|
||||||
|
linux_dir="$root/composeApp/build/packaging/linux"
|
||||||
|
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64 | amd64) arch=x86_64 ;;
|
||||||
|
aarch64 | arm64) arch=aarch64 ;;
|
||||||
|
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ ! -x "$app_dir/spotube" ]]; then
|
||||||
|
echo "No native distributable at $app_dir; run :composeApp:createGraalvmNativeDistributable first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$linux_dir/org.spotube.spotube.metainfo.xml" ]]; then
|
||||||
|
echo "No rendered metainfo in $linux_dir; run :composeApp:renderPackagingLinux first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# An AppImage build (-PappImage=true) leaves VLC plugins and a GTK/WebKit tree in the same dir
|
||||||
|
if [[ -d "$app_dir/plugins" || -d "$app_dir/usr" ]]; then
|
||||||
|
echo "$app_dir bundles VLC/GTK (an -PappImage=true build); rebuild without it" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
name="spotube-linux-$version-$arch"
|
||||||
|
staging="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$staging"' EXIT
|
||||||
|
dest="$staging/$name"
|
||||||
|
|
||||||
|
mkdir -p "$dest/share/applications" "$dest/share/metainfo" "$dest/share/icons/hicolor/512x512/apps"
|
||||||
|
cp -a "$app_dir" "$dest/app"
|
||||||
|
rm -f "$dest/app/.complete"
|
||||||
|
install -m644 "$linux_dir/org.spotube.spotube.desktop" "$dest/share/applications/"
|
||||||
|
install -m644 "$linux_dir/org.spotube.spotube.metainfo.xml" "$dest/share/metainfo/"
|
||||||
|
install -m644 "$root/composeApp/icons/$channel/icon.png" "$dest/share/icons/hicolor/512x512/apps/org.spotube.spotube.png"
|
||||||
|
install -m644 "$root/LICENSE" "$dest/LICENSE"
|
||||||
|
|
||||||
|
mkdir -p "$out_dir"
|
||||||
|
tarball="$(cd "$out_dir" && pwd)/$name.tar.xz"
|
||||||
|
tar -C "$staging" --sort=name --owner=0 --group=0 --numeric-owner \
|
||||||
|
--mtime="@${SOURCE_DATE_EPOCH:-$(git -C "$root" log -1 --format=%ct)}" \
|
||||||
|
-cf - "$name" | xz -T0 -9 > "$tarball"
|
||||||
|
|
||||||
|
echo "$tarball"
|
||||||
21
packaging/winget/KRTirtho.Spotube.installer.yaml.mustache
Normal file
21
packaging/winget/KRTirtho.Spotube.installer.yaml.mustache
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.10.0.schema.json
|
||||||
|
|
||||||
|
PackageIdentifier: KRTirtho.Spotube
|
||||||
|
PackageVersion: {{version}}
|
||||||
|
Platform:
|
||||||
|
- Windows.Desktop
|
||||||
|
MinimumOSVersion: 10.0.0.0
|
||||||
|
# electron-builder one-click NSIS installer (Nucleus), installs per user; winget's nullsoft default /S is silent
|
||||||
|
InstallerType: nullsoft
|
||||||
|
Scope: user
|
||||||
|
InstallModes:
|
||||||
|
- silent
|
||||||
|
- silentWithProgress
|
||||||
|
UpgradeBehavior: install
|
||||||
|
ReleaseDate: {{release.date}}
|
||||||
|
Installers:
|
||||||
|
- Architecture: x64
|
||||||
|
InstallerUrl: {{artifacts.windowsX64.url}}
|
||||||
|
InstallerSha256: {{artifacts.windowsX64.sha256Upper}}
|
||||||
|
ManifestType: installer
|
||||||
|
ManifestVersion: 1.10.0
|
||||||
34
packaging/winget/KRTirtho.Spotube.locale.en-US.yaml.mustache
Normal file
34
packaging/winget/KRTirtho.Spotube.locale.en-US.yaml.mustache
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.10.0.schema.json
|
||||||
|
|
||||||
|
PackageIdentifier: KRTirtho.Spotube
|
||||||
|
PackageVersion: {{version}}
|
||||||
|
PackageLocale: en-US
|
||||||
|
Publisher: Team Spotube
|
||||||
|
PublisherUrl: https://github.com/team-spotube
|
||||||
|
PublisherSupportUrl: https://github.com/team-spotube/spotube/issues
|
||||||
|
PrivacyUrl: https://spotube.org/p/privacy
|
||||||
|
Author: Team Spotube
|
||||||
|
PackageName: Spotube
|
||||||
|
PackageUrl: https://spotube.org
|
||||||
|
License: AGPL-3.0-or-later
|
||||||
|
LicenseUrl: https://github.com/team-spotube/spotube/blob/master/LICENSE
|
||||||
|
Copyright: Copyright (c) 2022-2026 Kingkor Roy Tirtho and Spotube Contributors
|
||||||
|
ShortDescription: Open source, plugin powered music streaming client
|
||||||
|
Description: |-
|
||||||
|
A cross-platform, extensible, open source music streaming platform. Bring your own music
|
||||||
|
metadata, playlists and audio sources with plugins made by the community or by yourself.
|
||||||
|
Moniker: spotube
|
||||||
|
Tags:
|
||||||
|
- audio
|
||||||
|
- music
|
||||||
|
- music-player
|
||||||
|
- streaming
|
||||||
|
- lyrics
|
||||||
|
- plugins
|
||||||
|
{{#release.notes}}
|
||||||
|
ReleaseNotes: |-
|
||||||
|
{{#indent2}}{{release.notes}}{{/indent2}}
|
||||||
|
{{/release.notes}}
|
||||||
|
ReleaseNotesUrl: {{release.url}}
|
||||||
|
ManifestType: defaultLocale
|
||||||
|
ManifestVersion: 1.10.0
|
||||||
7
packaging/winget/KRTirtho.Spotube.yaml.mustache
Normal file
7
packaging/winget/KRTirtho.Spotube.yaml.mustache
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.10.0.schema.json
|
||||||
|
|
||||||
|
PackageIdentifier: KRTirtho.Spotube
|
||||||
|
PackageVersion: {{version}}
|
||||||
|
DefaultLocale: en-US
|
||||||
|
ManifestType: version
|
||||||
|
ManifestVersion: 1.10.0
|
||||||
Loading…
Reference in New Issue
Block a user