diff --git a/demo/js/index.js b/demo/js/index.js index 72658661..80d20271 100644 --- a/demo/js/index.js +++ b/demo/js/index.js @@ -13,7 +13,6 @@ import zaxon from "../../skins/ZaxonRemake1-0.wsz"; import green from "../../skins/Green-Dimension-V2.wsz"; import base from "../../skins/base-2.91-png.wsz"; import internetArchive from "../../skins/Internet-Archive.wsz"; -import partialButterchurnOptions from "../../js/components/MilkdropWindow/options"; import { WINDOWS } from "../../js/constants"; import * as Selectors from "../../js/selectors"; @@ -147,6 +146,42 @@ Raven.context(async () => { let __butterchurnOptions = null; let __initialWindowLayout = null; if (isButterchurnSupported()) { + const partialButterchurnOptions = { + importButterchurn: () => { + return import(/* webpackChunkName: "butterchurn-initial-dependencies" */ + // @ts-ignore + "butterchurn"); + }, + getPresets: async () => { + if ("URLSearchParams" in window) { + const params = new URLSearchParams(location.search); + const butterchurnPresetUrlParam = params.get("butterchurnPresetUrl"); + const milkdropPresetUrl = params.get("milkdropPresetUrl"); + const initialPresets = []; + if (butterchurnPresetUrlParam) { + initialPresets.push({ + // TODO: Get name + name: "foo", + butterchurnPresetUrl: butterchurnPresetUrlParam + }); + } else if (milkdropPresetUrl) { + throw new Error("We still need to implement this"); + } + const resp = await fetch( + "https://unpkg.com/butterchurn-presets-weekly@0.0.2/weeks/week1/presets.json" + ); + // TODO: Fallback to some other presets? + const namesToPresetUrls = await resp.json(); + const presets = Object.entries(namesToPresetUrls).map( + ([name, butterchurnPresetUrl]) => { + return { name, butterchurnPresetUrl }; + } + ); + return [...initialPresets, ...presets]; + } + return []; + } + }; const startWithMilkdropHidden = library || document.body.clientWidth < MIN_MILKDROP_WIDTH || diff --git a/js/actionCreators/milkdrop.ts b/js/actionCreators/milkdrop.ts index a0bd61ee..6ce77cd4 100644 --- a/js/actionCreators/milkdrop.ts +++ b/js/actionCreators/milkdrop.ts @@ -10,44 +10,54 @@ import { Dispatchable, TransitionType, Preset, - LazyButterchurnPresetJson + ButterchurnOptions, + StatePreset } from "../types"; import * as FileUtils from "../fileUtils"; -export function initializePresets(presetOptions: any): Dispatchable { - return async dispatch => { - const { loadInitialDependencies, loadNonMinimalPresets } = presetOptions; - const { - butterchurn, - presetKeys, - minimalPresets - } = await loadInitialDependencies(); - dispatch({ type: GOT_BUTTERCHURN, butterchurn }); - - const presets: Preset[] = presetKeys.map((key: string) => { - if (minimalPresets[key] != null) { - return { - type: "BUTTERCHURN_JSON", - name: key, - definition: minimalPresets[key] - }; +function normalizePresetTypes(preset: Preset): StatePreset { + const { name } = preset; + if (preset.butterchurnPresetObject != null) { + return { + type: "RESOLVED", + name, + preset: preset.butterchurnPresetObject + }; + } else if (preset.getButterchrunPresetObject) { + return { + type: "UNRESOLVED", + name, + getPreset: preset.getButterchrunPresetObject + }; + } else if (preset.butterchurnPresetUrl != null) { + return { + type: "UNRESOLVED", + name, + getPreset: async () => { + const resp = await fetch(preset.butterchurnPresetUrl); + return resp.json(); } - return { - type: "LAZY_BUTTERCHURN_JSON", - name: key, - getDefinition: async () => { - // TODO: Avoid a race where we try to resolve this promise more than once in parallel. - const nonMinimalPresets = await loadNonMinimalPresets(); - return nonMinimalPresets[key]; - } - }; + }; + } + throw new Error("Invalid preset object"); +} + +export function initializePresets( + presetOptions: ButterchurnOptions +): Dispatchable { + return async dispatch => { + const { getPresets, importButterchurn } = presetOptions; + importButterchurn().then(butterchurn => { + dispatch({ type: GOT_BUTTERCHURN, butterchurn: butterchurn.default }); }); - dispatch(loadPresets(presets)); + const presets = await getPresets(); + const normalizePresets = presets.map(normalizePresetTypes); + dispatch(loadPresets(normalizePresets)); }; } -export function loadPresets(presets: Preset[]): Dispatchable { +export function loadPresets(presets: StatePreset[]): Dispatchable { return (dispatch, getState) => { const presetLength = getState().milkdrop.presets.length; dispatch({ type: GOT_BUTTERCHURN_PRESETS, presets }); @@ -57,12 +67,15 @@ export function loadPresets(presets: Preset[]): Dispatchable { export function appendPresetFileList(fileList: FileList): Dispatchable { return async dispatch => { - const presets: Preset[] = Array.from(fileList).map(file => { - const JSON_EXT = ".json"; - const MILK_EXT = ".milk"; - const filename = file.name.toLowerCase(); - if (filename.endsWith(MILK_EXT)) { - // Not sure why we need this type definition. + const presets: StatePreset[] = Array.from(fileList).map( + (file): StatePreset => { + const JSON_EXT = ".json"; + const MILK_EXT = ".milk"; + const filename = file.name.toLowerCase(); + if (filename.endsWith(MILK_EXT)) { + throw new Error(".milk preset support not yet implemented"); + // Not sure why we need this type definition. + /* const lazy: LazyButterchurnPresetJson = { type: "LAZY_BUTTERCHURN_JSON", name: file.name.slice(0, file.name.length - MILK_EXT.length), @@ -71,24 +84,25 @@ export function appendPresetFileList(fileList: FileList): Dispatchable { return {}; } }; - throw new Error(".milk preset support not yet implemented"); return lazy; - } else if (filename.endsWith(JSON_EXT)) { - // Not sure why we need this type definition. - const lazy: LazyButterchurnPresetJson = { - type: "LAZY_BUTTERCHURN_JSON", - name: file.name.slice(0, file.name.length - JSON_EXT.length), - getDefinition: async () => { - const str = await FileUtils.genStringFromFileReference(file); - // TODO: How should we handle the case where json parsing fails? - return JSON.parse(str); - } - }; - return lazy; - } else { - throw new Error("Invalid type"); + */ + } else if (filename.endsWith(JSON_EXT)) { + // Not sure why we need this type definition. + const lazy: StatePreset = { + type: "UNRESOLVED", + name: file.name.slice(0, file.name.length - JSON_EXT.length), + getPreset: async () => { + const str = await FileUtils.genStringFromFileReference(file); + // TODO: How should we handle the case where json parsing fails? + return JSON.parse(str); + } + }; + return lazy; + } else { + throw new Error("Invalid type"); + } } - }); + ); dispatch(loadPresets(presets)); // TODO: Select the first of these presets }; @@ -128,11 +142,11 @@ export function requestPresetAtIndex( return; } switch (preset.type) { - case "BUTTERCHURN_JSON": + case "RESOLVED": dispatch({ type: SELECT_PRESET_AT_INDEX, index, transitionType }); return; - case "LAZY_BUTTERCHURN_JSON": - const json = await preset.getDefinition(); + case "UNRESOLVED": + const json = await preset.getPreset(); // What if the index has changed? // Perhaps we could hold a reference to the preset at the index before // we await and confirm that it hasn't changed after the await? diff --git a/js/components/MilkdropWindow/options.ts b/js/components/MilkdropWindow/options.ts index 7dce5cab..02c3738a 100644 --- a/js/components/MilkdropWindow/options.ts +++ b/js/components/MilkdropWindow/options.ts @@ -1,42 +1,4 @@ -import { - ButterchurnOptions, - InitialButterchurnDependencies -} from "../../types"; - -async function loadInitialDependencies(): Promise< - InitialButterchurnDependencies -> { - const [butterchurn, butterchurnMinimalPresets, presetPackMeta] = - // prettier-ignore - await Promise.all([ - import( - /* webpackChunkName: "butterchurn-initial-dependencies" */ - // @ts-ignore - "butterchurn" - ), - import( - /* webpackChunkName: "butterchurn-initial-dependencies" */ - // @ts-ignore - "butterchurn-presets/lib/butterchurnPresetsMinimal.min" - ), - import( - /* webpackChunkName: "butterchurn-initial-dependencies" */ - // @ts-ignore - "butterchurn-presets/lib/butterchurnPresetPackMeta.min" - ) - ]); - return { - butterchurn: butterchurn.default, - minimalPresets: butterchurnMinimalPresets.default.getPresets(), - presetKeys: presetPackMeta.default.getMainPresetMeta().presets - }; -} - -async function loadNonMinimalPresets() { - return (await import(/* webpackChunkName: "butterchurn-non-minimal-presets" */ - // @ts-ignore - "butterchurn-presets/lib/butterchurnPresetsNonMinimal.min")).default.getPresets(); -} +import { ButterchurnOptions } from "../../types"; async function loadConvertPreset() { const { convertPreset } = @@ -48,19 +10,3 @@ async function loadConvertPreset() { ); return convertPreset; } - -const options: ButterchurnOptions = { - loadConvertPreset, - loadInitialDependencies, - loadNonMinimalPresets, - presetConverterEndpoint: - "https://p2tpeb5v8b.execute-api.us-east-2.amazonaws.com/default/milkdropShaderConverter" -}; - -if ("URLSearchParams" in window) { - const params = new URLSearchParams(location.search); - options.initialButterchurnPresetUrl = params.get("butterchurnPresetUrl"); - options.initialMilkdropPresetUrl = params.get("milkdropPresetUrl"); -} - -export default options; diff --git a/js/reducers/milkdrop.ts b/js/reducers/milkdrop.ts index 935980b1..fbef88c2 100644 --- a/js/reducers/milkdrop.ts +++ b/js/reducers/milkdrop.ts @@ -1,4 +1,4 @@ -import { Action, PresetId, Preset } from "../types"; +import { Action, PresetId, StatePreset } from "../types"; import { SET_MILKDROP_DESKTOP, GOT_BUTTERCHURN_PRESETS, @@ -14,7 +14,7 @@ export interface MilkdropState { desktop: boolean; overlay: boolean; presetOrder: PresetId[]; - presets: Preset[]; + presets: StatePreset[]; currentPresetIndex: number | null; butterchurn: any; transitionType: TransitionType; @@ -42,24 +42,16 @@ export const milkdrop = ( case GOT_BUTTERCHURN_PRESETS: return { ...state, - presets: state.presets.concat( - action.presets.map(preset => { - switch (preset.type) { - case "BUTTERCHURN_JSON": - case "LAZY_BUTTERCHURN_JSON": - return preset; - } - }) - ) + presets: state.presets.concat(action.presets) }; case RESOLVE_PRESET_AT_INDEX: const preset = state.presets[action.index]; return { ...state, presets: Utils.replaceAtIndex(state.presets, action.index, { + type: "RESOLVED", name: preset.name, - type: "BUTTERCHURN_JSON", - definition: action.json + preset: action.json }) }; case SELECT_PRESET_AT_INDEX: diff --git a/js/selectors.ts b/js/selectors.ts index 33d5d327..df9698c7 100644 --- a/js/selectors.ts +++ b/js/selectors.ts @@ -635,10 +635,10 @@ export function getCurrentPreset(state: AppState): any | null { return null; } const preset = state.milkdrop.presets[index]; - if (preset == null || preset.type !== "BUTTERCHURN_JSON") { + if (preset == null || preset.type === "UNRESOLVED") { return null; } - return preset.definition; + return preset.preset; } export function getPresetNames(state: AppState): string[] { diff --git a/js/types.ts b/js/types.ts index 5247a2c9..47d27c4a 100644 --- a/js/types.ts +++ b/js/types.ts @@ -115,57 +115,39 @@ type SkinData = { skinGenExColors: SkinGenExColors | null; }; -export interface InitialButterchurnDependencies { - // TODO: Type these - butterchurn: any; - minimalPresets: any; - presetKeys: any; -} - -export interface ButterchurnOptions { - loadNonMinimalPresets(): Promise; - loadInitialDependencies(): Promise; - loadConvertPreset(): Promise; - presetConverterEndpoint: string; - initialMilkdropPresetUrl?: string | null; - initialButterchurnPresetUrl?: string | null; -} - // This is what we actually pass to butterchurn type ButterchurnPresetJson = { - type: "BUTTERCHURN_JSON"; name: string; - definition: Object; -}; - -export type LazyButterchurnPresetJson = { - type: "LAZY_BUTTERCHURN_JSON"; - name: string; - getDefinition: () => Promise; + butterchurnPresetObject: Object; }; // A URL that points to a Butterchurn preset interface ButterchurnPresetUrl { - type: "BUTTERCHURN_URL"; - url: string; + name: string; + butterchurnPresetUrl: string; } -// A URL that points to a .milk preset -interface MilkdropPresetUrl { - type: "MILKDROP_URL"; - url: string; -} +export type LazyButterchurnPresetJson = { + name: string; + getButterchrunPresetObject: () => Promise; +}; -export type PresetDefinition = +export type Preset = | ButterchurnPresetJson - | LazyButterchurnPresetJson | ButterchurnPresetUrl - | MilkdropPresetUrl; + | LazyButterchurnPresetJson; -export type Preset = ButterchurnPresetJson | LazyButterchurnPresetJson; +export type StatePreset = + | { type: "RESOLVED"; name: string; preset: Object } + | { type: "UNRESOLVED"; name: string; getPreset: () => Promise }; export type PresetId = string; +export interface ButterchurnOptions { + getPresets(): Promise; + importButterchurn(): Promise; +} + export interface EqfPreset { name: string; hz60: number; @@ -483,7 +465,7 @@ export type Action = } | { type: "GOT_BUTTERCHURN_PRESETS"; - presets: Preset[]; + presets: StatePreset[]; } | { type: "GOT_BUTTERCHURN";