diff --git a/web/package-lock.json b/web/package-lock.json index 494fe116..5dfb7ffe 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -3780,6 +3780,11 @@ "is-symbol": "^1.0.2" } }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "escalade": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz", @@ -4528,6 +4533,15 @@ "readable-stream": "^2.3.6" } }, + "flv.js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/flv.js/-/flv.js-1.5.0.tgz", + "integrity": "sha512-7tFwccqkFXpA7RIED0KvuNny2qVnpuGc5nTGsRpzrCT+qtwIaZyciK5UgyvgtlAMYaPFzYS0wdI92JiSBKOyXw==", + "requires": { + "es6-promise": "^4.2.5", + "webworkify": "^1.5.0" + } + }, "follow-redirects": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", @@ -9335,6 +9349,11 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "webworkify": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/webworkify/-/webworkify-1.5.0.tgz", + "integrity": "sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==" + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/web/package.json b/web/package.json index 3ef90b89..da426e4c 100644 --- a/web/package.json +++ b/web/package.json @@ -54,6 +54,7 @@ "clsx": "^1.1.1", "d3": "^6.2.0", "date-fns": "^2.16.1", + "flv.js": "^1.5.0", "fontsource-roboto": "^2.1.4", "get-user-locale": "^1.4.0", "http-status-codes": "^1.4.0", diff --git a/web/src/collection/components/VideoDetailsPage/VideoPlayer.js b/web/src/collection/components/VideoDetailsPage/VideoPlayer.js index 050185ab..140d68e6 100644 --- a/web/src/collection/components/VideoDetailsPage/VideoPlayer.js +++ b/web/src/collection/components/VideoDetailsPage/VideoPlayer.js @@ -5,6 +5,8 @@ import { makeStyles } from "@material-ui/styles"; import { FileType } from "../FileBrowserPage/FileType"; import MediaPreview from "../../../common/components/MediaPreview"; import ReactPlayer from "react-player"; +import { FLV_GLOBAL } from "react-player/lib/players/FilePlayer"; +import flvjs from "flv.js"; import TimeCaption from "./TimeCaption"; import VideoController from "./VideoController"; import { useServer } from "../../../server-api/context"; @@ -12,6 +14,24 @@ import { Status } from "../../../server-api/Response"; import { useIntl } from "react-intl"; import WarningOutlinedIcon from "@material-ui/icons/WarningOutlined"; +/** + * Setup bundled flv.js. + * + * By default react-player tries to lazy-load playback SDK from CDN. + * But the application must be able play video files when Internet + * connection is not available. To solve that we bundle flv.js and + * initialize global variable consumed by react-player's FilePlayer. + * + * See https://www.npmjs.com/package/react-player#sdk-overrides + * See https://github.com/CookPete/react-player/issues/605#issuecomment-492561909 + */ +function setupBundledFlvJs() { + const FLV_VAR = FLV_GLOBAL || "flvjs"; + if (window[FLV_VAR] == null) { + window[FLV_VAR] = flvjs; + } +} + const useStyles = makeStyles((theme) => ({ container: {}, preview: { @@ -68,6 +88,9 @@ const VideoPlayer = function VideoPlayer(props) { const controller = useMemo(() => new VideoController(player, setWatch), []); const previewActions = useMemo(() => makePreviewActions(handleWatch), []); + // Make sure flv.js is available + useEffect(setupBundledFlvJs, []); + // Provide controller to the consumer useEffect(() => onReady && onReady(controller), [onReady]);