Skip to content

Commit

Permalink
chore(showcase): showcases for custom text tracks handling
Browse files Browse the repository at this point in the history
Introduces new showcases for integrators to benefit from the inclusion of custom text
tracks in the pillarbox player (see SRGSSR/pillarbox-web#207).

The showcases cover the implementation of: handling blocked segments, displaying current
chapters, and managing time intervals. Code examples with ample comments have been added
to provide developers with technical insight on how to integrate these features.
  • Loading branch information
jboix committed Feb 23, 2024
1 parent 30d1a7a commit 6836158
Show file tree
Hide file tree
Showing 10 changed files with 491 additions and 25 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"vite": "^5.0.12"
},
"dependencies": {
"@srgssr/pillarbox-web": "^1.0.1",
"@srgssr/pillarbox-web": "^1.1.0",
"highlight.js": "^11.9.0",
"lit": "^3.1.1",
"material-icons": "^1.13.12",
Expand Down
110 changes: 91 additions & 19 deletions src/layout/content/showcase/showcase-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,30 @@ import './showcase-component.js';
import '../../../components/code-block/code-block';
import showcasePageCss from './showcase-page.scss?inline';
import rawStartTimeExample from '../../../../static/showcases/start-time.html?raw';
import raeMultiPlayerExample from '../../../../static/showcases/multi-player.html?raw';
import rawMultiPlayerExample from '../../../../static/showcases/multi-player.html?raw';
import rawDetectBlockedSegmentsExample from '../../../../static/showcases/blocked-segment.html?raw';
import rawDisplayCurrentChapterExample from '../../../../static/showcases/chapters.html?raw';
import rawSkipCreditsExample from '../../../../static/showcases/skip-credits.html?raw';
import { getTextFromHTML } from './example-parser.js';

const startTimeExampleTxt = getTextFromHTML(rawStartTimeExample);
const multiPlayerExampleTxt = getTextFromHTML(raeMultiPlayerExample);
const multiPlayerExampleTxt = getTextFromHTML(rawMultiPlayerExample);
const detectBlockedSegmentsExampleTxt =
getTextFromHTML(rawDetectBlockedSegmentsExample);
const displayCurrentChapterExampleTxt =
getTextFromHTML(rawDisplayCurrentChapterExample);
const skipCreditsExampleTxt = getTextFromHTML(rawSkipCreditsExample);

export class ShowCasePage extends LitElement {
static styles = [theme, animations, unsafeCSS(showcasePageCss)];

render() {
return html`
${this.#renderStartTime()}
${this.#renderMultiplePlayers()}
${this.#renderStartTime()}
${this.#renderMultiplePlayers()}
${this.#renderDetectBlockedSegments()}
${this.#renderDisplayCurrentChapter()}
${this.#renderSkipCredits()}
`;
}

Expand Down Expand Up @@ -45,21 +56,82 @@ export class ShowCasePage extends LitElement {

#renderMultiplePlayers() {
return html`
<div class="fade-in" @animationend="${e => e.target.classList.remove('fade-in')}">
<showcase-component href="multi-player.html">
<h2 slot="title">Multiple Players</h2>
<p slot="description">
This example demonstrates how to incorporate multiple video players
on a webpage.In this showcase, two players are initialized, each
with its own configuration, a button allows to toggle the mute state
for both players.
</p>
<code-block slot="code" language="javascript">${multiPlayerExampleTxt}</code-block>
</showcase-component>
<a href="./static/showcases/multi-player.html" target="_blank">
Open this showcase
</a>
</div>
<div class="fade-in"
@animationend="${e => e.target.classList.remove('fade-in')}">
<showcase-component href="multi-player.html">
<h2 slot="title">Multiple Players</h2>
<p slot="description">
This example demonstrates how to incorporate multiple video players
on a webpage.In this showcase, two players are initialized, each
with its own configuration, a button allows to toggle the mute state
for both players.
</p>
<code-block slot="code" language="javascript">${multiPlayerExampleTxt}</code-block>
</showcase-component>
<a href="./static/showcases/multi-player.html" target="_blank">
Open this showcase
</a>
</div>
`;
}

#renderDetectBlockedSegments() {
return html`
<div class="fade-in"
@animationend="${e => e.target.classList.remove('fade-in')}">
<showcase-component href="blocked-segment.html">
<h2 slot="title">Detect Blocked Segments</h2>
<p slot="description">
This tutorial covers how to use pillarbox to create a plugin that
detects and notifies when a blocked segment is skipped.
</p>
<code-block slot="code" language="javascript">${detectBlockedSegmentsExampleTxt}</code-block>
</showcase-component>
<a href="./static/showcases/blocked-segment.html"
target="_blank">
Open this showcase
</a>
</div>
`;
}

#renderDisplayCurrentChapter() {
return html`
<div class="fade-in"
@animationend="${e => e.target.classList.remove('fade-in')}">
<showcase-component href="chapters.html">
<h2 slot="title">Display Current Chapter</h2>
<p slot="description">
This showcase explains how to use pillarbox to create a plugin that
displays the currently playing chapter in a box above the progress
bar.
</p>
<code-block slot="code" language="javascript">${displayCurrentChapterExampleTxt}</code-block>
</showcase-component>
<a href="./static/showcases/chapters.html"
target="_blank">
Open this showcase
</a>
</div>
`;
}

#renderSkipCredits() {
return html`
<div class="fade-in"
@animationend="${e => e.target.classList.remove('fade-in')}">
<showcase-component href="skip-credits.html">
<h2 slot="title">Skip Credits</h2>
<p slot="description">
This example shows how to use pillarbox to create a plugin that adds
a "Skip" button during detected credit intervals.
</p>
<code-block slot="code" language="javascript">${skipCreditsExampleTxt}</code-block>
</showcase-component>
<a href="./static/showcases/skip-credits.html" target="_blank">
Open this showcase
</a>
</div>
`;
}
}
Expand Down
117 changes: 117 additions & 0 deletions static/showcases/blocked-segment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Pillarbox Demo - Detect blocked segment</title>
<link rel="icon" type="image/x-icon" href="../../img/favicon.ico">
<link rel="stylesheet" href="./static-showcase.scss"/>
<link rel="stylesheet" href="./blocked-segment.scss"/>
</head>

<body>
<core-demo-header></core-demo-header>
<div class="showcase-content">
<h2>Detect blocked segment</h2>
<div class="video-container">
<video-js id="video-element-id" class="pillarbox-js" controls crossorigin="anonymous"></video-js>
</div>

<button class="showcase-btn" id="close-btn">Close this window</button>
</div>

<script type="module" data-implementation>
// Import the pillarbox library
import pillarbox from '@srgssr/pillarbox-web';

// Register a plugin to display notifications on blocked segments
pillarbox.registerPlugin('blockedSegmentNotification', function(options) {
// Get a reference to the player instance
const player = this;

// Wait for the player to be ready
player.ready(() => {
// Create a component for displaying the blocked segment notification
const blockSegmentNotification = player.addChild('component', {
className: 'pbw-blocked-segment-notification'
});

// Hide the notification initially
blockSegmentNotification.hide();

// Variable to store the timeout ID for clearing later
let timeoutId = undefined;

// Listen for the 'loadeddata' event on the player, this ensures that text tracks are available
player.on('loadeddata', () => {
// Get the text track with the ID 'srgssr-blocked-segments'
const blockedSegments = player.textTracks().getTrackById('srgssr-blocked-segments');

// Add a listener for the 'cuechange' event on the blocked segments text track
blockedSegments?.on('cuechange', () => {
// Check if there are active cues in the blocked segments text track
if (blockedSegments.activeCues.length > 0) {
// If there is an existing timeout, clear it
if (timeoutId) clearTimeout(timeoutId);

// Parse the JSON content of the active cue to get the blocked segment information
const blockSegment = JSON.parse(blockedSegments.activeCues[0].text);
const blockReason = blockSegment.blockReason;

// Update the displayed notification text with the appropriate message based on the block reason
blockSegmentNotification.el().textContent = options.i18n[blockReason] ?? options.i18n['UNKNOWN'];

// Show the blocked segment notification
blockSegmentNotification.show();

// Set a timeout to hide the notification after a specified delay
timeoutId = setTimeout(() => {
blockSegmentNotification.hide();
timeoutId = undefined;
}, options.delay);
}
});
});
});
});

// Create a pillarbox player instance with the blockedSegmentNotification plugin
const player = pillarbox(
'video-element-id', {
fill: true,
plugins: {
blockedSegmentNotification: {
delay: 5000, // Delay in milliseconds before hiding the notification
i18n: { // Labels for different block reasons
STARTDATE: 'ⓘ A portion of the video is not yet available',
ENDDATE: 'ⓘ A section of the video has expired',
LEGAL: 'ⓘ For legal reasons, a section of the video content is omitted',
COMMERCIAL: 'ⓘ A commercial break has been excluded',
GEOBLOCK: 'ⓘ This segment of the video is not accessible in your region',
AGERATING18: 'ⓘ A segment suitable for 18 years and older is omitted',
AGERATING12: 'ⓘ A segment suitable for 12 years and older is omitted',
UNKNOWN: 'ⓘ Due to an unidentified issue, a segment of the video is omitted.'
}
}
}
}
);

// Load the video source for the player
player.src({ src: 'urn:rts:video:10894383', type: 'srgssr/urn' });
</script>

<script type="module">
import pillarbox from '@srgssr/pillarbox-web';
import '../../src/layout/header/core-demo-header-component.js';

document.querySelector('#close-btn').addEventListener('click', () => {
window.close();
});

window.pillarbox = pillarbox;
</script>

</body>
</html>
16 changes: 16 additions & 0 deletions static/showcases/blocked-segment.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.pbw-blocked-segment-notification {
position: absolute;
right: var(--size-5);
bottom: var(--size-9);
display: flex;
align-items: center;
height: var(--size-6);
color: white;
background-color: rgb(0 0 0 / 70%);
border-radius: var(--radius-3);
box-shadow: var(--shadow-3);
backdrop-filter: blur(5px);
padding-inline: var(--size-2);
}


43 changes: 43 additions & 0 deletions static/showcases/chapters-showcase.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.pbw-current-chapter {
position: absolute;
top: calc(var(--size-8) * -1);
left: var(--size-4);
display: flex;
width: var(--size-15);
height: var(--size-9);
color: white;
background-color: rgb(0 0 0 / 50%);
border-radius: var(--radius-2);
box-shadow: var(--shadow-3);
backdrop-filter: sepia(50%);
}

.vjs-layout-medium {
.pbw-current-chapter {
width: var(--size-14);
}
}

.vjs-layout-tiny,
.vjs-layout-x-small,
.vjs-layout-small {
.pbw-current-chapter {
display: none;
}
}

.pbw-chapter-title {
display: -webkit-box;
padding: var(--size-1) var(--size-2);
overflow: hidden;
font-weight: var(--font-weight-3);
text-overflow: ellipsis;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
}

.pbw-chapter-thumbnail {
border-top-left-radius: var(--radius-2);
border-bottom-left-radius: var(--radius-2);
box-shadow: var(--inner-shadow-3);
}
Loading

0 comments on commit 6836158

Please sign in to comment.