Skip to content

Commit

Permalink
tlsync working
Browse files Browse the repository at this point in the history
  • Loading branch information
sphinxrave committed Nov 17, 2024
1 parent 59cae7d commit 6745095
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 6 deletions.
12 changes: 6 additions & 6 deletions manifest.json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ const manifest = ({
],
host_permissions: ["*://*.youtube.com/*", "*://*.holodex.net/*"],
content_scripts: [
{
matches: ["http://*/*", "https://*/*", "<all_urls>"],
js: ["src/pages/content/index.tsx"],
css: ["contentStyle.css"],
},
// {
// matches: ["http://*/*", "https://*/*", "<all_urls>"],
// js: ["src/pages/content/index.tsx"],
// css: ["contentStyle.css"],
// },
{
matches: ["*://*.youtube.com/live_chat*"], js: ["src/pages/content/yt-chat/yt-chat.ts"], all_frames: true, run_at: "document_end",
}
Expand All @@ -52,4 +52,4 @@ const manifest = ({
// },
}) as const satisfies ManifestV3Export;

export default manifest;
export default manifest;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"type": "module",
"dependencies": {
"protoframe": "^1.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"webext-bridge": "^6.0.1",
Expand Down
11 changes: 11 additions & 0 deletions src/pages/content/yt-chat/tlsyncProtocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ProtoframeDescriptor } from "protoframe";

export const tlsyncProtocol: ProtoframeDescriptor<{
initiate: {
body: { info?: string };
response: { state: "ok" | "failed" };
};
sendMessage: {
body: { text: string };
};
}> = { type: "tlsync_msgs" };
196 changes: 196 additions & 0 deletions src/pages/content/yt-chat/yt-chat.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { inject, validOrigin } from "@src/utils";
import injectPath from "./yt-chat-inject?script&module";
import { ProtoframePubsub } from "protoframe";
import { tlsyncProtocol } from "./tlsyncProtocol";

inject(injectPath);

Expand All @@ -14,3 +16,197 @@ window.addEventListener("message", (event) => {
window.postMessage(event.data, "*");
}
});

//--------------------------------------- SYNC TRANSLATION -------------------------------------------
// Targets for sending translation automation
let SendButtonElement: HTMLButtonElement | null = null;
let InputTextField: HTMLInputElement | null = null;

// Create a status span to display information
const spn = Object.assign(document.createElement("p"), {
textContent: "Looking for the chatbox...",
onmouseover(evt: MouseEvent) {
(evt.target as HTMLElement).style.opacity = "1";
},
onmouseout(evt: MouseEvent) {
(evt.target as HTMLElement).style.opacity = "0.4";
},
});
spn.style.color = "white";
spn.style.opacity = "0.4";
spn.style.width = "calc(100% - 32px)";
spn.style.position = "absolute";
spn.style.textAlign = "center";

// Container for the extension UI
const ExtContainer = Object.assign(document.createElement("div"), {
id: "Extcontainer",
});
ExtContainer.appendChild(spn);

/**
* Sends text to the input field and triggers the send button.
* @param {string} inputtext - The text to send.
*/
function SendTextEnter(inputtext: string) {
if (!InputTextField || !SendButtonElement) {
console.error(
"SendTextEnter called but InputTextField or SendButtonElement is not set."
);
return;
}
console.debug("Sending text:", inputtext);

InputTextField.textContent = inputtext.replaceAll('\\"', '"');
InputTextField.dispatchEvent(new InputEvent("input"));
setTimeout(() => {
SendButtonElement?.click();
console.info("Text sent successfully.");
}, 50);
}

/**
* Sets up the state by locating necessary DOM elements.
* @returns {boolean} True if setup is successful, otherwise false.
*/
function setupState(): boolean {
console.debug("Setting up state...");
SendButtonElement = document.querySelector("#send-button button");
InputTextField = document.querySelector(
"#input.yt-live-chat-text-input-field-renderer"
);

if (!SendButtonElement || !InputTextField) {
console.warn("Failed to locate chatbox elements.");
spn.textContent = "Holodex+ TL Relay [⚠️cannot find message input]";
return false;
} else {
console.info("Chatbox elements located successfully.");
spn.textContent = "Holodex+ TL Relay [✅Connected]";
return true;
}
}

/**
* Attaches event listeners to enable chat relay functionality.
*/
function LatchChatBox() {
console.debug("Latching onto chatbox...");
if (setupState() && SendButtonElement && InputTextField) {
window.addEventListener("message", Bouncer);
console.info("Chatbox latched and message listener attached.");
} else {
console.error("Failed to latch onto chatbox.");
}
}

/**
* Handles incoming messages from valid origins.
* @param {MessageEvent} e - The message event.
*/
function Bouncer(e: MessageEvent) {
if (!validOrigin(e.origin)) {
console.warn("Invalid origin:", e.origin);
return;
}

if (e.data.n === "HolodexSync") {
console.debug("Received HolodexSync message:", e.data);
if (InputTextField) {
SendTextEnter(e.data.d);
} else {
console.error("InputTextField is not set.");
}
}
}

/**
* Initializes the extension by attempting to attach to the chatbox.
* @param {MessageEvent} e - The message event.
*/
function Initializator(e: MessageEvent) {
if (!validOrigin(e.origin)) {
console.warn("Invalid origin during initialization:", e.origin);
return;
}

if (e.data.n === "HolodexSync" && e.data.d === "Initiate") {
console.info("HolodexSync initiation received.");
let attempts = 0;
const intervalId = setInterval(() => {
attempts++;
const target = document.getElementById("chat-messages");

if (target) {
console.info("Chatbox found, setting up UI.");
const prevExtContainer = document.getElementById("Extcontainer");
if (prevExtContainer) {
prevExtContainer.parentNode?.removeChild(prevExtContainer);
console.debug("Removed previous extension container.");
}
target.prepend(ExtContainer);
window.removeEventListener("message", Initializator);
LatchChatBox();
clearInterval(intervalId);
}

if (attempts >= 30) {
console.error("Failed to locate chatbox after 30 attempts.");
clearInterval(intervalId);
}
}, 1000);
}
}

/**
* Entry point for the extension.
*/
function Load() {
if (window.location !== parent.location) {
console.info("Adding Initializator event listener.");
window.addEventListener("message", Initializator);
} else {
console.debug("Skipping load; not in an iframe.");
}
}

// Initialize the extension
Load();

// ProtoframePubsub Manager
const manager = ProtoframePubsub.iframe(tlsyncProtocol);

manager.handleAsk(
"initiate",
async (body): Promise<{ state: "ok" | "failed" }> => {
console.info(
"Holodex+ TL Sync Initiation Requested:",
body,
"at",
new Date()
);

if (body?.info) {
console.debug("Additional initiation info:", body.info);
}

const tgt = document.getElementById("chat-messages");
if (tgt && !tgt.contains(ExtContainer)) {
tgt.prepend(ExtContainer);
console.debug("Extension container prepended to chat-messages.");
}

if (setupState()) {
console.info("Initialization successful.");
return { state: "ok" };
} else {
console.error("Initialization failed.");
return { state: "failed" };
}
}
);

manager.handleTell("sendMessage", (body) => {
console.info("Received message to send:", body.text, "at", new Date());
SendTextEnter(body.text);
});
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2984,6 +2984,11 @@ prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"

protoframe@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/protoframe/-/protoframe-1.1.1.tgz#492c6d9abfe7e785a12e2c6ccc2a1bb6191efee8"
integrity sha512-BkCfi0RWF/Ib4N45RF4xk4i3hd0hnrOLjhl8Yp8JmXprnT8+qK6Ds7KEASPh/q0c8+Xs9N7Qt5zKO7p/XeVcag==

pstree.remy@^1.1.8:
version "1.1.8"
resolved "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz"
Expand Down

0 comments on commit 6745095

Please sign in to comment.