Partyflow is a self-hostable music release manager (think Bandcamp) with a built-in on-demand transcoder, written in Java 17. The media formats it offers are customizable, but it ships with a large collection of pre-defined formats tuned to provide the best balance between filesize and audio fidelity.
Some of its headline features are gapless playback, native ReplayGain 2 support, metadata management (including album art formats not supported by FFmpeg), and a slick lightweight JS-optional web UI with customizable colors.
Partyflow is not yet complete. Some features are still missing, but the bulk of it is in place.
(What's currently working)
- In-browser setup
- Can use an embedded H2SQL database or connect to MariaDB
- Album and track art
- Creating releases
- Adding tracks
- On-the-fly transcoding
- Gapless playback
- ReplayGain 2
- Downloading tracks and release ZIPs
- Giving tracks lyrics and descriptions (Markdown when JS is off, WYSIWYG when JS is on)
- fdkaac and qaac support for AAC encoding (optional)
- yt-dlp integration (e.g. download FLACs directly from yt-dlp)
- All names can contain arbitrary Unicode
- Automatic AGPL compliance
- Abstracted storage backend; currently supports S3 and local filesystem
- Volumes above 100%
- Automatic extraction and organization of existing metadata from uploaded masters
- Automatic pruning of old transcodes that haven't been downloaded lately
- Download counts that don't count multiple downloads from the same IP (anonymously, via bloom filter)
- The core is becoming increasingly nice to use
(What still needs work)
- No way to make new accounts
- No way to pay for releases
- No per-user color customization yet
- Can't set the release date on releases to the past (for backcatalog)
- Can't override templates or static files
- No translation support
(Assorted notes about things needing improvement)
- If you're logged in as admin it's not possible to view a release/track as a normal user
- This is now a lot less bad as I ported over the new player to the edit page
- Halfway through a refactor to move business logic into *Api classes that also expose a JSON HTTP API
- Halfway through a refactor to put all SQL queries in one place for ease of reference
- All the SQL queries need to be confirmed to be compatible with MariaDB; I've tested a major number but not quite all
- Some stuff needs to get migrated to use Jetty APIs instead of pointlessly reimplementing it, like query strings
- All the booleans under "formats" should get moved into the database and controlled from the admin UI
- The core really needs to become a library so it can be reused
- I've never tested it on Windows but it probably works?
If you're okay with it being unfinished as described above, here's what you need to do to run it:
Release JARs are not yet provided for Partyflow. You'll need to install a Java 17 JDK and build the project like so (the Gradle wrapper will download Gradle for you):
./gradlew build
The resultant JAR will be in build/libs
.
Copy partyflow-config.sample.jkson
to partyflow-config.jkson
in the directory you intend to run
Partyflow in. Edit it to your liking; it's well-commented.
The config format is not yet stable. If you update Partyflow, your config may no longer work in the new version due to reorganization. If you have issues, start over from the current example.
Run the Partyflow jar with Java 17 in the same directory as the configuration. The database will be automatically initialized as described in the config.
A secret key is printed in the log if Partyflow is started with no defined admin users. Navigating
to the Partyflow instance will redirect you to /setup
, allowing you to create an admin user. That
secret key is required to perform the setup.
Under "Things you can do" while logged in as admin, one of the options is "Create a release". This will take you through the release creation flow. Once you've created the release and some tracks, you can publish the release and send the link to others to allow them to stream it or download it in a variety of formats.
Partyflow ships with 20 predefined transcode formats, for streaming and download. You can change the
config key formats.definitions
to a file path to replace the built-in formats with your own. You
will likely want to use the built-in formats.jkson
as a reference, as it's a fairly complex format.
If you need to add non-FFmpeg programs, you can add arbitrarily-named altcmds into the config in the same place as fdkaac and qaac, and utilize them within your custom format definitions file.
If you simply want to add new formats rather than changing or removing existing ones, then you can
set additionalDefinitions
instead, which will add additional formats on top of those already
defined. The format is the same.
FFmpeg has a built-in AAC encoder, but it is comically awful. As Partyflow is supposed to ship with good defaults for audio encoding, it flat out does not support it. Instead, you will need to do one of the following:
This is the easiest by far — it's even just available for install in a lot of distros. On Debian,
simply enabling the contrib
repository means it's a sudo apt install fdkaac
away.
Further information on FDK AAC can be found on the excellent HydrogenAudio wiki.
Once it's installed, you can make use of it by setting aacMode
in the config under formats
to
"fdkaac".
qaac is an open source wrapper tool for Apple's CoreAudio encoders, which were ported to Windows as part of Apple Application Support — a helper library that comes with most of Apple's Windows applications.
We have a wiki page explaining this process.
Note: qaac in Wine is very slow.
Once it's installed, you can make use of it by setting aacMode
in the config under formats
to
"qaac".
If you've already got an FFmpeg build with libfdk_aac support, you can reduce the involved moving
parts by setting aacMode
in the config under formats
to "ffmpeg-fdk". If your FFmpeg build does
not have libfdk_aac support, it is much easier to use the standalone fdkaac tool.
Once you've done any of these, you can, at your own risk, set allowEncumberedFormats
under
formats
in the config to true
.