From 43941a801f9b74441418a38e8934cd4c3581a118 Mon Sep 17 00:00:00 2001 From: Walter Seymour Date: Thu, 25 Jan 2024 08:57:16 -0600 Subject: [PATCH] feat: improved error interface (#8564) --- package-lock.json | 6 ++--- src/js/consts/errors.js | 13 +++++++++++ src/js/media-error.js | 43 +++++++++++++++++++++++++++-------- src/js/video.js | 4 ++++ test/unit/media-error.test.js | 9 +++++++- 5 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 src/js/consts/errors.js diff --git a/package-lock.json b/package-lock.json index 263c39af55..3fadc8b9d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1851,7 +1851,7 @@ "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", "dev": true }, "accepts": { @@ -3263,7 +3263,7 @@ "chainsaw": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", "dev": true, "requires": { "traverse": ">=0.3.0 <0.4" @@ -10472,7 +10472,7 @@ "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "requires": { "abbrev": "1" diff --git a/src/js/consts/errors.js b/src/js/consts/errors.js new file mode 100644 index 0000000000..ff5989fe4e --- /dev/null +++ b/src/js/consts/errors.js @@ -0,0 +1,13 @@ +export default { + UnsupportedSidxContainer: 'unsupported-sidx-container-error', + DashManifestSidxParsingError: 'dash-manifest-sidx-parsing-error', + HlsPlaylistRequestError: 'hls-playlist-request-error', + SegmentUnsupportedMediaFormat: 'segment-unsupported-media-format-error', + UnsupportedMediaInitialization: 'unsupported-media-initialization-error', + SegmentSwitchError: 'segment-switch-error', + SegmentExceedsSourceBufferQuota: 'segment-exceeds-source-buffer-quota-error', + SegmentAppendError: 'segment-append-error', + VttLoadError: 'vtt-load-error', + VttCueParsingError: 'vtt-cue-parsing-error', + EMEKeySessionCreationError: 'eme-key-session-creation-error' +}; diff --git a/src/js/media-error.js b/src/js/media-error.js index 57fa92e07e..e7ec8f396d 100644 --- a/src/js/media-error.js +++ b/src/js/media-error.js @@ -75,6 +75,21 @@ MediaError.prototype.message = ''; */ MediaError.prototype.status = null; +/** + * An object containing an error type, as well as other information regarding the error. + * + * @typedef {{errorType: string, [key: string]: any}} ErrorMetadata + */ + +/** + * An optional object to give more detail about the error. This can be used to give + * a higher level of specificity to an error versus the more generic MediaError codes. + * `metadata` expects an `errorType` string that should align with the values from videojs.Error. + * + * @type {ErrorMetadata} + */ +MediaError.prototype.metadata = null; + /** * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the * specification listed under {@link MediaError} for more information. @@ -111,16 +126,6 @@ MediaError.defaultMessages = { 5: 'The media is encrypted and we do not have the keys to decrypt it.' }; -// Add types as properties on MediaError -// e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; -for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { - MediaError[MediaError.errorTypes[errNum]] = errNum; - // values should be accessible on both the class and instance - MediaError.prototype[MediaError.errorTypes[errNum]] = errNum; -} - -// jsdocs for instance/static members added above -// instance methods use `#` and static methods use `.` /** * W3C error code for any custom error. * @@ -128,6 +133,8 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 0 */ +MediaError.MEDIA_ERR_CUSTOM = 0; + /** * W3C error code for any custom error. * @@ -135,6 +142,7 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 0 */ +MediaError.prototype.MEDIA_ERR_CUSTOM = 0; /** * W3C error code for media error aborted. @@ -143,6 +151,8 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 1 */ +MediaError.MEDIA_ERR_ABORTED = 1; + /** * W3C error code for media error aborted. * @@ -150,6 +160,7 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 1 */ +MediaError.prototype.MEDIA_ERR_ABORTED = 1; /** * W3C error code for any network error. @@ -158,6 +169,8 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 2 */ +MediaError.MEDIA_ERR_NETWORK = 2; + /** * W3C error code for any network error. * @@ -165,6 +178,7 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 2 */ +MediaError.prototype.MEDIA_ERR_NETWORK = 2; /** * W3C error code for any decoding error. @@ -173,6 +187,8 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 3 */ +MediaError.MEDIA_ERR_DECODE = 3; + /** * W3C error code for any decoding error. * @@ -180,6 +196,7 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 3 */ +MediaError.prototype.MEDIA_ERR_DECODE = 3; /** * W3C error code for any time that a source is not supported. @@ -188,6 +205,8 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 4 */ +MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; + /** * W3C error code for any time that a source is not supported. * @@ -195,6 +214,7 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 4 */ +MediaError.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; /** * W3C error code for any time that a source is encrypted. @@ -203,6 +223,8 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 5 */ +MediaError.MEDIA_ERR_ENCRYPTED = 5; + /** * W3C error code for any time that a source is encrypted. * @@ -210,5 +232,6 @@ for (let errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { * @constant {number} * @default 5 */ +MediaError.prototype.MEDIA_ERR_ENCRYPTED = 5; export default MediaError; diff --git a/src/js/video.js b/src/js/video.js index 9d2dde1f5a..ae0cf473d3 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -34,6 +34,7 @@ import * as Dom from './utils/dom.js'; import * as browser from './utils/browser.js'; import * as Url from './utils/url.js'; import * as Obj from './utils/obj'; +import VjsErrors from './consts/errors'; import xhr from '@videojs/xhr'; // Include the built-in techs @@ -617,4 +618,7 @@ videojs.str = Str; */ videojs.url = Url; +// The list of possible error types to occur in video.js +videojs.Error = VjsErrors; + export default videojs; diff --git a/test/unit/media-error.test.js b/test/unit/media-error.test.js index 3271f9ebdf..e15300a052 100644 --- a/test/unit/media-error.test.js +++ b/test/unit/media-error.test.js @@ -41,12 +41,19 @@ QUnit.test('can be constructed from a string', function(assert) { QUnit.test('can be constructed from an object', function(assert) { const mediaError = new MediaError({code: 2}); - const mediaErrorMsg = new MediaError({code: 2, message: 'hello, world'}); + const mediaErrorMsg = new MediaError({ + code: 2, + message: 'hello, world', + metadata: { + errorType: 'test-error' + } + }); assert.strictEqual(mediaError.code, 2); assert.strictEqual(mediaError.message, MediaError.defaultMessages['2']); assert.strictEqual(mediaErrorMsg.code, 2); assert.strictEqual(mediaErrorMsg.message, 'hello, world'); + assert.strictEqual(mediaErrorMsg.metadata.errorType, 'test-error'); }); if (isModernBrowser) {