Skip to content

Commit

Permalink
web: Add v1 api
Browse files Browse the repository at this point in the history
At this commit, the V1 API is identical to Legacy API
  • Loading branch information
Dinnerbone committed Nov 16, 2024
1 parent a3d7fac commit 3f12eb2
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 23 deletions.
2 changes: 1 addition & 1 deletion web/packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ If you want to control the Ruffle player, you may use our Javascript API.
let player = ruffle.createPlayer();
let container = document.getElementById("container");
container.appendChild(player);
player.load("movie.swf");
player.ruffle().load("movie.swf");
});
</script>
<script src="path/to/ruffle/ruffle.js"></script>
Expand Down
105 changes: 105 additions & 0 deletions web/packages/core/src/internal/player/impl_v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { PlayerV1 } from "../../public/player";
import { InnerPlayer, ReadyState } from "./inner";
import type { DataLoadOptions, URLLoadOptions } from "../../public/config";
import type { MovieMetadata } from "../../public/player";

export class PlayerV1Impl implements PlayerV1 {
#inner: InnerPlayer;

constructor(inner: InnerPlayer) {
this.#inner = inner;
}

get onFSCommand(): ((command: string, args: string) => boolean) | null {
return this.#inner.onFSCommand;
}

set onFSCommand(
value: ((command: string, args: string) => boolean) | null,
) {
this.#inner.onFSCommand = value;
}

get readyState(): ReadyState {
return this.#inner._readyState;
}

get metadata(): MovieMetadata | null {
return this.#inner.metadata;
}

get loadedConfig(): URLLoadOptions | DataLoadOptions | null {
return this.#inner.loadedConfig ?? null;
}

async reload(): Promise<void> {
await this.#inner.reload();
}

async load(
options: string | URLLoadOptions | DataLoadOptions,
isPolyfillElement: boolean = false,
): Promise<void> {
await this.#inner.load(options, isPolyfillElement);
}

play(): void {
this.#inner.play();
}

get isPlaying(): boolean {
return this.#inner.isPlaying;
}

get volume(): number {
return this.#inner.volume;
}

set volume(value: number) {
this.#inner.volume = value;
}

get fullscreenEnabled(): boolean {
return this.#inner.fullscreenEnabled;
}

get isFullscreen(): boolean {
return this.#inner.isFullscreen;
}

setFullscreen(isFull: boolean): void {
this.#inner.setFullscreen(isFull);
}

enterFullscreen(): void {
this.#inner.enterFullscreen();
}

exitFullscreen(): void {
this.#inner.exitFullscreen();
}

async downloadSwf(): Promise<void> {
await this.#inner.downloadSwf();
}

displayMessage(message: string): void {
this.#inner.displayMessage(message);
}

pause(): void {
this.#inner.pause();
}

set traceObserver(observer: ((message: string) => void) | null) {
this.#inner.traceObserver = observer;
}

get config(): URLLoadOptions | DataLoadOptions | object {
return this.#inner.config;
}

set config(value: URLLoadOptions | DataLoadOptions | object) {
this.#inner.config = value;
}
}
12 changes: 11 additions & 1 deletion web/packages/core/src/internal/player/ruffle-player-element.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { DataLoadOptions, URLLoadOptions } from "../../public/config";
import type { MovieMetadata, PlayerElement } from "../../public/player";
import { InnerPlayer, ReadyState } from "./inner";
import { APIVersions } from "../../public/player";
import { PlayerV1Impl } from "./impl_v1";

/**
* The ruffle player element that should be inserted onto the page.
Expand Down Expand Up @@ -54,6 +56,14 @@ export class RufflePlayerElement extends HTMLElement implements PlayerElement {
);
}

ruffle<V extends keyof APIVersions = 1>(version?: V): APIVersions[V] {
const v = version ?? 1;
if (v === 1) {
return new PlayerV1Impl(this.#inner) as APIVersions[V];
}
throw new Error(`Version ${version} not supported.`);
}

get loadedConfig(): URLLoadOptions | DataLoadOptions | null {
return this.#inner.loadedConfig ?? null;
}
Expand Down Expand Up @@ -145,7 +155,7 @@ export class RufflePlayerElement extends HTMLElement implements PlayerElement {

public PercentLoaded(): number {
// [NA] This is a stub - we need to research how this is actually implemented (is it just base swf loadedBytes?)
if (this.readyState === ReadyState.Loaded) {
if (this.#inner._readyState === ReadyState.Loaded) {
return 100;
} else {
return 0;
Expand Down
1 change: 1 addition & 0 deletions web/packages/core/src/public/player/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from "./flash";
export * from "./player-element";
export * from "./movie-metadata";
export * from "./legacy";
export * from "./v1";
73 changes: 71 additions & 2 deletions web/packages/core/src/public/player/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { ReadyState } from "../../internal/player/inner";
/**
* Legacy interface to the Ruffle API.
*
* These methods are deprecated and only exist for backwards compatibility.
* Due to the nature of Flash, they may be replaced at any time via ActionScript's `ExternalInterface` class.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* Any of these methods or properties may be replaced by Flash and are not guaranteed to exist.
*/
export interface LegacyRuffleAPI {
/**
Expand All @@ -16,25 +16,39 @@ export interface LegacyRuffleAPI {
* @param command A string passed to the host application for any use.
* @param args A string passed to the host application for any use.
* @returns True if the command was handled.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.onFSCommand}
*/
onFSCommand: ((command: string, args: string) => boolean) | null;

/**
* Any configuration that should apply to this specific player.
* This will be defaulted with any global configuration.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.config}
*/
config: URLLoadOptions | DataLoadOptions | object;

/**
* The effective config loaded with the last call to `load()`.
* If no such call has been made, this will be `null`.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.loadedConfig}
*/
readonly loadedConfig: URLLoadOptions | DataLoadOptions | null;

/**
* Indicates the readiness of the playing movie.
*
* @returns The `ReadyState` of the player.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.readyState}
*/
get readyState(): ReadyState;

Expand All @@ -44,13 +58,20 @@ export interface LegacyRuffleAPI {
* For example, `metadata.width` is the width of the SWF file, and not the width of the Ruffle player.
*
* @returns The metadata of the movie, or `null` if the movie metadata has not yet loaded.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.metadata}
*/
get metadata(): MovieMetadata | null;

/**
* Reloads the player, as if you called {@link load} with the same config as the last time it was called.
*
* If this player has never been loaded, this method will return an error.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.reload}
*/
reload(): Promise<void>;

Expand All @@ -69,18 +90,28 @@ export interface LegacyRuffleAPI {
*
* The options will be defaulted by the {@link config} field, which itself
* is defaulted by a global `window.RufflePlayer.config`.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.load}
*/
load(options: string | URLLoadOptions | DataLoadOptions): Promise<void>;

/**
* Plays or resumes the movie.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.play}
*/
play(): void;

/**
* Whether this player is currently playing.
*
* @returns True if this player is playing, false if it's paused or hasn't started yet.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.isPlaying}
*/
get isPlaying(): boolean;

Expand All @@ -90,6 +121,9 @@ export interface LegacyRuffleAPI {
* The volume is linear and not adapted for logarithmic hearing.
*
* @returns The volume. 1.0 is 100% volume.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.volume}
*/
get volume(): number;

Expand All @@ -99,20 +133,29 @@ export interface LegacyRuffleAPI {
* The volume should be linear and not adapted for logarithmic hearing.
*
* @param value The volume. 1.0 is 100% volume.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.volume}
*/
set volume(value: number);

/**
* Checks if this player is allowed to be fullscreen by the browser.
*
* @returns True if you may call {@link enterFullscreen}.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.fullscreenEnabled}
*/
get fullscreenEnabled(): boolean;

/**
* Checks if this player is currently fullscreen inside the browser.
*
* @returns True if it is fullscreen.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.isFullscreen}
*/
get isFullscreen(): boolean;

Expand All @@ -121,18 +164,29 @@ export interface LegacyRuffleAPI {
* it is allowed.
*
* @param isFull Whether to set to fullscreen or return to normal.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.setFullscreen}
*/
setFullscreen(isFull: boolean): void;

/**
* Requests the browser to make this player fullscreen.
*
* This is not guaranteed to succeed, please check {@link fullscreenEnabled} first.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.enterFullscreen}
*/
enterFullscreen(): void;

/**
* Requests the browser to no longer make this player fullscreen.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.exitFullscreen}
*/
exitFullscreen(): void;

Expand All @@ -141,6 +195,10 @@ export interface LegacyRuffleAPI {
*
* No more frames, scripts or sounds will be executed.
* This movie will be considered inactive and will not wake up until resumed.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.pause}
*/
pause(): void;

Expand All @@ -150,18 +208,29 @@ export interface LegacyRuffleAPI {
* The observer will be called, as a function, for each message that the playing movie will "trace" (output).
*
* @param observer The observer that will be called for each trace.
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.traceObserver}
*/
set traceObserver(observer: ((message: string) => void) | null);

/**
* Fetches the loaded SWF and downloads it.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.downloadSwf}
*/
downloadSwf(): Promise<void>;

/**
* Show a dismissible message in front of the player.
*
* @param message The message shown to the user.
*
* @deprecated Please use {@link PlayerElement.ruffle | ruffle()} to access a versioned API.
* This method may be replaced by Flash and is not guaranteed to exist.
* A direct replacement is {@link PlayerV1.displayMessage}
*/
displayMessage(message: string): void;
}
21 changes: 19 additions & 2 deletions web/packages/core/src/public/player/player-element.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
import { LegacyRuffleAPI } from "./legacy";
import { FlashAPI } from "./flash";
import { PlayerV1 } from "./v1";

/**
* A map of API version number, to API interface.
*/
export type APIVersions = {
1: PlayerV1;
};

/**
* A Ruffle player's HTML element.
*
* This is either created through `window.RufflePlayer.latest().createPlayer()`, or polyfilled from a `<embed>`/`<object>` tag.
*
* In addition to usual HTML attributes, this player contains methods and properties that belong to both
* the **Flash JS API** and **legacy Ruffle API**s.
* the **Flash JS API** and **legacy Ruffle API**s. You are strongly discouraged from using them, and should instead
* use `.ruffle(version)` to access a versioned API interface.
*/
export interface PlayerElement extends HTMLElement, LegacyRuffleAPI, FlashAPI {}
export interface PlayerElement extends HTMLElement, LegacyRuffleAPI, FlashAPI {
/**
* Access a specific version of the Ruffle API.
* If the given version is not supported, an error is thrown.
*
* @param version Version of the API to access. Defaults to 1.
*/
ruffle<V extends keyof APIVersions = 1>(version?: V): APIVersions[V];
}
Loading

0 comments on commit 3f12eb2

Please sign in to comment.