mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-06-14 17:41:20 +00:00
added videojs
This commit is contained in:
parent
1ba3bfca26
commit
df67a7a2fa
539
package-lock.json
generated
539
package-lock.json
generated
@ -20,9 +20,11 @@
|
||||
"idb-keyval": "^6.2.2",
|
||||
"react-dropzone": "^14.3.8",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-idle-timer": "^5.7.2",
|
||||
"react-intersection-observer": "^9.16.0",
|
||||
"short-unique-id": "^5.2.0",
|
||||
"ts-key-enum": "^3.0.13",
|
||||
"video.js": "^8.23.3",
|
||||
"zustand": "^4.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -42,6 +44,7 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^7.0.1",
|
||||
"@mui/material": "^7.0.1",
|
||||
"mediainfo.js": "^0.3.5",
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
@ -125,7 +128,6 @@
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
||||
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@ -1424,6 +1426,75 @@
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@videojs/http-streaming": {
|
||||
"version": "3.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.17.0.tgz",
|
||||
"integrity": "sha512-Ch1P3tvvIEezeZXyK11UfWgp4cWKX4vIhZ30baN/lRinqdbakZ5hiAI3pGjRy3d+q/Epyc8Csz5xMdKNNGYpcw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.1",
|
||||
"aes-decrypter": "^4.0.2",
|
||||
"global": "^4.4.0",
|
||||
"m3u8-parser": "^7.2.0",
|
||||
"mpd-parser": "^1.3.1",
|
||||
"mux.js": "7.1.0",
|
||||
"video.js": "^7 || ^8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": "^8.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@videojs/vhs-utils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-4.1.1.tgz",
|
||||
"integrity": "sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/@videojs/xhr": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.7.0.tgz",
|
||||
"integrity": "sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"global": "~4.4.0",
|
||||
"is-function": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aes-decrypter": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-4.0.2.tgz",
|
||||
"integrity": "sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.1",
|
||||
"global": "^4.4.0",
|
||||
"pkcs7": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/aggregate-error": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz",
|
||||
@ -1680,6 +1751,100 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cliui/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
@ -1693,7 +1858,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
@ -1704,8 +1868,7 @@
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "4.1.1",
|
||||
@ -1902,6 +2065,11 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-walk": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
|
||||
@ -1971,6 +2139,16 @@
|
||||
"@esbuild/win32-x64": "0.25.2"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
@ -2009,10 +2187,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.4.3",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
|
||||
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
|
||||
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
@ -2090,6 +2269,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
@ -2122,6 +2311,16 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/global": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"min-document": "^2.19.0",
|
||||
"process": "^0.11.10"
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||
@ -2329,11 +2528,16 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-function": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
|
||||
"integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
@ -2480,6 +2684,33 @@
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/m3u8-parser": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-7.2.0.tgz",
|
||||
"integrity": "sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.1.1",
|
||||
"global": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mediainfo.js": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/mediainfo.js/-/mediainfo.js-0.3.5.tgz",
|
||||
"integrity": "sha512-frLJzKOoAUC0sbPzmg9VOR+WFbNj5CarbTuOzXeH9cOl33haU/CGcyXUTWK00HPXCVS2N5eT0o0dirVxaPIOIw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"mediainfo.js": "dist/esm/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/meow": {
|
||||
"version": "12.1.1",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz",
|
||||
@ -2526,6 +2757,14 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/min-document": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
|
||||
"integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
|
||||
"dependencies": {
|
||||
"dom-walk": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
@ -2550,12 +2789,44 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/mpd-parser": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.3.1.tgz",
|
||||
"integrity": "sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/vhs-utils": "^4.0.0",
|
||||
"@xmldom/xmldom": "^0.8.3",
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"mpd-to-m3u8-json": "bin/parse.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mux.js": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.1.0.tgz",
|
||||
"integrity": "sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"muxjs-transmux": "bin/transmux.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
@ -2567,6 +2838,27 @@
|
||||
"thenify-all": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nested-error-stacks": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz",
|
||||
@ -2753,6 +3045,49 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/pkcs7": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz",
|
||||
"integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5"
|
||||
},
|
||||
"bin": {
|
||||
"pkcs7": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
|
||||
"integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-load-config": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
|
||||
@ -2795,6 +3130,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
@ -2891,6 +3235,16 @@
|
||||
"react-dom": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/react-idle-timer": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/react-idle-timer/-/react-idle-timer-5.7.2.tgz",
|
||||
"integrity": "sha512-+BaPfc7XEUU5JFkwZCx6fO1bLVK+RBlFH+iY4X34urvIzZiZINP6v2orePx3E6pAztJGE7t4DzvL7if2SL/0GQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16",
|
||||
"react-dom": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/react-intersection-observer": {
|
||||
"version": "9.16.0",
|
||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz",
|
||||
@ -2948,8 +3302,17 @@
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
@ -3129,6 +3492,18 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
@ -3293,12 +3668,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz",
|
||||
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
|
||||
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.3",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@ -3427,6 +3803,57 @@
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/video.js": {
|
||||
"version": "8.23.3",
|
||||
"resolved": "https://registry.npmjs.org/video.js/-/video.js-8.23.3.tgz",
|
||||
"integrity": "sha512-Toe0VLlDZcUhiaWfcePS1OEdT3ATfktm0hk/PELfD7zUoPDHeT+cJf/wZmCy5M5eGVwtGUg25RWPCj1L/1XufA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@videojs/http-streaming": "^3.17.0",
|
||||
"@videojs/vhs-utils": "^4.1.1",
|
||||
"@videojs/xhr": "2.7.0",
|
||||
"aes-decrypter": "^4.0.2",
|
||||
"global": "4.4.0",
|
||||
"m3u8-parser": "^7.2.0",
|
||||
"mpd-parser": "^1.3.1",
|
||||
"mux.js": "^7.0.1",
|
||||
"videojs-contrib-quality-levels": "4.1.0",
|
||||
"videojs-font": "4.2.0",
|
||||
"videojs-vtt.js": "0.15.5"
|
||||
}
|
||||
},
|
||||
"node_modules/videojs-contrib-quality-levels": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.1.0.tgz",
|
||||
"integrity": "sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"global": "^4.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16",
|
||||
"npm": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"video.js": "^8"
|
||||
}
|
||||
},
|
||||
"node_modules/videojs-font": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-4.2.0.tgz",
|
||||
"integrity": "sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/videojs-vtt.js": {
|
||||
"version": "0.15.5",
|
||||
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz",
|
||||
"integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"global": "^4.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
|
||||
@ -3558,6 +3985,90 @@
|
||||
"cuint": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/yargs/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "4.5.6",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz",
|
||||
|
@ -34,9 +34,11 @@
|
||||
"idb-keyval": "^6.2.2",
|
||||
"react-dropzone": "^14.3.8",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
"react-idle-timer": "^5.7.2",
|
||||
"react-intersection-observer": "^9.16.0",
|
||||
"short-unique-id": "^5.2.0",
|
||||
"ts-key-enum": "^3.0.13",
|
||||
"video.js": "^8.23.3",
|
||||
"zustand": "^4.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -44,6 +46,7 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^7.0.1",
|
||||
"@mui/material": "^7.0.1",
|
||||
"mediainfo.js": "^0.3.5",
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
14
src/common/useIdleTimeout.ts
Normal file
14
src/common/useIdleTimeout.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useIdleTimer } from "react-idle-timer";
|
||||
|
||||
const useIdleTimeout = ({ onIdle, onActive, idleTime = 10_000 }: any) => {
|
||||
const idleTimer = useIdleTimer({
|
||||
timeout: idleTime,
|
||||
onIdle: onIdle,
|
||||
onActive: onActive,
|
||||
});
|
||||
return {
|
||||
idleTimer,
|
||||
};
|
||||
};
|
||||
export default useIdleTimeout;
|
@ -160,7 +160,7 @@ const addItems = useListStore((s) => s.addItems);
|
||||
|
||||
|
||||
|
||||
const searchIntervalRef = useRef<null | number>(null)
|
||||
const searchIntervalRef = useRef<any>(null)
|
||||
const lastItemTimestampRef = useRef<null | number>(null)
|
||||
const stringifiedEntityParams = useMemo(()=> {
|
||||
if(!entityParams) return null
|
||||
|
@ -19,6 +19,7 @@ export const LoadingVideo = ({
|
||||
const progress = percentLoaded;
|
||||
return Number.isNaN(progress) ? "" : progress.toFixed(0) + "%";
|
||||
};
|
||||
if(status === 'READY') return null
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Box, IconButton, Slider, Typography } from "@mui/material";
|
||||
import { Box, IconButton, Popper, Slider, Typography } from "@mui/material";
|
||||
export const fontSizeExSmall = "60%";
|
||||
export const fontSizeSmall = "80%";
|
||||
import AspectRatioIcon from "@mui/icons-material/AspectRatio";
|
||||
@ -13,6 +13,7 @@ import {
|
||||
} from "@mui/icons-material";
|
||||
import { formatTime } from "../../utils/time.js";
|
||||
import { CustomFontTooltip } from "./CustomFontTooltip.js";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
const buttonPaddingBig = "6px";
|
||||
const buttonPaddingSmall = "4px";
|
||||
@ -49,36 +50,183 @@ export const ReloadButton = ({reloadVideo, isScreenSmall}: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ProgressSlider = ({progress, duration, videoRef}: any) => {
|
||||
const onProgressChange = async (_: any, value: number | number[]) => {
|
||||
if (!videoRef.current) return;
|
||||
videoRef.current.currentTime = value as number;
|
||||
};
|
||||
return (
|
||||
<Slider
|
||||
value={progress}
|
||||
onChange={onProgressChange}
|
||||
min={0}
|
||||
max={duration || 100}
|
||||
step={0.1}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: "42px",
|
||||
color: "#00abff",
|
||||
padding: "0px",
|
||||
// prevents the slider from jumping up 20px in certain mobile conditions
|
||||
"@media (pointer: coarse)": { padding: "0px" },
|
||||
export const ProgressSlider = ({progress, duration, playerRef, extractFrames}: any) => {
|
||||
const sliderRef = useRef(null);
|
||||
|
||||
"& .MuiSlider-thumb": {
|
||||
backgroundColor: "#fff",
|
||||
width: "16px",
|
||||
height: "16px",
|
||||
},
|
||||
"& .MuiSlider-thumb::after": { width: "20px", height: "20px" },
|
||||
"& .MuiSlider-rail": { opacity: 0.5, height: "6px" },
|
||||
"& .MuiSlider-track": { height: "6px", border: "0px" },
|
||||
}}
|
||||
/>
|
||||
const [hoverX, setHoverX] = useState<number | null>(null);
|
||||
const [thumbnailUrl, setThumbnailUrl] = useState<string | null>(null);
|
||||
const [showDuration, setShowDuration] = useState(0)
|
||||
const onProgressChange = (_: any, value: number | number[]) => {
|
||||
if (!playerRef.current) return;
|
||||
playerRef.current.currentTime(value as number);
|
||||
};
|
||||
|
||||
const THUMBNAIL_DEBOUNCE = 500;
|
||||
const THUMBNAIL_MIN_DIFF = 10;
|
||||
|
||||
const lastRequestedTimeRef = useRef<number | null>(null);
|
||||
const debounceTimeoutRef = useRef<any>(null);
|
||||
const previousBlobUrlRef = useRef<string | null>(null);
|
||||
|
||||
const debouncedExtract = useCallback(
|
||||
(time: number, clientX: number) => {
|
||||
const last = lastRequestedTimeRef.current;
|
||||
console.log('hello101')
|
||||
console.log('last', last)
|
||||
if (last !== null && Math.abs(time - last) < THUMBNAIL_MIN_DIFF) return;
|
||||
lastRequestedTimeRef.current = time;
|
||||
console.log('hello102')
|
||||
|
||||
extractFrames(time).then((blobUrl: string | null) => {
|
||||
console.log('blobUrl', blobUrl)
|
||||
if (!blobUrl) return;
|
||||
|
||||
// Clean up previous blob URL
|
||||
if (previousBlobUrlRef.current) {
|
||||
URL.revokeObjectURL(previousBlobUrlRef.current);
|
||||
}
|
||||
|
||||
previousBlobUrlRef.current = blobUrl;
|
||||
setThumbnailUrl(blobUrl);
|
||||
|
||||
});
|
||||
},
|
||||
[extractFrames]
|
||||
);
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent) => {
|
||||
const slider = sliderRef.current;
|
||||
if (!slider) return;
|
||||
|
||||
const rect = slider.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left;
|
||||
const percent = x / rect.width;
|
||||
const time = Math.min(Math.max(0, percent * duration), duration);
|
||||
console.log('hello100')
|
||||
setHoverX(e.clientX);
|
||||
|
||||
setShowDuration(time)
|
||||
if (debounceTimeoutRef.current) clearTimeout(debounceTimeoutRef.current);
|
||||
|
||||
// debounceTimeoutRef.current = setTimeout(() => {
|
||||
// debouncedExtract(time, e.clientX);
|
||||
// }, THUMBNAIL_DEBOUNCE);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
lastRequestedTimeRef.current = null;
|
||||
setThumbnailUrl(null);
|
||||
setHoverX(null);
|
||||
if (debounceTimeoutRef.current) clearTimeout(debounceTimeoutRef.current);
|
||||
|
||||
if (previousBlobUrlRef.current) {
|
||||
URL.revokeObjectURL(previousBlobUrlRef.current);
|
||||
previousBlobUrlRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Clean up on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (previousBlobUrlRef.current) {
|
||||
URL.revokeObjectURL(previousBlobUrlRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const hoverAnchorRef = useRef<HTMLDivElement | null>(null);
|
||||
if(hoverX){
|
||||
console.log('thumbnailUrl', thumbnailUrl, hoverX)
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<Box position="relative" sx={{
|
||||
width: '100%',
|
||||
padding: '0px 10px'
|
||||
}}>
|
||||
<Box
|
||||
ref={hoverAnchorRef}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: hoverX ?? -9999,
|
||||
top: 0,
|
||||
width: '1px',
|
||||
height: '1px',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
<Slider
|
||||
ref={sliderRef}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
value={progress}
|
||||
onChange={onProgressChange}
|
||||
min={0}
|
||||
max={duration || 100}
|
||||
step={0.1}
|
||||
sx={{
|
||||
|
||||
color: "#00abff",
|
||||
padding: "0px",
|
||||
borderRadius: '0px',
|
||||
height: '0px',
|
||||
"@media (pointer: coarse)": { padding: "0px" },
|
||||
"& .MuiSlider-thumb": {
|
||||
backgroundColor: "red",
|
||||
width: "14px",
|
||||
height: "14px",
|
||||
},
|
||||
"& .MuiSlider-thumb::after": { width: "14px", height: "14px", backgroundColor: 'red' },
|
||||
"& .MuiSlider-rail": { opacity: 0.5, height: "6px", backgroundColor: '#73859f80' },
|
||||
"& .MuiSlider-track": { height: "6px", border: "0px" , backgroundColor: 'red'},
|
||||
}}
|
||||
/>
|
||||
{hoverX !== null && (
|
||||
<Popper
|
||||
open
|
||||
anchorEl={hoverAnchorRef.current} placement="top"
|
||||
|
||||
|
||||
disablePortal
|
||||
modifiers={[{ name: "offset", options: { offset: [-20, 0] } }]}
|
||||
>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
{/* <Box
|
||||
sx={{
|
||||
width: 250,
|
||||
height: 125,
|
||||
backgroundColor: "black",
|
||||
border: "1px solid white",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: '7px',
|
||||
background: '#444444',
|
||||
padding: '2px'
|
||||
}}
|
||||
>
|
||||
|
||||
<img
|
||||
src={thumbnailUrl}
|
||||
alt="preview"
|
||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||||
/>
|
||||
</Box> */}
|
||||
<Typography sx={{
|
||||
fontSize: '0.8rom',
|
||||
textShadow: '0 0 5px rgba(0, 0, 0, 0.7)'
|
||||
|
||||
}}>{formatTime(showDuration)}</Typography>
|
||||
</Box>
|
||||
</Popper>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -26,9 +26,15 @@ interface VideoControlsBarProps {
|
||||
reloadVideo: ()=> void;
|
||||
volume: number
|
||||
onVolumeChange: (_: any, val: number)=> void
|
||||
toggleFullscreen: ()=> void
|
||||
extractFrames: (time: number)=> void
|
||||
showControls: boolean;
|
||||
showControlsFullScreen: boolean;
|
||||
isFullScreen: boolean;
|
||||
playerRef: any
|
||||
}
|
||||
|
||||
export const VideoControlsBar = ({reloadVideo, onVolumeChange, volume, isPlaying, canPlay, isScreenSmall, controlsHeight, videoRef, duration, progress, togglePlay}: VideoControlsBarProps) => {
|
||||
export const VideoControlsBar = ({showControls, isFullScreen, showControlsFullScreen, reloadVideo, onVolumeChange, volume, isPlaying, canPlay, isScreenSmall, controlsHeight, videoRef, playerRef, duration, progress, togglePlay, toggleFullscreen, extractFrames}: VideoControlsBarProps) => {
|
||||
|
||||
const showMobileControls = isScreenSmall && canPlay;
|
||||
|
||||
@ -39,23 +45,46 @@ export const VideoControlsBar = ({reloadVideo, onVolumeChange, volume, isPlaying
|
||||
height: controlsHeight,
|
||||
};
|
||||
|
||||
let additionalStyles: React.CSSProperties = {}
|
||||
if(isFullScreen && showControlsFullScreen){
|
||||
additionalStyles = {
|
||||
opacity: 1,
|
||||
position: 'fixed',
|
||||
bottom: 0
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ControlsContainer
|
||||
style={{
|
||||
padding: "0px",
|
||||
height: controlsHeight,
|
||||
opacity: showControls ? 1 : 0,
|
||||
pointerEvents: showControls ? 'auto' : 'none',
|
||||
transition: 'opacity 0.4s ease-in-out',
|
||||
// ...additionalStyles
|
||||
// height: controlsHeight,
|
||||
}}
|
||||
>
|
||||
{showMobileControls ? (
|
||||
null
|
||||
// <MobileControlsBar />
|
||||
) : canPlay ? (
|
||||
<>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%'
|
||||
}}>
|
||||
|
||||
<ProgressSlider extractFrames={extractFrames} playerRef={playerRef} progress={progress} duration={duration} />
|
||||
<Box sx={{
|
||||
width: '100%',
|
||||
display: 'flex'
|
||||
}}>
|
||||
<Box sx={controlGroupSX}>
|
||||
<PlayButton isPlaying={isPlaying} togglePlay={togglePlay}/>
|
||||
<ReloadButton reloadVideo={reloadVideo} />
|
||||
|
||||
<ProgressSlider videoRef={videoRef} progress={progress} duration={duration} />
|
||||
|
||||
|
||||
<VolumeControl onVolumeChange={onVolumeChange} volume={volume} sliderWidth={"100px"} />
|
||||
<VideoTime videoRef={videoRef} progress={progress}/>
|
||||
@ -65,9 +94,10 @@ export const VideoControlsBar = ({reloadVideo, onVolumeChange, volume, isPlaying
|
||||
<PlaybackRate />
|
||||
<ObjectFitButton />
|
||||
<PictureInPictureButton />
|
||||
<FullscreenButton />
|
||||
<FullscreenButton toggleFullscreen={toggleFullscreen} />
|
||||
</Box>
|
||||
</>
|
||||
</Box>
|
||||
</Box>
|
||||
) : null}
|
||||
</ControlsContainer>
|
||||
);
|
||||
|
@ -11,19 +11,33 @@ export const VideoContainer = styled(Box)(({ theme }) => ({
|
||||
height: "100%",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
borderRadius: '12px',
|
||||
overflow: 'hidden',
|
||||
"&:focus": { outline: "none" },
|
||||
}));
|
||||
|
||||
export const VideoElement = styled("video")(({ theme }) => ({
|
||||
width: "100%",
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
background: "rgb(33, 33, 33)",
|
||||
"&:focus": { outline: "none" },
|
||||
"&::-webkit-media-controls": {
|
||||
display:"none !important"
|
||||
},
|
||||
"&:fullscreen": {
|
||||
paddingBottom: '50px'
|
||||
}
|
||||
}));
|
||||
//1075 x 604
|
||||
export const ControlsContainer = styled(Box)`
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
background-image: linear-gradient(0deg,#000,#0000);
|
||||
`;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Ref, RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { ReactEventHandler, Ref, RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { QortalGetMetadata } from "../../types/interfaces/resources";
|
||||
import { VideoContainer, VideoElement } from "./VideoPlayer-styles";
|
||||
import { useVideoPlayerHotKeys } from "./useVideoPlayerHotKeys";
|
||||
@ -6,14 +6,19 @@ import { useProgressStore, useVideoStore } from "../../state/video";
|
||||
import { useVideoPlayerController } from "./useVideoPlayerController";
|
||||
import { LoadingVideo } from "./LoadingVideo";
|
||||
import { VideoControlsBar } from "./VideoControlsBar";
|
||||
import videojs from 'video.js';
|
||||
import 'video.js/dist/video-js.css';
|
||||
|
||||
import Player from "video.js/dist/types/player";
|
||||
|
||||
|
||||
type StretchVideoType = "contain" | "fill" | "cover" | "none" | "scale-down";
|
||||
|
||||
export interface VideoPlayerProps {
|
||||
|
||||
interface VideoPlayerProps {
|
||||
qortalVideoResource: QortalGetMetadata;
|
||||
videoRef: Ref<HTMLVideoElement>;
|
||||
retryAttempts?: number;
|
||||
showControls?: boolean;
|
||||
poster?: string;
|
||||
autoPlay?: boolean;
|
||||
onEnded?: (e: React.SyntheticEvent<HTMLVideoElement, Event>) => void;
|
||||
@ -27,7 +32,6 @@ export const VideoPlayer = ({
|
||||
videoRef,
|
||||
qortalVideoResource,
|
||||
retryAttempts,
|
||||
showControls,
|
||||
poster,
|
||||
autoPlay,
|
||||
onEnded,
|
||||
@ -39,14 +43,15 @@ export const VideoPlayer = ({
|
||||
volume: state.playbackSettings.volume,
|
||||
setVolume: state.setVolume,
|
||||
}));
|
||||
const playerRef = useRef<Player | null>(null);
|
||||
|
||||
const [videoCodec, setVideoCodec] = useState<null | false | string>(null)
|
||||
const [isMuted, setIsMuted] = useState(false);
|
||||
const { setProgress } = useProgressStore();
|
||||
const [localProgress, setLocalProgress] = useState(0)
|
||||
const [duration, setDuration] = useState(0)
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
|
||||
const [showControls, setShowControls] = useState(false)
|
||||
const {
|
||||
reloadVideo,
|
||||
togglePlay,
|
||||
@ -54,8 +59,6 @@ export const VideoPlayer = ({
|
||||
increaseSpeed,
|
||||
decreaseSpeed,
|
||||
toggleMute,
|
||||
showControlsFullScreen,
|
||||
setShowControlsFullScreen,
|
||||
isFullscreen,
|
||||
toggleObjectFit,
|
||||
controlsHeight,
|
||||
@ -68,7 +71,8 @@ export const VideoPlayer = ({
|
||||
startPlay,
|
||||
setProgressAbsolute,
|
||||
setAlwaysShowControls,
|
||||
status, percentLoaded
|
||||
status, percentLoaded,
|
||||
showControlsFullScreen
|
||||
} = useVideoPlayerController({
|
||||
autoPlay,
|
||||
videoRef,
|
||||
@ -105,6 +109,13 @@ export const VideoPlayer = ({
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const videoLocation = useMemo(() => {
|
||||
if (!qortalVideoResource) return null;
|
||||
return `${qortalVideoResource.service}-${qortalVideoResource.name}-${qortalVideoResource.identifier}`;
|
||||
@ -145,29 +156,26 @@ export const VideoPlayer = ({
|
||||
[setIsMuted, setVolume]
|
||||
);
|
||||
|
||||
const handleMouseEnter = useCallback(() => {
|
||||
setShowControlsFullScreen(true);
|
||||
}, [setShowControlsFullScreen]);
|
||||
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
setShowControlsFullScreen(false);
|
||||
}, [setShowControlsFullScreen]);
|
||||
|
||||
const videoStylesContainer = useMemo(() => {
|
||||
return {
|
||||
cursor: !showControlsFullScreen && isFullscreen ? "none" : "auto",
|
||||
cursor: !showControls && isFullscreen ? "none" : "auto",
|
||||
...videoStyles?.videoContainer,
|
||||
};
|
||||
}, [showControlsFullScreen, isFullscreen]);
|
||||
}, [showControls, isFullscreen]);
|
||||
|
||||
console.log('isFullscreen', isFullscreen, showControlsFullScreen)
|
||||
|
||||
const videoStylesVideo = useMemo(() => {
|
||||
return {
|
||||
...videoStyles?.video,
|
||||
objectFit: videoObjectFit,
|
||||
backgroundColor: "#000000",
|
||||
height: isFullscreen && showControls ? "calc(100vh - 40px)" : "100%",
|
||||
height: isFullscreen ? "calc(100vh - 40px)" : "100%",
|
||||
width: '100%'
|
||||
};
|
||||
}, [videoObjectFit, showControls, isFullscreen]);
|
||||
}, [videoObjectFit, isFullscreen]);
|
||||
|
||||
const handleEnded = useCallback(
|
||||
(e: React.SyntheticEvent<HTMLVideoElement, Event>) => {
|
||||
@ -201,20 +209,156 @@ export const VideoPlayer = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
const enterFullscreen = () => {
|
||||
const ref = containerRef?.current as any;
|
||||
console.log('refffff', ref)
|
||||
if (!ref) return;
|
||||
|
||||
if (ref.requestFullscreen && !isFullscreen) {
|
||||
console.log('requset ')
|
||||
ref.requestFullscreen();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
const exitFullscreen = () => {
|
||||
if (isFullscreen) document.exitFullscreen();
|
||||
};
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
isFullscreen ? exitFullscreen() : enterFullscreen();
|
||||
};
|
||||
|
||||
const canvasRef = useRef(null)
|
||||
const videoRefForCanvas = useRef<any>(null)
|
||||
const extractFrames = useCallback(async (time: number): Promise<string | null> => {
|
||||
const video = videoRefForCanvas?.current;
|
||||
const canvas: any = canvasRef.current;
|
||||
|
||||
if (!video || !canvas) return null;
|
||||
|
||||
// Avoid unnecessary resize if already correct
|
||||
if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
}
|
||||
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) return null;
|
||||
|
||||
// If video is already near the correct time, don't seek again
|
||||
const threshold = 0.01; // 10ms threshold
|
||||
if (Math.abs(video.currentTime - time) > threshold) {
|
||||
await new Promise<void>((resolve) => {
|
||||
const onSeeked = () => resolve();
|
||||
video.addEventListener("seeked", onSeeked, { once: true });
|
||||
video.currentTime = time;
|
||||
});
|
||||
}
|
||||
|
||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Use a faster method for image export (optional tradeoff)
|
||||
const blob = await new Promise<Blob | null>((resolve) => {
|
||||
canvas.toBlob((blob: any) => resolve(blob), "image/webp", 0.7);
|
||||
});
|
||||
|
||||
if (!blob) return null;
|
||||
|
||||
return URL.createObjectURL(blob);
|
||||
}, []);
|
||||
|
||||
|
||||
const hideTimeout = useRef<any>(null);
|
||||
|
||||
|
||||
const resetHideTimer = () => {
|
||||
setShowControls(true);
|
||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
setShowControls(false);
|
||||
}, 2500); // 3s of inactivity
|
||||
};
|
||||
|
||||
const handleMouseMove = () => {
|
||||
resetHideTimer();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
resetHideTimer(); // initial show
|
||||
return () => {
|
||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
setShowControls(false);
|
||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||
}, [setShowControls]);
|
||||
|
||||
const onLoadedMetadata= (e: any)=> {
|
||||
console.log('eeeeeeeeeee', e)
|
||||
const ref = videoRef as any;
|
||||
if (!ref.current) return;
|
||||
console.log('datataa', ref.current.audioTracks , // List of available audio tracks
|
||||
ref.current.textTracks , // Subtitles/closed captions
|
||||
ref.current.videoTracks )
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if(!resourceUrl || !isReady) return
|
||||
const options = {
|
||||
autoplay: true,
|
||||
controls: false,
|
||||
responsive: true,
|
||||
fluid: true,
|
||||
poster: startPlay ? "" : poster,
|
||||
sources: [
|
||||
{
|
||||
src: resourceUrl,
|
||||
type: 'video/mp4'
|
||||
},
|
||||
],
|
||||
};
|
||||
const ref = videoRef as any;
|
||||
if (!ref.current) return;
|
||||
// Only initialize once
|
||||
if (!playerRef.current && ref.current) {
|
||||
playerRef.current = videojs(ref.current, options, () => {
|
||||
playerRef.current?.poster('');
|
||||
if (playerRef.current){
|
||||
playerRef.current.play()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (playerRef.current) {
|
||||
playerRef.current.dispose();
|
||||
playerRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [isReady, resourceUrl]);
|
||||
|
||||
return (
|
||||
<VideoContainer
|
||||
tabIndex={0}
|
||||
style={videoStylesContainer}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
ref={containerRef}
|
||||
>
|
||||
<LoadingVideo togglePlay={togglePlay} isReady={isReady} status={status} percentLoaded={percentLoaded} isLoading={isLoading} />
|
||||
<VideoElement
|
||||
id={qortalVideoResource?.identifier}
|
||||
ref={videoRef}
|
||||
tabIndex={0}
|
||||
src={isReady && startPlay ? resourceUrl || undefined : undefined}
|
||||
className="video-js"
|
||||
|
||||
// src={isReady && startPlay ? resourceUrl || undefined : undefined}
|
||||
poster={startPlay ? "" : poster}
|
||||
onTimeUpdate={updateProgress}
|
||||
autoPlay={autoPlay}
|
||||
@ -226,8 +370,18 @@ export const VideoPlayer = ({
|
||||
onPlay={onPlay}
|
||||
onPause={onPause}
|
||||
onVolumeChange={onVolumeChangeHandler}
|
||||
controls={false}
|
||||
onLoadedMetadata={onLoadedMetadata}
|
||||
|
||||
/>
|
||||
<VideoControlsBar onVolumeChange={onVolumeChange} volume={volume} togglePlay={togglePlay} reloadVideo={hotkeyHandlers.reloadVideo} isPlaying={isPlaying} canPlay={true} isScreenSmall={false} controlsHeight={controlsHeight} videoRef={videoRef} duration={duration} progress={localProgress} />
|
||||
<canvas ref={canvasRef} style={{ display: "none" }}></canvas>
|
||||
<video src={isReady && startPlay ? resourceUrl || undefined : undefined} ref={videoRefForCanvas} style={{ display: "none" }}></video>
|
||||
|
||||
{isReady && (
|
||||
<VideoControlsBar playerRef={playerRef} isFullScreen={isFullscreen} showControlsFullScreen={showControlsFullScreen} showControls={showControls} extractFrames={extractFrames} toggleFullscreen={toggleFullscreen} onVolumeChange={onVolumeChange} volume={volume} togglePlay={togglePlay} reloadVideo={hotkeyHandlers.reloadVideo} isPlaying={isPlaying} canPlay={true} isScreenSmall={false} controlsHeight={controlsHeight} videoRef={videoRef} duration={duration} progress={localProgress} />
|
||||
)}
|
||||
|
||||
|
||||
</VideoContainer>
|
||||
);
|
||||
};
|
||||
|
@ -8,11 +8,10 @@ import {
|
||||
useRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { Key } from "ts-key-enum";
|
||||
import { useProgressStore, useVideoStore } from "../../state/video";
|
||||
import { VideoPlayerProps } from "./VideoPlayer";
|
||||
import { QortalGetMetadata } from "../../types/interfaces/resources";
|
||||
import { useResourceStatus } from "../../hooks/useResourceStatus";
|
||||
import useIdleTimeout from "../../common/useIdleTimeout";
|
||||
|
||||
const controlsHeight = "42px";
|
||||
const minSpeed = 0.25;
|
||||
@ -30,10 +29,10 @@ export const useVideoPlayerController = (props: UseVideoControls) => {
|
||||
const { autoPlay, videoRef, qortalVideoResource, retryAttempts } = props;
|
||||
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
const [showControlsFullScreen, setShowControlsFullScreen] = useState(false)
|
||||
const [videoObjectFit, setVideoObjectFit] = useState<"contain" | "fill">(
|
||||
"contain"
|
||||
);
|
||||
const [showControlsFullScreen, setShowControlsFullScreen] = useState(true);
|
||||
const [alwaysShowControls, setAlwaysShowControls] = useState(false);
|
||||
const [startPlay, setStartPlay] = useState(false);
|
||||
const [startedFetch, setStartedFetch] = useState(false);
|
||||
@ -47,6 +46,12 @@ export const useVideoPlayerController = (props: UseVideoControls) => {
|
||||
retryAttempts,
|
||||
});
|
||||
|
||||
const idleTime = 5000; // Time in milliseconds
|
||||
useIdleTimeout({
|
||||
onIdle: () => (setShowControlsFullScreen(false)),
|
||||
onActive: () => (setShowControlsFullScreen(true)),
|
||||
idleTime,
|
||||
});
|
||||
|
||||
|
||||
const videoLocation = useMemo(() => {
|
||||
@ -213,7 +218,6 @@ export const useVideoPlayerController = (props: UseVideoControls) => {
|
||||
increaseSpeed,
|
||||
decreaseSpeed,
|
||||
toggleMute,
|
||||
showControlsFullScreen,
|
||||
isFullscreen,
|
||||
toggleObjectFit,
|
||||
controlsHeight,
|
||||
@ -221,12 +225,11 @@ export const useVideoPlayerController = (props: UseVideoControls) => {
|
||||
toggleAlwaysShowControls,
|
||||
changeVolume,
|
||||
setProgressAbsolute,
|
||||
setShowControlsFullScreen,
|
||||
setAlwaysShowControls,
|
||||
startedFetch,
|
||||
isReady,
|
||||
resourceUrl,
|
||||
startPlay,
|
||||
status, percentLoaded
|
||||
status, percentLoaded, showControlsFullScreen
|
||||
};
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
interface UseVideoControls {
|
||||
reloadVideo: () => void;
|
||||
@ -31,15 +30,15 @@ export const useVideoPlayerHotKeys = (props: UseVideoControls) => {
|
||||
|
||||
const handleKeyDown = useCallback((e: KeyboardEvent) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const tag = target.tagName.toUpperCase();
|
||||
const role = target.getAttribute("role");
|
||||
const isTypingOrInteractive =
|
||||
["INPUT", "TEXTAREA", "SELECT", "BUTTON"].includes(tag) ||
|
||||
target.isContentEditable ||
|
||||
role === "button";
|
||||
const tag = target.tagName.toUpperCase();
|
||||
const role = target.getAttribute("role");
|
||||
const isTypingOrInteractive =
|
||||
["INPUT", "TEXTAREA", "SELECT", "BUTTON"].includes(tag) ||
|
||||
target.isContentEditable ||
|
||||
role === "button";
|
||||
|
||||
if (isTypingOrInteractive) return;
|
||||
e.preventDefault()
|
||||
e.preventDefault();
|
||||
const key = e.key;
|
||||
const mod = (s: number) => setProgressRelative(s);
|
||||
|
||||
@ -50,32 +49,30 @@ const isTypingOrInteractive =
|
||||
case "c":
|
||||
toggleAlwaysShowControls();
|
||||
break;
|
||||
case Key.Add:
|
||||
case "+":
|
||||
case ">":
|
||||
increaseSpeed(false);
|
||||
break;
|
||||
case Key.Subtract:
|
||||
case "-":
|
||||
case "<":
|
||||
decreaseSpeed();
|
||||
break;
|
||||
case Key.ArrowLeft:
|
||||
case "ArrowLeft":
|
||||
if (e.shiftKey) mod(-300);
|
||||
else if (e.ctrlKey) mod(-60);
|
||||
else if (e.altKey) mod(-10);
|
||||
else mod(-5);
|
||||
break;
|
||||
case Key.ArrowRight:
|
||||
case "ArrowRight":
|
||||
if (e.shiftKey) mod(300);
|
||||
else if (e.ctrlKey) mod(60);
|
||||
else if (e.altKey) mod(10);
|
||||
else mod(5);
|
||||
break;
|
||||
case Key.ArrowDown:
|
||||
case "ArrowDown":
|
||||
changeVolume(-0.05);
|
||||
break;
|
||||
case Key.ArrowUp:
|
||||
case "ArrowUp":
|
||||
changeVolume(0.05);
|
||||
break;
|
||||
case " ":
|
||||
@ -139,6 +136,5 @@ const isTypingOrInteractive =
|
||||
};
|
||||
}, [handleKeyDown]);
|
||||
|
||||
// Optional: return if you still want manual use
|
||||
return null
|
||||
return null;
|
||||
};
|
||||
|
@ -12,8 +12,8 @@ export const useResourceStatus = ({
|
||||
}: PropsUseResourceStatus) => {
|
||||
const resourceId = !resource ? null : `${resource.service}-${resource.name}-${resource.identifier}`;
|
||||
const status = usePublishStore((state)=> state.getResourceStatus(resourceId)) || null
|
||||
const intervalRef = useRef<null | number>(null)
|
||||
const timeoutRef = useRef<null | number>(null)
|
||||
const intervalRef = useRef<any>(null)
|
||||
const timeoutRef = useRef<any>(null)
|
||||
const setResourceStatus = usePublishStore((state) => state.setResourceStatus);
|
||||
const statusRef = useRef<ResourceStatus | null>(null)
|
||||
|
||||
|
@ -4,4 +4,5 @@
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
|
||||
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
@ -10,5 +10,6 @@ export default defineConfig({
|
||||
'@mui/system',
|
||||
'@emotion/react',
|
||||
'@emotion/styled',
|
||||
'mediainfo.js'
|
||||
],
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user