diff --git a/components/previews/VideoPreview.tsx b/components/previews/VideoPreview.tsx index dba650e..4d6dbcf 100644 --- a/components/previews/VideoPreview.tsx +++ b/components/previews/VideoPreview.tsx @@ -1,23 +1,80 @@ import type { OdFileObject } from '../../types' -import { useState } from 'react' + +import { FC, useEffect, useState } from 'react' import { useRouter } from 'next/router' -import { useClipboard } from 'use-clipboard-copy' -import DPlayer from 'react-dplayer' -import toast from 'react-hot-toast' import { useTranslation } from 'next-i18next' + +import axios from 'axios' +import toast from 'react-hot-toast' +import Plyr from 'plyr-react' import { useAsync } from 'react-async-hook' +import { useClipboard } from 'use-clipboard-copy' import { getBaseUrl } from '../../utils/getBaseUrl' import { getExtension } from '../../utils/getFileIcon' import { getReadablePath } from '../../utils/getReadablePath' import { getStoredToken } from '../../utils/protectedRouteHandler' + import { DownloadButton } from '../DownloadBtnGtoup' import { DownloadBtnContainer, PreviewContainer } from './Containers' import FourOhFour from '../FourOhFour' import Loading from '../Loading' import CustomEmbedLinkMenu from '../CustomEmbedLinkMenu' -const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => { +import 'plyr-react/dist/plyr.css' + +const VideoPlayer: FC<{ + videoName: string + videoUrl: string + width?: number + height?: number + thumbnail: string + subtitle: string + isFlv: boolean + mpegts: any +}> = ({ videoName, videoUrl, width, height, thumbnail, subtitle, isFlv, mpegts }) => { + useEffect(() => { + // Really really hacky way to inject subtitles as file blobs into the video element + axios + .get(subtitle, { responseType: 'blob' }) + .then(resp => { + const track = document.querySelector('track') + track?.setAttribute('src', URL.createObjectURL(resp.data)) + }) + .catch(() => { + console.log('Could not load subtitle.') + }) + + if (isFlv) { + const loadFlv = () => { + // Really hacky way to get the exposed video element from Plyr + const video = document.getElementById('plyr') + const flv = mpegts.createPlayer({ url: videoUrl, type: 'flv' }) + flv.attachMediaElement(video) + flv.load() + } + loadFlv() + } + }, [videoUrl, isFlv, mpegts, subtitle]) + + // Common plyr configs, including the video source and plyr options + const plyrSource = { + type: 'video', + title: videoName, + poster: thumbnail, + tracks: [{ kind: 'captions', label: videoName, src: '', default: true }], + } + const plyrOptions: Plyr.Options = { + ratio: `${width ?? 16}:${height ?? 9}`, + } + if (!isFlv) { + // If the video is not in flv format, we can use the native plyr and add sources directly with the video URL + plyrSource['sources'] = [{ src: videoUrl }] + } + return +} + +const VideoPreview: FC<{ file: OdFileObject }> = ({ file }) => { const { asPath } = useRouter() const hashedToken = getStoredToken(asPath) const clipboard = useClipboard() @@ -55,28 +112,15 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => { ) : loading && isFlv ? ( ) : ( - { - const flvPlayer = mpegts!.createPlayer({ - type: 'flv', - url: video.src, - }) - flvPlayer.attachMediaElement(video) - flvPlayer.load() - }, - }, - }, - subtitle: { url: subtitle }, - }} + )} diff --git a/package.json b/package.json index 824b5b5..7e8c2af 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "next": "^12.0.10", "next-i18next": "^10.2.0", "nextjs-progressbar": "^0.0.13", + "plyr-react": "^3.2.1", "preview-office-docs": "^1.0.2", "react": "^17.0.2", "react-async-hook": "^4.0.0", @@ -38,7 +39,6 @@ "react-cookie": "^4.1.1", "react-copy-to-clipboard": "^5.0.3", "react-dom": "^17.0.2", - "react-dplayer": "^0.4.2", "react-hot-toast": "^2.0.0", "react-hotkeys-hook": "^3.4.4", "react-markdown": "^8.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53dc331..57306fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,7 @@ specifiers: next: ^12.0.10 next-i18next: ^10.2.0 nextjs-progressbar: ^0.0.13 + plyr-react: ^3.2.1 postcss: ^8.4.5 prettier: ^2.5.1 prettier-plugin-tailwindcss: ^0.1.4 @@ -44,7 +45,6 @@ specifiers: react-cookie: ^4.1.1 react-copy-to-clipboard: ^5.0.3 react-dom: ^17.0.2 - react-dplayer: ^0.4.2 react-hot-toast: ^2.0.0 react-hotkeys-hook: ^3.4.4 react-markdown: ^8.0.0 @@ -82,6 +82,7 @@ dependencies: next: 12.0.10_react-dom@17.0.2+react@17.0.2 next-i18next: 10.2.0_61390be992b634a688f7c2555547b55b nextjs-progressbar: 0.0.13_next@12.0.10+react@17.0.2 + plyr-react: 3.2.1_react-dom@17.0.2+react@17.0.2 preview-office-docs: 1.0.2_react@17.0.2 react: 17.0.2 react-async-hook: 4.0.0_react@17.0.2 @@ -89,7 +90,6 @@ dependencies: react-cookie: 4.1.1_react@17.0.2 react-copy-to-clipboard: 5.0.4_react@17.0.2 react-dom: 17.0.2_react@17.0.2 - react-dplayer: 0.4.2_react@17.0.2 react-hot-toast: 2.2.0_6bba596ee6fb84e656d75c53902ecf01 react-hotkeys-hook: 3.4.4_react-dom@17.0.2+react@17.0.2 react-markdown: 8.0.0_b08e3c15324cbe90a6ff8fcd416c932c @@ -417,10 +417,6 @@ packages: '@types/ms': 0.7.31 dev: false - /@types/dplayer/1.25.2: - resolution: {integrity: sha512-bkTVZkK3Vi7N7eX2FUBnqKhCjTaeRLkhvY8H6zolatbSTtjPPdxyUzhE3C29sIBYRRq1kQHSduFgCHKg5VF3Jw==} - dev: false - /@types/hast/2.3.4: resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} dependencies: @@ -773,13 +769,6 @@ packages: engines: {node: '>=4'} dev: true - /axios/0.19.2: - resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==} - deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410 - dependencies: - follow-redirects: 1.5.10 - dev: false - /axios/0.25.0: resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} dependencies: @@ -800,10 +789,6 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /balloon-css/1.2.0: - resolution: {integrity: sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==} - dev: false - /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -1000,11 +985,6 @@ packages: readable-stream: 2.3.7 dev: true - /clsx/1.1.1: - resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==} - engines: {node: '>=6'} - dev: false - /cluster-key-slot/1.1.0: resolution: {integrity: sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==} engines: {node: '>=0.10.0'} @@ -1152,6 +1132,10 @@ packages: /csstype/3.0.10: resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==} + /custom-event-polyfill/1.0.7: + resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==} + dev: false + /d/1.0.1: resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} dependencies: @@ -1181,12 +1165,6 @@ packages: ms: 2.0.0 dev: true - /debug/3.1.0: - resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==} - dependencies: - ms: 2.0.0 - dev: false - /debug/3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} dependencies: @@ -1306,14 +1284,6 @@ packages: domhandler: 4.3.0 dev: true - /dplayer/1.26.0: - resolution: {integrity: sha512-uOE0w/WdlX7N9d0ppIEcAYrcnUjY52TMX+MBL4lj9Mj+JMljVuaEc5w88HkZp5Q11VqvN/jxnM8ktx2Dr7/MgA==} - dependencies: - axios: 0.19.2 - balloon-css: 1.2.0 - promise-polyfill: 8.1.3 - dev: false - /duplexify/3.7.1: resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} dependencies: @@ -1804,13 +1774,6 @@ packages: optional: true dev: false - /follow-redirects/1.5.10: - resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==} - engines: {node: '>=4.0'} - dependencies: - debug: 3.1.0 - dev: false - /format/0.2.2: resolution: {integrity: sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=} engines: {node: '>=0.4.x'} @@ -2620,6 +2583,10 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true + /loadjs/4.2.0: + resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==} + dev: false + /localforage/1.10.0: resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} dependencies: @@ -3122,6 +3089,7 @@ packages: /ms/2.0.0: resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} + dev: true /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -3318,10 +3286,6 @@ packages: es-abstract: 1.19.1 dev: true - /omit.js/2.0.2: - resolution: {integrity: sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==} - dev: false - /once/1.4.0: resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} dependencies: @@ -3464,6 +3428,28 @@ packages: engines: {node: '>=8.6'} dev: true + /plyr-react/3.2.1_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-ZXMA+d837mZCkb68oTXso6rH8O+B2+A7t8ux1fdU+kFSUh1NZa1/iuItItFgScmVC6FoO3DNj+FkZP2aikxoKg==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: ^16.13.0 || ^17.0.0 + react-dom: ^16.13.0 || ^17.0.0 + dependencies: + plyr: 3.6.12 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + dev: false + + /plyr/3.6.12: + resolution: {integrity: sha512-42WhYpMS/FEyX2unSEvhYtj1RvJgWvOsjZQFDongOQHA4eVzsyr7b06bzVpinMAOVC9e5H7RCbK+6CCAFIl2VQ==} + dependencies: + core-js: 3.21.0 + custom-event-polyfill: 1.0.7 + loadjs: 4.2.0 + rangetouch: 2.0.1 + url-polyfill: 1.1.12 + dev: false + /postcss-js/4.0.0_postcss@8.4.6: resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} engines: {node: ^12 || ^14 || >= 16} @@ -3572,10 +3558,6 @@ packages: engines: {node: 10.* || >= 12.*} dev: true - /promise-polyfill/8.1.3: - resolution: {integrity: sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==} - dev: false - /prop-types/15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -3630,6 +3612,10 @@ packages: underscore.string: 3.3.6 dev: true + /rangetouch/2.0.1: + resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==} + dev: false + /react-async-hook/4.0.0_react@17.0.2: resolution: {integrity: sha512-97lgjFkOcHCTYSrsKBpsXg3iVWM0LnzedB749iP76sb3/8Ouu4nHIkCLEOrQWHVYqrYxjF05NN6GHoXWFkB3Kw==} engines: {node: '>=8', npm: '>=5'} @@ -3682,18 +3668,6 @@ packages: scheduler: 0.20.2 dev: false - /react-dplayer/0.4.2_react@17.0.2: - resolution: {integrity: sha512-UnI6KaAsnGtP6MSz79lGCAEZko+j0DcKgwfNATtQJL/T/zRs1t3ZJDT/ymbCquuU1e3fADn0Cww1gpNJ3K2TiQ==} - peerDependencies: - react: ^16.x - dependencies: - '@types/dplayer': 1.25.2 - clsx: 1.1.1 - dplayer: 1.26.0 - omit.js: 2.0.2 - react: 17.0.2 - dev: false - /react-hot-toast/2.2.0_6bba596ee6fb84e656d75c53902ecf01: resolution: {integrity: sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==} engines: {node: '>=10'} @@ -4512,6 +4486,10 @@ packages: punycode: 2.1.1 dev: true + /url-polyfill/1.1.12: + resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==} + dev: false + /use-clipboard-copy/0.2.0_react@17.0.2: resolution: {integrity: sha512-f0PMMwZ2/Hh9/54L12capx4s6ASdd6edNJxg2OcqWVNM8BPvtOSmNFIN1Dg/q//fPp8MpUZceHfr7cnWOS0RxA==} peerDependencies: