Skip to content

Commit 4f30a5a

Browse files
authored
Popup playing memory, tooltip titles, and console.log cleaning (#54)
* Extension popup now remembers if it was playing * Sorted imports and changed -1 to null
1 parent 4bc8c68 commit 4f30a5a

26 files changed

Lines changed: 193 additions & 173 deletions

extension/src/components/button.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as React from "react";
2-
import "./button.css";
31
import { GearIcon } from "@radix-ui/react-icons";
42
import { IconProps } from "@radix-ui/react-icons/dist/types";
3+
import * as React from "react";
4+
import "./button.css";
55

66
export interface SoundButtonProps
77
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
@@ -22,7 +22,7 @@ const SoundButton = ({
2222
const classes = `soundButton ${className}`.trim();
2323

2424
return (
25-
<div className="soundButtonWrapper">
25+
<div className="soundButtonWrapper" title={label}>
2626
<button
2727
className={classes}
2828
name={label}
@@ -81,4 +81,4 @@ function chooseIcon(icon: string, props?: IconProps) {
8181
}
8282
}
8383

84-
export { SoundButton, IconButton };
84+
export { IconButton, SoundButton };

extension/src/entrypoints/background.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { CrossFunctions } from "@/utils/constants";
33
export default defineBackground(() => {
44
console.log("Background loaded!", { id: browser.runtime.id });
55

6+
let audioPlaying: number | null = null;
7+
68
browser.runtime.onInstalled.addListener(function (object) {
79
if (object.reason === browser.runtime.OnInstalledReason.INSTALL) {
810
openInfoPage();
@@ -28,6 +30,13 @@ export default defineBackground(() => {
2830
} catch (e) {
2931
console.error("openPopup failed:", e);
3032
}
33+
} else if (msg.type === CrossFunctions.SET_AUDIO_PLAYING) {
34+
audioPlaying = msg.audioID;
35+
} else if (msg.type === CrossFunctions.GET_AUDIO_PLAYING) {
36+
sendResponse(audioPlaying);
37+
return true;
38+
} else if (msg.type === CrossFunctions.AUDIO_ENDED) {
39+
audioPlaying = null;
3140
}
3241
});
3342

extension/src/entrypoints/inject.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,21 @@ function sendMessage(command: CrossFunctions) {
2727
}
2828

2929
function base64ToArrayBuffer(base64: string) {
30-
const real_base64 = base64.split(',')[1];
30+
const real_base64 = base64.split(",")[1];
3131
const binaryString = atob(real_base64);
3232

33-
const length = binaryString.length;
34-
const bytes = new Uint8Array(length);
33+
const length = binaryString.length;
34+
const bytes = new Uint8Array(length);
3535

36-
for (let i = 0; i < length; i++) {
37-
bytes[i] = binaryString.charCodeAt(i);
38-
}
36+
for (let i = 0; i < length; i++) {
37+
bytes[i] = binaryString.charCodeAt(i);
38+
}
3939

40-
return bytes.buffer;
40+
return bytes.buffer;
4141
}
4242

4343
export default defineUnlistedScript(() => {
44-
console.log("Successfully Injected!");
44+
console.log("Parakeet Successfully Injected!");
4545

4646
(async function () {
4747
const originalGUM = navigator.mediaDevices.getUserMedia.bind(
@@ -66,7 +66,6 @@ export default defineUnlistedScript(() => {
6666

6767
async function playSoundEffect(base64: string, volume: number) {
6868
// Prepare sound‐effect node (but don’t play yet)
69-
console.log("(inject.ts)Received sound effect base64");
7069
const buffer = base64ToArrayBuffer(base64);
7170
const fxBuffer = await loadEffectBuffer(audioCtx, buffer);
7271
let fxNode = null;
@@ -80,7 +79,6 @@ export default defineUnlistedScript(() => {
8079
fxGain.gain.value = 0;
8180
};
8281
fxNode.start();
83-
console.log("playing new audio");
8482

8583
window.soundboard.stopAudio = () => {
8684
fxGain.gain.value = 0;
@@ -155,7 +153,6 @@ export default defineUnlistedScript(() => {
155153
if (event.source !== window) return;
156154
switch (event.data.command) {
157155
case CrossFunctions.INJECT_AUDIO:
158-
console.log("Event received for playing audio:", event.data);
159156
if (window.soundboard.triggerAudio) {
160157
window.soundboard.triggerAudio(
161158
event.data.base64,

extension/src/entrypoints/popup/App.tsx

Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
import { useEffect, useState } from "react";
2-
import "./App.css";
3-
import { PublicPath } from "wxt/browser";
1+
import { storage } from "#imports";
42
import {
5-
postMessage,
3+
openInfoPage,
64
playLocalAudio,
7-
stopLocalAudio,
5+
postMessage,
86
setLocalVolume,
9-
openInfoPage,
7+
stopLocalAudio,
108
} from "@/utils";
11-
import { storage } from "#imports";
9+
import { getMySounds, getSounds, login } from "@/utils/api";
1210
import { CrossFunctions } from "@/utils/constants";
13-
import { login, getMySounds, getSounds } from "@/utils/api";
14-
import { storeSound, retrieveSound, isSoundCached } from "@/utils/db.ts";
11+
import { isSoundCached, retrieveSound, storeSound } from "@/utils/db.ts";
12+
import { useEffect, useState } from "react";
13+
import "./App.css";
1514

1615
import {
1716
BoxIcon,
@@ -23,12 +22,12 @@ import {
2322
SpeakerLoudIcon,
2423
UpdateIcon,
2524
} from "@radix-ui/react-icons";
26-
import { DropdownMenu, Popover, Separator, Slider } from "radix-ui";
27-
import { MicIcon, MicOffIcon, VideoIcon, VideoOffIcon } from "../../icons";
2825
import fuzzysort from "fuzzysort";
26+
import { DropdownMenu, Separator, Slider, Tooltip } from "radix-ui";
27+
import { MicIcon, MicOffIcon, VideoIcon, VideoOffIcon } from "../../icons";
2928

3029
function App() {
31-
const [currentlyPlaying, setCurrentlyPlaying] = useState(-1);
30+
const [currentlyPlaying, setCurrentlyPlaying] = useState<number | null>(null);
3231
const [searchInput, setSearchInput] = useState("");
3332
const [isMeet, setIsMeet] = useState<boolean>(false);
3433
const [soundButtons, setSoundButtons] = useState<any[]>([]);
@@ -81,10 +80,8 @@ function App() {
8180

8281
async function fetchSounds() {
8382
setIsSyncing(true);
84-
console.log("Fetching sounds...");
8583
try {
8684
const response = await getSounds();
87-
console.log("Default Sounds:", response);
8885
const sounds = await Promise.all(
8986
response.data.map(async (sound: any) => {
9087
const id = sound.id;
@@ -96,10 +93,8 @@ function App() {
9693
if (!isCached) {
9794
const audioResponse = await fetch(fullUrl);
9895
const blob = await audioResponse.blob();
99-
console.log("Caching new sound:", id);
10096
await storeSound(id, blob);
10197
} else {
102-
console.log("Sound already cached:", id);
10398
}
10499

105100
return {
@@ -151,9 +146,7 @@ function App() {
151146
}
152147

153148
async function playSound(id: number) {
154-
console.log("Playing sound with id:", id);
155149
const blob = await retrieveSound(id);
156-
console.log("(app.tsx)Retrieved sound blob:", blob);
157150
const base64 = await blobToBase64(blob);
158151
if (isMeet) {
159152
postMessage(CrossFunctions.INJECT_AUDIO, {
@@ -163,6 +156,10 @@ function App() {
163156
}
164157
const success = await playLocalAudio(base64, fxVolume);
165158
if (success) {
159+
browser.runtime.sendMessage({
160+
type: CrossFunctions.SET_AUDIO_PLAYING,
161+
audioID: id,
162+
});
166163
setCurrentlyPlaying(id);
167164
}
168165
}
@@ -172,7 +169,7 @@ function App() {
172169
postMessage(CrossFunctions.STOP_AUDIO);
173170
}
174171
stopLocalAudio();
175-
setCurrentlyPlaying(-1);
172+
setCurrentlyPlaying(null);
176173
}
177174

178175
async function handleMicMute(muteMic: boolean) {
@@ -219,15 +216,19 @@ function App() {
219216
setFxVolume(await fxVolumeStorage.getValue());
220217
setMicMuted(await micMutedStorage.getValue());
221218
setSelectedFolder(await selectedFolderStorage.getValue());
219+
setCurrentlyPlaying(
220+
await browser.runtime.sendMessage({
221+
type: CrossFunctions.GET_AUDIO_PLAYING,
222+
})
223+
);
222224
}
223225
loadStates();
224226
}, []);
225227

226228
useEffect(() => {
227-
// TODO: Make it check if the audio is still playing on reopen
228229
const listener = (msg: any) => {
229230
if (msg.type === CrossFunctions.AUDIO_ENDED) {
230-
setCurrentlyPlaying(-1);
231+
setCurrentlyPlaying(null);
231232
}
232233
};
233234

@@ -305,13 +306,11 @@ function App() {
305306
try {
306307
const res = await fetch("http://localhost:3001/login", {
307308
method: "POST",
308-
headers: { "Content-Type": "application/json",
309-
"Authorization": ""
310-
},
309+
headers: { "Content-Type": "application/json", Authorization: "" },
311310
body: JSON.stringify({
312311
user: { email: loginEmail, password: loginPassword },
313312
}),
314-
credentials: "omit"
313+
credentials: "omit",
315314
});
316315
const response = await res.json();
317316
const authHeader = res.headers.get("Authorization");
@@ -325,13 +324,14 @@ function App() {
325324
} catch (e) {
326325
console.error("Failed to store JWT in browser storage:", e);
327326
}
328-
await browser.storage.local.get("jwt").then((result) => {
329-
});
327+
await browser.storage.local.get("jwt").then((result) => {});
330328
setShowLogin(false);
331329
setLoginEmail("");
332330
setLoginPassword("");
333331
setUsername(response.status.data.user.username);
334-
await browser.storage.local.set({ username: response.status.data.user.username });
332+
await browser.storage.local.set({
333+
username: response.status.data.user.username,
334+
});
335335
alert("Logged in!");
336336
} catch {
337337
setLoginError("Login failed");
@@ -444,7 +444,7 @@ function App() {
444444
<button
445445
className="iconButton stopButton"
446446
onClick={stopSound}
447-
disabled={currentlyPlaying === -1}
447+
disabled={currentlyPlaying === null}
448448
>
449449
<BoxIcon className="buttonIcon stopButtonIcon" />
450450
</button>
@@ -458,28 +458,34 @@ function App() {
458458
<div className="controlPanelContainer">
459459
<h2 className="voiceLabel">
460460
Voice{" "}
461-
<Popover.Root>
462-
<Popover.Trigger asChild>
463-
<button className="iconButton infoButton">
464-
<InfoCircledIcon className="infoButtonIcon" />
465-
</button>
466-
</Popover.Trigger>
467-
<Popover.Portal>
468-
<Popover.Content
469-
className="infoButtonPopover"
470-
side="top"
471-
sideOffset={2}
472-
collisionPadding={8}
461+
<Tooltip.Provider delayDuration={200}>
462+
<Tooltip.Root>
463+
<Tooltip.Trigger
464+
asChild
465+
onClick={(event) => event.preventDefault()}
473466
>
474-
<p>
475-
This extension can only inject audio when your Google Meet
476-
microphone is unmuted. To play sound effects but mute your
477-
microphone, use this button!
478-
</p>
479-
<Popover.Arrow className="infoButtonArrow" />
480-
</Popover.Content>
481-
</Popover.Portal>
482-
</Popover.Root>
467+
<button className="iconButton infoButton">
468+
<InfoCircledIcon className="infoButtonIcon" />
469+
</button>
470+
</Tooltip.Trigger>
471+
<Tooltip.Portal>
472+
<Tooltip.Content
473+
className="infoButtonPopover"
474+
side="top"
475+
sideOffset={2}
476+
collisionPadding={8}
477+
onClick={(event) => event.preventDefault()}
478+
>
479+
<p>
480+
This extension can only inject audio when your Google
481+
Meet microphone is unmuted. To play sound effects but
482+
mute your microphone, use this button!
483+
</p>
484+
<Tooltip.Arrow className="infoButtonArrow" />
485+
</Tooltip.Content>
486+
</Tooltip.Portal>
487+
</Tooltip.Root>
488+
</Tooltip.Provider>
483489
</h2>
484490
<button
485491
className={

extension/src/utils/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ export enum CrossFunctions {
66
SET_VOLUME = "setVolume",
77
GET_MIC_MUTED = "getMicMuted",
88
AUDIO_ENDED = "audioEnded",
9+
SET_AUDIO_PLAYING = "setAudioPlaying",
10+
GET_AUDIO_PLAYING = "getAudioPlaying",
911
OPEN_POPUP = "openPopup",
1012
}

extension/src/utils/db.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ export async function storeSound(id: string, blob: Blob) {
99
});
1010
const existing = await db.get("sounds", id);
1111
if (!existing) {
12-
console.log("Storing sound in IndexedDB:", id);
1312
await db.put("sounds", blob, id);
1413
} else {
15-
console.log("Sound already cached:", id);
1614
}
1715
}
1816

@@ -23,10 +21,8 @@ export async function retrieveSound(id: number): Promise<Blob> {
2321
}
2422

2523
export async function isSoundCached(id: string): Promise<boolean> {
26-
console.log("checking if sound is cached");
2724
const db = await openDB("SoundCacheDB", 1, {
2825
upgrade(db) {
29-
console.log("in upgrade");
3026
if (!db.objectStoreNames.contains("sounds")) {
3127
db.createObjectStore("sounds");
3228
}

ui/src/App.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import "./App.css";
1+
import { useEffect } from "react";
22
import {
3+
Navigate,
4+
Route,
35
BrowserRouter as Router,
46
Routes,
5-
Route,
6-
Navigate,
77
} from "react-router-dom";
8-
import Home from "./components/Home";
8+
import "./App.css";
99
import Folders from "./components/Folders";
10-
import Sidebar from "./components/Sidebar";
1110
import FolderView from "./components/FolderView";
12-
import { useEffect } from "react";
11+
import Home from "./components/Home";
12+
import Sidebar from "./components/Sidebar";
1313

1414
function App() {
1515
useEffect(() => {

ui/src/components/FolderView.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
import { useNavigate, useParams } from "react-router-dom";
3-
import SoundGroup from "./SoundGroup";
4-
import { useEffect } from "react";
5-
import { useQuery } from "@tanstack/react-query";
62
import { UpdateIcon } from "@radix-ui/react-icons";
3+
import { useQuery } from "@tanstack/react-query";
4+
import { useEffect } from "react";
5+
import { useNavigate, useParams } from "react-router-dom";
76
import { API_URL } from "../util/db";
7+
import SoundGroup from "./SoundGroup";
88

99
const FolderView = () => {
1010
const navigate = useNavigate();

0 commit comments

Comments
 (0)