Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

CDGPlayer provides browser karaoke playback libraries under the `@cxing/cdg-\*` package family.

**BREAKING CHANGE**: The legacy `CDGPlayer` and `CDGControls` monolithic packages have been deprecated and replaced with a modular package architecture. See the [migration guide](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-migration-guide--docs) for details.
**BREAKING CHANGE**: The legacy `CDGPlayer` and `CDGControls` monolithic packages have been deprecated and replaced with a modular package architecture. See the [migration guide](https://cutterscrossing.com/?path=/docs/documentation-migration-guide--docs) for details.

## Packages

Expand All @@ -23,14 +23,14 @@ Install the packages your app needs.

## Documentation

- [Getting started](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-getting-started--documentation)
- [Migration guide](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-migration-guide--docs)
- [Logger contract](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-logger-contract--docs)
- [Loader contract](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-loader-contract--documentation)
- [Player contract](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-player-contract--documentation)
- [Controls contract](https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-controls-contract--documentation)
- [Framework-agnostic implementation guide](https://cutterbl.github.io/CDGPlayer/storybook-web/?path=/docs/examples-framework-agnostic-demo-implementation-guide--documentation)
- [React implementation guide](https://cutterbl.github.io/CDGPlayer/storybook-react/?path=/docs/examples-react-demo-implementation-guide--documentation)
- [Getting started](https://cutterscrossing.com/?path=/docs/documentation-getting-started--documentation)
- [Migration guide](https://cutterscrossing.com/?path=/docs/documentation-migration-guide--docs)
- [Logger contract](https://cutterscrossing.com/?path=/docs/documentation-api-logger-contract--docs)
- [Loader contract](https://cutterscrossing.com/?path=/docs/documentation-api-loader-contract--documentation)
- [Player contract](https://cutterscrossing.com/?path=/docs/documentation-api-player-contract--documentation)
- [Controls contract](https://cutterscrossing.com/?path=/docs/documentation-api-controls-contract--documentation)
- [Framework-agnostic implementation guide](https://cutterscrossing.com/storybook-web/?path=/docs/examples-framework-agnostic-demo-implementation-guide--documentation)
- [React implementation guide](https://cutterscrossing.com/storybook-react/?path=/docs/examples-react-demo-implementation-guide--documentation)

## Repository Contribution

Expand Down
8 changes: 8 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ export default [
files: ['**/*.{spec,test}.{ts,tsx,js,jsx}'],
rules: {
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
];
6 changes: 3 additions & 3 deletions packages/cdg-controls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ Your player adapter must provide:

## Docs

- Controls contract: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-controls-contract--docs
- Framework-agnostic guide: https://cutterbl.github.io/CDGPlayer/storybook-web/?path=/docs/examples-framework-agnostic-demo-implementation-guide--docs
- React guide: https://cutterbl.github.io/CDGPlayer/storybook-react/?path=/docs/examples-react-demo-implementation-guide--docs
- Controls contract: https://cutterscrossing.com/?path=/docs/documentation-api-controls-contract--docs
- Framework-agnostic guide: https://cutterscrossing.com/storybook-web/?path=/docs/examples-framework-agnostic-demo-implementation-guide--docs
- React guide: https://cutterscrossing.com/storybook-react/?path=/docs/examples-react-demo-implementation-guide--docs
2 changes: 1 addition & 1 deletion packages/cdg-controls/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"type": "git",
"url": "https://github.com/cutterbl/CDGPlayer.git"
},
"homepage": "https://cutterbl.github.io/CDGPlayer",
"homepage": "https://cutterscrossing.com",
"bugs": {
"url": "https://github.com/cutterbl/CDGPlayer/issues"
},
Expand Down
90 changes: 90 additions & 0 deletions packages/cdg-controls/src/lib/controls.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,74 @@ class MockPlayerWithoutTempo
}
}

class MockPlayerWithDelayedPlay
extends EventTarget
implements ControlsPlayerAdapter
{
private state: ControlsPlayerState = {
status: 'idle',
trackId: null,
currentTimeMs: 0,
durationMs: 0,
volume: 1,
playbackRate: 1,
pitchSemitones: 0,
};

plays = 0;
pauses = 0;
private resolvePlay: (() => void) | null = null;

getState(): Readonly<ControlsPlayerState> {
return this.state;
}

async play(): Promise<void> {
this.plays += 1;

await new Promise<void>((resolve) => {
this.resolvePlay = resolve;
});

this.setState({ status: 'playing' });
}

pause(): void {
this.pauses += 1;
this.setState({ status: 'paused' });
}

stop(): void {
this.setState({ status: 'ready', currentTimeMs: 0 });
}

seek(_args: { percentage: number }): void {
// Not needed for this test adapter.
}

setVolume(_args: { value: number }): void {
// Not needed for this test adapter.
}

setPlaybackRate(_args: { value: number }): void {
// Not needed for this test adapter.
}

setPitchSemitones(_args: { value: number }): void {
// Not needed for this test adapter.
}

flushPlayRequest(): void {
this.resolvePlay?.();
this.resolvePlay = null;
}

setState(nextPatch: Partial<ControlsPlayerState>): void {
this.state = { ...this.state, ...nextPatch };
this.dispatchEvent(new CustomEvent('statechange'));
}
}

describe('controls', () => {
it('supports distributed controls via a shared model', async () => {
const player = new MockPlayer();
Expand Down Expand Up @@ -350,4 +418,26 @@ describe('controls', () => {
controls.dispose();
container.remove();
});

it('pauses on the next toggle even when play is still pending', async () => {
const player = new MockPlayerWithDelayedPlay();
player.setState({ status: 'ready' });

const model = createControlsModel({
options: {
player,
},
});

const firstToggle = model.togglePlayPause();
expect(player.plays).toBe(1);

await model.togglePlayPause();
expect(player.pauses).toBe(1);

player.flushPlayRequest();
await firstToggle;

model.dispose();
});
});
16 changes: 13 additions & 3 deletions packages/cdg-controls/src/lib/controls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class DefaultCdgControlsModel implements CdgControlsModel {
(state: Readonly<ControlsViewState>) => void
>();
private state: ControlsViewState;
private playRequestInFlight = false;

constructor({ player }: { player: ControlsPlayerAdapter }) {
this.player = player;
Expand All @@ -266,16 +267,25 @@ class DefaultCdgControlsModel implements CdgControlsModel {
}

async togglePlayPause(): Promise<void> {
if (!this.state.isPlayable) {
const liveState = deriveViewState({ playerState: this.player.getState() });

if (!liveState.isPlayable) {
return;
}

if (this.state.isPlaying) {
if (liveState.isPlaying || this.playRequestInFlight) {
this.playRequestInFlight = false;
this.player.pause();
return;
}

await this.player.play();
this.playRequestInFlight = true;

try {
await this.player.play();
} finally {
this.playRequestInFlight = false;
}
}

seekPercent({ percentage }: { percentage: number }): void {
Expand Down
4 changes: 2 additions & 2 deletions packages/cdg-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ const instructions = parser.parseInstructions({ bytes: cdgBytes });

## Docs

- Architecture: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-architecture--docs
- Player contract: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-player-contract--docs
- Architecture: https://cutterscrossing.com/?path=/docs/documentation-architecture--docs
- Player contract: https://cutterscrossing.com/?path=/docs/documentation-api-player-contract--docs
2 changes: 1 addition & 1 deletion packages/cdg-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"type": "git",
"url": "https://github.com/cutterbl/CDGPlayer.git"
},
"homepage": "https://cutterbl.github.io/CDGPlayer",
"homepage": "https://cutterscrossing.com",
"bugs": {
"url": "https://github.com/cutterbl/CDGPlayer/issues"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/cdg-loader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@ You can use worker-backed loading via `loadInWorker(...)` with automatic fallbac

## Docs

- Loader contract: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-loader-contract--docs
- Migration guide: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-migration-guide--docs
- Loader contract: https://cutterscrossing.com/?path=/docs/documentation-api-loader-contract--docs
- Migration guide: https://cutterscrossing.com/?path=/docs/documentation-migration-guide--docs
2 changes: 1 addition & 1 deletion packages/cdg-loader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"type": "git",
"url": "https://github.com/cutterbl/CDGPlayer.git"
},
"homepage": "https://cutterbl.github.io/CDGPlayer",
"homepage": "https://cutterscrossing.com",
"bugs": {
"url": "https://github.com/cutterbl/CDGPlayer/issues"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/cdg-player/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,5 @@ player.setPitchSemitones({ value: -2 });

## Docs

- Player contract: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-player-contract--docs
- Controls contract: https://cutterbl.github.io/CDGPlayer/?path=/docs/documentation-api-controls-contract--docs
- Player contract: https://cutterscrossing.com/?path=/docs/documentation-api-player-contract--docs
- Controls contract: https://cutterscrossing.com/?path=/docs/documentation-api-controls-contract--docs
2 changes: 1 addition & 1 deletion packages/cdg-player/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"type": "git",
"url": "https://github.com/cutterbl/CDGPlayer.git"
},
"homepage": "https://cutterbl.github.io/CDGPlayer",
"homepage": "https://cutterscrossing.com",
"bugs": {
"url": "https://github.com/cutterbl/CDGPlayer/issues"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/logger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"type": "git",
"url": "https://github.com/cutterbl/CDGPlayer.git"
},
"homepage": "https://cutterbl.github.io/CDGPlayer",
"homepage": "https://cutterscrossing.com",
"bugs": {
"url": "https://github.com/cutterbl/CDGPlayer/issues"
},
Expand Down
Loading