Glimesh / broadcast-box

A broadcast, in a box.
MIT License
688 stars 57 forks source link

Change cinema mode state to use query search params #131

Open cgmartin opened 3 months ago

cgmartin commented 3 months ago

Hello! Thank you for this project!

My use-case is aggregating multiple remote game streams into OBS for a 4-way split screen (ie. Halo/Goldeneye multiplayer from days past).

When using browser sources in OBS, I wanted to automatically turn cinemaMode on via a URL param in the WHIP URLs, rather than manually pushing the Enable Cinema Mode button each time.

ie. http://localhost:3000/foo?cinemaMode=true

This is the code I'm using, in case it may be of any use to you.

Note: This change does not preserve backwards compatibility with the previous localstorage implementation.

Sean-Der commented 3 months ago

Glad it is useful :)

Could we do both localStorage + searchParam? I would do a || on the values maybe?

cgmartin commented 2 months ago

Could we do both localStorage + searchParam? I would do a || on the values maybe?

I think I can manage that change. Just to confirm, should it work as follows?:

  1. Use the searchParam as priority if true, otherwise (else) use the localstorage value if true
  2. Update the searchParams AND localstorage whenever state changes.
  3. Delete the key/value in searchParams AND localstorage when value is false
Sean-Der commented 2 months ago

@cgmartin That sounds great! Thank you so much :)

I think everyone would be happy, and code wise that is pretty simple. Definitely don't need a distinct path for local + url param.

cgmartin commented 2 months ago

Hi @Sean-Der, I thought it would be simple as well, but I believe I may be getting hung up on this bug: https://github.com/remix-run/react-router/issues/9991

I'm not very familiar with React, honestly. Here is the new code I'm trying to make work:

export function CinemaModeProvider({ children }) {
  const [searchParams, setSearchParams] = useSearchParams();
  const [cinemaMode, setCinemaMode] = useState(() => localStorage.getItem("cinema-mode") === "true");

  useEffect(() => {
    const paramCinemaMode = searchParams.get("cinemaMode");
    const storedCinemaMode = localStorage.getItem("cinema-mode");
    const newValue = paramCinemaMode === "true" || (paramCinemaMode === null && storedCinemaMode === "true");
    setCinemaMode(newValue);
  }, [searchParams]);

  useEffect(() => {
    localStorage.setItem("cinema-mode", cinemaMode ? "true" : "false");
  }, [cinemaMode]);

  const state = useMemo(() => ({
    cinemaMode,
    setCinemaMode,
    toggleCinemaMode: () => {
      setCinemaMode(!cinemaMode);
      searchParams.set("cinemaMode", cinemaMode ? "true" : "false");
      setSearchParams(searchParams);
    }
  }), [cinemaMode, setCinemaMode, searchParams, setSearchParams]);

  return (
    <CinemaModeContext.Provider value={state}>
      {children}
    </CinemaModeContext.Provider>
  );
}

It is very odd. When I try modifying the search param value from ?cinemaMode=true to ?cinemaMode=false, the param key will unexpectedly change to lowercase and the delete param functionality breaks.

I doubt I will spend much more time on this to try getting working, but feel free to change and utilize how you see fit. Cheers!