Compare commits

...
5 Commits
6 changed files with 363 additions and 0 deletions

No files matched your search

+24
View File
@@ -102,6 +102,30 @@ too. From a checkout, `nix develop` gives you `uv`, `ruff` and the audio tools
for the usual `uv sync` / `uv run pytest` workflow; `nix build` builds and
tests the package.
### Arch Linux
The `aur/PKGBUILD` here is AUR-ready, but the package is not published in the
AUR: the AUR has closed new sign-ups, so there is no account to push it to.
Build and install it from a checkout instead:
```bash
git clone https://tildeforge.dev/beefcarver/beefy-player
cd beefy-player/aur
makepkg -si # needs base-devel; builds, runs the test suite, installs
```
Once the AUR accepts new accounts again, the package can be published and
`paru -S beefy-player` / `yay -S beefy-player` will work; until then `makepkg`
is the only route. The `aur/PKGBUILD` is tracked and kept in sync with every
release either way.
The Python side is pulled in automatically. For audio, the output-synced
spectrum and image passthrough through tmux, install the optional tools too:
```bash
sudo pacman -S mpv ffmpeg libpulse tmux
```
### From source
```bash
+28
View File
@@ -0,0 +1,28 @@
pkgbase = beefy-player
pkgdesc = Flashy terminal player for internet radio with a live spectrum analyser
pkgver = 1.2.2
pkgrel = 1
url = https://tildeforge.dev/beefcarver/beefy-player
arch = any
license = WTFPL
depends = python
depends = python-dbus-next
depends = python-httpx
depends = python-numpy
depends = python-pillow
depends = python-rich
depends = python-textual
makedepends = python-build
makedepends = python-hatchling
makedepends = python-installer
makedepends = python-wheel
checkdepends = python-pytest
checkdepends = python-pytest-asyncio
optdepends = ffmpeg: decode the stream for the spectrum analyser, and ffplay as the audio fallback
optdepends = libpulse: capture the output monitor so the analyser follows what you hear (parec/pactl)
optdepends = mpv: preferred audio backend
optdepends = tmux: detect the outer terminal for kitty graphics passthrough inside tmux
source = beefy-player-1.2.2.tar.gz::https://tildeforge.dev/beefcarver/beefy-player/archive/941c7446384bf346e40d1438a7ce67939d9615df.tar.gz
sha256sums = 8ac568676ef5ef8345441c28e4f8f5d61fb06d5225e566ac578acae18672c778
pkgname = beefy-player
+59
View File
@@ -0,0 +1,59 @@
# Maintainer: beefy-player contributors <beefcarver@tilde.club>
pkgname=beefy-player
pkgver=1.2.2
pkgrel=1
pkgdesc="Flashy terminal player for internet radio with a live spectrum analyser"
arch=('any')
url="https://tildeforge.dev/beefcarver/beefy-player"
license=('WTFPL')
depends=(
'python'
'python-dbus-next'
'python-httpx'
'python-numpy'
'python-pillow'
'python-rich'
'python-textual'
)
makedepends=(
'python-build'
'python-hatchling'
'python-installer'
'python-wheel'
)
checkdepends=(
'python-pytest'
'python-pytest-asyncio'
)
optdepends=(
'ffmpeg: decode the stream for the spectrum analyser, and ffplay as the audio fallback'
'libpulse: capture the output monitor so the analyser follows what you hear (parec/pactl)'
'mpv: preferred audio backend'
'tmux: detect the outer terminal for kitty graphics passthrough inside tmux'
)
# Upstream does not tag releases yet, so the source is the archive of the
# commit that carries this version. Once a `v$pkgver` tag exists, switch to
#
# source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
#
_commit=941c7446384bf346e40d1438a7ce67939d9615df
source=("$pkgname-$pkgver.tar.gz::$url/archive/$_commit.tar.gz")
sha256sums=('8ac568676ef5ef8345441c28e4f8f5d61fb06d5225e566ac578acae18672c778')
build() {
cd "$pkgname"
python -m build --wheel --no-isolation
}
check() {
cd "$pkgname"
# The suite is offline: catalogues are fixtures, mpv/parec are faked.
python -m pytest -q
}
package() {
cd "$pkgname"
python -m installer --destdir="$pkgdir" dist/*.whl
}
+81
View File
@@ -0,0 +1,81 @@
# AUR packaging for beefy-player
An AUR repository holds exactly two tracked files, `PKGBUILD` and `.SRCINFO`.
This directory is the staging area for both; the rest of the project is
irrelevant to the AUR.
## Build it locally
```bash
cd aur
makepkg -si # build, run the test suite, install
```
`makepkg -o && makepkg -e` skips the download/checksum phase, and
`extra-x86_64-build` (devtools) builds in a clean chroot. The package builds
with `base-devel` plus the `makedepends`/`checkdepends` listed in the
`PKGBUILD`; every dependency comes from the official repositories, none from
the AUR.
## Publish to the AUR
```bash
git clone ssh://aur@aur.archlinux.org/beefy-player.git /tmp/aur-beefy-player
cp PKGBUILD .SRCINFO /tmp/aur-beefy-player/
cd /tmp/aur-beefy-player
git add PKGBUILD .SRCINFO
git commit -m "Initial import: beefy-player 1.2.2-1"
git push
```
## Releasing a new version
1. Set `pkgver` in `PKGBUILD` and `pyproject.toml`, and reset `pkgrel=1`.
2. Point `_commit` at the commit carrying that version:
```bash
git rev-parse HEAD # or the tag, once one exists
```
3. Refresh the checksum:
```bash
curl -fsSL "https://tildeforge.dev/beefcarver/beefy-player/archive/$_commit.tar.gz" | sha256sum
```
4. Regenerate the metadata (on Arch, or inside a chroot):
```bash
makepkg --printsrcinfo > .SRCINFO
```
5. Push to the AUR with the conventional commit message:
```bash
git commit -am "upgpkg: beefy-player <pkgver>-<pkgrel>"
```
## Why the source is a commit archive
Upstream publishes no tags or releases, so the checksum in `sha256sums`
belongs to the archive of a specific commit rather than of a `v$pkgver` tag.
Forge archives of a commit are deterministic, so the checksum stays stable.
Once `v$pkgver` is tagged, replace the `source` line with
```bash
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
```
## Packaging notes
- The wheel is built with `hatchling`; `theme.tcss` is force-included by
`pyproject.toml`, so it ends up in `site-packages/beefy_player/`.
- `check()` runs the real test suite. It is offline by design (station
catalogues are fixtures and `mpv`/`parec` are faked), which makes it safe in
a build chroot with no network.
- `mpv`, `ffmpeg`, `libpulse` (`parec`/`pactl`) and `tmux` are `optdepends`,
not `depends`: the player degrades gracefully without them and says so in
the UI. Users who want sound need `mpv` (or `ffmpeg` for `ffplay`) and, for
the output-synced spectrum, `libpulse`.
- `license=('WTFPL')` is an SPDX identifier shipped by Arch's `licenses`
package.
+51
View File
@@ -0,0 +1,51 @@
class BeefyPlayer < Formula
include Language::Python::Virtualenv
desc "Terminal player for internet radio with a live spectrum analyser"
homepage "https://tildeforge.dev/beefcarver/beefy-player"
url "https://tildeforge.dev/beefcarver/beefy-player/releases/download/v1.2.2/beefy-player-1.2.2.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000" # TODO: release asset
license "WTFPL"
head "https://tildeforge.dev/beefcarver/beefy-player.git", branch: "main"
depends_on "python@3.14"
# numpy and pillow are large native builds. Depending on Homebrew's own
# formulae (which have bottles) keeps them out of the app's virtualenv build;
# the venv sees them through system site-packages.
depends_on "numpy"
depends_on "pillow"
# Runtime tools the app shells out to: mpv for audio, ffmpeg for the stream
# decode fallback of the spectrum analyser. Both are optional at runtime --
# the UI degrades gracefully -- but a radio player without them is not much fun.
depends_on "ffmpeg"
depends_on "mpv"
# Tells `brew update-python-resources` what to resolve: numpy/pillow come from
# the formulae above, and dbus-next is marker-gated to Linux upstream so it
# has to be requested explicitly for the Linux side of the tap.
pypi_packages exclude_packages: "numpy,pillow", extra_packages: "dbus-next"
def install
# system_site_packages is the default, so the excluded numpy/pillow from the
# formulae are importable from the virtualenv.
virtualenv_install_with_resources
end
def caveats
<<~EOS
The spectrum analyser follows what you hear. On macOS 14.2+ grant your
terminal permission under System Settings > Privacy & Security > System
Audio Recording, otherwise it falls back to decoding the stream.
Inside tmux, install `tmux` for image passthrough.
EOS
end
test do
assert_match version.to_s, shell_output("#{bin}/beefy-player --version")
# --offline keeps the test hermetic: cached or bundled stations only.
assert_match(/^# /, shell_output("#{bin}/beefy-player --offline --list"))
end
end
+120
View File
@@ -0,0 +1,120 @@
# Homebrew packaging for beefy-player
A Homebrew **tap** is just a second git repository that Homebrew clones next to
homebrew/core. There is no central submission, no review and no binary host:
`brew` reads the Ruby formula from the tap, downloads the pinned source tarball
and installs it on the user's machine.
This directory is the staging area for the tap repository, which lives at
**https://tildeforge.dev/beefcarver/homebrew-tap** (repo name `homebrew-tap`, so
the tap name is `beefcarver/tap`).
Because Homebrew's one-argument `brew tap` assumes GitHub, a Forgejo tap has to
be tapped with its URL, and Homebrew 6+ also wants an explicit trust.
## Install (user side)
```bash
brew tap beefcarver/tap https://tildeforge.dev/beefcarver/homebrew-tap
brew trust --formula beefcarver/tap/beefy-player
brew install beefcarver/tap/beefy-player
```
`brew update` refreshes the tap from then on; `brew upgrade` picks up new
versions like any core formula. If the tap is mirrored to GitHub later,
`brew install beefcarver/tap/beefy-player` becomes a one-liner, because that
form auto-taps from GitHub and trusts only the formula it installs.
## Publishing the tap (maintainer side)
### 1. One tag per release, with a release asset
The formula pins a stable URL plus a SHA-256, so it needs an immutable tarball.
Do **not** point it at Forgejo's `/archive/v$VERSION.tar.gz` URL: those archives
are generated on demand and are not guaranteed byte-stable. Attach a tarball to
the release instead (Forgejo serves it at `/releases/download/<tag>/<file>`):
```bash
VERSION=$(uv run python -c 'import beefy_player; print(beefy_player.__version__)')
git archive --format=tar.gz --prefix="beefy-player-$VERSION/" \
-o "beefy-player-$VERSION.tar.gz" "v$VERSION"
sha256sum "beefy-player-$VERSION.tar.gz"
```
Create the tag on the mirror (`git push tildeforge "v$VERSION"`), upload the
tarball to the `v$VERSION` release, then paste the URL and checksum into
`Formula/b/beefy-player.rb`.
### 2. Resolve the Python resources
Every Python dependency (and its recursive dependencies) that is not provided by
another formula must be declared as a `resource` so Homebrew installs with
dependency resolution disabled. Never write these by hand:
```bash
brew tap beefcarver/tap /path/to/homebrew-tap # local clone, or the URL
brew update-python-resources --print-only beefcarver/tap/beefy-player
brew update-python-resources beefcarver/tap/beefy-player
```
`pypi_packages exclude_packages: "numpy,pillow"` keeps the two native builds out
of the resource list — they come from the `numpy`/`pillow` formulae, which ship
bottles, and the virtualenv picks them up through system site-packages.
`extra_packages: "dbus-next"` makes sure the Linux-only dependency is recorded
even though the resolver runs on macOS.
In a third-party tap, `--ignore-errors` records anything that cannot be resolved
and leaves a `RESOURCE-ERROR` comment; the official taps do not allow that, a
personal one does.
### 3. Build, test and audit locally
```bash
brew install --build-from-source beefcarver/tap/beefy-player
brew test beefcarver/tap/beefy-player
brew audit --strict beefcarver/tap/beefy-player
brew style beefcarver/tap/beefy-player
```
The formula's `test do` block runs `--version` and `--offline --list`, so it
needs no network and no audio device.
### 4. Push
```bash
git add Formula/b/beefy-player.rb && git commit -m 'beefy-player 1.2.2' && git push
```
## Version bumps
For each release: tag, upload the tarball, update `url`/`sha256`, rerun
`brew update-python-resources` (only needed when the dependency set or pins
changed), install from source, test, push. `brew bump-formula-pr` only works
against GitHub-hosted taps, so on Forgejo the bump is a `sed` plus a re-test.
Optional `livecheck` support, so `brew livecheck --tap beefcarver/tap` can spot
new tags:
```ruby
livecheck do
url "https://tildeforge.dev/beefcarver/beefy-player/tags"
regex(/^v?(\d+(?:\.\d+)+)$/i)
end
```
## Bottles (optional)
Without a `bottle do` block users build from source — for this app that means
filling a virtualenv with pure-Python resources while `numpy`, `pillow`, `mpv`
and `ffmpeg` arrive as bottles, so it is quick. Prebuilt bottles need Homebrew's
GitHub Actions workflows, which cannot run on Forgejo; skip them unless the tap
is also mirrored to GitHub.
## Why a tap and not homebrew-core
homebrew-core requires a tagged, immutable source URL and enough notability to
be accepted at all (roughly 75+ stars / 30+ forks, or coverage that makes a
project notable). A tap has none of those constraints, which is why upstream
taps are the normal route for a project this size. The formula here follows
core's conventions, so it could be submitted there later unchanged if the
project qualifies.