Skip to content

Make BasePlayer abstract instead of HTML5-defaulted #214

@maboa

Description

@maboa

Observation

BasePlayer (in js/hyperaudio-lite.js, line 7) currently provides HTML5-flavored defaults for getTime, setTime, play, and pause:

class BasePlayer {
  getTime() { return Promise.resolve(this.player.currentTime); }
  setTime(seconds) { this.player.currentTime = seconds; }
  play() { this.player.play(); this.paused = false; }
  pause() { this.player.pause(); this.paused = true; }
}

This is convenient for NativePlayer, which can extend BasePlayer and immediately work without overriding anything. But every non-native subclass (SoundCloudPlayer, VideoJSPlayer, VimeoPlayer, YouTubePlayer, SpotifyPlayer) has to override all four methods because their player object's API doesn't match the HTML5 surface.

Suggested direction

Treat BasePlayer as a proper abstract base with stub methods (throwing or no-op), and move the HTML5-specific behavior into NativePlayer itself. That way:

  • The base class signals the contract (every player must implement these four methods) rather than a particular implementation.
  • New player integrations can't accidentally inherit silently-wrong HTML5 behavior just by forgetting to override one method — they'd get a clear error.
  • The semantics of NativePlayer become explicit at the call site rather than implicit through inheritance.

Roughly:

class BasePlayer {
  initPlayer(instance) { throw new Error('initPlayer must be implemented'); }
  getTime() { throw new Error('getTime must be implemented'); }
  setTime(seconds) { throw new Error('setTime must be implemented'); }
  play() { throw new Error('play must be implemented'); }
  pause() { throw new Error('pause must be implemented'); }
}

class NativePlayer extends BasePlayer {
  initPlayer(instance) { return instance.player; }
  getTime() { return Promise.resolve(this.player.currentTime); }
  setTime(seconds) { this.player.currentTime = seconds; }
  play() { this.player.play(); this.paused = false; }
  pause() { this.player.pause(); this.paused = true; }
}

Trade-off

NativePlayer becomes slightly larger (~10 lines that were previously inherited). Other player classes stay roughly the same length. The total file grows by a handful of lines but each class becomes more honest about what it implements.

Priority

Low. Pure design hygiene — current code works correctly. Worth doing alongside other refactor work, not on its own.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions