revise url format

This commit is contained in:
0x464e 2026-03-19 16:33:30 +02:00
parent ec3fc782a8
commit 05d29ebc93
No known key found for this signature in database
GPG Key ID: E6D221DF6CBFBFFA
3 changed files with 45 additions and 15 deletions

View File

@ -24,6 +24,7 @@ import {
import { import {
parseRecordingReviewLink, parseRecordingReviewLink,
RECORDING_REVIEW_START_PARAM, RECORDING_REVIEW_START_PARAM,
RECORDING_REVIEW_TIMEZONE_PARAM,
} from "@/utils/recordingReviewUrl"; } from "@/utils/recordingReviewUrl";
import EventView from "@/views/events/EventView"; import EventView from "@/views/events/EventView";
import MotionSearchView from "@/views/motion-search/MotionSearchView"; import MotionSearchView from "@/views/motion-search/MotionSearchView";
@ -248,6 +249,7 @@ export default function Events() {
useEffect(() => { useEffect(() => {
const timestamp = searchParams.get(RECORDING_REVIEW_START_PARAM); const timestamp = searchParams.get(RECORDING_REVIEW_START_PARAM);
const timezone = searchParams.get(RECORDING_REVIEW_TIMEZONE_PARAM);
if (!timestamp) { if (!timestamp) {
return; return;
@ -257,7 +259,7 @@ export default function Events() {
? decodeURIComponent(location.hash.substring(1)) ? decodeURIComponent(location.hash.substring(1))
: null; : null;
const reviewLink = parseRecordingReviewLink(camera, timestamp); const reviewLink = parseRecordingReviewLink(camera, timestamp, timezone);
if (!reviewLink) { if (!reviewLink) {
navigate(location.pathname + location.hash, { navigate(location.pathname + location.hash, {

View File

@ -1,19 +1,39 @@
import { formatInTimeZone, fromZonedTime } from "date-fns-tz";
export const RECORDING_REVIEW_START_PARAM = "start_time"; export const RECORDING_REVIEW_START_PARAM = "start_time";
export const RECORDING_REVIEW_TIMEZONE_PARAM = "timezone";
export type RecordingReviewLinkState = { export type RecordingReviewLinkState = {
camera: string; camera: string;
timestamp: number; timestamp: number;
}; };
function formatRecordingReviewTimestamp(
timestamp: number,
timezone: string | undefined,
): string {
const date = new Date(Math.floor(timestamp) * 1000);
if (timezone) {
return formatInTimeZone(date, timezone, "yyyy-MM-dd'T'HH:mm:ss");
}
return formatInTimeZone(date, "UTC", "yyyy-MM-dd'T'HH:mm:ss'Z'");
}
export function parseRecordingReviewLink( export function parseRecordingReviewLink(
camera: string | null, camera: string | null,
start: string | null, start: string | null,
timezone: string | null,
): RecordingReviewLinkState | undefined { ): RecordingReviewLinkState | undefined {
if (!camera || !start) { if (!camera || !start) {
return undefined; return undefined;
} }
const parsedTimestamp = Number(start); const parsedDate = timezone
? fromZonedTime(start, timezone)
: new Date(start);
const parsedTimestamp = parsedDate.getTime() / 1000;
if (!Number.isFinite(parsedTimestamp)) { if (!Number.isFinite(parsedTimestamp)) {
return undefined; return undefined;
@ -28,15 +48,19 @@ export function parseRecordingReviewLink(
export function createRecordingReviewUrl( export function createRecordingReviewUrl(
pathname: string, pathname: string,
state: RecordingReviewLinkState, state: RecordingReviewLinkState,
timezone?: string,
): string { ): string {
const url = new URL(window.location.href); const url = new URL(globalThis.location.href);
url.pathname = pathname; const formattedTimestamp = formatRecordingReviewTimestamp(
url.hash = state.camera; state.timestamp,
url.search = ""; timezone,
url.searchParams.set(
RECORDING_REVIEW_START_PARAM,
`${Math.floor(state.timestamp)}`,
); );
const normalizedPathname = pathname.startsWith("/")
? pathname
: `/${pathname}`;
const timezoneParam = timezone
? `&${RECORDING_REVIEW_TIMEZONE_PARAM}=${encodeURIComponent(timezone)}`
: "";
return url.toString(); return `${url.origin}${normalizedPathname}?${RECORDING_REVIEW_START_PARAM}=${formattedTimestamp}${timezoneParam}#${encodeURIComponent(state.camera)}`;
} }

View File

@ -334,16 +334,20 @@ export function RecordingView({
}, [startTime, manuallySetCurrentTime]); }, [startTime, manuallySetCurrentTime]);
const onCopyReviewLink = useCallback(() => { const onCopyReviewLink = useCallback(() => {
const reviewUrl = createRecordingReviewUrl(location.pathname, { const reviewUrl = createRecordingReviewUrl(
camera: mainCamera, location.pathname,
timestamp: Math.floor(currentTime), {
}); camera: mainCamera,
timestamp: Math.floor(currentTime),
},
config?.ui.timezone,
);
copy(reviewUrl); copy(reviewUrl);
toast.success(t("toast.copyUrlToClipboard", { ns: "common" }), { toast.success(t("toast.copyUrlToClipboard", { ns: "common" }), {
position: "top-center", position: "top-center",
}); });
}, [location.pathname, mainCamera, currentTime, t]); }, [location.pathname, mainCamera, currentTime, config?.ui.timezone, t]);
useEffect(() => { useEffect(() => {
if (!scrubbing) { if (!scrubbing) {