@ceeblue/web-utils 2.4.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -184,6 +184,55 @@ declare namespace Connect {
184
184
  * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
185
185
  * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
186
186
  */
187
+ /**
188
+ * Log interface to deal with log everywhere:
189
+ * - subscribe logs: listen logs to effectuate some specific job related logs
190
+ * - intercept logs: intercept logs to change the default behavior
191
+ * - redirect logs: redirect logs to one other logger engine
192
+ * - redefine logs: change log text like adding a prefix
193
+ *
194
+ * You have 4 {@link LogType} 'error', 'warn', 'info', and 'debug', as commonly managed by browsers.
195
+ *
196
+ * @example
197
+ * // Intercept and redirect all the logs to the console (default behavior)
198
+ * import { log } from '@ceeblue/web-utils';
199
+ * log.on(type:LogType, args:uknown[]) => {
200
+ * console[type](...args.splice(0)); // args is empty after this call = final interception
201
+ * }
202
+ *
203
+ * // Intercept and redirect the logs from Player compoment to the console
204
+ * player.log.on(type:LogType, args:uknown[]) => {
205
+ * console[type](...args.splice(0)); // args is empty after this call = final interception
206
+ * }
207
+ *
208
+ * // Subscribe and redirect all the logs to a file logger
209
+ * log.on(type:LogType, args:uknown[]) => {
210
+ * fileLogger[type](...args); // args stays unchanged to let's continue the default behavior
211
+ * }
212
+ *
213
+ * // Redefine the log to add some prefix indication
214
+ * class Player {
215
+ * connector = new Connector();
216
+ * constructor() {
217
+ * connector.log = this.log.bind(this, "Connector log:");
218
+ * }
219
+ * }
220
+ *
221
+ */
222
+ interface ILog {
223
+ /**
224
+ * Build a log
225
+ */
226
+ (...args: unknown[]): Log;
227
+ /**
228
+ * Intercept, redefine or redirect any log
229
+ * If you clear args you intercept the log and nothing happen more after this call.
230
+ * @param type log level
231
+ * @param args args
232
+ * @returns
233
+ */
234
+ on: (type: LogType, args: unknown[]) => void;
235
+ }
187
236
  /**
188
237
  * Log types
189
238
  */
@@ -207,22 +256,6 @@ declare class Log {
207
256
  constructor(onLog: Function, ...args: unknown[]);
208
257
  private _bind;
209
258
  }
210
- /**
211
- * ILog interface used by log methods
212
- */
213
- interface ILog {
214
- /**
215
- * Build a log
216
- */
217
- (...args: unknown[]): Log;
218
- /**
219
- * Intercept or redefine any log
220
- * @param type log level
221
- * @param args args
222
- * @returns
223
- */
224
- on: (type: LogType, args: unknown[]) => void;
225
- }
226
259
  /**
227
260
  * Inherits from this class to use logs
228
261
  */
@@ -731,6 +764,12 @@ declare function getExtension(path: string): string;
731
764
  * @returns the file name
732
765
  */
733
766
  declare function getFile(path: string): string;
767
+ /**
768
+ * Get Base File part from path, without extension
769
+ * @param path path to parse
770
+ * @returns the base file name
771
+ */
772
+ declare function getBaseFile(path: string): string;
734
773
  /**
735
774
  * String Trim function with customizable chars
736
775
  * @param value string to trim
@@ -756,6 +795,7 @@ declare function trimEnd(value: string, chars?: string): string;
756
795
  declare const Util_EMPTY_FUNCTION: typeof EMPTY_FUNCTION;
757
796
  declare const Util_equal: typeof equal;
758
797
  declare const Util_fetch: typeof fetch;
798
+ declare const Util_getBaseFile: typeof getBaseFile;
759
799
  declare const Util_getExtension: typeof getExtension;
760
800
  declare const Util_getFile: typeof getFile;
761
801
  declare const Util_objectEntries: typeof objectEntries;
@@ -771,7 +811,7 @@ declare const Util_trim: typeof trim;
771
811
  declare const Util_trimEnd: typeof trimEnd;
772
812
  declare const Util_trimStart: typeof trimStart;
773
813
  declare namespace Util {
774
- export { Util_EMPTY_FUNCTION as EMPTY_FUNCTION, Util_equal as equal, Util_fetch as fetch, Util_getExtension as getExtension, Util_getFile as getFile, Util_objectEntries as objectEntries, Util_objectFrom as objectFrom, Util_options as options, Util_safePromise as safePromise, Util_sleep as sleep, Util_stringify as stringify, Util_time as time, Util_timeOrigin as timeOrigin, Util_toBin as toBin, Util_trim as trim, Util_trimEnd as trimEnd, Util_trimStart as trimStart };
814
+ export { Util_EMPTY_FUNCTION as EMPTY_FUNCTION, Util_equal as equal, Util_fetch as fetch, Util_getBaseFile as getBaseFile, Util_getExtension as getExtension, Util_getFile as getFile, Util_objectEntries as objectEntries, Util_objectFrom as objectFrom, Util_options as options, Util_safePromise as safePromise, Util_sleep as sleep, Util_stringify as stringify, Util_time as time, Util_timeOrigin as timeOrigin, Util_toBin as toBin, Util_trim as trim, Util_trimEnd as trimEnd, Util_trimStart as trimStart };
775
815
  }
776
816
 
777
817
  /**
@@ -927,6 +967,51 @@ declare class WebSocketReliable extends EventEmitter {
927
967
  private _send;
928
968
  }
929
969
 
970
+ /**
971
+ * Copyright 2024 Ceeblue B.V.
972
+ * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
973
+ * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
974
+ */
975
+ /**
976
+ * Decode the timestamp from a video element and compute the latency between the timestamp and the current date.
977
+ *
978
+ * @param {HTMLVideoElement} sourceEl the video element to get the image from
979
+ * @param {HTMLCanvasElement} canvas
980
+ * @param {CanvasRenderingContext2D} context
981
+ * @param {Date} now current date, new Date() by default
982
+ * @param {Number} blocksPerRow number of blocks in the line, 32 by default
983
+ * @param {Number} tolerance percentage of tolerance for the black and white threshold, 0.2 by default
984
+ * @returns {Number} The latency in millisecond between 'now' and the decoded timestamp, 0 if the timestamp cannot be decoded
985
+ */
986
+ declare function getLatency(sourceEl: HTMLVideoElement, canvas: HTMLCanvasElement, context: CanvasRenderingContext2D, now?: Date, blocksPerRow?: number, tolerance?: number): number;
987
+ /**
988
+ * Decode a previously encoded timestamp from a canvas
989
+ *
990
+ * @param {CanvasRenderingContext2D} context
991
+ * @param {Number} lineWidth width of the line in pixels
992
+ * @param {Number} blocksPerRow number of blocks in the line, 32 by default
993
+ * @param {Number} tolerance percentage of tolerance for the black and white threshold, 0.2 by default
994
+ * @returns {Date|null} The Date object representing the timestamp or null if the timestamp cannot be decoded
995
+ */
996
+ declare function decodeTimestamp(context: CanvasRenderingContext2D, lineWidth: number, blocksPerRow?: number, tolerance?: number): Date | undefined;
997
+ /**
998
+ * Encode the current timestamp into a line composed of blocks of black and white pixels
999
+ * written on the top of the canvas.
1000
+ *
1001
+ * @param {CanvasRenderingContext2D} context
1002
+ * @param {Number} lineWidth width of the line in pixels
1003
+ * @param {Number} blocksPerRow number of blocks in the line, 32 by default
1004
+ * @param {Date} now current date, new Date() by default
1005
+ */
1006
+ declare function encodeTimestamp(context: CanvasRenderingContext2D, lineWidth: number, blocksPerRow?: number, now?: Date): void;
1007
+
1008
+ declare const EpochTime_decodeTimestamp: typeof decodeTimestamp;
1009
+ declare const EpochTime_encodeTimestamp: typeof encodeTimestamp;
1010
+ declare const EpochTime_getLatency: typeof getLatency;
1011
+ declare namespace EpochTime {
1012
+ export { EpochTime_decodeTimestamp as decodeTimestamp, EpochTime_encodeTimestamp as encodeTimestamp, EpochTime_getLatency as getLatency };
1013
+ }
1014
+
930
1015
  /**
931
1016
  * Copyright 2024 Ceeblue B.V.
932
1017
  * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
@@ -935,4 +1020,4 @@ declare class WebSocketReliable extends EventEmitter {
935
1020
 
936
1021
  declare const VERSION: string;
937
1022
 
938
- export { BinaryReader, BinaryWriter, BitReader, ByteRate, Connect, EventEmitter, FixMap, type ILog, Log, LogType, Loggable, NetAddress, Numbers, Queue, SDP, Util, VERSION, WebSocketReliable, type WebSocketReliableError, log };
1023
+ export { BinaryReader, BinaryWriter, BitReader, ByteRate, Connect, EpochTime, EventEmitter, FixMap, type ILog, Log, LogType, Loggable, NetAddress, Numbers, Queue, SDP, Util, VERSION, WebSocketReliable, type WebSocketReliableError, log };
package/dist/web-utils.js CHANGED
@@ -633,10 +633,11 @@ function fetch(input, init) {
633
633
  return __awaiter(this, void 0, void 0, function* () {
634
634
  const response = yield self.fetch(input, init);
635
635
  if (response.status >= 300) {
636
+ let error;
636
637
  if (response.body) {
637
- throw (yield response.text()) || response.statusText;
638
+ error = yield response.text();
638
639
  }
639
- throw response.statusText;
640
+ throw (error || response.statusText || response.status).toString();
640
641
  }
641
642
  return response;
642
643
  });
@@ -659,6 +660,16 @@ function getExtension(path) {
659
660
  function getFile(path) {
660
661
  return path.substring(path.lastIndexOf('/') + 1);
661
662
  }
663
+ /**
664
+ * Get Base File part from path, without extension
665
+ * @param path path to parse
666
+ * @returns the base file name
667
+ */
668
+ function getBaseFile(path) {
669
+ const dot = path.lastIndexOf('.');
670
+ const file = path.lastIndexOf('/') + 1;
671
+ return dot >= 0 && dot >= file ? path.substring(file, dot) : path.substring(file);
672
+ }
662
673
  function codesFromString(value) {
663
674
  const codes = [];
664
675
  for (let i = 0; i < value.length; ++i) {
@@ -711,7 +722,7 @@ function trimEnd(value, chars = ' ') {
711
722
  --i;
712
723
  }
713
724
  return value.substring(0, i);
714
- }var Util=/*#__PURE__*/Object.freeze({__proto__:null,EMPTY_FUNCTION:EMPTY_FUNCTION,equal:equal,fetch:fetch,getExtension:getExtension,getFile:getFile,objectEntries:objectEntries,objectFrom:objectFrom,options:options,safePromise:safePromise,sleep:sleep,stringify:stringify,time:time,timeOrigin:timeOrigin,toBin:toBin,trim:trim,trimEnd:trimEnd,trimStart:trimStart});/**
725
+ }var Util=/*#__PURE__*/Object.freeze({__proto__:null,EMPTY_FUNCTION:EMPTY_FUNCTION,equal:equal,fetch:fetch,getBaseFile:getBaseFile,getExtension:getExtension,getFile:getFile,objectEntries:objectEntries,objectFrom:objectFrom,options:options,safePromise:safePromise,sleep:sleep,stringify:stringify,time:time,timeOrigin:timeOrigin,toBin:toBin,trim:trim,trimEnd:trimEnd,trimStart:trimStart});/**
715
726
  * Copyright 2024 Ceeblue B.V.
716
727
  * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
717
728
  * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
@@ -900,10 +911,6 @@ var Type;
900
911
  * @param params The parameters for which the media extension is to be defined
901
912
  */
902
913
  function defineMediaExt(type, params) {
903
- // Fix mediaExt in removing the possible '.' prefix
904
- if (params.mediaExt) {
905
- params.mediaExt = trimStart(params.mediaExt, '.');
906
- }
907
914
  // Compute appropriate mediaExt out parameter
908
915
  switch (type) {
909
916
  case Type.HESP:
@@ -917,7 +924,7 @@ function defineMediaExt(type, params) {
917
924
  const url = new URL(params.endPoint);
918
925
  const ext = getExtension(getFile(url.pathname));
919
926
  // set extension just if not json, json means a manifest file endPoint
920
- if (ext && ext !== 'json') {
927
+ if (ext && ext.toLowerCase() !== '.json') {
921
928
  params.mediaExt = ext;
922
929
  }
923
930
  }
@@ -941,6 +948,8 @@ function defineMediaExt(type, params) {
941
948
  console.warn('Unknown params type ' + type);
942
949
  break;
943
950
  }
951
+ // Fix mediaExt in removing the possible '.' prefix
952
+ trimStart(params.mediaExt, '.');
944
953
  }
945
954
  /**
946
955
  * Build an URL from {@link Type | type} and {@link Params | params}
@@ -962,7 +971,7 @@ function buildURL(type, params, protocol = 'wss') {
962
971
  url.pathname = '/webrtc/' + params.streamName;
963
972
  break;
964
973
  case Type.WRTS:
965
- url.pathname = '/wrts/' + params.streamName;
974
+ url.pathname = '/wrts/' + params.streamName + '.' + params.mediaExt;
966
975
  break;
967
976
  case Type.META:
968
977
  url.pathname = '/json_' + params.streamName + '.js';
@@ -1919,4 +1928,100 @@ class WebSocketReliable extends EventEmitter {
1919
1928
  * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
1920
1929
  * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
1921
1930
  */
1922
- const VERSION = '2.4.1';export{BinaryReader,BinaryWriter,BitReader,ByteRate,Connect,EventEmitter,FixMap,Log,LogType,Loggable,NetAddress,Numbers,Queue,SDP,Util,VERSION,WebSocketReliable,log};//# sourceMappingURL=web-utils.js.map
1931
+ /**
1932
+ * Decode the timestamp from a video element and compute the latency between the timestamp and the current date.
1933
+ *
1934
+ * @param {HTMLVideoElement} sourceEl the video element to get the image from
1935
+ * @param {HTMLCanvasElement} canvas
1936
+ * @param {CanvasRenderingContext2D} context
1937
+ * @param {Date} now current date, new Date() by default
1938
+ * @param {Number} blocksPerRow number of blocks in the line, 32 by default
1939
+ * @param {Number} tolerance percentage of tolerance for the black and white threshold, 0.2 by default
1940
+ * @returns {Number} The latency in millisecond between 'now' and the decoded timestamp, 0 if the timestamp cannot be decoded
1941
+ */
1942
+ function getLatency(sourceEl, canvas, context, now = new Date(), blocksPerRow = 32, tolerance = 0.2) {
1943
+ canvas.width = sourceEl.videoWidth;
1944
+ canvas.height = Math.floor(canvas.width / blocksPerRow);
1945
+ if (!canvas.width || !canvas.height) {
1946
+ // No pixel to parse!
1947
+ return 0;
1948
+ }
1949
+ context.drawImage(sourceEl, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
1950
+ const timestamp = decodeTimestamp(context, canvas.width, blocksPerRow, tolerance);
1951
+ return timestamp == null ? 0 : now.getTime() - timestamp.getTime();
1952
+ }
1953
+ /**
1954
+ * Decode a previously encoded timestamp from a canvas
1955
+ *
1956
+ * @param {CanvasRenderingContext2D} context
1957
+ * @param {Number} lineWidth width of the line in pixels
1958
+ * @param {Number} blocksPerRow number of blocks in the line, 32 by default
1959
+ * @param {Number} tolerance percentage of tolerance for the black and white threshold, 0.2 by default
1960
+ * @returns {Date|null} The Date object representing the timestamp or null if the timestamp cannot be decoded
1961
+ */
1962
+ function decodeTimestamp(context, lineWidth, blocksPerRow = 32, tolerance = 0.2) {
1963
+ const blockSize = lineWidth / blocksPerRow;
1964
+ let binaryTime = '';
1965
+ let i = blockSize / 2;
1966
+ const data = context.getImageData(0, Math.round(i), lineWidth, 1).data;
1967
+ const pixels = new Uint32Array(data.buffer);
1968
+ const blackThreshold = 0xffffff * tolerance;
1969
+ const whiteThreshold = 0xffffff * (1 - tolerance);
1970
+ while (i < pixels.length) {
1971
+ const pixel = pixels[Math.round(i)] & 0xffffff;
1972
+ pixels[Math.round(i)] = pixel;
1973
+ if (pixel < blackThreshold) {
1974
+ // Black
1975
+ binaryTime += '1';
1976
+ }
1977
+ else if (pixel > whiteThreshold) {
1978
+ // White
1979
+ binaryTime += '0';
1980
+ }
1981
+ else {
1982
+ return;
1983
+ }
1984
+ i += blockSize;
1985
+ }
1986
+ const day = parseInt(binaryTime.slice(0, 5), 2);
1987
+ const hour = parseInt(binaryTime.slice(5, 10), 2);
1988
+ const minute = parseInt(binaryTime.slice(10, 16), 2);
1989
+ const second = parseInt(binaryTime.slice(16, 22), 2);
1990
+ const millisecond = parseInt(binaryTime.slice(22, 32), 2);
1991
+ const now = new Date();
1992
+ return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), day, hour, minute, second, millisecond));
1993
+ }
1994
+ /**
1995
+ * Encode the current timestamp into a line composed of blocks of black and white pixels
1996
+ * written on the top of the canvas.
1997
+ *
1998
+ * @param {CanvasRenderingContext2D} context
1999
+ * @param {Number} lineWidth width of the line in pixels
2000
+ * @param {Number} blocksPerRow number of blocks in the line, 32 by default
2001
+ * @param {Date} now current date, new Date() by default
2002
+ */
2003
+ function encodeTimestamp(context, lineWidth, blocksPerRow = 32, now = new Date()) {
2004
+ const blockSize = Math.floor(lineWidth / blocksPerRow);
2005
+ const day = now.getUTCDate();
2006
+ const hour = now.getUTCHours();
2007
+ const minute = now.getUTCMinutes();
2008
+ const second = now.getUTCSeconds();
2009
+ const millisecond = now.getUTCMilliseconds();
2010
+ const binaryDay = day.toString(2).padStart(5, '0');
2011
+ const binaryHour = hour.toString(2).padStart(5, '0');
2012
+ const binaryMinute = minute.toString(2).padStart(6, '0');
2013
+ const binarySecond = second.toString(2).padStart(6, '0');
2014
+ const binaryMillisecond = millisecond.toString(2).padStart(10, '0');
2015
+ const binaryTime = binaryDay + binaryHour + binaryMinute + binarySecond + binaryMillisecond;
2016
+ for (let i = 0; i < binaryTime.length; i++) {
2017
+ const x = (i % blocksPerRow) * blockSize;
2018
+ const y = Math.floor(i / blocksPerRow) * blockSize;
2019
+ context.fillStyle = binaryTime[i] === '1' ? 'black' : 'white';
2020
+ context.fillRect(x, y, blockSize, blockSize);
2021
+ }
2022
+ }var EpochTime=/*#__PURE__*/Object.freeze({__proto__:null,decodeTimestamp:decodeTimestamp,encodeTimestamp:encodeTimestamp,getLatency:getLatency});/**
2023
+ * Copyright 2024 Ceeblue B.V.
2024
+ * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
2025
+ * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
2026
+ */
2027
+ const VERSION = '2.6.0';export{BinaryReader,BinaryWriter,BitReader,ByteRate,Connect,EpochTime,EventEmitter,FixMap,Log,LogType,Loggable,NetAddress,Numbers,Queue,SDP,Util,VERSION,WebSocketReliable,log};//# sourceMappingURL=web-utils.js.map