|
|
|
|
@@ -1,10 +1,13 @@
|
|
|
|
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
|
|
|
import { useDebouncedCallback } from "use-debounce";
|
|
|
|
|
import { Query, useQuery } from "@tanstack/react-query";
|
|
|
|
|
import type { SightingType } from "../types/types";
|
|
|
|
|
import { useSoundOnChange } from "react-sounds";
|
|
|
|
|
import { useSound } from "react-sounds";
|
|
|
|
|
import { useSoundContext } from "../context/SoundContext";
|
|
|
|
|
import { getSoundFileURL } from "../utils/utils";
|
|
|
|
|
import { checkIsHotListHit, getNPEDCategory, getSoundFileURL } from "../utils/utils";
|
|
|
|
|
import switchSound from "../assets/sounds/ui/switch.mp3";
|
|
|
|
|
import notification from "../assets/sounds/ui/notification.mp3";
|
|
|
|
|
import popup from "../assets/sounds/ui/popup_open.mp3";
|
|
|
|
|
|
|
|
|
|
async function fetchSighting(url: string | undefined, ref: number): Promise<SightingType> {
|
|
|
|
|
const res = await fetch(`${url}${ref}`, {
|
|
|
|
|
@@ -21,26 +24,21 @@ export function useSightingFeed(url: string | undefined) {
|
|
|
|
|
const [sessionStarted, setSessionStarted] = useState(false);
|
|
|
|
|
const [selectedSighting, setSelectedSighting] = useState<SightingType | null>(null);
|
|
|
|
|
|
|
|
|
|
const mostRecent = sightings[0] ?? null;
|
|
|
|
|
const latestRef = mostRecent?.ref ?? null;
|
|
|
|
|
|
|
|
|
|
const first = useRef(true);
|
|
|
|
|
const lastSoundAt = useRef(0);
|
|
|
|
|
const COOLDOWN_MS = 1500;
|
|
|
|
|
const currentRef = useRef<number>(-1);
|
|
|
|
|
const lastValidTimestamp = useRef<number>(Date.now());
|
|
|
|
|
|
|
|
|
|
const trigger = useMemo(() => {
|
|
|
|
|
if (latestRef == null || !audioArmed) return null;
|
|
|
|
|
if (first.current) {
|
|
|
|
|
first.current = false;
|
|
|
|
|
return Symbol("skip");
|
|
|
|
|
const soundSrcHotlist = useMemo(() => {
|
|
|
|
|
if (state?.hotlistSound?.includes(".mp3") || state.hotlistSound?.includes(".wav")) {
|
|
|
|
|
const file = state.soundOptions?.find((item) => item.name === state.hotlistSound);
|
|
|
|
|
return file?.soundUrl ?? notification;
|
|
|
|
|
}
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
if (now - lastSoundAt.current < COOLDOWN_MS) return Symbol("skip");
|
|
|
|
|
lastSoundAt.current = now;
|
|
|
|
|
return latestRef;
|
|
|
|
|
}, [audioArmed, latestRef]);
|
|
|
|
|
return getSoundFileURL(state?.hotlistSound) ?? notification;
|
|
|
|
|
}, [state.hotlistSound, state.soundOptions]);
|
|
|
|
|
|
|
|
|
|
const soundSrcNped = useMemo(() => {
|
|
|
|
|
if (state?.NPEDsound?.includes(".mp3") || state.NPEDsound?.includes(".wav")) {
|
|
|
|
|
const file = state.soundOptions?.find((item) => item.name === state.NPEDsound);
|
|
|
|
|
return file?.soundUrl ?? popup;
|
|
|
|
|
}
|
|
|
|
|
return getSoundFileURL(state.NPEDsound) ?? popup;
|
|
|
|
|
}, [state.NPEDsound, state.soundOptions]);
|
|
|
|
|
|
|
|
|
|
const soundSrc = useMemo(() => {
|
|
|
|
|
if (state?.sightingSound?.includes(".mp3") || state.sightingSound?.includes(".wav")) {
|
|
|
|
|
@@ -50,6 +48,15 @@ export function useSightingFeed(url: string | undefined) {
|
|
|
|
|
return getSoundFileURL(state?.sightingSound) ?? switchSound;
|
|
|
|
|
}, [state.sightingSound, state.soundOptions]);
|
|
|
|
|
|
|
|
|
|
const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume });
|
|
|
|
|
const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume });
|
|
|
|
|
const { play: sightingSound } = useSound(soundSrc, { volume: state.sightingVolume });
|
|
|
|
|
|
|
|
|
|
const mostRecent = sightings[0] ?? null;
|
|
|
|
|
|
|
|
|
|
const currentRef = useRef<number>(-1);
|
|
|
|
|
const lastValidTimestamp = useRef<number>(Date.now());
|
|
|
|
|
|
|
|
|
|
function refetchInterval(query: Query<SightingType, Error, SightingType, (string | undefined)[]>) {
|
|
|
|
|
if (!query) return;
|
|
|
|
|
const data = query.state.data as SightingType | undefined;
|
|
|
|
|
@@ -78,16 +85,36 @@ export function useSightingFeed(url: string | undefined) {
|
|
|
|
|
staleTime: 0,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//use latestref instead of trigger to revert back
|
|
|
|
|
const playHotlistsound = useDebouncedCallback(() => {
|
|
|
|
|
hotlistsound();
|
|
|
|
|
}, 500);
|
|
|
|
|
|
|
|
|
|
useSoundOnChange(soundSrc, trigger, {
|
|
|
|
|
volume: state.sightingVolume,
|
|
|
|
|
initial: false,
|
|
|
|
|
});
|
|
|
|
|
const playNPEDHitSound = useDebouncedCallback(() => {
|
|
|
|
|
npedSound();
|
|
|
|
|
}, 500);
|
|
|
|
|
|
|
|
|
|
const playSightingHitSound = useDebouncedCallback(() => {
|
|
|
|
|
sightingSound();
|
|
|
|
|
}, 500);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const data = query.data;
|
|
|
|
|
|
|
|
|
|
if (!data || data.ref === -1) return;
|
|
|
|
|
const isHotListHit = checkIsHotListHit(data);
|
|
|
|
|
const cat = getNPEDCategory(data);
|
|
|
|
|
|
|
|
|
|
const isNPEDHitA = cat === "A";
|
|
|
|
|
const isNPEDHitB = cat === "B";
|
|
|
|
|
const isNPEDHitC = cat === "C";
|
|
|
|
|
|
|
|
|
|
if ((isNPEDHitA && audioArmed) || (isNPEDHitB && audioArmed) || (isNPEDHitC && audioArmed)) {
|
|
|
|
|
playNPEDHitSound();
|
|
|
|
|
} else if (isHotListHit && audioArmed) {
|
|
|
|
|
playHotlistsound();
|
|
|
|
|
} else if (audioArmed) {
|
|
|
|
|
playSightingHitSound();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
|
|
|