diff --git a/docs/docs/contributing.md b/docs/docs/contributing.md index 651c15231..cfd70ad66 100644 --- a/docs/docs/contributing.md +++ b/docs/docs/contributing.md @@ -162,7 +162,7 @@ npm run test #### 1. Installation ```console -npm run install +npm install ``` #### 2. Local Development diff --git a/web/package-lock.json b/web/package-lock.json index 39a881299..c4709b7a0 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -2942,6 +2942,25 @@ "minimist": "^1.2.0" } }, + "@cycjimmy/awesome-js-funcs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cycjimmy/awesome-js-funcs/-/awesome-js-funcs-2.5.0.tgz", + "integrity": "sha512-xy4MkuL8FcmRfWm0FwdHUCWB+EQ/ljCuTAf6d3SdaXPDgD4celrq0/vJT9ekLF0E6Au4fLbvRh1G8sXnGwDUkg==" + }, + "@cycjimmy/jsmpeg-player": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-5.0.1.tgz", + "integrity": "sha512-x2kCCEfmXinebXC3d8XBJmOeFP+Jw0f4peT2rAmNvhggP1hYPvACP2ioobxeZvp255rPQTt/RPNi9y2SJ5ATMQ==", + "requires": { + "@cycjimmy/awesome-js-funcs": "^2.3.0", + "@cycjimmy/sass-lib": "^1.0.3" + } + }, + "@cycjimmy/sass-lib": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cycjimmy/sass-lib/-/sass-lib-1.0.3.tgz", + "integrity": "sha512-OTr8uMjeRapr0bWTKs782Jj84/xQt1XvVl5ZyYW1yi4sEbqY1FfW1FYLeflBp4gSU99o4c/nPi2Fx5aRxna5dw==" + }, "@dsherret/to-absolute-glob": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", @@ -4118,17 +4137,17 @@ "dev": true }, "@videojs/http-streaming": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.6.4.tgz", - "integrity": "sha512-sFVE0MVXhawAkET8EgiUSMvDDv6u3uGidtO0BvNXG0/qKWlze/zEzhvLsyPU4HmLFRnffKeHK5RE2XpO5vHY8Q==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.9.0.tgz", + "integrity": "sha512-fRooepCcSYUKcplrn4h/teqL08Nr5bo4KDs8uGI6RAYOuDhGfWjaxFpmdUhr6Yme9G+ci+2Hh/hk9hHXxYGWaw==", "requires": { "@babel/runtime": "^7.12.5", - "@videojs/vhs-utils": "^3.0.0", + "@videojs/vhs-utils": "^3.0.2", "aes-decrypter": "3.1.2", "global": "^4.4.0", - "m3u8-parser": "4.5.2", - "mpd-parser": "0.15.4", - "mux.js": "5.10.0", + "m3u8-parser": "4.7.0", + "mpd-parser": "0.17.0", + "mux.js": "5.11.0", "video.js": "^6 || ^7" }, "dependencies": { @@ -4878,14 +4897,6 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "chainsaw": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.0.9.tgz", - "integrity": "sha1-EaBRAtHEx4W20EFdM21aOhYSkT4=", - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -6091,11 +6102,6 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" - }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -6559,9 +6565,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -6685,14 +6691,6 @@ } } }, - "hashish": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz", - "integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=", - "requires": { - "traverse": ">=0.2.4" - } - }, "himalaya": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.0.tgz", @@ -8929,9 +8927,9 @@ "dev": true }, "m3u8-parser": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.5.2.tgz", - "integrity": "sha512-sN/lu3TiRxmG2RFjZxo5c0/7Dr4RrEztl43jXrWwj5gFZ7vfa2iIxGfiPx485dm5QCazaIcKk+vNkUso8Aq0Ag==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.0.tgz", + "integrity": "sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ==", "requires": { "@babel/runtime": "^7.12.5", "@videojs/vhs-utils": "^3.0.0", @@ -8953,6 +8951,7 @@ "version": "0.25.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, "requires": { "sourcemap-codec": "^1.4.4" } @@ -9116,14 +9115,14 @@ "dev": true }, "mpd-parser": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.15.4.tgz", - "integrity": "sha512-YcOclxKc5gnT87UQYwRoPJpWOFvQORwN+bXYmTWCJ4U2pCSS7jjtPrIhoOLHFAyekj48CHTX4hjGBV/VSNsUsg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.17.0.tgz", + "integrity": "sha512-oKS5G0jCcHHJ3sHYlcLeM9Xcbuixl08eAx7QW0Th7ChlZiI0YvLtGaHE/L0aKUBJFNvtkeksIr8XgJgSBBsS4g==", "requires": { "@babel/runtime": "^7.12.5", - "@videojs/vhs-utils": "^3.0.0", + "@videojs/vhs-utils": "^3.0.2", "global": "^4.4.0", - "xmldom": "^0.4.0" + "xmldom": "^0.5.0" }, "dependencies": { "global": { @@ -9157,9 +9156,9 @@ } }, "mux.js": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.10.0.tgz", - "integrity": "sha512-kLzvYsHYBwNa+ckkmpxWV3eImwntJbrwd1KbN4WR0hLe+dK/KB82aCuC0fQzAI2hkjYszdlSGsAWFgYdiFBUuA==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.11.0.tgz", + "integrity": "sha512-Q/iLfohHh5Pp6lW7EFtcxNuaCNJ3Ruywfy46pWLsY+yIxR1kXXImYY1wOhg8jLdBMs1kRaZqsiB4Zncsiw0a2Q==", "requires": { "@babel/runtime": "^7.11.2" } @@ -10281,14 +10280,6 @@ } } }, - "remove": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/remove/-/remove-0.1.5.tgz", - "integrity": "sha1-CV/9gn1lyfQa2X0z5BanWBEHmVU=", - "requires": { - "seq": ">= 0.3.5" - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -10473,23 +10464,6 @@ } } }, - "rollup-plugin-replace": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz", - "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==", - "requires": { - "magic-string": "^0.25.2", - "rollup-pluginutils": "^2.6.0" - } - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "requires": { - "estree-walker": "^0.6.1" - } - }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -10766,15 +10740,6 @@ "lru-cache": "^6.0.0" } }, - "seq": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/seq/-/seq-0.3.5.tgz", - "integrity": "sha1-rgKvOkJHk9jMvyEtaRdODFTf/jg=", - "requires": { - "chainsaw": ">=0.0.7 <0.1", - "hashish": ">=0.0.2 <0.1" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -11094,7 +11059,8 @@ "sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true }, "spdx-correct": { "version": "3.1.1", @@ -11575,11 +11541,6 @@ "punycode": "^2.1.1" } }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=" - }, "ts-morph": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-9.1.0.tgz", @@ -11926,20 +11887,34 @@ } }, "video.js": { - "version": "7.11.8", - "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.11.8.tgz", - "integrity": "sha512-iQmNYB+pdgu8b45Za1AKSa5J7uDyHIqfJy+picw4voKfjErXK/BEvs+A3f99Ck7SCZU4cmMmX/s17AwaaNs+1w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.13.0.tgz", + "integrity": "sha512-wJcB2R5q3/6Ez5XUfpZBZTdgF321rX/M1HkDKxXQIdfsVi/pfP4l+equ2xL9O3X0XAPHRxLEegraIEuX28mRkA==", "requires": { - "@babel/runtime": "^7.9.2", - "@videojs/http-streaming": "2.6.4", + "@babel/runtime": "^7.12.5", + "@videojs/http-streaming": "2.9.0", + "@videojs/vhs-utils": "^3.0.2", "@videojs/xhr": "2.5.1", - "global": "4.3.2", + "aes-decrypter": "3.1.2", + "global": "^4.4.0", "keycode": "^2.2.0", - "remove": "^0.1.5", - "rollup-plugin-replace": "^2.2.0", + "m3u8-parser": "4.7.0", + "mpd-parser": "0.17.0", + "mux.js": "5.11.0", "safe-json-parse": "4.0.0", "videojs-font": "3.2.0", - "videojs-vtt.js": "^0.15.2" + "videojs-vtt.js": "^0.15.3" + }, + "dependencies": { + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + } } }, "videojs-font": { @@ -12138,9 +12113,9 @@ "dev": true }, "xmldom": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.4.0.tgz", - "integrity": "sha512-2E93k08T30Ugs+34HBSTQLVtpi6mCddaY8uO+pMNk1pqSjV5vElzn4mmh6KLxN3hki8rNcHSYzILoh3TEWORvA==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz", + "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==" }, "xtend": { "version": "4.0.2", diff --git a/web/package.json b/web/package.json index 052d98234..c84713c95 100644 --- a/web/package.json +++ b/web/package.json @@ -11,13 +11,14 @@ "test": "jest" }, "dependencies": { + "@cycjimmy/jsmpeg-player": "^5.0.1", "date-fns": "^2.21.3", "idb-keyval": "^5.0.2", "immer": "^8.0.1", "preact": "^10.5.9", "preact-async-route": "^2.2.1", "preact-router": "^3.2.1", - "video.js": "^7.11.8", + "video.js": "^7.13.0", "videojs-playlist": "^4.3.1", "videojs-seek-buttons": "^2.0.1" }, diff --git a/web/src/App.jsx b/web/src/App.jsx index 49d572736..1212f293f 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -27,6 +27,7 @@ export default function App() { + diff --git a/web/src/Sidebar.jsx b/web/src/Sidebar.jsx index 3a9671160..cb97c8f05 100644 --- a/web/src/Sidebar.jsx +++ b/web/src/Sidebar.jsx @@ -49,6 +49,7 @@ export default function Sidebar() { ) : null } + diff --git a/web/src/components/JSMpegPlayer.jsx b/web/src/components/JSMpegPlayer.jsx new file mode 100644 index 000000000..b78da32c9 --- /dev/null +++ b/web/src/components/JSMpegPlayer.jsx @@ -0,0 +1,29 @@ +import { h } from 'preact'; +import { baseUrl } from '../api/baseUrl'; +import { useRef, useEffect } from 'preact/hooks'; +import JSMpeg from '@cycjimmy/jsmpeg-player'; + +export default function JSMpegPlayer({ camera }) { + const playerRef = useRef(); + const canvasRef = useRef(); + const url = `${baseUrl.replace(/^http/, 'ws')}/live/${camera}` + + useEffect(() => { + const video = new JSMpeg.VideoElement( + playerRef.current, + url, + {canvas: canvasRef.current}, + {protocols: []} + ); + + return () => { + video.destroy(); + }; + }, [url]); + + return ( +
+ +
+ ); +} diff --git a/web/src/routes/Birdseye.jsx b/web/src/routes/Birdseye.jsx new file mode 100644 index 000000000..5222854e9 --- /dev/null +++ b/web/src/routes/Birdseye.jsx @@ -0,0 +1,14 @@ +import { h } from 'preact'; +import JSMpegPlayer from '../components/JSMpegPlayer'; +import Heading from '../components/Heading'; + +export default function Birdseye() { + return ( +
+ Birdseye +
+ +
+
+ ); +} diff --git a/web/src/routes/index.js b/web/src/routes/index.js index 0b8a622b1..c5b40de8c 100644 --- a/web/src/routes/index.js +++ b/web/src/routes/index.js @@ -13,6 +13,11 @@ export async function getEvent(url, cb, props) { return module.default; } +export async function getBirdseye(url, cb, props) { + const module = await import('./Birdseye.jsx'); + return module.default; +} + export async function getEvents(url, cb, props) { const module = await import('./Events.jsx'); return module.default;