Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(showcase): showcases for custom text tracks handling #14

Merged
merged 1 commit into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
122 changes: 122 additions & 0 deletions static/showcases/blocked-segment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<!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';

const Plugin = pillarbox.getPlugin('plugin');

// A Pillarbox plugin to display a blocked segment notification.
class BlockedSegmentNotification extends Plugin {
// Reference to the component used to display the blocked segment notification.
#component;
// The id for the timeout function responsible for managing the auto-hide of the notification.
#timeoutId;

constructor(player, options) {
super(player, options);

// Attach the DOM element when the player is ready,
this.player.ready(() => this.#attachComponent());
// Wait for the 'loadeddata' event to ensure the text tracks are available
this.player.on('loadeddata', () => this.#handleBlockedSegmentChange());
}

#attachComponent() {
this.#component = player.addChild('component', {
// Set the class for styling and hide the element with 'vjs-hidden'
className: 'pbw-blocked-segment-notification vjs-hidden'
});
}

#handleBlockedSegmentChange() {
// Get the text track with the ID 'srgssr-blocked-segments'
const blockedSegments = this.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) return;

// Cancel the previous timeout
clearTimeout(this.#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 ?? 'UNKNOWN';
// Block reasons are localized out of the box, alternatively you can make your own
const message = this.#component.localize(blockReason);

// Update the displayed notification text with the appropriate message
this.#component.el().textContent = `ⓘ ${message}`;

// Show the blocked segment notification
this.#component.show();

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

// Get the options of this plugin
get options() {
return this.player.options().plugins.blockedSegmentNotification;
}
}

// Register a plugin to display notifications on blocked segments
pillarbox.registerPlugin('blockedSegmentNotification', BlockedSegmentNotification);

// 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
}
}
}
);

// 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
Loading