feat: add google-meet-transcripts-extension and caption-extension

This commit is contained in:
Arash_M
2026-06-09 15:15:37 +03:30
parent 4a3db4d59f
commit 12f950d786
44 changed files with 1945 additions and 0 deletions
@@ -0,0 +1 @@
//!function(e,t,c,r,n,s){e.GoogleAnalyticsObject=r,e[r]=e[r]||function(){(e[r].q=e[r].q||[]).push(arguments)},e[r].l=1*new Date,n=t.createElement(c),s=t.getElementsByTagName(c)[0],n.async=1,n.src=chrome.runtime.getURL("analytics/analyticsSource.js"),n.id="laxis-track",s.parentNode.insertBefore(n,s)}(window,document,"script","ga");let firstScript=document.getElementsByTagName("script")[1],s=document.createElement("script");s.src=chrome.runtime.getURL("analytics/load.js"),firstScript.parentNode.insertBefore(s,firstScript);
@@ -0,0 +1 @@
let currentRight="1px",currentTop="100px",startTime=new Date,sessionList=[],bookmarkList=[{color:"crimson",enable:!1,name:"Important",code:"#E94B4B",attributes:{width:"15",height:"18",viewBox:"0 0 15 18",fill:"none"},content:[{type:"path",attributes:{d:"M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416",fill:"#E94B4B"}},{type:"path",attributes:{d:"M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416",stroke:"#E94B4B","stroke-linecap":"round","stroke-linejoin":"round"}}]},{color:"gold",enable:!1,name:"Follow up",code:"#FFD339",attributes:{width:"15",height:"18",viewBox:"0 0 15 18",fill:"none"},content:[{type:"path",attributes:{d:"M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416",fill:"#FFD339"}},{type:"path",attributes:{d:"M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416",stroke:"#FFD339","stroke-linecap":"round","stroke-linejoin":"round"}}]},{color:"yellowGreen",enable:!1,name:"Action",code:"#9CCC65",attributes:{width:"15",height:"18",viewBox:"0 0 15 18",fill:"none"},content:[{type:"path",attributes:{d:"M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416",fill:"#9CCC65"}},{type:"path",attributes:{d:"M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416",stroke:"#9CCC65","stroke-linecap":"round","stroke-linejoin":"round"}}]}];const dateStr=(startTime.getMonth()>8?startTime.getMonth()+1:"0"+(startTime.getMonth()+1))+"-"+(startTime.getDate()>9?startTime.getDate():"0"+startTime.getDate())+"-"+startTime.getFullYear();let autoSaveInterval,meetingStatus=0;
@@ -0,0 +1 @@
const CACHE=[],KEY_TRANSCRIPT_IDS="hangouts",CURRENT_INTERVAL="current_interval",ERROR_SAVING="error_saving",APPLICATION_SPEECH_IDS="speeches",SEARCH_TEXT_NO_MEETING_NAME="Meeting details";let SPEAKER_NAME_MAP,TRANSCRIPT_FORMAT_SPEAKER,TRANSCRIPT_FORMAT_SPEAKER_JOIN,TRANSCRIPT_FORMAT_SESSION_JOIN,TRANSCRIPT_FORMAT_MEETING,DEBUG;const XPATH_SELECTOR_PARTICIPANTS="//div[@aria-label='Show everyone']//*[@d='M15 8c0-1.42-.5-2.73-1.33-3.76.42-.14.86-.24 1.33-.24 2.21 0 4 1.79 4 4s-1.79 4-4 4c-.43 0-.84-.09-1.23-.21-.03-.01-.06-.02-.1-.03A5.98 5.98 0 0 0 15 8zm1.66 5.13C18.03 14.06 19 15.32 19 17v3h4v-3c0-2.18-3.58-3.47-6.34-3.87zM9 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2m0 9c-2.7 0-5.8 1.29-6 2.01V18h12v-1c-.2-.71-3.3-2-6-2M9 4c2.21 0 4 1.79 4 4s-1.79 4-4 4-4-1.79-4-4 1.79-4 4-4zm0 9c2.67 0 8 1.34 8 4v3H1v-3c0-2.66 5.33-4 8-4z']",XPATH_SELECTOR_PARTICIPANTS_V20210602="//button[@aria-label='Show everyone'] | //button[@aria-label='Mostrar a todos'] | //button[@aria-label='显示所有人'] |//button[@aria-label='顯示所有參與者'] |//button[@aria-label='顯示所有人'] | //button[@aria-label='Alle anzeigen'] | //button[@aria-label='Afficher tout le monde'] | //button[@aria-label='全員を表示'] | //button[@aria-label='Mostra tutti'] | //button[@aria-label='Mostrar todas as pessoas'] | //button[@aria-label='Mostrar todos']",XPATH_MEETING_DETAILS='//div[contains(@jscontroller,"rYZP8b")] | //div[@aria-label="Meeting details"]',XPATH_MEETING_DETAILS_V20210602="//button[@aria-label='Meeting details']",XPATH_SELECTOR_CHAT="//div[@aria-label='Chat with everyone']//*[@d='M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H4V4h16v12z']",XPATH_SELECTOR_CHAT_V20210602="//button[@aria-label='Chat with everyone'] | //button[@aria-label='Chatear con todos'] | //button[@aria-label='与所有人聊天'] | //button[@aria-label='與所有參與者進行即時通訊'] | //button[@aria-label='同所有人即時通訊'] | //button[@aria-label='Mit allen chatten'] | //button[@aria-label='Clavarder avec tout le monde'] | //button[@aria-label='全員とチャット'] | //button[@aria-label='Chatta con tutti'] | //button[@aria-label='Conversar com todos'] | //button[@aria-label='Discuter avec tous les participants'] | //button[@aria-label='Chat com todos']",turnOnText=["Turn on captions","Untertitel aktivieren","Activer les sous-titres","Activar subtítulos","Attiva sottotitoli","字幕をオンにする","开启字幕","開啟字幕"],turnOffText=["Turn off captions","Untertitel deaktivieren","Désactiver les sous-titres","Desactivar subtítulos","Disattiva sottotitoli","字幕をオフにする","关闭字幕","關閉字幕"],XPATH_TURN_ON_CAPTIONS_BUTTON=turnOnText.map((t=>`//div[text()='${t}']/ancestor::div[@role='button']`)).join(" | "),XPATH_TURN_ON_CAPTIONS_BUTTON_V20210602=turnOnText.map((t=>`//button[contains(@aria-label, '${t}')]`)).join(" | "),XPATH_TURN_OFF_CAPTIONS_BUTTON=turnOffText.map((t=>`//div[text()='${t}']/ancestor::div[@role='button']`)).join(" | "),XPATH_TURN_OFF_CAPTIONS_BUTTON_V20210602=turnOffText.map((t=>`//button[contains(@aria-label, '${t}')]`)).join(" | "),XPATH_CAPTION_OPEN_TOAST="//div[contains(@id, 'J9Hpafc')]",XPATH_CAPTION_OPEN_TOAST_V20210602="//div[contains(@id, 'J9Hpafc')]",XPATH_TITLE="//div[contains(@jscontroller,'WEGDee')]",XPATH_TITLE_V20220324="//div[contains(@jscontroller,'yEvoid')]",XPATH_TITLE_TOOLTIP="//div[contains(@id,'tooltip-c15')]";let captionsContainer=null,closedCaptionsAttachInterval=null,isTranscribing=!1,weTurnedCaptionsOn=!1,currentTranscriptId=null,currentSessionIndex=null,firstStart=!0,loadLocalStorage=0,startTimeStored=null,loginStatus=0,appUser="You";const SHORTCUT_KEY="DEBUG";
@@ -0,0 +1 @@
const domainUrl="https://app.laxis.tech",extensionId=chrome.runtime.id,loginUrl=domainUrl+"/login?source=chrome-extension&extensionId="+extensionId,upgradeUrl=domainUrl+"/settings/plan",signupUrl=domainUrl+"/signup?source=chrome-extension&extensionId="+extensionId,googleMeetUrl="https://meet.google.com/*";
File diff suppressed because one or more lines are too long
@@ -0,0 +1,251 @@
const addTutorialPanel = () => {
var e, t;
e = chrome.runtime.getURL("feature/utilities/packages/html2pdf.bundle.min.js"), (t = document.createElement("script")).type = "application/javascript", t.src = e, document.head.appendChild(t);
const n = document.getElementById("laxis-root");
let l = document.getElementById("laxis-mainPanel");
if (l) l.style.display = "block";
else {
l = document.createElement("div"), l.setAttribute("id", "laxis-mainPanel"), l.classList.add("panelBase"), l.style.width = "300px", l.style.backgroundColor = "#454953";
const e = document.createElement("div");
e.setAttribute("name", "laxis-rootHeader"), e.style.cursor = "move", e.style.width = "300px", e.style.height = "50px", e.style.backgroundColor = "#454953", e.style.borderRadius = "12px 12px 0 0", e.style.display = "flex", e.style.alignItems = "center", e.style.justifyContent = "space-between";
const t = document.createElement("div");
t.style.display = "flex", t.style.alignItems = "center", t.style.paddingLeft = "8px";
const i = document.createElement("img");
i.src = chrome.runtime.getURL("image/logo.png"), i.addEventListener("click", (function() {
window.open(`${domainUrl}/login`)
})), i.alt = "none", i.style.height = "30px", i.style.width = "90px", i.style.marginLeft = "-16px", i.style.cursor = "pointer", i.style.zIndex = "999", t.appendChild(i), e.appendChild(t);
const o = document.createElement("div");
o.style.display = "flex", o.style.alignItems = "center";
const d = document.createElement("div");
d.classList.add("imageContainer"), d.title = "Minimize", d.addEventListener("click", minimize);
const a = createCollapseIcon();
d.appendChild(a), o.appendChild(d), e.appendChild(o), l.appendChild(e);
let s = document.createElement("div");
s.style.padding = "24px", s.style.fontSize = "14px", s.style.color = "#ffffff", s.style.backgroundColor = "#292c35", s.style.borderRadius = "0 0 12px 12px";
let c = document.createElement("div");
c.innerHTML = "Highlight with colors", s.appendChild(c);
let r = document.createElement("div");
r.style.display = "flex", r.style.alignItems = "center", r.style.justifyContent = "center", bookmarkList.forEach((e => {
let t = document.createElement("div");
t.classList.add("tutorialContainer"), t.style.border = "1px solid #9e9e9e", t.style.backgroundColor = "#454953", t.style.display = "flex", t.style.alignItems = "center", t.style.justifyContent = "center";
let n = createSVGIcon(e.attributes, e.content);
t.appendChild(n), r.appendChild(t)
})), s.appendChild(r);
let p = document.createElement("div");
p.style.textAlign = "center", p.innerHTML = "Use the three main color to hightlight any paragraph during the meeting.", s.appendChild(p);
let m = document.createElement("div");
m.innerHTML = "Select language", m.style.paddingTop = "32px", s.appendChild(m);
let u = document.createElement("div");
u.style.display = "flex", u.style.alignItems = "center", u.style.justifyContent = "center";
const y = document.createElement("div");
y.classList.add("tutorialContainer"), y.style.display = "flex", y.style.alignItems = "center", y.style.justifyContent = "center";
const g = createCaptionOnIcon();
y.appendChild(g), u.appendChild(y), s.appendChild(u);
let h = document.createElement("div");
h.style.textAlign = "center", h.innerHTML = "Laxis supports 69 languages in Google Meet", s.appendChild(h);
let x = document.createElement("div");
x.style.paddingTop = "32px", x.innerHTML = "Download", s.appendChild(x);
let C = document.createElement("div");
C.style.display = "flex", C.style.justifyContent = "center";
let v = document.createElement("div");
v.classList.add("tutorialContainer"), v.style.display = "flex", v.style.alignItems = "center", v.style.justifyContent = "center";
let E = createDownloadIcon();
v.appendChild(E), C.appendChild(v), s.appendChild(C);
let b = document.createElement("div");
b.style.textAlign = "center", b.innerHTML = "Laxis provides multiple formats for downloading the transcripts.", s.appendChild(b), l.appendChild(s), n.appendChild(l), dragElement(n)
}
};
function addRoot() {
const e = document.createElement("div");
e.setAttribute("id", "laxis-root"), e.style.position = "absolute", e.style.zIndex = "2000", e.style.right = currentRight, e.style.top = currentTop, e.style.height = "10px", e.style.width = "10px", document.body.appendChild(e)
}
function addMiniPanel() {
const e = document.getElementById("laxis-root"),
t = document.createElement("div");
t.setAttribute("id", "laxis-miniPanel"), t.classList.add("panelBase"), t.style.width = "60px", t.style.paddingBottom = "16px", t.style.backgroundColor = "#292c35";
const n = document.createElement("div");
n.setAttribute("name", "laxis-rootHeader"), n.style.cursor = "move", n.classList.add("col-12"), n.style.height = "50px", n.style.width = "50px", n.style.marginBottom = "-10px", n.style.cursor = "move", n.style.zIndex = "999";
const l = document.createElement("img");
l.src = chrome.runtime.getURL("image/logo.png"), l.addEventListener("click", (function() {
window.open(`${domainUrl}/login`)
})), l.style.cursor = "pointer", l.style.marginTop = "10px", l.style.height = "25px", l.style.width = "75px", l.style.marginLeft = "-16px", l.alt = "none", n.appendChild(l), t.appendChild(n);
const i = document.createElement("div");
i.title = "Expand", i.id = "laxis-expandPanel", i.classList.add("miniButtonContainer"), i.addEventListener("click", addTutorialPanel);
const o = createExpandIcon();
o.id = "expandInputIcon", i.appendChild(o), t.appendChild(i), e.appendChild(t), dragElement(e)
}
const addCaptionPanel = () => {
const e = findButtonContainer(),
t = document.getElementById("laxis-root");
if (e && !e.__gmt_button_added) {
e.__gmt_button_added = !0;
const n = document.getElementById("laxis-miniPanel"),
l = document.createElement("div");
l.title = "Captions settings", l.setAttribute("id", "laxis-caption-toggle-mini"), l.classList.add("miniButtonContainer"), l.addEventListener("click", getToSettings);
const i = createCaptionOnIcon();
i.id = "captionIconMini", l.appendChild(i), n.appendChild(l);
const o = document.createElement("div");
o.title = "Download", o.setAttribute("id", "laxis-download-menu-mini"), o.classList.add("miniButtonContainer"), o.addEventListener("click", displayMenu);
const d = createDownloadIcon();
d.id = "downloadIconMini", d.style.width = "20px", d.style.height = "20px", o.appendChild(d), n.appendChild(o);
const a = document.createElement("div");
a.style.margin = "12px 5px 0px", a.style.padding = "6px 12px", a.style.borderRadius = "12px", a.style.backgroundColor = "#3e4149";
for (let e = 0; e < bookmarkList.length; e++) {
const t = document.createElement("div"),
n = document.createElement("div");
t.style.display = "flex", t.style.flexDirection = "column", t.style.alignItems = "center", n.title = `Highlight as ${bookmarkList[e].name}`, n.classList.add("flagContainerMini"), n.id = `laxis-highlight-${bookmarkList[e].code}-mini`, n.onclick = () => {
highlight(e)
};
const l = createSVGIcon(bookmarkList[e].attributes, bookmarkList[e].content);
n.appendChild(l), t.appendChild(n), a.appendChild(t)
}
n.appendChild(a), n.style.display = "block";
let s = document.getElementById("laxis-mainPanel");
s && t.removeChild(s);
const c = document.createElement("div");
c.setAttribute("id", "laxis-mainPanel"), c.classList.add("panelBase"), c.style.width = "300px", c.style.display = "none";
const r = document.createElement("div");
r.setAttribute("name", "laxis-rootHeader"), r.style.cursor = "move", r.style.width = "300px", r.style.height = "50px", r.style.backgroundColor = "#454953", r.style.borderRadius = "12px 12px 0 0", r.style.display = "flex", r.style.alignItems = "center", r.style.justifyContent = "space-between";
const p = document.createElement("div");
p.style.display = "flex", p.style.alignItems = "center", p.style.paddingLeft = "8px";
const m = document.createElement("img");
m.src = chrome.runtime.getURL("image/logo.png"), m.alt = "none", m.addEventListener("click", (function() {
window.open(`${domainUrl}/login`)
})), m.style.height = "30px", m.style.marginLeft = "-16px", m.style.cursor = "pointer", m.style.zIndex = "999", p.appendChild(m), r.appendChild(p);
const u = document.createElement("div");
u.style.display = "flex", u.style.alignItems = "center";
const y = document.createElement("div");
y.title = "Retrieve local data", y.setAttribute("id", "laxis-repair"), y.classList.add("imageContainer"), y.style.display = "none", y.addEventListener("click", extractLocalStorage);
const g = document.createElement("img");
g.id = "restoreIcon", g.src = chrome.runtime.getURL("image/repair.svg"), g.style.width = "15px", g.style.height = "18px", y.appendChild(g), u.appendChild(y);
const h = document.createElement("div");
h.title = "Captions settings", h.setAttribute("id", "laxis-caption-toggle"), h.classList.add("imageContainer"), h.addEventListener("click", getToSettings);
const x = createCaptionOnIcon();
x.id = "captionIcon", h.appendChild(x), u.appendChild(h);
const C = document.createElement("div");
C.title = "Auto-Scroll", C.setAttribute("id", "laxis-autoScroll");
const v = document.createElement("input");
v.type = "hidden", v.value = 1, v.setAttribute("id", "autoscroll"), v.onchange = () => autoScroll(), C.appendChild(v), C.classList.add("imageContainer"), C.addEventListener("click", (function() {
let e = document.getElementById("autoscroll");
"0" === e.value.toString() ? e.value = 1 : e.value = 0, autoScroll()
}));
const E = createAutoScrollIcon();
E.style.width = "15px", E.style.height = "15px", C.appendChild(E), u.appendChild(C);
const b = document.createElement("div");
b.title = "Download", b.id = "laxis-openDownloadMenu", b.classList.add("imageContainer"), b.addEventListener("click", displayMenu);
const f = createDownloadIcon();
f.style.width = "15px", f.style.height = "15px", b.appendChild(f), u.appendChild(b);
const L = document.createElement("div");
L.title = "Minimize", L.id = "laxis-minimizePanel", L.classList.add("imageContainer"), L.addEventListener("click", minimize);
const k = createCollapseIcon();
k.style.width = "15px", k.style.height = "15px", L.appendChild(k), u.appendChild(L), r.appendChild(u), c.appendChild(r);
const I = document.createElement("div");
I.style.width = "300px", I.style.backgroundColor = "#292c35", I.style.paddingTop = "8px";
const w = document.createElement("div");
w.id = "login-prompt", w.style.display = "none", w.style.margin = "0px 8px", w.style.padding = "4px", w.style.textAlign = "center", w.addEventListener("click", signup), w.style.cursor = "pointer", w.innerHTML = "Please <span style='color:#2196f3'>log in</span> to enable autosave to Laxis Cloud.", w.style.borderRadius = "12px", w.style.border = "1px solid rgba(255, 255, 255, 0.5)", w.style.backgroundColor = "#454953", w.style.color = "#ffffff", w.style.fontSize = "10px";
const T = document.createElement("div");
T.id = "google-meet-quota", T.style.display = "none", T.style.margin = "0px 8px", T.style.padding = "4px", T.style.textAlign = "center", T.addEventListener("click", upgrade), T.style.cursor = "pointer", T.innerHTML = "Used Google Meet Quota: ", T.style.borderRadius = "12px", T.style.border = "1px solid rgba(255, 255, 255, 0.5)", T.style.backgroundColor = "#454953", T.style.color = "#ffffff", T.style.fontSize = "10px";
const M = document.createElement("div");
M.id = "meeting-name", M.style.fontWeight = "bold", M.style.padding = "8px", M.style.color = "#FFFFFF", I.appendChild(w), I.appendChild(T), I.appendChild(M);
const B = document.createElement("div");
B.style.paddingTop = "8px", B.style.width = "25%", I.style.paddingBottom = "8px", c.appendChild(I);
const S = document.createElement("div");
S.setAttribute("id", "feature"), S.style.width = "300px", S.style.backgroundColor = "#292c35", S.style.borderRadius = "0 0 12px 12px";
const A = document.createElement("div");
A.setAttribute("id", "caption"), A.style.height = "350px", A.style.width = "300px", A.style.overflowY = "auto", A.style.overflowX = "hidden", A.style.color = "#FFFFFF", A.style.paddingRight = "8px", A.onwheel = () => {
v.value = 0
}, S.appendChild(A);
const H = document.createElement("div");
H.id = "highlight-laxis", H.style.width = "300px", H.style.backgroundColor = "#292c35", H.style.display = "flex", H.style.justifyContent = "space-around", H.style.borderTop = "1px solid #e0e0e0", H.style.paddingTop = "10px", H.style.paddingBottom = "10px", H.classList.add("popup"), H.style.borderRadius = "0 0 12px 12px";
for (let e = 0; e < bookmarkList.length; e++) {
const t = document.createElement("div"),
n = document.createElement("div");
t.style.display = "flex", t.style.flexDirection = "column", t.style.alignItems = "center", n.style.textAlign = "center", n.style.fontSize = "10px", n.style.color = "#9e9e9e", n.style.marginTop = "4px", n.innerHTML = bookmarkList[e].name, n.id = `laxis-highlight-${bookmarkList[e].code}-title`;
const l = document.createElement("div");
l.title = `Highlight as ${bookmarkList[e].name}`, l.classList.add("flagContainer"), l.id = `laxis-highlight-${bookmarkList[e].code}`;
const i = createSVGIcon(bookmarkList[e].attributes, bookmarkList[e].content);
l.appendChild(i), l.onclick = () => {
highlight(e)
}, t.appendChild(l), t.appendChild(n), H.appendChild(t)
}
let N = document.createElement("div");
N.id = "popup", N.className = "popupText", N.innerHTML = "Test", N.onclick = () => {
clearTimeout(notificationsTimeout), N.classList.remove("show")
}, H.appendChild(N), S.appendChild(H), c.appendChild(S), t.appendChild(c), dragElement(t), autoScroll(), document.getElementById("laxis-downloadMenu") || addDownloadMenu(), checkCaptionStatusInterval = setInterval(checkCaptionStatus, 500), turnOnCaptions(), debug("turned on caption"), removeCaptionPanel(), checkToken(), autoSaveInterval = setInterval((() => {
let e = document.getElementById("autoSaveCheck");
e && e.checked && Export2App(!0).catch((e => {
console.error(e);
const t = get(ERROR_SAVING) || [];
set(ERROR_SAVING, [...t, e])
}))
}), 3e5), setTimeout(updateMeetingName, 500), clearInterval(checkOngoingMeeting)
}
},
addDownloadMenu = () => {
let e = document.createElement("div");
e.id = "laxis-downloadMenu", e.className = "modal", e.style.display = "none";
let t = document.createElement("div");
t.className = "modal-content", t.id = "laxis-downloadMenuContent";
let n = document.createElement("div");
n.className = "modal-header", n.innerHTML = "Download", t.appendChild(n);
let l = document.createElement("div"),
i = document.createElement("div");
i.className = "modal-body", i.innerHTML = "File Type<select name='extension' id='extension' value='txt'><option value='txt'>txt</option><option value='app'>Laxis Cloud</option><option value='doc'>doc</option><option value='pdf'>pdf</option></select>", l.appendChild(i);
let o = document.createElement("div");
o.className = "modal-body", o.innerHTML = "<div>Highlights</div><div><input type='checkbox' name='highlightCheck' id='highlightCheck' checked='true'/></div>", l.appendChild(o);
let d = document.createElement("div");
d.className = "modal-body", d.innerHTML = "<div>Timestamps</div><div><input type='checkbox' name='timestampCheck' id='timestampCheck'/></div>", l.appendChild(d);
let a = document.createElement("div");
a.className = "modal-body", a.title = "Autosave to Laxis every 5 minutes", a.style.cursor = "help", a.innerHTML = "<div>Autosave to Laxis Cloud</div><div><input type='checkbox' name='autoSaveCheck' id='autoSaveCheck'/></div>", l.appendChild(a), t.appendChild(l);
let s = document.createElement("div");
s.className = "modal-footer";
let c = document.createElement("button");
c.classList.add("modal-button"), c.id = "laxis-close-menu", c.style.border = "solid 2px #292c35", c.style.backgroundColor = "#454953", c.innerHTML = "Cancel", c.onclick = () => {
document.getElementById("laxis-downloadMenu").style.display = "none"
}, s.appendChild(c);
let r = document.createElement("button");
r.classList.add("modal-button"), r.style.backgroundColor = "#292c35", r.style.boxShadow = "box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.29)", r.innerHTML = "Download", r.addEventListener("click", downloadTranscript), r.setAttribute("id", "laxis-confirm-download"), s.appendChild(r), t.appendChild(s), e.appendChild(t);
const p = document.getElementById("laxis-root");
p && p.appendChild(e)
},
minimize = () => {
const e = document.getElementById("laxis-mainPanel"),
t = document.getElementById("laxis-miniPanel");
e.style.display = "none", t.style.display = "block"
},
autoScroll = () => {
let e = document.getElementById("laxis-autoScroll");
e.style.border = "1px solid #2196f3";
const t = document.getElementById("caption"),
n = document.getElementById("autoscroll"),
l = setInterval((function() {
"0" === n.value.toString() ? (clearInterval(l), e.style.border = "1px solid #292c35") : t.scrollTop = t.scrollHeight
}), 1e3)
},
updateMeetingName = () => {
const e = document.getElementById("meeting-name");
getMeetingName() ? (e.innerHTML = getMeetingName(), chrome.runtime.sendMessage({
type: "meetingName",
meetingName: getMeetingName()
})) : (e.innerHTML = getDefaultName(), chrome.runtime.sendMessage({
type: "meetingName",
meetingName: getDefaultName()
}))
},
highlight = e => {
let t = document.getElementById("highlight-laxis"),
n = document.getElementById("popup"),
l = document.getElementById("laxis-miniPanel");
weTurnedCaptionsOn ? bookmarkList.forEach(((l, i) => {
const o = t.childNodes[i].childNodes[0],
d = t.childNodes[i].childNodes[1],
a = document.getElementById(`laxis-highlight-${bookmarkList[i].code}-mini`);
i === e ? l.enable ? (l.enable = !1, o.style.backgroundColor = "", a.style.backgroundColor = "", d.style.color = "#9e9e9e", clearTimeout(notificationsTimeout), n.classList.remove("show")) : (l.enable = !0, o.style.backgroundColor = "#696969", a.style.backgroundColor = "#696969", d.style.color = "#ffffff", n.innerHTML = "Your conversation is being highlighted.", n.style.backgroundColor = "#454953", n.style.color = l.code, n.classList.add("show"), clearTimeout(notificationsTimeout), notificationsTimeout = setTimeout((() => {
n.classList.remove("show")
}), notificationsTimeoutDuration)) : (l.enable = !1, o.style.backgroundColor = "", a.style.backgroundColor = "", d.style.color = "#9e9e9e")
})) : (l.style.display && alert("Your caption is turned off"), n.style.backgroundColor = "#818388", n.style.color = "#292c35", n.innerHTML = "Your caption is turned off", n.classList.add("show"), clearTimeout(notificationsTimeout), notificationsTimeout = setTimeout((() => {
n.classList.remove("show")
}), notificationsTimeoutDuration))
};
@@ -0,0 +1,54 @@
const stopTranscribing = () => {
debug("call stopTranscribing"), notificationsOff(), clearInterval(closedCaptionsAttachInterval), closedCaptionsAttachInterval = null, captionContainerChildObserver.disconnect(), captionContainerAttributeObserver.disconnect()
},
startTranscribing = () => {
debug("call startTranscribing"), currentSessionIndex = null, closedCaptionsAttachInterval = setInterval(tryTo(closedCaptionsAttachLoop, "attach to captions"), 1e3), setCurrentTranscriptDetails()
},
toggleTranscribing = () => {
debug("call toggleTranscribing"), isTranscribing ? stopTranscribing() : startTranscribing(), isTranscribing = !isTranscribing
},
turnOnCaptions = () => {
const t = getElementWithXPathFallback(document, XPATH_TURN_ON_CAPTIONS_BUTTON, XPATH_TURN_ON_CAPTIONS_BUTTON_V20210602);
return debug("captionsButtonOn", t), t && (t.click(), notificationsOn()), t
},
turnOffCaptions = () => {
const t = getElementWithXPathFallback(document, XPATH_TURN_OFF_CAPTIONS_BUTTON, XPATH_TURN_OFF_CAPTIONS_BUTTON_V20210602);
return debug("captionsButtonOff", t), t && (t.click(), notificationsOff()), t
},
turnOnCaptionNotificationsOn = () => {
const t = document.getElementById("popup");
t.style.backgroundColor = "#818388", t.style.color = "#292c35", t.innerHTML = "Please turn on captions", t.classList.add("show"), clearTimeout(notificationsTimeout), notificationsTimeout = setTimeout((() => {
t.classList.remove("show")
}), 500)
},
notificationsOn = () => {
const t = document.getElementById("laxis-caption-toggle"),
n = document.getElementById("laxis-caption-toggle-mini"),
i = document.getElementById("captionIcon"),
o = document.getElementById("captionIconMini");
t.removeChild(i), n.removeChild(o);
const e = createCaptionOnIcon(),
c = createCaptionOnIcon();
e.id = "captionIcon", e.style.width = "15px", e.style.height = "15px", t.appendChild(e), c.id = "captionIconMini", c.style.width = "15px", c.style.height = "15px", n.appendChild(c);
const s = document.getElementById("popup");
s.style.backgroundColor = "#818388", s.style.color = "#292c35", s.innerHTML = "Your caption is turned on", s.classList.add("show"), clearTimeout(notificationsTimeout), notificationsTimeout = setTimeout((() => {
s.classList.remove("show")
}), notificationsTimeoutDuration)
},
notificationsOff = () => {
const t = document.getElementById("laxis-caption-toggle"),
n = document.getElementById("laxis-caption-toggle-mini"),
i = document.getElementById("captionIcon"),
o = document.getElementById("captionIconMini");
t.removeChild(i), n.removeChild(o);
const e = createCaptionOffIcon(),
c = createCaptionOffIcon();
e.id = "captionIcon", e.style.width = "15px", e.style.height = "15px", t.appendChild(e), c.id = "captionIconMini", c.style.width = "15px", c.style.height = "15px", n.appendChild(c);
const s = document.getElementById("popup");
s.style.backgroundColor = "#818388", s.style.color = "#292c35", s.innerHTML = "Your caption is turned off", s.classList.add("show"), clearTimeout(notificationsTimeout), notificationsTimeout = setTimeout((() => {
s.classList.remove("show")
}), notificationsTimeoutDuration)
},
toggleCaptions = () => {
debug("call toggleCaptions"), weTurnedCaptionsOn ? turnOffCaptions() : turnOnCaptions(), weTurnedCaptionsOn = !weTurnedCaptionsOn
};
@@ -0,0 +1,116 @@
const findCaptionsContainer = () => {
let e = document.querySelector('div[jsname="dsyhDe"]');
return e || (e = document.querySelector('div[jscontroller="D1tHje"] > div > div:first-child')), e && (captionContainerChildObserver.observe(e, {
childList: !0,
subtree: !0,
characterData: !0
}), captionContainerAttributeObserver.observe(e, {
attributes: !0,
subtree: !1,
attributeOldValue: !0
}), Array.from(e.children).forEach(tryTo((e => {
updateCurrentTranscriptSession(e)
}), "handling child node")), debug("Final CaptionsContainer", e)), e
},
findCaptionsContainerObsolete = () => {
captionContainerChildObserver.disconnect(), captionContainerAttributeObserver.disconnect();
const e = {},
t = Array.from(document.querySelectorAll("img")).filter((e => e.src.match(/\.googleusercontent\.com\//)));
for (let n of t) n.className in e || (e[n.className] = []), e[n.className].push(n);
const n = [];
for (let t of Object.values(e)) {
let e = 0;
for (let n of t) {
const t = document.evaluate("..//span", n.parentElement, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
let r;
for (; r = t.iterateNext();)
if (0 === r.children.length && r.textContent.length > 3) {
e += 1;
break
}
}
if (e !== t.length) continue;
let r = null;
if (t.length >= 2) {
const e = [...t];
let n = null,
o = !1;
do {
for (let t in e) {
if (!e[t].parent) {
o = !0;
break
}
e[t] = e[t].parent, 0 === t ? n = e[t] : n && n !== e[t] && (n = null), debug("current", n)
}
} while (null === n && !1 === o);
r = n
} else {
let e = t[0];
for (; null === r && e;) e.getAttribute("jscontroller") ? r = e : e = e.parentNode
}
if (r) {
const e = r?.firstChild?.firstChild?.tagName;
debug("first grand child tag name", e);
const t = "IMG" === e ? r : r.firstChild.firstChild;
debug("caption container candidate", t), null !== t && n.push(t)
}
}
if (1 === n.length) return captionContainerChildObserver.observe(n[0], {
childList: !0,
subtree: !0,
characterData: !0
}), captionContainerAttributeObserver.observe(n[0], {
attributes: !0,
subtree: !1,
attributeOldValue: !0
}), Array.from(n[0].children).forEach(tryTo((e => {
updateCurrentTranscriptSession(e)
}), "handling child node")), debug("Final CaptionsContainer", n[0]), n[0]
},
captionContainerChildObserver = new MutationObserver(tryTo((e => {
for (let t of e)
if (debug("mutation target", t.target), t.target === captionsContainer) {
debug("update with added nodes");
for (let e of t.addedNodes) updateCurrentTranscriptSession(e)
} else {
const e = Array.from(t.addedNodes).filter((e => "SPAN" === e.nodeName || "#text" === e.nodeName)),
n = Array.from(t.removedNodes).filter((e => "SPAN" === e.nodeName || "#text" === e.nodeName));
if (debug("addedSpansOrTexts", e), "characterData" === t.type || e.length > 0 || n.length > 0) {
let e = t.target;
for (; e && e.parentNode !== captionsContainer;) e = e.parentNode;
if (!e) {
debug("could not find root for", t.target);
continue
}
if (debug("update with parent node"), e.querySelector("button")) {
let t = Array.from(e.children),
n = t.slice(0, t.length - 1).slice(-4);
for (let e of n) updateCurrentTranscriptSession(e)
} else updateCurrentTranscriptSession(e)
}
}
}), "executing observer")),
captionContainerAttributeObserver = new MutationObserver(tryTo((e => {
for (let t of e)
if ("style" === t.attributeName) {
const e = t.target.getAttribute("style");
"display: none;" === t.oldValue && "" === e && (currentSessionIndex = null)
}
}), "executing observer"));
let isCaptionTurnedOn = !1;
const closedCaptionsAttachLoop = () => {
if (captionsContainer = findCaptionsContainer(), captionsContainer) debug("attached to closed captions"), isCaptionTurnedOn = !0, clearInterval(closedCaptionsAttachInterval);
else if (!hasCaptionButtons) {
if (isCaptionTurnedOn) return;
if (getElementWithXPathFallback(document, XPATH_CAPTION_OPEN_TOAST, XPATH_CAPTION_OPEN_TOAST_V20210602)) return popup.classList.remove("show"), isCaptionTurnedOn = !0, notificationsOn(), void clearInterval(closedCaptionsAttachInterval);
isCaptionTurnedOn || turnOnCaptionNotificationsOn()
}
},
removeCaptionPanel = () => {
// debug("start remove caption panel");
// const e = document.querySelector('div[jscontroller="D1tHje"]');
// debug("googleMeetCaptionsPanel", e), e && (e.style = "height: 0px", turnOffCaptions(), setTimeout((() => {
// turnOnCaptions()
// }), 500))
};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
const parents=e=>{const t=[e];for(;e;e=e.parentNode)t.unshift(e);return t},getCommonAncestor=(e,t)=>{const n=parents(e),o=parents(t);if(n[0]===o[0])for(let e=0;e<n.length;e++)if(n[e]!==o[e])return n[e-1]},xpath=(e,t=document)=>document.evaluate(e,t,null,XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue,findButtonContainer=()=>{const e=getElementWithXPathFallback(document,XPATH_MEETING_DETAILS,XPATH_MEETING_DETAILS_V20210602),t=getElementWithXPathFallback(document,XPATH_SELECTOR_CHAT,XPATH_SELECTOR_CHAT_V20210602);return getCommonAncestor(e,t)},getElementWithXPathFallback=(e,t,n)=>xpath(t,e)||xpath(n,e),displayMenu=()=>{document.getElementById("laxis-downloadMenu").style.display="block"},dragElement=e=>{let t=0,n=0,o=0,l=0;function u(e){(e=e||window.event).preventDefault(),o=e.clientX,l=e.clientY,document.onmouseup=c,document.onmousemove=a}function a(u){(u=u||window.event).preventDefault(),t=o-u.clientX,n=l-u.clientY,o=u.clientX,l=u.clientY,e.style.top=e.offsetTop-n+"px",e.style.left=e.offsetLeft-t+"px",currentTop=e.style.top,currentRight=e.style.right}function c(){document.onmouseup=null,document.onmousemove=null}document.getElementsByName(e.id+"Header")?document.getElementsByName(e.id+"Header").forEach((e=>{e.onmousedown=u})):e.onmousedown=u};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
window.__gmt_get=t=>get(`setting.${t}`),window.__gmt_set=(t,e)=>{set(`setting.${t}`,e),syncSettings()},window.__gmt_remove=t=>{remove(`setting.${t}`),syncSettings()};const syncSettings=()=>{TRANSCRIPT_FORMAT_MEETING=getOrSet("setting.transcript-format-meeting","# $year$-$month$-$day$ $name$\n\n$text$"),TRANSCRIPT_FORMAT_SESSION_JOIN=getOrSet("setting.transcript-format-session-join","\n\n...\n\n"),TRANSCRIPT_FORMAT_SPEAKER=getOrSet("setting.transcript-format-speaker","$hour$:$minute$:$second$\n $name$: $text$"),TRANSCRIPT_FORMAT_SPEAKER_JOIN=getOrSet("setting.transcript-format-speaker-join","\n\n"),SPEAKER_NAME_MAP=getOrSet("setting.speaker-name-map",{}),DEBUG=getOrSet("setting.debug",!1)};
@@ -0,0 +1 @@
const makeFullKey=e=>`__laxis_${e}`,makeTranscriptKey=(...e)=>{const[t,r,o]=e,n=[`hangout_${t}`];return e.length>=2&&(n.push(`session_${r}`),e.length>=3&&n.push(`speaker_${o}`)),n.join("_")},get=e=>{const t=window.localStorage.getItem(makeFullKey(e));return"string"==typeof t||t instanceof String?(debug(e,t),JSON.parse(t)):t},set=(e,t,r=!1)=>{const o=makeFullKey(e),n=JSON.stringify(t),a=makeFullKey("rotationKeys");let s=JSON.parse(window.localStorage.getItem(a))||[],i=new Set(s);for(;;)try{window.localStorage.setItem(o,n),r&&(i.add(o),window.localStorage.setItem(a,JSON.stringify(Array.from(i))));break}catch(e){if(e instanceof DOMException&&("QuotaExceededError"===e.name||e.code===DOMException.QUOTA_EXCEEDED_ERR)){if(console.log("Local storage quota exceeded! Deleting old keys to make room for new ones. This may take a while..."),debug("Local storage quota exceeded! Deleting old keys to make room for new ones. This may take a while..."),i.size>0){for(let e=0;e<5&&i.size>0;e++){const e=i.values().next().value;i.delete(e),window.localStorage.removeItem(e)}window.localStorage.setItem(a,JSON.stringify(Array.from(i)));continue}console.error("No keys available to delete.");break}console.error("Unexpected error:",e);break}},remove=e=>{debug(`remove ${makeFullKey(e)}`),window.localStorage.removeItem(makeFullKey(e))},getOrSet=(e,t)=>{const r=get(e);return null==r?(set(e,t),t):r},increment=e=>{const t=get(e);if(null==t)return set(e,0),0;{let r=t+1;return set(e,r),r}},setSpeaker=e=>{set(makeTranscriptKey(e.transcriptId,e.sessionIndex,e.speakerIndex),{image:e.image,person:e.person,text:e.text,startedAt:e.startedAt,endedAt:e.endedAt,highlight:e.highlight},!0)},getTranscript=e=>{const t=get(makeTranscriptKey(e))||0;let r=[];const o=get(makeTranscriptKey(e,t))||0;for(let n=0;n<=o;n+=1){const o=get(makeTranscriptKey(e,t,n));if(o&&o.text&&o.text.match(/\S/g)){startTimeStored||(startTimeStored=new Date(o.startedAt),startTime=new Date(o.startedAt));const a={transcriptId:e,sessionIndex:t,speakerIndex:n,person:o.person in SPEAKER_NAME_MAP?SPEAKER_NAME_MAP[o.person]:o.person,startedAt:new Date(o.startedAt),endedAt:new Date(o.endedAt),image:o.image,text:o.text,highlight:o.highlight};r.push(a)}}return r},deleteTranscript=e=>{const t=get(makeTranscriptKey(e));for(let r=0;r<=t;r+=1){const t=get(makeTranscriptKey(e,r));for(let o=0;o<=t;o+=1)remove(makeTranscriptKey(e,r,o));remove(makeTranscriptKey(e,r))}remove(makeTranscriptKey(e)),get(makeTranscriptKey(`${e}_name`))&&remove(makeTranscriptKey(`${e}_name`));let r=get(KEY_TRANSCRIPT_IDS)||[],o=get(APPLICATION_SPEECH_IDS)||[];const n=r.indexOf(e),a=o.findIndex((t=>t.ext===e));r.splice(n,1),o.splice(a,1),debug("would set transcript to",r),debug("would set transcript pairs to",o),set(KEY_TRANSCRIPT_IDS,r),set(APPLICATION_SPEECH_IDS,o);const s=document.querySelector(`#${e}`);if(s){const e=s.parentNode;e.removeChild(s),0===e.children.length&&(e.parentNode.removeChild(e.previousSibling),e.parentNode.removeChild(e))}else debug(`transcriptNode doesn't exist for ${e}`)},deletePreviousTranscripts=()=>{let e=get(KEY_TRANSCRIPT_IDS)||[];if(e.length>1)for(let t of e)t!==currentTranscriptId&&deleteTranscript(t)};
@@ -0,0 +1,289 @@
const getTranscriptText = (e, t) => {
let o = [];
sessionList.forEach((e => {
o.unshift(e)
}));
let n = "<div>",
i = {};
n += "<div style='font-size:20pt; color: #2F5496'>Transcripts<br></div>", o.forEach(((s, a) => {
if (s.text && s.text.length && (0 === a || s.startedAt !== o[a - 1].startedAt)) {
let o = "",
a = "You" === s.person ? appUser : s.person;
if (s.highlight.length && e && (o = s.highlight[0], s.highlight[0])) {
let e = s.highlight[0],
t = i[e] ? i[e] : [];
t.push({
text: s.text,
time: getTimeStr(startTime, s.startedAt),
person: a
}), i[e] = t
}
if (n += "<div style='font-size:11pt'>", n = n + "<i style='color:#9e9e9e'>" + a, t && (n += ` (${getTimeStr(startTime,s.startedAt)})`), n += ": </i>", e && o.length) {
const e = bookmarkList.find((e => e.color === o)).code;
n += `<div style="color:${e}; display:inline">`
}
n += s.text, e && o.length && (n += "</div>"), n += "<br><br></div>"
}
})), n += "</div>";
let s = "";
return e && (s += "<div>", s += "<div style='font-size:20pt; color: #2F5496'>Highlights<br></div>", Object.keys(i).forEach((e => {
let t = bookmarkList.find((t => t.color === e)),
o = t.name,
n = t.code;
s += "<div>", s += `<span style="color:${n}; font-weight:bold; font-size:14pt">${o}:<br></span>`, i[e].forEach((e => {
s += `<div style='font-size:11pt'><i style='color:#9e9e9e'>${e.person} (${e.time}): </i>${e.text}<br><br></div>`
})), s += "</div>"
})), s += "</div>"), `<div style='font-family:calibri'><div style='font-size:14pt'>${startTime}<br></div>` + s + n + "</div>"
},
Export2Txt = (e, t = "") => {
let o = document.createElement("a"),
n = e.replaceAll("<br>", "\n"),
i = document.createElement("div");
i.style.display = "none", i.innerHTML = n;
let s = i.innerText;
const a = new File([s], "filename"),
d = URL.createObjectURL(a);
return o.href = d, o.download = `${t}.txt`, document.body.appendChild(o), o.click(), document.body.removeChild(o), Promise.resolve(1)
},
Export2Pdf = (e, t = "") => {
const o = window.html2pdf;
t = t ? t + ".pdf" : `${getDefaultName()}.pdf`;
let n = document.createElement("div");
n.innerHTML = e, document.body.appendChild(n);
const i = {
margin: [8, 16, 8, 16],
filename: `${t}.pdf`,
enableLinks: !1,
pagebreak: {
avoid: ["div"],
mode: ["css"]
},
image: {
type: "jpeg",
quality: 1
},
html2canvas: {
allowTaint: !0,
dpi: 144,
letterRendering: !0,
logging: !1,
scale: 2,
scrollX: 0,
scrollY: 0
}
};
return new Promise(((e, t) => {
o().from(n).set(i).toPdf().get("pdf").then((e => {
const t = e.internal.getNumberOfPages();
for (let o = 1; o < t + 1; o++) e.setPage(o), e.setFontSize(14), e.text(`${o}/${t}`, e.internal.pageSize.getWidth() - 10, e.internal.pageSize.getHeight() - 5);
document.body.removeChild(n)
})).save().then((() => {
e("Downloaded")
})).catch((e => t(e)))
}))
},
Export2Word = (e, t = "") => {
var o = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Export HTML To Doc</title></head><body>" + e + "</body></html>",
n = new Blob(["\ufeff", o], {
type: "application/msword"
}),
i = "data:application/vnd.ms-word;charset=utf-8," + encodeURIComponent(o);
t = t ? `${t}.doc` : `${getDefaultName()}.doc`;
var s = document.createElement("a");
return document.body.appendChild(s), navigator.msSaveOrOpenBlob ? navigator.msSaveOrOpenBlob(n, t) : (s.href = i, s.download = t, s.click()), document.body.removeChild(s), Promise.resolve(1)
},
disableSaveToLaxisCloud = e => {
const t = document.getElementById("laxis-confirm-download");
t && (t.disabled = e, t.style.color = t.disabled ? "#999" : "");
const o = document.getElementById("extension");
o && (o.onchange = () => {
t && (t.disabled = e && "app" === o.value, t.style.color = t.disabled ? "#999" : "")
});
const n = document.getElementById("autoSaveCheck");
n && (n.disabled = e)
},
displayGoogleMeetQuota = (e, t) => {
const o = document.getElementById("google-meet-quota");
o && -1 !== t && 0 !== t && (e < t ? (o.innerHTML = `Autosave to Laxis cloud: ${e.toFixed(0)} / ${t.toFixed(0)} minutes. <br/> Please <span style='color: #2196f3;'>upgrade</span> to enjoy unlimited autosave.`, disableSaveToLaxisCloud(!1)) : (o.innerHTML = `Autosave to Laxis cloud: <span style='color: #E94B4B;'>${e.toFixed(0)} / ${t.toFixed(0)}</span> minutes. <br/> Please <span style='color: #2196f3;'>upgrade</span> to enjoy unlimited autosave.`, disableSaveToLaxisCloud(!0)), o.style.display = "block")
},
reDisplayPrompt = () => {
const e = document.getElementById("login-prompt");
e && (e.style.display = "block"), chrome.storage.local.remove("token")
},
addRemindLogin = () => {
console.log("add login");
const e = document.getElementById("laxis-miniPanel"),
t = document.getElementById("laxis-expandPanel"),
o = document.createElement("div");
o.title = "Login to autosave notes", o.id = "laxis-remindLogin", o.style.width = "40px", o.style.height = "40px", o.classList.add("miniButtonContainer"), o.style.border = "0", o.addEventListener("click", signup), o.style.padding = "0";
const n = createRemindLoginIcon();
n.id = "remindLoginIcon", o.appendChild(n), n.id = "remindLoginIcon", o.style.display = "none", e.insertBefore(o, t)
},
reDisplayRemindLogin = () => {
console.log("redisplay");
const e = document.getElementById("laxis-remindLogin");
e && (e.style.display = "block"), chrome.storage.local.remove("token")
},
getTopics = (e, t) => window.fetch(`${domainUrl}/api/v2/templates/${e}/topics`, t),
Export2App = async (e, t = !1) => new Promise(((o, n) => {
chrome.storage.local.get(["token"], (function(i) {
if (i.token) {
let s = document.getElementById("laxis-openDownloadMenu"),
a = document.getElementById("laxis-download-menu-mini");
s.classList.add("loading"), a.classList.add("loading"), window.fetch(`${domainUrl}/api/v2/templates?quick-note=true`, {
method: "GET",
headers: {
Authorization: `Bearer ${i.token}`,
"Content-Type": "application/json"
}
}).then((s => {
200 === s.status ? s.json().then((s => {
s.items.length ? getTopics(s.items[0].id, {
method: "GET",
headers: {
Authorization: `Bearer ${i.token}`,
"Content-Type": "application/json"
}
}).then((a => {
a.json().then((a => {
const d = a.items;
let l = [];
if (getTranscript(currentTranscriptId).forEach((({
image: t,
person: o,
text: n,
startedAt: i,
endedAt: s,
highlight: a
}) => {
let r = [];
if (a && e) {
const e = bookmarkList.find((e => e.color === a[0]));
if (e) {
const t = d.find((t => t.color.toLowerCase() === e.code.toLowerCase()));
t && (r = [t.id])
}
}
n && l.push({
imageUrl: t,
person: "You" === o ? appUser : o,
startedAt: i,
endedAt: s || i,
highlights: r,
text: n
})
})), l.length) {
let e = JSON.stringify({
meetingId: currentTranscriptId,
meetingName: document.getElementById("meeting-name").innerText,
templateId: s.items[0].id,
transcripts: l,
isEnded: t
}),
a = {
Authorization: `Bearer ${i.token}`,
"Content-Type": "application/json"
},
d = get(APPLICATION_SPEECH_IDS) || [],
r = d.findIndex((e => e.ext === currentTranscriptId));
if (-1 === r) window.fetch(`${domainUrl}/api/v1/speeches/google-meet`, {
method: "POST",
headers: a,
body: e
}).then((e => {
200 === e.status ? e.json().then((e => {
set(APPLICATION_SPEECH_IDS, [...d, {
ext: currentTranscriptId,
app: e.id
}]), chrome.runtime.sendMessage({
type: "transcriptId",
transcriptId: e.id
}), o(e.id)
})) : 401 === e.status ? (e.json().then((e => {
saveLog(`Export2App 401 fail 1 ${i.token} ${e.id} ${e.message}`)
})), reDisplayPrompt(), n("Expired token")) : e.json().then((e => {
n(e.message)
}))
})).catch((e => {
n(e)
}));
else {
let t = d[r].app;
window.fetch(`${domainUrl}/api/v1/speeches/google-meet/${t}`, {
method: "PUT",
headers: a,
body: e
}).then((e => {
200 === e.status ? e.json().then((() => {
o(t)
})) : 401 === e.status ? (e.json().then((e => {
saveLog(`Export2App 401 fail 2 ${i.token} ${t} ${e.message}`)
})), reDisplayPrompt(), n("Expired token")) : e.json().then((e => {
n(e.message)
}))
})).catch((e => {
n(e)
}))
}
} else n("Empty transcript")
}))
})).catch((e => n(e))) : n("No quick note template")
})) : 401 === s.status ? (s.json().then((e => {
saveLog(`Export2App 401 fail 3 ${e.message} ${i.token}`)
})), reDisplayPrompt(), n("Expired token")) : s.json().then((e => n(e.message)))
})).catch((e => {
n(e)
})).finally((() => {
s.classList.remove("loading"), a.classList.remove("loading"), s.classList.add("finishing"), a.classList.add("finishing"), setTimeout((() => {
s.classList.remove("finishing"), a.classList.remove("finishing")
}), 3e3)
}))
} else n("Not logged in")
}))
})), downloadTranscript = () => {
const e = document.getElementById("meeting-name").innerText,
t = document.getElementById("laxis-confirm-download");
t.innerHTML = "Downloading...";
const o = document.getElementById("highlightCheck").checked,
n = document.getElementById("timestampCheck").checked,
i = document.getElementById("extension").value.toString(),
s = getTranscriptText(o, n);
let a;
switch (i) {
case "pdf":
a = () => Export2Pdf(s, e);
break;
case "doc":
a = () => Export2Word(s, e);
break;
case "txt":
a = () => Export2Txt(s, e);
break;
default:
a = () => Export2App(o)
}
a().then((e => {
"app" === i && window.open(`${domainUrl}/transcript/${e}`, "_blank")
})).catch((e => {
window.alert(e);
const t = get(ERROR_SAVING) || [];
set(ERROR_SAVING, [...t, e])
})).finally((() => {
t.innerHTML = "Download";
const e = document.getElementById("laxis-downloadMenu");
e && (e.style.display = "none")
}))
};
function saveLog(e) {
const t = {
message: e,
time: (new Date).toISOString()
};
chrome.storage.local.get("logs", (function(e) {
var o = structuredClone(e.logs);
void 0 === o ? o = [t] : o.push(t), chrome.storage.local.set({
logs: o
})
}))
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.stringSimilarity=e():t.stringSimilarity=e()}(self,(function(){return t={138:t=>{function e(t,e){if((t=t.replace(/\s+/g,""))===(e=e.replace(/\s+/g,"")))return 1;if(t.length<2||e.length<2)return 0;let r=new Map;for(let e=0;e<t.length-1;e++){const n=t.substring(e,e+2),o=r.has(n)?r.get(n)+1:1;r.set(n,o)}let n=0;for(let t=0;t<e.length-1;t++){const o=e.substring(t,t+2),s=r.has(o)?r.get(o):0;s>0&&(r.set(o,s-1),n++)}return 2*n/(t.length+e.length-2)}t.exports={compareTwoStrings:e,findBestMatch:function(t,r){if(!function(t,e){return"string"==typeof t&&!!Array.isArray(e)&&!!e.length&&!e.find((function(t){return"string"!=typeof t}))}(t,r))throw new Error("Bad arguments: First argument should be a string, second should be an array of strings");const n=[];let o=0;for(let s=0;s<r.length;s++){const i=r[s],f=e(t,i);n.push({target:i,rating:f}),f>n[o].rating&&(o=s)}return{ratings:n,bestMatch:n[o],bestMatchIndex:o}}}}},e={},function r(n){if(e[n])return e[n].exports;var o=e[n]={exports:{}};return t[n](o,o.exports,r),o.exports}(138);var t,e}));
@@ -0,0 +1 @@
const pad=t=>t<10?`0${t}`:t,debug=(...t)=>{DEBUG&&console.log("[laxis debug]",...t)},tryTo=(t,e)=>async(...n)=>{try{return await t(...n)}catch(t){console.error(`error ${e}:`,t)}},getTimeStr=(t,e)=>{const n=new Date(e)-t,o=Math.trunc(n/1e3)%60,a=Math.trunc(n/1e3/60);return pad(a)+":"+pad(o)},signup=()=>{window.open(loginUrl)},upgrade=()=>{window.open(upgradeUrl)},getDefaultName=()=>{const t=new Date,e=t.getDate(),n=t.getMonth(),o=t.getFullYear(),a=t.getHours(),r=t.getMinutes();return`Meeting_${o}${pad(n+1)}${pad(e)}_${pad(a)}${pad(r)}`};function onShortcut(t){var e="";document.addEventListener("keydown",(function(n){if(n.shiftKey){if((e+=""+n.key)===SHORTCUT_KEY)return t();SHORTCUT_KEY.indexOf(e)&&(e=""+n.key)}}))}onShortcut((function(){const t=document.getElementById("laxis-repair");t&&(t.style.display="block")}));const getCurrentLanguage=()=>{const t=xpath('//button[contains(@jsname,"gnzhTe")]',document);if(t){const e=t.ariaLabel;return e.substring(0,e.length-17)}return""},getToSettings=()=>{const t='//div[contains(@jscontroller,"bZ0mod")]';if(xpath('//div[contains(@aria-label, "Settings")]',document)){const t=xpath('//button[contains(@aria-label, "Close dialog")]',document);if(t)return void t.click()}else{const e=xpath('//button[contains(@aria-label, "More options") and contains(@jscontroller, "PIVayb")]',document);e&&e.click();let n=!1;const o=xpath(t,document);if(o&&"none"!==o?.style?.display&&(o.style.display="none",n=!0),!n){let e=setInterval((()=>{const n=xpath(t,document);n&&"none"!==n?.style?.display&&(n.style.display="none",clearInterval(e))}),[50])}let a=setInterval((()=>{const t=xpath('//i[contains(text(), "settings")]',document);if(t){t.click(),clearInterval(a);let e=setInterval((()=>{const t=xpath('//button[contains(@aria-label, "Captions")]',document);t&&(t.click(),clearInterval(e))}),[50])}}),[50])}},extractLocalStorage=()=>{const t=(t,e="")=>{let n=document.createElement("a");const o=new File([t],"filename"),a=URL.createObjectURL(o);return n.href=a,n.download=`${e}.json`,document.body.appendChild(n),n.click(),document.body.removeChild(n),Promise.resolve(1)};console.log((()=>{var e,n={};for(e in window.localStorage)e.includes("laxis")&&(value=window.localStorage.getItem(e),n[e]=value);if(!chrome||!chrome.storage)return t(JSON.stringify(n),"dumplocalStorage"),n;chrome.storage.local.get(null,(function(e){for(var o in e)return n[o]=e[o],t(JSON.stringify(n),"dumplocalStorage"),n}))})())};
@@ -0,0 +1,4 @@
<svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416" fill="#E94B4B"/>
<path d="M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416" stroke="#E94B4B" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,4 @@
<svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416" fill="#FFD339"/>
<path d="M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416" stroke="#FFD339" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,4 @@
<svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416" fill="#9CCC65"/>
<path d="M1 11.8277H13.5105C13.682 11.8277 13.8499 11.7788 13.9945 11.6867C14.1392 11.5947 14.2546 11.4634 14.3274 11.3081C14.4001 11.1528 14.427 10.98 14.4051 10.81C14.3832 10.64 14.3132 10.4797 14.2035 10.3479L10.9254 6.41387L14.2035 2.47979C14.3132 2.34805 14.3832 2.18778 14.4051 2.01773C14.427 1.84769 14.4001 1.67492 14.3274 1.51965C14.2546 1.36438 14.1392 1.23304 13.9945 1.14101C13.8499 1.04898 13.682 1.00006 13.5105 1H1V17.2416" stroke="#9CCC65" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" height="160" width="160" version="1.0">
<g fill="#fff">
<path d="m80 15c-35.88 0-65 29.12-65 65s29.12 65 65 65 65-29.12 65-65-29.12-65-65-65zm0 10c30.36 0 55 24.64 55 55s-24.64 55-55 55-55-24.64-55-55 24.64-55 55-55z"/>
<path d="m57.373 18.231a9.3834 9.1153 0 1 1 -18.767 0 9.3834 9.1153 0 1 1 18.767 0z" transform="matrix(1.1989 0 0 1.2342 21.214 28.75)"/>
<path d="m90.665 110.96c-0.069 2.73 1.211 3.5 4.327 3.82l5.008 0.1v5.12h-39.073v-5.12l5.503-0.1c3.291-0.1 4.082-1.38 4.327-3.82v-30.813c0.035-4.879-6.296-4.113-10.757-3.968v-5.074l30.665-1.105"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#9e9e9e" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 81.159 81.159" xml:space="preserve">
<g>
<path d="M74.175,5.262c-1.068-1.069-2.527-1.659-4.107-1.659c-1.775,0-3.563,0.748-4.934,2.058l-5.884,4.776l-0.229,0.208
c-1.301,1.299-1.813,3.124-1.498,4.962L43.806,28.926l-2.302-1.992c1.65-6.453,1.447-15.049-4.118-20.614
C33.311,2.245,28.097,0,22.706,0c-2.143,0-4.261,0.358-6.296,1.063c-0.932,0.323-1.646,1.083-1.909,2.034s-0.042,1.969,0.59,2.726
l7.393,8.836l-0.364,5.683l-6.144,0.701l-8.771-7.338c-0.757-0.634-1.776-0.855-2.727-0.59c-0.951,0.264-1.711,0.978-2.034,1.91
c-2.396,6.919-0.285,14.371,5.792,20.444c3.274,3.276,7.988,5.007,13.63,5.007c0.413,0,0.829-0.021,1.245-0.041
c-0.209,0.182-0.419,0.362-0.617,0.56L5.641,57.847c-4.679,4.679-4.679,12.291,0,16.97l2.827,2.827
c2.266,2.267,5.28,3.515,8.485,3.515s6.219-1.248,8.485-3.515L42.29,60.791c0.934-0.933,1.669-1.982,2.223-3.103l14.969,17.296
c0.048,0.055,0.098,0.107,0.148,0.159c1.678,1.677,4.196,2.601,7.094,2.601c3.521,0,7.095-1.385,9.326-3.615
c3.922-3.922,5.158-12.267,1.012-16.416c-0.053-0.051-0.104-0.101-0.159-0.146L55.108,38.709L67.682,25.76
c0.346,0.059,0.692,0.088,1.041,0.088c1.506,0,2.896-0.563,3.916-1.582l4.984-6.113c1.141-1.192,1.855-2.695,2.021-4.251
c0.193-1.822-0.398-3.568-1.621-4.79L74.175,5.262z M38.048,56.549L21.196,73.402c-1.133,1.133-2.64,1.757-4.243,1.757
s-3.109-0.624-4.243-1.757l-2.827-2.827c-2.339-2.34-2.339-6.146,0-8.484l16.853-16.854c1.133-1.133,2.64-1.757,4.242-1.757
c0.471,0,0.932,0.062,1.379,0.165l7.438,8.595C39.813,53.797,39.234,55.363,38.048,56.549z M71.806,69.887
c-1.111,1.111-3.154,1.857-5.084,1.857c-1.211,0-2.246-0.293-2.793-0.789L32.121,34.203c-0.797-0.921-2.073-1.269-3.225-0.88
c-2.24,0.754-4.671,1.152-7.031,1.152c-3.958,0-7.292-1.154-9.387-3.25c-1.896-1.896-4.559-5.25-4.957-9.432l5.59,4.677
c0.63,0.528,1.447,0.773,2.266,0.68l9.915-1.132c1.443-0.165,2.561-1.339,2.653-2.789l0.601-9.384
c0.049-0.769-0.199-1.526-0.693-2.116l-4.789-5.724c3.663,0.1,7.229,1.709,10.077,4.557c3.918,3.919,3.833,11.259,2.095,16.421
c-0.389,1.154-0.041,2.429,0.88,3.226l36.757,31.808C74.206,63.476,73.891,67.801,71.806,69.887z M73.261,14.035l-4.707,5.772
c-0.049-0.019-0.104-0.045-0.164-0.081l-2.037-1.21l-15.787,16.26l-2.207-1.909l16.41-15.935l-1.209-2.035
c-0.035-0.062-0.063-0.117-0.08-0.165l5.541-4.499l0.23-0.208c0.299-0.297,0.598-0.4,0.784-0.417l3.646,3.646
C73.669,13.404,73.572,13.723,73.261,14.035z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@@ -0,0 +1 @@
const script=document.createElement("script");script.setAttribute("type","text/javascript");const filePath=chrome.runtime.getURL("runtime.js");script.setAttribute("src",filePath),document.body.appendChild(script);
+127
View File
@@ -0,0 +1,127 @@
try {
importScripts("config/share.js"), importScripts("config/panel.js")
} catch (e) {
console.error(e)
}
let meetingId = null,
transcriptId = null,
meetingName = null,
username = "";
chrome.storage.session.setAccessLevel({
accessLevel: "TRUSTED_AND_UNTRUSTED_CONTEXTS"
});
const getTopics = (e, t) => fetch(`${domainUrl}/api/v2/templates/${e}/topics`, t);
chrome.tabs.onRemoved.addListener(((e, t) => {
chrome.storage.session.get(["sessionList"], (e => {
if (e.sessionList) {
let t = e.sessionList;
console.log(t), chrome.storage.local.get(["token"], (e => {
if (e.token) {
let o = e.token;
fetch(`${domainUrl}/api/v2/templates?quick-note=true`, {
method: "GET",
headers: {
Authorization: `Bearer ${o}`,
"Content-Type": "application/json"
}
}).then((e => {
200 === e.status ? e.json().then((e => {
e.items.length ? getTopics(e.items[0].id, {
method: "GET",
headers: {
Authorization: `Bearer ${o}`,
"Content-Type": "application/json"
}
}).then((s => {
s.json().then((s => {
const n = s.items;
let r = [];
if (t.forEach((({
image: e,
person: t,
text: o,
startedAt: s,
endedAt: i,
highlight: a
}) => {
let c = [];
if (a) {
const e = bookmarkList.find((e => e.color === a[0]));
if (e) {
const t = n.find((t => t.color.toLowerCase() === e.code.toLowerCase()));
t && (c = [t.id])
}
}
o && r.push({
imageUrl: e,
person: "You" === t ? username : t,
startedAt: s,
endedAt: i || s,
highlights: c,
text: o
})
})), r.length) {
let t = JSON.stringify({
meetingId: meetingId,
meetingName: meetingName,
templateId: e.items[0].id,
transcripts: r,
isEnded: !0
}),
s = {
Authorization: `Bearer ${o}`,
"Content-Type": "application/json"
};
transcriptId ? fetch(`${domainUrl}/api/v1/speeches/google-meet/${transcriptId}`, {
method: "PUT",
headers: s,
body: t
}).then((e => {
200 === e.status ? (console.log("save success"), chrome.tabs.create({
url: `${domainUrl}/transcript/${transcriptId}`
})) : 401 === e.status ? console.log("Expired token") : e.json().then((e => {
console.log(e.message)
}))
})).catch((e => {
console.log(e)
})) : fetch(`${domainUrl}/api/v1/speeches/google-meet`, {
method: "POST",
headers: s,
body: t
}).then((e => {
200 === e.status ? (chrome.tabs.create({
url: `${domainUrl}/transcript/${transcriptId}`
}), console.log("success")) : 401 === e.status ? console.log("Expired token") : e.json().then((e => {
console.log(e.message)
}))
})).catch((e => {
console.log(e)
}))
} else console.log("Empty transcript")
}))
})).catch((e => reject(e))) : console.log("No quick note template")
})) : 401 === e.status ? console.log("Expired token") : e.json().then((e => console.log(e.message)))
}))
}
}))
}
}))
})), chrome.runtime.onMessage.addListener((e => {
console.log(e), "meetingId" === e.type && (console.log(e.meetingId), meetingId = e.meetingId), "transcriptId" === e.type && (console.log(e.transcriptId), transcriptId = e.transcriptId), "meetingName" === e.type && (meetingName = e.meetingName), "username" === e.type && (username = e.data)
})), chrome.runtime.onInstalled.addListener((e => {
// e.reason === chrome.runtime.OnInstalledReason.INSTALL && chrome.tabs.create({
// url: signupUrl
// }, (function(e) {}))
})), chrome.runtime.onMessageExternal.addListener((function(e, t, o) {
t.origin === domainUrl && (o("extension received the token"), chrome.storage.local.set({
token: e.token,
refreshToken: e.refreshToken
}, (function() {})), chrome.tabs.query({
url: googleMeetUrl
}, (function(t) {
t[0] && chrome.tabs.sendMessage(t[0].id, {
token: e.token,
refreshToken: e.refreshToken
}, (function(e) {}))
})))
})), chrome.runtime.setUninstallURL("https://www.laxis.tech/uninstall-survey");
@@ -0,0 +1,61 @@
{
"update_url": "https://clients2.google.com/service/update2/crx",
"manifest_version": 3,
"name": "Google Meet Transcripts & AI Summary",
"description": "Google Meet Transcription, AI Summary and Insight. Get the most out of Google Meet!",
"version": "4.3.12",
"icons": {
"16": "image/logo16x16.png",
"48": "image/logo48x48.png",
"128": "image/logo128x128.png"
},
"background": {
"service_worker": "login.js"
},
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": [
"feature/utilities/packages/jquery.min.js",
"feature/utilities/packages/html2canvas.js",
"feature/utilities/packages/html2pdf.bundle.min.js",
"feature/utilities/packages/string-similarity.min.js",
"feature/utilities/util.js",
"inject.js",
"style/panel.js",
"config/share.js",
"config/panel.js",
"config/record.js",
"feature/record/captionObserver.js",
"feature/record/captionControls.js",
"feature/record/captionProcessing.js",
"feature/record/settings.js",
"feature/record/storage.js",
"feature/record/dom.js",
"feature/record/transcript.js",
"feature/record/meetingInfo.js",
"feature/panel/main.js",
"feature/panel/icons.js",
"runtime.js"
],
"run_at": "document_idle",
"all_frames": false
}
],
"web_accessible_resources": [
{
"resources": [
"runtime.js",
"image/bookmark/*.svg",
"image/logo.png",
"image/info.svg",
"image/repair.svg",
"style/panel.css"
],
"matches": ["https://meet.google.com/*"]
}
],
"permissions": ["storage"],
"host_permissions": ["https://meet.google.com/*"]
}
@@ -0,0 +1 @@
addRoot(),addMiniPanel(),addRemindLogin();const checkOngoingMeeting=setInterval(tryTo(addCaptionPanel,"adding button"),1e3);let notificationsTimeout;const notificationsTimeoutDuration=3e3;let checkCaptionStatusInterval;function saveLog(e){const t={message:e,time:(new Date).toISOString()};chrome.storage.local.get("logs",(function(e){var n=structuredClone(e.logs);void 0===n?n=[t]:n.push(t),chrome.storage.local.set({logs:n})}))}syncSettings(),window.addEventListener("click",(e=>{const t=document.getElementById("laxis-downloadMenu");e.target===t&&(t.style.display="none")})),chrome.runtime.onMessage.addListener((function(e,t,n){if(t.id===extensionId)if(e.token){n("token received by content script");const t={method:"GET",headers:{Authorization:`Bearer ${e.token}`}},o=()=>window.fetch(`${domainUrl}/api/v1/users/info`,t),i=()=>window.fetch(`${domainUrl}/api/v2/templates?quick-note=true`,t),s=e=>window.fetch(`${domainUrl}/api/v2/templates/${e}/topics`,t);Promise.all([o(),i()]).then((t=>{if(200===t[0].status&&200===t[1].status){loginStatus=1;const e=document.getElementById("login-prompt");e&&(e.style.display="none");const n=document.getElementById("laxis-remindLogin");n&&(n.style.display="none"),t[0].json().then((e=>{appUser=`${e.firstName} ${e.lastName}`,chrome.runtime.sendMessage({type:"username",data:`${e.firstName} ${e.lastName}`})})),t[1].json().then((e=>{let t=bookmarkList;s(e.items[0].id).then((e=>e.json().then((e=>{e.items.forEach((e=>{let n=bookmarkList.findIndex((t=>t.code===e.color));if(-1!==n){if(t[n].name=e.name,document.getElementById(`laxis-highlight-${e.color}-title`)){document.getElementById(`laxis-highlight-${e.color}-title`).innerHTML=e.name}let o=document.getElementById(`laxis-highlight-${e.color}`),i=document.getElementById(`laxis-highlight-${e.color}-mini`);o&&(o.title=`Highlight as ${e.name}`),i&&(i.title=`Highlight as ${e.name}`)}}))})))).catch((e=>console.warn(e))),bookmarkList=t}))}else 401===t[0].status||401===t[1].status?(401===t[0].status?t[0].json().then((t=>{saveLog(`chrome.runtime.onMessage.addListener 401 fail ${t.message} ${e.token}`)})):t[1].json().then((t=>{saveLog(`chrome.runtime.onMessage.addListener 401 fail ${t.message} ${e.token}`)})),reDisplayPrompt(),reDisplayRemindLogin()):t[0].json().then((e=>{window.alert(e.message)}))})).catch((e=>{window.alert(e)}))}else saveLog(`chrome.runtime.onMessage.addListener token empty fail ${e.token}`),reDisplayRemindLogin()}));
@@ -0,0 +1,269 @@
* {
box-sizing: border-box;
}
.panelBase {
position: absolute;
z-index: 998;
right: 0;
top: 0;
border-radius: 12px;
}
.col-12 {
padding: 8px;
width: 100%;
}
/*toggle*/
/*!*caption hover*!*/
/*.highlight-caption:hover {*/
/* background-color: #696969;*/
/*}*/
/*tooltip*/
.popup {
position: relative;
}
.popup .popupText {
position: absolute;
visibility: hidden;
width: 90%;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 7px 0;
z-index: 1;
bottom: calc(100% + 7px);
left: 5%;
font-size: 13px;
color: #292c35;
background-color: #818388;
font-weight: bold;
border-radius: 8px;
}
.popup .show {
visibility: visible;
opacity: 1;
}
.tooltip {
position: relative;
display: inline-block;
}
.tooltip:hover {
background-color: #454953;
border-radius: 12px;
border: solid 1px #c7c7c7;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 100px;
background-color: #454953;
color: #fff;
text-align: center;
border-radius: 4px;
position: absolute;
z-index: 1000;
bottom: 100%;
left: 98%;
margin-left: -100px;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip .tooltiptext::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #000000 transparent transparent transparent;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
.settings-tooltip {
position: relative;
display: inline-block;
}
.settings-tooltip .tooltiplargetext {
visibility: hidden;
min-width: 200px;
background-color: #454953;
color: #fff;
text-align: center;
border-radius: 4px;
border: 1px solid #c7c7c7;
position: absolute;
z-index: 1000;
bottom: 100%;
left: 98%;
margin-left: -100px;
opacity: 0;
transition: opacity 0.3s;
padding: 2px;
margin-bottom: 8px;
}
.settings-tooltip .tooltiplargetext::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #000000 transparent transparent transparent;
}
.settings-tooltip:hover .tooltiplargetext {
visibility: visible;
opacity: 1;
}
.modal {
display: none; /* Hidden by default */
position: absolute; /* Stay in place */
z-index: 1500; /* Sit on top */
right: 0;
top: 0;
width: 300px; /* Full width */
overflow: auto; /* Enable scroll if needed */
}
/* Modal Content/Box */
.modal-content {
background-color: #454953;
color: #ffffff;
border: solid 1px #ffffff;
margin-top: 98px;
margin-left: 17px;
width: 266px;
border-radius: 12px;
font-size: 16px;
}
.modal-header {
padding: 20px;
padding-bottom: 16px;
border-bottom: 1px solid #e0e0e0;
width: 100%;
}
.modal-body {
padding-top: 24px;
padding-left: 30px;
padding-right: 30px;
justify-content: space-between;
display: flex;
}
.modal-footer {
border-top: 1px solid #e0e0e0;
margin-top: 48px;
padding-top: 12px;
padding-bottom: 12px;
padding-left: 30px;
padding-right: 30px;
display: flex;
justify-content: space-around;
}
.modal-button {
width: 45%;
display: flex;
justify-content: center;
align-items: center;
height: 36px;
border-radius: 4px;
color: #ffffff;
cursor: pointer;
}
.miniButtonContainer {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: 40px;
border-radius: 50%;
margin-left: 10px;
margin-top: 12px;
padding: 9px 0 9px 0;
background-color: #3e4149;
cursor: pointer;
border: 1px solid #3e4149;
}
.miniButtonContainer:hover {
border: 1px solid #2196f3;
}
.imageContainer {
display: flex;
align-items: center;
justify-content: center;
height: 32px;
width: 32px;
border-radius: 50%;
border: 1px solid #292c35;
padding: 7px;
background-color: #292c35;
margin-right: 12px;
cursor: pointer;
}
.imageContainer:hover {
border: 1px solid #2196f3;
}
.tutorialContainer {
height: 40px;
width: 40px;
padding: 8px;
margin: 12px;
border-radius: 50%;
background-color: #454953;
}
.flagContainer {
border-radius: 50%;
border: 1px solid #9e9e9e;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
padding: 8px;
cursor: pointer;
}
.flagContainer:hover {
border: 1px solid #2196f3;
}
.flagContainerMini {
border-radius: 50%;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
padding: 8px;
cursor: pointer;
margin: 6px 0px;
background-color: #292c35;
}
.flagContainerMini:hover {
border: 1px solid #2196f3;
}
.loading {
border: 1px solid rgb(0, 38, 255);
}
.finishing {
border: 1px solid #2196f3;
}
@@ -0,0 +1 @@
const STYLE=document.createElement("style"),promise=new Promise((e=>{fetch(chrome.runtime.getURL("style/panel.css")).then((e=>e.text())).then((t=>{e(t)}))}));promise.then((e=>{STYLE.innerText=e.toString(),document.body.append(STYLE)}));