mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-21 22:15:40 +00:00
feat(flatpak): add Flatpak packaging and CI release pipeline (#271)
Adds full Flatpak support for Psysonic including: - Flatpak manifest (org.gnome.Platform 47 + rust-stable + node20) with proper finish-args for MPRIS, Discord RPC, PulseAudio, Wayland/X11 - AppStream metainfo XML and .desktop entry - In-app updater disabled at build time via VITE_PSYSONIC_FLATPAK=1 - CI job \`build-flatpak\` in release.yml: generates cargo/npm offline sources, patches manifest with release tag/commit, builds bundle via flatpak/flatpak-github-actions@v6, uploads .flatpak to GitHub release - Release docs updated in CLAUDE.md (Flatpak bump and Flathub mirror flow)
This commit is contained in:
@@ -228,6 +228,78 @@ jobs:
|
|||||||
\( -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" \) \
|
\( -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" \) \
|
||||||
| xargs gh release upload "app-v${VERSION}" --clobber
|
| xargs gh release upload "app-v${VERSION}" --clobber
|
||||||
|
|
||||||
|
build-flatpak:
|
||||||
|
needs: create-release
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
container:
|
||||||
|
image: bilelmoussaoui/flatpak-github-actions:gnome-47
|
||||||
|
options: --privileged
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: install source-generation tools
|
||||||
|
run: |
|
||||||
|
dnf install -y python3-pip python3-aiohttp
|
||||||
|
pip3 install --break-system-packages tomlkit
|
||||||
|
|
||||||
|
- name: install flatpak-builder-tools
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 \
|
||||||
|
https://github.com/flatpak/flatpak-builder-tools.git \
|
||||||
|
/tmp/flatpak-builder-tools
|
||||||
|
# cargo generator: still a single script
|
||||||
|
# node generator: now a proper Python package, install via pip
|
||||||
|
pip3 install --break-system-packages \
|
||||||
|
/tmp/flatpak-builder-tools/node
|
||||||
|
|
||||||
|
- name: generate cargo offline sources
|
||||||
|
run: |
|
||||||
|
python3 /tmp/flatpak-builder-tools/cargo/flatpak-cargo-generator.py \
|
||||||
|
src-tauri/Cargo.lock -o packages/flatpak/cargo-sources.json
|
||||||
|
|
||||||
|
- name: generate npm offline sources
|
||||||
|
run: |
|
||||||
|
flatpak-node-generator npm package-lock.json \
|
||||||
|
-o packages/flatpak/npm-sources.json
|
||||||
|
|
||||||
|
- name: patch manifest for this release
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.create-release.outputs.package_version }}
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory /__w/psysonic/psysonic
|
||||||
|
# Dereference the release tag to get the commit it points to.
|
||||||
|
# ^{} peels annotated tag objects; falls back for lightweight tags.
|
||||||
|
COMMIT=$(git ls-remote origin "refs/tags/app-v${VERSION}^{}" | awk '{print $1}')
|
||||||
|
if [ -z "$COMMIT" ]; then
|
||||||
|
COMMIT=$(git ls-remote origin "refs/tags/app-v${VERSION}" | awk '{print $1}')
|
||||||
|
fi
|
||||||
|
sed -i \
|
||||||
|
-e "s|tag: app-v.*|tag: app-v${VERSION}|" \
|
||||||
|
-e "s|commit: PLACEHOLDER_COMMIT|commit: ${COMMIT}|" \
|
||||||
|
-e "s|VITE_LASTFM_API_KEY=__LASTFM_KEY__|VITE_LASTFM_API_KEY=${{ secrets.VITE_LASTFM_API_KEY }}|" \
|
||||||
|
-e "s|VITE_LASTFM_API_SECRET=__LASTFM_SECRET__|VITE_LASTFM_API_SECRET=${{ secrets.VITE_LASTFM_API_SECRET }}|" \
|
||||||
|
packages/flatpak/dev.psysonic.Psysonic.yml
|
||||||
|
|
||||||
|
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
|
with:
|
||||||
|
bundle: Psysonic_${{ needs.create-release.outputs.package_version }}.flatpak
|
||||||
|
manifest-path: packages/flatpak/dev.psysonic.Psysonic.yml
|
||||||
|
cache-key: flatpak-${{ github.sha }}
|
||||||
|
|
||||||
|
- name: install gh CLI
|
||||||
|
run: dnf install -y gh
|
||||||
|
|
||||||
|
- name: upload flatpak bundle to release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
VERSION=${{ needs.create-release.outputs.package_version }}
|
||||||
|
gh release upload "app-v${VERSION}" \
|
||||||
|
"Psysonic_${VERSION}.flatpak" \
|
||||||
|
--clobber
|
||||||
|
|
||||||
# Verifies that `nix build .#psysonic` still works against the current source,
|
# Verifies that `nix build .#psysonic` still works against the current source,
|
||||||
# refreshes `nix/upstream-sources.json` (npmDepsHash) + `flake.lock`
|
# refreshes `nix/upstream-sources.json` (npmDepsHash) + `flake.lock`
|
||||||
# (nixpkgs pin), and pushes the resulting store paths to the public Cachix
|
# (nixpkgs pin), and pushes the resulting store paths to the public Cachix
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Generated by flatpak-cargo-generator and flatpak-node-generator.
|
||||||
|
# Committed only in the Flathub mirror repo, not here.
|
||||||
|
cargo-sources.json
|
||||||
|
npm-sources.json
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=Psysonic
|
||||||
|
Comment=Desktop music player for Subsonic API-compatible servers
|
||||||
|
Exec=psysonic
|
||||||
|
Icon=dev.psysonic.Psysonic
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=AudioVideo;Audio;Music;Player;
|
||||||
|
StartupWMClass=psysonic
|
||||||
|
Keywords=music;player;subsonic;navidrome;streaming;
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop-application">
|
||||||
|
<id>dev.psysonic.Psysonic</id>
|
||||||
|
<name>Psysonic</name>
|
||||||
|
<summary>Music player for Subsonic-compatible servers</summary>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>GPL-3.0-only</project_license>
|
||||||
|
|
||||||
|
<developer id="dev.psysonic">
|
||||||
|
<name>Psychotoxical</name>
|
||||||
|
</developer>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Psysonic is a desktop music player for Subsonic-compatible servers such as
|
||||||
|
Navidrome and Gonic. It connects to your self-hosted music library and lets
|
||||||
|
you stream your collection from anywhere.
|
||||||
|
</p>
|
||||||
|
<p>Features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Gapless playback with a native Rust audio engine</li>
|
||||||
|
<li>Fullscreen ambient player with album art backdrop</li>
|
||||||
|
<li>Synced and plain lyrics via LRCLIB and YouLy+</li>
|
||||||
|
<li>Scrobbling to Last.fm</li>
|
||||||
|
<li>Discord Rich Presence integration</li>
|
||||||
|
<li>MPRIS media controls and global shortcuts</li>
|
||||||
|
<li>Multiple server profiles</li>
|
||||||
|
<li>Catppuccin-themed UI with glassmorphism effects</li>
|
||||||
|
<li>Play queue management with drag-and-drop</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<launchable type="desktop-id">dev.psysonic.Psysonic.desktop</launchable>
|
||||||
|
|
||||||
|
<url type="homepage">https://github.com/Psychotoxical/psysonic</url>
|
||||||
|
<url type="bugtracker">https://github.com/Psychotoxical/psysonic/issues</url>
|
||||||
|
<url type="donation">https://ko-fi.com/psychotoxic</url>
|
||||||
|
<url type="vcs-browser">https://github.com/Psychotoxical/psysonic</url>
|
||||||
|
|
||||||
|
<categories>
|
||||||
|
<category>AudioVideo</category>
|
||||||
|
<category>Audio</category>
|
||||||
|
<category>Music</category>
|
||||||
|
<category>Player</category>
|
||||||
|
</categories>
|
||||||
|
|
||||||
|
<keywords>
|
||||||
|
<keyword>music</keyword>
|
||||||
|
<keyword>player</keyword>
|
||||||
|
<keyword>subsonic</keyword>
|
||||||
|
<keyword>navidrome</keyword>
|
||||||
|
<keyword>gonic</keyword>
|
||||||
|
<keyword>streaming</keyword>
|
||||||
|
<keyword>self-hosted</keyword>
|
||||||
|
</keywords>
|
||||||
|
|
||||||
|
<!-- OARS 1.1 — music streaming player, no objectionable content generated by the app.
|
||||||
|
social-info:mild covers Last.fm scrobbling and Discord Rich Presence. -->
|
||||||
|
<content_rating type="oars-1.1">
|
||||||
|
<content_attribute id="social-info">mild</content_attribute>
|
||||||
|
</content_rating>
|
||||||
|
|
||||||
|
<recommends>
|
||||||
|
<display_length compare="ge">768</display_length>
|
||||||
|
<control>keyboard</control>
|
||||||
|
<control>pointing</control>
|
||||||
|
</recommends>
|
||||||
|
|
||||||
|
<supports>
|
||||||
|
<internet>always</internet>
|
||||||
|
</supports>
|
||||||
|
|
||||||
|
<!-- Screenshots: replace placeholders with real 16:9 screenshots (no window
|
||||||
|
decorations) before submitting to Flathub. At least 3 are required. -->
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default">
|
||||||
|
<caption>Main player view with album art and play queue</caption>
|
||||||
|
<image type="source" width="1600" height="900">https://raw.githubusercontent.com/Psychotoxical/psysonic/main/assets/screenshots/main.png</image>
|
||||||
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<caption>Fullscreen ambient player</caption>
|
||||||
|
<image type="source" width="1600" height="900">https://raw.githubusercontent.com/Psychotoxical/psysonic/main/assets/screenshots/fullscreen.png</image>
|
||||||
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<caption>Settings — server profiles and appearance</caption>
|
||||||
|
<image type="source" width="1600" height="900">https://raw.githubusercontent.com/Psychotoxical/psysonic/main/assets/screenshots/settings.png</image>
|
||||||
|
</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
|
||||||
|
<releases>
|
||||||
|
<release version="1.43.0" date="2026-04-20">
|
||||||
|
<url type="details">https://github.com/Psychotoxical/psysonic/releases/tag/app-v1.43.0</url>
|
||||||
|
<description>
|
||||||
|
<p>Added user management for Navidrome admins, seekable HTTP streaming,
|
||||||
|
mini player improvements, floating player bar, NVIDIA DMA-BUF auto-disable,
|
||||||
|
and smoother lyrics scroll animation.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="1.42.1" date="2026-04-19">
|
||||||
|
<url type="details">https://github.com/Psychotoxical/psysonic/releases/tag/app-v1.42.1</url>
|
||||||
|
<description>
|
||||||
|
<p>Critical fix: mini player no longer hangs the app on Windows. Added
|
||||||
|
optional "Preload mini player" setting on Linux and macOS.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
</releases>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
app-id: dev.psysonic.Psysonic
|
||||||
|
runtime: org.gnome.Platform
|
||||||
|
runtime-version: '47'
|
||||||
|
sdk: org.gnome.Sdk
|
||||||
|
sdk-extensions:
|
||||||
|
- org.freedesktop.Sdk.Extension.rust-stable
|
||||||
|
- org.freedesktop.Sdk.Extension.node20
|
||||||
|
command: psysonic
|
||||||
|
separate-locales: false
|
||||||
|
|
||||||
|
finish-args:
|
||||||
|
# Network: Subsonic server, Last.fm, Discord RPC, LRCLIB, Bandsintown
|
||||||
|
- --share=network
|
||||||
|
- --share=ipc
|
||||||
|
# Display
|
||||||
|
- --socket=wayland
|
||||||
|
- --socket=fallback-x11
|
||||||
|
# Audio: PulseAudio + ALSA, USB DACs (UMC202HD etc.)
|
||||||
|
- --socket=pulseaudio
|
||||||
|
- --device=all
|
||||||
|
# D-Bus: MPRIS, Discord RPC, tray icon
|
||||||
|
- --socket=session-bus
|
||||||
|
- --talk-name=org.mpris.MediaPlayer2.*
|
||||||
|
- --own-name=org.mpris.MediaPlayer2.psysonic
|
||||||
|
- --talk-name=com.discordapp.*
|
||||||
|
# Discord RPC unix socket lives in $XDG_RUNTIME_DIR
|
||||||
|
- --filesystem=xdg-run/discord-ipc-0:ro
|
||||||
|
- --filesystem=xdg-run/discord-ipc-1:ro
|
||||||
|
- --filesystem=xdg-run/discord-ipc-2:ro
|
||||||
|
- --filesystem=xdg-run/discord-ipc-3:ro
|
||||||
|
- --filesystem=xdg-run/discord-ipc-4:ro
|
||||||
|
# Tray icon (GNOME needs AppIndicator extension installed)
|
||||||
|
- --talk-name=org.kde.StatusNotifierWatcher
|
||||||
|
- --talk-name=org.freedesktop.Notifications
|
||||||
|
# Local music library (read-only, for future local-file playback)
|
||||||
|
- --filesystem=xdg-music:ro
|
||||||
|
|
||||||
|
build-options:
|
||||||
|
append-path: /usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/node20/bin
|
||||||
|
env:
|
||||||
|
- CARGO_HOME=/run/build/psysonic/cargo
|
||||||
|
- CARGO_NET_OFFLINE=true
|
||||||
|
- RUSTUP_TOOLCHAIN=stable
|
||||||
|
|
||||||
|
modules:
|
||||||
|
- name: psysonic
|
||||||
|
buildsystem: simple
|
||||||
|
build-options:
|
||||||
|
env:
|
||||||
|
# Disables the in-app updater UI — Flathub owns updates for Flatpak installs
|
||||||
|
- VITE_PSYSONIC_FLATPAK=1
|
||||||
|
# Prevents tauri-build from checking whether the Vite dev server is running
|
||||||
|
- TAURI_SKIP_DEVSERVER_CHECK=true
|
||||||
|
# Last.fm API keys — replaced with real values by the CI job at build time
|
||||||
|
- VITE_LASTFM_API_KEY=__LASTFM_KEY__
|
||||||
|
- VITE_LASTFM_API_SECRET=__LASTFM_SECRET__
|
||||||
|
# npm offline cache — flatpak-node-generator places sources in flatpak-node/npm-cache
|
||||||
|
- npm_config_cache=/run/build/psysonic/flatpak-node/npm-cache
|
||||||
|
build-commands:
|
||||||
|
# Install npm dependencies from pre-generated offline sources
|
||||||
|
- npm ci --offline
|
||||||
|
# Build frontend (dist/ must exist before cargo compiles the Rust crate,
|
||||||
|
# because tauri-build embeds the assets at compile time)
|
||||||
|
- npm run build
|
||||||
|
# Build the Rust binary (offline, using pre-vendored cargo sources)
|
||||||
|
- cargo build --manifest-path src-tauri/Cargo.toml --release
|
||||||
|
# Install binary and assets
|
||||||
|
- install -Dm755 src-tauri/target/release/psysonic "${FLATPAK_DEST}/bin/psysonic"
|
||||||
|
- install -Dm644 dev.psysonic.Psysonic.desktop "${FLATPAK_DEST}/share/applications/dev.psysonic.Psysonic.desktop"
|
||||||
|
- install -Dm644 dev.psysonic.Psysonic.metainfo.xml "${FLATPAK_DEST}/share/metainfo/dev.psysonic.Psysonic.metainfo.xml"
|
||||||
|
- install -Dm644 src-tauri/icons/32x32.png "${FLATPAK_DEST}/share/icons/hicolor/32x32/apps/dev.psysonic.Psysonic.png"
|
||||||
|
- install -Dm644 src-tauri/icons/128x128.png "${FLATPAK_DEST}/share/icons/hicolor/128x128/apps/dev.psysonic.Psysonic.png"
|
||||||
|
- install -Dm644 src-tauri/icons/128x128@2x.png "${FLATPAK_DEST}/share/icons/hicolor/256x256/apps/dev.psysonic.Psysonic.png"
|
||||||
|
- install -Dm644 src-tauri/icons/icon.png "${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/dev.psysonic.Psysonic.png"
|
||||||
|
sources:
|
||||||
|
- type: git
|
||||||
|
url: https://github.com/Psychotoxical/psysonic.git
|
||||||
|
# Updated automatically by the CI release job; bump manually for local builds
|
||||||
|
tag: app-v1.43.0
|
||||||
|
commit: PLACEHOLDER_COMMIT
|
||||||
|
# Generated by the CI job via flatpak-cargo-generator and flatpak-node-generator.
|
||||||
|
# Committed into git only for the Flathub mirror repo (separate from this source
|
||||||
|
# repo); locally, run packages/flatpak/generate-sources.sh to create them.
|
||||||
|
- cargo-sources.json
|
||||||
|
- npm-sources.json
|
||||||
|
- type: file
|
||||||
|
path: dev.psysonic.Psysonic.desktop
|
||||||
|
- type: file
|
||||||
|
path: dev.psysonic.Psysonic.metainfo.xml
|
||||||
@@ -94,6 +94,9 @@ function pickAsset(assets: GithubAsset[]): GithubAsset | undefined {
|
|||||||
type DlState = 'idle' | 'downloading' | 'done' | 'error';
|
type DlState = 'idle' | 'downloading' | 'done' | 'error';
|
||||||
|
|
||||||
export default function AppUpdater() {
|
export default function AppUpdater() {
|
||||||
|
// Flathub manages updates for Flatpak installs — updater UI must not appear
|
||||||
|
if (import.meta.env.VITE_PSYSONIC_FLATPAK === '1') return null;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [release, setRelease] = useState<ReleaseData | null>(null);
|
const [release, setRelease] = useState<ReleaseData | null>(null);
|
||||||
const [dismissed, setDismissed] = useState(false);
|
const [dismissed, setDismissed] = useState(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user