























@@ -327,11 +327,13 @@ function meetStatusScript(params: {
327327autoJoin: boolean;
328328captureCaptions: boolean;
329329guestName: string;
330+readOnly?: boolean;
330331}) {
331332return `() => {
332333 const text = (node) => (node?.innerText || node?.textContent || "").trim();
333334 const allowMicrophone = ${JSON.stringify(params.allowMicrophone)};
334335 const captureCaptions = ${JSON.stringify(params.captureCaptions)};
336+ const readOnly = ${JSON.stringify(Boolean(params.readOnly))};
335337 const buttons = [...document.querySelectorAll('button')];
336338 const buttonLabel = (button) =>
337339 [
@@ -351,7 +353,7 @@ function meetStatusScript(params: {
351353 const input = [...document.querySelectorAll('input')].find((el) =>
352354 /your name/i.test(el.getAttribute('aria-label') || el.placeholder || '')
353355 );
354- if (${JSON.stringify(params.autoJoin)} && input && !input.value) {
356+ if (!readOnly && ${JSON.stringify(params.autoJoin)} && input && !input.value) {
355357 input.focus();
356358 input.value = ${JSON.stringify(params.guestName)};
357359 input.dispatchEvent(new Event('input', { bubbles: true }));
@@ -363,20 +365,20 @@ function meetStatusScript(params: {
363365 const pageUrl = location.href;
364366 const permissionNeeded = /permission needed|microphone problem|speaker problem|allow.*(microphone|camera)|blocked.*(microphone|camera)|permission.*(microphone|camera|speaker)/i.test(permissionText);
365367 const mic = buttons.find((button) => /turn off microphone|turn on microphone|microphone/i.test(button.getAttribute('aria-label') || text(button)));
366- if (!allowMicrophone && mic && /turn off microphone/i.test(mic.getAttribute('aria-label') || text(mic))) {
368+ if (!readOnly && !allowMicrophone && mic && /turn off microphone/i.test(mic.getAttribute('aria-label') || text(mic))) {
367369 mic.click();
368370 notes.push("Muted Meet microphone for observe-only mode.");
369371 }
370- const join = ${JSON.stringify(params.autoJoin)}
372+ const join = !readOnly && ${JSON.stringify(params.autoJoin)}
371373 ? findButton(/join now|ask to join/i)
372374 : null;
373375 if (join) join.click();
374376 const microphoneChoice = findButton(/\\buse microphone\\b/i);
375377 const noMicrophoneChoice = findButton(/\\b(continue|join|use) without (microphone|mic)\\b|\\bnot now\\b/i);
376- if (allowMicrophone && microphoneChoice) {
378+ if (!readOnly && allowMicrophone && microphoneChoice) {
377379 microphoneChoice.click();
378380 notes.push("Accepted Meet microphone prompt with browser automation.");
379- } else if (!allowMicrophone && noMicrophoneChoice) {
381+ } else if (!readOnly && !allowMicrophone && noMicrophoneChoice) {
380382 noMicrophoneChoice.click();
381383 notes.push("Skipped Meet microphone prompt for observe-only mode.");
382384 }
@@ -431,7 +433,7 @@ function meetStatusScript(params: {
431433 }
432434 };
433435 if (captionState) {
434- if (inCall && !captionState.enabledAttempted) {
436+ if (!readOnly && inCall && !captionState.enabledAttempted) {
435437 const captionButton = findButton(/turn on captions|show captions|captions/i);
436438 const captionLabel = captionButton ? (captionButton.getAttribute("aria-label") || captionButton.getAttribute("data-tooltip") || text(captionButton)) : "";
437439 if (captionButton) {
@@ -669,6 +671,7 @@ async function inspectRecoverableMeetTab(params: {
669671callBrowser: BrowserRequestCaller;
670672config: GoogleMeetConfig;
671673mode?: "realtime" | "transcribe";
674+readOnly?: boolean;
672675timeoutMs: number;
673676tab: BrowserTab;
674677targetId: string;
@@ -680,11 +683,13 @@ async function inspectRecoverableMeetTab(params: {
680683body: { targetId: params.targetId },
681684timeoutMs: Math.min(params.timeoutMs, 5_000),
682685});
683-const permissionNotes = await grantMeetMediaPermissions({
684- allowMicrophone,
685-callBrowser: params.callBrowser,
686-timeoutMs: params.timeoutMs,
687-});
686+const permissionNotes = params.readOnly
687+ ? []
688+ : await grantMeetMediaPermissions({
689+ allowMicrophone,
690+callBrowser: params.callBrowser,
691+timeoutMs: params.timeoutMs,
692+});
688693const evaluated = await params.callBrowser({
689694method: "POST",
690695path: "/act",
@@ -696,6 +701,7 @@ async function inspectRecoverableMeetTab(params: {
696701captureCaptions: params.mode === "transcribe",
697702guestName: params.config.chrome.guestName,
698703autoJoin: false,
704+readOnly: params.readOnly,
699705}),
700706},
701707timeoutMs: Math.min(params.timeoutMs, 10_000),
@@ -724,6 +730,7 @@ async function inspectRecoverableMeetTab(params: {
724730export async function recoverCurrentMeetTab(params: {
725731config: GoogleMeetConfig;
726732mode?: "realtime" | "transcribe";
733+readOnly?: boolean;
727734url?: string;
728735}): Promise<{
729736transport: "chrome";
@@ -760,6 +767,7 @@ export async function recoverCurrentMeetTab(params: {
760767callBrowser: callLocalBrowserRequest,
761768config: params.config,
762769mode: params.mode,
770+readOnly: params.readOnly,
763771 timeoutMs,
764772 tab,
765773 targetId,
@@ -771,6 +779,7 @@ export async function recoverCurrentMeetTabOnNode(params: {
771779runtime: PluginRuntime;
772780config: GoogleMeetConfig;
773781mode?: "realtime" | "transcribe";
782+readOnly?: boolean;
774783url?: string;
775784}): Promise<{
776785transport: "chrome-node";
@@ -823,6 +832,7 @@ export async function recoverCurrentMeetTabOnNode(params: {
823832}),
824833config: params.config,
825834mode: params.mode,
835+readOnly: params.readOnly,
826836 timeoutMs,
827837 tab,
828838 targetId,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。