From 98748701400a371a0acdd3d266dfaaa704a0e506 Mon Sep 17 00:00:00 2001 From: Samuel Guillemet Date: Tue, 1 Aug 2023 11:50:55 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=93=96=20DOC:=20Add=20NPM=20version?= =?UTF-8?q?=20badge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 82accba..516f658 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Cern Paella Plugins [![Build and push to NPM](https://github.com/cern-vc/cern-paella-plugins/actions/workflows/build.yml/badge.svg)](https://github.com/cern-vc/cern-paella-plugins/actions/workflows/build.yml) +[![npm version](https://badge.fury.io/js/cern-paella-plugins.svg)](https://badge.fury.io/js/cern-paella-plugins) This repository contains the plugins for the Paella Player used at CERN. From 8002afc3fe4aad1a58a39066e3093f23384b3423 Mon Sep 17 00:00:00 2001 From: Samuel Guillemet Date: Tue, 1 Aug 2023 11:51:17 +0200 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=91=8C=20IMPROVE:=20Add=20`dist`=20to?= =?UTF-8?q?=20gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c2658d7..b947077 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +dist/ From 49bc4adf08b2c329a33f9eabcd2d48917c9808aa Mon Sep 17 00:00:00 2001 From: Samuel Guillemet Date: Tue, 1 Aug 2023 11:51:25 +0200 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=93=A6=20NEW:=20Add=20icons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/icons/live-icon.png | Bin 0 -> 3671 bytes src/plugins/icons/next-icon.svg | 8 ++++++++ src/plugins/icons/previous-icon.svg | 8 ++++++++ 3 files changed, 16 insertions(+) create mode 100644 src/plugins/icons/live-icon.png create mode 100644 src/plugins/icons/next-icon.svg create mode 100644 src/plugins/icons/previous-icon.svg diff --git a/src/plugins/icons/live-icon.png b/src/plugins/icons/live-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cb4913457d4cce25aae436a8ea4ca8bba28026aa GIT binary patch literal 3671 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 + + + + + \ No newline at end of file diff --git a/src/plugins/icons/previous-icon.svg b/src/plugins/icons/previous-icon.svg new file mode 100644 index 0000000..d6f3299 --- /dev/null +++ b/src/plugins/icons/previous-icon.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file From 1d2065b2626bb317bcd615700c201c44069b6fee Mon Sep 17 00:00:00 2001 From: Samuel Guillemet Date: Tue, 1 Aug 2023 11:51:39 +0200 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=93=A6=20NEW:=20Add=20cern=20related?= =?UTF-8?q?=20packages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...h.cern.paella.liveStreamIndicatorPlugin.js | 82 +++++++++++++ ...n.paella.liveStreamingProgressIndicator.js | 110 ++++++++++++++++++ .../ch.cern.paella.matomoAnalyticsPlugin.js | 61 ++++++++++ ...aella.matomoAnalyticsUserTrackingPlugin.js | 50 ++++++++ .../ch.cern.paella.nextTimeButtonPlugin.js | 86 ++++++++++++++ .../ch.cern.paella.prevTimeButtonPlugin.js | 86 ++++++++++++++ ...h.cern.paella.vttManifestCaptionsPlugin.js | 47 ++++++++ 7 files changed, 522 insertions(+) create mode 100644 src/plugins/ch.cern.paella.liveStreamIndicatorPlugin.js create mode 100644 src/plugins/ch.cern.paella.liveStreamingProgressIndicator.js create mode 100644 src/plugins/ch.cern.paella.matomoAnalyticsPlugin.js create mode 100644 src/plugins/ch.cern.paella.matomoAnalyticsUserTrackingPlugin.js create mode 100644 src/plugins/ch.cern.paella.nextTimeButtonPlugin.js create mode 100644 src/plugins/ch.cern.paella.prevTimeButtonPlugin.js create mode 100644 src/plugins/ch.cern.paella.vttManifestCaptionsPlugin.js diff --git a/src/plugins/ch.cern.paella.liveStreamIndicatorPlugin.js b/src/plugins/ch.cern.paella.liveStreamIndicatorPlugin.js new file mode 100644 index 0000000..a517d5e --- /dev/null +++ b/src/plugins/ch.cern.paella.liveStreamIndicatorPlugin.js @@ -0,0 +1,82 @@ +/* eslint-disable no-param-reassign */ +/* eslint-disable max-classes-per-file */ +import { Canvas, CanvasPlugin, createElementWithHtmlText } from "paella-core"; +import * as img_url from "./icons/live-icon.png"; + +// Canvas implementation +export class LiveStreamIndicatorCanvas extends Canvas { + /** + * This class displays an image indicating whether the stream is live or not. + * + * @param {*} player + * @param {*} videoContainer + * @param {*} stream + */ + constructor(player, videoContainer, stream) { + super("div", player, videoContainer); + this.stream = stream; + this.parentContainer = videoContainer; + } + + /** + * When the plugin is loaded, this code will be executed. + * It will display the image of the live stream indicator if the stream is live. + * + * @param {*} player + */ + async loadCanvas() { + let isLiveStream = false; + + const streamSources = this.stream.sources; + + const setStreamAsLive = (key, value) => { + const tempIsLiveStream = value[0].isLiveStream; + if (tempIsLiveStream) { + isLiveStream = tempIsLiveStream; + } + }; + + Object.keys(streamSources).forEach((key) => { + setStreamAsLive(key, streamSources[key]); + }); + + if (isLiveStream) { + const indicator = document.getElementById("live-stream-indicator"); + if (indicator) { + return; + } + console.log("Stream is live. Displaying the live stream indicator"); + createElementWithHtmlText( + `
`, + this.parentContainer + ); + } + } +} + +// Canvas plugin definition +export default class LiveStreamIndicatorPlugin extends CanvasPlugin { + // eslint-disable-next-line class-methods-use-this + get parentContainer() { + return "videoContainer"; // or videoContainer + } + + isCompatible(stream) { + if (!Array.isArray(stream.canvas) || stream.canvas.length === 0) { + console.log("No canvas defined in the stream"); + // By default, the default canvas is HTML video canvas + this.stream = stream; + return true; + } + + return super.isCompatible(stream); + } + + getCanvasInstance(videoContainer) { + return new LiveStreamIndicatorCanvas( + this.player, + videoContainer, + this.stream + ); + } +} diff --git a/src/plugins/ch.cern.paella.liveStreamingProgressIndicator.js b/src/plugins/ch.cern.paella.liveStreamingProgressIndicator.js new file mode 100644 index 0000000..a643f35 --- /dev/null +++ b/src/plugins/ch.cern.paella.liveStreamingProgressIndicator.js @@ -0,0 +1,110 @@ +import { ProgressIndicatorPlugin } from "paella-core"; + +function draw(context, width, height) { + console.log("draw params", { + context, + width, + height, + }); + let posX = 0; + let textMargin = 0; + const circleSize = 8; + + if (this.side === "left") { + posX = this.margin; + textMargin = circleSize + 4; + } else if (this.side === "center") { + posX = width / 2; + textMargin = 0; + } else if (this.side === "right") { + posX = width - this.margin; + textMargin = -(circleSize + 4); + } + + const circleMargin = this.side === "center" ? -40 : 0; + context.fillStyle = this.textColor; + context.font = `bold 14px Arial`; + context.textAlign = this.side; + const textHeight = height / 2 + 3; + + context.fillText("Live", posX + textMargin, textHeight); + + context.beginPath(); + context.fillStyle = this.circleColor; + context.arc( + posX + circleMargin, + height / 2, + circleSize / 2, + 0, + 2 * Math.PI, + false + ); + context.fill(); +} + +function minHeight() { + return 25; +} + +function minHeightHover() { + return 25; +} + +export default class LiveStreamingProgressIndicatorPlugin extends ProgressIndicatorPlugin { + async isEnabled() { + const e = await super.isEnabled(); + console.log("isEnabled1", e); + console.log("player", this.player); + console.log("isEnabled2", this.player.videoContainer.isLiveStream); + return true; + return e && this.player.videoContainer.isLiveStream; + } + + async load() { + this.layer = this.config.layer ?? "foreground"; + this.side = this.config.side ?? "right"; + this.margin = this.config.margin ?? 50; + this.textColor = this.config.textColor ?? "white"; + this.circleColor = this.config.circleColor ?? "red"; + + if (["foreground", "background"].indexOf(this.layer) === -1) { + throw new Error( + "Invalid layer set in plugin 'es.upv.paella.liveStreamingPlugin'. Valid values are 'foreground' or 'background'" + ); + } + + if (["left", "center", "right"].indexOf(this.side) === -1) { + throw new Error( + "Invalid side set in plugin 'es.upv.paella.liveStreamingPlugin'. Valid values are 'left', 'center' or 'right'" + ); + } + + console.log("load params", { + layer: this.layer, + side: this.side, + margin: this.margin, + textColor: this.textColor, + circleColor: this.circleColor, + }); + } + + drawForeground(context, width, height, isHover) { + if (this.layer === "foreground") { + draw.apply(this, [context, width, height, isHover]); + } + } + + drawBackground(context, width, height, isHover) { + if (this.layer === "background") { + draw.apply(this, [context, width, height, isHover]); + } + } + + get minHeight() { + return minHeight.apply(this); + } + + get minHeightHover() { + return minHeightHover.apply(this); + } +} diff --git a/src/plugins/ch.cern.paella.matomoAnalyticsPlugin.js b/src/plugins/ch.cern.paella.matomoAnalyticsPlugin.js new file mode 100644 index 0000000..aedd87a --- /dev/null +++ b/src/plugins/ch.cern.paella.matomoAnalyticsPlugin.js @@ -0,0 +1,61 @@ +/* eslint-disable no-underscore-dangle */ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable no-multi-assign */ +import { DataPlugin } from "paella-core"; + +export default class MatomoAnalyticsUserTrackingDataPlugin extends DataPlugin { + async load() { + console.log("Loading matomo analytics plugin"); + const { trackingId } = this.config; + // const domain = this.config.domain || "auto"; + if (trackingId) { + console.log("Matomo Analytics Enabled"); + const _paq = (window._paq = window._paq || []); + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(["trackPageView"]); + _paq.push(["enableLinkTracking"]); + // eslint-disable-next-line func-names + (function () { + const u = "https://webanalytics.web.cern.ch/"; + _paq.push(["setTrackerUrl", `${u}matomo.php`]); + _paq.push(["setSiteId", trackingId]); + const d = document; + const g = d.createElement("script"); + const s = d.getElementsByTagName("script")[0]; + g.async = true; + g.src = `${u}matomo.js`; + s.parentNode.insertBefore(g, s); + })(); + } else { + console.log( + "No Matomo Tracking ID found in config file. Disabling Matomo Analytics", + ); + } + } + + async write(context, { id }, data) { + if (this.config.category === undefined || this.config.category === true) { + const category = "PaellaPlayer"; + const action = data.event; + const labelData = { + videoId: id, + plugin: data.plugin, + }; + + // try { + // // Test if data parameters can be serialized + // JSON.stringify(data.params); + // labelData.params = data.params; + // } catch (error) { + // console.log(error); + // } + + const label = JSON.stringify(labelData); + if (category.length > 0 && action.length > 0) { + // _paq.push(['trackEvent', 'Contact', 'Email Link Click', 'name@example.com']); + // eslint-disable-next-line no-undef + _paq.push(["trackEvent", category, action, label]); + } + } + } +} diff --git a/src/plugins/ch.cern.paella.matomoAnalyticsUserTrackingPlugin.js b/src/plugins/ch.cern.paella.matomoAnalyticsUserTrackingPlugin.js new file mode 100644 index 0000000..7b86b47 --- /dev/null +++ b/src/plugins/ch.cern.paella.matomoAnalyticsUserTrackingPlugin.js @@ -0,0 +1,50 @@ +import { Events, EventLogPlugin } from "paella-core"; + +// const eventKeys = Object.keys(Events); + +const getPaellaEvents = (events) => + events.map((eventName) => Events[eventName]); + +export default class MatomoAnalyticsUserEventTrackerPlugin extends EventLogPlugin { + get events() { + if (this.config.events) { + return getPaellaEvents(this.config.events); + } + + return [ + Events.PLAY, + Events.PAUSE, + Events.SEEK, + Events.STOP, + Events.ENDED, + Events.FULLSCREEN_CHANGED, + Events.VOLUME_CHANGED, + Events.BUTTON_PRESS, + Events.RESIZE_END, + ]; + } + + async onEvent(event, params) { + const id = this.player.videoId; + // Remove plugin reference to avoid circular references + if (params.plugin) { + const { name, config } = params.plugin; + // eslint-disable-next-line no-param-reassign + params.plugin = { name, config }; + } + const trackingData = { event, params }; + + switch (event) { + case Events.SHOW_POPUP: + case Events.HIDE_POPUP: + case Events.BUTTON_PRESS: + trackingData.plugin = params.plugin?.name || null; + break; + default: + break; + } + + const context = this.config.context || "matomoUserTracking"; + await this.player.data.write(context, { id }, trackingData); + } +} diff --git a/src/plugins/ch.cern.paella.nextTimeButtonPlugin.js b/src/plugins/ch.cern.paella.nextTimeButtonPlugin.js new file mode 100644 index 0000000..35b6c1b --- /dev/null +++ b/src/plugins/ch.cern.paella.nextTimeButtonPlugin.js @@ -0,0 +1,86 @@ +import { ButtonPlugin } from "paella-core"; +import defaultForwardIcon from "./icons/next-icon.svg"; + +const params = new Proxy(new URLSearchParams(window.location.search), { + get: (searchParams, prop) => searchParams.get(prop), +}); + +export function toSeconds(timeExpr) { + const units = { h: 3600, m: 60, s: 1 }; + const regex = /(\d+)([hms])/g; + + let seconds = 0; + let match = regex.exec(timeExpr); + + while (match) { + seconds += parseInt(match[1], 10) * units[match[2]]; + match = regex.exec(timeExpr); + } + + return seconds; +} + +export default class NextTimeButtonPlugin extends ButtonPlugin { + getAriaLabel() { + return this.player.translate("Go to next time"); + } + + getDescription() { + return this.getAriaLabel(); + } + + async isEnabled() { + const enabled = (await super.isEnabled()) && params.time; + if (!enabled) { + return false; + } + this.time = this.config.time || 30; + this.timeParams = params.time.split(","); + this.slots = []; + if (this.timeParams) { + this.timeParams.forEach((element) => { + if (/[hms]/.test(element)) { + this.slots.push(toSeconds(element)); + } else { + this.slots.push(parseFloat(element)); + } + }); + } + this.player.currentPosition = 0; + this.goToPosition(this.player.currentPosition); + return enabled; + } + + async load() { + const addSuffix = + this.config.suffix !== undefined ? this.config.suffix : true; + this.suffix = addSuffix ? "s" : ""; + this.icon = ``; + setTimeout(() => { + Array.from(this.iconElement.getElementsByClassName("time-text")).forEach( + (textIcon) => { + // eslint-disable-next-line no-param-reassign + textIcon.innerHTML = this.time + this.suffix; + }, + ); + }, 100); + } + + goToPosition(position) { + if (position > this.slots.length - 1) { + this.player.currentPosition = this.slots.length - 1; + } else { + this.player.currentPosition = position; + } + this.time = this.slots[this.player.currentPosition]; + console.log( + `Jump to next time: ${this.time}. Slot ${this.player.currentPosition}`, + ); + // const currentTime = await this.player.videoContainer.currentTime(); + this.player.videoContainer.setCurrentTime(this.time); + } + + async action() { + this.goToPosition(this.player.currentPosition + 1); + } +} diff --git a/src/plugins/ch.cern.paella.prevTimeButtonPlugin.js b/src/plugins/ch.cern.paella.prevTimeButtonPlugin.js new file mode 100644 index 0000000..7616fc2 --- /dev/null +++ b/src/plugins/ch.cern.paella.prevTimeButtonPlugin.js @@ -0,0 +1,86 @@ +import { ButtonPlugin } from "paella-core"; +import defaultIcon from "./icons/previous-icon.svg"; + +const params = new Proxy(new URLSearchParams(window.location.search), { + get: (searchParams, prop) => searchParams.get(prop), +}); + +export function toSeconds(timeExpr) { + const units = { h: 3600, m: 60, s: 1 }; + const regex = /(\d+)([hms])/g; + + let seconds = 0; + let match = regex.exec(timeExpr); + + while (match) { + seconds += parseInt(match[1], 10) * units[match[2]]; + match = regex.exec(timeExpr); + } + + return seconds; +} + +export default class PrevTimeButtonPlugin extends ButtonPlugin { + getAriaLabel() { + return this.player.translate("Go to previous time"); + } + + getDescription() { + return this.getAriaLabel(); + } + + async isEnabled() { + const enabled = (await super.isEnabled()) && params.time; + if (!enabled) { + return false; + } + this.time = 0; + this.timeParams = params.time.split(","); + this.slots = []; + if (this.timeParams) { + this.timeParams.forEach((element) => { + if (/[hms]/.test(element)) { + this.slots.push(toSeconds(element)); + } else { + this.slots.push(parseFloat(element)); + } + }); + } + this.player.currentPosition = 0; + // this.goToPosition(this.player.currentPosition); + + return enabled; + } + + async load() { + const addSuffix = + this.config.suffix !== undefined ? this.config.suffix : true; + this.suffix = addSuffix ? "s" : ""; + this.icon = ``; + setTimeout(() => { + Array.from(this.iconElement.getElementsByClassName("time-text")).forEach( + (textIcon) => { + // eslint-disable-next-line no-param-reassign + textIcon.innerHTML = this.time + this.suffix; + }, + ); + }, 100); + } + + goToPosition(position) { + if (position < 0) { + this.player.currentPosition = 0; + } else { + this.player.currentPosition = position; + } + this.time = this.slots[this.player.currentPosition]; + console.log( + `Jump to previous time: ${this.time}. Slot ${this.player.currentPosition}`, + ); + this.player.videoContainer.setCurrentTime(this.time); + } + + async action() { + this.goToPosition(this.player.currentPosition - 1); + } +} diff --git a/src/plugins/ch.cern.paella.vttManifestCaptionsPlugin.js b/src/plugins/ch.cern.paella.vttManifestCaptionsPlugin.js new file mode 100644 index 0000000..09f7d83 --- /dev/null +++ b/src/plugins/ch.cern.paella.vttManifestCaptionsPlugin.js @@ -0,0 +1,47 @@ +import { CaptionsPlugin, utils, WebVTTParser } from "paella-core"; + +export default class VttManifestCaptionsPlugin extends CaptionsPlugin { + async isEnabled() { + const enabled = await super.isEnabled(); + return ( + enabled && + this.player.videoManifest.captions && + this.player.videoManifest.captions.length > 0 + ); + } + + async getCaptions() { + const result = []; + const p = []; + this.player.videoManifest.captions.forEach((captions) => { + p.push( + new Promise((resolve) => { + if (/vtt/i.test(captions.format)) { + const fileUrl = utils.resolveResourcePath( + this.player, + captions.url, + ); + fetch(fileUrl, { credentials: "include" }) + // eslint-disable-next-line consistent-return + .then((fetchResult) => { + if (fetchResult.ok) { + return fetchResult.text(); + } + // reject(); + console.error(fetchResult); + }) + .then((text) => { + const parser = new WebVTTParser(text); + parser.captions.label = captions.text; + parser.captions.language = captions.lang; + result.push(parser.captions); + resolve(); + }); + } + }), + ); + }); + await Promise.all(p); + return result; + } +} From 367b671ec48f011d9e4c0fdae992a98e8e56a6d4 Mon Sep 17 00:00:00 2001 From: Samuel Guillemet Date: Tue, 1 Aug 2023 11:52:01 +0200 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=9A=80=20RELEASE:=20Bump=20to=20v0.2.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1029128..8aa77cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cern-paella-plugins", - "version": "0.1.0", + "version": "0.2.0", "description": "Paella plugins for cern use", "main": "src/index.js", "module": "dist/cern-paella-plugins.js",