Skip to content

hyperaudio/hyperaudio-lite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

460 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ¦‹ Hyperaudio Lite πŸ¦‹

πŸ”† To make media on the web more accessible we believe that every piece of spoken-word audio and video should come with an Interactive Transcript.πŸ”†

Hyperaudio Lite - is an Interactive Transcript Viewer

You can use Hyperaudio Lite to provide Interactive Transcripts, this readme details why and how.

  • lightweight (around 10Kb minified)
  • no dependencies
  • no frameworks (vanilla JavaScript)
  • no build step
  • MIT Licensed

🐯 Hyperaudio Lite in the Wild 🐯

As demonstrated here https://hyperaudio.github.io/hyperaudio-lite/ plus equivalent multiplayer version

Active word version https://hyperaudio.github.io/hyperaudio-lite/active.html

Alternatively styled version https://lab.hyperaud.io/mozfest2021/interviews/lance_weiler/

YouTube Integration https://hyperaudio.github.io/hyperaudio-lite/youtube.html β€” and a multiplayer version with two YouTube players on one page

SoundCloud Integration https://hyperaudio.github.io/hyperaudio-lite/soundcloud.html

Vimeo Integration https://hyperaudio.github.io/hyperaudio-lite/vimeo.html

VideoJS Integration https://hyperaudio.github.io/hyperaudio-lite/videojs.html

VidStack Integration https://hyperaudio.github.io/hyperaudio-lite/vidstack.html

Spotify Integration https://hyperaudio.github.io/hyperaudio-lite/spotify.html

Vitorio's version https://github.com/vitorio/hyperaudio-lite

🌟 Hyper Powers 🌟

Interactive transcripts are transcripts with special powers. Hyperaudio's Interactive Transcripts are called Hypertranscripts and are infused with the following hyper-powers:

πŸ—ΊοΈ Navigate

Click on the text to navigate directly to the part of the audio where that word was said.

πŸ”Ž Search

Find words and phrases inside your transcript and make your media search-engine friendly.

πŸ‘©β€β€οΈβ€πŸ‘© Share

Selecting part of a transcript creates a URL with timing data which when shared will take people directly to the corresponding piece of audio where the highlighted words are spoken.

πŸ“Ό Data Formats πŸ“Ό

Hypertranscripts contain the following data:

  • Paragraphs
  • Words
  • Word start time (data-m milliseconds)
  • Word duration (data-d milliseconds)

That's it!

Here's an example:

<p>
  <span data-m="52890" data-d="0" class="speaker">Alexandra: </span>
  <span data-m="52890" data-d="90">I </span>
  <span data-m="52980" data-d="240">think </span>
  <span data-m="53220" data-d="720">unfortunately </span>
  <span data-m="53970" data-d="60">at </span>
  <span data-m="54030" data-d="60">the </span>
  <span data-m="54090" data-d="270">minute, </span>
  <span data-m="54390" data-d="180">we </span>
  <span data-m="54570" data-d="180">make </span>
  <span data-m="54750" data-d="270">people </span>
  <span data-m="55020" data-d="300">aware </span>
  <span data-m="55320" data-d="90">of </span>
  <span data-m="55410" data-d="150">their </span>
  <span data-m="55560" data-d="480">personal </span>
  <span data-m="56040" data-d="330">data </span>
  <span data-m="56370" data-d="210">when </span>
  <span data-m="56580" data-d="480">terrible </span>
  <span data-m="57060" data-d="300">things </span>
  <span data-m="57360" data-d="510">happen. </span>
</p>

Hyperaudio Lite is "tag agnostic" so for example, you could use other tags instead of <span> to wrap words.

You could also make headings link to chapter points using attributes, like this:

<h5 data-m="214800">
  What kind of help is available for people to manage their own data?
</h5>

We can see that a Hypertranscript is really just HTML, this helps keep it:

  • πŸ‘ extensible
  • πŸ‘ accessible
  • πŸ‘ readable

How to make a Hypertranscript

The best way is to use the Hyperaudio Lite Editor.

Another way is to use the Hyperaudio Converter

This currently takes 4 possible inputs:

*JavaScript Object Notation - a common data format

πŸ’Ύ Hyperaudio Lite Code πŸ’Ύ

Essentially the Hyperaudio Lite library is made from 4 JavaScript files:

  1. hyperaudio-lite.js - the core that deals with the linking of media to words
  2. hyperaudio-lite wrapper - adds search, selection and playback rate functionality

and the associated CSS files:

  1. hyperaudio-lite-player.css

Autoscroll uses the browser's native smooth scrolling.

Add to your HTML file in the following way:

<head>
  <link rel="stylesheet" href="css/hyperaudio-lite-player.css">
</head>

and at the end of the <body>:

  <script src="js/hyperaudio-lite.js"></script>
  <script src="js/hyperaudio-lite-wrapper.js"></script>
</body>

Using as an ES module or CommonJS

Hyperaudio Lite is also distributed as ES module and CommonJS forms alongside the classic script, so modern frontend projects (Vite, webpack, Rollup, etc.) and Node-based tooling can consume it directly without vendoring or patching:

// ESM
import { HyperaudioLite } from 'hyperaudio-lite';

// CommonJS
const { HyperaudioLite } = require('hyperaudio-lite');

The classic <script> form still works exactly as before. Bundlers and Node resolve to js/hyperaudio-lite.mjs (ESM) or js/hyperaudio-lite.js (CJS) automatically via the package's exports map.

Finally instantiate the Transcript Player. Pass an options object identifying the transcript and player elements (by id), plus any optional behaviour flags:

new HyperaudioLite({
  transcript: "hypertranscript",
  player: "hyperplayer",
  autoScroll: true,
  playOnClick: true,
});

All options:

Option Default Description
transcript (required) Element id of the transcript container
player (required) Element id of the audio/video element (or third-party player iframe)
autoScroll true Scroll the transcript to follow playback and seeks
playOnClick true Start playback when the user clicks a word
doubleClick false Require a double-click instead of a single click for word interaction
minimizedMode false Show the current word in the browser tab title (experimental)
webMonetization false Inject <link rel="monetization"> from data-wm payment pointers in the transcript
scrollOffset 0 Pixels to subtract from the autoscroll target (useful when a sticky header overlaps the transcript)
scrollContainer transcript element The element that scrolls to follow playback β€” an element or an element id. Pass document.scrollingElement for layouts where the page itself scrolls rather than the transcript

Deprecated positional form

The original positional-argument form still works for backward compatibility across the 2.x line, but is no longer recommended:

// Deprecated β€” emits a console warning
new HyperaudioLite("hypertranscript", "hyperplayer", false, true, false, false, true);

Autoscroll behaviour

When autoScroll is enabled, the transcript follows playback and also follows seeks while paused β€” scrubbing the media (drag the seek bar, jump in the native controls, set currentTime) re-aligns the transcript's read/unread state and scroll position to the new playhead.

To temporarily disable autoscroll (e.g. while a user is editing the transcript), call pauseAutoscroll() and re-enable it with resumeAutoscroll():

const player = new HyperaudioLite({ transcript: "hypertranscript", player: "hyperplayer" });
player.pauseAutoscroll();
// ...later
player.resumeAutoscroll();

Tearing down

If you mount and unmount transcripts dynamically (for example in a single-page app), call destroy() when you're done with an instance. It removes every DOM listener the instance added (transcript, native player, popover), stops the playback polling loop, and cancels any in-flight scroll animation:

const player = new HyperaudioLite({ transcript: "hypertranscript", player: "hyperplayer" });
// ...when the view unmounts
player.destroy();

Note – embed players (YouTube, Vimeo, SoundCloud, Spotify) keep listeners inside their own iframe APIs; discard the instance (and the embed) after calling destroy().

Keyboard access and reduced motion

Pressing Enter or Space on a focused transcript word sets the playhead, exactly like a click. Words are <span>s, so they aren't focusable by default β€” add tabindex="0" to the word elements in your transcript markup to enable keyboard navigation:

<span data-m="4470" data-d="270" tabindex="0">We </span>

When a visitor has "reduce motion" enabled in their operating system (prefers-reduced-motion: reduce), autoscroll jumps directly to the target paragraph instead of animating.

Driving the transcript from a custom seek bar

If you're building your own seek bar (or any other custom scrubbing UI) and want the transcript to follow it live, call updateTranscriptVisualState(currentTime, forceActiveWord):

mySeekBar.addEventListener('input', () => {
  const t = (mySeekBar.value / mySeekBar.max) * media.duration;
  media.currentTime = t;
  player.updateTranscriptVisualState(t, true);
});

The second argument, forceActiveWord, defaults to false. When true, the word-level .active class is added even while the media is paused β€” needed so that default CSS (.active > .active) continues to highlight the active word during a paused scrub. Pass true from any custom seek/scrub handler that runs while paused. The library's own internal seeked listener already passes true, so consumers relying only on the native player controls don't need to do anything.

If you want to use the native audio/video capabilities of your browser, you would define your player something like this:

<video id="hyperplayer" controls></video>

or in the case of audio:

<audio id="hyperplayer" controls></audio>

Optionally, you can include your source media file in the player definition:

<video id="hyperplayer" controls src="https://example.com/somevideo.mp4"></video>

Note – hyperplayer is the id that you will use to instantiate (see above).

If you want to use other players such as YouTube or Soundcloud, use the embeds in the following sections instead.

You will also need to define your interactive transcript – something like this:

<div id="hypertranscript" class="hyperaudio-transcript">
  <article>
    <section data-media-src="https://example.com/somevideo.mp4">
      <p>
        <span data-m="4470" data-d="0" class="speaker">Doc: </span>
        <span data-m="4470" data-d="270">We </span>
        <span data-m="4740" data-d="240">have </span>
        <span data-m="5010" data-d="300">two </span>
        <span data-m="5310" data-d="600">selves </span>
        <span data-m="6030" data-d="150">in </span>
        <span data-m="6180" data-d="120">the </span>
        <span data-m="6300" data-d="300">world </span>
        <span data-m="6600" data-d="90">at </span>
        <span data-m="6690" data-d="150">any </span>
        <span data-m="6840" data-d="300">given </span>
        <span data-m="7140" data-d="310">time </span>
        <span data-m="7540" data-d="180">now. </span>
      </p>
    </section>
  </article>
</div>

Note – it is up to you where you define your media source. In our examples we include it in the transcript itself using the data-media-src attribute.

For a complete example see demos/index.html β€” or use the View source button on any demo page at hyperaudio.github.io/hyperaudio-lite/.

See a version with multiple players in a single page https://hyperaudio.github.io/hyperaudio-lite/multiplayer.html

πŸ“Ί YouTube Support πŸ“Ί

In addition to supporting the web-native HTML <audio> and <video> elements we also support a YouTube iframe embed.

Example of YouTube iframe embed:

<iframe
  id="hyperplayer"
  data-player-type="youtube"
  width="400"
  height="300"
  frameborder="no"
  allow="autoplay"
  src="https://www.youtube.com/embed/xLcsdc823dg?enablejsapi=1"
>
</iframe>

πŸ”‰ SoundCloud Support πŸ”‰

We also support a SoundCloud iframe embed.

Example of Soundcloud API and iframe embed:

<script src="https://w.soundcloud.com/player/api.js"></script>
<iframe
  id="hyperplayer"
  data-player-type="soundcloud"
  width="100%"
  height="166"
  scrolling="no"
  frameborder="no"
  allow="autoplay"
  src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/730479133&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true"
></iframe>

You can get the snippet of code by visiting the page of the SoundCloud file you're interested in, clicking on Share and then Embed.

😍 Other Player Support 😍

We also now support Vimeo and VideoJS players. See the Vimeo example and VideoJS example for how to emebed. Please let us know if their are other types of players you wish us to support by creating an issue.

Adding your own player

You can plug in a player we don't ship support for with HyperaudioLite.registerPlayer(). Register a class for a data-player-type value before instantiating; it should extend BasePlayer (exported from the module builds) β€” or at minimum accept the HyperaudioLite instance in its constructor and implement getTime(), setTime(seconds), play() and pause():

class MyPlayer extends BasePlayer {
  initPlayer(instance) { return myPlayerApi(instance.player.id); }
  getTime() { return Promise.resolve(this.player.position()); }
  setTime(seconds) { this.player.seek(seconds); }
  play() { this.player.play(); this.paused = false; }
  pause() { this.player.pause(); this.paused = true; }
}

HyperaudioLite.registerPlayer("myplayer", MyPlayer);
<div id="hyperplayer" data-player-type="myplayer">...</div>

πŸ“  Captions πŸ“ 

For those using native video, we also provide a way to add autogenerated captions.

First, ensure that your video player has a text track defined:

<video id="hyperplayer" controls>
  <track id="hyperplayer-vtt" label="English" kind="subtitles" srclang="en" src="">
</video>

Next, make sure you include the caption.js file:

<script src="js/caption.js"></script>

and finally add this snippet of JavaScript after instantiating the HyperaudioLite object:

let cap1 = caption();
cap1.init("hypertranscript", "hyperplayer", '37' , '21'); // transcript Id, player Id, max chars, min chars for caption line

πŸ’Έ Web Monetization Support πŸ’Έ

Web Monetization is a browser API, stewarded by the Interledger Foundation, that lets visitors stream micropayments to the sites they're reading. There is currently no native browser support β€” visitors need a Web Monetization agent (browser extension) installed to actually pay.

With Hyperaudio Lite you can apportion those streamed funds to different recipients depending on which transcript β€” or which part of the transcript β€” the viewer is currently listening to.

See demos/active.html for a working example.

How to enable it

Set the Web Monetization parameter to true when instantiating HyperaudioLite:

let minimizedMode = false;
let autoScroll = true;
let doubleClick = false;
let webMonetization = true;
let playOnClick = true;

new HyperaudioLite("hypertranscript", "hyperplayer", minimizedMode, autoScroll, doubleClick, webMonetization, playOnClick);

Then add data-wm attributes (containing wallet URLs) to elements in your transcript. As playback moves between elements, Hyperaudio Lite injects a <link rel="monetization" href="..."> element into the page <head>, pointed at the currently active wallet URL.

   <article data-wm="https://ilp.uphold.com/123article">

      <section data-wm="https://ilp.uphold.com/123section">

        <h5 data-m="0">How do we make people more aware of their personal data?</h5>

        <p data-wm="https://ilp.uphold.com/123Doc">
          <span data-m="4470" data-d="0" class="speaker">Doc: </span>
          <span data-m="4470" data-d="270">We </span>
          <span data-m="4740" data-d="240">have </span>
          <span data-m="5010" data-d="300">two </span>
          <span data-m="5310" data-d="600">selves </span>
          ...

Note – if a data-wm attribute is not present on an element, Hyperaudio Lite walks up to the parent (and the parent's parent, etc.) until it finds one.

Note – the value of data-wm should be a full wallet URL (e.g. https://ilp.uphold.com/...), not the older $-prefixed payment-pointer shorthand. The shorthand form is no longer recognised by current Web Monetization agents.

πŸ‘· Testing πŸ‘·

Currently we use Jest for testing.

Install Jest using yarn: yarn add --dev jest then yarn add -D jest-environment-jsdom

Or npm: npm install --save-dev jest then npm install -D jest-environment-jsdom

To run the tests: yarn test or npm run test

Note: If you have issues runing the tests, try a more recent version of node. (node v18.0.0 should work).

Contributing changes to the library

js/hyperaudio-lite.mjs (the ES module build) is generated from js/hyperaudio-lite.js. If you edit the library, regenerate it with:

npm run build

CI runs the tests and fails if the generated ESM build is out of step with the source.

βœ‹ How do I create timed transcripts to use with Hyperaudio Lite? βœ‹

  1. You can use our the Hyperaudio Lite Editor
  2. You can convert from various formats with our Converter

πŸ’Έ Support πŸ’Έ

Please support The Hyperaudio Project by donating to our Patreon account.


Find out more about the Hyperaudio Project at hyper.audio or contact mark@hyperaud.io

About

Hyperaudio Lite - a Super-lightweight Interactive Transcript Player

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors