1. Home
  2. Developers
  3. Advanced topics
  4. Implement Interactive Transcript

Implement Interactive Transcript


Interactive transcripts use .srt files to provide a written rendering of spoken phrases and a textual description of sounds. The contents of the .srt file are placed into a separate element on the webpage. As sounds/phrases occur in the video, the accompanying text is highlighted in the transcript. Users are then also able to select specific phrases in the interactive transcript to immediately access that part of the video.

Follow the instructions below to implement interactive transcripts for your videos.

Note:

The HTML, JavaScript and CSS code used in the following instructions should be viewed as a fully functional example. The examples can be styled and modified to meet client-specific needs with regard to branding and webpage functionality.

1.0 | Enable the interactive transcript button

  1. Create/select a playout and go to the “Miscellaneous” tab
  2. Scroll down to “Interactive Template” and select “Interactive Transcript Button” from the dropdown menu. This will enable the viewer to acces the transcript by clicking the button in the player.
Note:

Contact our contact our support team if the “Interactive Transcript Button” is not already listed in the dropdown menu. Our support team will be glad to activate the template for you.

Note:

Generic styling is applied to the interactive transcript button. Contact contact our support team for more options.

2.0 | Add an HTML <div> element

An HTML element is required to present the .srt file contents as an interactive transcript. Determine the location for the video and interactive transcript in the <body> section and insert the following HTML:

<div class="col-wrapper">
    <div class="player-wrapper">
            <!-- Place your JavaScript here -->
    </div>
 	<div class="transcript-wrapper hidden">
            <div class="ar16-9">
        	<div class="transcript-outer">
        		<div class="transcript"></div>
        	</div>
            </div>
        </div>
</div>

3.0 | Embed a video

    1. Go to the Media Library and click “Media Clips” in the left menu column.
    2. Open a Media Clip and select the “Embed” tab.
    3. Select the playout with the enabled Interactive Transcript button and copy the JavaScript embed code.
    4. Head over to the HTML element that you’ve added in the previous step and look for <div class="player-wrapper"></div>
    5. Paste the embed code to replace the comment (“Place your JavaScript here”).
    6. Make sure to pass the following callback parameter to the “src” URL: ?callback=onPlayerLoaded.
      For example:
    7. <script type="text/javascript" src="https://mypublication.bbvms.com/p/myfavoriteplayout/c/1234567.js" async="true"></script>

      should be changed into:

      <script type="text/javascript" src="https://mypublication.bbvms.com/p/myfavoriteplayout/c/1234567.js?callback=onPlayerLoaded" async="true"></script>

4.0 | Add JavaScript

JavaScript code is required to insert the .srt file contents into a designated HTML element. Place the following script in the <head> section.

<script type="text/javascript">
        class TranscriptParser {
            div = null;
            api = null;
            subtitleLines = null;
            constructor(api, div) {
                this.div = div;
                this.api = api;
                this.init();
            }
        init() {
            this.api.on('subtitlechange', () => {
                this.onSubtitleChange(this.api.getCurrentSubtitle());
            });
            this.api.on('subtitlelinechange', () => {
                this.onSubtitleLineChange(this.api.getCurrentSubtitleLine());
            });
            this.api.on('started', () => {
                this.onSubtitleChange(this.api.getCurrentSubtitle());
            });
            setTimeout(() => {
                if (!this.subtitleLines) {
                    this.onSubtitleChange(this.api.getCurrentSubtitle());
                }
            }, 500);
            setTimeout(() => {
                if (!this.subtitleLines) {
                    this.onSubtitleChange(this.api.getCurrentSubtitle());
                }
            }, 2500);
            if (this.div) {
                this.div.addEventListener('mouseenter', () => {
                    this.onMouseEnter();
                });
                this.div.addEventListener('mouseleave', () => {
                    this.onMouseLeave();
                });
            }
        }
        onMouseEnter() {
            this.mouseIsOver = true;
        }
        onMouseLeave() {
            this.mouseIsOver = false;
        }
        onSubtitleChange(subtitle) {
            if (!subtitle || !subtitle.parsedData) return;
            let td = this.div;
            td.innerHTML = '';
            this.subtitleLines = subtitle.parsedData;
            this.subtitleLines.forEach((sub) => {
                let subLineDiv = document.createElement('div');
                subLineDiv.title = this.formatTime(sub.inPoint) + ' - ' + this.formatTime(sub.outPoint);
                subLineDiv.classList.add('sub-line');
                subLineDiv.innerHTML = sub.subtitleLine;
                subLineDiv.onclick = () => {
                    if (!this.api.isPlaying()) {
                        this.api.play();
                    }
                    this.api.seek(sub.inPoint);
                };
                td.appendChild(subLineDiv);
            });
        }
        onSubtitleLineChange(subtitleLine) {
            let currentTime = this.api.getCurrentTime();
            let activeElement = null;
            this.subtitleLines.forEach((line, i) => {
                let lineElement = this.div.childNodes[i];
                if (line.inPoint < currentTime && line.outPoint > currentTime) {
                    lineElement.classList.add('active');
                    activeElement = lineElement;
                } else {
                    lineElement.classList.remove('active');
                }
            });
            if (!this.mouseIsOver && activeElement) {
                activeElement.scrollIntoView({
                    block: 'center',
                    behavior: 'smooth'
                });
            }
        }
        formatTime(s) {
            return new Date(s * 1000).toISOString().substr(14, 5);
        }
    }		
    window.onPlayerLoaded = (api) => {
        const tp = new TranscriptParser(api, document.querySelector('.transcript'));
    }
</script>

5.0 | Add CSS Styling

Add the following CSS to the <head> section:

<style>
        .col-wrapper {
            display: grid;
            grid-gap: 20px;
            grid-template-columns: 1fr 1fr;
        }
        .transcript-wrapper {
            opacity: 1;
            transition: opacity 0.25s;
            text-align: left;
            overflow: hidden;
        }
        .transcript-wrapper.hidden {
            opacity: 0;
            pointer-events: none;
            display: none;
        }
        .ar16-9 {
            overflow: hidden;
            position: relative;
            padding-top: 56.25%;
            background-color: white;
        }
        .transcript {
            padding: 10px;
        } 
        .transcript-outer {
            position: absolute;
            left: 0;
            top: 0;
            bottom: 0;
            right: 0;
            width: 100%;
            height: 100%;
            overflow: auto;
        }
        .sub-line {
            font-family: helvetica;
            line-height: 1.5;
            color: #444444;
            cursor: pointer;
            display: inline-block;
            padding: 1px 2px;
        }
        .sub-line:hover,
        .sub-line.active {
            font-weight: 500;
            color: #DF681C;
        }
        @media (max-width: 968px) {
 		   .col-wrapper {
                grid-template-columns: 1fr;
                	}
        	}
</style>

Was this article helpful?

Related Articles

Contact Support
Can't find the answer you're looking for?
Contact Support