A media player built with xo-app.
  • C 98.2%
  • JavaScript 1.1%
  • Shell 0.3%
  • Makefile 0.2%
  • CSS 0.1%
Find a file
xo corvus 1c03a3da1b
All checks were successful
/ linux release (push) Successful in 36s
/ windows debug, tests under wine (push) Successful in 10m49s
/ windows release (push) Successful in 30s
/ linux debug, tests (push) Successful in 12m5s
/ linux screenshots (push) Successful in 50s
/ windows screenshots under wine (push) Successful in 50s
/ android apk (push) Successful in 22s
/ receiver, gcast.xo.codes (push) Successful in 20s
/ development build (push) Successful in 41s
receiver: bars at the sung line's edges, page turns early on the last row, small play mark, no shuffle/repeat marks, smaller logo
2026-11-13 14:11:12 -08:00
.forgejo/workflows a job that deploys receiver/ to gcast.xo.codes 2026-11-13 01:20:42 -08:00
android finding Chromecasts over mDNS 2026-11-12 21:40:48 -08:00
assets a development update channel, and CI putting up each build of main for it 2026-11-03 00:33:59 -08:00
receiver receiver: bars at the sung line's edges, page turns early on the last row, small play mark, no shuffle/repeat marks, smaller logo 2026-11-13 14:11:12 -08:00
src cast_output: nothing is queued while the player hasn't heard the device went on 2026-11-13 12:37:03 -08:00
stage sheet outline round its top, Manage on now playing's menu, avoid for the byline, hold picks as it buzzes 2026-11-03 02:17:53 -08:00
test live queue tests: the idle between items is printed, not forbidden 2026-11-13 12:52:26 -08:00
tools casttone: an APK that casts a tone to a Chromecast from a phone 2026-11-12 21:36:20 -08:00
.clang-format initial commit 2026-10-06 12:14:30 -07:00
.gitattributes fusion pixel as the font, scale in settings 2026-10-07 12:23:24 -07:00
.gitignore initial commit 2026-10-06 12:14:30 -07:00
build-darwin.bash scripts marked executable 2026-10-08 11:08:08 -07:00
build-linux.bash the language's words in one table, written out as vocab.json; skin-check lays pages out, with a fixture per mistake 2026-10-19 14:51:16 -07:00
build-win32.cmd the language's words in one table, written out as vocab.json; skin-check lays pages out, with a fixture per mistake 2026-10-19 14:51:16 -07:00
LICENSE GPL 3 2026-10-12 11:24:34 -07:00
README.md a development update channel, and CI putting up each build of main for it 2026-11-03 00:33:59 -08:00

paradise

A music player, built on xo-app. Windows, Linux and Android.

Checking It Out

paradise builds xo-app and its skins from the folders beside it, so check all three out side by side:

xo-app/
paradise/
paradise-skins/

The build stops if ../paradise-skins isn't there. The skins and their language, skin.pss, are documented in paradise-skins' README.

Building

Same toolchain as xo-app: clang, the MSYS2 mingw64 sysroot on Windows (XA_SYSROOT), llvm-mingw and Wine to cross-build Windows from Linux. xo-app's README has the details.

  • Windows: build-win32.cmd
  • Linux: build-linux.bash. win32 in its arguments cross-builds for Windows.
  • Android: android in either script's arguments, x86_64 with it for the emulator instead of arm64-v8a.
  • macOS: build-darwin.bash exists and says it's not supported yet.

Both scripts compile in parallel, a job to each CPU. --serial in the arguments, or XA_JOBS=1 in the environment, builds one file at a time; XA_JOBS=N sets the count.

Output goes to out/<platform>-<config>/: paradise, skin-check, pss-vocab, and fonts/LICENSES and any skins beside them. The skins are the ones committed in paradise-skins but the two built into the exe, paradise and paradise-phone; a copy that isn't a git checkout ships everything in it, with a warning.

argument
debug The default.
release Built for size, LTO.
run Builds, then runs it. On Android it installs the APK with adb and starts it.
test Builds and runs the tests. On Linux, that's test, asan, tsan and test-release one after another.
test-release The tests, built as release is.
asan, tsan Linux only. The tests under the address and undefined, or the thread, sanitizer.
install A release build that runs as paradise, copied to %LOCALAPPDATA%\Programs\paradise or ${XDG_DATA_HOME:-~/.local/share}/paradise/app with its fonts and skins. Its settings are copied over the dev build's.
stage Linux only, win32 too for the Windows build under Wine. A screenshot of paradise over stage/wallpaper.png, into out/<platform>-stage/shots. Wants xvfb-desktop on PATH; xo-app's .forgejo/ci-image has one.
profile Windows only, with a config: release profile, debug profile. paradise and xo-app built for Superluminal, into out/win32-<config>-profile/ in each, as xo-app's README has it.
format, format-check clang-format over the code, or check it's formatted. clang-format 23, as in xo-app.
clean Deletes out/.

XA_TEST_ARGS is passed to the tests.

VERSION, as 1.4.2, builds it as that version, with minor and patch under 100. 1.4.2-dev.57 is the development stream's 57th build on the way to 1.4.2, which says its commit too, and isn't for Android. Without it, it's dev and the commit. The APK's versionCode is 10402 for 1.4.2.

UPDATES=1 builds a paradise that updates itself from git.xo.codes, once its user turns that on: from the releases, each checked against the public key in assets/update.pub (or the file UPDATE_KEY names), or from the development stream, checked against assets/update-dev.pub (or DEV_KEY), as the user picks under Updates from. Neither takes what the other's key signed. Only the release and development builds have it; Android never does. Switching it on or off in an out/ folder already built needs a clean first. PARADISE_UPDATE_URL in the environment points such a build at another release's JSON, for trying one before it's out. What's there still has to be signed with the build's key.

Every build checks the online catalog's index against the public key in assets/catalog.pub (or the file CATALOG_KEY names), the one xo-apps/paradise-plugins is signed with. PARADISE_CATALOG_URL points it at a copy of that repo somewhere else, with the same /raw/... paths; the index there still has to be signed with that key.

Everything but install and stage runs as paradise-dev, with its own settings and skins folder, and leaves an installed paradise alone.

Android

The build makes out/android-<abi>-<config>/paradise.apk. It wants ANDROID_HOME and ANDROID_NDK set, a JDK's bin on PATH, and platform-tools for run. xo-app's android-tools.txt has the versions it's built with. paradise's target SDK is the newest platforms/android-* under ANDROID_HOME, the minimum API 26.

  • The package name is codes.xo.paradise unless ANDROID_PACKAGE says otherwise.
  • It's signed with ~/.xo-app/debug.keystore, made on the first build and shared by every checkout, unless ANDROID_KEYSTORE names another, with its password in the file ANDROID_KEYSTORE_PASS.
  • The platform and build-tools are the ones in xo-app's android-tools.txt, and the APK's entries are in order with one date, so the same commit and VERSION make the same APK anywhere.
  • The skins that aren't built in and fonts/LICENSES go in as assets, copied out on the first start.

Command Line

paradise [--phone WxH] [--insets L,T,R,B] [--dev] [--hidden] [--] [FILE...]
  • FILE... - files and folders to play.
  • --dev - Dev mode on, as the settings page turns it on: phone-only skins offered, and the skin loads again when its files change.
  • --phone WxH - a phone's skin opens at this many physical pixels, as on a phone, and lays out as it would there: a phone under 320 points wide gets 320 and everything drawn smaller.
  • --insets L,T,R,B - physical pixels that pretend bars cover, left, top, right, bottom.
  • --hidden - nothing shown to start. Launching it again shows it.
  • -- - everything after it is a file.

An option it doesn't know, or a bad value, is skipped with a warning.

Working on It

  • test/manual.md has the checks that need a person.
  • skin-check PATH... loads skins, with their variants, and add-ons' .pxt without opening anything and prints each problem with its line. paradise-skins' README says how. test/skin-check holds a skin, a variant or an add-on for each mistake it finds, the first line of each saying what it prints.
  • tools/vscode-skin is a VS Code extension for .pss and .pxt; its README says how to install it. What it knows of the language is vocab.json, which build-win32.cmd vocab or ./build-linux.bash vocab writes from the code after the language changes. The vocab tests fail until it's written.
  • tools/release.bash VERSION LEVEL makes a release from Windows, with Linux and the APK built in WSL: builds from clean copies of the three repos' pushed commits, signs release.txt and the APK, tags all three and publishes it on git.xo.codes. --dry-run stops before tagging. The keys and the token come from the environment; the top of the script says which.
  • tools/publish-dev.bash is the development stream: the Windows build of what's checked out, signed with the development key and put up as the dev prerelease, keeping that build's zip and the one before. CI's dev-release job runs it after every push to main that passes, and does nothing while the repository has no PARADISE_DEV_KEY secret. It won't put up a build older than, or made of the same commits as, the one that's up. --dry-run builds and signs into out/publish-dev and puts up nothing.
  • .forgejo/workflows/ci.yml checks out xo-app and paradise-skins beside it and runs the Linux tests, skin-check over the skins and the test skin and format-check, release builds, the Windows tests under Wine, the stage screenshots, the Android APK, built but not run, and on main the development build.

License

GPL 3.0 or later, in LICENSE. The Selawik and Noto fonts xo-app builds in, and the icons under android carry their own licences, in assets/fonts/LICENSES and android/LICENSES. The Jellyfin logo on now playing's source line is the Jellyfin project's, redrawn by Simple Icons; its notice is in assets/licences/jellyfin.txt. Lief is Lady Liefy's, marked CC0 1.0.