diff --git a/src/components/views/LceOnlineView.tsx b/src/components/views/LceOnlineView.tsx index 3d38a78..ad14582 100644 --- a/src/components/views/LceOnlineView.tsx +++ b/src/components/views/LceOnlineView.tsx @@ -25,7 +25,7 @@ const LceOnlineView = memo(function LceOnlineView({ onClearAddFriendTarget, invites: invitesProp, }: LceOnlineViewProps) { - const { setActiveView } = useUI(); + const { setActiveView, setIsUiHidden } = useUI(); const { animationsEnabled } = useConfig(); const { playPressSound, playBackSound } = useAudio(); const game = useGame(); @@ -364,6 +364,122 @@ const LceOnlineView = memo(function LceOnlineView({ } }, [focusIndex, isAddingFriend]); + const touhouOverlayRef = useRef(null); + const touhouBlobUrlRef = useRef(null); + const touhouAudioRef = useRef(null); + useEffect(() => { + const GIF_URL = + "https://raw.githubusercontent.com/neoapps-dev/neoapps-dev/main/badapple_small.gif"; + const MP3_URL = + "https://raw.githubusercontent.com/Soldr/bad-apple-but-its-node.js/master/bad-apple.mp3"; + + const stopAudio = () => { + if (touhouAudioRef.current) { + touhouAudioRef.current.pause(); + touhouAudioRef.current.src = ""; + touhouAudioRef.current = null; + } + }; + + const onlineUser = lceOnlineService.account?.username; + if (onlineUser === "TOUHOU") { + if (!touhouOverlayRef.current) { + setIsUiHidden(true); + const overlay = document.createElement("div"); + overlay.style.cssText = + "position:fixed;inset:0;z-index:99999;background:#000;display:flex;align-items:center;justify-content:center;cursor:pointer"; + const spinner = document.createElement("div"); + spinner.textContent = "Loading..."; + spinner.style.cssText = + "color:#fff;font-family:'Mojangles',monospace;font-size:24px;letter-spacing:4px"; + overlay.appendChild(spinner); + document.body.appendChild(overlay); + const img = document.createElement("img"); + img.style.cssText = "width:100%;height:100%;object-fit:contain"; + const audio = new Audio(MP3_URL); + audio.loop = true; + audio.volume = 0.5; + touhouAudioRef.current = audio; + const audioReady = new Promise((resolve) => { + if (audio.readyState >= 3) resolve(); + else { + audio.oncanplaythrough = () => resolve(); + audio.onerror = () => resolve(); + } + }); + + const gifReady = fetch(GIF_URL) + .then((r) => r.arrayBuffer()) + .then((buf) => { + const blob = new Blob([buf], { type: "image/gif" }); + const url = URL.createObjectURL(blob); + touhouBlobUrlRef.current = url; + img.src = url; + return new Promise((resolve) => { + if (img.complete) resolve(); + else { + img.onload = () => resolve(); + img.onerror = () => resolve(); + } + }); + }) + .catch(() => { + img.src = GIF_URL; + return new Promise((resolve) => { + if (img.complete) resolve(); + else { + img.onload = () => resolve(); + img.onerror = () => resolve(); + } + }); + }); + + Promise.all([gifReady, audioReady]).then(() => { + spinner.remove(); + overlay.appendChild(img); + audio.currentTime = 2; + audio.play().catch(() => {}); + }); + + const cleanup = () => { + stopAudio(); + setIsUiHidden(false); + if (overlay.parentNode) overlay.remove(); + touhouOverlayRef.current = null; + if (touhouBlobUrlRef.current) { + URL.revokeObjectURL(touhouBlobUrlRef.current); + touhouBlobUrlRef.current = null; + } + }; + overlay.onclick = cleanup; + touhouOverlayRef.current = overlay; + } + } else { + if (touhouOverlayRef.current) { + stopAudio(); + touhouOverlayRef.current.remove(); + touhouOverlayRef.current = null; + if (touhouBlobUrlRef.current) { + URL.revokeObjectURL(touhouBlobUrlRef.current); + touhouBlobUrlRef.current = null; + } + setIsUiHidden(false); + } + } + return () => { + stopAudio(); + setIsUiHidden(false); + if (touhouOverlayRef.current) { + touhouOverlayRef.current.remove(); + touhouOverlayRef.current = null; + if (touhouBlobUrlRef.current) { + URL.revokeObjectURL(touhouBlobUrlRef.current); + touhouBlobUrlRef.current = null; + } + } + }; + }, [isSignedIn, setIsUiHidden]); + const renderContent = () => { if (!isSignedIn) { return (