Ampache8 for Admins
WORK IN PROGRESS
Ampache8 for Admins
This page will cover the visual, backend and Admin specific changes to Ampache.
User specific changes are available at Ampache8 for Users
There are a few changes in Ampache8 that might block you upgrading.
Consider all the changes before upgrading.
Try it out Ampache8 using git
The develop branch is holding the current WIP of Ampache8.
NOTE This used to be the develop8 branch. Ampache8 is now the mainline, so develop is Ampache8 and the Ampache7 line lives on release7.
You can check out a new install on the branch.
git clone -b develop https://github.com/ampache/ampache.git ampache8
Or you can pull the branch onto your current system.
git checkout develop
If you were already tracking develop8, point your checkout at the new branch.
git fetch origin
git checkout develop
If you have any issues you can reset the branch forcibly with.
git reset --hard origin/develop
Then after the reset make sure you run composer and NPM.
composer update --no-dev --prefer-source
npm install
npm run build
You can verify your NPM install has complete using the verify:install command.
npm run verify:install
Docker
We will start building official Ampache8 images for docker closer to release.
In the meantime the docker-compose.yml in the repository is now a full development stack.
It builds docker/Dockerfilephp85 (PHP 8.5) and adds a MariaDB service with a persistent volume and healthcheck.
New environment variables allow a zero-touch first run: DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, AMPACHE_DB_USER, AMPACHE_DB_PASSWORD, AMPACHE_ADMIN_USER, AMPACHE_ADMIN_PASSWORD and AMPACHE_ADMIN_EMAIL.
The entrypoint creates the .htaccess files from their .dist versions, runs composer and npm when missing, installs the database and creates the admin user.
Set DB_NAME to an empty value if you want to use the web installer instead.
The php8.2, php8.3 and php8.4 Dockerfiles have been removed.
Rollback to Ampache7
Ampache8 now makes real database changes. (New tables, new preferences and data resets)
Ampache 7.10.0 added the downgrade path from Ampache8 so make sure you are on the latest Ampache7 release before trying it out.
To go back, check out your Ampache7 branch and run the update command; the database will be downgraded to match your version.
php bin/cli admin:updateDatabase -e

PHP Version support
The first major change is that Ampache8 supports PHP8.5+ ONLY!
Builds will no longer support other versions.
Your distribution probably doesn't ship PHP8.5 yet, and you don't have to wait for it.
Both of the third party repositories below are maintained by the people who package PHP for the distributions themselves.
PHP8.5 on Debian and Ubuntu (Sury)
On Debian, add the Sury repository.
sudo apt-get update
sudo apt-get -y install lsb-release ca-certificates curl
sudo curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
sudo apt-get update
On Ubuntu, use the same maintainer's PPA instead.
sudo add-apt-repository ppa:ondrej/php
sudo apt update
Then install the versioned packages Ampache needs.
sudo apt install php8.5 php8.5-curl php8.5-gd php8.5-intl php8.5-mbstring php8.5-mysql php8.5-xml php8.5-zip
Every version is co-installable, so PHP8.5 goes on beside the one your system already uses.
PHP8.5 on RHEL, Rocky, Alma and Fedora (Remi)
Install the release package for your version, replacing 9 with 10 on Enterprise Linux 10.
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
On Fedora use the matching Fedora release package instead.
sudo dnf install https://rpms.remirepo.net/fedora/remi-release-43.rpm
Then switch the module stream to PHP8.5 and install.
dnf module list php
sudo dnf module reset php
sudo dnf module install php:remi-8.5
sudo dnf install php-curl php-gd php-intl php-mbstring php-mysqlnd php-xml php-zip
Run dnf module list php first to confirm the stream name on your release.
Staying on Ampache7 instead
If you can't move your server yet, stay on the patch7 or release7 branch by checking out the git branch.
git checkout patch7
PHP fileinfo extension is required
To make sure the new Captcha works, the core php fileinfo module is being used.
This is usually included in Linux with PHP installs but platforms like Windows may require that you enable the extension.
In your php.ini, make sure the extension is uncommented.
extension=fileinfo
Transcoding bitrates are sent in full bps: remove the k from your config
Ampache 7.8.0 asked you to add a k to all %BITRATE% values in your encode_args_* settings.
Ampache8 reverses this: the bitrate is now expanded to full bps before it is inserted into your transcode command.
The config defaults have changed from %BITRATE%k back to %BITRATE%.
; e.g. the new default mp3 encode args
encode_args_mp3 = "-vn -b:a %BITRATE% -c:a libmp3lame -f mp3 pipe:1"
NOTE This can not be updated automatically in your config file. If you keep the k your transcoder will be asked for bitrates like 128000k, so check every encode_args_ parameter when upgrading. (encode_args_ts still uses %MAXBITRATE%k)
New output profiles are available if you want to add them to your own encode_args_* config: mp3_rg, mp3_car, opus_rg and opus_car (ReplayGain-aware variants, never written to the transcode cache), plus a fragmented-MP4 m4a profile.
Transcoding preferences moved per-user
encode_target, encode_video_target and the per-player encode_player_webplayer_target/encode_player_api_target settings used to live only in ampache.cfg.php. In Ampache8 they are per-user preferences under Streaming -> Transcoding instead; your existing config values just seed the default the first time a user's preferences are created on upgrade, so nothing changes for users until they open that page.
Two more per-user preferences add dynamic downsampling: max_bit_rate/min_bit_rate let a user cap and floor their own transcode bitrate, and transcode_bitrate_webplayer/transcode_bitrate_api override the bitrate per-player (0 uses the site default transcode_bitrate).
An explicit format= request parameter still always takes priority over the target preferences.
Playlist art mosaic
Automatically generated playlist cover art can now be a mosaic of up to nine covers from the playlist instead of a single random cover. Playlists with fewer than four distinct covers keep the old single-cover behaviour.
; DEFAULT: "true"
playlist_art_mosaic = "true"
Set playlist_art_mosaic_fallback to true if you'd rather a playlist with no art of its own got a generated mosaic than the blank placeholder; the image is only built once and then stored as that playlist's own art.
; DEFAULT: "false"
;playlist_art_mosaic_fallback = "true"
Statistical Graphs no longer need ext-gd
Graphs are now drawn by goat1000/svggraph (LGPL-3.0) instead of szymach/c-pchart. Since it's a normal dependency rather than a dev-only one, a release download works out of the box with nothing extra to install — see the updated Charts and Graphs page.
Graphs render as SVG instead of PNG, so they scale to the page and stay sharp on a high-dpi screen, and statistical_graphs now defaults to "true". Set it to "false" to skip the graph queries entirely on a very large catalog.
Database changes for Ampache8
Ampache8 brings the first new database updates since the version split.
- New tables
folderandfolder_mapholding a virtual folder tree for each catalog - New tables
object_count_summaryandobject_count_archivefor play history consolidation folderadded to theobject_typeenum oncache_object_count,cache_object_count_run,image,object_count,rating,tag_map,user_activityanduser_flag- New
user.subsonic_secretcolumn holding the per-user Subsonic Password - New
last_playedcolumn onalbum,album_disk,artist,podcast,podcast_episode,songandvideo, backfilled from your existing play history - New tables
collectionandcollection_mapholding collections collectionadded to theobject_typeenum oncache_object_count,cache_object_count_run,image,object_count,object_count_archive,object_count_summary,ratinganduser_flag- The
unique_collection_mapkey was dropped fromcollection_map, so whether a collection may hold the same object twice is decided by the per-userunique_playlistpreference rather than by the schema - New
position_ms,playback_rateandstatecolumns onnow_playing, holding what an OpenSubsonic client reports throughreportPlayback - New
artist.lastfm_urlcolumn keeping the last.fm page url with the rest of the cached artist info label_assogains a nullablealbumcolumn and itsartistcolumn becomes nullable, so a label can be associated with an album as well as an artist- New preference
api_enable_8(Allow Ampache API8 responses) - New preference
show_folder(Show 'Folders' link in the main sidebar) - New preference
show_collection(Show 'Collections' link in the main sidebar) - New preference
mini_player(Lock this user into the mini player interface) - New per-user transcoding preferences:
encode_target,encode_video_target,encode_player_webplayer_target,encode_player_api_target,max_bit_rate,min_bit_rate,transcode_bitrate_webplayerandtranscode_bitrate_api— see Transcoding preferences moved per-user - Removed preferences
webplayer_flash,webplayer_auroraandplay2 - Any user with
subsonic_legacyenabled has it disabled (OpenSubsonic becomes the default) - Any
direct_play_limitset to 0 (unlimited) is reset to a cap of 500 tracks - Existing
transcode_bitratevalues are migrated to bits per second (see Transcoding bitrates are sent in full bps above) - Dropped four redundant
object_countindexes that duplicated or prefixedobject_count_UNIQUE_IDX/object_count_date_IDX - Uploaded art with a corrected mime type (
.jpgno longer stored as the invalidimage/jpg)
NOTE The object_type enum updates also delete orphaned rows that reference an invalid object type. This is bad data cleanup but it is destructive, so back up your database before updating.
Play history consolidation
Large, long-running servers can end up with millions of rows in object_count. Ampache8 can now roll old detail rows up into summary counts.
Set stats_consolidate_threshold in your config to the number of days of detailed play history you want to keep (the default 0 disables consolidation entirely):
; Keep 2 years of detailed history, consolidate anything older
stats_consolidate_threshold = 730
Run the new CLI command to consolidate anything past the threshold. Like most cleanup commands it defaults to a dry-run; pass -e to actually write:
php bin/cli cleanup:consolidateStats -e
Consolidation is lossless: nothing is discarded. Detail rows past the threshold move into object_count_archive and get rolled up into object_count_summary; play counts, played flags and streamed data size stay exact. Only period-based statistics (trending, recent, graphs, Last.fm export), smart playlist play-history rules, and play-count sorting only see the retained window — and the "Recently Played" smart playlist rule only reaches back as far as the retained window, since it needs individual timestamps.
If you need the detail back (to re-run a report over the full history, or you consolidated too aggressively), restore it with:
php bin/cli cleanup:restoreStats -e
This puts the archived detail rows back and regenerates the album, album_disk, artist and podcast counts from them.
An example systemd unit and timer for running consolidation on a schedule is in docs/examples.
OpenID Connect (OIDC) login
Ampache8 adds a new oidc auth method so you can log in through a single OpenID Connect provider. (Keycloak, Entra ID, Authentik, Google, Okta, ...)
Add oidc to your auth_methods and keep mysql in the list so local accounts can still log in.
auth_methods = "mysql,oidc"
The login uses the authorization code flow with PKCE (S256) and only one provider is supported.
Register the redirect uri <web_path>/oidc/ with your provider. It carries no query string and needs no extra webserver configuration.
Three keys are required; discovery fills in the rest from /.well-known/openid-configuration.
; Provider base url
oidc_url = "https://idp.example.com/realms/ampache"
; The confidential client registered with your provider
oidc_client_id = "ampache"
oidc_client_secret = "secret"
Users are matched by the claim in oidc_username_claim (default preferred_username) and are provisioned through the existing auto_create, auto_user and external_auto_update settings, exactly like LDAP.
Optional claim mappings copy provider data to the account: oidc_name_claim, oidc_email_claim, oidc_website_claim, oidc_state_claim and oidc_city_claim.
Other keys: oidc_issuer, oidc_scopes, oidc_use_userinfo, oidc_button_text, oidc_auto_redirect, oidc_cert_path, oidc_disable_ssl_verify and manual endpoint overrides (oidc_authorization_endpoint, oidc_token_endpoint, oidc_userinfo_endpoint, oidc_jwks_uri, oidc_end_session_endpoint) for providers without discovery.
Enable oidc_auto_redirect to skip the local login form entirely; the local form stays reachable at login.php?force_display=1.
Point logout_redirect at your provider's end_session_endpoint to sign out of the provider as well.
NOTE OIDC users can not authenticate with a username and password, so give them an API key for API clients. (user_create_apikey will do this automatically for new users)

Updated captcha with OCR testing
The old easycaptcha code has finally been replaced with Gregwar/Captcha.
The library will generate a picture and then test it by using convert and ocrad to read the file.
If ocrad can read the captcha phrase it will generate a new file and try again.
In Debian you can install these packages to enable OCR testing:
- graphicsmagick-imagemagick-compat: (/usr/bin/convert)
- ocrad: (/usr/bin/ocrad)
If you don't have these programs installed the code will generate a picture without testing the result.
NOTE This was also backported to Ampache 7.10.0 for security.
Folders: a virtual filesystem view of your catalogs
Ampache8 can map every song, podcast episode and video to its filesystem folder and let users browse the tree.
The folder tables are not filled automatically; scan them from the catalog pages.
- Each catalog's action dropdown gains a Scan Folders action
- The Manage Catalogs page gains a Scan All Folders action


The sidebar Folders link only appears once the folder table has data and the show_folder preference is enabled.
WebDAV browsing has been rewritten on top of the folder tree, so WebDAV clients now see your real folder hierarchy.
Collections: curate a list of anything
A collection is a hand-curated list that is not restricted to playable things.
A playlist can only hold media and a smartlist is built from rules, so neither can hold an album, an artist or a genre.
Albums, album disks, artists, genres, labels, live streams, playlists, podcasts, episodes, songs and videos can all sit in the same collection.
Nothing creates collections for you, so the tables stay empty until someone makes one.
A collection can be left mixed or pinned to a single type, after which anything else is refused when it is added.
A collection is ordered, and the order is part of the data. Members keep the order they were curated into, new ones are appended, and positions stay dense and 1-based, so they are renumbered after anything is added, removed or moved. Members are addressed by their membership row rather than by the object they point at, which is what makes duplicates unambiguous.
Whether a collection may hold the same object twice follows the existing per-user unique_playlist preference rather than a rule of its own. It is off by default, so duplicates are allowed by default, exactly as they are for that user's playlists. There is no separate collection setting to configure.
Playing one expands its members, so an album contributes its songs and anything unplayable is skipped.
Visibility and collaborators work exactly like playlists: a collaborator is allowed to change the contents, only the owner or an admin can delete the list.
The sidebar Collections link appears whenever the show_collection preference is enabled — it no longer waits for a collection to exist, so there is a way in from a fresh install. The preference also gates the collection half of the add-to-list dialog; a server with collections off still just says "Add to playlist".

The web interface covers the whole lifecycle: a Create Collection button on the collections browse, the standard edit dialog for name, visibility, pinned type and collaborators, the art picker, drag-to-reorder with Save Track Order on a mixed collection, per-row and Multi-Select removal, and delete.
Adding is through the same add-to-list dialog as playlists, which now offers both under a "Playlists" and a "Collections" heading. Only the halves that can take what is being added are offered, so a genre offers collections alone — a playlist stores the media an item expands to, and a genre expands to nothing. Genres and labels gained that control for the first time, since both can be collected even though only one can go in a playlist.
API access is covered by the API8 collection methods; the REST paths are under collections/.
Mini player
There's a new stripped-down /m/ page showing only the home category plugins and the web player, aimed at small screens and simple accounts.
The mini_player preference (admin-only, per user) locks a user into that page — it hides the rest of the interface but is not an access control, since the user's normal access level still decides what data they can reach. Logging in returns the user to whatever page they originally asked for, including old index.php#page.php?... links.
A new Mini player button appears on the login form, next to Register and Lost Password, so anyone can jump straight to /m/ after logging in without an admin needing to set the preference. Hide that button site-wide with the new show_mini_player config option:
; DEFAULT: "true"
show_mini_player = "false"
/m/ itself stays reachable by url either way.
The play2 stream action has been removed
The alternative play2 playback action has been merged into the normal play action.
Old action=play2 links keep working through a redirect, and the play2 preference has been removed.
The Web Player is HTML5 only
The Flash fallback (jquery.jplayer.swf) and the Aurora.js JavaScript decoders have been deleted.
The webplayer_flash and webplayer_aurora preferences are removed with them.
If your browser can not play a format natively, enable transcoding for it.
API8 is here
API version 8 joins the concurrent live surfaces (3, 4, 5 and 6) and is the new default API version.
If you send a version 7 API call you will now receive an access denied error.
- New
api_enable_8preference to enable/disable API8 responses per user - API8 returns real HTTP status codes for errors and empty results (API3-6 always returned 200)
- API error messages are US English and are not translated
- Parameters for
POST/PUT/PATCH/DELETEmay be sent as a JSON request body as well as a query string or a form - New methods including
folders,playlist_remove,randomand zip downloads for whole containers viadownload - New collection methods
collections,collection,collection_items,collection_create,collection_edit,collection_delete,collection_addandcollection_remove - Album disks are reachable at last:
album_disks,album_diskandalbum_disk_songs, plusalbum_disksupport inindex,list,browse,statsandget_art. With the per-useralbum_grouppreference off the web interface browses album disks, and until now the API had no way to see the same objects - New
sonic_matchmethod (RESTsongs/{song_id}/sonic-match) returning songs that sound like a given song, each with a similarity score on the same 0.0-1.0 scale as the OpenSubsonicsonicMatchfield. It needs a sonic analysis plugin, and refuses the request rather than returning an empty list when none is enabled
NOTE album_disk, sonic_match and random are API8 only. API6 is served by both Ampache7 and Ampache8 and has to stay identical between them, so anything new lands on API8 alone.
The REST interface is documented with a full OpenAPI spec at ampache.org/rest/swagger.
Two specs are published there: openapi.json for the current API8 surface, and openapi-6.json pinned to API6 for clients that also need to work against Ampache7. See the REST API docs for the differences.
All changes will be documented in the API before final release.
OpenSubsonic is now forced as the default Subsonic implementation
After a lot of poor implementation the split between Subsonic and Opensubsonic is now very clear.
When updating to Ampache8 all users will default to OpenSubsonic to ensure that everyone is using the latest version.
Users can still disable OpenSubsonic but the old implementation is now 1.16.1 compatible and does not support OpenSubsonic extensions.
Subsonic transcoding now converts the client maxBitRate correctly, so clients asking for e.g. 128kbps actually get 128kbps.
OpenSubsonic now implements the full specification
Ampache8 implements every endpoint in the OpenSubsonic specification and reports ten extensions.
Four are new: transcoding, playbackReport, topSongsByArtistId and sonicSimilarity.
XML responses now carry the same OpenSubsonic fields as JSON, which was not the case before.
Songs, albums, videos and podcast episodes now report played, the date and time they were last streamed.
NOTE The internet radio station response field was being sent as homepageUrl instead of homePageUrl.
This was wrong on the plain Subsonic API too, so a client reading that field will start seeing it for the first time.
sonicSimilarity needs a sonic analysis plugin, which is a new plugin type in Ampache8.
Without one, getSonicSimilarTracks and findSonicPath report the feature as unsupported.
The new AudioMuse plugin provides it by talking to an AudioMuse-AI server that you run yourself.
Setup and how it works is documented in AudioMuse.
The full extension list and what is left out is in the Subsonic API docs.
NOTE The REST paths, including everything under /rest/, need webserver rewrite rules to work at all.
If your Subsonic clients get a 404 from every request, that is almost always the cause.
See Rewrite Rules for Apache, nginx and the other supported webservers.
A dedicated Subsonic Password
Subsonic token auth (t/s params) has always needed the server to recompute md5(password + salt), which Ampache can't do against a normal hashed account password — until now that meant handing your API key to a Subsonic client as its "password".
Ampache8 adds a separate, per-user Subsonic Password, settable from the user's own account page, the admin user-edit page, or the CLI:
php bin/cli admin:updateUser some-user --subsonic "a-different-password"
It's stored encrypted with secret_key (not hashed, since the server has to recover the plaintext to compute the token), so changing secret_key invalidates every stored Subsonic Password. The API key keeps working as the Subsonic password too, for both token and plaintext auth, so existing clients don't need reconfiguring.
Faster catalog scans
Catalog verify, clean and add have been reworked to cache file lists, query less and skip non-media files early.
Large catalogs should see noticeably faster update and clean actions.
Placeholder labels are filtered out of your catalog
Publisher tags often hold placeholder text instead of a real label.
Discogs-sourced tags write [no label] and Not On Label (Artist Self-released) for releases that never had a publisher, and rippers leave behind fragments like /v/.
These are no longer created while scanning, and the catalog clean up removes the ones earlier scans already imported.
NOTE This deletes rows from the label table on your next catalog clean up, along with the art, ratings and shouts attached to them.
A label a user created by hand is never removed, however odd its name looks; only imported labels are swept.
Which names count as placeholders is a regex you control.
; DEFAULT: "^\[no label\]|^not on label\b|^\[fwd:|^self[\s-]*released?\b|\(self[\s-]*released?\)|^[^\p{L}\p{N}]*[\p{L}\p{N}]?[^\p{L}\p{N}]*$"
;label_ignore_pattern = "^\[no label\]|^not on label\b"
It is matched case-insensitively against the whole name, and setting it replaces the default rather than adding to it.
The last branch of the default drops names holding fewer than two letters or digits, such as /< or /v/, while leaving short real labels like XL and 4AD alone.
Set it to a pattern that cannot match, such as (?!), to keep every name you have.
Label pages list albums
A label page now has an Albums tab beside its artists and songs.
The scanner records a release's label tag against the album, which is also what the OpenSubsonic AlbumID3.recordLabels field reports.

Debug page hides more secrets
The admin debug page now masks LDAP, MusicBrainz, proxy, Spotify, Last.fm and OIDC secrets along with your secret_key.
It also shows the PHP version and the last auto-update check time.
Song previews come from iTunes and Deezer
The 7digital plugin has been deleted; the api it called no longer exists, so song previews on the wanted list had been dead for some time.
Two new plugins replace it, iTunes and Deezer, and either one on its own is enough. Install them from Admin → Modules → Plugins.
Neither needs an api key, an account or a preference, so nothing has to be signed up for or configured after installing.
The sample is played straight from the provider's url — Ampache stores the link and answers a preview request with a redirect, so no preview traffic passes through your server.
Neither provider indexes MusicBrainz ids, so a track is looked up by artist and title text. Results that aren't a close enough match are dropped, so a track that can't be found gives no preview instead of playing a different song.
Database 800040 removes the 7digital_api_key and 7digital_secret_api_key preferences along with the plugin's installed version row. Nothing is needed from you; if you had 7digital installed it simply disappears from the module list.
Plugins that provided previews also lose their streaming half: stream_song_preview() and the SONG_PREVIEW_STREAM_PROVIDER plugin type are gone, and a preview plugin now only implements get_song_preview(). See Writing Plugins if you maintain one of your own.
Config changes
The config version has been bumped from 89 to 95 over the course of Ampache8 development, adding:
stats_consolidate_threshold— see Play history consolidationplaylist_art_mosaicandplaylist_art_mosaic_fallback— see Playlist art mosaicshow_mini_player— see Mini playerlabel_ignore_pattern— see Placeholder labels are filtered out of your catalogallow_lost_password— set tofalseto hide theLost Passwordlink on the login page and rejectlostpassword.phpoutright, so nobody can trigger reset mail to your users by posting to it directly. Only relevant on a server with mail enabled; without mail the feature is already off
; DEFAULT: "true"
;allow_lost_password = "false"
api_debug_handler has been removed entirely.
New Options
New site options and preferences are documented in wiki at ampache8-for-users