diff --git a/package.json b/package.json
index c2fc1ec..8875000 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"@emotion/styled": "^11.1.5",
"@material-ui/core": "^5.0.0-alpha.21",
"@material-ui/lab": "^5.0.0-alpha.21",
+ "@tanstack/react-query": "^4.36.1",
"@use-gesture/react": "^10.2.23",
"chokidar": "^3.5.1",
"cors": "^2.8.5",
diff --git a/src/components/Controls/Controls.tsx b/src/components/Controls/Controls.tsx
index 13a936b..7aaa4d7 100644
--- a/src/components/Controls/Controls.tsx
+++ b/src/components/Controls/Controls.tsx
@@ -6,7 +6,8 @@ import { useStreamStore } from "utils/stream"
import { css } from "@emotion/react"
import { theme } from "utils/theme"
import { ScrobberRange } from "components/Scrobber/ScrobberRange"
-import { MutableRefObject } from "react"
+import { MutableRefObject, useEffect } from "react"
+import { useQuery } from "@tanstack/react-query"
function ControlsHeader(props: {
stream: {
diff --git a/src/components/Scrobber/ScrobberShift.utils.ts b/src/components/Scrobber/ScrobberShift.utils.ts
index 5925776..3c81b34 100644
--- a/src/components/Scrobber/ScrobberShift.utils.ts
+++ b/src/components/Scrobber/ScrobberShift.utils.ts
@@ -3,7 +3,7 @@ import { useEffect, useLayoutEffect, useState } from "react"
async function getServerTimeDiff() {
const clientStart = Date.now(),
timeBefore = performance.now()
- const serverReq = await fetch("http://192.168.2.152:3000/api/time")
+ const serverReq = await fetch("/api/time")
const timeAfter = performance.now()
const roundTripTime = timeAfter - timeBefore
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 97b4800..34bbeb2 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -12,9 +12,12 @@ import NoSleep from "nosleep.js"
import dayjs from "dayjs"
import minMax from "dayjs/plugin/minMax"
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
dayjs.extend(minMax)
+const queryClient = new QueryClient()
+
export default function App(props: AppProps) {
const { Component, pageProps } = props
@@ -35,68 +38,70 @@ export default function App(props: AppProps) {
)
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+ overflow-x: hidden;
+ }
+ `}
+ />
-
-
-
-
+
+
+
+
+
)
}
diff --git a/src/pages/api/data/[folder]/log/stream.ts b/src/pages/api/data/[folder]/log/stream.ts
index 77f88e6..d9f9a91 100644
--- a/src/pages/api/data/[folder]/log/stream.ts
+++ b/src/pages/api/data/[folder]/log/stream.ts
@@ -6,7 +6,7 @@ import cors from "cors"
const dbRef = createPersistentDatabase()
-const RANGE = 10 * 2 // 20s
+const RANGE = 10 * 60 // 20s
export default async function handler(
req: NextApiRequest,
diff --git a/src/pages/camera/[cameraKey].tsx b/src/pages/camera/[cameraKey].tsx
index 8a6c791..61f65c1 100644
--- a/src/pages/camera/[cameraKey].tsx
+++ b/src/pages/camera/[cameraKey].tsx
@@ -11,6 +11,8 @@ import {
useStreamStore,
useStreamPeriodicRefreshNow,
generateUrl,
+ fitDateInBounds,
+ getDateBounds,
} from "utils/stream"
import { NextSeo } from "next-seo"
import Head from "next/head"
@@ -18,6 +20,122 @@ import { GetServerSideProps } from "next"
import { loadServerConfig } from "shared/config"
import { theme } from "utils/theme"
import { useVisibleTimer } from "components/Controls/Controls.utils"
+import { useQuery } from "@tanstack/react-query"
+import { encodeQuery } from "utils/query"
+import { z } from "zod"
+import { useServerTimeDiff } from "components/Scrobber/ScrobberShift.utils"
+import dayjs from "dayjs"
+
+const schema = z.object({
+ cart: z.object({
+ items: z.array(
+ z.object({ name: z.string(), price: z.number(), qty: z.number() })
+ ),
+ }),
+})
+
+function LogStream(props: {
+ stream: {
+ key: string
+ }
+}) {
+ const stream = useStreamStore((state) => state.stream)
+ const log = useQuery(
+ [props.stream.key, stream] as const,
+ async ({ queryKey: [camera, args] }) => {
+ let url: string
+
+ if ("from" in args && "to" in args) {
+ url = encodeQuery(`/api/data/${camera}/log/stream`, {
+ from: Math.floor(args.from / 1000),
+ to: Math.floor(args.to / 1000),
+ })
+ } else {
+ url = encodeQuery(`/api/data/${camera}/log/stream`, {
+ shift: Math.floor(args.shift / 1000),
+ })
+ }
+
+ const json: Array<{
+ json: string
+ timestamp: number
+ }> = await fetch(url).then((res) => res.json())
+
+ return json
+ .map(({ json, timestamp }) => ({
+ timestamp,
+ data: schema.parse(JSON.parse(json)),
+ }))
+ .reverse()
+ },
+ { refetchInterval: 1000 }
+ )
+
+ const serverDiff = useServerTimeDiff()
+ const now = useStreamStore((state) => state.now)
+ const playback = useStreamStore((state) => state.playback)
+
+ const displayDate = (
+ "playing" in playback
+ ? now.add(playback.playing, "millisecond")
+ : playback.paused
+ ).add(serverDiff, "millisecond")
+
+ const currentItem = log.data?.find(
+ ({ timestamp }) => dayjs(timestamp).valueOf() <= displayDate.valueOf()
+ )
+
+ return (
+
+
+
+ {currentItem?.data.cart.items.map((item, idx) => {
+ const name = item.name || "Zboží"
+ return (
+
+ {item.qty} x {name} ... {item.price * item.qty} Kč
+
+ )
+ })}
+
+
+
+ )
+}
export default function Page() {
useStreamPeriodicRefreshNow()
@@ -98,6 +216,8 @@ export default function Page() {
}}
/>
)}
+
+ {meta && }
)
diff --git a/src/utils/stream.ts b/src/utils/stream.ts
index ba90277..9a27915 100644
--- a/src/utils/stream.ts
+++ b/src/utils/stream.ts
@@ -21,16 +21,13 @@ export type PlaybackType = { playing: number } | { paused: dayjs.Dayjs }
export function generateUrl(name: string, args: StreamType): string | null {
if ("from" in args && "to" in args) {
- return encodeQuery(
- `http://192.168.2.152:3000/api/data/${name}/slice.m3u8`,
- {
- from: Math.floor(args.from / 1000),
- to: Math.floor(args.to / 1000),
- }
- )
+ return encodeQuery(`/api/data/${name}/slice.m3u8`, {
+ from: Math.floor(args.from / 1000),
+ to: Math.floor(args.to / 1000),
+ })
}
- return encodeQuery(`http://192.168.2.152:3000/api/data/${name}/stream.m3u8`, {
+ return encodeQuery(`/api/data/${name}/stream.m3u8`, {
shift: Math.floor(args.shift / 1000),
})
}
diff --git a/yarn.lock b/yarn.lock
index c362981..99f1284 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -954,6 +954,19 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
+"@tanstack/query-core@4.36.1":
+ version "4.36.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524"
+ integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==
+
+"@tanstack/react-query@^4.36.1":
+ version "4.36.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2"
+ integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==
+ dependencies:
+ "@tanstack/query-core" "4.36.1"
+ use-sync-external-store "^1.2.0"
+
"@types/babel__core@^7.1.14":
version "7.1.19"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460"
@@ -4642,7 +4655,7 @@ use-subscription@1.5.1:
dependencies:
object-assign "^4.1.1"
-use-sync-external-store@1.2.0:
+use-sync-external-store@1.2.0, use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==