diff --git a/docs/tutorials/upgrade.md b/docs/tutorials/upgrade.md index ce17faad09..396b131caf 100644 --- a/docs/tutorials/upgrade.md +++ b/docs/tutorials/upgrade.md @@ -96,8 +96,10 @@ application: - Configuration changes: - `streaming.forceTransmuxTS` has been renamed to `streaming.forceTransmux` (deprecated in v4.3.0) - - `manifest.dash.manifestPreprocessor` callback now receives a type of `shaka.externs.xml.Node` instead of `Element`. - - `manifest.mss.manifestPreprocessor` callback now receives a type of `shaka.externs.xml.Node` instead of `Element`. + - Callbacks that used to accept `Element` now accept `shaka.externs.xml.Node`: + (`manifest.dash.manifestPreprocessor` and `manifest.mss.manifestPreprocessor`). + `getAttribute()` and `textContent` results must now be decoded if they might contain + escape sequences. You can use `shaka.util.StringUtils.htmlUnescape` for this purpose. - `streaming.useNativeHlsOnSafari` has removed. Now we have another config to do the same for FairPlay `streaming.useNativeHlsForFairPlay` or for HLS (any browser) `streaming.preferNativeHls`. - Plugin changes: diff --git a/lib/dash/content_protection.js b/lib/dash/content_protection.js index a63f30597d..38be75da7f 100644 --- a/lib/dash/content_protection.js +++ b/lib/dash/content_protection.js @@ -191,6 +191,7 @@ shaka.dash.ContentProtection = class { * @return {string} */ static getWidevineLicenseUrl(element) { + const StringUtils = shaka.util.StringUtils; const dashIfLaurlNode = shaka.util.TXml.findChildNS( element.node, shaka.dash.ContentProtection.DashIfNamespaceUri_, 'Laurl', @@ -204,7 +205,8 @@ shaka.dash.ContentProtection = class { const mslaurlNode = shaka.util.TXml.findChildNS( element.node, 'urn:microsoft', 'laurl'); if (mslaurlNode) { - return mslaurlNode.attributes['licenseUrl'] || ''; + return StringUtils.htmlUnescape( + mslaurlNode.attributes['licenseUrl']) || ''; } return ''; } @@ -642,7 +644,8 @@ shaka.dash.ContentProtection = class { } const ivHex = cryptoPeriod.attributes['IV']; - const keyUri = cryptoPeriod.attributes['keyUriTemplate']; + const keyUri = shaka.util.StringUtils.htmlUnescape( + cryptoPeriod.attributes['keyUriTemplate']); if (!ivHex || !keyUri) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, diff --git a/lib/dash/segment_base.js b/lib/dash/segment_base.js index eaee5006af..ed31002f52 100644 --- a/lib/dash/segment_base.js +++ b/lib/dash/segment_base.js @@ -16,6 +16,7 @@ goog.require('shaka.media.WebmSegmentIndexParser'); goog.require('shaka.util.Error'); goog.require('shaka.util.ManifestParserUtils'); goog.require('shaka.util.ObjectUtils'); +goog.require('shaka.util.StringUtils'); goog.require('shaka.util.TXml'); goog.requireType('shaka.dash.DashParser'); goog.requireType('shaka.media.PresentationTimeline'); @@ -39,6 +40,7 @@ shaka.dash.SegmentBase = class { const MpdUtils = shaka.dash.MpdUtils; const TXml = shaka.util.TXml; const ManifestParserUtils = shaka.util.ManifestParserUtils; + const StringUtils = shaka.util.StringUtils; const initialization = MpdUtils.inheritChild(context, callback, 'Initialization'); @@ -49,7 +51,9 @@ shaka.dash.SegmentBase = class { let resolvedUris = context.representation.getBaseUris(); const uri = initialization.attributes['sourceURL']; if (uri) { - resolvedUris = ManifestParserUtils.resolveUris(resolvedUris, [uri]); + resolvedUris = ManifestParserUtils.resolveUris(resolvedUris, [ + StringUtils.htmlUnescape(uri), + ]); } let startByte = 0; @@ -244,13 +248,15 @@ shaka.dash.SegmentBase = class { const ManifestParserUtils = shaka.util.ManifestParserUtils; const MpdUtils = shaka.dash.MpdUtils; const SegmentBase = shaka.dash.SegmentBase; + const StringUtils = shaka.util.StringUtils; const representationIndex = MpdUtils.inheritChild( context, SegmentBase.fromInheritance_, 'RepresentationIndex'); let indexUris = context.representation.getBaseUris(); if (representationIndex) { - const representationUri = representationIndex.attributes['sourceURL']; + const representationUri = + StringUtils.htmlUnescape(representationIndex.attributes['sourceURL']); if (representationUri) { indexUris = ManifestParserUtils.resolveUris( indexUris, [representationUri]); diff --git a/lib/dash/segment_list.js b/lib/dash/segment_list.js index 7a4dbcfa52..42bf753e62 100644 --- a/lib/dash/segment_list.js +++ b/lib/dash/segment_list.js @@ -16,6 +16,7 @@ goog.require('shaka.media.SegmentReference'); goog.require('shaka.util.Error'); goog.require('shaka.util.Functional'); goog.require('shaka.util.ManifestParserUtils'); +goog.require('shaka.util.StringUtils'); goog.require('shaka.util.TXml'); goog.requireType('shaka.dash.DashParser'); goog.requireType('shaka.media.PresentationTimeline'); @@ -290,6 +291,7 @@ shaka.dash.SegmentList = class { ].filter(Functional.isNotNull); const TXml = shaka.util.TXml; + const StringUtils = shaka.util.StringUtils; // Search each SegmentList for one with at least one SegmentURL element, // select the first one, and convert each SegmentURL element to a tuple. return segmentLists @@ -305,7 +307,7 @@ shaka.dash.SegmentList = class { 'attribute or SegmentTimeline, which must be accurate.'); } - const uri = urlNode.attributes['media']; + const uri = StringUtils.htmlUnescape(urlNode.attributes['media']); const range = TXml.parseAttr( urlNode, 'mediaRange', TXml.parseRange, {start: 0, end: null}); diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index 57fc09b0d2..0fa70c368e 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -17,6 +17,7 @@ goog.require('shaka.util.Error'); goog.require('shaka.util.IReleasable'); goog.require('shaka.util.ManifestParserUtils'); goog.require('shaka.util.ObjectUtils'); +goog.require('shaka.util.StringUtils'); goog.requireType('shaka.dash.DashParser'); goog.requireType('shaka.media.PresentationTimeline'); @@ -195,6 +196,7 @@ shaka.dash.SegmentTemplate = class { static parseSegmentTemplateInfo_(context) { const SegmentTemplate = shaka.dash.SegmentTemplate; const MpdUtils = shaka.dash.MpdUtils; + const StringUtils = shaka.util.StringUtils; const segmentInfo = MpdUtils.parseSegmentInfo(context, SegmentTemplate.fromInheritance_); @@ -211,7 +213,7 @@ shaka.dash.SegmentTemplate = class { unscaledPresentationTimeOffset: segmentInfo.unscaledPresentationTimeOffset, timeline: segmentInfo.timeline, - mediaTemplate: media, + mediaTemplate: media && StringUtils.htmlUnescape(media), indexTemplate: index, }; } @@ -534,11 +536,12 @@ shaka.dash.SegmentTemplate = class { const ManifestParserUtils = shaka.util.ManifestParserUtils; const SegmentTemplate = shaka.dash.SegmentTemplate; - const initialization = MpdUtils.inheritAttribute( + let initialization = MpdUtils.inheritAttribute( context, SegmentTemplate.fromInheritance_, 'initialization'); if (!initialization) { return null; } + initialization = shaka.util.StringUtils.htmlUnescape(initialization); const repId = context.representation.id; const bandwidth = context.bandwidth || null;