diff --git a/config.js b/config.js index f042ad2e0..69ea0e060 100644 --- a/config.js +++ b/config.js @@ -41,6 +41,8 @@ const config = { PINNED_URI_2: process.env.PINNED_URI_2, PINNED_LABEL_2: process.env.PINNED_LABEL_2, KNOWN_APP_DOMAINS: process.env.KNOWN_APP_DOMAINS ? process.env.KNOWN_APP_DOMAINS.split(',') : [], + CHANNEL_THUMBNAIL_FALLBACK: process.env.CHANNEL_THUMBNAIL_FALLBACK, + STREAM_THUMBNAIL_FALLBACK: process.env.STREAM_THUMBNAIL_FALLBACK, }; config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`; diff --git a/package.json b/package.json index e7414cc5d..acd3d2e3f 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,9 @@ "electron-updater": "^4.2.4", "express": "^4.17.1", "if-env": "^1.0.4", - "remark-breaks": "^2.0.1", - "remove-markdown": "^0.3.0", + "remove-markdown": "^0.3.0", + "react-image": "^4.0.3", + "remark-breaks": "^2.0.1", "tempy": "^0.6.0", "videojs-logo": "^2.1.4" }, @@ -205,6 +206,7 @@ "video.js": "^7.10.1", "videojs-contrib-quality-levels": "^2.0.9", "videojs-event-tracking": "^1.0.1", + "videojs-hls-quality-selector": "^1.1.4", "villain-react": "^1.0.9", "wavesurfer.js": "^2.2.1", "webpack": "^4.28.4", diff --git a/ui/component/channelStakedIndicator/view.jsx b/ui/component/channelStakedIndicator/view.jsx index fb548728f..6f0187f7b 100644 --- a/ui/component/channelStakedIndicator/view.jsx +++ b/ui/component/channelStakedIndicator/view.jsx @@ -23,10 +23,10 @@ function getChannelLevel(amount: number): number { case amount >= 50 && amount < 250: level = 3; break; - case amount >= 250 && amount < 1000: + case amount >= 100 && amount < 1000: level = 4; break; - case amount >= 1000: + case amount > 1000: level = 5; break; } diff --git a/ui/component/channelThumbnail/view.jsx b/ui/component/channelThumbnail/view.jsx index 129565416..d3af5c508 100644 --- a/ui/component/channelThumbnail/view.jsx +++ b/ui/component/channelThumbnail/view.jsx @@ -5,7 +5,6 @@ import classnames from 'classnames'; import Gerbil from './gerbil.png'; import FreezeframeWrapper from 'component/fileThumbnail/FreezeframeWrapper'; import ChannelStakedIndicator from 'component/channelStakedIndicator'; -import { getThumbnailCdnUrl } from 'util/thumbnail'; type Props = { thumbnail: ?string, @@ -68,14 +67,6 @@ function ChannelThumbnail(props: Props) { ); } - let url = channelThumbnail; - // @if TARGET='web' - // Pass image urls through a compression proxy - if (thumbnail) { - url = getThumbnailCdnUrl({ thumbnail }); - } - // @endif - return (
setThumbError(true)} // if thumb fails (including due to https replace, show gerbil. /> )} @@ -100,7 +91,7 @@ function ChannelThumbnail(props: Props) { {__('Channel setThumbError(true)} // if thumb fails (including due to https replace, show gerbil. /> )} diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index cd6b6d8d9..00e0173bb 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -2,8 +2,9 @@ import type { Node } from 'react'; import React, { useEffect, forwardRef } from 'react'; import { NavLink, withRouter } from 'react-router-dom'; +import { useImage } from 'react-image'; import classnames from 'classnames'; -import { SIMPLE_SITE } from 'config'; +import { CHANNEL_THUMBNAIL_FALLBACK, STREAM_THUMBNAIL_FALLBACK, SIMPLE_SITE } from 'config'; import { parseURI, convertToShareLink } from 'lbry-redux'; import { openCopyLinkMenu } from 'util/context-menu'; import { formatLbryUrlForWeb } from 'util/url'; @@ -188,6 +189,11 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { // Weird placement warning // Make sure this happens after we figure out if this claim needs to be hidden const thumbnailUrl = useGetThumbnail(contentUri, claim, streamingUrl, getFile, shouldHide); + const isStream = claim && claim.value_type === 'stream'; + const { src: thumbnailUrlWithFallback } = useImage({ + srcList: [thumbnailUrl, isStream ? STREAM_THUMBNAIL_FALLBACK : CHANNEL_THUMBNAIL_FALLBACK], + useSuspense: false, + }); function handleContextMenu(e) { // @if TARGET='app' @@ -282,7 +288,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { <> {!pending ? ( - + {/* @if TARGET='app' */} {claim && (
@@ -298,7 +304,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { ) : ( - + )} )} diff --git a/ui/component/common/icon-custom.jsx b/ui/component/common/icon-custom.jsx index 049e80325..5f9c9c8d1 100644 --- a/ui/component/common/icon-custom.jsx +++ b/ui/component/common/icon-custom.jsx @@ -1100,4 +1100,29 @@ export const icons = { ), + [ICONS.MOVIES]: (props: CustomProps) => ( + + + + + + + + + + + + + ), }; diff --git a/ui/component/fileThumbnail/view.jsx b/ui/component/fileThumbnail/view.jsx index ad818c19c..8ee1d4c5e 100644 --- a/ui/component/fileThumbnail/view.jsx +++ b/ui/component/fileThumbnail/view.jsx @@ -46,9 +46,11 @@ function FileThumbnail(props: Props) { } // @endif + const cleanUrl = url ? url.replace(/'/g, "\\'") : ''; + return (
{ - this.updatePlugin(); - }); - } - - updatePlugin() { - // If there is the HLS tech - if (this.getHls()) { - // Show quality selector - this._qualityButton.show(); - } else { - // Hide quality selector - this._qualityButton.hide(); - } - } - - /** - * Returns HLS Plugin - * - * @return {*} - videojs-hls-contrib plugin. - */ - getHls() { - return this.player.tech({ IWillNotUseThisInPlugins: true }).hls; - } - - /** - * Binds listener for quality level changes. - */ - bindPlayerEvents() { - this.player.qualityLevels().on('addqualitylevel', this.onAddQualityLevel.bind(this)); - } - - /** - * Adds the quality menu button to the player control bar. - */ - createQualityButton() { - const player = this.player; - - this._qualityButton = new ConcreteButton(player); - - const placementIndex = player.controlBar.children().length - 2; - const concreteButtonInstance = player.controlBar.addChild( - this._qualityButton, - { componentClass: 'qualitySelector' }, - this.config.placementIndex || placementIndex - ); - - concreteButtonInstance.addClass('vjs-quality-selector'); - if (!this.config.displayCurrentQuality) { - const icon = ` ${this.config.vjsIconClass || 'vjs-icon-hd'}`; - - concreteButtonInstance.menuButton_.$('.vjs-icon-placeholder').className += icon; - } else { - this.setButtonInnerText('auto'); - } - concreteButtonInstance.removeClass('vjs-hidden'); - } - - /** - *Set inner button text. - * - * @param {string} text - the text to display in the button. - */ - setButtonInnerText(text) { - this._qualityButton.menuButton_.$('.vjs-icon-placeholder').innerHTML = text; - } - - /** - * Builds individual quality menu items. - * - * @param {Object} item - Individual quality menu item. - * @return {ConcreteMenuItem} - Menu item - */ - getQualityMenuItem(item) { - const player = this.player; - - return new ConcreteMenuItem(player, item, this._qualityButton, this); - } - - /** - * Executed when a quality level is added from HLS playlist. - */ - onAddQualityLevel() { - const player = this.player; - const qualityList = player.qualityLevels(); - const levels = qualityList.levels_ || []; - const levelItems = []; - - for (let i = 0; i < levels.length; ++i) { - if ( - !levelItems.filter((_existingItem) => { - return _existingItem.item && _existingItem.item.value === levels[i].height; - }).length - ) { - const levelItem = this.getQualityMenuItem.call(this, { - label: levels[i].height + 'p', - value: levels[i].height, - }); - - levelItems.push(levelItem); - } - } - - levelItems.sort((current, next) => { - if (typeof current !== 'object' || typeof next !== 'object') { - return -1; - } - if (current.item.value < next.item.value) { - return -1; - } - if (current.item.value > next.item.value) { - return 1; - } - return 0; - }); - - levelItems.push( - this.getQualityMenuItem.call(this, { - label: player.localize('Auto'), - value: 'auto', - selected: true, - }) - ); - - if (this._qualityButton) { - this._qualityButton.createItems = function () { - return levelItems; - }; - this._qualityButton.update(); - } - } - - /** - * Sets quality (based on media height) - * - * @param {number} height - A number representing HLS playlist. - */ - setQuality(height) { - const qualityList = this.player.qualityLevels(); - - // Set quality on plugin - this._currentQuality = height; - - if (this.config.displayCurrentQuality) { - this.setButtonInnerText(height === 'auto' ? height : `${height}p`); - } - - for (let i = 0; i < qualityList.length; ++i) { - const quality = qualityList[i]; - - quality.enabled = quality.height === height || height === 'auto'; - } - this._qualityButton.unpressButton(); - } - - /** - * Return the current set quality or 'auto' - * - * @return {string} the currently set quality - */ - getCurrentQuality() { - return this._currentQuality || 'auto'; - } -} - -/** - * Function to invoke when the player is ready. - * - * This is a great place for your plugin to initialize itself. When this - * function is called, the player will have its DOM and child components - * in place. - * - * @function onPlayerReady - * @param {Player} player - * A Video.js player object. - * - * @param {Object} [options={}] - * A plain object containing options for the plugin. - */ -const onPlayerReady = (player, options) => { - player.addClass('vjs-hls-quality-selector'); - player.hlsQualitySelector = new HlsQualitySelectorPlugin(player, options); -}; - -/** - * A video.js plugin. - * - * In the plugin function, the value of `this` is a video.js `Player` - * instance. You cannot rely on the player being in a "ready" state here, - * depending on how the plugin is invoked. This may or may not be important - * to you; if not, remove the wait for "ready"! - * - * @function hlsQualitySelector - * @param {Object} [options={}] - * An object of options left to the plugin author to define. - */ -const hlsQualitySelector = function (options) { - this.ready(() => { - onPlayerReady(this, videojs.mergeOptions(defaults, options)); - }); -}; - -// Register the plugin with video.js. -registerPlugin('hlsQualitySelector', hlsQualitySelector); - -// Include the version number. -hlsQualitySelector.VERSION = VERSION; - -export default hlsQualitySelector; -/* eslint-enable */ diff --git a/ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/plugin.scss b/ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/plugin.scss deleted file mode 100644 index f0e5c7c39..000000000 --- a/ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/plugin.scss +++ /dev/null @@ -1,9 +0,0 @@ -// Sass for videojs-hls-quality-selector - -.video-js { - - // This class is added to the video.js element by the plugin by default. - &.vjs-hls-quality-selector { - display: block; - } -} diff --git a/ui/component/viewers/videoViewer/internal/videojs.jsx b/ui/component/viewers/videoViewer/internal/videojs.jsx index 796b241ec..4f2ef44ef 100644 --- a/ui/component/viewers/videoViewer/internal/videojs.jsx +++ b/ui/component/viewers/videoViewer/internal/videojs.jsx @@ -8,7 +8,7 @@ import 'video.js/dist/alt/video-js-cdn.min.css'; import eventTracking from 'videojs-event-tracking'; import * as OVERLAY from './overlays'; import './plugins/videojs-mobile-ui/plugin'; -import hlsQualitySelector from './plugins/videojs-hls-quality-selector/plugin'; +import qualitySelector from 'videojs-hls-quality-selector'; import qualityLevels from 'videojs-contrib-quality-levels'; import isUserTyping from 'util/detect-typing'; @@ -102,7 +102,7 @@ if (!Object.keys(videojs.getPlugins()).includes('eventTracking')) { } if (!Object.keys(videojs.getPlugins()).includes('hlsQualitySelector')) { - videojs.registerPlugin('hlsQualitySelector', hlsQualitySelector); + videojs.registerPlugin('hlsQualitySelector', qualitySelector); } if (!Object.keys(videojs.getPlugins()).includes('qualityLevels')) { @@ -379,6 +379,11 @@ export default React.memo(function VideoJs(props: Props) { // initialize mobile UI player.mobileUi(); // Inits mobile version. No-op if Desktop. + // Add quality selector to player + player.hlsQualitySelector({ + displayCurrentQuality: true, + }); + // I think this is a callback function onPlayerReady(player); }); @@ -442,17 +447,6 @@ export default React.memo(function VideoJs(props: Props) { src: source, type: type, }); - - // Add quality selector to player - player.hlsQualitySelector({ - displayCurrentQuality: true, - }); - - // Update player source - player.src({ - src: source, - type: type, - }); }); }, [source, reload]); diff --git a/ui/constants/icons.js b/ui/constants/icons.js index df733f879..1b5de2e32 100644 --- a/ui/constants/icons.js +++ b/ui/constants/icons.js @@ -136,3 +136,4 @@ export const CHANNEL_LEVEL_2 = 'ChannelLevel2'; export const CHANNEL_LEVEL_3 = 'ChannelLevel3'; export const CHANNEL_LEVEL_4 = 'ChannelLevel4'; export const CHANNEL_LEVEL_5 = 'ChannelLevel5'; +export const MOVIES = 'Movies'; diff --git a/ui/scss/component/_channel.scss b/ui/scss/component/_channel.scss index 4e4ac9e97..f802fce6d 100644 --- a/ui/scss/component/_channel.scss +++ b/ui/scss/component/_channel.scss @@ -343,7 +343,6 @@ $metadata-z-index: 1; .channel__list-text { font-weight: var(--font-weight-bold); - color: var(--color-text); } .channel__selector { diff --git a/web/index.js b/web/index.js index 46362ccdc..487c09d80 100644 --- a/web/index.js +++ b/web/index.js @@ -6,7 +6,6 @@ const logger = require('koa-logger'); const router = require('./src/routes'); const redirectMiddleware = require('./middleware/redirect'); const cacheControlMiddleware = require('./middleware/cache-control'); -const iframeDestroyerMiddleware = require('./middleware/iframe-destroyer'); const app = new Koa(); const DIST_ROOT = path.resolve(__dirname, 'dist'); @@ -26,7 +25,6 @@ app.use(async (ctx, next) => { app.use(logger()); app.use(cacheControlMiddleware); app.use(redirectMiddleware); -app.use(iframeDestroyerMiddleware); app.use(serve(DIST_ROOT)); // Check if the request url matches any assets inside of /dist app.use(router.routes()); diff --git a/web/middleware/iframe-destroyer.js b/web/middleware/iframe-destroyer.js deleted file mode 100644 index 1737480f3..000000000 --- a/web/middleware/iframe-destroyer.js +++ /dev/null @@ -1,15 +0,0 @@ -const PAGES = require('../../ui/constants/pages'); - -async function iframeDestroyerMiddleware(ctx, next) { - const { - request: { path }, - } = ctx; - - if (!path.startsWith(`/$/${PAGES.EMBED}`)) { - ctx.set('X-Frame-Options', 'DENY'); - } - - return next(); -} - -module.exports = iframeDestroyerMiddleware; diff --git a/yarn.lock b/yarn.lock index 6d5569fa4..681ae0a2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2114,6 +2114,11 @@ any-observable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -5306,6 +5311,17 @@ fs-copy-file-sync@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz#11bf32c096c10d126e5f6b36d06eece776062918" +fs-extra@^0.26.5: + version "0.26.7" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + integrity sha1-muH92UiXeY7at20JGM9C0MMYT6k= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + fs-extra@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -5339,6 +5355,16 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" +fs-promise@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-0.5.0.tgz#4347d6bf624655a7061a4319213c393276ad3ef3" + integrity sha1-Q0fWv2JGVacGGkMZITw5MnatPvM= + dependencies: + any-promise "^1.0.0" + fs-extra "^0.26.5" + mz "^2.3.1" + thenify-all "^1.6.0" + fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -5631,7 +5657,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -6789,7 +6815,7 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" -jsonfile@^2.2.3: +jsonfile@^2.1.0, jsonfile@^2.2.3: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: @@ -6833,6 +6859,14 @@ jszip@~2.5.0: dependencies: pako "~0.2.5" +karma-safaritechpreview-launcher@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/karma-safaritechpreview-launcher/-/karma-safaritechpreview-launcher-0.0.6.tgz#7a841105aeb7053940e33df850edcf220eed906a" + integrity sha512-2QMxAGXPQ37H3KoR9SCdh0OoktQZ5MyrxkvBiZ+VVOQfYVrcyOQXGrPea0/DKvf8qoQvrvP2FHcP/BxsuxuyHw== + dependencies: + fs-promise "^0.5.0" + marcosc-async "^3.0.4" + keycode@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04" @@ -6874,6 +6908,13 @@ kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= + optionalDependencies: + graceful-fs "^4.1.9" + latest-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" @@ -7329,6 +7370,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +marcosc-async@^3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/marcosc-async/-/marcosc-async-3.0.5.tgz#41e6d56c656c811859d34b97a0a26093f71dc360" + integrity sha1-QebVbGVsgRhZ00uXoKJgk/cdw2A= + markdown-escapes@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" @@ -7707,6 +7753,15 @@ mux.js@5.6.7: resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.6.7.tgz#d39fc85cded5a1257de9f6eeb5cf1578c4a63eb8" integrity sha512-YSr6B8MUgE4S18MptbY2XM+JKGbw9JDkgs7YkuE/T2fpDKjOhZfb/nD6vmsVxvLYOExWNaQn1UGBp6PGsnTtew== +mz@^2.3.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nan@^2.12.1: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" @@ -9201,6 +9256,11 @@ react-hot-loader@^4.11.1: shallowequal "^1.1.0" source-map "^0.7.3" +react-image@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/react-image/-/react-image-4.0.3.tgz#6fa722877660b67295298a914bff1ed87ad2cf83" + integrity sha512-19MUK9u1qaw9xys8XEsVkSpVhHctEBUeYFvrLTe1PN+4w5Co13AN2WA7xtBshPM6SthsOj77SlDrEAeOaJpf7g== + react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.2: version "16.13.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" @@ -10780,6 +10840,20 @@ text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +thenify-all@^1.0.0, thenify-all@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + three-full@^17.1.0: version "17.2.0" resolved "https://registry.yarnpkg.com/three-full/-/three-full-17.2.0.tgz#b6086360a9429e733e080093c25d02a3171ba1cc" @@ -11461,7 +11535,7 @@ vfile@^2.0.0: unist-util-stringify-position "^1.0.0" vfile-message "^1.0.0" -"video.js@^6 || ^7", video.js@^7.0.0, video.js@^7.10.1: +"video.js@^6 || ^7", video.js@^7.0.0, video.js@^7.10.1, video.js@^7.5.5: version "7.10.2" resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.10.2.tgz#5156aabad7820e726d72ea6c32324059c68885a4" integrity sha512-kJTTrqcQn2MhPzWR8zQs6W3HPJWpowO/ZGZcKt2dcJeJdJT0dEDLYtiFdjV37SylCmu66V0flRnV8cipbthveQ== @@ -11495,6 +11569,16 @@ videojs-font@3.2.0: resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232" integrity sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA== +videojs-hls-quality-selector@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/videojs-hls-quality-selector/-/videojs-hls-quality-selector-1.1.4.tgz#281b78c6653137b08c544e806aa9c91b71d16989" + integrity sha512-wWAjlLQui02gp//t9KHGd3XnbYO7wdOptskh3ZYCrbl/5Lbkveqb9yBVjH4e0zIQBPvGdWPMcOeDukf8iuYeBw== + dependencies: + global "^4.3.2" + karma-safaritechpreview-launcher "0.0.6" + video.js "^7.5.5" + videojs-contrib-quality-levels "^2.0.9" + videojs-logo@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/videojs-logo/-/videojs-logo-2.1.4.tgz#56675b3f95949910bad3c217835ea57aa6fdf212"