Add getPlayerMediaStatus instance method

This commit is contained in:
Jordan Eldredge 2025-06-29 22:44:49 -07:00
parent 3feae65585
commit eb0898fe4e
7 changed files with 90 additions and 12 deletions

View file

@ -104,6 +104,23 @@ Get the current "playing" status. The return value is one of: `"PLAYING"`, `"STO
const isPlaying = webamp.getMediaStatus() === "PLAYING";
```
### `getPlayerMediaStatus(): PlayerMediaStatus`
Get the current "playing" status of the player. Similar to `getMediaStatus()`, but can differentiate between different reasons why the player might not be playing, such as "ENDED" when the end of the playlist has been reached or "CLOSED" when the player has been closed.
The return value is one of: `"PLAYING"`, `"STOPPED"`, `"PAUSED"`, `"ENDED"`, or `"CLOSED"`.
**Since** 2.1.3
```ts
const playerStatus = webamp.getPlayerMediaStatus();
if (playerStatus === "ENDED") {
console.log("Playlist has ended");
} else if (playerStatus === "CLOSED") {
console.log("Player is closed");
}
```
### `pause(): void`
Pause the current track.

View file

@ -9,6 +9,7 @@
- Added new `Webamp` instance methods:
- `webamp.toggleShuffle`
- `webamp.toggleRepeat`
- `webamp.getPlayerMediaStatus`
- Add new config option `enableMediaSession` to allow Webamp to connect to the browser's Media Session API. This enables OS/hardware level media controls like play/pause/next/previous.
- Ensure the promise returned from `renderWhenReady` only resolves after the Webamp instance has been fully mounted and inserted into the DOM. Previously it resolved after the DOM node was created but before it was inserted into the DOM.

View file

@ -5,6 +5,7 @@ import {
LoadStyle,
TimeMode,
WindowId,
PlayerMediaStatus,
} from "./types";
import baseSkin from "./baseSkin.json";
export const BANDS: Band[] = [
@ -64,9 +65,17 @@ export const TIME_MODE: Record<TimeMode, TimeMode> = {
REMAINING: "REMAINING",
};
// TODO: Convert to enum once we are fully Typescript
export const MEDIA_STATUS: Record<MediaStatus, MediaStatus> = {
PLAYING: "PLAYING",
STOPPED: "STOPPED",
PAUSED: "PAUSED",
};
export const PLAYER_MEDIA_STATUS: Record<PlayerMediaStatus, PlayerMediaStatus> =
{
PLAYING: "PLAYING",
STOPPED: "STOPPED",
PAUSED: "PAUSED",
ENDED: "ENDED",
CLOSED: "CLOSED",
};

View file

@ -1,4 +1,4 @@
import { Action, MediaStatus, TimeMode } from "../types";
import { Action, PlayerMediaStatus, TimeMode } from "../types";
import {
PLAY,
STOP,
@ -13,8 +13,10 @@ import {
TOGGLE_TIME_MODE,
UPDATE_TIME_ELAPSED,
LOAD_SERIALIZED_STATE,
CLOSE_WINAMP,
OPEN_WINAMP,
} from "../actionTypes";
import { TIME_MODE, MEDIA_STATUS } from "../constants";
import { TIME_MODE, PLAYER_MEDIA_STATUS } from "../constants";
import { MediaSerializedStateV1 } from "../serializedStates/v1Types";
export interface MediaState {
@ -24,7 +26,7 @@ export interface MediaState {
balance: number;
shuffle: boolean;
repeat: boolean;
status: MediaStatus;
status: PlayerMediaStatus;
}
const defaultState = {
@ -39,7 +41,7 @@ const defaultState = {
shuffle: false,
repeat: false,
// TODO: Enforce possible values
status: MEDIA_STATUS.STOPPED,
status: PLAYER_MEDIA_STATUS.STOPPED,
};
const media = (
@ -50,12 +52,17 @@ const media = (
// TODO: Make these constants
case PLAY:
case IS_PLAYING:
return { ...state, status: MEDIA_STATUS.PLAYING };
return { ...state, status: PLAYER_MEDIA_STATUS.PLAYING };
case PAUSE:
return { ...state, status: MEDIA_STATUS.PAUSED };
return { ...state, status: PLAYER_MEDIA_STATUS.PAUSED };
case STOP:
return { ...state, status: PLAYER_MEDIA_STATUS.STOPPED };
case IS_STOPPED:
return { ...state, status: MEDIA_STATUS.STOPPED };
return { ...state, status: PLAYER_MEDIA_STATUS.ENDED };
case OPEN_WINAMP:
return { ...state, status: PLAYER_MEDIA_STATUS.STOPPED };
case CLOSE_WINAMP:
return { ...state, status: PLAYER_MEDIA_STATUS.CLOSED };
case TOGGLE_TIME_MODE:
const newMode =
state.timeMode === TIME_MODE.REMAINING

View file

@ -8,7 +8,6 @@ import {
WindowPositions,
PlaylistStyle,
TransitionType,
MediaStatus,
TimeMode,
SkinImages,
Cursors,
@ -16,6 +15,8 @@ import {
GenLetterWidths,
MilkdropMessage,
DummyVizData,
PlayerMediaStatus,
MediaStatus,
} from "./types";
import { createSelector, defaultMemoize } from "reselect";
import * as Utils from "./utils";
@ -29,6 +30,7 @@ import {
MEDIA_TAG_REQUEST_STATUS,
WINDOWS,
VISUALIZERS,
PLAYER_MEDIA_STATUS,
} from "./constants";
import { createPlaylistURL } from "./playlistHtml";
import * as fromTracks from "./reducers/tracks";
@ -337,11 +339,28 @@ export const getCurrentTrackDisplayName = createSelector(
return getName(id);
}
);
export const getMediaStatus = (state: AppState): MediaStatus => {
export const getPlayerMediaStatus = (state: AppState): PlayerMediaStatus => {
return state.media.status;
};
export const getMediaStatus = createSelector(
getPlayerMediaStatus,
(status: PlayerMediaStatus): MediaStatus => {
switch (status) {
case "PLAYING":
case "PAUSED":
return status;
case "STOPPED":
case "ENDED":
case "CLOSED":
return "STOPPED";
default:
const s: never = status;
throw new Error(`Unknown media status: ${s}`);
}
}
);
export const getMediaIsPlaying = (state: AppState) =>
state.media.status === MEDIA_STATUS.PLAYING;

View file

@ -564,8 +564,22 @@ export type MediaTagRequestStatus =
| "COMPLETE"
| "NOT_REQUESTED";
/** The status of the current media. */
export type MediaStatus = "PLAYING" | "STOPPED" | "PAUSED";
/**
* The media status of the player. Similar to MediaStatus but can discriminate
* between different reasons for being stopped.
*/
export type PlayerMediaStatus =
| "PLAYING"
| "STOPPED"
| "PAUSED"
/** We have reached the end of the playlist. */
| "ENDED"
/** The player is closed. */
| "CLOSED";
export type LoadStyle = "BUFFER" | "PLAY" | "NONE";
export type TimeMode = "ELAPSED" | "REMAINING";

View file

@ -13,6 +13,7 @@ import {
Options,
MediaStatus,
PlaylistTrack,
PlayerMediaStatus,
} from "./types";
import getStore from "./store";
import App from "./components/App";
@ -337,10 +338,20 @@ class Webamp {
/**
* Get the current "playing" status.
*/
getMediaStatus(): MediaStatus | null {
getMediaStatus(): MediaStatus {
return Selectors.getMediaStatus(this.store.getState());
}
/**
* Get the current "playing" status of the player. Similar to
* `getMediaStatus()`, but can differentiate between different reasons why the
* player might not be playing, such as "ENDED" when the end of the playlist
* has been reached or "CLOSED" when the player has been closed.
*/
getPlayerMediaStatus(): PlayerMediaStatus {
return Selectors.getPlayerMediaStatus(this.store.getState());
}
/**
* A callback which will be called when Webamp is _about to_ close. Returns an
* "unsubscribe" function. The callback will be passed a `cancel` function