diff --git a/goodtube.js b/goodtube.js
index 76991f4..4017884 100644
--- a/goodtube.js
+++ b/goodtube.js
@@ -2,13 +2,17 @@
'use strict';
- /* Bypass CSP restrictions (introduced by the latest Chrome updates)
+ /* Setup the CSP (content security policy)
------------------------------------------------------------------------------------------ */
- if (window.trustedTypes && window.trustedTypes.createPolicy && !window.trustedTypes.defaultPolicy) {
- window.trustedTypes.createPolicy('default', {
- createHTML: string => string,
- createScriptURL: string => string,
- createScript: string => string
+ // Include DOM Purify DOM Purify (https://github.com/cure53/DOMPurify/blob/main/dist/purify.min.js)
+ // We keep this inline this because fetching it from an external repo we don't control is likely unreliable in the long term.
+ !function (e, t) { "object" == typeof exports && "undefined" != typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define(t) : (e = "undefined" != typeof globalThis ? globalThis : e || self).DOMPurify = t() }(this, (function () { "use strict"; const { entries: e, setPrototypeOf: t, isFrozen: n, getPrototypeOf: o, getOwnPropertyDescriptor: r } = Object; let { freeze: i, seal: a, create: l } = Object, { apply: c, construct: s } = "undefined" != typeof Reflect && Reflect; i || (i = function (e) { return e }), a || (a = function (e) { return e }), c || (c = function (e, t) { for (var n = arguments.length, o = new Array(n > 2 ? n - 2 : 0), r = 2; r < n; r++)o[r - 2] = arguments[r]; return e.apply(t, o) }), s || (s = function (e) { for (var t = arguments.length, n = new Array(t > 1 ? t - 1 : 0), o = 1; o < t; o++)n[o - 1] = arguments[o]; return new e(...n) }); const u = w(Array.prototype.forEach), m = w(Array.prototype.lastIndexOf), p = w(Array.prototype.pop), f = w(Array.prototype.push), d = w(Array.prototype.splice), h = w(String.prototype.toLowerCase), g = w(String.prototype.toString), T = w(String.prototype.match), y = w(String.prototype.replace), E = w(String.prototype.indexOf), A = w(String.prototype.trim), _ = w(Object.prototype.hasOwnProperty), b = w(RegExp.prototype.test), S = (N = TypeError, function () { for (var e = arguments.length, t = new Array(e), n = 0; n < e; n++)t[n] = arguments[n]; return s(N, t) }); var N; function w(e) { return function (t) { t instanceof RegExp && (t.lastIndex = 0); for (var n = arguments.length, o = new Array(n > 1 ? n - 1 : 0), r = 1; r < n; r++)o[r - 1] = arguments[r]; return c(e, t, o) } } function R(e, o) { let r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : h; t && t(e, null); let i = o.length; for (; i--;) { let t = o[i]; if ("string" == typeof t) { const e = r(t); e !== t && (n(o) || (o[i] = e), t = e) } e[t] = !0 } return e } function D(e) { for (let t = 0; t < e.length; t++) { _(e, t) || (e[t] = null) } return e } function C(t) { const n = l(null); for (const [o, r] of e(t)) { _(t, o) && (Array.isArray(r) ? n[o] = D(r) : r && "object" == typeof r && r.constructor === Object ? n[o] = C(r) : n[o] = r) } return n } function v(e, t) { for (; null !== e;) { const n = r(e, t); if (n) { if (n.get) return w(n.get); if ("function" == typeof n.value) return w(n.value) } e = o(e) } return function () { return null } } const O = i(["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "decorator", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "marquee", "menu", "menuitem", "meter", "nav", "nobr", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "search", "section", "select", "shadow", "slot", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]), x = i(["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "enterkeyhint", "exportparts", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "inputmode", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "part", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"]), L = i(["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"]), k = i(["animate", "color-profile", "cursor", "discard", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]), I = i(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover", "mprescripts"]), M = i(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]), U = i(["#text"]), z = i(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "exportparts", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inert", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "part", "pattern", "placeholder", "playsinline", "popover", "popovertarget", "popovertargetaction", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "slot", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "wrap", "xmlns", "slot"]), P = i(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]), F = i(["accent", "accentunder", "align", "bevelled", "close", "columnsalign", "columnlines", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lspace", "lquote", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]), H = i(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]), B = a(/\{\{[\w\W]*|[\w\W]*\}\}/gm), G = a(/<%[\w\W]*|[\w\W]*%>/gm), W = a(/\$\{[\w\W]*/gm), Y = a(/^data-[\-\w.\u00B7-\uFFFF]+$/), j = a(/^aria-[\-\w]+$/), X = a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i), q = a(/^(?:\w+script|data):/i), $ = a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g), K = a(/^html$/i), V = a(/^[a-z][.\w]*(-[.\w]+)+$/i); var Z = Object.freeze({ __proto__: null, ARIA_ATTR: j, ATTR_WHITESPACE: $, CUSTOM_ELEMENT: V, DATA_ATTR: Y, DOCTYPE_NAME: K, ERB_EXPR: G, IS_ALLOWED_URI: X, IS_SCRIPT_OR_DATA: q, MUSTACHE_EXPR: B, TMPLIT_EXPR: W }); const J = 1, Q = 3, ee = 7, te = 8, ne = 9, oe = function () { return "undefined" == typeof window ? null : window }; var re = function t() { let n = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : oe(); const o = e => t(e); if (o.version = "3.3.0", o.removed = [], !n || !n.document || n.document.nodeType !== ne || !n.Element) return o.isSupported = !1, o; let { document: r } = n; const a = r, c = a.currentScript, { DocumentFragment: s, HTMLTemplateElement: N, Node: w, Element: D, NodeFilter: B, NamedNodeMap: G = n.NamedNodeMap || n.MozNamedAttrMap, HTMLFormElement: W, DOMParser: Y, trustedTypes: j } = n, q = D.prototype, $ = v(q, "cloneNode"), V = v(q, "remove"), re = v(q, "nextSibling"), ie = v(q, "childNodes"), ae = v(q, "parentNode"); if ("function" == typeof N) { const e = r.createElement("template"); e.content && e.content.ownerDocument && (r = e.content.ownerDocument) } let le, ce = ""; const { implementation: se, createNodeIterator: ue, createDocumentFragment: me, getElementsByTagName: pe } = r, { importNode: fe } = a; let de = { afterSanitizeAttributes: [], afterSanitizeElements: [], afterSanitizeShadowDOM: [], beforeSanitizeAttributes: [], beforeSanitizeElements: [], beforeSanitizeShadowDOM: [], uponSanitizeAttribute: [], uponSanitizeElement: [], uponSanitizeShadowNode: [] }; o.isSupported = "function" == typeof e && "function" == typeof ae && se && void 0 !== se.createHTMLDocument; const { MUSTACHE_EXPR: he, ERB_EXPR: ge, TMPLIT_EXPR: Te, DATA_ATTR: ye, ARIA_ATTR: Ee, IS_SCRIPT_OR_DATA: Ae, ATTR_WHITESPACE: _e, CUSTOM_ELEMENT: be } = Z; let { IS_ALLOWED_URI: Se } = Z, Ne = null; const we = R({}, [...O, ...x, ...L, ...I, ...U]); let Re = null; const De = R({}, [...z, ...P, ...F, ...H]); let Ce = Object.seal(l(null, { tagNameCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, attributeNameCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, allowCustomizedBuiltInElements: { writable: !0, configurable: !1, enumerable: !0, value: !1 } })), ve = null, Oe = null; const xe = Object.seal(l(null, { tagCheck: { writable: !0, configurable: !1, enumerable: !0, value: null }, attributeCheck: { writable: !0, configurable: !1, enumerable: !0, value: null } })); let Le = !0, ke = !0, Ie = !1, Me = !0, Ue = !1, ze = !0, Pe = !1, Fe = !1, He = !1, Be = !1, Ge = !1, We = !1, Ye = !0, je = !1, Xe = !0, qe = !1, $e = {}, Ke = null; const Ve = R({}, ["annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", "style", "svg", "template", "thead", "title", "video", "xmp"]); let Ze = null; const Je = R({}, ["audio", "video", "img", "source", "image", "track"]); let Qe = null; const et = R({}, ["alt", "class", "for", "id", "label", "name", "pattern", "placeholder", "role", "summary", "title", "value", "style", "xmlns"]), tt = "http://www.w3.org/1998/Math/MathML", nt = "http://www.w3.org/2000/svg", ot = "http://www.w3.org/1999/xhtml"; let rt = ot, it = !1, at = null; const lt = R({}, [tt, nt, ot], g); let ct = R({}, ["mi", "mo", "mn", "ms", "mtext"]), st = R({}, ["annotation-xml"]); const ut = R({}, ["title", "style", "font", "a", "script"]); let mt = null; const pt = ["application/xhtml+xml", "text/html"]; let ft = null, dt = null; const ht = r.createElement("form"), gt = function (e) { return e instanceof RegExp || e instanceof Function }, Tt = function () { let e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; if (!dt || dt !== e) { if (e && "object" == typeof e || (e = {}), e = C(e), mt = -1 === pt.indexOf(e.PARSER_MEDIA_TYPE) ? "text/html" : e.PARSER_MEDIA_TYPE, ft = "application/xhtml+xml" === mt ? g : h, Ne = _(e, "ALLOWED_TAGS") ? R({}, e.ALLOWED_TAGS, ft) : we, Re = _(e, "ALLOWED_ATTR") ? R({}, e.ALLOWED_ATTR, ft) : De, at = _(e, "ALLOWED_NAMESPACES") ? R({}, e.ALLOWED_NAMESPACES, g) : lt, Qe = _(e, "ADD_URI_SAFE_ATTR") ? R(C(et), e.ADD_URI_SAFE_ATTR, ft) : et, Ze = _(e, "ADD_DATA_URI_TAGS") ? R(C(Je), e.ADD_DATA_URI_TAGS, ft) : Je, Ke = _(e, "FORBID_CONTENTS") ? R({}, e.FORBID_CONTENTS, ft) : Ve, ve = _(e, "FORBID_TAGS") ? R({}, e.FORBID_TAGS, ft) : C({}), Oe = _(e, "FORBID_ATTR") ? R({}, e.FORBID_ATTR, ft) : C({}), $e = !!_(e, "USE_PROFILES") && e.USE_PROFILES, Le = !1 !== e.ALLOW_ARIA_ATTR, ke = !1 !== e.ALLOW_DATA_ATTR, Ie = e.ALLOW_UNKNOWN_PROTOCOLS || !1, Me = !1 !== e.ALLOW_SELF_CLOSE_IN_ATTR, Ue = e.SAFE_FOR_TEMPLATES || !1, ze = !1 !== e.SAFE_FOR_XML, Pe = e.WHOLE_DOCUMENT || !1, Be = e.RETURN_DOM || !1, Ge = e.RETURN_DOM_FRAGMENT || !1, We = e.RETURN_TRUSTED_TYPE || !1, He = e.FORCE_BODY || !1, Ye = !1 !== e.SANITIZE_DOM, je = e.SANITIZE_NAMED_PROPS || !1, Xe = !1 !== e.KEEP_CONTENT, qe = e.IN_PLACE || !1, Se = e.ALLOWED_URI_REGEXP || X, rt = e.NAMESPACE || ot, ct = e.MATHML_TEXT_INTEGRATION_POINTS || ct, st = e.HTML_INTEGRATION_POINTS || st, Ce = e.CUSTOM_ELEMENT_HANDLING || {}, e.CUSTOM_ELEMENT_HANDLING && gt(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck) && (Ce.tagNameCheck = e.CUSTOM_ELEMENT_HANDLING.tagNameCheck), e.CUSTOM_ELEMENT_HANDLING && gt(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck) && (Ce.attributeNameCheck = e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck), e.CUSTOM_ELEMENT_HANDLING && "boolean" == typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (Ce.allowCustomizedBuiltInElements = e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements), Ue && (ke = !1), Ge && (Be = !0), $e && (Ne = R({}, U), Re = [], !0 === $e.html && (R(Ne, O), R(Re, z)), !0 === $e.svg && (R(Ne, x), R(Re, P), R(Re, H)), !0 === $e.svgFilters && (R(Ne, L), R(Re, P), R(Re, H)), !0 === $e.mathMl && (R(Ne, I), R(Re, F), R(Re, H))), e.ADD_TAGS && ("function" == typeof e.ADD_TAGS ? xe.tagCheck = e.ADD_TAGS : (Ne === we && (Ne = C(Ne)), R(Ne, e.ADD_TAGS, ft))), e.ADD_ATTR && ("function" == typeof e.ADD_ATTR ? xe.attributeCheck = e.ADD_ATTR : (Re === De && (Re = C(Re)), R(Re, e.ADD_ATTR, ft))), e.ADD_URI_SAFE_ATTR && R(Qe, e.ADD_URI_SAFE_ATTR, ft), e.FORBID_CONTENTS && (Ke === Ve && (Ke = C(Ke)), R(Ke, e.FORBID_CONTENTS, ft)), Xe && (Ne["#text"] = !0), Pe && R(Ne, ["html", "head", "body"]), Ne.table && (R(Ne, ["tbody"]), delete ve.tbody), e.TRUSTED_TYPES_POLICY) { if ("function" != typeof e.TRUSTED_TYPES_POLICY.createHTML) throw S('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.'); if ("function" != typeof e.TRUSTED_TYPES_POLICY.createScriptURL) throw S('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.'); le = e.TRUSTED_TYPES_POLICY, ce = le.createHTML("") } else void 0 === le && (le = function (e, t) { if ("object" != typeof e || "function" != typeof e.createPolicy) return null; let n = null; const o = "data-tt-policy-suffix"; t && t.hasAttribute(o) && (n = t.getAttribute(o)); const r = "dompurify" + (n ? "#" + n : ""); try { return e.createPolicy(r, { createHTML: e => e, createScriptURL: e => e }) } catch (e) { return console.warn("TrustedTypes policy " + r + " could not be created."), null } }(j, c)), null !== le && "string" == typeof ce && (ce = le.createHTML("")); i && i(e), dt = e } }, yt = R({}, [...x, ...L, ...k]), Et = R({}, [...I, ...M]), At = function (e) { f(o.removed, { element: e }); try { ae(e).removeChild(e) } catch (t) { V(e) } }, _t = function (e, t) { try { f(o.removed, { attribute: t.getAttributeNode(e), from: t }) } catch (e) { f(o.removed, { attribute: null, from: t }) } if (t.removeAttribute(e), "is" === e) if (Be || Ge) try { At(t) } catch (e) {} else try { t.setAttribute(e, "") } catch (e) {} }, bt = function (e) { let t = null, n = null; if (He) e = "