JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 25
  • Score
    100M100P100Q56427F
  • License UNLICENSED

A web component for an interactive transcript built from WebVTT cues.

Package Exports

  • media-transcript

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (media-transcript) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Media Transcript

A web component for displaying WebVTT cues as an interactive transcript.

Install

Since this module isn't hosted on npm, you'll need to install directly from GitLab via SSH. Send a message if you need access.

npm install git+ssh://git@gitlab.com:wwnorton/platform/media-transcript.git#v1.2.0

Usage

Instantiate the MediaTranscript class and then add cues to it. The MediaTranscript class requires a related media element ( or ) to get started. This can be an actual element, or a selector.

const MediaTranscript = require('media-transcript');

const vid = document.querySelector('video');
const transcript = new MediaTranscript(vid);

If you'd like to use the browser script (in dist/), the MediaTranscript class will be attached to the window. You can also instantiate a new element with document.createElement('media-transcript').

...
<body>
    ...
    <script type="text/javascript" src="media-transcript.js"></script>
    <script type="text/javascript">
        const vid = document.querySelector('video');

        /** instantiate with `new` */
        const t1 = new MediaTranscript(vid);

        /** instantiate with .createElement() */
        const t2 = document.createElement('media-transcript');
        /** make it interactive by adding the .relatedElement */
        t2.relatedElement = vid;
    </script>
</body>
...

Options

Pass either a relatedElement, or a config object to the MediaTranscript class on instantiation. Config options are documented here.

  • relatedElement | {String|HTMLElement} | default: null (required for interactive=true)
    Provide a related element either as a selector string (e.g. '#my-video') or as an element (e.g. document.getElementById('my-video')). The related element should either be the ancestor of an <audio>/<video> element, or be one itself. This can also be added later with the .relatedElement setter.

  • idleTime | {Number} in ms | default: 4000
    Time until the states.idle class is added to the transcript (interactive only)

  • timeFormat | {String} | default: 'mm:ss'
    How the <time> element in the transcript cue line should be formatted. Options are mm:ss or hh:mm:ss.

  • timeupdateListener | {Boolean} | default: true
    Trigger cue changes on the mediaElement's (<audio> or <video>) timeupdate events.

  • rover | {Object} | default: { horizontal: false, wrap: false }
    Configuration used to set up focus-rover.

  • classNames | {Object.<String>}
    Classes used to name the elements of the transcript.

    • transcript | default: 'transcript' | applied to <media-transcript>
    • cue | default: 'cue' | applied to <media-cue> (child of <media-transcript>)
    • timestamp | default: 'cue__timestamp' | applied to <time> (child of <media-cue>)
    • text | default: 'cue__text' | applied to <span> (child of <media-cue>)
  • states | {Object.<String>}
    Classes used to denote the state of various elements.

    • idle | default: 'transcript--idle' | applied to <media-transcript> after idleTime has passed
    • interactive | default: 'cue--interactive' | applied to <media-cue> when config.interactive=true
    • active | default: 'cue--active' | applied to <media-cue> when it is currently active

Structure

With default options and interactive=true, the transcript might look like this:

<media-transcript class="transcript transcript--idle" id="my-video-transcript" role="listbox">
  ...
  <media-cue start="43.36" end="45.48" class="cue cue--interactive" tabindex="-1">
    <time class="cue__timestamp">00:43</time>
    <span class="cue__text">...</span>
  </media-cue>
  <media-cue start="45.48" end="47.15" class="cue cue--interactive cue--active" tabindex="0">
    <time class="cue__timestamp">00:45</time>
    <span class="cue__text">...</span>
  </media-cue>
  ...
</media-transcript>

Examples

The following examples can be found in the examples/ directory, and can be tested with npm run serve.

Interactive transcript using the HTML5 <track> element

const vid = document.querySelector('video');
const captions = vid.querySelector('track[kind=captions]');
const track = captions.track;

/** track interfaces don't emit events if they're disabled */
if (track.mode === 'disabled') track.mode = 'hidden';

/** initialize the transcript via .createElement() */
const transcript = document.createElement('media-transcript');

/** add the relatedElement to the transcript */
transcript.relatedElement = vid;

/** once loaded, add cues to the transcript and add it to the DOM */
captions.addEventListener('load', function(e) {
    transcript.addCues([...track.cues]);
    vid.parentElement.appendChild(transcript);
});

Static transcript using vtt.js to parse a WebVTT file

/** where to put the transcript when we're done */
const container = document.getElementById('transcript');

/** initialize the transcript as non-interactive via new */
const transcript = new MediaTranscript({ interactive: false });

/** initialize vtt.js with the provided decoder */
const parser = new WebVTT.Parser(window, WebVTT.StringDecoder());

/** set up cue events to add a cue to our transcript custom element */
parser.oncue = cue => transcript.addCue(cue);

/** append the transcript when all cues have been parsed */
parser.onflush = () => {
    container.appendChild(transcript);
};

/** get the WebVTT and parse it */
getVTT('my-text-track.vtt', (cap) => {
    parser.parse(cap);
    parser.flush();
});

/** helper function for getting the WebVTT */
function getVTT(vttPath, callback) {
    const r = new XMLHttpRequest();
    r.onreadystatechange = () => {
        if (r.readyState === 4 && r.status === 200) {
            callback(r.responseText);
        }
    };
    r.open('GET', vttPath, true);
    r.send();
}