Pull demo site webamp config into typed module (#1057)

* Pull demo site webamp config into typed module

* Tybe the demo index.js file

* Update entrypoint to point to tsx file
This commit is contained in:
Jordan Eldredge 2021-01-02 13:16:26 -08:00 committed by GitHub
parent 1809cc74e8
commit b53bd1fe37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 317 additions and 272 deletions

View file

@ -76,7 +76,7 @@ module.exports = {
maxAssetSize: 7000000,
},
entry: {
webamp: ["./js/index.js"],
webamp: ["./js/index.tsx"],
},
context: path.resolve(__dirname, "../"),
output: {

View file

@ -4,7 +4,12 @@
// away once we've figured out how to expose all the things that the demo site
// needs, or reduce the things that the demo site needs access to.
export { default as WebampLazy } from "../../js/webampLazy";
export {
default as WebampLazy,
Options,
PrivateOptions,
WindowLayout,
} from "../../js/webampLazy";
export {
ButterchurnOptions,
Track,

View file

@ -33,7 +33,7 @@ if ("URLSearchParams" in window) {
// SHOW_DESKTOP_ICONS = Boolean(params.get("icons"));
}
export const skinUrl = config.skinUrl === undefined ? null : config.skinUrl;
export const skinUrl = config.skinUrl ?? null;
// https://freemusicarchive.org/music/netBloc_Artists/netBloc_Vol_24_tiuqottigeloot/
const album = "netBloc Vol. 24: tiuqottigeloot";

View file

@ -1,253 +0,0 @@
/* global SENTRY_DSN */
import * as Sentry from "@sentry/browser";
import ReactDOM from "react-dom";
import createMiddleware from "redux-sentry-middleware";
import isButterchurnSupported from "butterchurn/lib/isSupported.min";
import { loggerMiddleware } from "./eventLogger";
import {
WebampLazy,
WINDOWS,
STEP_MARQUEE,
UPDATE_TIME_ELAPSED,
UPDATE_WINDOW_POSITIONS,
SET_VOLUME,
SET_BALANCE,
SET_BAND_VALUE,
DISABLE_MARQUEE,
TOGGLE_REPEAT,
TOGGLE_SHUFFLE,
SET_EQ_AUTO,
SET_DUMMY_VIZ_DATA,
} from "./Webamp";
import { getButterchurnOptions } from "./butterchurnOptions";
import dropboxFilePicker from "./dropboxFilePicker";
import availableSkins from "./avaliableSkins";
import {
skinUrl as configSkinUrl,
initialTracks,
initialState,
disableMarquee,
} from "./config";
import DemoDesktop from "./DemoDesktop";
import enableMediaSession from "./mediaSession";
import screenshotInitialState from "./screenshotInitialState";
const DEFAULT_DOCUMENT_TITLE = document.title;
const NOISY_ACTION_TYPES = new Set([
STEP_MARQUEE,
UPDATE_TIME_ELAPSED,
UPDATE_WINDOW_POSITIONS,
SET_VOLUME,
SET_BALANCE,
SET_BAND_VALUE,
]);
const MIN_MILKDROP_WIDTH = 725;
let screenshot = false;
let skinUrl = configSkinUrl;
if ("URLSearchParams" in window) {
const params = new URLSearchParams(location.search);
screenshot = params.get("screenshot");
skinUrl = params.get("skinUrl") || skinUrl;
}
function supressDragAndDrop(e) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
window.addEventListener("dragenter", supressDragAndDrop);
window.addEventListener("dragover", supressDragAndDrop);
window.addEventListener("drop", supressDragAndDrop);
let lastActionType = null;
// Filter out consecutive common actions
function filterBreadcrumbActions(action) {
const noisy =
NOISY_ACTION_TYPES.has(action.type) &&
NOISY_ACTION_TYPES.has(lastActionType);
lastActionType = action.type;
return !noisy;
}
try {
Sentry.init({
dsn: SENTRY_DSN,
/* global COMMITHASH */
release: typeof COMMITHASH !== "undefined" ? COMMITHASH : "DEV",
});
} catch (e) {
// Archive.org tries to rewrite the DSN to point to a archive.org version
// since it looks like a URL. When this happens, Sentry crashes.
console.error(e);
}
const sentryMiddleware = createMiddleware(Sentry, {
filterBreadcrumbActions,
stateTransformer: getDebugData,
});
async function main() {
const about = document.getElementsByClassName("about")[0];
if (screenshot) {
about.style.visibility = "hidden";
}
if (!WebampLazy.browserIsSupported()) {
document.getElementById("browser-compatibility").style.display = "block";
document.getElementById("app").style.visibility = "hidden";
return;
}
about.classList.add("loaded");
let __butterchurnOptions = null;
let __initialWindowLayout = null;
if (isButterchurnSupported()) {
const startWithMilkdropHidden =
document.body.clientWidth < MIN_MILKDROP_WIDTH ||
skinUrl != null ||
screenshot;
__butterchurnOptions = getButterchurnOptions(startWithMilkdropHidden);
if (startWithMilkdropHidden) {
__initialWindowLayout = {
[WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
[WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
[WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 0] },
[WINDOWS.MILKDROP]: { position: { x: 0, y: 348 }, size: [0, 0] },
};
} else {
__initialWindowLayout = {
[WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
[WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
[WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 4] },
[WINDOWS.MILKDROP]: { position: { x: 275, y: 0 }, size: [7, 12] },
};
}
document.getElementById("butterchurn-share").style.display = "flex";
}
const initialSkin = !skinUrl ? null : { url: skinUrl };
const webamp = new WebampLazy({
initialSkin,
initialTracks: screenshot ? null : initialTracks,
availableSkins,
filePickers: [dropboxFilePicker],
enableHotkeys: true,
handleTrackDropEvent: (e) => {
const trackJson = e.dataTransfer.getData("text/json");
if (trackJson == null) {
return null;
}
try {
const track = JSON.parse(trackJson);
return [track];
} catch (err) {
return null;
}
},
requireJSZip: () =>
import(/* webpackChunkName: "jszip" */ "jszip/dist/jszip"),
requireMusicMetadata: () =>
import(
/* webpackChunkName: "music-metadata-browser" */ "music-metadata-browser/dist/index"
),
__initialWindowLayout,
__initialState: screenshot ? screenshotInitialState : initialState,
__butterchurnOptions,
__customMiddlewares: [sentryMiddleware, loggerMiddleware],
});
if (disableMarquee || screenshot) {
webamp.store.dispatch({ type: DISABLE_MARQUEE });
}
if (screenshot) {
window.document.body.style.backgroundColor = "#000";
webamp.store.dispatch({ type: TOGGLE_REPEAT });
webamp.store.dispatch({ type: TOGGLE_SHUFFLE });
webamp.store.dispatch({ type: SET_EQ_AUTO, value: true });
webamp.store.dispatch({
type: SET_DUMMY_VIZ_DATA,
data: {
0: 11.75,
8: 11.0625,
16: 8.5,
24: 7.3125,
32: 6.75,
40: 6.4375,
48: 6.25,
56: 5.875,
64: 5.625,
72: 5.25,
80: 5.125,
88: 4.875,
96: 4.8125,
104: 4.375,
112: 3.625,
120: 1.5625,
},
});
}
webamp.onTrackDidChange((track) => {
document.title =
track == null
? DEFAULT_DOCUMENT_TITLE
: `${track.metaData.title} - ${track.metaData.artist} \u00B7 ${DEFAULT_DOCUMENT_TITLE}`;
});
enableMediaSession(webamp);
// Expose a file input in the DOM for testing.
const fileInput = document.createElement("input");
fileInput.id = "webamp-file-input";
fileInput.style.display = "none";
fileInput.type = "file";
fileInput.value = null;
fileInput.addEventListener("change", (e) => {
const firstFile = e.target.files[0];
if (firstFile == null) {
return;
}
const url = URL.createObjectURL(firstFile);
webamp.setSkinFromUrl(url);
});
document.body.appendChild(fileInput);
// Expose webamp instance for debugging and integration tests.
window.__webamp = webamp;
await webamp.renderWhenReady(document.getElementById("app"));
if (!screenshot) {
ReactDOM.render(
<DemoDesktop webamp={webamp} />,
document.getElementById("demo-desktop")
);
}
}
function getDebugData(state) {
return {
...state,
display: {
...state.display,
skinGenLetterWidths: "[[REDACTED]]",
skinImages: "[[REDACTED]]",
skinCursors: "[[REDACTED]]",
skinRegion: "[[REDACTED]]",
},
};
}
main();

View file

@ -0,0 +1,156 @@
import * as Sentry from "@sentry/browser";
import ReactDOM from "react-dom";
// @ts-ignore
import isButterchurnSupported from "butterchurn/lib/isSupported.min";
import { getWebampConfig } from "./webampConfig";
import {
WebampLazy,
DISABLE_MARQUEE,
TOGGLE_REPEAT,
TOGGLE_SHUFFLE,
SET_EQ_AUTO,
SET_DUMMY_VIZ_DATA,
} from "./Webamp";
import { disableMarquee, skinUrl as configSkinUrl } from "./config";
import DemoDesktop from "./DemoDesktop";
import enableMediaSession from "./mediaSession";
declare global {
const SENTRY_DSN: string;
const COMMITHASH: string | undefined;
interface Window {
__webamp: WebampLazy;
}
}
const DEFAULT_DOCUMENT_TITLE = document.title;
let screenshot = false;
let skinUrl = configSkinUrl;
if ("URLSearchParams" in window) {
const params = new URLSearchParams(location.search);
screenshot = Boolean(params.get("screenshot"));
skinUrl = params.get("skinUrl") || skinUrl;
}
function supressDragAndDrop(e: DragEvent) {
e.preventDefault();
if (e.dataTransfer == null) {
return;
}
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
window.addEventListener("dragenter", supressDragAndDrop);
window.addEventListener("dragover", supressDragAndDrop);
window.addEventListener("drop", supressDragAndDrop);
try {
Sentry.init({
dsn: SENTRY_DSN,
release: COMMITHASH ?? "DEV",
});
} catch (e) {
// Archive.org tries to rewrite the DSN to point to a archive.org version
// since it looks like a URL. When this happens, Sentry crashes.
console.error(e);
}
async function main() {
const about = document.getElementsByClassName("about")[0] as HTMLDivElement;
if (screenshot) {
about.style.visibility = "hidden";
}
if (!WebampLazy.browserIsSupported()) {
(document.getElementById(
"browser-compatibility"
) as HTMLDivElement).style.display = "block";
(document.getElementById("app") as HTMLDivElement).style.visibility =
"hidden";
return;
}
about.classList.add("loaded");
if (isButterchurnSupported()) {
(document.getElementById(
"butterchurn-share"
) as HTMLDivElement).style.display = "flex";
}
const webamp = new WebampLazy(getWebampConfig(screenshot, skinUrl));
if (disableMarquee || screenshot) {
webamp.store.dispatch({ type: DISABLE_MARQUEE });
}
if (screenshot) {
window.document.body.style.backgroundColor = "#000";
webamp.store.dispatch({ type: TOGGLE_REPEAT });
webamp.store.dispatch({ type: TOGGLE_SHUFFLE });
webamp.store.dispatch({ type: SET_EQ_AUTO, value: true });
webamp.store.dispatch({
type: SET_DUMMY_VIZ_DATA,
data: {
0: 11.75,
8: 11.0625,
16: 8.5,
24: 7.3125,
32: 6.75,
40: 6.4375,
48: 6.25,
56: 5.875,
64: 5.625,
72: 5.25,
80: 5.125,
88: 4.875,
96: 4.8125,
104: 4.375,
112: 3.625,
120: 1.5625,
},
});
}
webamp.onTrackDidChange((track) => {
document.title =
track == null
? DEFAULT_DOCUMENT_TITLE
: `${track.metaData.title} - ${track.metaData.artist} \u00B7 ${DEFAULT_DOCUMENT_TITLE}`;
});
enableMediaSession(webamp);
// Expose a file input in the DOM for testing.
const fileInput = document.createElement("input");
fileInput.id = "webamp-file-input";
fileInput.style.display = "none";
fileInput.type = "file";
fileInput.addEventListener("change", (e) => {
// @ts-ignore We know this will always be a file input
const firstFile = e.target.files[0];
if (firstFile == null) {
return;
}
const url = URL.createObjectURL(firstFile);
webamp.setSkinFromUrl(url);
});
document.body.appendChild(fileInput);
// Expose webamp instance for debugging and integration tests.
window.__webamp = webamp;
await webamp.renderWhenReady(
document.getElementById("app") as HTMLDivElement
);
if (!screenshot) {
ReactDOM.render(
<DemoDesktop webamp={webamp} />,
document.getElementById("demo-desktop")
);
}
}
main();

View file

@ -0,0 +1,134 @@
import * as Sentry from "@sentry/browser";
// @ts-ignore
import createMiddleware from "redux-sentry-middleware";
// @ts-ignore
import isButterchurnSupported from "butterchurn/lib/isSupported.min";
import { loggerMiddleware } from "./eventLogger";
import {
Action,
Options,
PrivateOptions,
WINDOWS,
STEP_MARQUEE,
UPDATE_TIME_ELAPSED,
UPDATE_WINDOW_POSITIONS,
SET_VOLUME,
SET_BALANCE,
SET_BAND_VALUE,
AppState,
WindowLayout,
} from "./Webamp";
import { getButterchurnOptions } from "./butterchurnOptions";
import dropboxFilePicker from "./dropboxFilePicker";
import availableSkins from "./avaliableSkins";
import { initialTracks, initialState } from "./config";
import screenshotInitialState from "./screenshotInitialState";
const NOISY_ACTION_TYPES = new Set([
STEP_MARQUEE,
UPDATE_TIME_ELAPSED,
UPDATE_WINDOW_POSITIONS,
SET_VOLUME,
SET_BALANCE,
SET_BAND_VALUE,
]);
const MIN_MILKDROP_WIDTH = 725;
let lastActionType: string | null = null;
// Filter out consecutive common actions
function filterBreadcrumbActions(action: Action) {
const noisy =
lastActionType != null &&
NOISY_ACTION_TYPES.has(action.type) &&
NOISY_ACTION_TYPES.has(lastActionType);
lastActionType = action.type;
return !noisy;
}
const sentryMiddleware = createMiddleware(Sentry, {
filterBreadcrumbActions,
stateTransformer: getDebugData,
});
export function getWebampConfig(
screenshot: boolean,
skinUrl: string | null
): Options & PrivateOptions {
let __butterchurnOptions;
let __initialWindowLayout: WindowLayout | undefined;
if (isButterchurnSupported()) {
const startWithMilkdropHidden =
document.body.clientWidth < MIN_MILKDROP_WIDTH ||
skinUrl != null ||
screenshot;
__butterchurnOptions = getButterchurnOptions(startWithMilkdropHidden);
if (startWithMilkdropHidden) {
__initialWindowLayout = {
[WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
[WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
[WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 0] },
[WINDOWS.MILKDROP]: { position: { x: 0, y: 348 }, size: [0, 0] },
};
} else {
__initialWindowLayout = {
[WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
[WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
[WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 4] },
[WINDOWS.MILKDROP]: { position: { x: 275, y: 0 }, size: [7, 12] },
};
}
}
const initialSkin = !skinUrl ? undefined : { url: skinUrl };
return {
initialSkin,
initialTracks: screenshot ? undefined : initialTracks,
availableSkins,
filePickers: [dropboxFilePicker],
enableHotkeys: true,
handleTrackDropEvent: (e) => {
const trackJson = e.dataTransfer.getData("text/json");
if (trackJson == null) {
return null;
}
try {
const track = JSON.parse(trackJson);
return [track];
} catch (err) {
return null;
}
},
requireJSZip: () =>
// @ts-ignore
import(/* webpackChunkName: "jszip" */ "jszip/dist/jszip"),
requireMusicMetadata: () =>
import(
/* webpackChunkName: "music-metadata-browser" */ "music-metadata-browser/dist/index"
),
__initialWindowLayout,
__initialState: screenshot ? screenshotInitialState : initialState,
__butterchurnOptions,
__customMiddlewares: [sentryMiddleware, loggerMiddleware],
};
}
function getDebugData(state: AppState) {
return {
...state,
display: {
...state.display,
skinGenLetterWidths: "[[REDACTED]]",
skinImages: "[[REDACTED]]",
skinCursors: "[[REDACTED]]",
skinRegion: "[[REDACTED]]",
},
};
}

View file

@ -360,7 +360,7 @@ export type Action =
}
| {
type: "SET_DUMMY_VIZ_DATA";
data: null;
data: DummyVizData;
}
| {
type: "SET_BAND_VALUE";
@ -705,7 +705,7 @@ export interface IMusicMetadataBrowserApi {
}
export interface Extras {
requireJSZip(): Promise<never>;
requireJSZip(): Promise<any>;
requireMusicMetadata(): Promise<IMusicMetadataBrowserApi>;
convertPreset: ((file: File) => Promise<Object>) | null;
handleTrackDropEvent?: (

View file

@ -39,8 +39,9 @@ import Emitter from "./emitter";
import "../css/base-skin.css";
import { SerializedStateV1 } from "./serializedStates/v1Types";
import Disposable from "./Disposable";
import { DeepPartial } from "redux";
interface Options {
export interface Options {
/**
* An object representing the initial skin to use.
*
@ -113,21 +114,23 @@ interface Options {
handleSaveListEvent?: (tracks: Track[]) => null | Promise<null>;
}
interface PrivateOptions {
avaliableSkins?: { url: string; name: string }[]; // Old misspelled name
requireJSZip(): Promise<never>; // TODO: Type JSZip
requireMusicMetadata(): Promise<any>; // TODO: Type musicmetadata
__initialState?: AppState;
__customMiddlewares?: Middleware[];
__initialWindowLayout: {
[windowId: string]: {
size: null | [number, number];
position: WindowPosition;
};
export type WindowLayout = {
[windowId: string]: {
size?: null | [number, number];
position: WindowPosition;
};
__butterchurnOptions: ButterchurnOptions;
};
export interface PrivateOptions {
avaliableSkins?: { url: string; name: string }[]; // Old misspelled name
requireJSZip(): Promise<any>; // TODO: Type JSZip
requireMusicMetadata(): Promise<any>; // TODO: Type musicmetadata
__initialState?: DeepPartial<AppState>;
__customMiddlewares?: Middleware[];
__initialWindowLayout?: WindowLayout;
__butterchurnOptions?: ButterchurnOptions;
// This is used by https://winampify.io/ to proxy through to Spotify's API.
__customMediaClass: typeof Media; // This should have the same interface as Media
__customMediaClass?: typeof Media; // This should have the same interface as Media
}
// Return a promise that resolves when the store matches a predicate.