@kudoai/chatgpt.js 3.8.2 → 3.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  # MIT License
28
28
 
29
- **Copyright © 2023–2025 [KudoAI](https://github.com/KudoAI) & [contributors](.#-contributors).**
29
+ **Copyright © 2023–2025 [KudoAI](https://github.com/KudoAI) & [contributors](.#-contributors)**
30
30
 
31
31
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
32
32
 
package/README.md CHANGED
@@ -51,8 +51,8 @@
51
51
  <img src="https://img.shields.io/badge/License-MIT-fc4f2d.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
52
52
  <a href="https://www.npmjs.com/package/@kudoai/chatgpt.js/v/latest" target="_blank" rel="noopener">
53
53
  <img src="https://img.shields.io/npm/v/%40kudoai%2Fchatgpt.js?logo=npm&logoColor=white&labelColor=464646&color=blue&style=for-the-badge&label=Latest+Release"></a>
54
- <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.2/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
- <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.2&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
54
+ <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.4/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
+ <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.4&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
56
56
  <a href="https://www.codefactor.io/repository/github/kudoai/chatgpt.js" target="_blank" rel="noopener">
57
57
  <img src="https://img.shields.io/codefactor/grade/github/kudoai/chatgpt.js?label=Code+Quality&logo=codefactor&logoColor=white&labelColor=464646&color=1acc6c&style=for-the-badge"></a>
58
58
  <a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=kudoai_chatgpt.js" target="_blank" rel="noopener">
@@ -120,7 +120,7 @@
120
120
 
121
121
  ```js
122
122
  (async () => {
123
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
123
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
124
124
  // Your code here...
125
125
  })();
126
126
  ```
@@ -129,7 +129,7 @@
129
129
 
130
130
  ```js
131
131
  var xhr = new XMLHttpRequest();
132
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
132
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
133
133
  xhr.onload = function () {
134
134
  if (xhr.status === 200) {
135
135
  var chatgptJS = document.createElement('script');
@@ -152,7 +152,7 @@ function yourCode() {
152
152
 
153
153
  ```js
154
154
  ...
155
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js
155
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js
156
156
  // ==/UserScript==
157
157
 
158
158
  // Your code here...
@@ -222,7 +222,7 @@ chatgpt.get('reply', 'last');
222
222
 
223
223
  Each call equally fetches the last response. If you think it works, it probably will... so just type it!
224
224
 
225
- If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.2/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
225
+ If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.4/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
226
226
 
227
227
  <img height=8px width="100%" src="https://assets.chatgptjs.org/images/separators/gradient-aqua.png?v=e638eac">
228
228
 
@@ -416,7 +416,9 @@ This library exists thanks to code, translations, issues & ideas from the follow
416
416
  <a href="https://github.com/ericdachen" target="_blank" rel="noopener">
417
417
  <img title="@ericdachen" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/54382303?first-contrib=2025.3.20-implement-warp-to-golden-sponsors&h=47&w=47&mask=circle&maxage=7d"></a>
418
418
  <a href="https://github.com/m-k8s" target="_blank" rel="noopener">
419
- <img title="@m-k8s" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/42094254?first-contrib=2025.7.26-fixed-hand,ling-of-intermediate-msgs-by-getchatdata&h=47&w=47&mask=circle&maxage=7d"></a>
419
+ <img title="@m-k8s" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/42094254?first-contrib=2025.7.26-fixed-handling-of-intermediate-msgs-by-getchatdata&h=47&w=47&mask=circle&maxage=7d"></a>
420
+ <a href="https://github.com/ahnupeng" target="_blank" rel="noopener">
421
+ <img title="@ahnupeng" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/5319112?first-contrib=2025.9.4-suggested-allow-edit-slider-vals&h=47&w=47&mask=circle&maxage=7d"></a>
420
422
  <a href="https://github.com/dependabot" target="_blank" rel="noopener">
421
423
  <img title="Dependabot" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/in/29110&h=47&w=47&mask=circle&maxage=7d"></a>
422
424
  <a href="https://chatgpt.com" target="_blank" rel="noopener">
@@ -480,7 +482,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
480
482
  <div align="center">
481
483
 
482
484
  **[Releases](https://github.com/KudoAI/chatgpt.js/releases)** /
483
- [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.2/docs/USERGUIDE.md) /
485
+ [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.4/docs/USERGUIDE.md) /
484
486
  [Discuss](https://github.com/KudoAI/chatgpt.js/discussions) /
485
487
  [Back to top ↑](#top)
486
488
 
package/chatgpt.js CHANGED
@@ -38,7 +38,7 @@ const chatgpt = {
38
38
  reason: 'button[data-testid=composer-button-reason]',
39
39
  send: 'button[data-testid=send-button]',
40
40
  sidebar: 'div[style*=-sidebar-width] button[data-testid=close-sidebar-button], div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]',
41
- stop: 'button[data-testid=stop-button]',
41
+ stop: 'div:has(> svg > path[d^="M10 2.08496C14.3713"])',
42
42
  upload: 'button:has(> svg > path[d^="M12 3C12.5523"])',
43
43
  voice: 'button[data-testid*=composer-speech-button]'
44
44
  },
@@ -127,13 +127,14 @@ const chatgpt = {
127
127
 
128
128
  drag: {
129
129
  mousedown(event) { // find modal, update styles, attach listeners, init XY offsets
130
- if (event.button != 0) return // prevent non-left-click drag
131
- if (!/auto|default/.test(getComputedStyle(event.target).cursor))
132
- return // prevent drag on interactive elems
130
+ if ( // prevent drag when...
131
+ event.button != 0 // non-left-click
132
+ || !/auto|default/.test(getComputedStyle(event.target).cursor) // cursor changed
133
+ ) return
133
134
  chatgpt.draggingModal = event.currentTarget
134
135
  event.preventDefault() // prevent sub-elems like icons being draggable
135
136
  Object.assign(chatgpt.draggingModal.style, {
136
- transition: '0.1s', willChange: 'transform', transform: 'scale(1.05)' })
137
+ transition: 'transform 0.1s ease', transform: 'scale(1.05)' })
137
138
  document.body.style.cursor = 'grabbing' // update cursor
138
139
  ;[...chatgpt.draggingModal.children] // prevent hover FX if drag lags behind cursor
139
140
  .forEach(child => child.style.pointerEvents = 'none')
@@ -153,7 +154,7 @@ const chatgpt = {
153
154
 
154
155
  mouseup() { // restore styles/pointer events, remove listeners, reset chatgpt.draggingModal
155
156
  Object.assign(chatgpt.draggingModal.style, { // restore styles
156
- cursor: 'inherit', transition: 'inherit', willChange: 'auto', transform: 'scale(1)' })
157
+ cursor: 'inherit', transition: 'inherit', transform: 'scale(1)' })
157
158
  document.body.style.cursor = '' // restore cursor
158
159
  ;[...chatgpt.draggingModal.children] // restore pointer events
159
160
  .forEach(child => child.style.pointerEvents = '')
@@ -1893,7 +1894,7 @@ const chatgpt = {
1893
1894
  if (!sidebar) { return console.error('Sidebar element not found!') || false }
1894
1895
  else return chatgpt.browser.isMobile() ?
1895
1896
  document.documentElement.style.overflow == 'hidden'
1896
- : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px'
1897
+ : sidebar.style.visibility != 'hidden' && parseInt(getComputedStyle(sidebar).width) > 150
1897
1898
  },
1898
1899
 
1899
1900
  toggle() {
@@ -4,7 +4,7 @@
4
4
  * User guide: https://chatgptjs.org/userguide
5
5
  * Latest minified release: https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js/chatgpt.min.js
6
6
  */
7
- localStorage.alertQueue=JSON.stringify([]),localStorage.notifyProps=JSON.stringify({queue:{topRight:[],bottomRight:[],bottomLeft:[],topLeft:[]}});let chatgpt={endpoints:{assets:"https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@f7b484a29466e42a15b21f91d04a0c3a251aba93",openAI:{session:"https://chatgpt.com/api/auth/session",chats:"https://chatgpt.com/backend-api/conversations",chat:"https://chatgpt.com/backend-api/conversation",share_create:"https://chatgpt.com/backend-api/share/create",share:"https://chatgpt.com/backend-api/share",instructions:"https://chatgpt.com/backend-api/user_system_messages"}},selectors:{btns:{continue:'button:has(svg[class*=rotate] > path[d^="M4.47189"])',createImage:"button[data-testid=composer-create-image]",deepResearch:"button[data-testid=composer-deep-research]",login:"button[data-testid*=login]",newChat:'a[href="/"]:has(svg),button:has([d^="M3.06957"])',regen:'button[data-testid*=regenerate],div[role=menuitem] div:has(svg):has(path[d^="M3.06957"])',scroll:'button:has(> svg > path[d^="M12 21C11.7348"])',search:"button[data-testid=composer-button-search]",reason:"button[data-testid=composer-button-reason]",send:"button[data-testid=send-button]",sidebar:"div[style*=-sidebar-width] button[data-testid=close-sidebar-button], div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]",stop:"button[data-testid=stop-button]",upload:'button:has(> svg > path[d^="M12 3C12.5523"])',voice:"button[data-testid*=composer-speech-button]"},chatDivs:{convo:"div[class*=thread]",msg:"div[data-message-author-role]",reply:"div[data-message-author-role=assistant]"},chatHistory:"div#history",errors:{toast:"div.toast-root",txt:"div[class*=text-error]"},footer:"div#thread-bottom-container > div:last-of-type > div, span.text-sm.leading-none",header:"header#page-header",links:{newChat:'nav a[href="/"]',sidebarItem:"nav a"},sidebar:"div#stage-slideover-sidebar, div.bg-token-sidebar-surface-primary",ssgManifest:'script[src*="_ssgManifest.js"]'},actAs(s){return new Promise((r,a)=>{let n=new XMLHttpRequest;n.open("GET","https://cdn.jsdelivr.net/gh/KudoAI/chat-prompts@f7b484a29466e42a15b21f91d04a0c3a251aba93/dist/personas.min.json",!0),n.send(),n.onload=()=>{if(200!=n.status)return a("🤖 chatgpt.js >> Request failed. Cannot retrieve prompts data.");var e=JSON.parse(n.responseText).personas;if(s){var t=e.find(e=>e.title.toLowerCase()==s.toLowerCase());if(!t)return a(`🤖 chatgpt.js >> Persona '${s}' was not found!`);chatgpt.send(t.prompt,"click"),console.info(`Loading ${s} persona...`),chatgpt.isIdle().then(()=>console.info("Persona activated!"))}else{console.log("\n%c🤖 chatgpt.js personas\n","font-family: sans-serif ; font-size: xxx-large ; font-weight: bold");for(var o of e)console.log("%c"+o.title,"font-family: monospace ; font-size: larger ;")}return r()}})},activateDarkMode(){document.documentElement.classList.replace("light","dark"),document.documentElement.style.colorScheme=localStorage.theme="dark"},activateLightMode(){document.documentElement.classList.replace("dark","light"),document.documentElement.style.colorScheme=localStorage.theme="light"},alert(o,r,e,a,t){let n=chatgpt.isDarkMode()?"dark":"light",s=chatgpt.browser.isMobile(),i={dismiss:{click(e){e.target!=e.currentTarget&&!e.target.closest("[class*=-close-btn]")||f()},key(e){if(/^(?: |Space|Enter|Return|Esc)/.test(e.key)&&[32,13,27].includes(e.keyCode))for(var t of m){var t=document.getElementById(t);if(!t||"none"==t.style.display)return;e.key.startsWith("Esc")||27==e.keyCode?f():(t=t.querySelector(".modal-buttons").lastChild)&&(t.click(),e.preventDefault())}}},drag:{mousedown(e){var t;0==e.button&&/auto|default/.test(getComputedStyle(e.target).cursor)&&(chatgpt.draggingModal=e.currentTarget,e.preventDefault(),Object.assign(chatgpt.draggingModal.style,{transition:"0.1s",willChange:"transform",transform:"scale(1.05)"}),document.body.style.cursor="grabbing",[...chatgpt.draggingModal.children].forEach(e=>e.style.pointerEvents="none"),["mousemove","mouseup"].forEach(e=>document.addEventListener(e,i.drag[e])),t=chatgpt.draggingModal.getBoundingClientRect(),i.drag.offsetX=e.clientX-t.left+21,i.drag.offsetY=e.clientY-t.top+12)},mousemove(e){var t;chatgpt.draggingModal&&(t=e.clientX-i.drag.offsetX,e=e.clientY-i.drag.offsetY,Object.assign(chatgpt.draggingModal.style,{left:t+"px",top:e+"px"}))},mouseup(){Object.assign(chatgpt.draggingModal.style,{cursor:"inherit",transition:"inherit",willChange:"auto",transform:"scale(1)"}),document.body.style.cursor="",[...chatgpt.draggingModal.children].forEach(e=>e.style.pointerEvents=""),["mousemove","mouseup"].forEach(e=>document.removeEventListener(e,i.drag[e])),chatgpt.draggingModal=null}}},c=document.createElement("div"),l=(c.id=Math.floor(1e6*chatgpt.randomFloat())+Date.now(),c.classList.add("chatgpt-modal"),document.createElement("div")),d=document.createElement("h2"),g=document.createElement("p");var u=1739338889852;let h=document.querySelector("#chatgpt-modal-style"),p=((!h||parseInt(h.getAttribute("last-updated"),10)<u)&&(h||((h=document.createElement("style")).id="chatgpt-modal-style",h.setAttribute("last-updated",u.toString()),document.head.append(h)),h.textContent=`.chatgpt-modal { /* vars */
7
+ localStorage.alertQueue=JSON.stringify([]),localStorage.notifyProps=JSON.stringify({queue:{topRight:[],bottomRight:[],bottomLeft:[],topLeft:[]}});let chatgpt={endpoints:{assets:"https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3ca5d31dec7beef19945b0ca788a5b9ba913175d",openAI:{session:"https://chatgpt.com/api/auth/session",chats:"https://chatgpt.com/backend-api/conversations",chat:"https://chatgpt.com/backend-api/conversation",share_create:"https://chatgpt.com/backend-api/share/create",share:"https://chatgpt.com/backend-api/share",instructions:"https://chatgpt.com/backend-api/user_system_messages"}},selectors:{btns:{continue:'button:has(svg[class*=rotate] > path[d^="M4.47189"])',createImage:"button[data-testid=composer-create-image]",deepResearch:"button[data-testid=composer-deep-research]",login:"button[data-testid*=login]",newChat:'a[href="/"]:has(svg),button:has([d^="M3.06957"])',regen:'button[data-testid*=regenerate],div[role=menuitem] div:has(svg):has(path[d^="M3.06957"])',scroll:'button:has(> svg > path[d^="M12 21C11.7348"])',search:"button[data-testid=composer-button-search]",reason:"button[data-testid=composer-button-reason]",send:"button[data-testid=send-button]",sidebar:"div[style*=-sidebar-width] button[data-testid=close-sidebar-button], div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]",stop:'div:has(> svg > path[d^="M10 2.08496C14.3713"])',upload:'button:has(> svg > path[d^="M12 3C12.5523"])',voice:"button[data-testid*=composer-speech-button]"},chatDivs:{convo:"div[class*=thread]",msg:"div[data-message-author-role]",reply:"div[data-message-author-role=assistant]"},chatHistory:"div#history",errors:{toast:"div.toast-root",txt:"div[class*=text-error]"},footer:"div#thread-bottom-container > div:last-of-type > div, span.text-sm.leading-none",header:"header#page-header",links:{newChat:'nav a[href="/"]',sidebarItem:"nav a"},sidebar:"div#stage-slideover-sidebar, div.bg-token-sidebar-surface-primary",ssgManifest:'script[src*="_ssgManifest.js"]'},actAs(s){return new Promise((r,a)=>{let n=new XMLHttpRequest;n.open("GET","https://cdn.jsdelivr.net/gh/KudoAI/chat-prompts@3ca5d31dec7beef19945b0ca788a5b9ba913175d/dist/personas.min.json",!0),n.send(),n.onload=()=>{if(200!=n.status)return a("🤖 chatgpt.js >> Request failed. Cannot retrieve prompts data.");var e=JSON.parse(n.responseText).personas;if(s){var t=e.find(e=>e.title.toLowerCase()==s.toLowerCase());if(!t)return a(`🤖 chatgpt.js >> Persona '${s}' was not found!`);chatgpt.send(t.prompt,"click"),console.info(`Loading ${s} persona...`),chatgpt.isIdle().then(()=>console.info("Persona activated!"))}else{console.log("\n%c🤖 chatgpt.js personas\n","font-family: sans-serif ; font-size: xxx-large ; font-weight: bold");for(var o of e)console.log("%c"+o.title,"font-family: monospace ; font-size: larger ;")}return r()}})},activateDarkMode(){document.documentElement.classList.replace("light","dark"),document.documentElement.style.colorScheme=localStorage.theme="dark"},activateLightMode(){document.documentElement.classList.replace("dark","light"),document.documentElement.style.colorScheme=localStorage.theme="light"},alert(o,r,e,a,t){let n=chatgpt.isDarkMode()?"dark":"light",s=chatgpt.browser.isMobile(),i={dismiss:{click(e){e.target!=e.currentTarget&&!e.target.closest("[class*=-close-btn]")||f()},key(e){if(/^(?: |Space|Enter|Return|Esc)/.test(e.key)&&[32,13,27].includes(e.keyCode))for(var t of m){var t=document.getElementById(t);if(!t||"none"==t.style.display)return;e.key.startsWith("Esc")||27==e.keyCode?f():(t=t.querySelector(".modal-buttons").lastChild)&&(t.click(),e.preventDefault())}}},drag:{mousedown(e){var t;0==e.button&&/auto|default/.test(getComputedStyle(e.target).cursor)&&(chatgpt.draggingModal=e.currentTarget,e.preventDefault(),Object.assign(chatgpt.draggingModal.style,{transition:"transform 0.1s ease",transform:"scale(1.05)"}),document.body.style.cursor="grabbing",[...chatgpt.draggingModal.children].forEach(e=>e.style.pointerEvents="none"),["mousemove","mouseup"].forEach(e=>document.addEventListener(e,i.drag[e])),t=chatgpt.draggingModal.getBoundingClientRect(),i.drag.offsetX=e.clientX-t.left+21,i.drag.offsetY=e.clientY-t.top+12)},mousemove(e){var t;chatgpt.draggingModal&&(t=e.clientX-i.drag.offsetX,e=e.clientY-i.drag.offsetY,Object.assign(chatgpt.draggingModal.style,{left:t+"px",top:e+"px"}))},mouseup(){Object.assign(chatgpt.draggingModal.style,{cursor:"inherit",transition:"inherit",transform:"scale(1)"}),document.body.style.cursor="",[...chatgpt.draggingModal.children].forEach(e=>e.style.pointerEvents=""),["mousemove","mouseup"].forEach(e=>document.removeEventListener(e,i.drag[e])),chatgpt.draggingModal=null}}},c=document.createElement("div"),l=(c.id=Math.floor(1e6*chatgpt.randomFloat())+Date.now(),c.classList.add("chatgpt-modal"),document.createElement("div")),d=document.createElement("h2"),g=document.createElement("p");var h=1739338889852;let u=document.querySelector("#chatgpt-modal-style"),p=((!u||parseInt(u.getAttribute("last-updated"),10)<h)&&(u||((u=document.createElement("style")).id="chatgpt-modal-style",u.setAttribute("last-updated",h.toString()),document.head.append(u)),u.textContent=`.chatgpt-modal { /* vars */
8
8
  --transition: opacity 0.65s cubic-bezier(.165,.84,.44,1), /* for fade-in */
9
9
  transform 0.55s cubic-bezier(.165,.84,.44,1) ; /* for move-in */
10
10
  --bg-transition: background-color 0.25s ease ; /* for bg dim */
@@ -74,7 +74,7 @@ localStorage.alertQueue=JSON.stringify([]),localStorage.notifyProps=JSON.stringi
74
74
  .chatgpt-modal input[type=checkbox]:focus {
75
75
  outline: none ; box-shadow: none ; -webkit-box-shadow: none ; -moz-box-shadow: none }
76
76
  .chatgpt-modal .checkbox-group label {
77
- cursor: pointer ; font-size: 14px ; color: ${"dark"==n?"#e1e1e1":"#1e1e1e"}}`),d.textContent=o||"",g.innerText=r||"",chatgpt.renderHTML(g),document.createElement("div"));p.classList.add("modal-buttons","no-mobile-tap-outline"),e&&(e=Array.isArray(e)?e:[e]).forEach(e=>{var t=document.createElement("button");t.textContent=e.name.replace(/[_-]\w/g,e=>e.slice(1).toUpperCase()).replace(/([A-Z])/g," $1").replace(/^\w/,e=>e.toUpperCase()),t.onclick=()=>{f(),e()},p.insertBefore(t,p.firstChild)});u=document.createElement("button"),u.textContent=e?"Dismiss":"OK",p.insertBefore(u,p.firstChild),p.lastChild.classList.add("primary-modal-btn"),o=document.createElement("div");if(a){o.classList.add("checkbox-group");let e=a,t=document.createElement("input");t.type="checkbox",t.onchange=e;r=document.createElement("label");r.onclick=()=>{t.checked=!t.checked,e()},r.textContent=e.name[0].toUpperCase()+e.name.slice(1).replace(/([A-Z])/g,(e,t)=>" "+t.toLowerCase()).replace(/\b(\w+)nt\b/gi,"$1n't").trim(),o.append(t),o.append(r)}e=document.createElement("div"),e.title="Close",e.classList.add("modal-close-btn","no-mobile-tap-outline"),a=document.createElementNS("http://www.w3.org/2000/svg","svg"),a.setAttribute("height","10px"),a.setAttribute("viewBox","0 0 14 14"),a.setAttribute("fill","none"),r=document.createElementNS("http://www.w3.org/2000/svg","path");r.setAttribute("fill-rule","evenodd"),r.setAttribute("clip-rule","evenodd"),r.setAttribute("fill",chatgpt.isDarkMode()?"white":"black"),r.setAttribute("d","M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z"),a.append(r),e.append(a),l.append(e,d,g,o,p),l.style.width=`${t||458}px`,c.append(l),document.body.append(c);let m=JSON.parse(localStorage.alertQueue),f=(m.push(c.id),localStorage.alertQueue=JSON.stringify(m),c.style.display="none",1==m.length&&(c.style.display="",setTimeout(()=>{l.parentNode.style.backgroundColor=`rgba(67,70,72,${"dark"==n?.62:.33})`,l.parentNode.classList.add("animated")},100)),[c,e,a,u].forEach(e=>e.onclick=i.dismiss.click),document.addEventListener("keydown",i.dismiss.key),l.onmousedown=i.drag.mousedown,()=>{c.style.backgroundColor="transparent",l.style.animation="alert-zoom-fade-out 0.165s ease-out",l.onanimationend=()=>{if(c.remove(),(m=JSON.parse(localStorage.alertQueue)).shift(),localStorage.alertQueue=JSON.stringify(m),document.removeEventListener("keydown",i.dismiss.key),0<m.length){let e=document.getElementById(m[0]);setTimeout(()=>{e.style.display="",setTimeout(()=>e.classList.add("animated"),100)},500)}}});return c.id},async askAndGetReply(e){return chatgpt.send(e),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},autoRefresh:{activate(e){if(this.isActive)return console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh already active!`);let o=this,r=(this.toggle.refreshFrame(),t=>{var e=Math.max(2,Math.floor(21*chatgpt.randomFloat()-10));o.isActive=setTimeout(()=>{var e=document.querySelector(chatgpt.selectors.ssgManifest);e&&(document.querySelector("#refresh-frame").src=e.src+"?"+Date.now(),console.log(`↻ ChatGPT >> [${o.nowTimeStamp()}] ChatGPT session refreshed`)),r(t)},1e3*(t+e))});r(e?parseInt(e,10):30),console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh activated`),navigator.userAgent.includes("Chrome")&&void 0!==document.hidden&&document.addEventListener("visibilitychange",this.toggle.beacons)},deactivate(){this.isActive?(this.toggle.refreshFrame(),document.removeEventListener("visibilitychange",this.toggle.beacons),clearTimeout(this.isActive),this.isActive=null,console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh de-activated`)):console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh already inactive!`)},nowTimeStamp(){var e=new Date,t=e.getHours()%12||12;let o=e.getMinutes(),r=e.getSeconds();o<10&&(o="0"+o),r<10&&(r="0"+r);e=e.getHours()<12?"AM":"PM";return`${t}:${o}:${r} `+e},toggle:{beacons(){chatgpt.autoRefresh.beaconID?(clearInterval(chatgpt.autoRefresh.beaconID),chatgpt.autoRefresh.beaconID=null,console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Beacons de-activated`)):(chatgpt.autoRefresh.beaconID=setInterval(()=>{navigator.sendBeacon("https://httpbin.org/post",new Uint8Array),console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Beacon sent`)},9e4),console.log(`ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Beacons activated`))},refreshFrame(){let e=document.querySelector("#refresh-frame");e?e.remove():(e=Object.assign(document.createElement("iframe"),{id:"refresh-frame",style:"display: none"}),document.head.prepend(e))}}},browser:{isLightMode(){return window.matchMedia?.("(prefers-color-scheme: light)")?.matches},isDarkMode(){return window.matchMedia?.("(prefers-color-scheme: dark)")?.matches},isChromium(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Chromium")},isChrome(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Chrome")},isEdge(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Edge")},isBrave(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Brave")},isFirefox(){return navigator.userAgent.includes("Firefox")},isFullScreen(){var e=navigator.userAgent;return e.includes("Chrome")?window.matchMedia("(display-mode: fullscreen)").matches:e.includes("Firefox")?window.fullScreen:/MSIE|rv:/.test(e)?document.msFullscreenElement:document.webkitIsFullScreen},isMobile(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}},async clearChats(){return new Promise((o,r)=>chatgpt.getAccessToken().then(e=>{let t=new XMLHttpRequest;t.open("PATCH",chatgpt.endpoints.openAI.chats,!0),t.setRequestHeader("Content-Type","application/json"),t.setRequestHeader("Authorization","Bearer "+e),t.onload=()=>{if(200!=t.status)return r("🤖 chatgpt.js >> Request failed. Cannot clear chats.");console.info("Chats successfully cleared"),o()},t.send(JSON.stringify({is_visible:!1}))}).catch(e=>r(new Error(e.message))))},code:{async execute(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Display the output as if you were terminal:\n\n"+e),console.info("Executing code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},extract(e){var t=e.match(/(?<=```.*\n)[\s\S]*?(?=```)/g);return t?t[t.length-1]:e},async isIdle(t=null){let a={childList:!0,subtree:!0};var e=t?new Promise(e=>setTimeout(()=>e(!1),t)):null,o=(async()=>{await new Promise(o=>{document.querySelector(chatgpt.selectors.chatDivs.msg)?o():new MutationObserver((e,t)=>{document.querySelector(chatgpt.selectors.chatDivs.msg)&&(t.disconnect(),o())}).observe(document.body,a)}),await new Promise(o=>new MutationObserver((e,t)=>{chatgpt.getStopBtn()&&(t.disconnect(),o())}).observe(document.body,{childList:!0,subtree:!0}));let e=document.querySelectorAll(chatgpt.selectors.chatDivs.reply),r=e[e.length-1];return await new Promise(o=>new MutationObserver((e,t)=>{r?.querySelector("pre")&&(t.disconnect(),o())}).observe(document.body,a)),new Promise(o=>new MutationObserver((e,t)=>{!r?.querySelector("pre")?.nextElementSibling&&chatgpt.getStopBtn()||(t.disconnect(),o(!0))}).observe(document.body,a))})();return e?Promise.race([o,e]):o},async minify(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Minify the following code:\n\n"+e),console.info("Minifying code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},async obfuscate(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Obfuscate the following code:\n\n"+e),console.info("Obfuscating code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},async refactor(e,t){if(!e)return console.error("Code (1st) argument not supplied. Pass some code!");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send(`Refactor the following code for ${t||"brevity"}:
77
+ cursor: pointer ; font-size: 14px ; color: ${"dark"==n?"#e1e1e1":"#1e1e1e"}}`),d.textContent=o||"",g.innerText=r||"",chatgpt.renderHTML(g),document.createElement("div"));p.classList.add("modal-buttons","no-mobile-tap-outline"),e&&(e=Array.isArray(e)?e:[e]).forEach(e=>{var t=document.createElement("button");t.textContent=e.name.replace(/[_-]\w/g,e=>e.slice(1).toUpperCase()).replace(/([A-Z])/g," $1").replace(/^\w/,e=>e.toUpperCase()),t.onclick=()=>{f(),e()},p.insertBefore(t,p.firstChild)});h=document.createElement("button"),h.textContent=e?"Dismiss":"OK",p.insertBefore(h,p.firstChild),p.lastChild.classList.add("primary-modal-btn"),o=document.createElement("div");if(a){o.classList.add("checkbox-group");let e=a,t=document.createElement("input");t.type="checkbox",t.onchange=e;r=document.createElement("label");r.onclick=()=>{t.checked=!t.checked,e()},r.textContent=e.name[0].toUpperCase()+e.name.slice(1).replace(/([A-Z])/g,(e,t)=>" "+t.toLowerCase()).replace(/\b(\w+)nt\b/gi,"$1n't").trim(),o.append(t),o.append(r)}e=document.createElement("div"),e.title="Close",e.classList.add("modal-close-btn","no-mobile-tap-outline"),a=document.createElementNS("http://www.w3.org/2000/svg","svg"),a.setAttribute("height","10px"),a.setAttribute("viewBox","0 0 14 14"),a.setAttribute("fill","none"),r=document.createElementNS("http://www.w3.org/2000/svg","path");r.setAttribute("fill-rule","evenodd"),r.setAttribute("clip-rule","evenodd"),r.setAttribute("fill",chatgpt.isDarkMode()?"white":"black"),r.setAttribute("d","M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z"),a.append(r),e.append(a),l.append(e,d,g,o,p),l.style.width=`${t||458}px`,c.append(l),document.body.append(c);let m=JSON.parse(localStorage.alertQueue),f=(m.push(c.id),localStorage.alertQueue=JSON.stringify(m),c.style.display="none",1==m.length&&(c.style.display="",setTimeout(()=>{l.parentNode.style.backgroundColor=`rgba(67,70,72,${"dark"==n?.62:.33})`,l.parentNode.classList.add("animated")},100)),[c,e,a,h].forEach(e=>e.onclick=i.dismiss.click),document.addEventListener("keydown",i.dismiss.key),l.onmousedown=i.drag.mousedown,()=>{c.style.backgroundColor="transparent",l.style.animation="alert-zoom-fade-out 0.165s ease-out",l.onanimationend=()=>{if(c.remove(),(m=JSON.parse(localStorage.alertQueue)).shift(),localStorage.alertQueue=JSON.stringify(m),document.removeEventListener("keydown",i.dismiss.key),0<m.length){let e=document.getElementById(m[0]);setTimeout(()=>{e.style.display="",setTimeout(()=>e.classList.add("animated"),100)},500)}}});return c.id},async askAndGetReply(e){return chatgpt.send(e),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},autoRefresh:{activate(e){if(this.isActive)return console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh already active!`);let o=this,r=(this.toggle.refreshFrame(),t=>{var e=Math.max(2,Math.floor(21*chatgpt.randomFloat()-10));o.isActive=setTimeout(()=>{var e=document.querySelector(chatgpt.selectors.ssgManifest);e&&(document.querySelector("#refresh-frame").src=e.src+"?"+Date.now(),console.log(`↻ ChatGPT >> [${o.nowTimeStamp()}] ChatGPT session refreshed`)),r(t)},1e3*(t+e))});r(e?parseInt(e,10):30),console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh activated`),navigator.userAgent.includes("Chrome")&&void 0!==document.hidden&&document.addEventListener("visibilitychange",this.toggle.beacons)},deactivate(){this.isActive?(this.toggle.refreshFrame(),document.removeEventListener("visibilitychange",this.toggle.beacons),clearTimeout(this.isActive),this.isActive=null,console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh de-activated`)):console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh already inactive!`)},nowTimeStamp(){var e=new Date,t=e.getHours()%12||12;let o=e.getMinutes(),r=e.getSeconds();o<10&&(o="0"+o),r<10&&(r="0"+r);e=e.getHours()<12?"AM":"PM";return`${t}:${o}:${r} `+e},toggle:{beacons(){chatgpt.autoRefresh.beaconID?(clearInterval(chatgpt.autoRefresh.beaconID),chatgpt.autoRefresh.beaconID=null,console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Beacons de-activated`)):(chatgpt.autoRefresh.beaconID=setInterval(()=>{navigator.sendBeacon("https://httpbin.org/post",new Uint8Array),console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Beacon sent`)},9e4),console.log(`ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Beacons activated`))},refreshFrame(){let e=document.querySelector("#refresh-frame");e?e.remove():(e=Object.assign(document.createElement("iframe"),{id:"refresh-frame",style:"display: none"}),document.head.prepend(e))}}},browser:{isLightMode(){return window.matchMedia?.("(prefers-color-scheme: light)")?.matches},isDarkMode(){return window.matchMedia?.("(prefers-color-scheme: dark)")?.matches},isChromium(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Chromium")},isChrome(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Chrome")},isEdge(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Edge")},isBrave(){return!!JSON.stringify(navigator.userAgentData?.brands)?.includes("Brave")},isFirefox(){return navigator.userAgent.includes("Firefox")},isFullScreen(){var e=navigator.userAgent;return e.includes("Chrome")?window.matchMedia("(display-mode: fullscreen)").matches:e.includes("Firefox")?window.fullScreen:/MSIE|rv:/.test(e)?document.msFullscreenElement:document.webkitIsFullScreen},isMobile(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}},async clearChats(){return new Promise((o,r)=>chatgpt.getAccessToken().then(e=>{let t=new XMLHttpRequest;t.open("PATCH",chatgpt.endpoints.openAI.chats,!0),t.setRequestHeader("Content-Type","application/json"),t.setRequestHeader("Authorization","Bearer "+e),t.onload=()=>{if(200!=t.status)return r("🤖 chatgpt.js >> Request failed. Cannot clear chats.");console.info("Chats successfully cleared"),o()},t.send(JSON.stringify({is_visible:!1}))}).catch(e=>r(new Error(e.message))))},code:{async execute(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Display the output as if you were terminal:\n\n"+e),console.info("Executing code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},extract(e){var t=e.match(/(?<=```.*\n)[\s\S]*?(?=```)/g);return t?t[t.length-1]:e},async isIdle(t=null){let a={childList:!0,subtree:!0};var e=t?new Promise(e=>setTimeout(()=>e(!1),t)):null,o=(async()=>{await new Promise(o=>{document.querySelector(chatgpt.selectors.chatDivs.msg)?o():new MutationObserver((e,t)=>{document.querySelector(chatgpt.selectors.chatDivs.msg)&&(t.disconnect(),o())}).observe(document.body,a)}),await new Promise(o=>new MutationObserver((e,t)=>{chatgpt.getStopBtn()&&(t.disconnect(),o())}).observe(document.body,{childList:!0,subtree:!0}));let e=document.querySelectorAll(chatgpt.selectors.chatDivs.reply),r=e[e.length-1];return await new Promise(o=>new MutationObserver((e,t)=>{r?.querySelector("pre")&&(t.disconnect(),o())}).observe(document.body,a)),new Promise(o=>new MutationObserver((e,t)=>{!r?.querySelector("pre")?.nextElementSibling&&chatgpt.getStopBtn()||(t.disconnect(),o(!0))}).observe(document.body,a))})();return e?Promise.race([o,e]):o},async minify(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Minify the following code:\n\n"+e),console.info("Minifying code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},async obfuscate(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Obfuscate the following code:\n\n"+e),console.info("Obfuscating code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},async refactor(e,t){if(!e)return console.error("Code (1st) argument not supplied. Pass some code!");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send(`Refactor the following code for ${t||"brevity"}:
78
78
 
79
79
  `+e),console.info("Refactoring code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))},async review(e){return e?"string"==typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Review the following code for me:\n\n"+e),console.info("Reviewing code..."),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")):console.error("Code argument not supplied. Pass some code!")},async unminify(e){return e?"string"!=typeof e?console.error("Code argument must be a string!"):(chatgpt.send("Unminify the following code.:\n\n"+e),console.info("Unminifying code..."),await chatgpt.isIdle(),chatgpt.code.extract(await chatgpt.getChatData("active","msg","chatgpt","latest"))):console.error("Code argument not supplied. Pass some code!")},async write(e,t){if(!e)return console.error("Prompt (1st) argument not supplied. Pass a prompt!");if(!t)return console.error("outputLang (2nd) argument not supplied. Pass a language!");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send(e+`
80
80
 
@@ -85,8 +85,8 @@ Write this as code in `+t),console.info("Writing code..."),await chatgpt.isIdle(
85
85
  CHATGPT: ${l.chatgpt}
86
86
 
87
87
  `}else{s=await(await fetch(await chatgpt.shareChat(e))).text(),i=(new DOMParser).parseFromString(s,"text/html");o=`${i.querySelector("title").textContent||"ChatGPT conversation"}.html`,i.querySelectorAll("link[rel=stylesheet]").forEach(e=>{var t=e.getAttribute("href");t?.startsWith("/")&&e.setAttribute("href","https://chat.openai.com"+t)}),a=(new XMLSerializer).serializeToString(i)}if(console.info(`Exporting transcript as ${t.toUpperCase()}...`),"pdf"==t){a=a.replace(/<svg.*?<\/svg>/g,e=>`<img src="${"data:image/svg+xml,"+encodeURIComponent(e)}">`);let e=window.open("","","toolbar=0, location=0, menubar=0, height=600, width=800");e.document.write(a),setTimeout(()=>{e.print({toPDF:!0})},100)}else{"md"==t&&(c=/<.*<h1(.|\n)*?href=".*?continue[^"]*".*?\/a>.*?<[^/]/.exec(a)[1],a=c||a,o=o.replace(".html",".md"));r=new Blob([a],{type:"text/"+("html"==t?"html":"md"==t?"markdown":"plain")}),n=document.createElement("a"),e=URL.createObjectURL(r);n.href=e,n.download=o,document.body.append(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(e)}},extractCode(){chatgpt.code.extract()},focusChatbar(){chatgpt.getChatBox()?.focus()},footer:{get(){return document.querySelector(chatgpt.selectors.footer)},hide(){var e=chatgpt.footer.get();return e?"hidden"==e.style.visibility?console.info("Footer already hidden!"):void(e.style.display="none"):console.error("Footer element not found!")},show(){var e=chatgpt.footer.get();return e?"hidden"!=e.style.visibility?console.info("Footer already shown!"):void(e.style.display="inherit"):console.error("Footer element not found!")}},generateRandomIP(){var e=Array.from({length:4},()=>Math.floor(256*chatgpt.randomFloat())).join(".");return console.info("IP generated: "+e),e},get(e,t=""){if("string"!=typeof e||"string"!=typeof t)throw new TypeError("Invalid arguments. Both arguments must be strings.");if(!cjsTargetTypes.includes(e.toLowerCase()))throw new Error(`Invalid targetType: ${e}. Valid values are: `+JSON.stringify(cjsTargetTypes));var o,r=[],a=new RegExp(`^get(.*)${e}$`,"i");for(o in chatgpt)"function"==typeof chatgpt[o]&&a.test(o)&&r.push(o.replace(a,"$1").toLowerCase());if(!r.includes(t.toLowerCase()))throw new Error(`Invalid targetName: ${t}. `+(0<r.length?"Valid values are: "+JSON.stringify(r):"targetType "+e.toLowerCase()+" does not require additional options."));let n=("get"+t+e).toLowerCase();return this[Object.keys(this).find(e=>e.toLowerCase()==n)]()},getAccessToken(){return new Promise((e,t)=>{if(chatgpt.accessToken&&0<=Date.parse(chatgpt.accessToken.expireDate)-Date.parse(new Date))return e(chatgpt.accessToken.token);let o=new XMLHttpRequest;o.open("GET",chatgpt.endpoints.openAI.session,!0),o.setRequestHeader("Content-Type","application/json"),o.onload=()=>{if(200!=o.status)return t("🤖 chatgpt.js >> Request failed. Cannot retrieve access token.");console.info("Token expiration: "+new Date(JSON.parse(o.responseText).expires).toLocaleString().replace(","," at")),chatgpt.accessToken={token:JSON.parse(o.responseText).accessToken,expireDate:JSON.parse(o.responseText).expires},e(chatgpt.accessToken.token)},o.send()})},getAccountDetails(...s){var e,t=["email","id","image","name","picture"];for(e of s=arguments[0]?Array.isArray(arguments[0])?arguments[0]:Array.from(arguments):t)if(!t.includes(e))return console.error(`Invalid detail arg '${e}' supplied. Valid details are:
88
- `+` [${t}]`);return new Promise((r,a)=>{let n=new XMLHttpRequest;n.open("GET",chatgpt.endpoints.openAI.session,!0),n.setRequestHeader("Content-Type","application/json"),n.onload=()=>{if(200!=n.status)return a("🤖 chatgpt.js >> Request failed. Cannot retrieve account details.");var e,t=JSON.parse(n.responseText).user,o={};for(e of s)o[e]=t[e];return r(o)},n.send()})},getChatBox(){return document.getElementById("prompt-textarea")},getChatData(d=1,o="all",h="all",p="all"){var e,t=["all","id","title","create_time","update_time","msg"],r=["all","both","user","chatgpt"];d=d?Number.isInteger(d)||/^\d+$/.test(d)?0==parseInt(d,10)?0:parseInt(d,10)-1:d:"active",o=["all",""].includes(o)?t.filter(e=>/^(?!all$|msg$).*/.test(e)):Array.isArray(o)?o:[o],h=h?r.includes(h)?h:"invalid":"all",p=Number.isInteger(p)||/^\d+$/.test(p)?0==parseInt(p,10)?0:parseInt(p,10)-1:["all","latest"].includes(p.toLowerCase())?p.toLowerCase():p?"invalid":"all";for(e of o)if(!t.includes(e))return console.error(`Invalid detail arg '${e}' passed. Valid details are:
89
- `+` [${t}]`);if("invalid"==h)return console.error("Invalid sender arg passed. Valid senders are:\n"+` [${r}]`);if("invalid"==p)return console.error("Invalid msgToGet arg passed. Valid msg's to get are:\n [ 'all' | 'latest' | index of msg to get ]");let a=(e,c)=>{let l=/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/;return new Promise((t,s)=>{let i=new XMLHttpRequest;i.open("GET",chatgpt.endpoints.openAI.chats,!0),i.setRequestHeader("Content-Type","application/json"),i.setRequestHeader("Authorization","Bearer "+e),i.onload=()=>{if(200!=i.status)return s("🤖 chatgpt.js >> Request failed. Cannot retrieve chat details.");var o=JSON.parse(i.responseText).items;if(o.length<=0)return s("🤖 chatgpt.js >> Chat list is empty.");var r={};if(Number.isInteger(d)||"latest"==d||"active"==d&&!new RegExp(`/${l.source}$`).test(location.href)){if((d=Number.isInteger(d)?d:0)>o.length)return s("🤖 chatgpt.js >> Chat with index "+(d+1)+` is out of bounds. Only ${o.length} chats exist!`);for(var e of c)r[e]=o[d][e]}else{var a,n="active"==d||new RegExp(`^${l.source}$`).test(d)?"id":"title";"active"==d&&(d=l.exec(window.location.href)[0]);let e,t;for(e=0;e<o.length;e++)if(o[e][n]==d){t=!0;break}if(!t)return s(`🤖 chatgpt.js >> No chat with ${n} = ${d} found.`);for(a of c)r[a]=o[e][a]}return t(r)},i.send()})},n=t=>new Promise((d,g)=>{let u=new XMLHttpRequest;a(t,["id"]).then(e=>{u.open("GET",chatgpt.endpoints.openAI.chat+"/"+e.id,!0),u.setRequestHeader("Content-Type","application/json"),u.setRequestHeader("Authorization","Bearer "+t),u.onload=()=>{if(200!=u.status)return g("🤖 chatgpt.js >> Request failed. Cannot retrieve chat messages.");let n=JSON.parse(u.responseText).mapping;var e,t,o=[],r=[],a=[];for(e in n)null!=n[e].message&&"user"==n[e].message.author.role&&o.push({id:n[e].id,msg:n[e].message});if(o.sort((e,t)=>e.msg.create_time-t.msg.create_time),parseInt(p,10)+1>o.length)return g("🤖 chatgpt.js >> Message/response with index "+(p+1)+` is out of bounds. Only ${o.length} messages/responses exist!`);for(t of o){let e=[];for(var s in n)null!=n[s].message&&"assistant"==n[s].message.author.role&&((e,t)=>{let o=e,r=0;for(;o&&r<10;){var a=n[o];if(!a?.message)return;if(a.id==t)return 1;o=a.parent,r++}})(s,t.id)&&e.push(n[s].message);e.sort((e,t)=>e.create_time-t.create_time),e=1==(e=e.map(e=>{switch(e.content.content_type){case"code":return e.content.text;case"text":return e.content.parts[0];default:return}})).length?e[0]:e,r.push(e)}if("user"==h)for(var i in o)a.push(o[i].msg.content.parts[0]);else if("chatgpt"==h)for(var c of r)a.push("latest"==p?r[r.length-1]:c);else{let e=0;for(var l in o)a.push({user:o[l].msg.content.parts[0],chatgpt:"latest"==p?r[e][r[e].length-1]:r[e]}),e++}return d("all"==p?a:"latest"==p?a[a.length-1]:a[p])},u.send()})});return new Promise(t=>chatgpt.getAccessToken().then(e=>t(o.includes("msg")?n(e):a(e,o))))},getChatInput(){return chatgpt.getChatBox().firstChild.innerText},getContinueButton(){return document.querySelector(chatgpt.selectors.btns.continue)},getErrorMsg(){return document.querySelector(chatgpt.selectors.errors.txt+":last-of-type")?.innerText},getFooterDiv(){return chatgpt.footer.get()},getHeaderDiv(){return chatgpt.header.get()},getLastPrompt(){return chatgpt.getChatData("active","msg","user","latest")},getLastResponse(){return chatgpt.getChatData("active","msg","chatgpt","latest")},getLoginButton(){return document.querySelector(chatgpt.selectors.btns.login)},getNewChatButton(){return document.querySelector(chatgpt.selectors.btns.newChat)},getNewChatLink(){return document.querySelector(chatgpt.selectors.links.newChat)},getRegenerateButton(){return document.querySelector(chatgpt.selectors.btns.regen)},getResponse(){return chatgpt.response.get(...arguments)},getResponseFromAPI(e,t){return chatgpt.response.getFromAPI(e,t)},getResponseFromDOM(e){return chatgpt.response.getFromDOM(e)},getScrollToBottomButton(){return document.querySelector(chatgpt.selectors.btns.scroll)},getSendButton(){return document.querySelector(chatgpt.selectors.btns.send)},getStopButton(){return document.querySelector(chatgpt.selectors.btns.stop)},getUserLanguage(){return navigator.languages[0]||navigator.language||navigator.browserLanguage||navigator.systemLanguage||navigator.userLanguage||""},getVoiceButton(){return document.querySelector(chatgpt.selectors.btns.voice)},header:{get(){return document.querySelector(chatgpt.selectors.header)},hide(){chatgpt.header.get().style.display="none"},show(){chatgpt.header.get().style.display="flex"}},hideFooter(){chatgpt.footer.hide()},hideHeader(){chatgpt.header.hide()},history:{async isLoaded(t=null){var e=t?new Promise(e=>setTimeout(()=>e(!1),t)):null,o=new Promise(o=>{document.querySelector(chatgpt.selectors.chatHistory)?o(!0):new MutationObserver((e,t)=>{document.querySelector(chatgpt.selectors.chatHistory)&&(t.disconnect(),o(!0))}).observe(document.documentElement,{childList:!0,subtree:!0})});return e?Promise.race([o,e]):o}},instructions:{add(r,a){var e;return r?"string"!=typeof r?console.error("Instruction must be a string"):(e=["user","chatgpt"],a?"string"!=typeof a?console.error("Target must be a string"):(a=a.toLowerCase(),e.includes(a)?(r=`
88
+ `+` [${t}]`);return new Promise((r,a)=>{let n=new XMLHttpRequest;n.open("GET",chatgpt.endpoints.openAI.session,!0),n.setRequestHeader("Content-Type","application/json"),n.onload=()=>{if(200!=n.status)return a("🤖 chatgpt.js >> Request failed. Cannot retrieve account details.");var e,t=JSON.parse(n.responseText).user,o={};for(e of s)o[e]=t[e];return r(o)},n.send()})},getChatBox(){return document.getElementById("prompt-textarea")},getChatData(d=1,o="all",u="all",p="all"){var e,t=["all","id","title","create_time","update_time","msg"],r=["all","both","user","chatgpt"];d=d?Number.isInteger(d)||/^\d+$/.test(d)?0==parseInt(d,10)?0:parseInt(d,10)-1:d:"active",o=["all",""].includes(o)?t.filter(e=>/^(?!all$|msg$).*/.test(e)):Array.isArray(o)?o:[o],u=u?r.includes(u)?u:"invalid":"all",p=Number.isInteger(p)||/^\d+$/.test(p)?0==parseInt(p,10)?0:parseInt(p,10)-1:["all","latest"].includes(p.toLowerCase())?p.toLowerCase():p?"invalid":"all";for(e of o)if(!t.includes(e))return console.error(`Invalid detail arg '${e}' passed. Valid details are:
89
+ `+` [${t}]`);if("invalid"==u)return console.error("Invalid sender arg passed. Valid senders are:\n"+` [${r}]`);if("invalid"==p)return console.error("Invalid msgToGet arg passed. Valid msg's to get are:\n [ 'all' | 'latest' | index of msg to get ]");let a=(e,c)=>{let l=/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/;return new Promise((t,s)=>{let i=new XMLHttpRequest;i.open("GET",chatgpt.endpoints.openAI.chats,!0),i.setRequestHeader("Content-Type","application/json"),i.setRequestHeader("Authorization","Bearer "+e),i.onload=()=>{if(200!=i.status)return s("🤖 chatgpt.js >> Request failed. Cannot retrieve chat details.");var o=JSON.parse(i.responseText).items;if(o.length<=0)return s("🤖 chatgpt.js >> Chat list is empty.");var r={};if(Number.isInteger(d)||"latest"==d||"active"==d&&!new RegExp(`/${l.source}$`).test(location.href)){if((d=Number.isInteger(d)?d:0)>o.length)return s("🤖 chatgpt.js >> Chat with index "+(d+1)+` is out of bounds. Only ${o.length} chats exist!`);for(var e of c)r[e]=o[d][e]}else{var a,n="active"==d||new RegExp(`^${l.source}$`).test(d)?"id":"title";"active"==d&&(d=l.exec(window.location.href)[0]);let e,t;for(e=0;e<o.length;e++)if(o[e][n]==d){t=!0;break}if(!t)return s(`🤖 chatgpt.js >> No chat with ${n} = ${d} found.`);for(a of c)r[a]=o[e][a]}return t(r)},i.send()})},n=t=>new Promise((d,g)=>{let h=new XMLHttpRequest;a(t,["id"]).then(e=>{h.open("GET",chatgpt.endpoints.openAI.chat+"/"+e.id,!0),h.setRequestHeader("Content-Type","application/json"),h.setRequestHeader("Authorization","Bearer "+t),h.onload=()=>{if(200!=h.status)return g("🤖 chatgpt.js >> Request failed. Cannot retrieve chat messages.");let n=JSON.parse(h.responseText).mapping;var e,t,o=[],r=[],a=[];for(e in n)null!=n[e].message&&"user"==n[e].message.author.role&&o.push({id:n[e].id,msg:n[e].message});if(o.sort((e,t)=>e.msg.create_time-t.msg.create_time),parseInt(p,10)+1>o.length)return g("🤖 chatgpt.js >> Message/response with index "+(p+1)+` is out of bounds. Only ${o.length} messages/responses exist!`);for(t of o){let e=[];for(var s in n)null!=n[s].message&&"assistant"==n[s].message.author.role&&((e,t)=>{let o=e,r=0;for(;o&&r<10;){var a=n[o];if(!a?.message)return;if(a.id==t)return 1;o=a.parent,r++}})(s,t.id)&&e.push(n[s].message);e.sort((e,t)=>e.create_time-t.create_time),e=1==(e=e.map(e=>{switch(e.content.content_type){case"code":return e.content.text;case"text":return e.content.parts[0];default:return}})).length?e[0]:e,r.push(e)}if("user"==u)for(var i in o)a.push(o[i].msg.content.parts[0]);else if("chatgpt"==u)for(var c of r)a.push("latest"==p?r[r.length-1]:c);else{let e=0;for(var l in o)a.push({user:o[l].msg.content.parts[0],chatgpt:"latest"==p?r[e][r[e].length-1]:r[e]}),e++}return d("all"==p?a:"latest"==p?a[a.length-1]:a[p])},h.send()})});return new Promise(t=>chatgpt.getAccessToken().then(e=>t(o.includes("msg")?n(e):a(e,o))))},getChatInput(){return chatgpt.getChatBox().firstChild.innerText},getContinueButton(){return document.querySelector(chatgpt.selectors.btns.continue)},getErrorMsg(){return document.querySelector(chatgpt.selectors.errors.txt+":last-of-type")?.innerText},getFooterDiv(){return chatgpt.footer.get()},getHeaderDiv(){return chatgpt.header.get()},getLastPrompt(){return chatgpt.getChatData("active","msg","user","latest")},getLastResponse(){return chatgpt.getChatData("active","msg","chatgpt","latest")},getLoginButton(){return document.querySelector(chatgpt.selectors.btns.login)},getNewChatButton(){return document.querySelector(chatgpt.selectors.btns.newChat)},getNewChatLink(){return document.querySelector(chatgpt.selectors.links.newChat)},getRegenerateButton(){return document.querySelector(chatgpt.selectors.btns.regen)},getResponse(){return chatgpt.response.get(...arguments)},getResponseFromAPI(e,t){return chatgpt.response.getFromAPI(e,t)},getResponseFromDOM(e){return chatgpt.response.getFromDOM(e)},getScrollToBottomButton(){return document.querySelector(chatgpt.selectors.btns.scroll)},getSendButton(){return document.querySelector(chatgpt.selectors.btns.send)},getStopButton(){return document.querySelector(chatgpt.selectors.btns.stop)},getUserLanguage(){return navigator.languages[0]||navigator.language||navigator.browserLanguage||navigator.systemLanguage||navigator.userLanguage||""},getVoiceButton(){return document.querySelector(chatgpt.selectors.btns.voice)},header:{get(){return document.querySelector(chatgpt.selectors.header)},hide(){chatgpt.header.get().style.display="none"},show(){chatgpt.header.get().style.display="flex"}},hideFooter(){chatgpt.footer.hide()},hideHeader(){chatgpt.header.hide()},history:{async isLoaded(t=null){var e=t?new Promise(e=>setTimeout(()=>e(!1),t)):null,o=new Promise(o=>{document.querySelector(chatgpt.selectors.chatHistory)?o(!0):new MutationObserver((e,t)=>{document.querySelector(chatgpt.selectors.chatHistory)&&(t.disconnect(),o(!0))}).observe(document.documentElement,{childList:!0,subtree:!0})});return e?Promise.race([o,e]):o}},instructions:{add(r,a){var e;return r?"string"!=typeof r?console.error("Instruction must be a string"):(e=["user","chatgpt"],a?"string"!=typeof a?console.error("Target must be a string"):(a=a.toLowerCase(),e.includes(a)?(r=`
90
90
 
91
91
  `+r,new Promise(o=>{chatgpt.getAccessToken().then(async e=>{var t=await this.fetchData();return"user"==a?t.about_user_message+=r:"chatgpt"==a&&(t.about_model_message+=r),await this.sendRequest("POST",e,t),o()})})):console.error(`Invalid target ${a}. Valid targets are [${e}]`)):console.error("Please provide a valid target!")):console.error("Please provide an instruction")},clear(r){var e=["user","chatgpt"];return r?"string"!=typeof r?console.error("Target must be a string"):(r=r.toLowerCase(),e.includes(r)?new Promise(o=>{chatgpt.getAccessToken().then(async e=>{var t=await this.fetchData();return"user"==r?t.about_user_message="":"chatgpt"==r&&(t.about_model_message=""),await this.sendRequest("POST",e,t),o()})}):console.error(`Invalid target ${r}. Valid targets are [${e}]`)):console.error("Please provide a valid target!")},fetchData(){return new Promise(t=>chatgpt.getAccessToken().then(async e=>t(await this.sendRequest("GET",e))))},sendRequest(a,e,n){for(let e=0;e<arguments.length-1;e++)if("string"==typeof arguments[e])return console.error(`Argument ${e+1} must be a string`);var t=["POST","GET"];return(a=(a||"").trim().toUpperCase())&&t.includes(a)?e?n&&"object"!=typeof n?console.error(`Invalid body data type. Got ${typeof n}, expected object`):new Promise((t,o)=>{let r=new XMLHttpRequest;r.open(a,chatgpt.endpoints.openAI.instructions,!0),r.setRequestHeader("Accept-Language","en-US"),r.setRequestHeader("Authorization","Bearer "+e),"POST"==a&&r.setRequestHeader("Content-Type","application/json"),r.onload=()=>{var e=JSON.parse(r.responseText);return 422==r.status?o("🤖 chatgpt.js >> Character limit exceeded. Custom instructions can have a maximum length of 1500 characters."):403==r.status&&"content_policy"==e.detail.reason?o("🤖 chatgpt.js >> "+e.detail.description):200!=r.status?o("🤖 chatgpt.js >> Request failed. Cannot contact custom instructions endpoint."):(console.info("Custom instructions successfully contacted with method "+a),t(e||{}))},r.send(JSON.stringify(n)||"")}):console.error("Please provide a valid access token!"):console.error("Valid methods are "+t)},turnOff(){return new Promise(o=>chatgpt.getAccessToken().then(async e=>{var t=await this.fetchData();return t.enabled=!1,await this.sendRequest("POST",e,t),o()}))},turnOn(){return new Promise(o=>chatgpt.getAccessToken().then(async e=>{var t=await this.fetchData();return t.enabled=!0,await this.sendRequest("POST",e,t),o()}))},toggle(){return new Promise(t=>this.fetchData().then(async e=>(await(e.enabled?this.turnOff():this.turnOn()),t())))}},isDarkMode(){return document.documentElement.classList.contains("dark")},isFullScreen(){return chatgpt.browser.isFullScreen()},async isIdle(t=null){let e={childList:!0,subtree:!0};var o=t?new Promise(e=>setTimeout(()=>e(!1),t)):null,r=(async()=>(await new Promise(o=>{document.querySelector(chatgpt.selectors.chatDivs.msg)?o():new MutationObserver((e,t)=>{document.querySelector(chatgpt.selectors.chatDivs.msg)&&(t.disconnect(),o())}).observe(document.body,e)}),await new Promise(o=>new MutationObserver((e,t)=>{chatgpt.getStopBtn()&&(t.disconnect(),o())}).observe(document.body,e)),new Promise(o=>new MutationObserver((e,t)=>{chatgpt.getStopBtn()||(t.disconnect(),o(!0))}).observe(document.body,e))))();return o?Promise.race([r,o]):r},async isLoaded(t=null){var e=t?new Promise(e=>setTimeout(()=>e(!1),t)):null,o=new Promise(o=>{chatgpt.getNewChatBtn()?o(!0):new MutationObserver((e,t)=>{chatgpt.getNewChatBtn()&&(t.disconnect(),o(!0))}).observe(document.documentElement,{childList:!0,subtree:!0})});return e?Promise.race([o,e]):o},isLightMode(){return document.documentElement.classList.contains("light")},isTempChat(){return"?temporary-chat=true"==location.search},isTyping(){return!!this.getStopButton()},login(){window.location.href="https://chat.openai.com/auth/login"},logout(){window.location.href="https://chat.openai.com/auth/logout"},menu:{elems:[],append(e,t={}){var o=["button","dropdown"];if(!e||"string"!=typeof e)return console.error("🤖 chatgpt.js >> Please supply a valid string element name!");if(e=e.toLowerCase(),!o.includes(e))return console.error(`🤖 chatgpt.js >> Invalid element! Valid elems are [${o}]`);let r=document.createElement("dropdown"==e?"select":"button"==e?"a":e);if(r.id=Math.floor(1e6*chatgpt.randomFloat())+Date.now(),"button"==e){r.textContent=t?.label&&"string"==typeof t.label?t.label:"chatgpt.js button";o=document.createElement("img");o.src=t?.icon&&"string"==typeof t.icon?t.icon:chatgpt.endpoints.assets+"/starters/chrome/extension/icons/icon128.png",o.width=18,r.firstChild.before(o),r.onclick=t?.onclick&&"function"==typeof t.onclick?t.onclick:function(){}}else if("dropdown"==e){if(t?.items&&Array.isArray(t.items)&&t.items.length||(t.items=[{text:"🤖 chatgpt.js option",value:"chatgpt.js option value"}]),!t.items.every(e=>"object"==typeof e))return console.error("'items' must be an array of objects!");r.style="background-color: #000; width: 100%; border: none;",t.items.forEach(e=>{var t=document.createElement("option");t.textContent=e?.text,t.value=e?.value,r.add(t)})}let a=()=>{var e,t=document.querySelectorAll("a[role=menuitem]");let o;for(e of t)if("Settings"==e.textContent){o=e.classList;break}let r=t[0].parentNode;chatgpt.menu.elems.forEach(e=>{if(e.setAttribute("class",o),!r.contains(e))try{r.firstChild.before(e)}catch(e){console.error(e)}})};this.elems.push(r);o=document.querySelector("nav button[id*=headless]");return this.addedEvent||(o?.addEventListener("click",()=>setTimeout(a,25)),this.addedEvent=!0),r.id},close(){try{document.querySelector("nav [id*=menu-button][aria-expanded=true]").click()}catch(e){console.error(e.message)}},open(){try{document.querySelector("nav [id*=menu-button][aria-expanded=false]").click()}catch(e){console.error(e.message)}}},minify(){chatgpt.code.minify()},notify(...e){var t=chatgpt.isDarkMode()?"dark":"light";let o,r,a,n,s,i=("object"!=typeof e[0]||Array.isArray(e[0])?[o,r,a,n]=e:{msg:o,position:r,notifDuration:a,shadow:n,toast:s}=e[0],a=a?+a:1.75,document.createElement("div"));i.id=Math.floor(1e6*chatgpt.randomFloat())+Date.now(),i.classList.add("chatgpt-notif"),i.textContent=o,document.body.append(i);var e=document.createElement("div"),c=(e.title="Dismiss",e.classList.add("notif-close-btn","no-mobile-tap-outline"),document.createElementNS("http://www.w3.org/2000/svg","svg")),l=(c.setAttribute("height","8px"),c.setAttribute("viewBox","0 0 14 14"),c.setAttribute("fill","none"),c.style.height=c.style.width="8px",document.createElementNS("http://www.w3.org/2000/svg","path")),l=(l.setAttribute("fill-rule","evenodd"),l.setAttribute("clip-rule","evenodd"),l.setAttribute("fill","white"),l.setAttribute("d","M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z"),c.append(l),e.append(c),i.append(e),i.isTop=!r||!/low|bottom/i.test(r),i.isRight=!r||!/left/i.test(r),i.quadrant=(i.isTop?"top":"bottom")+(i.isRight?"Right":"Left"),1746996635555);let d=document.querySelector("#chatgpt-notif-style"),g=((!d||parseInt(d.getAttribute("last-updated"),10)<l)&&(d||((d=document.createElement("style")).id="chatgpt-notif-style",d.setAttribute("last-updated",l.toString()),document.head.append(d)),d.textContent='.chatgpt-notif {font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC","Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;.no-mobile-tap-outline { outline: none ; -webkit-tap-highlight-color: transparent }background-color: black ; padding: 10px 13px 10px 18px ;border-radius: 11px ; border: 1px solid #f5f5f7 ;opacity: 0 ; position: fixed ; z-index: 9999 ; font-size: 1.8rem ; color: white ;user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -o-user-select: none ;-ms-user-select: none ;'+`transform: translateX(${i.isRight?"":"-"}35px) ;`+(n?`--shadow: -8px 13px 25px 0 ${/\b(?:shadow|on)\b/i.test(n)?"gray":n};
92
92
  box-shadow: var(--shadow) ; -webkit-box-shadow: var(--shadow) ; -moz-box-shadow: var(--shadow)`:"")+"}"+`.notif-close-btn {
@@ -96,6 +96,6 @@ CHATGPT: ${l.chatgpt}
96
96
  ${"dark"==t?"border: 2px solid white ;":""}
97
97
  margin-${i.isTop?"top: 42px":"bottom: 105px"};
98
98
  transform: translate(-50%, -50%) scale(0.6) !important }
99
- div.chatgpt-notif > div.notif-close-btn { top: 18px ; right: 7px ; transform: scale(2) }`),JSON.parse(localStorage.notifyProps));g.queue[i.quadrant].push(i.id),localStorage.notifyProps=JSON.stringify(g),i.style.top=i.isTop?23..toString()+"px":"",i.style.bottom=i.isTop?"":23..toString()+"px",i.style.right=i.isRight?27..toString()+"px":"",i.style.left=i.isRight?"":27..toString()+"px";e=g.queue[i.quadrant];if(1<e.length)try{for(var u of e.slice(0,-1)){var h=document.getElementById(u),p=h.style.top?"top":"bottom",m=+parseInt(h.style[p])+5+h.getBoundingClientRect().height;h.style[p]=m+"px"}}catch(e){console.warn("Failed to re-position notification:",e)}setTimeout(()=>{i.style.opacity=chatgpt.isDarkMode()?.8:.67,i.style.transform="translateX(0)",i.style.transition="transform 0.15s ease, opacity 0.15s ease"},10);l=a<.35?0:a-.35,t=()=>{i.style.animation="notif-zoom-fade-out 0.35s ease-out",clearTimeout(f)};let f=setTimeout(t,1e3*l);return c.onclick=t,i.onanimationend=()=>{i.remove(),(g=JSON.parse(localStorage.notifyProps)).queue[i.quadrant].shift(),localStorage.notifyProps=JSON.stringify(g)},i},obfuscate(){chatgpt.code.obfuscate()},printAllFunctions(){let o={cmdPrompt:["#ff00ff","#00ff00"],objName:["#0611e9","#f9ee16"],methodName:["#005aff","#ffa500"],entryType:["#467e06","#b981f9"],srcMethod:["#ff0000","#00ffff"]};Object.keys(o).forEach(e=>{o[e][1]=o[e][1]||"#"+(16777215^Number("0x1"+o[e][0].replace(/^#/,""))).toString(16).substring(1).toUpperCase()});var e=[];for(let t in this)if("function"==typeof this[t]){var r=!Object.keys(this).find(e=>Object.keys(this[e]).includes(this[t].name));e.push([r?"chatgpt":"other",t])}else if("object"==typeof this[t])for(var a in this[t])"function"==typeof this[t][a]&&e.push([t,a]);e.sort((e,t)=>e[0].localeCompare(t[0])||e[1].localeCompare(t[1]));var n=window.matchMedia("(prefers-color-scheme: dark)").matches,s="font-family: monospace ; font-size: larger ; ";console.log("\n%c🤖 chatgpt.js methods\n","font-family: sans-serif ; font-size: xxx-large ; font-weight: bold");for(let t of e){var i=/chatgpt|other/.test(t[0]),c="chatgpt"==t[0]?this[t[1]].name:"other"!=t[0]?t[0]+"."+t[1]:Object.keys(this).find(e=>Object.keys(this[e]).includes(this[t[1]].name))+"."+this[t[1]].name,l="AsyncFunction"==this[t[1]]?.constructor.name;console.log("%c>> %c"+(i?"":t[0]+".%c")+t[1]+" - https://chatgptjs.org/userguide/"+/(?:.*\.)?(.*)/.exec(c)[1].toLowerCase()+(l?"-async":"")+"\n%c[%c"+("chatgpt"==t[0]&&t[1]==this[t[1]].name||!i?"Function":"Alias of")+"%c: %c"+c+"%c]",s+"font-weight: bold ; color:"+o.cmdPrompt[+n],s+"font-weight: bold ;color:"+o[i?"methodName":"objName"][+n],s+"font-weight: "+(i?"initial":"bold")+";color:"+(i?"initial":o.methodName[+n]),s+"font-weight: "+(i?"bold":"initial")+";color:"+(i?o.entryType[+n]:"initial"),s+"font-weight: "+(i?"initial":"bold")+";color:"+(i?"initial":o.entryType[+n]),s+(i?"font-style: italic":"font-weight: initial")+";color:"+(i?o.srcMethod[+n]:"initial"),s+(i?"font-weight: initial":"font-style: italic")+";color:"+(i?"initial":o.srcMethod[+n]),i?"":s+"color: initial ; font-weight: initial")}},randomFloat(){return(window.crypto||window.msCrypto)?.getRandomValues(new Uint32Array(1))[0]/4294967295||Math.random()},refactor(){chatgpt.code.refactor()},regenerate(){chatgpt.response.regenerate()},renderHTML(s){var i,e=/<([a-z\d]+)\b([^>]*)>([\s\S]*?)<\/\1>/g,c=/(\S+)=['"]?((?:.(?!['"]?\s+\S+=|[>']))+.)['"]?/g,t=s.childNodes;chatgpt.renderHTML.preWrapSet||(s.style.whiteSpace="pre-wrap",chatgpt.renderHTML.preWrapSet=!0,setTimeout(()=>chatgpt.renderHTML.preWrapSet=!1,100));for(i of t)if(i.nodeType==Node.TEXT_NODE){var l=i.nodeValue,d=[...l.matchAll(e)];if(0<d.length){let e=d[0],[t,o,r,a]=e.slice(0,4),n=document.createElement(o);n.textContent=a;[...r.matchAll(c)].forEach(e=>{var t=e[1],e=e[2].replace(/['"]/g,"");n.setAttribute(t,e)});var d=chatgpt.renderHTML(n),g=document.createTextNode(l.substring(0,e.index)),l=document.createTextNode(l.substring(e.index+t.length));s.replaceChild(g,i),s.insertBefore(d,g.nextSibling),s.insertBefore(l,d.nextSibling)}}else i.nodeType==Node.ELEMENT_NODE&&chatgpt.renderHTML(i);return s},async resend(){chatgpt.send(await chatgpt.getChatData("latest","msg","user","latest"))},response:{continue(){try{chatgpt.getContinueBtn().click()}catch(e){console.error(e.message)}},get(){return this["getFrom"+(location.href.startsWith("https://chatgpt.com/c/")?"DOM":"API")].apply(null,arguments)},getFromAPI(e,t){return e=e||"latest",t=t||"latest",chatgpt.getChatData(e,"msg","chatgpt",t)},getFromDOM(e){var t=document.querySelectorAll("div[data-message-author-role=assistant]"),o=e.toString().toLowerCase();let r="";return t.length?r=(r=(/last|final/.test(o)?t[t.length-1]:t[(Number.isInteger(e)?e:/^\d+/.test(o)?/^\d+/.exec(o)[0]:(/^(?:1|one|fir)(?:st)?$/.test(o)?1:/^(?:2|tw(?:o|en|el(?:ve|f))|seco)(?:nd|t[yi])?(?:e?th)?$/.test(o)?2:/^(?:3|th(?:ree|ir?))(?:rd|teen|t[yi])?(?:e?th)?$/.test(o)?3:/^(?:4|fou?r)(?:teen|t[yi])?(?:e?th)?$/.test(o)?4:/^(?:5|fi(?:ve|f))(?:teen|t[yi])?(?:e?th)?$/.test(o)?5:/^(?:6|six)(?:teen|t[yi])?(?:e?th)?$/.test(o)?6:/^(?:7|seven)(?:teen|t[yi])?(?:e?th)?$/.test(o)?7:/^(?:8|eight?)(?:teen|t[yi])?(?:e?th)?$/.test(o)?8:/^(?:9|nine?)(?:teen|t[yi])?(?:e?th)?$/.test(o)?9:/^(?:10|ten)(?:th)?$/.test(o)?10:1)*(/(?:ty|ieth)$/.test(o)?10:1)+(/teen(?:th)?$/.test(o)?10:0))-1]).textContent).replace(/^ChatGPT(?:ChatGPT)?/,""):console.error("No conversation found!")},getLast(){return chatgpt.getChatData("active","msg","chatgpt","latest")},regenerate(){try{chatgpt.getRegenerateBtn().click()}catch(e){console.error(e.message)}},stopGenerating(){try{chatgpt.getStopBtn().click()}catch(e){console.error(e.message)}}},reviewCode(){chatgpt.code.review()},scrollToBottom(){try{chatgpt.getScrollBtn().click()}catch(e){console.error(e.message)}},send(e,o=""){for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string!`);let r=chatgpt.getChatBox();if(!r)return console.error("Chatbar element not found!");var t=document.createElement("p");t.textContent=e,r.querySelector("p").replaceWith(t),r.dispatchEvent(new Event("input",{bubbles:!0})),setTimeout(function e(){var t=chatgpt.getSendButton();t?.hasAttribute("disabled")?setTimeout(e,222):"click"==o.toLowerCase()||chatgpt.browser.isMobile()?t.click():r.dispatchEvent(new KeyboardEvent("keydown",{key:"Enter",bubbles:!0}))},222)},sendInNewChat(e){if("string"!=typeof e)return console.error("Message must be a string!");try{chatgpt.getNewChatBtn().click()}catch(e){return console.error(e.message)}setTimeout(()=>chatgpt.send(e),500)},settings:{scheme:{isDark(){return document.documentElement.classList.contains("dark")},isLight(){return document.documentElement.classList.contains("light")},set(e){var t=["dark","light","system"];if(!e)return console.error("Please specify a scheme value!");if(!t.includes(e))return console.error(`Invalid scheme value. Valid values are [${t}]`);let o=e;"system"==e&&(o=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),localStorage.setItem("theme",e),console.info(`Scheme set to ${e.toUpperCase()}.`),document.documentElement.classList.contains(o)||this.toggle()},toggle(){var[e,t]=this.isDark()?["dark","light"]:["light","dark"];document.documentElement.classList.replace(e,t),document.documentElement.style.colorScheme=t,localStorage.setItem("theme",t)}}},async sentiment(e,t){for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send("What is the sentiment of the following text"+(t?` towards the entity ${t},`:"")+" from strongly negative to strongly positive?\n\n"+e),console.info("Analyzing sentiment..."),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},setScheme(e){chatgpt.settings.scheme.set(e)},shareChat(s,i="clipboard"){var e=["alert","notify","notification","clipboard","copy"];if(!e.includes(i))return console.error(`Invalid method '${i}' passed. Valid methods are [${e}].`);return new Promise(o=>{chatgpt.getAccessToken().then(t=>{var a;a=t,new Promise((t,o)=>{let r=new XMLHttpRequest;chatgpt.getChatData(s).then(e=>{r.open("GET",chatgpt.endpoints.openAI.chat+"/"+e.id,!0),r.setRequestHeader("Content-Type","application/json"),r.setRequestHeader("Authorization","Bearer "+a),r.onload=()=>200!=r.status?o("🤖 chatgpt.js >> Request failed. Cannot retrieve chat node."):t(JSON.parse(r.responseText).current_node),r.send()})}).then(e=>{var a,n;a=t,n=e,new Promise((t,o)=>{let r=new XMLHttpRequest;chatgpt.getChatData(s).then(e=>{r.open("POST",chatgpt.endpoints.openAI.share_create,!0),r.setRequestHeader("Content-Type","application/json"),r.setRequestHeader("Authorization","Bearer "+a),r.onload=()=>200!=r.status?o("🤖 chatgpt.js >> Request failed. Cannot initialize share chat."):t(JSON.parse(r.responseText)),r.send(JSON.stringify({current_node_id:n,conversation_id:e.id,is_anonymous:!0}))})}).then(e=>{var r,a;r=t,a=e,new Promise((e,t)=>{let o=new XMLHttpRequest;o.open("PATCH",chatgpt.endpoints.openAI.share+"/"+a.share_id,!0),o.setRequestHeader("Content-Type","application/json"),o.setRequestHeader("Authorization","Bearer "+r),o.onload=()=>200!=o.status?t("🤖 chatgpt.js >> Request failed. Cannot share chat."):(console.info(`Chat shared at '${a.share_url}'`),e()),o.send(JSON.stringify({share_id:a.share_id,highlighted_message_id:a.highlighted_message_id,title:a.title,is_public:!0,is_visible:a.is_visible,is_anonymous:a.is_anonymous}))}).then(()=>{["copy","clipboard"].includes(i)?navigator.clipboard.writeText(e.share_url):chatgpt.alert("🚀 Share link created!",`"${e.title}" is available at: <a target="blank" rel="noopener" href="${e.share_url}">${e.share_url}</a>`,[function(){window.open(e.share_url,"_blank","noopener")},function(){navigator.clipboard.writeText(e.share_url)}]),o(e.share_url)})})})})})},showFooter(){chatgpt.footer.show()},showHeader(){chatgpt.header.show()},sidebar:{elems:[],observer:{},activateObserver(){if(this.observer instanceof MutationObserver&&this.observer.disconnect(),!this.elems.length)return console.error("🤖 chatgpt.js >> No elems to append!");let t;for(var e of document.querySelectorAll(chatgpt.selectors.links.sidebarItem))if(/.*chat/.exec(e.text)[0]){t=e.classList,e.parentNode.style.margin="2px 0";break}this.elems.forEach(e=>{e.setAttribute("class",t),e.style.maxHeight=e.style.minHeight="44px",e.style.margin="2px 0"});let o=document.querySelector(chatgpt.selectors.chatHistory);if(!o)return console.error("Sidebar element not found!");this.observer=new MutationObserver(e=>e.forEach(e=>{("childList"==e.type&&e.addedNodes.length||"attributes"==e.type&&"data-chatgptjs"==e.attributeName)&&this.elems.forEach(e=>{if(!o.contains(e))try{o.querySelector("a").parentNode.before(e)}catch(e){console.error(e)}})})),this.observer.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0})},append(e,t={}){var o=["button","dropdown"];if(!e||"string"!=typeof e)return console.error("🤖 chatgpt.js >> Please supply a valid string element name!");if(e=e.toLowerCase(),!o.includes(e))return console.error(`🤖 chatgpt.js >> Invalid element! Valid elems are [${o}]`);let r=document.createElement("dropdown"==e?"select":e);if(r.id=Math.floor(1e6*chatgpt.randomFloat())+Date.now(),"button"==e){r.textContent=t?.label&&"string"==typeof t.label?t.label:"chatgpt.js button";o=document.createElement("img");o.src=t?.icon&&"string"==typeof t.icon?t.icon:chatgpt.endpoints.assets+"/starters/chrome/extension/icons/icon128.png",o.width=18,r.firstChild.before(o),r.onclick=t?.onclick&&"function"==typeof t.onclick?t.onclick:function(){}}else if("dropdown"==e){if(t?.items&&Array.isArray(t.items)&&t.items.length||(t.items=[{text:"🤖 chatgpt.js option",value:"chatgpt.js option value"}]),!t.items.every(e=>"object"==typeof e))return console.error("'items' must be an array of objects!");t.items.forEach(e=>{var t=document.createElement("option");t.textContent=e?.text,t.value=e?.value,r.add(t)})}return"dropdown"==e&&(r.style.backgroundColor="var(--gray-900, rgb(32,33,35))"),this.elems.push(r),this.activateObserver(),document.body.setAttribute("data-chatgptjs","observer-trigger"),r.id},exists(){return!!chatgpt.getNewChatLink()},hide(){this.isOn()?this.toggle():console.info("Sidebar already hidden!")},show(){this.isOff()?this.toggle():console.info("Sidebar already shown!")},isOff(){return!this.isOn()},isOn(){var e=chatgpt.sidebar.exists()?document.querySelector(chatgpt.selectors.sidebar):null;return e?chatgpt.browser.isMobile()?"hidden"==document.documentElement.style.overflow:"hidden"!=e.style.visibility&&"0px"!=e.style.width:console.error("Sidebar element not found!")||!1},toggle(){var e=document.querySelector(chatgpt.selectors.btns.sidebar);e||console.error("Sidebar toggle not found!"),e.click()},async isLoaded(t=5e3){await chatgpt.isLoaded();var e=new Promise(e=>setTimeout(()=>e(!1),t)),o=new Promise(o=>{chatgpt.getNewChatLink()?o(!0):new MutationObserver((e,t)=>{chatgpt.getNewChatLink()&&(t.disconnect(),o(!0))}).observe(document.documentElement,{childList:!0,subtree:!0})});return Promise.race([o,e])}},startNewChat(){try{chatgpt.getNewChatBtn().click()}catch(e){console.error(e.message)}},stop(){chatgpt.response.stopGenerating()},async suggest(e,t){if(!e)return console.error("ideaType (1st argument) not supplied(e.g. 'gifts', 'names', 'recipes', etc.)");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send("Suggest some names. "+(t||"")),console.info(`Creating ${e}...`),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},speak(e,{voice:t=2,pitch:o=2,speed:r=1.1,onend:a}={}){if("string"!=typeof e)return console.error("Message must be a string!");var n,s=["voice","pitch","speed","onend"];for(n in arguments[1]){if(!s.includes(n))return console.error(`Invalid option '${n}'. Valid keys are: `+s);var i=arguments[1][n];if("onend"!=n&&"number"!=typeof i&&!/^\d+$/.test(i))return console.error(`Invalid ${n} value '${i}'. Must be a number!`);if("onend"==n&&"function"!=typeof i)return console.error(`Invalid ${n} value. Must be a function!`)}try{var c=new SpeechSynthesisUtterance,l=speechSynthesis.getVoices();Object.assign(c,{text:e,voice:l[t],pitch:o,speed:r,onend:a}),speechSynthesis.speak(c)}catch(e){console.error(e)}},async summarize(e){return e?"string"!=typeof e?console.error("Text argument must be a string!"):(chatgpt.send("Summarize the following text:\n\n"+e),console.info("Summarizing text..."),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")):console.error("Text (1st) argument not supplied. Pass some text!")},toggleScheme(){chatgpt.settings.scheme.toggle()},async translate(e,t){if(!e)return console.error("Text (1st) argument not supplied. Pass some text!");if(!t)return console.error("outputLang (2nd) argument not supplied. Pass a language!");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string!`);return chatgpt.send(`Translate the following text to ${t}. Only reply with the translation.
99
+ div.chatgpt-notif > div.notif-close-btn { top: 18px ; right: 7px ; transform: scale(2) }`),JSON.parse(localStorage.notifyProps));g.queue[i.quadrant].push(i.id),localStorage.notifyProps=JSON.stringify(g),i.style.top=i.isTop?23..toString()+"px":"",i.style.bottom=i.isTop?"":23..toString()+"px",i.style.right=i.isRight?27..toString()+"px":"",i.style.left=i.isRight?"":27..toString()+"px";e=g.queue[i.quadrant];if(1<e.length)try{for(var h of e.slice(0,-1)){var u=document.getElementById(h),p=u.style.top?"top":"bottom",m=+parseInt(u.style[p])+5+u.getBoundingClientRect().height;u.style[p]=m+"px"}}catch(e){console.warn("Failed to re-position notification:",e)}setTimeout(()=>{i.style.opacity=chatgpt.isDarkMode()?.8:.67,i.style.transform="translateX(0)",i.style.transition="transform 0.15s ease, opacity 0.15s ease"},10);l=a<.35?0:a-.35,t=()=>{i.style.animation="notif-zoom-fade-out 0.35s ease-out",clearTimeout(f)};let f=setTimeout(t,1e3*l);return c.onclick=t,i.onanimationend=()=>{i.remove(),(g=JSON.parse(localStorage.notifyProps)).queue[i.quadrant].shift(),localStorage.notifyProps=JSON.stringify(g)},i},obfuscate(){chatgpt.code.obfuscate()},printAllFunctions(){let o={cmdPrompt:["#ff00ff","#00ff00"],objName:["#0611e9","#f9ee16"],methodName:["#005aff","#ffa500"],entryType:["#467e06","#b981f9"],srcMethod:["#ff0000","#00ffff"]};Object.keys(o).forEach(e=>{o[e][1]=o[e][1]||"#"+(16777215^Number("0x1"+o[e][0].replace(/^#/,""))).toString(16).substring(1).toUpperCase()});var e=[];for(let t in this)if("function"==typeof this[t]){var r=!Object.keys(this).find(e=>Object.keys(this[e]).includes(this[t].name));e.push([r?"chatgpt":"other",t])}else if("object"==typeof this[t])for(var a in this[t])"function"==typeof this[t][a]&&e.push([t,a]);e.sort((e,t)=>e[0].localeCompare(t[0])||e[1].localeCompare(t[1]));var n=window.matchMedia("(prefers-color-scheme: dark)").matches,s="font-family: monospace ; font-size: larger ; ";console.log("\n%c🤖 chatgpt.js methods\n","font-family: sans-serif ; font-size: xxx-large ; font-weight: bold");for(let t of e){var i=/chatgpt|other/.test(t[0]),c="chatgpt"==t[0]?this[t[1]].name:"other"!=t[0]?t[0]+"."+t[1]:Object.keys(this).find(e=>Object.keys(this[e]).includes(this[t[1]].name))+"."+this[t[1]].name,l="AsyncFunction"==this[t[1]]?.constructor.name;console.log("%c>> %c"+(i?"":t[0]+".%c")+t[1]+" - https://chatgptjs.org/userguide/"+/(?:.*\.)?(.*)/.exec(c)[1].toLowerCase()+(l?"-async":"")+"\n%c[%c"+("chatgpt"==t[0]&&t[1]==this[t[1]].name||!i?"Function":"Alias of")+"%c: %c"+c+"%c]",s+"font-weight: bold ; color:"+o.cmdPrompt[+n],s+"font-weight: bold ;color:"+o[i?"methodName":"objName"][+n],s+"font-weight: "+(i?"initial":"bold")+";color:"+(i?"initial":o.methodName[+n]),s+"font-weight: "+(i?"bold":"initial")+";color:"+(i?o.entryType[+n]:"initial"),s+"font-weight: "+(i?"initial":"bold")+";color:"+(i?"initial":o.entryType[+n]),s+(i?"font-style: italic":"font-weight: initial")+";color:"+(i?o.srcMethod[+n]:"initial"),s+(i?"font-weight: initial":"font-style: italic")+";color:"+(i?"initial":o.srcMethod[+n]),i?"":s+"color: initial ; font-weight: initial")}},randomFloat(){return(window.crypto||window.msCrypto)?.getRandomValues(new Uint32Array(1))[0]/4294967295||Math.random()},refactor(){chatgpt.code.refactor()},regenerate(){chatgpt.response.regenerate()},renderHTML(s){var i,e=/<([a-z\d]+)\b([^>]*)>([\s\S]*?)<\/\1>/g,c=/(\S+)=['"]?((?:.(?!['"]?\s+\S+=|[>']))+.)['"]?/g,t=s.childNodes;chatgpt.renderHTML.preWrapSet||(s.style.whiteSpace="pre-wrap",chatgpt.renderHTML.preWrapSet=!0,setTimeout(()=>chatgpt.renderHTML.preWrapSet=!1,100));for(i of t)if(i.nodeType==Node.TEXT_NODE){var l=i.nodeValue,d=[...l.matchAll(e)];if(0<d.length){let e=d[0],[t,o,r,a]=e.slice(0,4),n=document.createElement(o);n.textContent=a;[...r.matchAll(c)].forEach(e=>{var t=e[1],e=e[2].replace(/['"]/g,"");n.setAttribute(t,e)});var d=chatgpt.renderHTML(n),g=document.createTextNode(l.substring(0,e.index)),l=document.createTextNode(l.substring(e.index+t.length));s.replaceChild(g,i),s.insertBefore(d,g.nextSibling),s.insertBefore(l,d.nextSibling)}}else i.nodeType==Node.ELEMENT_NODE&&chatgpt.renderHTML(i);return s},async resend(){chatgpt.send(await chatgpt.getChatData("latest","msg","user","latest"))},response:{continue(){try{chatgpt.getContinueBtn().click()}catch(e){console.error(e.message)}},get(){return this["getFrom"+(location.href.startsWith("https://chatgpt.com/c/")?"DOM":"API")].apply(null,arguments)},getFromAPI(e,t){return e=e||"latest",t=t||"latest",chatgpt.getChatData(e,"msg","chatgpt",t)},getFromDOM(e){var t=document.querySelectorAll("div[data-message-author-role=assistant]"),o=e.toString().toLowerCase();let r="";return t.length?r=(r=(/last|final/.test(o)?t[t.length-1]:t[(Number.isInteger(e)?e:/^\d+/.test(o)?/^\d+/.exec(o)[0]:(/^(?:1|one|fir)(?:st)?$/.test(o)?1:/^(?:2|tw(?:o|en|el(?:ve|f))|seco)(?:nd|t[yi])?(?:e?th)?$/.test(o)?2:/^(?:3|th(?:ree|ir?))(?:rd|teen|t[yi])?(?:e?th)?$/.test(o)?3:/^(?:4|fou?r)(?:teen|t[yi])?(?:e?th)?$/.test(o)?4:/^(?:5|fi(?:ve|f))(?:teen|t[yi])?(?:e?th)?$/.test(o)?5:/^(?:6|six)(?:teen|t[yi])?(?:e?th)?$/.test(o)?6:/^(?:7|seven)(?:teen|t[yi])?(?:e?th)?$/.test(o)?7:/^(?:8|eight?)(?:teen|t[yi])?(?:e?th)?$/.test(o)?8:/^(?:9|nine?)(?:teen|t[yi])?(?:e?th)?$/.test(o)?9:/^(?:10|ten)(?:th)?$/.test(o)?10:1)*(/(?:ty|ieth)$/.test(o)?10:1)+(/teen(?:th)?$/.test(o)?10:0))-1]).textContent).replace(/^ChatGPT(?:ChatGPT)?/,""):console.error("No conversation found!")},getLast(){return chatgpt.getChatData("active","msg","chatgpt","latest")},regenerate(){try{chatgpt.getRegenerateBtn().click()}catch(e){console.error(e.message)}},stopGenerating(){try{chatgpt.getStopBtn().click()}catch(e){console.error(e.message)}}},reviewCode(){chatgpt.code.review()},scrollToBottom(){try{chatgpt.getScrollBtn().click()}catch(e){console.error(e.message)}},send(e,o=""){for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string!`);let r=chatgpt.getChatBox();if(!r)return console.error("Chatbar element not found!");var t=document.createElement("p");t.textContent=e,r.querySelector("p").replaceWith(t),r.dispatchEvent(new Event("input",{bubbles:!0})),setTimeout(function e(){var t=chatgpt.getSendButton();t?.hasAttribute("disabled")?setTimeout(e,222):"click"==o.toLowerCase()||chatgpt.browser.isMobile()?t.click():r.dispatchEvent(new KeyboardEvent("keydown",{key:"Enter",bubbles:!0}))},222)},sendInNewChat(e){if("string"!=typeof e)return console.error("Message must be a string!");try{chatgpt.getNewChatBtn().click()}catch(e){return console.error(e.message)}setTimeout(()=>chatgpt.send(e),500)},settings:{scheme:{isDark(){return document.documentElement.classList.contains("dark")},isLight(){return document.documentElement.classList.contains("light")},set(e){var t=["dark","light","system"];if(!e)return console.error("Please specify a scheme value!");if(!t.includes(e))return console.error(`Invalid scheme value. Valid values are [${t}]`);let o=e;"system"==e&&(o=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),localStorage.setItem("theme",e),console.info(`Scheme set to ${e.toUpperCase()}.`),document.documentElement.classList.contains(o)||this.toggle()},toggle(){var[e,t]=this.isDark()?["dark","light"]:["light","dark"];document.documentElement.classList.replace(e,t),document.documentElement.style.colorScheme=t,localStorage.setItem("theme",t)}}},async sentiment(e,t){for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send("What is the sentiment of the following text"+(t?` towards the entity ${t},`:"")+" from strongly negative to strongly positive?\n\n"+e),console.info("Analyzing sentiment..."),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},setScheme(e){chatgpt.settings.scheme.set(e)},shareChat(s,i="clipboard"){var e=["alert","notify","notification","clipboard","copy"];if(!e.includes(i))return console.error(`Invalid method '${i}' passed. Valid methods are [${e}].`);return new Promise(o=>{chatgpt.getAccessToken().then(t=>{var a;a=t,new Promise((t,o)=>{let r=new XMLHttpRequest;chatgpt.getChatData(s).then(e=>{r.open("GET",chatgpt.endpoints.openAI.chat+"/"+e.id,!0),r.setRequestHeader("Content-Type","application/json"),r.setRequestHeader("Authorization","Bearer "+a),r.onload=()=>200!=r.status?o("🤖 chatgpt.js >> Request failed. Cannot retrieve chat node."):t(JSON.parse(r.responseText).current_node),r.send()})}).then(e=>{var a,n;a=t,n=e,new Promise((t,o)=>{let r=new XMLHttpRequest;chatgpt.getChatData(s).then(e=>{r.open("POST",chatgpt.endpoints.openAI.share_create,!0),r.setRequestHeader("Content-Type","application/json"),r.setRequestHeader("Authorization","Bearer "+a),r.onload=()=>200!=r.status?o("🤖 chatgpt.js >> Request failed. Cannot initialize share chat."):t(JSON.parse(r.responseText)),r.send(JSON.stringify({current_node_id:n,conversation_id:e.id,is_anonymous:!0}))})}).then(e=>{var r,a;r=t,a=e,new Promise((e,t)=>{let o=new XMLHttpRequest;o.open("PATCH",chatgpt.endpoints.openAI.share+"/"+a.share_id,!0),o.setRequestHeader("Content-Type","application/json"),o.setRequestHeader("Authorization","Bearer "+r),o.onload=()=>200!=o.status?t("🤖 chatgpt.js >> Request failed. Cannot share chat."):(console.info(`Chat shared at '${a.share_url}'`),e()),o.send(JSON.stringify({share_id:a.share_id,highlighted_message_id:a.highlighted_message_id,title:a.title,is_public:!0,is_visible:a.is_visible,is_anonymous:a.is_anonymous}))}).then(()=>{["copy","clipboard"].includes(i)?navigator.clipboard.writeText(e.share_url):chatgpt.alert("🚀 Share link created!",`"${e.title}" is available at: <a target="blank" rel="noopener" href="${e.share_url}">${e.share_url}</a>`,[function(){window.open(e.share_url,"_blank","noopener")},function(){navigator.clipboard.writeText(e.share_url)}]),o(e.share_url)})})})})})},showFooter(){chatgpt.footer.show()},showHeader(){chatgpt.header.show()},sidebar:{elems:[],observer:{},activateObserver(){if(this.observer instanceof MutationObserver&&this.observer.disconnect(),!this.elems.length)return console.error("🤖 chatgpt.js >> No elems to append!");let t;for(var e of document.querySelectorAll(chatgpt.selectors.links.sidebarItem))if(/.*chat/.exec(e.text)[0]){t=e.classList,e.parentNode.style.margin="2px 0";break}this.elems.forEach(e=>{e.setAttribute("class",t),e.style.maxHeight=e.style.minHeight="44px",e.style.margin="2px 0"});let o=document.querySelector(chatgpt.selectors.chatHistory);if(!o)return console.error("Sidebar element not found!");this.observer=new MutationObserver(e=>e.forEach(e=>{("childList"==e.type&&e.addedNodes.length||"attributes"==e.type&&"data-chatgptjs"==e.attributeName)&&this.elems.forEach(e=>{if(!o.contains(e))try{o.querySelector("a").parentNode.before(e)}catch(e){console.error(e)}})})),this.observer.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0})},append(e,t={}){var o=["button","dropdown"];if(!e||"string"!=typeof e)return console.error("🤖 chatgpt.js >> Please supply a valid string element name!");if(e=e.toLowerCase(),!o.includes(e))return console.error(`🤖 chatgpt.js >> Invalid element! Valid elems are [${o}]`);let r=document.createElement("dropdown"==e?"select":e);if(r.id=Math.floor(1e6*chatgpt.randomFloat())+Date.now(),"button"==e){r.textContent=t?.label&&"string"==typeof t.label?t.label:"chatgpt.js button";o=document.createElement("img");o.src=t?.icon&&"string"==typeof t.icon?t.icon:chatgpt.endpoints.assets+"/starters/chrome/extension/icons/icon128.png",o.width=18,r.firstChild.before(o),r.onclick=t?.onclick&&"function"==typeof t.onclick?t.onclick:function(){}}else if("dropdown"==e){if(t?.items&&Array.isArray(t.items)&&t.items.length||(t.items=[{text:"🤖 chatgpt.js option",value:"chatgpt.js option value"}]),!t.items.every(e=>"object"==typeof e))return console.error("'items' must be an array of objects!");t.items.forEach(e=>{var t=document.createElement("option");t.textContent=e?.text,t.value=e?.value,r.add(t)})}return"dropdown"==e&&(r.style.backgroundColor="var(--gray-900, rgb(32,33,35))"),this.elems.push(r),this.activateObserver(),document.body.setAttribute("data-chatgptjs","observer-trigger"),r.id},exists(){return!!chatgpt.getNewChatLink()},hide(){this.isOn()?this.toggle():console.info("Sidebar already hidden!")},show(){this.isOff()?this.toggle():console.info("Sidebar already shown!")},isOff(){return!this.isOn()},isOn(){var e=chatgpt.sidebar.exists()?document.querySelector(chatgpt.selectors.sidebar):null;return e?chatgpt.browser.isMobile()?"hidden"==document.documentElement.style.overflow:"hidden"!=e.style.visibility&&150<parseInt(getComputedStyle(e).width):console.error("Sidebar element not found!")||!1},toggle(){var e=document.querySelector(chatgpt.selectors.btns.sidebar);e||console.error("Sidebar toggle not found!"),e.click()},async isLoaded(t=5e3){await chatgpt.isLoaded();var e=new Promise(e=>setTimeout(()=>e(!1),t)),o=new Promise(o=>{chatgpt.getNewChatLink()?o(!0):new MutationObserver((e,t)=>{chatgpt.getNewChatLink()&&(t.disconnect(),o(!0))}).observe(document.documentElement,{childList:!0,subtree:!0})});return Promise.race([o,e])}},startNewChat(){try{chatgpt.getNewChatBtn().click()}catch(e){console.error(e.message)}},stop(){chatgpt.response.stopGenerating()},async suggest(e,t){if(!e)return console.error("ideaType (1st argument) not supplied(e.g. 'gifts', 'names', 'recipes', etc.)");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string.`);return chatgpt.send("Suggest some names. "+(t||"")),console.info(`Creating ${e}...`),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},speak(e,{voice:t=2,pitch:o=2,speed:r=1.1,onend:a}={}){if("string"!=typeof e)return console.error("Message must be a string!");var n,s=["voice","pitch","speed","onend"];for(n in arguments[1]){if(!s.includes(n))return console.error(`Invalid option '${n}'. Valid keys are: `+s);var i=arguments[1][n];if("onend"!=n&&"number"!=typeof i&&!/^\d+$/.test(i))return console.error(`Invalid ${n} value '${i}'. Must be a number!`);if("onend"==n&&"function"!=typeof i)return console.error(`Invalid ${n} value. Must be a function!`)}try{var c=new SpeechSynthesisUtterance,l=speechSynthesis.getVoices();Object.assign(c,{text:e,voice:l[t],pitch:o,speed:r,onend:a}),speechSynthesis.speak(c)}catch(e){console.error(e)}},async summarize(e){return e?"string"!=typeof e?console.error("Text argument must be a string!"):(chatgpt.send("Summarize the following text:\n\n"+e),console.info("Summarizing text..."),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")):console.error("Text (1st) argument not supplied. Pass some text!")},toggleScheme(){chatgpt.settings.scheme.toggle()},async translate(e,t){if(!e)return console.error("Text (1st) argument not supplied. Pass some text!");if(!t)return console.error("outputLang (2nd) argument not supplied. Pass a language!");for(let e=0;e<arguments.length;e++)if("string"!=typeof arguments[e])return console.error(`Argument ${e+1} must be a string!`);return chatgpt.send(`Translate the following text to ${t}. Only reply with the translation.
100
100
 
101
101
  `+e),console.info("Translating text..."),await chatgpt.isIdle(),chatgpt.getChatData("active","msg","chatgpt","latest")},unminify(){chatgpt.code.unminify()},uuidv4(){try{return crypto.randomUUID()}catch(e){let o=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{var t=(o+window.crypto.getRandomValues(new Uint32Array(1))[0]/(Math.pow(2,32)-1)*16)%16|0;return o=Math.floor(o/16),("x"==e?t:3&t|8).toString(16)})}},writeCode(){chatgpt.code.write()}},cjsBtnActions=(chatgpt.scheme={...chatgpt.settings.scheme},["click","get"]),cjsTargetTypes=["button","link","div","response"];for(let t of cjsBtnActions)chatgpt[t+"Button"]=function(o){var e=/^[.#]/.test(o)?document.querySelector(o):/send/i.test(o)?document.querySelector(chatgpt.selectors.btns.send):/scroll/i.test(o)?document.querySelector(chatgpt.selectors.btns.scroll):(()=>{for(var e of document.querySelectorAll("button"))if(e.textContent.toLowerCase().includes(o.toLowerCase()))return e;for(var t of document.querySelectorAll(chatgpt.selectors.links.sidebarItem))if(t.textContent.toLowerCase().includes(o.toLowerCase()))return t})();if("click"!=t)return e;e.click()};let cjsFuncAliases=[["actAs","act","become","persona","premadePrompt","preMadePrompt","prePrompt","rolePlay","rp"],["activateAutoRefresh","activateAutoRefresher","activateRefresher","activateSessionRefresher","autoRefresh","autoRefresher","autoRefreshSession","refresher","sessionRefresher"],["continue","continueChat","continueGenerating","continueResponse"],["deactivateAutoRefresh","deactivateAutoRefresher","deactivateRefresher","deactivateSessionRefresher"],["detectLanguage","getLanguage"],["executeCode","codeExecute"],["exists","isAvailable","isExistent","isPresent"],["exportChat","chatExport","export"],["getFooterDiv","getFooter"],["getHeaderDiv","getHeader"],["getLastPrompt","getLastQuery","getMyLastMessage","getMyLastQuery"],["getContinueButton","getContinueGeneratingButton"],["getScrollToBottomButton","getScrollButton"],["getStopButton","getStopGeneratingButton"],["getTextarea","getTextArea","getChatbar","getChatBar","getChatbox","getChatBox"],["getVoiceButton","getVoiceModeButton"],["isFullScreen","isFullscreen"],["isTempChat","isIncognito","isIncognitoMode","isTempChatMode"],["minify","codeMinify","minifyCode"],["new","newChat","startNewChat"],["obfuscate","codeObfuscate","obfuscateCode"],["printAllFunctions","showAllFunctions"],["refactor","codeRefactor","refactorCode"],["refreshReply","regenerate","regenerateReply"],["refreshSession","sessionRefresh"],["renderHTML","renderHtml","renderLinks","renderTags"],["reviewCode","codeReview"],["send","sendChat","sendMessage"],["sendInNewChat","sendNewChat"],["sentiment","analyzeSentiment","sentimentAnalysis"],["startNewChat","new","newChat"],["stop","stopChat","stopGenerating","stopResponse"],["suggest","suggestion","recommend"],["toggleAutoRefresh","toggleAutoRefresher","toggleRefresher","toggleSessionRefresher"],["toggleScheme","toggleMode"],["translate","translation","translator"],["unminify","unminifyCode","codeUnminify"],["writeCode","codeWrite"]],cjsFuncSynonyms=[["account","acct"],["activate","turnOn"],["analyze","check","evaluate","review"],["ask","send","submit"],["button","btn"],["continue","resume"],["chats","history"],["chat","conversation","convo"],["clear","delete","remove"],["data","details"],["deactivate","deActivate","turnOff"],["execute","interpret","interpreter","run"],["firefox","ff"],["generating","generation"],["login","logIn","logOn","signIn","signOn"],["logout","logOut","logOff","signOff","signOut"],["message","msg"],["minify","uglify"],["refactor","rewrite"],["regenerate","regen"],["render","parse"],["reply","response"],["sentiment","attitude","emotion","feeling","opinion","perception"],["speak","play","say","speech","talk","tts"],["summarize","tldr"],["temp","temporary"],["typing","generating"],["unminify","beautify","prettify","prettyPrint"]];function toCamelCase(e){return e.map((e,t)=>0==t?e:e[0].toUpperCase()+e.slice(1)).join("")}!function e(n=chatgpt){for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&"object"==typeof n[t]&&e(n[t]);let s;do{s=!1;for(let a in n)if(Object.prototype.hasOwnProperty.call(n,a)&&"function"==typeof n[a]){n[a.toLowerCase()]=n[a],cjsFuncAliases.forEach(e=>{e.includes(a)&&e.forEach(e=>{n[e]||(n[e]=n[e.toLowerCase()]=n[a],s=!0)})});let r=a.split(/(?=[A-Z])/);r.forEach(o=>{cjsFuncSynonyms.filter(e=>e.includes(o.toLowerCase())).flat().filter(e=>e!=o.toLowerCase()).forEach(t=>{var e=toCamelCase(r.map(e=>e==o?t:e));n[e]||(n[e]=n[e.toLowerCase()]=n[a],s=!0)})})}}while(s)}();let consolePrefix="🤖 chatgpt.js >> ",ogError=console.error,ogInfo=console.info;console.error=(...e)=>{e[0].startsWith(consolePrefix)?ogError(...e):ogError(consolePrefix+e[0],...e.slice(1))},console.info=e=>{e.startsWith(consolePrefix)?ogInfo(e):ogInfo(consolePrefix+e)};try{window.chatgpt=chatgpt}catch(e){}try{module.exports=chatgpt}catch(e){}
package/docs/README.md CHANGED
@@ -51,8 +51,8 @@
51
51
  <img src="https://img.shields.io/badge/License-MIT-fc4f2d.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
52
52
  <a href="https://www.npmjs.com/package/@kudoai/chatgpt.js/v/latest" target="_blank" rel="noopener">
53
53
  <img src="https://img.shields.io/npm/v/%40kudoai%2Fchatgpt.js?logo=npm&logoColor=white&labelColor=464646&color=blue&style=for-the-badge&label=Latest+Release"></a>
54
- <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.2/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
- <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.2&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
54
+ <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.4/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
+ <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.4&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
56
56
  <a href="https://www.codefactor.io/repository/github/kudoai/chatgpt.js" target="_blank" rel="noopener">
57
57
  <img src="https://img.shields.io/codefactor/grade/github/kudoai/chatgpt.js?label=Code+Quality&logo=codefactor&logoColor=white&labelColor=464646&color=1acc6c&style=for-the-badge"></a>
58
58
  <a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=kudoai_chatgpt.js" target="_blank" rel="noopener">
@@ -120,7 +120,7 @@
120
120
 
121
121
  ```js
122
122
  (async () => {
123
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
123
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
124
124
  // Your code here...
125
125
  })();
126
126
  ```
@@ -129,7 +129,7 @@
129
129
 
130
130
  ```js
131
131
  var xhr = new XMLHttpRequest();
132
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
132
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
133
133
  xhr.onload = function () {
134
134
  if (xhr.status === 200) {
135
135
  var chatgptJS = document.createElement('script');
@@ -152,7 +152,7 @@ function yourCode() {
152
152
 
153
153
  ```js
154
154
  ...
155
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js
155
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js
156
156
  // ==/UserScript==
157
157
 
158
158
  // Your code here...
@@ -222,7 +222,7 @@ chatgpt.get('reply', 'last');
222
222
 
223
223
  Each call equally fetches the last response. If you think it works, it probably will... so just type it!
224
224
 
225
- If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.2/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
225
+ If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.4/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
226
226
 
227
227
  <img height=8px width="100%" src="https://assets.chatgptjs.org/images/separators/gradient-aqua.png?v=e638eac">
228
228
 
@@ -416,7 +416,9 @@ This library exists thanks to code, translations, issues & ideas from the follow
416
416
  <a href="https://github.com/ericdachen" target="_blank" rel="noopener">
417
417
  <img title="@ericdachen" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/54382303?first-contrib=2025.3.20-implement-warp-to-golden-sponsors&h=47&w=47&mask=circle&maxage=7d"></a>
418
418
  <a href="https://github.com/m-k8s" target="_blank" rel="noopener">
419
- <img title="@m-k8s" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/42094254?first-contrib=2025.7.26-fixed-hand,ling-of-intermediate-msgs-by-getchatdata&h=47&w=47&mask=circle&maxage=7d"></a>
419
+ <img title="@m-k8s" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/42094254?first-contrib=2025.7.26-fixed-handling-of-intermediate-msgs-by-getchatdata&h=47&w=47&mask=circle&maxage=7d"></a>
420
+ <a href="https://github.com/ahnupeng" target="_blank" rel="noopener">
421
+ <img title="@ahnupeng" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/5319112?first-contrib=2025.9.4-suggested-allow-edit-slider-vals&h=47&w=47&mask=circle&maxage=7d"></a>
420
422
  <a href="https://github.com/dependabot" target="_blank" rel="noopener">
421
423
  <img title="Dependabot" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/in/29110&h=47&w=47&mask=circle&maxage=7d"></a>
422
424
  <a href="https://chatgpt.com" target="_blank" rel="noopener">
@@ -480,7 +482,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
480
482
  <div align="center">
481
483
 
482
484
  **[Releases](https://github.com/KudoAI/chatgpt.js/releases)** /
483
- [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.2/docs/USERGUIDE.md) /
485
+ [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.4/docs/USERGUIDE.md) /
484
486
  [Discuss](https://github.com/KudoAI/chatgpt.js/discussions) /
485
487
  [Back to top ↑](#top)
486
488
 
package/docs/USERGUIDE.md CHANGED
@@ -165,7 +165,7 @@
165
165
 
166
166
  ```js
167
167
  (async () => {
168
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
168
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
169
169
  // Your code here...
170
170
  })();
171
171
  ```
@@ -174,7 +174,7 @@
174
174
 
175
175
  ```js
176
176
  var xhr = new XMLHttpRequest();
177
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
177
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js');
178
178
  xhr.onload = function () {
179
179
  if (xhr.status === 200) {
180
180
  var chatgptJS = document.createElement('script');
@@ -196,7 +196,7 @@ function yourCode() {
196
196
 
197
197
  ```js
198
198
  ...
199
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js
199
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js
200
200
  // ==/UserScript==
201
201
 
202
202
  // Your code here...
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudoai/chatgpt.js",
3
- "version": "3.8.2",
3
+ "version": "3.8.4",
4
4
  "description": "Client-side JavaScript library for ChatGPT",
5
5
  "author": {
6
6
  "name": "KudoAI & contributors",
@@ -74,17 +74,17 @@
74
74
  "bugs": "https://github.com/KudoAI/chatgpt.js/issues",
75
75
  "devDependencies": {
76
76
  "@adamlui/minify.js": "^1.8.6",
77
- "@adamlui/scss-to-css": "^1.10.36",
78
- "@eslint/css": "^0.10.0",
79
- "@eslint/json": "^0.13.1",
80
- "@eslint/markdown": "^7.1.0",
81
- "@html-eslint/eslint-plugin": "^0.43.1",
82
- "@html-eslint/parser": "^0.43.0",
83
- "@stylistic/eslint-plugin": "^5.2.2",
84
- "eslint": "^9.32.0",
77
+ "@adamlui/scss-to-css": "^1.10.42",
78
+ "@eslint/css": "^0.13.0",
79
+ "@eslint/json": "^0.13.2",
80
+ "@eslint/markdown": "^7.4.0",
81
+ "@html-eslint/eslint-plugin": "^0.47.0",
82
+ "@html-eslint/parser": "^0.47.0",
83
+ "@stylistic/eslint-plugin": "^5.4.0",
84
+ "eslint": "^9.37.0",
85
85
  "eslint-plugin-import": "^2.32.0",
86
- "eslint-plugin-regexp": "^2.9.0",
87
- "eslint-plugin-yml": "^1.18.0",
86
+ "eslint-plugin-regexp": "^2.10.0",
87
+ "eslint-plugin-yml": "^1.19.0",
88
88
  "get-port": "^7.1.0",
89
89
  "husky": "^9.1.7"
90
90
  }
@@ -19,11 +19,11 @@ window.modals = {
19
19
  + `<span style="${labelStyles}">🏷️ Version:</span> `
20
20
  + `<span class="about-em">${app.version}</span>\n`
21
21
  + `<span style="${labelStyles}">📜 Open source code:</span> `
22
- + `<a href="${app.urls.gitHub}" target="_blank" rel="nopener">`
23
- + app.urls.gitHub + '</a>\n'
22
+ + `<a href="${app.urls.github}" target="_blank" rel="nopener">`
23
+ + app.urls.github + '</a>\n'
24
24
  + `<span style="${labelStyles}">🚀 Latest changes:</span> `
25
- + `<a href="${app.urls.gitHub}/commits" target="_blank" rel="nopener">`
26
- + `${app.urls.gitHub}/commits</a>\n`
25
+ + `<a href="${app.urls.github}/commits" target="_blank" rel="nopener">`
26
+ + `${app.urls.github}/commits</a>\n`
27
27
  + `<span style="${labelStyles}">⚡ Powered by:</span> `
28
28
  + `<a href="${app.urls.chatgptjs}" target="_blank" rel="noopener">chatgpt.js</a>`,
29
29
  [ function getSupport(){}, function rateUs(){}, function moreAiExtensions(){} ], // button labels
@@ -31,8 +31,8 @@ window.modals = {
31
31
  )
32
32
 
33
33
  // Format text
34
- aboutModal.querySelector('h2').style.cssText = (
35
- 'text-align: center ; font-size: 51px ; line-height: 46px ; padding: 15px 0' )
34
+ aboutModal.querySelector('h2').style.cssText = `
35
+ text-align: center ; font-size: 51px ; line-height: 46px ; padding: 15px 0`
36
36
  aboutModal.querySelector('p').style.cssText = (
37
37
  'text-align: center ; overflow-wrap: anywhere ;'
38
38
  + `margin: ${ isPortrait ? '6px 0 -16px' : '3px 0 0' }` )
@@ -45,8 +45,8 @@ window.modals = {
45
45
  // Replace buttons w/ clones that don't dismiss modal
46
46
  btn.replaceWith(btn = btn.cloneNode(true))
47
47
  btn.onclick = () => this.safeWinOpen(
48
- btn.textContent == 'Get Support' ? `${app.urls.gitHub}/issues`
49
- : btn.textContent == 'Rate Us' ? `${app.urls.gitHub}/discussions`
48
+ btn.textContent == 'Get Support' ? `${app.urls.github}/issues`
49
+ : btn.textContent == 'Rate Us' ? `${app.urls.github}/discussions`
50
50
  : app.urls.relatedExtensions
51
51
  )
52
52
 
@@ -108,42 +108,48 @@ window.modals = {
108
108
  stylize() {
109
109
  const { ui: { scheme }, browser: { isMobile }} = env
110
110
  if (!this.styles) document.head.append(this.styles = dom.create.elem('style'))
111
- this.styles.textContent = (
112
- `.${this.class} {` // modals
113
- + 'user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -ms-user-select: none ;'
114
- + 'font-family: -apple-system, system-ui, BlinkMacSystemFont, Segoe UI, Roboto,'
115
- + 'Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif ;'
116
- + 'padding: 20px 25px 24px 25px !important ; font-size: 20px ;'
117
- + `color: ${ scheme == 'dark' ? 'white' : 'black' } !important ;`
118
- + `background-image: linear-gradient(180deg, ${
119
- scheme == 'dark' ? '#99a8a6 -200px, black 200px' : '#b6ebff -296px, white 171px' }) }`
120
- + `.${this.class} [class*=modal-close-btn] {`
121
- + 'position: absolute !important ; float: right ; top: 14px !important ; right: 16px !important ;'
122
- + 'cursor: pointer ; width: 33px ; height: 33px ; border-radius: 20px }'
123
- + `.${this.class} [class*=modal-close-btn] svg { height: 10px }`
124
- + `.${this.class} [class*=modal-close-btn] path {`
125
- + `${ scheme == 'dark' ? 'stroke: white ; fill: white' : 'stroke: #9f9f9f ; fill: #9f9f9f' }}`
126
- + ( scheme == 'dark' ? // invert dark mode hover paths
127
- `.${this.class} [class*=modal-close-btn]:hover path { stroke: black ; fill: black }` : '' )
128
- + `.${this.class} [class*=modal-close-btn]:hover { background-color: #f2f2f2 }` // hover underlay
129
- + `.${this.class} [class*=modal-close-btn] svg { margin: 11.5px }` // center SVG for hover underlay
130
- + `.${this.class} a { color: #${ scheme == 'dark' ? '00cfff' : '1e9ebb' } !important }`
131
- + `.${this.class} h2 { font-weight: bold }`
132
- + `.${this.class} button {`
133
- + '--btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ;'
134
- + 'font-size: 14px ; text-transform: uppercase ;' // shrink/uppercase labels
135
- + 'border-radius: 0 !important ;' // square borders
136
- + 'transition: var(--btn-transition) ;' // smoothen hover fx
137
- + '-webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ;'
138
- + '-o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) ;'
139
- + 'cursor: pointer !important ;' // add finger cursor
140
- + `border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' } !important ;`
141
- + 'padding: 8px !important ; min-width: 102px }' // resize
142
- + `.${this.class} button:hover {` // add zoom, re-scheme
143
- + 'transform: scale(1.055) ; color: black !important ;'
144
- + `background-color: #${ scheme == 'dark' ? '00cfff' : '9cdaff' } !important }`
145
- + ( !isMobile ? `.${this.class} .modal-buttons { margin-left: -13px !important }` : '' )
146
- + `.about-em { color: ${ scheme == 'dark' ? 'white' : 'green' } !important }`
147
- )
111
+ this.styles.textContent = `
112
+ .${this.class} { /* modals */
113
+ user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -ms-user-select: none ;
114
+ font-family: -apple-system, system-ui, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu,
115
+ Cantarell, Helvetica Neue, sans-serif ;
116
+ padding: 20px 25px 24px 25px !important ; font-size: 20px ;
117
+ color: ${ scheme == 'dark' ? 'white' : 'black' } !important ;
118
+ background-image: linear-gradient(180deg, ${
119
+ scheme == 'dark' ? '#99a8a6 -200px, black 200px' : '#b6ebff -296px, white 171px' })
120
+ }
121
+ .${this.class} [class*=modal-close-btn] {
122
+ position: absolute !important ; float: right ; top: 14px !important ; right: 16px !important ;
123
+ cursor: pointer ; width: 33px ; height: 33px ; border-radius: 20px
124
+ }
125
+ .${this.class} [class*=modal-close-btn] svg { height: 10px }
126
+ .${this.class} [class*=modal-close-btn] path {
127
+ ${ scheme == 'dark' ? 'stroke: white ; fill: white' : 'stroke: #9f9f9f ; fill: #9f9f9f' }}
128
+ ${ scheme == 'dark' ? // invert dark mode hover paths
129
+ `.${this.class} [class*=modal-close-btn]:hover path { stroke: black ; fill: black }` : '' }
130
+ .${this.class} [class*=modal-close-btn]:hover { background-color: #f2f2f2 } /* hover underlay */
131
+ .${this.class} [class*=modal-close-btn] svg { margin: 11.5px } /* center SVG for hover underlay */
132
+ .${this.class} a { color: #${ scheme == 'dark' ? '00cfff' : '1e9ebb' } !important }
133
+ .${this.class} a:hover { text-decoration: none ; opacity: 0.7 ; transition: 0.15s ease }
134
+ .${this.class} h2 { font-weight: bold }
135
+ .${this.class} button {
136
+ --btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ;
137
+ font-size: 14px ; text-transform: uppercase ; /* shrink/uppercase labels */
138
+ border-radius: 0 !important ; /* square borders */
139
+ transition: var(--btn-transition) ; /* smoothen hover fx */
140
+ -webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ;
141
+ -o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) ;
142
+ cursor: pointer !important ; /* add finger cursor */
143
+ border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' } !important ;
144
+ padding: 8px !important ; min-width: 102px /* resize */
145
+ }
146
+ .${this.class} button:hover {
147
+ ${ scheme == 'light' ? // reduce intensity of light scheme hover glow
148
+ '--btn-shadow: 2px 1px 43px #00cfff70 ;' : '' }
149
+ color: inherit ; background-color: inherit /* remove color hacks */
150
+ }
151
+ ${ !isMobile ? `.${this.class} .modal-buttons { margin-left: -13px !important }` : '' }
152
+ .about-em { color: ${ scheme == 'dark' ? 'white' : 'green' } !important }`
153
+ if (!this.styles.isConnected) document.head.append(this.styles)
148
154
  }
149
155
  };
@@ -4,8 +4,9 @@
4
4
  (async () => {
5
5
 
6
6
  // Import JS resources
7
- for (const resource of ['components/modals.js', 'lib/chatgpt.js', 'lib/dom.js', 'lib/settings.js', 'lib/ui.js'])
8
- await import(chrome.runtime.getURL(resource))
7
+ for (const resource of [
8
+ 'components/modals.js', 'lib/chatgpt.js', 'lib/dom.js', 'lib/feedback.js', 'lib/settings.js', 'lib/ui.js'
9
+ ]) await import(chrome.runtime.getURL(resource))
9
10
 
10
11
  // Init ENV context
11
12
  window.env = { browser: { isMobile: chatgpt.browser.isMobile() }, ui: { scheme: ui.getScheme() }}
@@ -14,11 +15,15 @@
14
15
  // Import APP data
15
16
  ;({ app: window.app } = await chrome.storage.local.get('app'))
16
17
 
17
- chrome.runtime.onMessage.addListener(({ action, options }) => { // from service-worker.js + popup/index.html
18
+ chrome.runtime.onMessage.addListener(({ action, options, source }) => { // from service-worker.js + popup/index.html
18
19
  ({
19
- notify: () => notify(...['msg', 'pos', 'notifDuration', 'shadow'].map(arg => options[arg])),
20
+ notify: () => feedback.notify(...['msg', 'pos', 'notifDuration', 'shadow'].map(arg => options[arg])),
20
21
  alert: () => modals.alert(...['title', 'msg', 'btns', 'checkbox', 'width'].map(arg => options[arg])),
21
- showAbout: () => { config.skipAlert = true ; chatgpt.isLoaded().then(() => modals.open('about')) },
22
+ showAbout: () => {
23
+ if (!source?.endsWith('service-worker.js')) return
24
+ config.skipAlert = true
25
+ chatgpt.isLoaded().then(() => modals.open('about'))
26
+ },
22
27
  syncConfigToUI: () => syncConfigToUI(options)
23
28
  }[action]?.() || console.warn(`Chome msg listener warning: "${action}"`))
24
29
  })
@@ -29,42 +34,14 @@
29
34
 
30
35
  // Define FUNCTIONS
31
36
 
32
- function notify(msg, pos = '', notifDuration = '', shadow = '') {
33
-
34
- // Strip state word to append colored one later
35
- const foundState = ['ON', 'OFF'].find(word => msg.includes(word))
36
- if (foundState) msg = msg.replace(foundState, '')
37
-
38
- // Show notification
39
- chatgpt.notify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || env.ui.scheme == 'light')
40
- const notif = document.querySelector('.chatgpt-notif:last-child')
41
-
42
- // Append styled state word
43
- if (foundState) {
44
- const stateStyles = {
45
- on: {
46
- light: 'color: #5cef48 ; text-shadow: rgba(255,250,169,0.38) 2px 1px 5px',
47
- dark: 'color: #5cef48 ; text-shadow: rgb(55,255,0) 3px 0 10px'
48
- },
49
- off: {
50
- light: 'color: #ef4848 ; text-shadow: rgba(255,169,225,0.44) 2px 1px 5px',
51
- dark: 'color: #ef4848 ; text-shadow: rgba(255, 116, 116, 0.87) 3px 0 9px'
52
- }
53
- }
54
- const styledStateSpan = document.createElement('span')
55
- styledStateSpan.style.cssText = stateStyles[foundState.toLowerCase()][env.ui.scheme]
56
- styledStateSpan.append(foundState) ; notif.append(styledStateSpan)
57
- }
58
- }
59
-
60
- async function syncConfigToUI(options) { // eslint-disable-line
37
+ async function syncConfigToUI(options = {}) { // eslint-disable-line
61
38
  await settings.load('extensionDisabled', Object.keys(settings.controls)) // load from Chrome storage to content.js config
62
39
  if (config.extensionDisabled) {
63
40
  // Remove all hacks
64
41
  } else {
65
42
  // Add/remove hacks to reflect each potentially updated setting per settings.controls in lib/settings.mjs
66
43
  // e.g. if you created toolbar popup toggle to hide ChatGPT footer using hiddenFooter key...
67
- // ...here you would use options?.updatedKey == 'hiddenFooter' && config.hiddenFooter...
44
+ // ...here you would use options.updatedKey == 'hiddenFooter' && config.hiddenFooter...
68
45
  // ...to conditionally append/remove hidden footer style...
69
46
  // ...(initial style creation + append if config.hiddenFooter would go in main routine)
70
47
  }
@@ -91,7 +68,7 @@
91
68
  modals.alert('≫ ChatGPT extension loaded! 🚀', // title
92
69
  'Success! Press Ctrl+Shift+J to view all chatgpt.js methods.', // msg
93
70
  function getHelp() { // button
94
- open(`${app.urls.gitHub}/issues`) },
71
+ open(`${app.urls.github}/issues`) },
95
72
  function dontShowAgain() { // checkbox
96
73
  settings.save('skipAlert', !config.skipAlert) }
97
74
  )
@@ -38,7 +38,7 @@ const chatgpt = {
38
38
  reason: 'button[data-testid=composer-button-reason]',
39
39
  send: 'button[data-testid=send-button]',
40
40
  sidebar: 'div[style*=-sidebar-width] button[data-testid=close-sidebar-button], div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]',
41
- stop: 'button[data-testid=stop-button]',
41
+ stop: 'div:has(> svg > path[d^="M10 2.08496C14.3713"])',
42
42
  upload: 'button:has(> svg > path[d^="M12 3C12.5523"])',
43
43
  voice: 'button[data-testid*=composer-speech-button]'
44
44
  },
@@ -127,13 +127,14 @@ const chatgpt = {
127
127
 
128
128
  drag: {
129
129
  mousedown(event) { // find modal, update styles, attach listeners, init XY offsets
130
- if (event.button != 0) return // prevent non-left-click drag
131
- if (!/auto|default/.test(getComputedStyle(event.target).cursor))
132
- return // prevent drag on interactive elems
130
+ if ( // prevent drag when...
131
+ event.button != 0 // non-left-click
132
+ || !/auto|default/.test(getComputedStyle(event.target).cursor) // cursor changed
133
+ ) return
133
134
  chatgpt.draggingModal = event.currentTarget
134
135
  event.preventDefault() // prevent sub-elems like icons being draggable
135
136
  Object.assign(chatgpt.draggingModal.style, {
136
- transition: '0.1s', willChange: 'transform', transform: 'scale(1.05)' })
137
+ transition: 'transform 0.1s ease', transform: 'scale(1.05)' })
137
138
  document.body.style.cursor = 'grabbing' // update cursor
138
139
  ;[...chatgpt.draggingModal.children] // prevent hover FX if drag lags behind cursor
139
140
  .forEach(child => child.style.pointerEvents = 'none')
@@ -153,7 +154,7 @@ const chatgpt = {
153
154
 
154
155
  mouseup() { // restore styles/pointer events, remove listeners, reset chatgpt.draggingModal
155
156
  Object.assign(chatgpt.draggingModal.style, { // restore styles
156
- cursor: 'inherit', transition: 'inherit', willChange: 'auto', transform: 'scale(1)' })
157
+ cursor: 'inherit', transition: 'inherit', transform: 'scale(1)' })
157
158
  document.body.style.cursor = '' // restore cursor
158
159
  ;[...chatgpt.draggingModal.children] // restore pointer events
159
160
  .forEach(child => child.style.pointerEvents = '')
@@ -1893,7 +1894,7 @@ const chatgpt = {
1893
1894
  if (!sidebar) { return console.error('Sidebar element not found!') || false }
1894
1895
  else return chatgpt.browser.isMobile() ?
1895
1896
  document.documentElement.style.overflow == 'hidden'
1896
- : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px'
1897
+ : sidebar.style.visibility != 'hidden' && parseInt(getComputedStyle(sidebar).width) > 150
1897
1898
  },
1898
1899
 
1899
1900
  toggle() {
@@ -34,7 +34,10 @@ window.dom = {
34
34
 
35
35
  elem(elemType, attrs = {}) {
36
36
  const elem = document.createElement(elemType)
37
- for (const attr in attrs) elem.setAttribute(attr, attrs[attr])
37
+ for (const attr in attrs) {
38
+ if (attr in elem) elem[attr] = attrs[attr]
39
+ else elem.setAttribute(attr, attrs[attr])
40
+ }
38
41
  return elem
39
42
  },
40
43
 
@@ -0,0 +1,33 @@
1
+ // Requires lib/<browser|chatgpt|dom|styles>.js + <app|env|configt>
2
+
3
+ window.feedback = {
4
+ notify(msg, pos = '', notifDuration = '', shadow = '') {
5
+
6
+ // Strip state word to append colored one later
7
+ const foundState = ['ON', 'OFF'].find(word => msg.includes(word))
8
+ if (foundState) msg = msg.replace(foundState, '')
9
+
10
+ // Show notification
11
+ chatgpt.notify(`${app.symbol} ${msg}`, pos ||( config.notifBottom ? 'bottom' : '' ),
12
+ notifDuration, shadow || env.ui.scheme == 'light')
13
+ const notif = document.querySelector('.chatgpt-notif:last-child')
14
+ notif.classList.add(app.slug) // for styles.toast
15
+
16
+ // Append styled state word
17
+ if (foundState) {
18
+ const stateStyles = {
19
+ on: {
20
+ light: 'color: #5cef48 ; text-shadow: rgba(255,250,169,0.38) 2px 1px 5px',
21
+ dark: 'color: #5cef48 ; text-shadow: rgb(55,255,0) 3px 0 10px'
22
+ },
23
+ off: {
24
+ light: 'color: #ef4848 ; text-shadow: rgba(255,169,225,0.44) 2px 1px 5px',
25
+ dark: 'color: #ef4848 ; text-shadow: rgba(255, 116, 116, 0.87) 3px 0 9px'
26
+ }
27
+ }
28
+ const styledStateSpan = dom.create.elem('span')
29
+ styledStateSpan.style.cssText = stateStyles[foundState == 'Off' ? 'off' : 'on'][env.ui.scheme]
30
+ styledStateSpan.append(foundState) ; notif.append(styledStateSpan)
31
+ }
32
+ }
33
+ };
@@ -48,10 +48,14 @@ window.settings = {
48
48
 
49
49
  load(...keys) {
50
50
  return Promise.all(keys.flat().map(async key => // resolve promise when all keys load
51
- config[key] = (await chrome.storage.local.get(key))[key] ?? initDefaultVal(key)))
52
- function initDefaultVal(key) {
53
- const ctrlData = settings.controls?.[key]
54
- return ctrlData?.defaultVal ?? ( ctrlData?.type == 'slider' ? 100 : ctrlData?.type == 'toggle' )
51
+ config[key] = processKey(key, (await chrome.storage.local.get(key))[key])))
52
+ function processKey(key, val) {
53
+ const ctrl = settings.controls?.[key]
54
+ if (val != undefined && ( // validate stored val
55
+ (ctrl?.type == 'toggle' && typeof val != 'boolean')
56
+ || (ctrl?.type == 'slider' && isNaN(parseFloat(val)))
57
+ )) val = undefined
58
+ return val ?? (ctrl?.defaultVal ?? (ctrl?.type == 'slider' ? 100 : false))
55
59
  }
56
60
  },
57
61
 
@@ -3,8 +3,7 @@
3
3
  "name": "ChatGPT Extension",
4
4
  "short_name": "ChatGPT 🧩",
5
5
  "description": "A Chromium extension template to start using chatgpt.js like a boss!",
6
- "version": "2025.7.27",
7
- "author": "KudoAI",
6
+ "version": "2025.10.15",
8
7
  "homepage_url": "https://github.com/KudoAI/chatgpt.js-chrome-starter",
9
8
  "icons": { "16": "icons/icon16.png", "32": "icons/icon32.png", "64": "icons/icon64.png", "128": "icons/icon128.png" },
10
9
  "permissions": ["activeTab", "storage"],
@@ -8,61 +8,89 @@
8
8
  for (const resource of ['components/icons.js', 'lib/dom.js', 'lib/settings.js'])
9
9
  await import(chrome.runtime.getURL(resource))
10
10
 
11
- // Init ENV context
11
+ // Init DATA
12
12
  window.env = {
13
13
  site: new URL((await chrome.tabs.query({ active: true, currentWindow: true }))[0].url)
14
14
  .hostname.split('.').slice(-2, -1)[0], // extract 2nd-level domain
15
15
  menu: { isDark: document.documentElement.classList.contains('dark') }
16
16
  }
17
-
18
- // Import DATA
19
17
  ;({ app: window.app } = await chrome.storage.local.get('app'))
20
18
 
21
19
  // Define FUNCTIONS
22
20
 
23
21
  function createMenuEntry(entryData) {
24
-
25
- // Assemble elems
26
22
  const entry = {
27
23
  div: dom.create.elem('div', {
28
24
  id: entryData.key, class: 'menu-entry highlight-on-hover', title: entryData.helptip || '' }),
29
25
  leftElem: dom.create.elem('div', { class: `menu-icon ${ entryData.type || '' }`}),
30
- label: dom.create.elem('span')
26
+ label: dom.create.elem('span', { textContent: entryData.label })
31
27
  }
32
- entry.label.textContent = entryData.label
33
28
  entry.div.append(entry.leftElem, entry.label)
29
+
34
30
  if (entryData.type == 'toggle') { // add track to left, init knob pos
35
31
  entry.leftElem.append(dom.create.elem('span', { class: 'track' }))
36
32
  entry.leftElem.classList.toggle('on', settings.typeIsEnabled(entryData.key))
33
+
37
34
  } else { // add symbol to left, append status to right
38
35
  entry.leftElem.textContent = entryData.symbol || '⚙️' ; entry.label.style.flexGrow = 1
39
36
  if (entryData.status) entry.label.textContent += ` — ${entryData.status}`
40
37
  if (entryData.type == 'link') {
41
38
  entry.label.after(entry.rightElem = dom.create.elem('div', { class: 'menu-right-elem' }))
42
- entry.rightElem.append(icons.create({ key: 'open', size: 17, fill: 'black' }))
39
+ if (entryData.favicon) entry.favicon = dom.create.elem('img', { width: 15,
40
+ src: typeof entryData.favicon == 'string' ? entryData.favicon
41
+ : `https://www.google.com/s2/favicons?domain=${new URL(entryData.url).hostname}` })
42
+ entry.openIcon = icons.create({ key: 'open', size: 17, fill: 'black' })
43
+ entry.rightElem.append(entry.favicon || entry.openIcon)
44
+ if (entry.favicon) entry.rightElem.onmouseenter = entry.rightElem.onmouseleave = ({ type }) =>
45
+ entry.rightElem.firstChild.replaceWith(entry[type == 'mouseenter' ? 'openIcon' : 'favicon'])
43
46
  }
44
47
  }
45
- if (entryData.type == 'category')
48
+
49
+ if (entryData.type == 'category') // append drop-down caret
46
50
  entry.div.append(icons.create({ key: 'caretDown', size: 11, class: 'menu-caret menu-right-elem' }))
51
+
47
52
  else if (entryData.type == 'slider') { // append slider, add listeners, remove .highlight-on-hover
48
- entry.slider = dom.create.elem('input', { class: 'slider', type: 'range',
49
- min: entryData.min || 0, max: entryData.max || 100, value: config[entryData.key] })
53
+ const minVal = entryData.min ?? 0, maxVal = entryData.max ?? 100
54
+
55
+ // Create/append slider elems
56
+ entry.div.append(entry.slider = dom.create.elem('input', { class: 'slider', type: 'range',
57
+ min: minVal, max: maxVal, value: config[entryData.key] }))
58
+ entry.div.classList.remove('highlight-on-hover')
50
59
  if (entryData.step || env.browser.isFF) // use val from entryData or default to 2% in FF for being laggy
51
60
  entry.slider.step = entryData.step || ( 0.02 * entry.slider.max - entry.slider.min )
52
61
  entry.label.textContent += `: ${entry.slider.value}${ entryData.labelSuffix || '' }`
62
+ entry.label.append(entry.editLink = dom.create.elem('span', {
63
+ class: 'edit-link', role: 'button', tabindex: '0', 'aria-label': entryData.helptip, textContent: 'Edit'
64
+ }))
53
65
  entry.slider.style.setProperty('--track-fill-percent', `${ entry.slider.value / entry.slider.max *100 }%`)
66
+
67
+ // Add listeners
68
+ entry.editLink.onclick = () => {
69
+ const promptMsg = `Enter new value for ${entryData.label} (between ${minVal}–${maxVal}):`,
70
+ userVal = prompt(promptMsg, entry.slider.value)
71
+ if (userVal == null) return // user cancelled so do nothing
72
+ if (!/\d/.test(userVal)) return alert(`Enter a valid number between ${minVal} and ${maxVal}!`)
73
+ let validVal = parseInt(userVal.replace(/\D/g, '')) ; if (isNaN(validVal)) return
74
+ validVal = Math.max(minVal, Math.min(maxVal, validVal))
75
+ entry.slider.value = validVal ; settings.save(entryData.key, validVal)
76
+ sync.configToUI({ updatedKey: entryData.key })
77
+ entry.label.textContent = `${entryData.label}: ${validVal}${ entryData.labelSuffix || '' }`
78
+ entry.label.append(entry.editLink)
79
+ entry.slider.style.setProperty('--track-fill-percent', `${ validVal / entry.slider.max *100 }%`)
80
+ }
54
81
  entry.slider.oninput = ({ target: { value }}) => { // update label/color
55
82
  settings.save(entryData.key, parseInt(value)) ; sync.configToUI({ updatedKey: entryData.key })
56
83
  entry.label.textContent = `${entryData.label}: ${value}${ entryData.labelSuffix || '' }`
84
+ entry.label.append(entry.editLink)
57
85
  entry.slider.style.setProperty('--track-fill-percent', `${ value / entry.slider.max *100 }%`)
58
86
  }
59
- entry.div.onwheel = event => { // move slider by 2 steps
60
- entry.slider.value = parseInt(entry.slider.value) -Math.sign(event.deltaY) *2
87
+ entry.div.onwheel = ({ deltaY }) => { // move slider by 2 steps
88
+ entry.slider.value = parseInt(entry.slider.value) - Math.sign(deltaY) *2
61
89
  entry.slider.dispatchEvent(new Event('input'))
62
90
  }
63
- entry.div.append(entry.slider) ; entry.div.classList.remove('highlight-on-hover')
64
91
  }
65
- if (entryData.dependencies) {
92
+
93
+ if (entryData.dependencies) { // hide/show according to toggle state
66
94
  const toDisable = Object.values(entryData.dependencies).flat().some(dep => !settings.typeIsEnabled(dep))
67
95
  Object.assign(entry.div.style, {
68
96
  transition: '', minHeight: 'auto', opacity: +!toDisable,
@@ -83,8 +111,8 @@
83
111
  entry.leftElem.classList.toggle('on')
84
112
  settings.save(entryData.key, !config[entryData.key])
85
113
  sync.configToUI({ updatedKey: entryData.key })
86
- requestAnimationFrame(() => notify(`${entryData.label} ${chrome.i18n.getMessage(`state_${
87
- settings.typeIsEnabled(entryData.key) ? 'on' : 'off' }`).toUpperCase()}`))
114
+ requestAnimationFrame(() => notify(
115
+ `${entryData.label} ${['OFF', 'ON'][+settings.typeIsEnabled(entryData.key)]}`))
88
116
  },
89
117
  link: () => { open(entryData.url) ; close() }
90
118
  })[entryData.type]()
@@ -99,8 +127,7 @@
99
127
  for (const [ctrlKey, ctrlData] of Object.entries({ ...settings.categories, ...settings.controls }))
100
128
  if (Object.values(ctrlData.dependencies || {}).flat().includes(entryData.key)) {
101
129
  const depDiv = document.querySelector(`div#${ctrlKey}`) ; if (!depDiv) continue
102
- const ctgChildrenDiv = depDiv.closest('.categorized-entries'),
103
- ctgChildren = ctgChildrenDiv.querySelectorAll('.menu-entry'),
130
+ const ctgChildren = depDiv.closest('.categorized-entries').querySelectorAll('.menu-entry'),
104
131
  toDisable = !settings.typeIsEnabled(entryData.key)
105
132
  requestAnimationFrame(() => Object.assign(depDiv.closest('.categorized-entries').style, {
106
133
  height: `${dom.get.computedHeight(ctgChildren)}px`,
@@ -144,7 +171,7 @@
144
171
  if (elem.id && (elem.matches(`#${elem.id}:has(> div.link)`) || elem.id == 'aboutEntry'))
145
172
  return // never disable link/About entries
146
173
  elem.style.transition = config.extensionDisabled ? '' : 'opacity 0.15s ease-in'
147
- const toDisable = config.extensionIsDisabled || !depIsEnabled(elem.id)
174
+ const toDisable = config.extensionDisabled || !depIsEnabled(elem.id)
148
175
  if (elem.classList.contains('categorized-entries')) { // fade category strip
149
176
  elem.style.transition = toDisable ? 'none' : 'var(--border-transition)'
150
177
  elem.style.borderImage = elem.style.borderImage.replace(
@@ -207,7 +234,6 @@
207
234
  masterToggle.div.append(masterToggle.switch) ; masterToggle.switch.append(masterToggle.track)
208
235
  await settings.load('extensionDisabled') ; masterToggle.switch.classList.toggle('on', !config.extensionDisabled)
209
236
  masterToggle.div.onclick = () => {
210
- env.extensionWasDisabled = config.extensionDisabled
211
237
  masterToggle.switch.classList.toggle('on') ; settings.save('extensionDisabled', !config.extensionDisabled)
212
238
  Object.keys(sync).forEach(key => sync[key]()) // sync fade + storage to UI
213
239
  notify(`${app.name} ${ this.checked ? 'ON' : 'OFF' }`)
@@ -228,17 +254,17 @@
228
254
  Object.values(categorizedCtrls.general || {}).forEach(ctrl => menuEntriesDiv.append(createMenuEntry(ctrl)))
229
255
 
230
256
  // Create/append categorized controls
231
- Object.entries(categorizedCtrls).forEach(([category, ctrls]) => {
232
- if (category == 'general') return
233
- const ctgData = { ...settings.categories[category], key: category, type: 'category' },
234
- ctgChildrenDiv = dom.create.elem('div', { class: 'categorized-entries' })
235
- if (ctgData.color) { // color the stripe
236
- const [r, g, b] = ctgData.color.match(/\w\w/g).map(v => parseInt(v, 16))
257
+ Object.entries(settings.categories).forEach(([key, category]) => {
258
+ if (!categorizedCtrls[key]) return
259
+ category.key = key ; category.type = 'category'
260
+ const ctgChildrenDiv = dom.create.elem('div', { class: 'categorized-entries' })
261
+ if (category.color) { // color the stripe
262
+ const [r, g, b] = category.color.match(/\w\w/g).map(v => parseInt(v, 16))
237
263
  ctgChildrenDiv.style.borderImage = `linear-gradient(transparent, rgba(${r},${g},${b},${
238
264
  env.menu.isDark ? 0.5 : 1 })) 30 100% ${ env.menu.isDark ? '/ 100' : '' }`
239
265
  }
240
- menuEntriesDiv.append(createMenuEntry(ctgData), ctgChildrenDiv)
241
- Object.values(ctrls).forEach(ctrl => ctgChildrenDiv.append(createMenuEntry(ctrl)))
266
+ menuEntriesDiv.append(createMenuEntry(category), ctgChildrenDiv)
267
+ Object.values(categorizedCtrls[key]).forEach(ctrl => ctgChildrenDiv.append(createMenuEntry(ctrl)))
242
268
  })
243
269
  }
244
270
 
@@ -261,15 +287,18 @@
261
287
  aboutEntry.div.onclick = () => { chrome.runtime.sendMessage({ action: 'showAbout' }) ; close() }
262
288
 
263
289
  // Create/append CHATGPT entry
264
- const activeTabURL = (await chrome.tabs.query({ active: true, currentWindow: true }))[0].url,
290
+ const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }),
265
291
  chatgptURL = chrome.runtime.getManifest().content_scripts[0].matches.map(url => url.replace(/\/\*$/, ''))
266
- if (!activeTabURL.includes(chatgptURL)) footer.before(createMenuEntry({
267
- key: 'chatgptEntry', type: 'link', symbol: '🤖', label: 'Open ChatGPT', url: chatgptURL, helptip: chatgptURL }))
292
+ if (!activeTab.url.includes(chatgptURL))
293
+ footer.before(createMenuEntry({
294
+ key: 'chatgptEntry', type: 'link', symbol: '🤖', url: chatgptURL, helptip: chatgptURL, label: 'Open ChatGPT',
295
+ favicon: 'data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%22180%22%20height=%22180%22%20fill=%22none%22%3E%3Cstyle%3E:root%7B--primary-fill:%23000;--secondary-fill:%23fff;%7D@media%20(prefers-color-scheme:dark)%7B:root%7B--primary-fill:%23fff;--secondary-fill:%23000;%7D%7D%3C/style%3E%3Cg%20clip-path=%22url(%23a)%22%3E%3Crect%20width=%22180%22%20height=%22180%22%20fill=%22var(--primary-fill)%22%20rx=%2290%22/%3E%3Cg%20clip-path=%22url(%23b)%22%3E%3Cpath%20fill=%22var(--secondary-fill)%22%20d=%22M75.91%2073.628V62.232c0-.96.36-1.68%201.199-2.16l22.912-13.194c3.119-1.8%206.838-2.639%2010.676-2.639%2014.394%200%2023.511%2011.157%2023.511%2023.032%200%20.839%200%201.799-.12%202.758l-23.752-13.914c-1.439-.84-2.879-.84-4.318%200L75.91%2073.627Zm53.499%2044.383v-27.23c0-1.68-.72-2.88-2.159-3.719L97.142%2069.55l9.836-5.638c.839-.48%201.559-.48%202.399%200l22.912%2013.195c6.598%203.839%2011.035%2011.995%2011.035%2019.912%200%209.116-5.397%2017.513-13.915%2020.992v.001Zm-60.577-23.99-9.836-5.758c-.84-.48-1.2-1.2-1.2-2.16v-26.39c0-12.834%209.837-22.55%2023.152-22.55%205.039%200%209.716%201.679%2013.676%204.678L70.993%2055.516c-1.44.84-2.16%202.039-2.16%203.719v34.787-.002Zm21.173%2012.234L75.91%2098.339V81.546l14.095-7.917%2014.094%207.917v16.793l-14.094%207.916Zm9.056%2036.467c-5.038%200-9.716-1.68-13.675-4.678l23.631-13.676c1.439-.839%202.159-2.038%202.159-3.718V85.863l9.956%205.757c.84.48%201.2%201.2%201.2%202.16v26.389c0%2012.835-9.957%2022.552-23.27%2022.552v.001Zm-28.43-26.75L47.72%20102.778c-6.599-3.84-11.036-11.996-11.036-19.913%200-9.236%205.518-17.513%2014.034-20.992v27.35c0%201.68.72%202.879%202.16%203.718l29.989%2017.393-9.837%205.638c-.84.48-1.56.48-2.399%200Zm-1.318%2019.673c-13.555%200-23.512-10.196-23.512-22.792%200-.959.12-1.919.24-2.879l23.63%2013.675c1.44.84%202.88.84%204.32%200l30.108-17.392v11.395c0%20.96-.361%201.68-1.2%202.16l-22.912%2013.194c-3.119%201.8-6.837%202.639-10.675%202.639Zm29.748%2014.274c14.515%200%2026.63-10.316%2029.39-23.991%2013.434-3.479%2022.071-16.074%2022.071-28.91%200-8.396-3.598-16.553-10.076-22.43.6-2.52.96-5.039.96-7.557%200-17.153-13.915-29.99-29.989-29.99-3.239%200-6.358.48-9.477%201.56-5.398-5.278-12.835-8.637-20.992-8.637-14.515%200-26.63%2010.316-29.39%2023.991-13.434%203.48-22.07%2016.074-22.07%2028.91%200%208.396%203.598%2016.553%2010.075%2022.431-.6%202.519-.96%205.038-.96%207.556%200%2017.154%2013.915%2029.989%2029.99%2029.989%203.238%200%206.357-.479%209.476-1.559%205.397%205.278%2012.835%208.637%2020.992%208.637Z%22/%3E%3C/g%3E%3C/g%3E%3Cdefs%3E%3CclipPath%20id=%22a%22%3E%3Cpath%20d=%22M0%200h180v180H0z%22/%3E%3C/clipPath%3E%3CclipPath%20id=%22b%22%3E%3Cpath%20d=%22M29.487%2029.964h121.035v119.954H29.487z%22/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E'
296
+ }))
268
297
 
269
298
  // Create/append LATEST CHANGES entry
270
299
  const latestChangesURL = `${app.urls.github}/commits`
271
300
  footer.before(createMenuEntry({
272
- key: 'latestChangesEntry', type: 'link', symbol: '🚀',
301
+ key: 'latestChangesEntry', type: 'link', symbol: '🚀', favicon: true,
273
302
  label: 'Latest Changes...', url: latestChangesURL, helptip: latestChangesURL
274
303
  }))
275
304
 
@@ -8,7 +8,7 @@ body {
8
8
  width: 268px ; margin: 0 ; font-size: .905rem ;
9
9
  font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
10
10
  "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;
11
- background-image: linear-gradient(180deg, #b6ebff -163px, white 65px)
11
+ background-image: linear-gradient(180deg, #b6ebff -96px, white 65px)
12
12
  }
13
13
 
14
14
  /* Color/fade mods */
@@ -45,7 +45,7 @@ header {
45
45
  border-bottom: solid 1px lightgrey ; padding: 5px 5px 5px 0 ; margin: 0 ;
46
46
  height: 38px ; display: flex ; align-items: center }
47
47
  .logo { margin: 0 8px 0 12px ; position: relative ; top: 3px }
48
- .menu-title { font-size: 0.85rem ; font-weight: 600 ; padding-right: 3px }
48
+ .menu-title { font-size: 1rem ; font-weight: 600 ; padding: 4px }
49
49
  .master-toggle { margin-left: auto ; display: flex }
50
50
 
51
51
  /* Menu item elements */
@@ -84,6 +84,8 @@ div.menu-entry > input.slider {
84
84
  border: 4px solid var(--thumb-border) ; border-radius: 16px ; cursor: ew-resize ; transition: transform 0.05s ease
85
85
  }
86
86
  .slider::-webkit-slider-thumb:hover { transform: scaleX(1.325) }
87
+ .edit-link { text-transform: uppercase ; font-size: 0.65em ; margin-left: 0.75em ; opacity: 0.5 ; cursor: pointer }
88
+ .edit-link:hover { transition: opacity 0.1s ease-in-out ; opacity: 1 }
87
89
 
88
90
  /* Toggle elements */
89
91
  .toggle .track {
@@ -105,7 +107,7 @@ div#about > div.menu-icon { padding: 8px 10px 8px 11px }
105
107
  mask-image: var(--mask) ; -webkit-mask-image: var(--mask) /* eslint-disable-line */
106
108
  }
107
109
  .ticker-em { color: green } .highlight-on-hover:hover .ticker-em { color: #28ee28 }
108
- .ticker > div { animation: ticker linear 75s infinite }
110
+ .ticker > div { animation: ticker linear 85s infinite }
109
111
  @keyframes ticker { 0% { transform: translateX(100%) } 100% { transform: translateX(-2000%) }}
110
112
 
111
113
  /* Footer */
@@ -139,6 +141,7 @@ html.dark .menu-icon svg, html.dark .menu-right-elem, html.dark .menu-right-elem
139
141
  html.dark .menu-icon img { filter: brightness(0) invert(1) }
140
142
  html.dark .menu-icon:hover img { filter: none }
141
143
  html.dark .ticker-em { color: #28ee28 } html.dark .highlight-on-hover:hover .ticker-em { color: green }
144
+ html.dark #chatgptEntry:hover img { filter: invert(1) } /* to white favicon for legibility */
142
145
 
143
146
  /* Non-baseline features */
144
147
  @supports (cursor: pointer) { .highlight-on-hover:hover, .toggle .track, .chatgptjs-logo { cursor: pointer }}
@@ -8,33 +8,33 @@ chrome.storage.local.set({ app: {
8
8
  urls: {
9
9
  chatgptjs: 'https://chatgptjs.org',
10
10
  contributors: 'https://docs.chatgptjs.org/#-contributors',
11
- gitHub: 'https://github.com/KudoAI/chatgpt.js-chrome-starter',
11
+ github: 'https://github.com/KudoAI/chatgpt.js-chrome-starter',
12
12
  relatedExtensions: 'https://aiwebextensions.com',
13
13
  support: 'https://github.com/KudoAI/chatgpt.js-chrome-starter/issues'
14
14
  }
15
15
  }}) // save to Chrome storage
16
16
 
17
17
  // Launch CHATGPT on install
18
- chrome.runtime.onInstalled.addListener(details => {
19
- if (details.reason == 'install') // to exclude updates
18
+ chrome.runtime.onInstalled.addListener(({ reason }) => {
19
+ if (reason == 'install') // to exclude updates
20
20
  chrome.tabs.create({ url: chatgptURL })
21
21
  })
22
22
 
23
23
  // Sync SETTINGS to activated tabs
24
- chrome.tabs.onActivated.addListener(activeInfo =>
25
- chrome.tabs.sendMessage(activeInfo.tabId, { action: 'syncConfigToUI' }))
24
+ chrome.tabs.onActivated.addListener(({ tabId }) =>
25
+ chrome.tabs.sendMessage(tabId, { action: 'syncConfigToUI' }))
26
26
 
27
27
  // Show ABOUT modal on ChatGPT when toolbar button clicked
28
- chrome.runtime.onMessage.addListener(async req => {
29
- if (req.action == 'showAbout') {
28
+ chrome.runtime.onMessage.addListener(async ({ action }) => {
29
+ if (action == 'showAbout') {
30
30
  const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true })
31
31
  const chatgptTab = new URL(activeTab.url).hostname == 'chatgpt.com' ? activeTab
32
- : await chrome.tabs.create({ url: chatgptURL })
32
+ : await chrome.tabs.create({ url: chatgptURL })
33
33
  if (activeTab != chatgptTab) await new Promise(resolve => // after new tab loads
34
- chrome.tabs.onUpdated.addListener(function loadedListener(tabId, changeInfo) {
35
- if (tabId == chatgptTab.id && changeInfo.status == 'complete') {
36
- chrome.tabs.onUpdated.removeListener(loadedListener) ; setTimeout(resolve, 500)
34
+ chrome.tabs.onUpdated.addListener(function loadedListener(tabId, { status }) {
35
+ if (tabId == chatgptTab.id && status == 'complete') {
36
+ chrome.tabs.onUpdated.removeListener(loadedListener) ; setTimeout(resolve, 1500)
37
37
  }}))
38
- chrome.tabs.sendMessage(chatgptTab.id, { action: 'showAbout' })
38
+ chrome.tabs.sendMessage(chatgptTab.id, { action: 'showAbout', source: 'service-worker.js' })
39
39
  }
40
40
  })
@@ -3,12 +3,12 @@
3
3
  // @description A Greasemonkey template to start using chatgpt.js like a boss
4
4
  // @author chatgpt.js
5
5
  // @namespace https://chatgpt.js.org
6
- // @version 2025.7.28
6
+ // @version 2025.10.15
7
7
  // @license MIT
8
8
  // @icon data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%20fill='none'%3e%3cstyle%3e%20:root%20{%20--primary-fill:%20%23000;%20--secondary-fill:%20%23fff;%20}%20@media%20(prefers-color-scheme:%20dark)%20{%20:root%20{%20--primary-fill:%20%23fff;%20--secondary-fill:%20%23000;%20}%20}%20%3c/style%3e%3cg%20clip-path='url(%23a)'%3e%3crect%20width='180'%20height='180'%20fill='var(--primary-fill)'%20rx='90'%20/%3e%3cg%20clip-path='url(%23b)'%3e%3cpath%20fill='var(--secondary-fill)'%20d='M75.91%2073.628V62.232c0-.96.36-1.68%201.199-2.16l22.912-13.194c3.119-1.8%206.838-2.639%2010.676-2.639%2014.394%200%2023.511%2011.157%2023.511%2023.032%200%20.839%200%201.799-.12%202.758l-23.752-13.914c-1.439-.84-2.879-.84-4.318%200L75.91%2073.627Zm53.499%2044.383v-27.23c0-1.68-.72-2.88-2.159-3.719L97.142%2069.55l9.836-5.638c.839-.48%201.559-.48%202.399%200l22.912%2013.195c6.598%203.839%2011.035%2011.995%2011.035%2019.912%200%209.116-5.397%2017.513-13.915%2020.992v.001Zm-60.577-23.99-9.836-5.758c-.84-.48-1.2-1.2-1.2-2.16v-26.39c0-12.834%209.837-22.55%2023.152-22.55%205.039%200%209.716%201.679%2013.676%204.678L70.993%2055.516c-1.44.84-2.16%202.039-2.16%203.719v34.787-.002Zm21.173%2012.234L75.91%2098.339V81.546l14.095-7.917%2014.094%207.917v16.793l-14.094%207.916Zm9.056%2036.467c-5.038%200-9.716-1.68-13.675-4.678l23.631-13.676c1.439-.839%202.159-2.038%202.159-3.718V85.863l9.956%205.757c.84.48%201.2%201.2%201.2%202.16v26.389c0%2012.835-9.957%2022.552-23.27%2022.552v.001Zm-28.43-26.75L47.72%20102.778c-6.599-3.84-11.036-11.996-11.036-19.913%200-9.236%205.518-17.513%2014.034-20.992v27.35c0%201.68.72%202.879%202.16%203.718l29.989%2017.393-9.837%205.638c-.84.48-1.56.48-2.399%200Zm-1.318%2019.673c-13.555%200-23.512-10.196-23.512-22.792%200-.959.12-1.919.24-2.879l23.63%2013.675c1.44.84%202.88.84%204.32%200l30.108-17.392v11.395c0%20.96-.361%201.68-1.2%202.16l-22.912%2013.194c-3.119%201.8-6.837%202.639-10.675%202.639Zm29.748%2014.274c14.515%200%2026.63-10.316%2029.39-23.991%2013.434-3.479%2022.071-16.074%2022.071-28.91%200-8.396-3.598-16.553-10.076-22.43.6-2.52.96-5.039.96-7.557%200-17.153-13.915-29.99-29.989-29.99-3.239%200-6.358.48-9.477%201.56-5.398-5.278-12.835-8.637-20.992-8.637-14.515%200-26.63%2010.316-29.39%2023.991-13.434%203.48-22.07%2016.074-22.07%2028.91%200%208.396%203.598%2016.553%2010.075%2022.431-.6%202.519-.96%205.038-.96%207.556%200%2017.154%2013.915%2029.989%2029.99%2029.989%203.238%200%206.357-.479%209.476-1.559%205.397%205.278%2012.835%208.637%2020.992%208.637Z'%20/%3e%3c/g%3e%3c/g%3e%3cdefs%3e%3cclipPath%20id='a'%3e%3cpath%20d='M0%200h180v180H0z'%20/%3e%3c/clipPath%3e%3cclipPath%20id='b'%3e%3cpath%20d='M29.487%2029.964h121.035v119.954H29.487z'%20/%3e%3c/clipPath%3e%3c/defs%3e%3c/svg%3e
9
9
  // @icon64 data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%20fill='none'%3e%3cstyle%3e%20:root%20{%20--primary-fill:%20%23000;%20--secondary-fill:%20%23fff;%20}%20@media%20(prefers-color-scheme:%20dark)%20{%20:root%20{%20--primary-fill:%20%23fff;%20--secondary-fill:%20%23000;%20}%20}%20%3c/style%3e%3cg%20clip-path='url(%23a)'%3e%3crect%20width='180'%20height='180'%20fill='var(--primary-fill)'%20rx='90'%20/%3e%3cg%20clip-path='url(%23b)'%3e%3cpath%20fill='var(--secondary-fill)'%20d='M75.91%2073.628V62.232c0-.96.36-1.68%201.199-2.16l22.912-13.194c3.119-1.8%206.838-2.639%2010.676-2.639%2014.394%200%2023.511%2011.157%2023.511%2023.032%200%20.839%200%201.799-.12%202.758l-23.752-13.914c-1.439-.84-2.879-.84-4.318%200L75.91%2073.627Zm53.499%2044.383v-27.23c0-1.68-.72-2.88-2.159-3.719L97.142%2069.55l9.836-5.638c.839-.48%201.559-.48%202.399%200l22.912%2013.195c6.598%203.839%2011.035%2011.995%2011.035%2019.912%200%209.116-5.397%2017.513-13.915%2020.992v.001Zm-60.577-23.99-9.836-5.758c-.84-.48-1.2-1.2-1.2-2.16v-26.39c0-12.834%209.837-22.55%2023.152-22.55%205.039%200%209.716%201.679%2013.676%204.678L70.993%2055.516c-1.44.84-2.16%202.039-2.16%203.719v34.787-.002Zm21.173%2012.234L75.91%2098.339V81.546l14.095-7.917%2014.094%207.917v16.793l-14.094%207.916Zm9.056%2036.467c-5.038%200-9.716-1.68-13.675-4.678l23.631-13.676c1.439-.839%202.159-2.038%202.159-3.718V85.863l9.956%205.757c.84.48%201.2%201.2%201.2%202.16v26.389c0%2012.835-9.957%2022.552-23.27%2022.552v.001Zm-28.43-26.75L47.72%20102.778c-6.599-3.84-11.036-11.996-11.036-19.913%200-9.236%205.518-17.513%2014.034-20.992v27.35c0%201.68.72%202.879%202.16%203.718l29.989%2017.393-9.837%205.638c-.84.48-1.56.48-2.399%200Zm-1.318%2019.673c-13.555%200-23.512-10.196-23.512-22.792%200-.959.12-1.919.24-2.879l23.63%2013.675c1.44.84%202.88.84%204.32%200l30.108-17.392v11.395c0%20.96-.361%201.68-1.2%202.16l-22.912%2013.194c-3.119%201.8-6.837%202.639-10.675%202.639Zm29.748%2014.274c14.515%200%2026.63-10.316%2029.39-23.991%2013.434-3.479%2022.071-16.074%2022.071-28.91%200-8.396-3.598-16.553-10.076-22.43.6-2.52.96-5.039.96-7.557%200-17.153-13.915-29.99-29.989-29.99-3.239%200-6.358.48-9.477%201.56-5.398-5.278-12.835-8.637-20.992-8.637-14.515%200-26.63%2010.316-29.39%2023.991-13.434%203.48-22.07%2016.074-22.07%2028.91%200%208.396%203.598%2016.553%2010.075%2022.431-.6%202.519-.96%205.038-.96%207.556%200%2017.154%2013.915%2029.989%2029.99%2029.989%203.238%200%206.357-.479%209.476-1.559%205.397%205.278%2012.835%208.637%2020.992%208.637Z'%20/%3e%3c/g%3e%3c/g%3e%3cdefs%3e%3cclipPath%20id='a'%3e%3cpath%20d='M0%200h180v180H0z'%20/%3e%3c/clipPath%3e%3cclipPath%20id='b'%3e%3cpath%20d='M29.487%2029.964h121.035v119.954H29.487z'%20/%3e%3c/clipPath%3e%3c/defs%3e%3c/svg%3e
10
10
  // @match *://chatgpt.com/*
11
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js
11
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.4/dist/chatgpt.min.js
12
12
  // @grant GM_getValue
13
13
  // @grant GM_setValue
14
14
  // @noframes