Compare commits
443 Commits
v1.0.1
...
app-v1.40.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 225609e93c | |||
| 4773f1ca8c | |||
| 129cd3ea23 | |||
| 98352bb656 | |||
| a2f880da0d | |||
| 95f714654d | |||
| e201bc630c | |||
| 36f0ef79fe | |||
| 939ed3d412 | |||
| bddfd45086 | |||
| 48c10e5619 | |||
| 216e6c957f | |||
| 425addffa0 | |||
| 43df830960 | |||
| 6ed41070a5 | |||
| 061c96a89f | |||
| 31d6e5bd77 | |||
| df91396ba1 | |||
| fb927c5a2e | |||
| 7ee03e917b | |||
| 21f65915db | |||
| 33ba1dfa28 | |||
| f60dabbd31 | |||
| f8bc39036a | |||
| f9f39ccfc2 | |||
| a8317f5877 | |||
| 46bbae873e | |||
| ba43ed867a | |||
| 832bacb569 | |||
| b9093883a4 | |||
| 77edfaa867 | |||
| bac0417e00 | |||
| f30920bfeb | |||
| 8e72e7084b | |||
| dcd356aee7 | |||
|
4f188be792
|
|||
|
cd1417b604
|
|||
| ee437fca5a | |||
| e102320e32 | |||
| d79de7904d | |||
| bf93ee17da | |||
| 02c7a3fe22 | |||
| 34b4445c13 | |||
| e1b807d0ef | |||
| d18646de23 | |||
| ccdb899833 | |||
| b197694804 | |||
| b45bb95522 | |||
| cd1c785e43 | |||
| 1e54946939 | |||
| 34e374cf03 | |||
| 9387ceca83 | |||
| c165669db5 | |||
| c50addaacf | |||
| 7e64ef8f2a | |||
| 8c87ba95ff | |||
| 54962a15c1 | |||
| 689d2dc019 | |||
| f3fb730fbc | |||
| 5576fb0d13 | |||
| 99c6720b86 | |||
| 7b20965c1b | |||
| 28844e8456 | |||
| 572eb81927 | |||
| b6812de26b | |||
| 2f1d52e100 | |||
| 06902acd4b | |||
| 2deaed50b8 | |||
| 3ac82595f9 | |||
| 7db42d74ef | |||
| 58851da817 | |||
| 3262458cd3 | |||
| bf3d896016 | |||
| 442ed9d191 | |||
| e23280c013 | |||
| 189bb519eb | |||
| c573784fbb | |||
| 03b56afc92 | |||
| f437017359 | |||
| 34acc46c12 | |||
| d248a78acc | |||
| a4d8dd41fd | |||
| b7a2e91a62 | |||
| d519042917 | |||
| ccbf3605a0 | |||
| fce8dc3208 | |||
| 2384b73908 | |||
| 7cd0eaf9e1 | |||
| 9383a6f6ed | |||
| 624bd6bff7 | |||
| 67f02def43 | |||
| 1a2bc3f65b | |||
| 56d025f150 | |||
| 602811908b | |||
| fc90617e9c | |||
| a44581e5d6 | |||
| eb061bd9de | |||
| 6533991e7d | |||
| c75297fcf6 | |||
| 19b7c8ec06 | |||
| c3ebc9b951 | |||
| 117be0d85e | |||
| 12818e02f8 | |||
| 7ceaf4d5f2 | |||
| 76da684c8d | |||
| 795701a447 | |||
| 5340d696cf | |||
| 0a14123a0b | |||
| 7cd03248c8 | |||
| 4c6fc4d6d5 | |||
| 6996dacdf7 | |||
| 798812d5ef | |||
| 9f4c7382aa | |||
| d34de09673 | |||
| 1ff4f1ef0f | |||
| 9a9be253e3 | |||
| 38e59d7a5e | |||
| 915f0143f7 | |||
| e0bb02b65e | |||
| 0d5011c5be | |||
| 34d899806a | |||
| 928cdba17a | |||
| 17a5c92174 | |||
| 58f99ae846 | |||
| ef9a620ac6 | |||
| 01f71cf50c | |||
| 39966d1c65 | |||
| cbf72c7eba | |||
| 4207455440 | |||
| 9983d13122 | |||
| 1b55e88cd5 | |||
| 2326f1f94b | |||
| 27ea221130 | |||
| 9cd4743d1c | |||
| e75fda168e | |||
| ec021516c7 | |||
| 82e1b458f3 | |||
| fc7a5815ef | |||
| 1cf5faff21 | |||
| 16cb4f5a6f | |||
| 9b22327bb0 | |||
| dba89cc4e4 | |||
| 91d4cb58b8 | |||
| 374ebce9b5 | |||
| 083c5f62cb | |||
| 592a479c30 | |||
| 6439200e95 | |||
| 9cb1471170 | |||
| 21e26e2604 | |||
| 94323e91fa | |||
| bef6941a2b | |||
| 805b6bf163 | |||
| fee454da5d | |||
| a765bcd5d0 | |||
| 7e50c7af40 | |||
| a12d6a4015 | |||
| da1cc91ff1 | |||
| 08235e1aa5 | |||
| 57dbd50092 | |||
| 4a2baaf87d | |||
| 65e748c464 | |||
| 346fe604d9 | |||
| 600af0e527 | |||
| 2dd993257a | |||
| c2f7d6d495 | |||
| 6a8422ad1f | |||
| 8f45f7230e | |||
| ae2e1bcb97 | |||
| 3d07a877f2 | |||
| bf38a286cd | |||
| 8f18f73b33 | |||
| 1a2352009b | |||
| eedf6f9337 | |||
| b9b8f3fc15 | |||
| b46acc88e3 | |||
| b4c3124168 | |||
| 20dabbfd03 | |||
| 003e7a3203 | |||
| c142e9e983 | |||
| 549677ffd4 | |||
| dcc3e52ad1 | |||
| 4b6888049f | |||
| f45892e975 | |||
| 16c511c167 | |||
|
9986149e2c
|
|||
| 31f72b0459 | |||
| e060737de9 | |||
| 28b23a9de1 | |||
| 649f5223b4 | |||
| 1cc674e4ee | |||
| 41e98d5783 | |||
| 6ffcd6f6fa | |||
| 33a15fd17a | |||
| 084543e59b | |||
| b0081e3d7a | |||
| ccc9f2cae5 | |||
| f34bd7c0f1 | |||
| 8cb5eb9384 | |||
| 02a4c43f61 | |||
| c49f6af38b | |||
| 69c0c5a907 | |||
| 4de577eede | |||
| c9dfbcc19f | |||
| 36f3d42dbe | |||
| 49f7fe5f6e | |||
| 28943f1ecb | |||
| 46cefb5712 | |||
| 74985fe331 | |||
| 4861d99cb1 | |||
| d2592839b0 | |||
| bbeb2f661e | |||
| 5f0fb5dcbd | |||
| 6f6cb0fd6b | |||
| 15dc970f53 | |||
| fc40d235d0 | |||
| f304589ea1 | |||
| 22f7de45e8 | |||
| 05da369aad | |||
| 9671f89a48 | |||
| 9567a94dea | |||
| 1ba8619a37 | |||
| 973b472c1f | |||
| 20bf93c344 | |||
| fd834314ba | |||
| a78c0fe9ac | |||
| 9c57d4f887 | |||
| 5d067b1f8b | |||
| 48d0145dc8 | |||
| 0da92c2fa1 | |||
| 4e3efa3814 | |||
| 77085a544e | |||
| 8ffecb4b7c | |||
| c569ff5f34 | |||
| d16a99a6f9 | |||
| 9b239892ef | |||
| ba670bd1e8 | |||
| c1e57b4c06 | |||
| fbe68116cc | |||
| dba0c26480 | |||
| 3643a78cd6 | |||
| 1e4b851e9e | |||
|
37799fb861
|
|||
| 099516121e | |||
| 9047a44480 | |||
| 47fcade3b3 | |||
| d832dfb253 | |||
| 041d946b58 | |||
| 64d8b1cbd3 | |||
| 5848c621fd | |||
| 0a0dde057d | |||
| 0119e27f6d | |||
| c7adb599ee | |||
| d6546e12ca | |||
| f0438cae5e | |||
| e64d151079 | |||
| f0b423ddc4 | |||
| 8f3b9ebe00 | |||
| d4b18fec5a | |||
| dbb53bfa70 | |||
| 737b057d4a | |||
| 0c2ac13fed | |||
| 1624880c2a | |||
| 6587c82e0c | |||
| 8a1d942128 | |||
| 829936a78d | |||
| ada7dd010f | |||
| 67de94d955 | |||
| 705c80ef07 | |||
| 504c53e71d | |||
| 5be7f7cabd | |||
| c1624342d3 | |||
| 4182b67732 | |||
| 7b4eeea0dc | |||
| 47cea7e3d6 | |||
| 5ed1b58d67 | |||
| 900853fedc | |||
| 2c3c89f078 | |||
| 45fa606ae1 | |||
| d49137475f | |||
| dd4e2f1162 | |||
| 78beb699a7 | |||
| 6f63d7020c | |||
| a606d1edd6 | |||
| 9ef8566d64 | |||
| 4b8b6ae797 | |||
| 9319c40fde | |||
| 63a3bcd0f4 | |||
| a4c400cc69 | |||
| e4aad22c03 | |||
| 489d50016f | |||
| 47490072ef | |||
| ff0a588014 | |||
| e4041287e2 | |||
| 70f0641439 | |||
| c779e8f587 | |||
| 95468fb137 | |||
| c36b1ea538 | |||
| 3f1b6fd92d | |||
| 1c2aa79e29 | |||
| f08619fb3d | |||
| 5ec8fa8ba3 | |||
| 51c118806e | |||
| fc653941c2 | |||
| 8add62a502 | |||
| 44287a7ceb | |||
| 0f3033d84e | |||
| d49af977ed | |||
| d73f348339 | |||
| 390e6e788d | |||
| ff950efb0c | |||
| 4ef21d6d78 | |||
| 7fc0550b65 | |||
| 5d06738ce1 | |||
| 1197c1f916 | |||
| b448c2bc82 | |||
| 6226383762 | |||
| 13a8f696d0 | |||
| 64e0948904 | |||
| 10b2bde5ef | |||
| 1c92f9ed74 | |||
| 443e0c0675 | |||
| 9cc8cfe087 | |||
| 7ac417fbfc | |||
| 50ac1b8284 | |||
| 29203803de | |||
| 83c36de091 | |||
| 1d0965708b | |||
| 2b5416f423 | |||
| 8cd4cdcd64 | |||
| a32ca64792 | |||
| 939abace35 | |||
| 4f7236e986 | |||
| 9be0d8dfa9 | |||
| 67f31b0700 | |||
| c873880a26 | |||
| 463b7483fd | |||
| 3d11ef91a1 | |||
| c365140870 | |||
| 651b3cb050 | |||
| e2ee9247ad | |||
| 74df7b6b88 | |||
| 27a6693c8c | |||
| a932e7c2db | |||
| 7263d93d42 | |||
| 95283d792b | |||
| 53d5888ebf | |||
| cad4338324 | |||
| f9bc67cb77 | |||
| 74c75d83ca | |||
| 005abae97d | |||
| a9c20dfbdf | |||
| 0b5db172bd | |||
| bf99a64baf | |||
| 523596e414 | |||
| 2fe35e3f9b | |||
| e9fa541933 | |||
| 746aa69405 | |||
| 205b2c1914 | |||
| 0086b3e310 | |||
| 55e7cb835b | |||
| d8da511a8f | |||
| 434ee0ecf1 | |||
| 7d1c66071e | |||
| 1adfda1daa | |||
| e65c476a76 | |||
| 560349819f | |||
| ada5327493 | |||
| c67d606f89 | |||
| 662cc94ca8 | |||
| 1eacaf678c | |||
| 4a8fb64c66 | |||
| 43c656dfc3 | |||
| 74b519f9f5 | |||
| 3d03b8d5a1 | |||
| d6f6e6466c | |||
| 95cdbc7fc7 | |||
| 42863877f6 | |||
| 7ed0fa4914 | |||
| 4f8e7d7bc7 | |||
| bb56269cd1 | |||
| 29a4363dca | |||
| e1d27798eb | |||
| b35539d3cf | |||
| a1b3022140 | |||
| b6fb66c46d | |||
| 936e548f40 | |||
| b67c198227 | |||
| 65a828e3fa | |||
| 6bdd6f3a59 | |||
| d62bffd082 | |||
| ff706104ab | |||
| 0abef4b266 | |||
| 3effad0830 | |||
| 361e9cfdb3 | |||
| 5516d95b52 | |||
| d927ef2082 | |||
| 867c5fbd3e | |||
| e550340565 | |||
| 57b70e6154 | |||
| 0b1ed8cc5a | |||
| c9c68a0e57 | |||
| 9d4997baac | |||
| a99e2e0657 | |||
| 7f85b587b4 | |||
| c8d5e9c028 | |||
| 2ba7845c79 | |||
| 9400a5fb2b | |||
| 0e88e8a5cd | |||
| 7de4b97df0 | |||
| 59115a09d2 | |||
| 18199a1f8a | |||
| d4e44199e9 | |||
| 9b4eb0982c | |||
| 8ec642f368 | |||
| 73f836b2ee | |||
| af18aef42a | |||
| d3ffa30bf5 | |||
| f666f84479 | |||
| c91fdd7e1d | |||
| 9bdd433a4b | |||
| a5fd70d3eb | |||
| 744775d3a1 | |||
| 9b1f3b019f | |||
| baa701dd74 | |||
| 1e599d9636 | |||
| 623a6a4a54 | |||
| 32571a2986 | |||
| c9b4bc091e | |||
| 409c20a79e | |||
| 3384db76cd | |||
| e889a76f5f | |||
| eb011bdfdf | |||
| 1d23b21f6f | |||
| 5528123193 | |||
| 85823ff4c4 | |||
| e36a81f847 | |||
| f8c45efd2b | |||
| 7e0cffc892 | |||
| 04773e83f7 | |||
| 45a220989f | |||
| 8a5cca799b | |||
| ee49258c4a | |||
| df9334f844 |
@@ -0,0 +1,12 @@
|
||||
# Arch Linux's rust package bakes -fuse-ld=lld into the default rustflags.
|
||||
# ring (pulled in by tauri-plugin-updater) ships C/asm objects that lld cannot
|
||||
# resolve (ring_core_* symbols). Fix: force cc as linker driver and append
|
||||
# -fuse-ld=bfd so it overrides the hardcoded -fuse-ld=lld (last flag wins).
|
||||
# bfd is always available via binutils (part of base-devel on Arch).
|
||||
#
|
||||
# NOTE: When building via makepkg (AUR), RUSTFLAGS from /etc/makepkg.conf
|
||||
# overrides target-specific rustflags here. The PKGBUILD's build() applies
|
||||
# the same fix by patching the RUSTFLAGS env var directly.
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "cc"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=bfd"]
|
||||
@@ -0,0 +1,15 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: psychotoxic
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
polar: # Replace with a single Polar username
|
||||
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||
thanks_dev: # Replace with a single thanks.dev username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@@ -6,7 +6,73 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
create-release:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.result }}
|
||||
package_version: ${{ steps.get-version.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
- name: get version
|
||||
id: get-version
|
||||
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||
- name: extract changelog
|
||||
id: changelog
|
||||
run: |
|
||||
VERSION="${{ steps.get-version.outputs.version }}"
|
||||
# Extract the block between ## [VERSION] and the next ## heading
|
||||
BODY=$(awk "/^## \[$VERSION\]/{found=1; next} found && /^## \[/{exit} found{print}" CHANGELOG.md)
|
||||
# Store multiline output
|
||||
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
|
||||
echo "body<<$EOF" >> $GITHUB_OUTPUT
|
||||
echo "$BODY" >> $GITHUB_OUTPUT
|
||||
echo "$EOF" >> $GITHUB_OUTPUT
|
||||
- name: create release
|
||||
id: create-release
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PACKAGE_VERSION: ${{ steps.get-version.outputs.version }}
|
||||
CHANGELOG_BODY: ${{ steps.changelog.outputs.body }}
|
||||
with:
|
||||
script: |
|
||||
const tag = `app-v${process.env.PACKAGE_VERSION}`;
|
||||
const body = process.env.CHANGELOG_BODY || 'See the assets to download this version and install.';
|
||||
try {
|
||||
const { data } = await github.rest.repos.getReleaseByTag({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
tag,
|
||||
});
|
||||
await github.rest.repos.updateRelease({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
release_id: data.id,
|
||||
body,
|
||||
});
|
||||
return data.id;
|
||||
} catch (e) {
|
||||
if (e.status !== 404) throw e;
|
||||
}
|
||||
const { data } = await github.rest.repos.createRelease({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
tag_name: tag,
|
||||
name: `Psysonic v${process.env.PACKAGE_VERSION}`,
|
||||
body,
|
||||
draft: true,
|
||||
prerelease: false
|
||||
});
|
||||
return data.id;
|
||||
|
||||
build-macos-windows:
|
||||
needs: create-release
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
@@ -17,41 +83,216 @@ jobs:
|
||||
args: '--target aarch64-apple-darwin'
|
||||
- platform: 'macos-latest'
|
||||
args: '--target x86_64-apple-darwin'
|
||||
- platform: 'ubuntu-22.04'
|
||||
args: ''
|
||||
- platform: 'windows-latest'
|
||||
args: ''
|
||||
|
||||
args: '--bundles nsis'
|
||||
runs-on: ${{ matrix.settings.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: install dependencies (ubuntu only)
|
||||
if: matrix.settings.platform == 'ubuntu-22.04'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
cache: 'npm'
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.settings.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
|
||||
- name: cache cargo
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
- name: install npm dependencies
|
||||
run: npm install
|
||||
- name: write Apple API key (macOS only)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
mkdir -p ~/private_keys
|
||||
echo "${{ secrets.APPLE_API_KEY_B64 }}" | base64 --decode > ~/private_keys/AuthKey.p8
|
||||
echo "APPLE_API_KEY_PATH=$HOME/private_keys/AuthKey.p8" >> $GITHUB_ENV
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }}
|
||||
VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }}
|
||||
# Apple signing + notarization (macOS runner only — ignored on Windows)
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
||||
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
||||
# APPLE_API_KEY_PATH comes from the previous step via $GITHUB_ENV
|
||||
# Tauri Updater signing — produces .sig files alongside the update bundles
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
with:
|
||||
releaseId: ${{ needs.create-release.outputs.release_id }}
|
||||
args: ${{ matrix.settings.args }}
|
||||
- name: re-sign updater bundle + upload .sig (macOS only)
|
||||
# tauri-action re-packs the .app into .app.tar.gz after tauri CLI is
|
||||
# done, which invalidates the .sig tauri CLI created (different hash).
|
||||
# We can't stop the repack (it's tied to includeUpdaterJson), so we
|
||||
# sign the final repacked .tar.gz ourselves and upload the fresh .sig.
|
||||
if: runner.os == 'macOS'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
run: |
|
||||
set -e
|
||||
VERSION=${{ needs.create-release.outputs.package_version }}
|
||||
TARGET_ARG='${{ matrix.settings.args }}'
|
||||
if echo "$TARGET_ARG" | grep -q 'aarch64'; then
|
||||
TARGET="aarch64-apple-darwin"
|
||||
ARCH="aarch64"
|
||||
else
|
||||
TARGET="x86_64-apple-darwin"
|
||||
ARCH="x64"
|
||||
fi
|
||||
TARBALL="src-tauri/target/${TARGET}/release/bundle/macos/Psysonic.app.tar.gz"
|
||||
if [ ! -f "$TARBALL" ]; then
|
||||
echo "::error::Expected tarball missing: $TARBALL"
|
||||
ls -la "$(dirname "$TARBALL")" || true
|
||||
exit 1
|
||||
fi
|
||||
npx @tauri-apps/cli signer sign "$TARBALL"
|
||||
cp "${TARBALL}.sig" "Psysonic_${ARCH}.app.tar.gz.sig"
|
||||
gh release upload "app-v${VERSION}" \
|
||||
"Psysonic_${ARCH}.app.tar.gz.sig" \
|
||||
--clobber
|
||||
|
||||
generate-manifest:
|
||||
needs: [create-release, build-macos-windows]
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: generate latest.json
|
||||
env:
|
||||
VERSION: ${{ needs.create-release.outputs.package_version }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: node scripts/generate-update-manifest.js
|
||||
- name: upload latest.json to release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
VERSION=${{ needs.create-release.outputs.package_version }}
|
||||
gh release upload "app-v${VERSION}" latest.json --clobber
|
||||
|
||||
build-linux:
|
||||
needs: create-release
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf \
|
||||
libasound2-dev squashfs-tools cmake
|
||||
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: cache cargo
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
|
||||
- name: install npm dependencies
|
||||
run: npm install
|
||||
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
- name: build
|
||||
env:
|
||||
VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }}
|
||||
VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }}
|
||||
APPIMAGE_EXTRACT_AND_RUN: 1
|
||||
run: npm run tauri:build -- --bundles deb,rpm,appimage
|
||||
|
||||
- name: upload Linux artifacts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
VERSION=${{ needs.create-release.outputs.package_version }}
|
||||
find src-tauri/target/release/bundle \
|
||||
\( -name "*.deb" -o -name "*.rpm" -o -name "*.AppImage" \) \
|
||||
| xargs gh release upload "app-v${VERSION}" --clobber
|
||||
|
||||
# Verifies that `nix build .#psysonic` still works against the current source,
|
||||
# refreshes `nix/upstream-sources.json` (npmDepsHash) + `flake.lock`
|
||||
# (nixpkgs pin), and pushes the resulting store paths to the public Cachix
|
||||
# binary cache so end users can `nix profile install github:Psychotoxical/psysonic`
|
||||
# without having to compile locally.
|
||||
#
|
||||
# The refreshed lock/hash files are committed back to `main` when they change.
|
||||
verify-nix:
|
||||
needs: create-release
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
tagName: app-v__VERSION__
|
||||
releaseName: 'Psysonic v__VERSION__'
|
||||
releaseBody: 'See the assets to download this version and install.'
|
||||
releaseDraft: false
|
||||
prerelease: false
|
||||
args: ${{ matrix.settings.args }}
|
||||
# Full history so we can push the auto-commit back to the default branch.
|
||||
fetch-depth: 0
|
||||
# Checkout main, not the tag — we want to push lock/hash refreshes to
|
||||
# the moving branch, not the immutable tag ref.
|
||||
ref: main
|
||||
|
||||
- name: install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@v15
|
||||
|
||||
# cachix-action with no signingKey = Cachix-managed signing (Cachix signs
|
||||
# server-side). The action watches the nix store during subsequent build
|
||||
# steps and uploads new paths automatically.
|
||||
- name: configure Cachix (managed signing)
|
||||
uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: psysonic
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
|
||||
- name: compute npmDepsHash from package-lock.json
|
||||
id: npm-hash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
HASH="$(nix run nixpkgs/nixos-unstable#prefetch-npm-deps -- package-lock.json)"
|
||||
echo "hash=$HASH" >> "$GITHUB_OUTPUT"
|
||||
echo "Computed npmDepsHash: $HASH"
|
||||
|
||||
- name: write npmDepsHash into nix/upstream-sources.json
|
||||
run: |
|
||||
set -euo pipefail
|
||||
HASH='${{ steps.npm-hash.outputs.hash }}'
|
||||
jq --arg h "$HASH" '.npmDepsHash = $h' nix/upstream-sources.json > nix/upstream-sources.json.new
|
||||
mv nix/upstream-sources.json.new nix/upstream-sources.json
|
||||
cat nix/upstream-sources.json
|
||||
|
||||
- name: refresh flake.lock (nixpkgs pin)
|
||||
run: nix flake update --accept-flake-config
|
||||
|
||||
- name: verify nix build + push to Cachix
|
||||
run: nix build .#psysonic --accept-flake-config --no-link --print-build-logs
|
||||
|
||||
- name: commit + push refreshed lock and hash (if changed)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add flake.lock nix/upstream-sources.json
|
||||
if git diff --cached --quiet; then
|
||||
echo "flake.lock / nix/upstream-sources.json unchanged — nothing to commit."
|
||||
exit 0
|
||||
fi
|
||||
VERSION="${{ needs.create-release.outputs.package_version }}"
|
||||
git commit -m "chore(nix): refresh lock + npmDepsHash for v${VERSION}"
|
||||
git push origin HEAD:main
|
||||
|
||||
@@ -7,6 +7,11 @@ yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Environment variables (API keys)
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Node
|
||||
node_modules
|
||||
dist
|
||||
@@ -26,6 +31,20 @@ dist-ssr
|
||||
|
||||
# Tauri
|
||||
src-tauri/target/
|
||||
src-tauri/gen/
|
||||
|
||||
# Documentation
|
||||
CLAUDE.md
|
||||
|
||||
# Claude Code memory (local only)
|
||||
memory/
|
||||
|
||||
# Local scratchpad / notes (not committed)
|
||||
tmp/
|
||||
|
||||
# Third-party clones for local research (not committed)
|
||||
research/
|
||||
|
||||
# Nix build output symlink
|
||||
result
|
||||
result-*
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
MIT License
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (c) 2026 Psychotoxical
|
||||
Copyright (C) 2026 Psychotoxical
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
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 General Public License for more details.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
The full license text is available at:
|
||||
https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Privacy Policy
|
||||
|
||||
Psysonic is a self-hosted music player. It does not collect telemetry, analytics, or any data on its own. All data stays on your device or travels exclusively between your device and services you explicitly configure.
|
||||
|
||||
## Data sent to third-party services
|
||||
|
||||
All third-party integrations listed below are **opt-in**. Nothing is sent until you enable the respective feature.
|
||||
|
||||
### Your Subsonic / Navidrome server
|
||||
Your server URL, username, and password are stored locally in the app's data directory. All playback and library requests go directly to your own server. Psysonic has no access to this data.
|
||||
|
||||
### Last.fm
|
||||
If you connect a Last.fm account in Settings, Psysonic sends:
|
||||
- **Scrobbles** — track title, artist, album, and timestamp when a song reaches 50% playback
|
||||
- **Now Playing** — the currently playing track (title, artist, album)
|
||||
- **Love / Unlove** — when you mark a track as loved or unloved
|
||||
|
||||
All requests go to the [Last.fm API](https://www.last.fm/api). Your Last.fm credentials are stored locally and never leave your device. You can disconnect your account at any time in Settings.
|
||||
|
||||
### LRCLIB (Lyrics)
|
||||
When lyrics are fetched from LRCLIB, Psysonic sends the track title, artist, album, and duration to [lrclib.net](https://lrclib.net) as a search query. No account is required. This feature can be disabled in Settings → Lyrics.
|
||||
|
||||
### NetEase Cloud Music (Lyrics)
|
||||
If NetEase is enabled as a lyrics source in Settings → Lyrics, Psysonic sends the track artist and title to the NetEase Cloud Music API (via a Rust-side proxy request) to search for synced lyrics. No account is required. This feature is disabled by default.
|
||||
|
||||
### Apple Music / iTunes Search API
|
||||
If "Use Apple Music covers for Discord" is enabled in Settings, Psysonic queries the [iTunes Search API](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/iTuneSearchAPI/) with the current track's artist and album name to find cover art. No Apple account is required. Apple's own privacy policy applies to these requests.
|
||||
|
||||
### Discord Rich Presence
|
||||
If Discord is running and Rich Presence is not disabled, Psysonic connects to the local Discord client via its IPC socket to display the currently playing track. This data is sent to Discord and subject to [Discord's privacy policy](https://discord.com/privacy). No data is sent if Discord is not installed or not running.
|
||||
|
||||
## Data stored locally
|
||||
|
||||
The following data is stored exclusively on your device in the app's local storage directory and is never transmitted:
|
||||
|
||||
- Server profiles (URL, username, password)
|
||||
- Last.fm session key
|
||||
- Playback preferences, themes, keybindings, and all other settings
|
||||
- Synced device manifests
|
||||
|
||||
## No telemetry
|
||||
|
||||
Psysonic contains no crash reporting, analytics, usage tracking, or any form of telemetry.
|
||||
|
||||
## Open source
|
||||
|
||||
Psysonic is fully open source under the [GNU General Public License v3.0](LICENSE). You can verify exactly what data is sent by reading the source code.
|
||||
@@ -1,49 +1,110 @@
|
||||
<div align="center">
|
||||
<img src="public/logo.png" alt="Psysonic Logo" width="200"/>
|
||||
<h1>Psysonic</h1>
|
||||
<img src="public/psysonic-inapp-logo.svg" alt="Psysonic Logo" width="300"/>
|
||||
|
||||
<p><strong>A modern, gorgeous, and blazing fast desktop client for Subsonic API compatible music servers (Navidrome, Gonic, etc.).</strong></p>
|
||||
|
||||
<p>
|
||||
<a href="https://github.com/Psychotoxical/psysonic/releases/latest"><img alt="Latest Release" src="https://img.shields.io/github/v/release/Psychotoxical/psysonic?style=flat-square&color=8839ef"></a>
|
||||
<a href="https://github.com/Psychotoxical/psysonic/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/Psychotoxical/psysonic?style=flat-square&color=cba6f7"></a>
|
||||
<a href="https://github.com/Psychotoxical/psysonic/blob/main/LICENSE"><img alt="License: GPL v3" src="https://img.shields.io/badge/License-GPLv3-cba6f7?style=flat-square"></a>
|
||||
<a href="https://tauri.app/"><img alt="Built with Tauri" src="https://img.shields.io/badge/Built%20with-Tauri-242938?style=flat-square&logo=tauri"></a>
|
||||
<a href="https://aur.archlinux.org/packages/psysonic"><img alt="AUR" src="https://img.shields.io/aur/version/psysonic?style=flat-square&color=1793d1"></a>
|
||||
<a href="https://aur.archlinux.org/packages/psysonic-bin"><img alt="AUR (bin)" src="https://img.shields.io/aur/version/psysonic-bin?style=flat-square&color=1793d1&label=AUR%20(bin)"></a>
|
||||
<a href="https://discord.gg/pq6d2ZYSg"><img alt="Discord" src="https://img.shields.io/badge/Discord-Join%20us-5865F2?style=flat-square&logo=discord&logoColor=white"></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
> [!WARNING]
|
||||
> **Psysonic is under heavy active development.** Bugs and rough edges are to be expected. We reserve the right to change, remove, or rework existing features at any time without prior notice.
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<a href="https://discord.gg/AMnDRErm4u">
|
||||
<img src="https://img.shields.io/badge/Join%20the%20Psysonic%20Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white" alt="Join Discord"/>
|
||||
</a>
|
||||
<p>Have questions, ideas, or just want to hang out? Come chat in our Discord server!</p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Psysonic is a beautiful desktop music player built completely from the ground up for the modern era. Utilizing **Tauri v2** and **React**, it offers a native-feeling, lightweight, and incredibly fast experience with a stunning UI inspired by the [Catppuccin](https://github.com/catppuccin/catppuccin) aesthetic.
|
||||
Psysonic is a beautiful desktop music player built completely from the ground up for the modern era. Utilizing **Tauri v2** and **React**, it offers a native-feeling, lightweight, and incredibly fast experience with a stunning UI inspired by the [Catppuccin](https://github.com/catppuccin/catppuccin) and [Nord](https://www.nordtheme.com/) aesthetics.
|
||||
|
||||
Designed specifically for users hosting their own music via Navidrome or other Subsonic API servers, Psysonic aims to be the best way to interact with your personal library.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🎨 **Gorgeous UI**: Deeply integrated Catppuccin themes (Mocha & Latte) with smooth glassmorphism effects and micro-animations.
|
||||
- ⚡ **Blazing Fast**: Built with Rust & Tauri, resulting in minimal RAM usage compared to typical Electron apps.
|
||||
- 🌍 **Internationalization (i18n)**: Fully translated into English and German (v1.0.0).
|
||||
- 📻 **Live "Now Playing"**: See what other users on your server are currently listening to in real-time.
|
||||
- 🎵 **Last.fm Scrobbling**: Full integration for scrobbling your tracks via the Navidrome server.
|
||||
- 💾 **Local Caching**: Fast loading times with customizable image caching thresholds.
|
||||
- 💿 **Album & Artist Views**: Beautiful grid displays and detailed artist pages with related albums.
|
||||
- 🎛️ **Queue Management**: Drag & drop support, playlist saving, and loading directly built into the queue. Server-side queue synchronization is fully supported.
|
||||
- 🖥️ **Cross-Platform**: Available natively for Windows, macOS, and Linux.
|
||||
- 🎨 **Wide Theme Selection**: Dozens of themes across 8 groups — Open Source Classics (Catppuccin, Nord, Gruvbox, Nightfox, Dracula), Operating Systems, Games, Movies, Series, Social Media, and Psysonic originals. Glassmorphism effects, micro-animations, and a time-based **Theme Scheduler** for automatic day/night switching.
|
||||
- ⚡ **Native Performance**: Built with Rust & Tauri — native audio engine (rodio), minimal RAM usage, no Electron overhead.
|
||||
- 🎵 **Last.fm Integration**: Scrobbling, Now Playing, love/unlove, Similar Artists, and top stats — no Navidrome config needed.
|
||||
- 🎤 **Synchronized Lyrics**: Auto-scrolling synced lyrics with click-to-seek in the sidebar and fullscreen player, powered by LRCLIB and your Navidrome server.
|
||||
- 📻 **Radio & Infinite Queue**: Smart Radio sessions from any song or artist, built-in Internet Radio (ICY/HLS), and an Infinite Queue that silently refills when the queue runs out.
|
||||
- 🎛️ **Advanced Audio**: 10-band graphic EQ with custom presets, **AutoEQ** headphone correction, Replay Gain, gapless playback, and crossfade.
|
||||
- 〰️ **10 Seekbar Styles**: Waveform, Bar, Thick Bar, Segmented, Line+Dot, Neon, Pulse Wave, Particle Trail, Liquid Fill, and Retro Tape.
|
||||
- 🖥️ **Fullscreen Player**: Album art, animated synced lyrics overlay, and artist image in a dedicated fullscreen view.
|
||||
- 📋 **Playlists & Library**: Full playlist management with drag-and-drop reorder and smart suggestions. Genre browsing, Random Mix, Advanced Search, ratings (1–5 stars), and multi-select actions.
|
||||
- 💾 **Device Sync**: Export your library to a USB drive or portable device using a configurable filename template.
|
||||
- 🖥️ **CLI Control**: Control playback, switch servers, manage the queue, and more directly from the command line.
|
||||
- ⌨️ **Customization**: Configurable keybindings, UI fonts, global zoom slider, system tray, backup & restore, and in-app auto-update.
|
||||
- 🌍 **8 Languages**: English, German, French, Dutch, Spanish, Chinese, Norwegian, Russian.
|
||||
- 🖥️ **Cross-Platform**: Windows, macOS, and Linux (Arch AUR, .deb, .rpm).
|
||||
|
||||
## 🛡️ Security
|
||||
## 🗺️ Roadmap
|
||||
|
||||
With the **v1.0.0 Release**, Psysonic has been hardened for public use:
|
||||
- **Secured Credentials**: Industry-standard security using Tauri's native encrypted store.
|
||||
- **Hardened Sandbox**: Restricted filesystem permissions to only necessary directories.
|
||||
- **Native Security**: Disabled global Tauri objects to significantly reduce XSS attack vectors.
|
||||
### 📋 Planned
|
||||
- [ ] Theme contrast & legibility audit — systematic review of text/background contrast ratios across all themes
|
||||
- [ ] Accessibility (a11y) — keyboard navigation, screen reader support, ARIA labels
|
||||
- [ ] More languages
|
||||
|
||||
---
|
||||
|
||||
## 📥 Installation
|
||||
|
||||
Navigate to the [Releases](https://github.com/Psychotoxical/psysonic/releases) page and download the installer for your operating system.
|
||||
|
||||
- **Windows**: `.exe` or `.msi`
|
||||
### 🐧 Linux
|
||||
|
||||
**Quick Install (Recommended):**
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Psychotoxical/psysonic/main/scripts/install.sh | sudo bash
|
||||
```
|
||||
|
||||
**Manual Installation:**
|
||||
- **Ubuntu / Debian**: `.deb` from GitHub Releases
|
||||
- **Fedora / RHEL**: `.rpm` from GitHub Releases
|
||||
|
||||
### 🍎 macOS
|
||||
|
||||
- **macOS**: `.dmg` (Universal or Apple Silicon)
|
||||
- **Linux**: `.AppImage` or `.deb`
|
||||
|
||||
> [!WARNING]
|
||||
> **Gatekeeper Note:**
|
||||
> Since the app is released without an Apple Developer certificate, macOS will block it by default. To bypass this, run the following command in the Terminal after moving the app to the Applications folder:
|
||||
> ```sh
|
||||
> xattr -cr /Applications/Psysonic.app
|
||||
> ```
|
||||
|
||||
### 🪟 Windows
|
||||
|
||||
- **Windows**: `.exe` (NSIS installer)
|
||||
|
||||
> [!WARNING]
|
||||
> **SmartScreen Note:**
|
||||
> Windows SmartScreen might show a warning because the installer isn't signed with an expensive developer certificate. Click on **"More info"** and then **"Run anyway"**.
|
||||
|
||||
## 📦 Installation (Arch Linux / AUR)
|
||||
|
||||
Psysonic is available in the **AUR** in two versions. Choose the one that best fits your needs:
|
||||
|
||||
| Package | Type | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| [**psysonic**](https://aur.archlinux.org/packages/psysonic) | **Source** | Builds from source using your system's native **WebKitGTK** (no bundled libs, no EGL/Mesa compatibility issues). |
|
||||
| [**psysonic-bin**](https://aur.archlinux.org/packages/psysonic-bin) | **Binary** | Pre-compiled version for faster installation. |
|
||||
|
||||
> [!TIP]
|
||||
> The AUR binary package is kindly provided and maintained by [**kilyabin**](https://github.com/kilyabin).
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
@@ -59,6 +120,10 @@ If you want to build Psysonic from source or contribute to the project:
|
||||
### Prerequisites
|
||||
- [Node.js](https://nodejs.org/) (v18+)
|
||||
- [Rust](https://www.rust-lang.org/) (v1.75+)
|
||||
- **`cmake`** — required to compile the bundled libopus (Opus audio support). Install it before running `cargo build` or `npm run tauri:build`:
|
||||
- Linux: `sudo apt install cmake` / `sudo pacman -S cmake`
|
||||
- macOS: `brew install cmake`
|
||||
- Windows: [cmake.org/download](https://cmake.org/download/) or `winget install cmake`
|
||||
- OS-specific build dependencies for Tauri (see the [Tauri prerequisites guide](https://tauri.app/v2/guides/getting-started/prerequisites)).
|
||||
|
||||
### Setup
|
||||
@@ -90,4 +155,10 @@ Contributions are completely welcome! Whether it is translating the app into a n
|
||||
|
||||
## 📄 License
|
||||
|
||||
Distributed under the MIT License. See `LICENSE` for more information.
|
||||
Distributed under the **GNU General Public License v3.0**. See `LICENSE` for more information.
|
||||
|
||||
This means: you are free to use, study, and modify Psysonic. If you distribute a modified version, you must release it under the same GPL v3 license and keep the original copyright notice intact. You may **not** incorporate this code into proprietary software.
|
||||
|
||||
## 🔒 Privacy
|
||||
|
||||
Psysonic contains no telemetry or analytics. All third-party integrations (Last.fm, LRCLIB, Discord) are opt-in. See [PRIVACY.md](PRIVACY.md) for full details.
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Shell completion for `psysonic`
|
||||
|
||||
Covers global flags (`--help`, `--info`, …), `completions …`, and `--player` commands (`next`, `audio-device …`, `library …`, `mix …`, …). Run `psysonic --help` for the full list.
|
||||
|
||||
The same scripts are **embedded in the release binary**: run **`psysonic completions`** for install instructions, or **`psysonic completions bash` / `zsh`** to print the scripts (no repo checkout needed).
|
||||
|
||||
## zsh
|
||||
|
||||
Copy or symlink `_psysonic` into a directory on your `$fpath`, then reload completion:
|
||||
|
||||
```sh
|
||||
mkdir -p ~/.zsh/completions
|
||||
ln -sf /path/to/psysonic/completions/_psysonic ~/.zsh/completions/_psysonic
|
||||
fpath=(~/.zsh/completions $fpath)
|
||||
autoload -Uz compinit && compinit
|
||||
```
|
||||
|
||||
If you use a plugin manager, point its `fpath` at this repo’s `completions/` directory instead.
|
||||
|
||||
## bash
|
||||
|
||||
Source the script once (e.g. in `~/.bashrc`):
|
||||
|
||||
```sh
|
||||
source /path/to/psysonic/completions/psysonic.bash
|
||||
```
|
||||
|
||||
Use this only under **bash** (including macOS’s `/bin/bash` 3.2). **zsh** users should install `_psysonic` instead — do not `source` the `.bash` file in zsh.
|
||||
|
||||
## Device names after `audio-device set`
|
||||
|
||||
Completion can suggest IDs from `psysonic-cli-audio-devices.json` (same paths the app uses: `$XDG_RUNTIME_DIR` or `$TMPDIR`/`/tmp`). That file appears after you run **`psysonic --player audio-device list`** while the app is running. Optional: install **`jq`** for parsing that JSON in the completion scripts.
|
||||
|
||||
## Folder ids after `library set`
|
||||
|
||||
Same idea with **`psysonic-cli-library.json`**, produced by **`psysonic --player library list`**. Optional **`jq`** for completion of folder ids plus the literal **`all`**.
|
||||
@@ -0,0 +1,144 @@
|
||||
#compdef psysonic
|
||||
# Zsh completion for Psysonic CLI (see `psysonic --help`).
|
||||
|
||||
_psysonic_audio_device_json() {
|
||||
local f
|
||||
if [[ -n $XDG_RUNTIME_DIR ]]; then
|
||||
f="$XDG_RUNTIME_DIR/psysonic-cli-audio-devices.json"
|
||||
[[ -r $f ]] && { print -r -- "$f"; return }
|
||||
fi
|
||||
f="${TMPDIR:-/tmp}/psysonic-cli-audio-devices.json"
|
||||
[[ -r $f ]] && print -r -- "$f"
|
||||
}
|
||||
|
||||
_psysonic_audio_device_ids() {
|
||||
command -v jq &>/dev/null || return
|
||||
local jf
|
||||
jf="$(_psysonic_audio_device_json)" || return
|
||||
local -a devs
|
||||
devs=( ${(@f)"$(jq -r '.devices[]? | select(type == "string")' "$jf" 2>/dev/null)"} )
|
||||
(( $#devs )) && compadd -a devs
|
||||
}
|
||||
|
||||
_psysonic_library_json() {
|
||||
local f
|
||||
if [[ -n $XDG_RUNTIME_DIR ]]; then
|
||||
f="$XDG_RUNTIME_DIR/psysonic-cli-library.json"
|
||||
[[ -r $f ]] && { print -r -- "$f"; return }
|
||||
fi
|
||||
f="${TMPDIR:-/tmp}/psysonic-cli-library.json"
|
||||
[[ -r $f ]] && print -r -- "$f"
|
||||
}
|
||||
|
||||
_psysonic_library_folder_ids() {
|
||||
command -v jq &>/dev/null || return
|
||||
local jf
|
||||
jf="$(_psysonic_library_json)" || return
|
||||
local -a ids
|
||||
ids=( ${(@f)"$(jq -r '.folders[]? | select(.id != null) | .id | tostring' "$jf" 2>/dev/null)"} )
|
||||
(( $#ids )) && compadd -a ids
|
||||
}
|
||||
|
||||
_psysonic_snapshot_json() {
|
||||
local f
|
||||
if [[ -n $XDG_RUNTIME_DIR ]]; then
|
||||
f="$XDG_RUNTIME_DIR/psysonic-cli-snapshot.json"
|
||||
[[ -r $f ]] && { print -r -- "$f"; return }
|
||||
fi
|
||||
f="${TMPDIR:-/tmp}/psysonic-cli-snapshot.json"
|
||||
[[ -r $f ]] && print -r -- "$f"
|
||||
}
|
||||
|
||||
_psysonic_server_ids() {
|
||||
command -v jq &>/dev/null || return
|
||||
local jf
|
||||
jf="$(_psysonic_snapshot_json)" || return
|
||||
local -a ids
|
||||
ids=( ${(@f)"$(jq -r '.servers[]? | select(.id != null) | .id | tostring' "$jf" 2>/dev/null)"} )
|
||||
(( $#ids )) && compadd -a ids
|
||||
}
|
||||
|
||||
_psysonic_globals() {
|
||||
compadd -J options -X 'option' -- \
|
||||
--help --version --info --json --quiet --player completions
|
||||
}
|
||||
|
||||
integer i pidx=0
|
||||
for (( i = 2; i < CURRENT; i++ )); do
|
||||
[[ ${words[i]} == --player ]] && pidx=i
|
||||
done
|
||||
|
||||
if (( pidx == 0 )); then
|
||||
if (( CURRENT == 3 )) && [[ ${words[2]} == completions ]]; then
|
||||
compadd help bash zsh
|
||||
return
|
||||
fi
|
||||
_psysonic_globals
|
||||
return
|
||||
fi
|
||||
|
||||
local -a sub
|
||||
if (( pidx + 1 <= CURRENT - 1 )); then
|
||||
sub=( ${words[pidx + 1,CURRENT - 1]} )
|
||||
else
|
||||
sub=()
|
||||
fi
|
||||
|
||||
integer n=${#sub[@]}
|
||||
if (( n == 0 )); then
|
||||
compadd -J verbs -X 'player command' -- \
|
||||
next prev play pause stop seek volume shuffle repeat mute unmute star unstar rating reload \
|
||||
audio-device library server search mix
|
||||
return
|
||||
fi
|
||||
|
||||
case ${sub[1]} in
|
||||
audio-device)
|
||||
if (( n == 1 )); then
|
||||
compadd list set
|
||||
elif [[ ${sub[2]} == set ]] && (( n == 2 )); then
|
||||
compadd default
|
||||
_psysonic_audio_device_ids
|
||||
fi
|
||||
;;
|
||||
library)
|
||||
if (( n == 1 )); then
|
||||
compadd list set
|
||||
elif [[ ${sub[2]} == set ]] && (( n == 2 )); then
|
||||
compadd all
|
||||
_psysonic_library_folder_ids
|
||||
fi
|
||||
;;
|
||||
mix)
|
||||
(( n == 1 )) && compadd append new
|
||||
;;
|
||||
server)
|
||||
if (( n == 1 )); then
|
||||
compadd list set
|
||||
elif [[ ${sub[2]} == set ]] && (( n == 2 )); then
|
||||
_psysonic_server_ids
|
||||
fi
|
||||
;;
|
||||
search)
|
||||
if (( n == 1 )); then
|
||||
compadd track album artist
|
||||
elif (( n >= 2 )); then
|
||||
_message -e descriptions 'search query'
|
||||
fi
|
||||
;;
|
||||
repeat)
|
||||
(( n == 1 )) && compadd off all one
|
||||
;;
|
||||
rating)
|
||||
(( n == 1 )) && compadd 0 1 2 3 4 5
|
||||
;;
|
||||
seek)
|
||||
(( n == 1 )) && _message -e descriptions 'integer delta (seconds, e.g. -5)'
|
||||
;;
|
||||
volume)
|
||||
(( n == 1 )) && _message -e descriptions 'percent 0–100'
|
||||
;;
|
||||
play)
|
||||
(( n == 1 )) && _message -e descriptions 'Subsonic id (song, album, or artist)'
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,167 @@
|
||||
# bash completion for Psysonic (see `psysonic --help`).
|
||||
# Install: source /path/to/completions/psysonic.bash
|
||||
# Optional: jq + prior `psysonic --player audio-device list` for device name completion.
|
||||
#
|
||||
# Uses no `mapfile` so bash 3.2 (macOS default) works.
|
||||
#
|
||||
# compopt is bash-only (programmable completion). Guard so sourcing this file
|
||||
# under zsh or plain sh does not print "command not found: compopt".
|
||||
|
||||
_psysonic_compopt() {
|
||||
command -v compopt &>/dev/null || return 0
|
||||
compopt "$@" 2>/dev/null || return 0
|
||||
}
|
||||
|
||||
_psysonic_compreply_from_compgen() {
|
||||
# $1 = compgen -W word list, $2 = current word
|
||||
COMPREPLY=()
|
||||
local line
|
||||
while IFS= read -r line; do
|
||||
[[ -n $line ]] && COMPREPLY+=("$line")
|
||||
done < <(compgen -W "$1" -- "$2")
|
||||
}
|
||||
|
||||
_psysonic_audio_device_json() {
|
||||
local f
|
||||
if [[ -n ${XDG_RUNTIME_DIR:-} ]]; then
|
||||
f="$XDG_RUNTIME_DIR/psysonic-cli-audio-devices.json"
|
||||
[[ -r $f ]] && { printf '%s' "$f"; return; }
|
||||
fi
|
||||
f="${TMPDIR:-/tmp}/psysonic-cli-audio-devices.json"
|
||||
[[ -r $f ]] && printf '%s' "$f"
|
||||
}
|
||||
|
||||
_psysonic_library_json() {
|
||||
local f
|
||||
if [[ -n ${XDG_RUNTIME_DIR:-} ]]; then
|
||||
f="$XDG_RUNTIME_DIR/psysonic-cli-library.json"
|
||||
[[ -r $f ]] && { printf '%s' "$f"; return; }
|
||||
fi
|
||||
f="${TMPDIR:-/tmp}/psysonic-cli-library.json"
|
||||
[[ -r $f ]] && printf '%s' "$f"
|
||||
}
|
||||
|
||||
_psysonic_snapshot_json() {
|
||||
local f
|
||||
if [[ -n ${XDG_RUNTIME_DIR:-} ]]; then
|
||||
f="$XDG_RUNTIME_DIR/psysonic-cli-snapshot.json"
|
||||
[[ -r $f ]] && { printf '%s' "$f"; return; }
|
||||
fi
|
||||
f="${TMPDIR:-/tmp}/psysonic-cli-snapshot.json"
|
||||
[[ -r $f ]] && printf '%s' "$f"
|
||||
}
|
||||
|
||||
_psysonic_complete() {
|
||||
local cur
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
|
||||
local i pidx=0
|
||||
for (( i = 1; i < COMP_CWORD; i++ )); do
|
||||
[[ ${COMP_WORDS[i]} == --player ]] && pidx=$i
|
||||
done
|
||||
|
||||
if (( pidx == 0 )); then
|
||||
if [[ ${COMP_WORDS[1]} == completions && COMP_CWORD -eq 2 ]]; then
|
||||
_psysonic_compreply_from_compgen 'help bash zsh' "$cur"
|
||||
return
|
||||
fi
|
||||
_psysonic_compreply_from_compgen '--help --version --info --json --quiet --player completions' "$cur"
|
||||
return
|
||||
fi
|
||||
|
||||
local -a sub=()
|
||||
for (( i = pidx + 1; i < COMP_CWORD; i++ )); do
|
||||
sub+=("${COMP_WORDS[i]}")
|
||||
done
|
||||
local n=${#sub[@]}
|
||||
|
||||
if (( n == 0 )); then
|
||||
_psysonic_compreply_from_compgen 'next prev play pause stop seek volume shuffle repeat mute unmute star unstar rating reload audio-device library server search mix' "$cur"
|
||||
return
|
||||
fi
|
||||
|
||||
case ${sub[0]} in
|
||||
audio-device)
|
||||
if (( n == 1 )); then
|
||||
_psysonic_compreply_from_compgen 'list set' "$cur"
|
||||
elif [[ ${sub[1]} == set ]] && (( n == 2 )); then
|
||||
COMPREPLY=()
|
||||
local jf d
|
||||
jf="$(_psysonic_audio_device_json)"
|
||||
if [[ -n $jf ]] && command -v jq &>/dev/null; then
|
||||
while IFS= read -r d; do
|
||||
[[ -n $d && $d == "$cur"* ]] && COMPREPLY+=("$d")
|
||||
done < <(jq -r '.devices[]? | select(type == "string")' "$jf" 2>/dev/null)
|
||||
fi
|
||||
while IFS= read -r line; do
|
||||
[[ -n $line ]] && COMPREPLY+=("$line")
|
||||
done < <(compgen -W 'default' -- "$cur")
|
||||
((${#COMPREPLY[@]})) && _psysonic_compopt -o filenames
|
||||
fi
|
||||
;;
|
||||
library)
|
||||
if (( n == 1 )); then
|
||||
_psysonic_compreply_from_compgen 'list set' "$cur"
|
||||
elif [[ ${sub[1]} == set ]] && (( n == 2 )); then
|
||||
COMPREPLY=()
|
||||
local jf id line
|
||||
jf="$(_psysonic_library_json)"
|
||||
if [[ -n $jf ]] && command -v jq &>/dev/null; then
|
||||
while IFS= read -r id; do
|
||||
[[ -n $id && $id == "$cur"* ]] && COMPREPLY+=("$id")
|
||||
done < <(jq -r '.folders[]? | select(.id != null) | .id | tostring' "$jf" 2>/dev/null)
|
||||
fi
|
||||
while IFS= read -r line; do
|
||||
[[ -n $line ]] && COMPREPLY+=("$line")
|
||||
done < <(compgen -W 'all' -- "$cur")
|
||||
((${#COMPREPLY[@]})) && _psysonic_compopt -o filenames
|
||||
fi
|
||||
;;
|
||||
mix)
|
||||
(( n == 1 )) && _psysonic_compreply_from_compgen 'append new' "$cur"
|
||||
;;
|
||||
server)
|
||||
if (( n == 1 )); then
|
||||
_psysonic_compreply_from_compgen 'list set' "$cur"
|
||||
elif [[ ${sub[1]} == set ]] && (( n == 2 )); then
|
||||
COMPREPLY=()
|
||||
local jf sid
|
||||
jf="$(_psysonic_snapshot_json)"
|
||||
if [[ -n $jf ]] && command -v jq &>/dev/null; then
|
||||
while IFS= read -r sid; do
|
||||
[[ -n $sid && $sid == "$cur"* ]] && COMPREPLY+=("$sid")
|
||||
done < <(jq -r '.servers[]? | select(.id != null) | .id | tostring' "$jf" 2>/dev/null)
|
||||
fi
|
||||
((${#COMPREPLY[@]})) && _psysonic_compopt -o filenames
|
||||
fi
|
||||
;;
|
||||
search)
|
||||
if (( n == 1 )); then
|
||||
_psysonic_compreply_from_compgen 'track album artist' "$cur"
|
||||
elif (( n >= 2 )); then
|
||||
_psysonic_compopt -o default
|
||||
COMPREPLY=()
|
||||
fi
|
||||
;;
|
||||
repeat)
|
||||
(( n == 1 )) && _psysonic_compreply_from_compgen 'off all one' "$cur"
|
||||
;;
|
||||
rating)
|
||||
(( n == 1 )) && _psysonic_compreply_from_compgen '0 1 2 3 4 5' "$cur"
|
||||
;;
|
||||
seek|volume)
|
||||
if (( n == 1 )); then
|
||||
_psysonic_compopt -o default
|
||||
COMPREPLY=()
|
||||
fi
|
||||
;;
|
||||
play)
|
||||
if (( n == 1 )); then
|
||||
_psysonic_compopt -o default
|
||||
COMPREPLY=()
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
complete -F _psysonic_complete psysonic
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1776169885,
|
||||
"narHash": "sha256-l/iNYDZ4bGOAFQY2q8y5OAfBBtrDAaPuRQqWaFHVRXM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4bd9165a9165d7b5e33ae57f3eecbcb28fb231c9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
description = ''
|
||||
Psysonic for NixOS / nixpkgs: installable app + dev shell.
|
||||
|
||||
Packages:
|
||||
nix build .#psysonic # or .#default — desktop app (.desktop + icon)
|
||||
nix profile install .#psysonic
|
||||
|
||||
Run (after build, or from any clone with flake):
|
||||
nix run .#psysonic
|
||||
nix run github:Psychotoxical/psysonic
|
||||
|
||||
Development:
|
||||
nix develop # mkShell (Rust/Node/WebKit deps + hooks)
|
||||
nix shell .#devShells.default # same environment without entering subshell semantics
|
||||
|
||||
Release pipeline updates `flake.lock` (nixpkgs pin refresh) and
|
||||
`nix/upstream-sources.json` (npmDepsHash) on every `v*` tag push —
|
||||
see `.github/workflows/release.yml` (verify-nix job). Package version
|
||||
is read from `package.json`; nothing in this file needs manual bumping
|
||||
per release.
|
||||
'';
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
inherit (nixpkgs) lib;
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
forSystem = f: lib.genAttrs systems f;
|
||||
|
||||
mkShellFor =
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
gstPlugins = with pkgs.gst_all_1; [
|
||||
gstreamer
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
gst-plugins-bad
|
||||
];
|
||||
gstPluginPath = pkgs.lib.makeSearchPath "lib/gstreamer-1.0" gstPlugins;
|
||||
in
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
nodejs_22
|
||||
rustc
|
||||
cargo
|
||||
cmake
|
||||
pkg-config
|
||||
openssl
|
||||
gtk3
|
||||
webkitgtk_4_1
|
||||
libsoup_3
|
||||
glib-networking
|
||||
atk
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
pango
|
||||
librsvg
|
||||
alsa-lib
|
||||
libayatana-appindicator
|
||||
]
|
||||
++ gstPlugins;
|
||||
|
||||
shellHook = ''
|
||||
export LD_LIBRARY_PATH="${pkgs.libayatana-appindicator}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
export GST_PLUGIN_PATH="${gstPluginPath}''${GST_PLUGIN_PATH:+:$GST_PLUGIN_PATH}"
|
||||
export GIO_EXTRA_MODULES="${pkgs.glib-networking}/lib/gio/modules''${GIO_EXTRA_MODULES:+:$GIO_EXTRA_MODULES}"
|
||||
export GDK_BACKEND=x11
|
||||
export WEBKIT_DISABLE_COMPOSITING_MODE=1
|
||||
export WEBKIT_DISABLE_DMABUF_RENDERER=1
|
||||
unset CI
|
||||
'';
|
||||
|
||||
OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include";
|
||||
};
|
||||
|
||||
upstreamMeta = lib.importJSON ./nix/upstream-sources.json;
|
||||
|
||||
psysonicFor =
|
||||
system:
|
||||
nixpkgs.legacyPackages.${system}.callPackage ./nix/psysonic.nix {
|
||||
src = self;
|
||||
inherit upstreamMeta;
|
||||
};
|
||||
in
|
||||
{
|
||||
devShells = forSystem (system: { default = mkShellFor system; });
|
||||
|
||||
packages = forSystem (system: {
|
||||
psysonic = psysonicFor system;
|
||||
default = psysonicFor system;
|
||||
});
|
||||
|
||||
apps = forSystem (
|
||||
system:
|
||||
let
|
||||
p = psysonicFor system;
|
||||
in
|
||||
{
|
||||
default = {
|
||||
type = "app";
|
||||
program = lib.getExe p;
|
||||
meta = {
|
||||
inherit (p.meta) description homepage license;
|
||||
mainProgram = "psysonic";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -6,9 +6,6 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="Psysonic – Dein Navidrome Desktop Player" />
|
||||
<title>Psysonic</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
# Installable Psysonic (Tauri): npm build → cargo tauri build --no-bundle.
|
||||
# Source: `self` (this repo). Package version is read from package.json.
|
||||
# `npmDepsHash` in nix/upstream-sources.json is refreshed by the release
|
||||
# workflow (see .github/workflows/release.yml, verify-nix job).
|
||||
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchNpmDeps,
|
||||
npmHooks,
|
||||
rustPlatform,
|
||||
cargo,
|
||||
rustc,
|
||||
pkg-config,
|
||||
cmake,
|
||||
openssl,
|
||||
gtk3,
|
||||
webkitgtk_4_1,
|
||||
libsoup_3,
|
||||
glib-networking,
|
||||
alsa-lib,
|
||||
libayatana-appindicator,
|
||||
atk,
|
||||
cairo,
|
||||
gdk-pixbuf,
|
||||
glib,
|
||||
pango,
|
||||
librsvg,
|
||||
cargo-tauri,
|
||||
nodejs,
|
||||
makeWrapper,
|
||||
wrapGAppsHook4,
|
||||
copyDesktopItems,
|
||||
makeDesktopItem,
|
||||
gst_all_1,
|
||||
src,
|
||||
upstreamMeta,
|
||||
}:
|
||||
|
||||
let
|
||||
version = (lib.importJSON (src + "/package.json")).version;
|
||||
# WebKit media stack needs discoverable GStreamer plugins (e.g. appsink in gst-plugins-base).
|
||||
gstPlugins = with gst_all_1; [
|
||||
gstreamer
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
gst-plugins-bad
|
||||
];
|
||||
gstPluginPath = lib.makeSearchPath "lib/gstreamer-1.0" gstPlugins;
|
||||
srcClean = lib.cleanSourceWith {
|
||||
inherit src;
|
||||
filter =
|
||||
path: _:
|
||||
let
|
||||
f = toString path;
|
||||
in
|
||||
!(lib.hasInfix "/node_modules/" f)
|
||||
&& !(lib.hasInfix "/dist/" f)
|
||||
&& !(lib.hasInfix "/target/" f)
|
||||
&& !(lib.hasInfix "/.git/" f)
|
||||
&& !(lib.hasInfix "/result/" f)
|
||||
&& !(lib.hasInfix "/.flatpak-builder/" f);
|
||||
};
|
||||
npmDeps = fetchNpmDeps {
|
||||
src = srcClean;
|
||||
hash = upstreamMeta.npmDepsHash;
|
||||
};
|
||||
cargoLockFile = src + "/src-tauri/Cargo.lock";
|
||||
in
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "psysonic";
|
||||
inherit version;
|
||||
src = srcClean;
|
||||
inherit npmDeps;
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
# cmake is only for Rust deps (e.g. libopus); no top-level CMakeLists.txt in repo root
|
||||
dontUseCmakeConfigure = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
npmHooks.npmConfigHook
|
||||
cargo
|
||||
rustc
|
||||
rustPlatform.cargoSetupHook
|
||||
pkg-config
|
||||
cmake
|
||||
makeWrapper
|
||||
wrapGAppsHook4
|
||||
copyDesktopItems
|
||||
cargo-tauri
|
||||
nodejs
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
gtk3
|
||||
webkitgtk_4_1
|
||||
libsoup_3
|
||||
glib-networking
|
||||
openssl
|
||||
alsa-lib
|
||||
libayatana-appindicator
|
||||
atk
|
||||
cairo
|
||||
gdk-pixbuf
|
||||
glib
|
||||
pango
|
||||
librsvg
|
||||
]
|
||||
++ gstPlugins;
|
||||
|
||||
cargoRoot = "src-tauri";
|
||||
cargoDeps = rustPlatform.importCargoLock {
|
||||
lockFile = cargoLockFile;
|
||||
# Local path overrides for `[patch.crates-io]` entries in src-tauri/Cargo.toml.
|
||||
# Keep in sync with that block — importCargoLock needs the source to match
|
||||
# the lockfile entries for patched crates (otherwise it tries to fetch from
|
||||
# crates.io and the hash mismatches).
|
||||
outputHashes = { };
|
||||
};
|
||||
|
||||
dontUseCargoParallelJobs = true;
|
||||
|
||||
env = {
|
||||
OPENSSL_DIR = "${openssl.dev}";
|
||||
OPENSSL_LIB_DIR = "${openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${openssl.dev}/include";
|
||||
VITE_LASTFM_API_KEY = "";
|
||||
VITE_LASTFM_API_SECRET = "";
|
||||
};
|
||||
|
||||
# beforeBuildCommand runs npm run build; npmConfigHook supplies offline node_modules
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
export HOME=$(mktemp -d)
|
||||
(cd src-tauri && cargo tauri build --no-bundle -v)
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
install -Dm755 src-tauri/target/release/psysonic -t $out/bin
|
||||
install -Dm644 src-tauri/icons/128x128.png $out/share/icons/hicolor/128x128/apps/psysonic.png
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
desktopItems = [
|
||||
(makeDesktopItem {
|
||||
name = "psysonic";
|
||||
desktopName = "Psysonic";
|
||||
comment = "Subsonic-compatible music player";
|
||||
icon = "psysonic";
|
||||
exec = "psysonic";
|
||||
categories = [ "AudioVideo" "Audio" "Player" ];
|
||||
})
|
||||
];
|
||||
|
||||
postFixup = ''
|
||||
wrapProgram $out/bin/psysonic \
|
||||
--prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ libayatana-appindicator ]}" \
|
||||
--prefix GST_PLUGIN_PATH : "${gstPluginPath}" \
|
||||
--prefix GIO_EXTRA_MODULES : "${glib-networking}/lib/gio/modules" \
|
||||
--set GDK_BACKEND x11 \
|
||||
--set WEBKIT_DISABLE_COMPOSITING_MODE 1 \
|
||||
--set WEBKIT_DISABLE_DMABUF_RENDERER 1
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Desktop music player for Subsonic-compatible servers";
|
||||
homepage = "https://github.com/Psychotoxical/psysonic";
|
||||
license = lib.licenses.gpl3Only;
|
||||
mainProgram = "psysonic";
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"npmDepsHash": "sha256-GwwfdTSGsjLvaJiSrEJPj+I027Lp6uPLkDXZJ+pDers="
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "psysonic",
|
||||
"version": "1.0.1",
|
||||
"version": "1.40.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -8,21 +8,39 @@
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri",
|
||||
"tauri:dev": "GDK_BACKEND=x11 WEBKIT_DISABLE_COMPOSITING_MODE=1 tauri dev",
|
||||
"tauri:build": "tauri build"
|
||||
"tauri:build": "tauri build",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/dm-sans": "^5.2.8",
|
||||
"@fontsource-variable/figtree": "^5.2.10",
|
||||
"@fontsource-variable/geist": "^5.2.8",
|
||||
"@fontsource-variable/golos-text": "^5.2.8",
|
||||
"@fontsource-variable/inter": "^5.2.8",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
"@fontsource-variable/lexend": "^5.2.11",
|
||||
"@fontsource-variable/manrope": "^5.2.8",
|
||||
"@fontsource-variable/nunito": "^5.2.7",
|
||||
"@fontsource-variable/outfit": "^5.2.8",
|
||||
"@fontsource-variable/plus-jakarta-sans": "^5.2.8",
|
||||
"@fontsource-variable/rubik": "^5.2.8",
|
||||
"@fontsource-variable/space-grotesk": "^5.2.10",
|
||||
"@fontsource-variable/unbounded": "^5.2.8",
|
||||
"@tanstack/react-virtual": "^3.13.23",
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-dialog": "^2.6.0",
|
||||
"@tauri-apps/plugin-fs": "^2.4.5",
|
||||
"@tauri-apps/plugin-dialog": "^2.7.0",
|
||||
"@tauri-apps/plugin-fs": "^2.5.0",
|
||||
"@tauri-apps/plugin-global-shortcut": "^2",
|
||||
"@tauri-apps/plugin-notification": "^2",
|
||||
"@tauri-apps/plugin-process": "^2.3.1",
|
||||
"@tauri-apps/plugin-shell": "^2",
|
||||
"@tauri-apps/plugin-store": "^2",
|
||||
"@tauri-apps/plugin-updater": "^2.10.0",
|
||||
"@tauri-apps/plugin-window-state": "^2.4.1",
|
||||
"axios": "^1.7.7",
|
||||
"howler": "^2.2.4",
|
||||
"i18next": "^25.8.16",
|
||||
"lucide-react": "^0.462.0",
|
||||
"md5": "^2.3.0",
|
||||
"papaparse": "^5.5.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^16.5.6",
|
||||
@@ -31,13 +49,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/howler": "^2.2.12",
|
||||
"@types/md5": "^2.3.5",
|
||||
"@types/node": "^25.3.5",
|
||||
"@types/papaparse": "^5.5.2",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^6.0.3"
|
||||
"vite": "^6.0.3",
|
||||
"vitest": "^4.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
src/
|
||||
pkg/
|
||||
*.tar.zst
|
||||
*.tar.gz
|
||||
@@ -0,0 +1,81 @@
|
||||
# Maintainer: Psychotoxic <psychotoxic@gmx.de>
|
||||
pkgname=psysonic
|
||||
pkgver=1.40.0
|
||||
pkgrel=1
|
||||
pkgdesc="Desktop music player for Subsonic API-compatible servers (Navidrome, Gonic, etc.)"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/Psychotoxical/psysonic"
|
||||
license=('GPL-3.0-only')
|
||||
depends=(
|
||||
'webkit2gtk-4.1'
|
||||
'gtk3'
|
||||
'openssl'
|
||||
'alsa-lib'
|
||||
)
|
||||
makedepends=(
|
||||
'npm'
|
||||
'rust'
|
||||
'cargo'
|
||||
'clang'
|
||||
'nasm'
|
||||
'cmake'
|
||||
)
|
||||
source=("$pkgname-$pkgver.tar.gz::https://github.com/Psychotoxical/psysonic/archive/refs/tags/v$pkgver.tar.gz")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
build() {
|
||||
cd "psysonic-$pkgver"
|
||||
|
||||
export CARGO_HOME="$srcdir/cargo-home"
|
||||
export npm_config_cache="$srcdir/npm-cache"
|
||||
|
||||
# ring (used by reqwest → rustls-tls) ships C/asm objects whose
|
||||
# symbols (ring_core_*) lld cannot resolve. On Arch/CachyOS, -fuse-ld=lld
|
||||
# is hardcoded into rustc itself (not just makepkg.conf RUSTFLAGS), so a
|
||||
# string substitution is a no-op. Appending -C link-arg=-fuse-ld=bfd works
|
||||
# because the last -fuse-ld=* flag passed to cc wins.
|
||||
export RUSTFLAGS="${RUSTFLAGS} -C link-arg=-fuse-ld=bfd"
|
||||
|
||||
# CachyOS sets -flto=auto in CFLAGS. ring compiles its C/asm objects via the
|
||||
# cc crate and picks up CFLAGS, producing fat-LTO objects. bfd cannot resolve
|
||||
# symbols from fat-LTO objects when linking against non-LTO Rust rlibs, causing
|
||||
# "undefined reference to ring_core_*" even though the symbols exist in the .a.
|
||||
# Strip CFLAGS/CXXFLAGS entirely so ring builds plain ELF objects.
|
||||
unset CFLAGS CXXFLAGS
|
||||
|
||||
npm install
|
||||
npm run tauri:build -- --no-bundle
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "psysonic-$pkgver"
|
||||
|
||||
# Binary (in /usr/lib to make room for the wrapper)
|
||||
install -Dm755 "src-tauri/target/release/psysonic" "$pkgdir/usr/lib/psysonic/psysonic"
|
||||
|
||||
# Wrapper script that sets necessary env vars for WebKitGTK on Wayland
|
||||
install -Dm755 /dev/stdin "$pkgdir/usr/bin/psysonic" <<EOF
|
||||
#!/bin/sh
|
||||
export GDK_BACKEND=x11
|
||||
export WEBKIT_DISABLE_COMPOSITING_MODE=1
|
||||
export WEBKIT_DISABLE_DMABUF_RENDERER=1
|
||||
exec /usr/lib/psysonic/psysonic "\$@"
|
||||
EOF
|
||||
|
||||
# Desktop entry
|
||||
install -Dm644 /dev/stdin "$pkgdir/usr/share/applications/psysonic.desktop" <<EOF
|
||||
[Desktop Entry]
|
||||
Name=Psysonic
|
||||
Comment=Desktop music player for Subsonic API-compatible servers
|
||||
Exec=psysonic
|
||||
Icon=psysonic
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=AudioVideo;Audio;Music;Player;
|
||||
EOF
|
||||
|
||||
# Icons
|
||||
install -Dm644 "src-tauri/icons/32x32.png" "$pkgdir/usr/share/icons/hicolor/32x32/apps/psysonic.png"
|
||||
install -Dm644 "src-tauri/icons/128x128.png" "$pkgdir/usr/share/icons/hicolor/128x128/apps/psysonic.png"
|
||||
install -Dm644 "src-tauri/icons/128x128@2x.png" "$pkgdir/usr/share/icons/hicolor/256x256/apps/psysonic.png"
|
||||
}
|
||||
|
After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="115.549mm"
|
||||
height="130.30972mm"
|
||||
viewBox="0 0 115.549 130.30972"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="p-small.svg"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"><inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="115.549"
|
||||
height="130.30972"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" /></sodipodi:namedview><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(220.53237,27.789086)"><path
|
||||
style="fill:#ffffff"
|
||||
d="m -191.83501,87.581279 v -14.93937 l 1.01946,-0.029 c 1.8496,-0.0526 5.09881,-2.007 6.98453,-4.20123 2.13731,-2.48697 3.28384,-4.43657 4.52545,-7.69521 0.51751,-1.35819 1.078,-2.78694 1.24554,-3.175 0.16755,-0.38805 0.88173,-2.7693 1.58707,-5.29166 0.70533,-2.52236 1.41605,-4.90361 1.57937,-5.29167 0.16441,-0.39067 0.30759,11.85061 0.32081,27.42847 l 0.0239,28.134031 h -8.64306 -8.64305 z m -3.42317,-19.65031 c -0.81559,-0.16111 -1.84746,-0.48272 -2.29306,-0.71468 -1.09242,-0.5687 -2.72853,-2.16884 -2.74064,-2.68038 -0.005,-0.22765 -0.38465,-0.86265 -0.84281,-1.41111 -0.8626,-1.03264 -2.38323,-4.66133 -4.63113,-11.05137 -1.72997,-4.91772 -1.63358,-4.68451 -3.35352,-8.11389 -0.82714,-1.64924 -1.91998,-3.45186 -2.42853,-4.00582 -1.28805,-1.40307 -4.41406,-2.7715 -6.89485,-3.01827 l -2.08965,-0.20785 1.43221,-0.99035 c 1.5468,-1.06957 5.31147,-2.35399 6.9124,-2.35835 1.72563,-0.005 4.25283,0.7809 5.71247,1.77575 1.63175,1.11217 3.92377,3.83335 3.77488,4.48172 -0.0559,0.24344 0.11427,0.44261 0.37817,0.44261 0.53171,0 3.78445,6.24176 3.78445,7.26208 0,0.15195 0.30609,0.92171 0.6802,1.71057 0.37412,0.78887 1.08633,2.44854 1.5827,3.68817 1.00279,2.50434 2.57055,5.33152 2.95544,5.32962 0.85183,-0.004 3.83204,-7.97894 5.40479,-14.46266 1.9193,-7.91232 5.01161,-18.44694 6.10967,-20.81389 2.30114,-4.96024 4.60601,-7.03734 8.12223,-7.31959 1.95377,-0.15683 2.44243,-0.0601 4.01261,0.79453 2.49546,1.35819 3.31044,2.35029 5.40102,6.57479 0.93741,1.89425 3.29625,9.1126 4.36446,13.35583 0.51289,2.03729 1.21262,4.57729 1.55498,5.64444 0.34236,1.06716 0.83543,2.65466 1.09573,3.52778 0.96371,3.23267 3.75139,8.2344 5.51689,9.89856 2.09506,1.9748 4.10606,3.2977 5.85136,3.84922 0.72761,0.22993 1.32292,0.49404 1.32292,0.58692 0,0.0929 -0.71641,0.48577 -1.59202,0.87309 -2.29705,1.01609 -6.48839,1.02714 -8.75823,0.0231 -3.42674,-1.51581 -6.17101,-4.45149 -8.36088,-8.94406 -0.59782,-1.22642 -1.23412,-2.50231 -1.41401,-2.8353 -0.17988,-0.333 -0.47718,-1.20612 -0.66066,-1.94028 -0.74987,-3.00045 -6.42415,-19.25706 -6.99617,-20.04376 -0.79895,-1.09881 -0.87818,-1.08476 -1.55823,0.27628 -1.1693,2.3402 -2.07427,5.18987 -3.61302,11.37709 -3.03871,12.21839 -6.36478,22.38234 -8.0081,24.47148 -0.36655,0.466 -0.66646,0.99153 -0.66646,1.16785 0,0.86017 -2.61454,3.05174 -4.28395,3.59089 -1.94625,0.62857 -2.53141,0.65417 -4.78366,0.20926 z m 49.82815,-13.29265 c -2.77991,-0.70614 -6.29714,-6.05076 -8.15323,-12.38927 -0.30389,-1.03778 -0.47868,-1.96073 -0.38841,-2.051 0.0903,-0.0903 1.5695,-0.22877 3.28719,-0.30779 8.47079,-0.38969 9.78292,-0.63406 14.05919,-2.61837 3.78653,-1.75706 9.09259,-6.79386 10.56941,-10.03304 3.78708,-8.30644 4.33485,-14.20262 2.08448,-22.4376404 -1.15336,-4.22063002 -3.6401,-8.21361 -6.73205,-10.80969 -1.12271,-0.94265 -2.12066,-1.8146 -2.21767,-1.93765 -0.3794,-0.48123 -4.30858,-2.4333296 -6.41876,-3.1889796 -2.16778,-0.77628 -2.64336,-0.79956 -18.71666,-0.91597 l -16.49236,-0.11945 V -0.68605142 10.798429 h -0.8256 c -1.53109,0 -5.09758,2.09614 -6.79456,3.99338 -1.65639,1.85186 -4.54446,7.43871 -5.41264,10.47051 -0.25002,0.87312 -0.58222,1.98437 -0.73823,2.46944 -0.39136,1.2169 -2.0765,7.30176 -3.12634,11.28889 -0.2052,0.7793 -0.33685,-11.27627 -0.35693,-32.6846104 l -0.0318,-33.9193396 1.55319,-0.12371 c 0.85426,-0.068 12.32395,-0.10028 25.4882,-0.0716 20.69377,0.045 24.2694,0.12953 26.40444,0.62402 3.9887,0.92382 7.58472,2.04932 7.58472,2.3739 0,0.16576 0.52886,0.30139 1.17524,0.30139 2.09331,0 10.76432,4.87704 10.22435,5.75072 -0.12186,0.19718 -0.0447,0.24734 0.17328,0.11263 0.60692,-0.3751 4.21691,3.0333 6.9953,6.60467 2.06429,2.6534496 4.63504,8.4775396 5.94174,13.4611396 1.7681,6.7433 1.74625,15.8657704 -0.0549,22.9305504 -2.11084,8.27937 -4.97852,13.41407 -10.75456,19.25647 -2.59968,2.62955 -8.78375,7.02548 -9.88326,7.02548 -0.27557,0 -0.68644,0.1854 -0.91304,0.412 -0.39593,0.39593 -0.78905,0.56749 -4.31522,1.88319 -3.68968,1.37672 -10.83412,2.28545 -13.21446,1.68081 z m 7.57002,-15.26489 c 0,-0.19403 -0.07,-0.35278 -0.15557,-0.35278 -0.0856,0 -0.25368,0.15875 -0.3736,0.35278 -0.11992,0.19403 -0.0499,0.35278 0.15557,0.35278 0.20548,0 0.3736,-0.15875 0.3736,-0.35278 z"
|
||||
id="path1" /></g></svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 558 KiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 937 KiB |
|
After Width: | Height: | Size: 566 KiB |
|
After Width: | Height: | Size: 365 KiB |
@@ -0,0 +1,52 @@
|
||||
# Scripts
|
||||
|
||||
## install.sh - Auto-Installer for Debian and RHEL-based Systems
|
||||
|
||||
This script automatically downloads and installs the latest Psysonic release from GitHub Releases.
|
||||
|
||||
### Supported Distributions
|
||||
|
||||
- **Debian/Ubuntu**: Downloads and installs `.deb` package
|
||||
- **RHEL/Fedora/CentOS**: Downloads and installs `.rpm` package
|
||||
|
||||
### Usage
|
||||
|
||||
#### Quick Install (Recommended)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Psychotoxical/psysonic/main/scripts/install.sh | sudo bash
|
||||
```
|
||||
|
||||
#### Manual Installation
|
||||
|
||||
```bash
|
||||
# Download the script
|
||||
wget https://raw.githubusercontent.com/Psychotoxical/psysonic/main/scripts/install.sh
|
||||
|
||||
# Make it executable
|
||||
chmod +x install.sh
|
||||
|
||||
# Run with sudo
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
### What it does
|
||||
|
||||
1. Detects your OS type (Debian or RHEL-based)
|
||||
2. Fetches the latest release from GitHub
|
||||
3. Downloads the appropriate package (.deb or .rpm)
|
||||
4. Installs it using your system's package manager
|
||||
5. Cleans up temporary files
|
||||
|
||||
### Requirements
|
||||
|
||||
- `curl` - for downloading packages
|
||||
- `sudo` or root access
|
||||
- Internet connection
|
||||
- Supported package manager (apt-get, dnf, or yum)
|
||||
|
||||
### Notes
|
||||
|
||||
- If Psysonic is already installed, the script will ask if you want to reinstall
|
||||
- The script automatically handles dependency installation for Debian systems
|
||||
- After installation, you can launch Psysonic from your application menu or by running `psysonic` in the terminal
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env node
|
||||
// Generates latest.json for the Tauri updater from a GitHub release.
|
||||
// Reads .sig files uploaded by tauri-action, assembles the manifest, writes latest.json.
|
||||
//
|
||||
// macOS-only for now — Windows + Linux are added once their signing pipelines
|
||||
// (Certum cert for Windows, native package managers for Linux) are wired up.
|
||||
//
|
||||
// Required env vars: VERSION, GITHUB_TOKEN
|
||||
// Usage: node scripts/generate-update-manifest.js
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
const VERSION = process.env.VERSION;
|
||||
const REPO = 'Psychotoxical/psysonic';
|
||||
const TAG = `app-v${VERSION}`;
|
||||
|
||||
if (!VERSION) {
|
||||
console.error('VERSION env var required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Platform → update bundle filename (produced by tauri-action with updater plugin)
|
||||
const PLATFORM_FILES = {
|
||||
'darwin-aarch64': 'Psysonic_aarch64.app.tar.gz',
|
||||
'darwin-x86_64': 'Psysonic_x64.app.tar.gz',
|
||||
};
|
||||
|
||||
const platforms = {};
|
||||
|
||||
// A real minisign .sig file is multi-line and ~200+ chars.
|
||||
// A public key (RWTxxx... single line, ~56 chars) must never appear here.
|
||||
function validateSignature(sig, platform, sigFile) {
|
||||
if (/^RWT[A-Za-z0-9+/]{10,}={0,2}$/.test(sig)) {
|
||||
throw new Error(
|
||||
`${platform}: .sig file "${sigFile}" contains a PUBLIC KEY instead of a signature.\n` +
|
||||
` Got: ${sig}\n` +
|
||||
` TAURI_SIGNING_PRIVATE_KEY must be the private key, not the public one.`
|
||||
);
|
||||
}
|
||||
if (sig.length < 80) {
|
||||
throw new Error(
|
||||
`${platform}: .sig file "${sigFile}" looks too short (${sig.length} chars) to be a valid signature.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [platform, filename] of Object.entries(PLATFORM_FILES)) {
|
||||
const sigFile = `${filename}.sig`;
|
||||
try {
|
||||
execSync(
|
||||
`gh release download "${TAG}" --repo "${REPO}" -p "${sigFile}" --clobber`,
|
||||
{ stdio: 'pipe' }
|
||||
);
|
||||
const signature = fs.readFileSync(sigFile, 'utf8').trim();
|
||||
validateSignature(signature, platform, sigFile);
|
||||
const url = `https://github.com/${REPO}/releases/download/${TAG}/${filename}`;
|
||||
platforms[platform] = { signature, url };
|
||||
console.log(`✓ ${platform}`);
|
||||
} catch (e) {
|
||||
console.warn(`⚠ Skipping ${platform}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(platforms).length === 0) {
|
||||
console.error('No platforms found — aborting manifest generation');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let notes = '';
|
||||
try {
|
||||
const raw = execSync(
|
||||
`gh release view "${TAG}" --repo "${REPO}" --json body`,
|
||||
{ stdio: 'pipe' }
|
||||
).toString();
|
||||
notes = JSON.parse(raw).body ?? '';
|
||||
} catch {
|
||||
console.warn('Could not fetch release notes');
|
||||
}
|
||||
|
||||
const manifest = {
|
||||
version: VERSION,
|
||||
notes,
|
||||
pub_date: new Date().toISOString(),
|
||||
platforms,
|
||||
};
|
||||
|
||||
fs.writeFileSync('latest.json', JSON.stringify(manifest, null, 2));
|
||||
console.log(`\nWrote latest.json for v${VERSION} with platforms: ${Object.keys(platforms).join(', ')}`);
|
||||
@@ -0,0 +1,171 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Psysonic Auto-Installer
|
||||
# Automatically detects your OS and installs the latest release from GitHub
|
||||
|
||||
REPO="Psychotoxical/psysonic"
|
||||
APP_NAME="psysonic"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
error "Please run this script as root (use sudo)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Detect package manager and OS type
|
||||
detect_os() {
|
||||
if command -v apt &> /dev/null; then
|
||||
OS_TYPE="debian"
|
||||
PACKAGE_MANAGER="apt"
|
||||
info "Detected Debian/Ubuntu-based system (apt)"
|
||||
elif command -v dnf &> /dev/null; then
|
||||
OS_TYPE="rhel"
|
||||
PACKAGE_MANAGER="dnf"
|
||||
info "Detected RHEL/Fedora-based system (dnf)"
|
||||
elif command -v yum &> /dev/null; then
|
||||
OS_TYPE="rhel"
|
||||
PACKAGE_MANAGER="yum"
|
||||
info "Detected RHEL/CentOS-based system (yum)"
|
||||
else
|
||||
error "Unsupported package manager. This installer supports Debian/Ubuntu and RHEL/Fedora/CentOS systems."
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the latest release download URL for the specific package type
|
||||
get_download_url() {
|
||||
local api_url="https://api.github.com/repos/${REPO}/releases/latest"
|
||||
|
||||
info "Fetching latest release information..."
|
||||
|
||||
local release_info
|
||||
release_info=$(curl -s "$api_url")
|
||||
|
||||
if echo "$release_info" | grep -q "message.*Not Found"; then
|
||||
error "Could not fetch release information. Please check your internet connection."
|
||||
fi
|
||||
|
||||
local tag_name
|
||||
tag_name=$(echo "$release_info" | grep -o '"tag_name": *"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
|
||||
if [ -z "$tag_name" ]; then
|
||||
error "Could not determine latest release version."
|
||||
fi
|
||||
|
||||
info "Latest version: $tag_name"
|
||||
|
||||
local download_url=""
|
||||
|
||||
if [ "$OS_TYPE" = "debian" ]; then
|
||||
download_url=$(echo "$release_info" | grep -o '"browser_download_url": *"[^"]*\.deb"' | head -1 | cut -d'"' -f4)
|
||||
elif [ "$OS_TYPE" = "rhel" ]; then
|
||||
download_url=$(echo "$release_info" | grep -o '"browser_download_url": *"[^"]*\.rpm"' | head -1 | cut -d'"' -f4)
|
||||
fi
|
||||
|
||||
if [ -z "$download_url" ]; then
|
||||
error "Could not find download URL for $OS_TYPE package."
|
||||
fi
|
||||
|
||||
echo "$download_url"
|
||||
}
|
||||
|
||||
# Install the package
|
||||
install_package() {
|
||||
local download_url="$1"
|
||||
local temp_dir
|
||||
temp_dir=$(mktemp -d)
|
||||
local package_file="$temp_dir/${APP_NAME}_latest"
|
||||
|
||||
info "Downloading package..."
|
||||
|
||||
if [ "$OS_TYPE" = "debian" ]; then
|
||||
package_file="${package_file}.deb"
|
||||
curl -L -o "$package_file" "$download_url"
|
||||
|
||||
info "Installing package..."
|
||||
$PACKAGE_MANAGER install -y "$package_file" || {
|
||||
warn "Trying to fix broken dependencies..."
|
||||
$PACKAGE_MANAGER install -f -y
|
||||
}
|
||||
elif [ "$OS_TYPE" = "rhel" ]; then
|
||||
package_file="${package_file}.rpm"
|
||||
curl -L -o "$package_file" "$download_url"
|
||||
|
||||
info "Installing package..."
|
||||
$PACKAGE_MANAGER install -y "$package_file"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$temp_dir"
|
||||
}
|
||||
|
||||
# Check if app is already installed
|
||||
check_installed() {
|
||||
if command -v $APP_NAME &> /dev/null || command -v ${APP_NAME^} &> /dev/null; then
|
||||
warn "${APP_NAME} appears to be already installed."
|
||||
read -p "Do you want to reinstall? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
info "Installation cancelled."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main installation flow
|
||||
main() {
|
||||
echo -e "${GREEN}"
|
||||
echo "╔══════════════════════════════════════════════════════════╗"
|
||||
echo "║ Psysonic Auto-Installer ║"
|
||||
echo "║ Install the latest release from GitHub Releases ║"
|
||||
echo "╚══════════════════════════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
|
||||
check_root
|
||||
detect_os
|
||||
check_installed
|
||||
|
||||
local download_url
|
||||
download_url=$(get_download_url)
|
||||
|
||||
if [ -z "$download_url" ]; then
|
||||
error "Failed to get download URL."
|
||||
fi
|
||||
|
||||
info "Download URL: $download_url"
|
||||
|
||||
install_package "$download_url"
|
||||
|
||||
echo ""
|
||||
success "Psysonic has been installed successfully!"
|
||||
echo -e "${BLUE}You can launch it from your application menu or by running:${NC} psysonic"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "psysonic"
|
||||
version = "1.0.1"
|
||||
version = "1.40.0"
|
||||
description = "Psysonic Desktop Music Player"
|
||||
authors = []
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "psysonic"
|
||||
edition = "2021"
|
||||
rust-version = "1.77.2"
|
||||
rust-version = "1.89"
|
||||
|
||||
[lib]
|
||||
name = "psysonic_lib"
|
||||
@@ -22,11 +22,67 @@ tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = ["tray-icon", "image-png"] }
|
||||
tauri-plugin-single-instance = "2"
|
||||
tauri-plugin-shell = "2"
|
||||
tauri-plugin-notification = "2"
|
||||
tauri-plugin-global-shortcut = "2"
|
||||
tauri-plugin-store = "2"
|
||||
tauri-plugin-dialog = "2"
|
||||
tauri-plugin-fs = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
rodio = { version = "0.19", default-features = false, features = ["symphonia-all"] }
|
||||
symphonia = { version = "0.5", default-features = false, features = ["flac", "mp3", "pcm", "aac", "alac", "isomp4", "vorbis", "ogg", "wav", "adpcm"] }
|
||||
reqwest = { version = "0.12", default-features = false, features = ["stream", "json", "multipart", "rustls-tls", "rustls-tls-native-roots", "blocking"] }
|
||||
futures-util = "0.3"
|
||||
md5 = "0.7"
|
||||
tokio = { version = "1", features = ["rt", "time", "sync"] }
|
||||
biquad = "0.4"
|
||||
ringbuf = "0.3"
|
||||
tauri-plugin-window-state = "2.4.1"
|
||||
tauri-plugin-process = "2"
|
||||
tauri-plugin-updater = "2"
|
||||
souvlaki = { version = "0.8", default-features = false, features = ["use_zbus"] }
|
||||
discord-rich-presence = "0.2"
|
||||
url = "2"
|
||||
thread-priority = "1"
|
||||
lofty = "0.22"
|
||||
sysinfo = { version = "0.33", default-features = false, features = ["disk"] }
|
||||
id3 = "1.16.4"
|
||||
symphonia-adapter-libopus = "0.2.7"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
zbus = { version = "5.9", default-features = false, features = ["blocking-api"] }
|
||||
# Match wry/tauri’s WebKitGTK stack — used only to turn off kinetic wheel scrolling.
|
||||
webkit2gtk = { version = "2.0", default-features = false, features = ["v2_40"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { version = "0.58", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Graphics",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_System_Com",
|
||||
"Win32_UI_Controls",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
] }
|
||||
|
||||
[patch.crates-io]
|
||||
# Local patch for Symphonia's isomp4 demuxer:
|
||||
# - Fixes descriptor.unwrap() panic on malformed esds atoms (older iTunes M4A)
|
||||
# - Tolerates SL predefined=0x01 (null) used by some older iTunes-purchased files
|
||||
# - Gracefully skips malformed trak atoms (e.g. MJPEG cover-art streams) instead
|
||||
# of failing the entire probe
|
||||
symphonia-format-isomp4 = { path = "patches/symphonia-format-isomp4" }
|
||||
|
||||
# Local patch for cpal's CoreAudio backend on macOS:
|
||||
# - Forces IOType::DefaultOutput for all output streams so that macOS never
|
||||
# triggers the TCC microphone-permission prompt. Upstream cpal uses
|
||||
# IOType::HalOutput when the user pins a non-default device, which routes
|
||||
# through AUHAL — that component is flagged as input-capable and triggers
|
||||
# the mic consent dialog on first launch / after each update.
|
||||
# - Tradeoff: output-device selection is a no-op on macOS (stream follows
|
||||
# system default). Surfaced in the Settings UI.
|
||||
cpal = { path = "patches/cpal-0.15.3" }
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- Sandbox disabled: app is unsigned/ad-hoc signed, so an active sandbox
|
||||
would restrict network access more than without it. macOS users bypass
|
||||
Gatekeeper via: xattr -cr /Applications/Psysonic.app -->
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<false/>
|
||||
|
||||
<!-- Allow outbound TCP connections to the Navidrome server (reqwest in audio.rs).
|
||||
Respected by ad-hoc signatures on some macOS versions. -->
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- Allow HTTP (non-TLS) connections so that internet radio streams and
|
||||
Navidrome servers running without HTTPS can load media in WKWebView.
|
||||
Without this, macOS App Transport Security blocks HTTP audio src. -->
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -7,8 +7,7 @@
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"shell:default",
|
||||
"shell:allow-open",
|
||||
"notification:default",
|
||||
{ "identifier": "shell:allow-open", "allow": [{ "url": "https://**" }] },
|
||||
"global-shortcut:allow-register",
|
||||
"global-shortcut:allow-unregister",
|
||||
"store:default",
|
||||
@@ -18,13 +17,27 @@
|
||||
"store:allow-save",
|
||||
"dialog:default",
|
||||
"dialog:allow-open",
|
||||
"dialog:allow-save",
|
||||
"fs:default",
|
||||
"fs:allow-write-file",
|
||||
"fs:allow-read-file",
|
||||
"fs:allow-mkdir",
|
||||
"fs:scope-download-recursive",
|
||||
"fs:scope-home-recursive",
|
||||
"window-state:allow-save-window-state",
|
||||
"window-state:allow-restore-state",
|
||||
"core:window:allow-set-title",
|
||||
"core:window:allow-close",
|
||||
"core:window:allow-minimize",
|
||||
"core:window:allow-toggle-maximize",
|
||||
"core:window:allow-hide",
|
||||
"core:window:allow-show"
|
||||
"core:window:allow-show",
|
||||
"core:window:allow-set-fullscreen",
|
||||
"core:window:allow-is-fullscreen",
|
||||
"core:window:allow-start-dragging",
|
||||
"core:window:allow-create",
|
||||
"core:webview:allow-create-webview-window",
|
||||
"process:allow-restart",
|
||||
"updater:default"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"default":{"identifier":"default","description":"Default capabilities for Psysonic","local":true,"windows":["main"],"permissions":["core:default","shell:default","shell:allow-open","notification:default","global-shortcut:allow-register","global-shortcut:allow-unregister","store:default","store:allow-load","store:allow-set","store:allow-get","store:allow-save","dialog:default","dialog:allow-open","fs:default","fs:allow-write-file","fs:allow-mkdir","fs:scope-download-recursive","core:window:allow-set-title","core:window:allow-close","core:window:allow-hide","core:window:allow-show"],"platforms":["linux","macOS","windows"]}}
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 241 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 325 KiB After Width: | Height: | Size: 310 KiB |
|
Before Width: | Height: | Size: 998 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 985 KiB After Width: | Height: | Size: 829 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "ac6cbb2ba55e61665a35ab88ae136a83380d1354"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
name: cpal
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
clippy-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Update apt
|
||||
run: sudo apt update
|
||||
- name: Install alsa
|
||||
run: sudo apt-get install libasound2-dev
|
||||
- name: Install libjack
|
||||
run: sudo apt-get install libjack-jackd2-dev libjack-jackd2-0
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
target: armv7-linux-androideabi
|
||||
- name: Run clippy
|
||||
run: cargo clippy --all --all-features
|
||||
- name: Run clippy for Android target
|
||||
run: cargo clippy --all --features asio --features oboe/fetch-prebuilt --target armv7-linux-androideabi
|
||||
|
||||
rustfmt-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt
|
||||
- name: Run rustfmt
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
cargo-publish:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Update apt
|
||||
run: sudo apt update
|
||||
- name: Install alsa
|
||||
run: sudo apt-get install libasound2-dev
|
||||
- name: Verify publish crate
|
||||
uses: katyo/publish-crates@v2
|
||||
with:
|
||||
dry-run: true
|
||||
ignore-unpublished-changes: true
|
||||
- name: Publish crate
|
||||
uses: katyo/publish-crates@v2
|
||||
with:
|
||||
ignore-unpublished-changes: true
|
||||
registry-token: ${{ secrets.CRATESIO_TOKEN }}
|
||||
|
||||
ubuntu-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Update apt
|
||||
run: sudo apt update
|
||||
- name: Install alsa
|
||||
run: sudo apt-get install libasound2-dev
|
||||
- name: Install libjack
|
||||
run: sudo apt-get install libjack-jackd2-dev libjack-jackd2-0
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Run without features
|
||||
run: cargo test --all --no-default-features --verbose
|
||||
- name: Run all features
|
||||
run: cargo test --all --all-features --verbose
|
||||
|
||||
linux-check-and-test-armv7:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install stable toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: armv7-unknown-linux-gnueabihf
|
||||
|
||||
- name: Build image
|
||||
run: docker build -t cross/cpal_armv7:v1 ./
|
||||
|
||||
- name: Install cross
|
||||
run: cargo install cross
|
||||
|
||||
- name: Check without features for armv7
|
||||
run: cross check --target armv7-unknown-linux-gnueabihf --workspace --no-default-features --verbose
|
||||
|
||||
- name: Test without features for armv7
|
||||
run: cross test --target armv7-unknown-linux-gnueabihf --workspace --no-default-features --verbose
|
||||
|
||||
- name: Check all features for armv7
|
||||
run: cross check --target armv7-unknown-linux-gnueabihf --workspace --all-features --verbose
|
||||
|
||||
- name: Test all features for armv7
|
||||
run: cross test --target armv7-unknown-linux-gnueabihf --workspace --all-features --verbose
|
||||
|
||||
asmjs-wasm32-test:
|
||||
strategy:
|
||||
matrix:
|
||||
target: [wasm32-unknown-emscripten]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Emscripten toolchain
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
- name: Build beep example
|
||||
run: cargo build --example beep --release --target ${{ matrix.target }}
|
||||
|
||||
wasm32-bindgen-test:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
target: [wasm32-unknown-unknown]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
- name: Build beep example
|
||||
run: cargo build --example beep --target ${{ matrix.target }} --features=wasm-bindgen
|
||||
|
||||
wasm32-wasi-test:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
target: [wasm32-wasi]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
- name: Build beep example
|
||||
run: cargo build --example beep --target ${{ matrix.target }}
|
||||
|
||||
windows-test:
|
||||
strategy:
|
||||
matrix:
|
||||
version: [x86_64, i686]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install ASIO SDK
|
||||
env:
|
||||
LINK: https://www.steinberg.net/asiosdk
|
||||
run: |
|
||||
curl -L -o asio.zip $env:LINK
|
||||
7z x -oasio asio.zip
|
||||
move asio\*\* asio\
|
||||
- name: Install ASIO4ALL
|
||||
run: choco install asio4all
|
||||
- name: Install llvm and clang
|
||||
run: choco install llvm
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: ${{ matrix.version }}-pc-windows-msvc
|
||||
- name: Run without features
|
||||
run: cargo test --all --no-default-features --verbose
|
||||
- name: Run all features
|
||||
run: |
|
||||
$Env:CPAL_ASIO_DIR = "$Env:GITHUB_WORKSPACE\asio"
|
||||
cargo test --all --all-features --verbose
|
||||
|
||||
macos-test:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install llvm and clang
|
||||
run: brew install llvm
|
||||
- name: Install stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Build beep example
|
||||
run: cargo build --example beep
|
||||
- name: Run without features
|
||||
run: cargo test --all --no-default-features --verbose
|
||||
- name: Run all features
|
||||
run: cargo test --all --all-features --verbose
|
||||
|
||||
android-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install stable (Android target)
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
target: armv7-linux-androideabi
|
||||
- name: Check android
|
||||
run: cargo check --example android --target armv7-linux-androideabi --features oboe/fetch-prebuilt --verbose
|
||||
- name: Check beep
|
||||
run: cargo check --example beep --target armv7-linux-androideabi --features oboe/fetch-prebuilt --verbose
|
||||
- name: Check enumerate
|
||||
run: cargo check --example enumerate --target armv7-linux-androideabi --features oboe/fetch-prebuilt --verbose
|
||||
- name: Check feedback
|
||||
run: cargo check --example feedback --target armv7-linux-androideabi --features oboe/fetch-prebuilt --verbose
|
||||
- name: Check record_wav
|
||||
run: cargo check --example record_wav --target armv7-linux-androideabi --features oboe/fetch-prebuilt --verbose
|
||||
|
||||
android-apk-build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install stable (Android targets)
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: armv7-linux-androideabi,aarch64-linux-android,i686-linux-android,x86_64-linux-android
|
||||
- name: Set Up Android tools
|
||||
run: |
|
||||
${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT --install "platforms;android-30"
|
||||
- name: Install Cargo APK
|
||||
run: cargo install cargo-apk
|
||||
- name: Build APK
|
||||
run: cargo apk build --example android
|
||||
|
||||
ios-build:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install llvm and clang
|
||||
run: brew install llvm
|
||||
- name: Install stable (iOS targets)
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: aarch64-apple-ios,x86_64-apple-ios
|
||||
- name: Install cargo lipo
|
||||
run: cargo install cargo-lipo
|
||||
- name: Build iphonesimulator feedback example
|
||||
run: cd examples/ios-feedback && xcodebuild -scheme cpal-ios-example -configuration Debug -derivedDataPath build -sdk iphonesimulator
|
||||
|
||||
wasm-beep-build:
|
||||
# this only confirms that the Rust source builds
|
||||
# and checks to prevent regressions like #721.
|
||||
#
|
||||
# It does not test the javascript/web integration
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install stable (wasm32 target)
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- name: Cargo Build
|
||||
working-directory: ./examples/wasm-beep
|
||||
run: cargo build --target wasm32-unknown-unknown
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
.cargo/
|
||||
.DS_Store
|
||||
recorded.wav
|
||||
rls*.log
|
||||
@@ -0,0 +1,196 @@
|
||||
# Unreleased
|
||||
|
||||
# Version 0.15.3 (2024-03-04)
|
||||
|
||||
- Add `try_with_sample_rate`, a non-panicking variant of `with_sample_rate`.
|
||||
- struct `platform::Stream` is now #[must_use].
|
||||
- enum `SupportedBufferSize` and struct `SupportedStreamConfigRange` are now `Copy`.
|
||||
- `platform::Device` is now `Clone`.
|
||||
- Remove `parking_lot` dependency in favor of the std library.
|
||||
- Fix crash on web/wasm when `atomics` flag is enabled.
|
||||
- Improve Examples: Migrate wasm example to `trunk`, Improve syth-thones example.
|
||||
- Improve CI: Update actions, Use Android 30 API level in CI, Remove `asmjs-unknown-emscripten` target.
|
||||
- Update `windows` dependency to v0.54
|
||||
- Update `jni` dependency to 0.21
|
||||
- Update `alsa` dependency to 0.9
|
||||
- Update `oboe` dependency to 0.6
|
||||
- Update `ndk` dependency to 0.8 and disable `default-features`.
|
||||
- Update `wasm-bindgen` to 0.2.89
|
||||
|
||||
# Version 0.15.2 (2023-03-30)
|
||||
|
||||
- webaudio: support multichannel output streams
|
||||
- Update `windows` dependency
|
||||
- wasapi: fix some thread panics
|
||||
|
||||
# Version 0.15.1 (2023-03-14)
|
||||
|
||||
- Add feature `oboe-shared-stdcxx` to enable `shared-stdcxx` on `oboe` for Android support
|
||||
- Remove `thiserror` dependency
|
||||
- Swith `mach` dependency to `mach2`
|
||||
|
||||
# Version 0.15.0 (2023-01-29)
|
||||
|
||||
- Update `windows-rs`, `jack`, `coreaudio-sys`, `oboe`, `alsa` dependencies
|
||||
- Switch to the `dasp_sample` crate for the sample trait
|
||||
- Switch to `web-sys` on the emscripten target
|
||||
- Adopt edition 2021
|
||||
- Add disconnection detection on Mac OS
|
||||
|
||||
# Version 0.14.1 (2022-10-23)
|
||||
|
||||
- Support the 0.6.1 release of `alsa-rs`
|
||||
- Fix `asio` feature broken in 0.14.0
|
||||
- `NetBSD` support
|
||||
- CI improvements
|
||||
|
||||
# Version 0.14.0 (2022-08-22)
|
||||
|
||||
- Switch to `windows-rs` crate
|
||||
- Turn `ndk-glue` into a dev-dependency and use `ndk-context` instead
|
||||
- Update dependencies (ndk, ndk-glue, parking_lot, once_cell, jack)
|
||||
|
||||
# Version 0.13.5 (2022-01-28)
|
||||
|
||||
- Faster sample format conversion
|
||||
- Update dependencies (ndk, oboe, ndk-glue, jack, alsa, nix)
|
||||
|
||||
# Version 0.13.4 (2021-08-08)
|
||||
|
||||
- wasapi: Allow both threading models and switch the default to STA
|
||||
- Update dependencies (core-foundation-sys, jni, rust-jack)
|
||||
- Alsa: improve stream setup parameters
|
||||
|
||||
# Version 0.13.3 (2021-03-29)
|
||||
|
||||
- Give each thread a unique name
|
||||
- Fix distortion regression on some alsa configs
|
||||
|
||||
# Version 0.13.2 (2021-03-16)
|
||||
|
||||
- Update dependencies (ndk, nix, oboe, jni, etc)
|
||||
|
||||
# Version 0.13.1 (2020-11-08)
|
||||
|
||||
- Don't panic when device is plugged out on Windows
|
||||
- Update `parking_lot` dependency
|
||||
|
||||
# Version 0.13.0 (2020-10-28)
|
||||
|
||||
- Add Android support via `oboe-rs`.
|
||||
- Add Android APK build an CI job.
|
||||
|
||||
# Version 0.12.1 (2020-07-23)
|
||||
|
||||
- Bugfix release to get the asio feature working again.
|
||||
|
||||
# Version 0.12.0 (2020-07-09)
|
||||
|
||||
- Large refactor removing the blocking EventLoop API.
|
||||
- Rename many `Format` types to `StreamConfig`:
|
||||
- `Format` type's `data_type` field renamed to `sample_format`.
|
||||
- `Shape` -> `StreamConfig` - The configuration input required to build a stream.
|
||||
- `Format` -> `SupportedStreamConfig` - Describes a single supported stream configuration.
|
||||
- `SupportedFormat` -> `SupportedStreamConfigRange` - Describes a range of supported configurations.
|
||||
- `Device::default_input/output_format` -> `Device::default_input/output_config`.
|
||||
- `Device::supported_input/output_formats` -> `Device::supported_input/output_configs`.
|
||||
- `Device::SupportedInput/OutputFormats` -> `Device::SupportedInput/OutputConfigs`.
|
||||
- `SupportedFormatsError` -> `SupportedStreamConfigsError`
|
||||
- `DefaultFormatError` -> `DefaultStreamConfigError`
|
||||
- `BuildStreamError::FormatNotSupported` -> `BuildStreamError::StreamConfigNotSupported`
|
||||
- Address deprecated use of `mem::uninitialized` in WASAPI.
|
||||
- Removed `UnknownTypeBuffer` in favour of specifying sample type.
|
||||
- Added `build_input/output_stream_raw` methods allowing for dynamically
|
||||
handling sample format type.
|
||||
- Added support for DragonFly platform.
|
||||
- Add `InputCallbackInfo` and `OutputCallbackInfo` types and update expected
|
||||
user data callback function signature to provide these.
|
||||
|
||||
# Version 0.11.0 (2019-12-11)
|
||||
|
||||
- Fix some underruns that could occur in ALSA.
|
||||
- Add name to `HostId`.
|
||||
- Use `snd_pcm_hw_params_set_buffer_time_near` rather than `set_buffer_time_max`
|
||||
in ALSA backend.
|
||||
- Remove many uses of `std::mem::uninitialized`.
|
||||
- Fix WASAPI capture logic.
|
||||
- Panic on stream ID overflow rather than returning an error.
|
||||
- Use `ringbuffer` crate in feedback example.
|
||||
- Move errors into a separate module.
|
||||
- Switch from `failure` to `thiserror` for error handling.
|
||||
- Add `winbase` winapi feature to solve windows compile error issues.
|
||||
- Lots of CI improvements.
|
||||
|
||||
# Version 0.10.0 (2019-07-05)
|
||||
|
||||
- core-foundation-sys and coreaudio-rs version bumps.
|
||||
- Add an ASIO host, available under Windows.
|
||||
- Introduce a new Host API, adding support for alternative audio APIs.
|
||||
- Remove sleep loop on macOS in favour of using a `Condvar`.
|
||||
- Allow users to handle stream callback errors with a new `StreamEvent` type.
|
||||
- Overhaul error handling throughout the crate.
|
||||
- Remove unnecessary Mutex from ALSA and WASAPI backends in favour of channels.
|
||||
- Remove `panic!` from OutputBuffer Deref impl as it is no longer necessary.
|
||||
|
||||
# Version 0.9.0 (2019-06-06)
|
||||
|
||||
- Better buffer handling
|
||||
- Fix logic error in frame/sample size
|
||||
- Added error handling for unknown ALSA device errors
|
||||
- Fix resuming a paused stream on Windows (wasapi).
|
||||
- Implement `default_output_format` for emscripten backend.
|
||||
|
||||
# Version 0.8.1 (2018-03-18)
|
||||
|
||||
- Fix the handling of non-default sample rates for coreaudio input streams.
|
||||
|
||||
# Version 0.8.0 (2018-02-15)
|
||||
|
||||
- Add `record_wav.rs` example. Records 3 seconds to
|
||||
`$CARGO_MANIFEST_DIR/recorded.wav` using default input device.
|
||||
- Update `enumerate.rs` example to display default input/output devices and
|
||||
formats.
|
||||
- Add input stream support to coreaudio, alsa and windows backends.
|
||||
- Introduce `StreamData` type for handling either input or output streams in
|
||||
`EventLoop::run` callback.
|
||||
- Add `Device::supported_{input/output}_formats` methods.
|
||||
- Add `Device::default_{input/output}_format` methods.
|
||||
- Add `default_{input/output}_device` functions.
|
||||
- Replace usage of `Voice` with `Stream` throughout the crate.
|
||||
- Remove `Endpoint` in favour of `Device` for supporting both input and output
|
||||
streams.
|
||||
|
||||
# Version 0.7.0 (2018-02-04)
|
||||
|
||||
- Rename `ChannelsCount` to `ChannelCount`.
|
||||
- Rename `SamplesRate` to `SampleRate`.
|
||||
- Rename the `min_samples_rate` field of `SupportedFormat` to `min_sample_rate`
|
||||
- Rename the `with_max_samples_rate()` method of`SupportedFormat` to `with_max_sample_rate()`
|
||||
- Rename the `samples_rate` field of `Format` to `sample_rate`
|
||||
- Changed the type of the `channels` field of the `SupportedFormat` struct from `Vec<ChannelPosition>` to `ChannelCount` (an alias to `u16`)
|
||||
- Remove unused ChannelPosition API.
|
||||
- Implement `Endpoint` and `Format` Enumeration for macOS.
|
||||
- Implement format handling for macos `build_voice` method.
|
||||
|
||||
# Version 0.6.0 (2017-12-11)
|
||||
|
||||
- Changed the emscripten backend to consume less CPU.
|
||||
- Added improvements to the crate documentation.
|
||||
- Implement `pause` and `play` for ALSA backend.
|
||||
- Reduced the number of allocations in the CoreAudio backend.
|
||||
- Fixes for macOS build (#186, #189).
|
||||
|
||||
# Version 0.5.1 (2017-10-21)
|
||||
|
||||
- Added `Sample::to_i16()`, `Sample::to_u16()` and `Sample::from`.
|
||||
|
||||
# Version 0.5.0 (2017-10-21)
|
||||
|
||||
- Removed the dependency on the `futures` library.
|
||||
- Removed the `Voice` and `SamplesStream` types.
|
||||
- Added `EventLoop::build_voice`, `EventLoop::destroy_voice`, `EventLoop::play`,
|
||||
and `EventLoop::pause` that can be used to create, destroy, play and pause voices.
|
||||
- Added a `VoiceId` struct that is now used to identify a voice owned by an `EventLoop`.
|
||||
- Changed `EventLoop::run()` to take a callback that is called whenever a voice requires sound data.
|
||||
- Changed `supported_formats()` to produce a list of `SupportedFormat` instead of `Format`. A
|
||||
`SupportedFormat` must then be turned into a `Format` in order to build a voice.
|
||||
@@ -0,0 +1,184 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
name = "cpal"
|
||||
version = "0.15.3"
|
||||
description = "Low-level cross-platform audio I/O library in pure Rust."
|
||||
documentation = "https://docs.rs/cpal"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"audio",
|
||||
"sound",
|
||||
]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/rustaudio/cpal"
|
||||
|
||||
[[example]]
|
||||
name = "android"
|
||||
crate-type = ["cdylib"]
|
||||
path = "examples/android.rs"
|
||||
|
||||
[[example]]
|
||||
name = "beep"
|
||||
|
||||
[[example]]
|
||||
name = "enumerate"
|
||||
|
||||
[[example]]
|
||||
name = "feedback"
|
||||
|
||||
[[example]]
|
||||
name = "record_wav"
|
||||
|
||||
[[example]]
|
||||
name = "synth_tones"
|
||||
|
||||
[dependencies.dasp_sample]
|
||||
version = "0.11"
|
||||
|
||||
[dev-dependencies.anyhow]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.clap]
|
||||
version = "4.0"
|
||||
features = ["derive"]
|
||||
|
||||
[dev-dependencies.hound]
|
||||
version = "3.5"
|
||||
|
||||
[dev-dependencies.ringbuf]
|
||||
version = "0.3"
|
||||
|
||||
[features]
|
||||
asio = [
|
||||
"asio-sys",
|
||||
"num-traits",
|
||||
]
|
||||
oboe-shared-stdcxx = ["oboe/shared-stdcxx"]
|
||||
|
||||
[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.js-sys]
|
||||
version = "0.3.35"
|
||||
|
||||
[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.wasm-bindgen]
|
||||
version = "0.2.58"
|
||||
optional = true
|
||||
|
||||
[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.web-sys]
|
||||
version = "0.3.35"
|
||||
features = [
|
||||
"AudioContext",
|
||||
"AudioContextOptions",
|
||||
"AudioBuffer",
|
||||
"AudioBufferSourceNode",
|
||||
"AudioNode",
|
||||
"AudioDestinationNode",
|
||||
"Window",
|
||||
"AudioContextState",
|
||||
]
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\"))".dependencies.alsa]
|
||||
version = "0.9"
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\"))".dependencies.jack]
|
||||
version = "0.11"
|
||||
optional = true
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\"))".dependencies.libc]
|
||||
version = "0.2"
|
||||
|
||||
[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.core-foundation-sys]
|
||||
version = "0.8.2"
|
||||
|
||||
[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.mach2]
|
||||
version = "0.4"
|
||||
|
||||
[target."cfg(target_os = \"android\")".dependencies.jni]
|
||||
version = "0.21"
|
||||
|
||||
[target."cfg(target_os = \"android\")".dependencies.ndk]
|
||||
version = "0.8"
|
||||
default-features = false
|
||||
|
||||
[target."cfg(target_os = \"android\")".dependencies.ndk-context]
|
||||
version = "0.1"
|
||||
|
||||
[target."cfg(target_os = \"android\")".dependencies.oboe]
|
||||
version = "0.6"
|
||||
features = ["java-interface"]
|
||||
|
||||
[target."cfg(target_os = \"android\")".dev-dependencies.ndk-glue]
|
||||
version = "0.7"
|
||||
|
||||
[target."cfg(target_os = \"emscripten\")".dependencies.js-sys]
|
||||
version = "0.3.35"
|
||||
|
||||
[target."cfg(target_os = \"emscripten\")".dependencies.wasm-bindgen]
|
||||
version = "0.2.89"
|
||||
|
||||
[target."cfg(target_os = \"emscripten\")".dependencies.wasm-bindgen-futures]
|
||||
version = "0.4.33"
|
||||
|
||||
[target."cfg(target_os = \"emscripten\")".dependencies.web-sys]
|
||||
version = "0.3.35"
|
||||
features = [
|
||||
"AudioContext",
|
||||
"AudioContextOptions",
|
||||
"AudioBuffer",
|
||||
"AudioBufferSourceNode",
|
||||
"AudioNode",
|
||||
"AudioDestinationNode",
|
||||
"Window",
|
||||
"AudioContextState",
|
||||
]
|
||||
|
||||
[target."cfg(target_os = \"ios\")".dependencies.coreaudio-rs]
|
||||
version = "0.11"
|
||||
features = [
|
||||
"audio_unit",
|
||||
"core_audio",
|
||||
"audio_toolbox",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[target."cfg(target_os = \"macos\")".dependencies.coreaudio-rs]
|
||||
version = "0.11"
|
||||
features = [
|
||||
"audio_unit",
|
||||
"core_audio",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies.asio-sys]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies.num-traits]
|
||||
version = "0.2.6"
|
||||
optional = true
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies.windows]
|
||||
version = "0.54.0"
|
||||
features = [
|
||||
"Win32_Media_Audio",
|
||||
"Win32_Foundation",
|
||||
"Win32_Devices_Properties",
|
||||
"Win32_Media_KernelStreaming",
|
||||
"Win32_System_Com_StructuredStorage",
|
||||
"Win32_System_Threading",
|
||||
"Win32_Security",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_Variant",
|
||||
"Win32_Media_Multimedia",
|
||||
"Win32_UI_Shell_PropertiesSystem",
|
||||
]
|
||||