diff --git a/CHANGELOG.md b/CHANGELOG.md index 55db7cd03..fee643bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] +### Added +- Support for a new placeholder `{adBreakRemainingTime}` in [AdMessageLabel](https://cdn.bitmovin.com/player/ui/3/docs/classes/AdMessageLabel.html) that displays the remaining time in an ad break. [Documentation](https://cdn.bitmovin.com/player/ui/3/docs/functions/StringUtils.replaceAdMessagePlaceholders.html) on usage. + ## [3.69.0] - 2024-08-14 ### Added - API doc generation and publishing. The API doc from the UI can be found [here](https://cdn.bitmovin.com/player/ui/3/docs/index.html) diff --git a/src/ts/stringutils.ts b/src/ts/stringutils.ts index 027e657ae..f54c1326d 100644 --- a/src/ts/stringutils.ts +++ b/src/ts/stringutils.ts @@ -1,4 +1,4 @@ -import { PlayerAPI } from 'bitmovin-player'; +import { Ad, LinearAd, PlayerAPI } from 'bitmovin-player'; import { i18n } from './localization/i18n'; /** @@ -73,8 +73,8 @@ export namespace StringUtils { /** * Fills out placeholders in an ad message. * - * Has the placeholders '{remainingTime[formatString]}', '{playedTime[formatString]}' and - * '{adDuration[formatString]}', which are replaced by the remaining time until the ad can be skipped, the current + * Has the placeholders '{remainingTime[formatString]}', '{playedTime[formatString]}', + * '{adDuration[formatString]}' and {adBreakRemainingTime[formatString]}, which are replaced by the remaining time until the ad can be skipped, the current * time or the ad duration. The format string is optional. If not specified, the placeholder is replaced by the time * in seconds. If specified, it must be of the following format: * - %d - Inserts the time as an integer. @@ -91,6 +91,8 @@ export namespace StringUtils { * An input value of 100 would be displayed as: 'Ad: 01:40 secs' * - { text: 'Ad: {remainingTime%f} secs' } * An input value of 100 would be displayed as: 'Ad: 100.0 secs' + * - { text: 'Adbreak: {adBreakRemainingTime%f} secs' } + * Adbreak with 2 ads each 50 seconds would be displayed as: 'Ad: 100.0 secs' * * @param adMessage an ad message with optional placeholders to fill * @param skipOffset if specified, {remainingTime} will be filled with the remaining time until the ad can be skipped @@ -99,7 +101,7 @@ export namespace StringUtils { */ export function replaceAdMessagePlaceholders(adMessage: string, skipOffset: number, player: PlayerAPI) { let adMessagePlaceholderRegex = new RegExp( - '\\{(remainingTime|playedTime|adDuration)(}|%((0[1-9]\\d*(\\.\\d+(d|f)|d|f)|\\.\\d+f|d|f)|hh:mm:ss|mm:ss)})', + '\\{(remainingTime|playedTime|adDuration|adBreakRemainingTime)(}|%((0[1-9]\\d*(\\.\\d+(d|f)|d|f)|\\.\\d+f|d|f)|hh:mm:ss|mm:ss)})', 'g', ); @@ -115,7 +117,22 @@ export namespace StringUtils { time = player.getCurrentTime(); } else if (formatString.indexOf('adDuration') > -1) { time = player.getDuration(); + } else if (formatString.indexOf('adBreakRemainingTime') > -1) { // To display the remaining time in the ad break as opposed to in the ad + time = 0; + + // compute list of ads and calculate duration of remaining ads based on index of active ad + if (player.ads.isLinearAdActive()) { + const isActiveAd = (ad: Ad) => player.ads.getActiveAd().id === ad.id; + const indexOfActiveAd = player.ads.getActiveAdBreak().ads.findIndex(isActiveAd); + const duration = player.ads.getActiveAdBreak().ads + .slice(indexOfActiveAd) + .reduce((total, ad) => total + (ad.isLinear ? (ad as LinearAd).duration : 0), 0); + + // And remaning ads duration minus time played + time = duration - player.getCurrentTime(); + } } + return formatNumber(Math.round(time), formatString); }); }