Allow users to provide their own Butterchurn presets (#1309)

* Allow users to provide their own Butterchurn presets

* Ensure entrypoints have anchor links
This commit is contained in:
Jordan Eldredge 2025-07-15 16:58:52 -07:00 committed by GitHub
parent e82db4cddd
commit 6f8f85c865
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 67 additions and 20 deletions

View file

@ -6,7 +6,7 @@ All bundles are minified ES modules with provided TypeScript types. For examples
The main bundles are exposed as the following [package entrypoints](https://nodejs.org/api/packages.html#package-entry-points):
# `webamp/butterchurn`
## `webamp/butterchurn`
**Since** [v2.2.0](../12_changelog.md#220)
@ -20,7 +20,7 @@ This all-inclusive minified bundle has everything you need to enable all Webamp
import Webamp from "webamp/butterchurn";
```
# `webamp/lazy`
## `webamp/lazy`
:::warning
Using this entrypoint requires that you have a rather sophisticated bundler setup.
@ -38,7 +38,7 @@ import Webamp from "webamp/lazy";
For instructions on how to use this entrypoint, see the [Bundle Size Guide](../07_guides/03_bundle-size.md).
# `webamp`
## `webamp`
:::warning
In a future version of Webamp, this entrypoint will become an alias of `webamp/butterchurn`.

View file

@ -254,3 +254,15 @@ const webamp = new Webamp({
// ...other config options
});
```
### `requireButterchurnPresets?: () => Promise<Preset[]>`
**Since** [unreleased](../12_changelog.md#unreleased)
Milkdrop (Butterchurn) presets to be used. If not specified, the default presets
included in the bundle will be used.
Presets are expected to be in Butterchurn's JSON format. You can find these `.json` files in:
- The [Milkdrop Presets Collection](https://archive.org/details/milkdrops) at the Internet Archive.
- The [`butterchurn-presets@3.0.0-beta.4`](https://www.npmjs.com/package/butterchurn-presets/v/3.0.0-beta.4) NPM package

View file

@ -1,12 +1,16 @@
# Changelog
<!-- ## Unreleased
## Unreleased
_These changes are not yet published to NPM with an official version number._
:::tip
If you want access to the changes in this section before they are officially released you can do `npm install webamp@main`.
::: -->
:::
### Improvements
- Added new [`requireButterchurnPresets`](./06_API/02_webamp-constructor.md#requirebutterchurnpresets---promisepreset) option when constructing a Webamp instance. This allows you to specify which Butterchurn presets to use for the Milkdrop visualizer. If you don't specify this option, Webamp will use the default Butterchurn presets.
## 2.2.0

View file

@ -741,6 +741,18 @@ export interface Options {
* https://developer.mozilla.org/en-US/docs/Web/API/Media_Session_API
*/
enableMediaSession?: boolean;
/**
* Milkdrop (Butterchurn) presets to be used. If not specified, the default presets
* included in the bundle will be used.
*
* Presets are expected to be in Butterchurn's JSON format. You can find these
* `.json` files in:
*
* * The [Milkdrop Presets Collection](https://archive.org/details/milkdrops) at the Internet Archive.
* * The `butterchurn-presets@3.0.0-beta.4` NPM package
*/
requireButterchurnPresets?: () => Promise<Preset[]>;
}
/**

View file

@ -16,6 +16,7 @@ import {
PlaylistTrack,
PlayerMediaStatus,
IMetadataApi,
Preset,
} from "./types";
import getStore from "./store";
import App from "./components/App";
@ -44,6 +45,7 @@ export interface PrivateOptions {
export interface InjectableDependencies {
requireJSZip: () => Promise<JSZip>;
requireMusicMetadata: () => Promise<IMetadataApi>;
requireButterchurnPresets?: () => Promise<Preset[]>;
}
class Webamp {
@ -51,7 +53,9 @@ class Webamp {
_actionEmitter: Emitter;
_root: ReactDOM.Root | null;
_disposable: Disposable;
options: Options & PrivateOptions & InjectableDependencies; // TODO: Make this _private
// TODO: Make this _private
options: Options & PrivateOptions & InjectableDependencies;
media: IMedia; // TODO: Make this _private
store: Store; // TODO: Make this _private
@ -84,6 +88,7 @@ class Webamp {
zIndex,
requireJSZip,
requireMusicMetadata,
requireButterchurnPresets,
handleTrackDropEvent,
handleAddUrlEvent,
handleLoadListEvent,
@ -93,11 +98,22 @@ class Webamp {
__customMediaClass,
} = this.options;
const butterchurnOptions = __butterchurnOptions;
if (requireButterchurnPresets != null) {
if (butterchurnOptions == null) {
throw new Error(
"You must pass `__butterchurnOptions` if you are using `requireButterchurnPresets`."
);
}
butterchurnOptions.getPresets = requireButterchurnPresets;
}
// TODO: Make this much cleaner.
let convertPreset = null;
if (__butterchurnOptions != null) {
if (butterchurnOptions != null) {
const { importConvertPreset, presetConverterEndpoint } =
__butterchurnOptions;
butterchurnOptions;
if (importConvertPreset != null && presetConverterEndpoint != null) {
convertPreset = async (file: File): Promise<Object> => {
@ -148,14 +164,12 @@ class Webamp {
this.store.dispatch({ type: "SET_Z_INDEX", zIndex });
}
if (options.__butterchurnOptions) {
if (butterchurnOptions) {
this.store.dispatch({
type: "ENABLE_MILKDROP",
open: options.__butterchurnOptions.butterchurnOpen,
open: butterchurnOptions.butterchurnOpen,
});
this.store.dispatch(
Actions.initializePresets(options.__butterchurnOptions)
);
this.store.dispatch(Actions.initializePresets(butterchurnOptions));
}
const handleOnline = () =>

View file

@ -1,4 +1,4 @@
import { Options } from "./types";
import { Options, Preset } from "./types";
import { PrivateOptions } from "./webampLazy";
import Webamp from "./webamp";
// @ts-ignore
@ -19,18 +19,23 @@ const DEFAULT_BUTTERCHURN_WINDOW_LAYOUT = {
},
};
const DEFAULT_REQUIRE_BUTTERCHURN_PRESETS = async () =>
Object.entries(butterchurnPresets).map(([name, preset]) => {
return { name, butterchurnPresetObject: preset as Object };
});
export default class WebampWithButterchurn extends Webamp {
constructor(options: Options & PrivateOptions) {
const requireButterchurnPresets =
options.requireButterchurnPresets ?? DEFAULT_REQUIRE_BUTTERCHURN_PRESETS;
super({
...options,
requireButterchurnPresets,
__butterchurnOptions: {
importButterchurn: () => Promise.resolve(butterchurn),
// @ts-ignore
getPresets: () => {
return Object.entries(butterchurnPresets).map(([name, preset]) => {
return { name, butterchurnPresetObject: preset };
});
},
// This should be considered deprecated, and users should instead supply
// the top level `requireButterchurnPresets` option.
getPresets: requireButterchurnPresets,
butterchurnOpen: true,
},
windowLayout: options.windowLayout ?? DEFAULT_BUTTERCHURN_WINDOW_LAYOUT,