@kudoai/chatgpt.js 3.2.1 → 3.3.1

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.
@@ -410,36 +410,42 @@ const chatgpt = { // eslint-disable-line no-redeclare
410
410
  return codeBlocks ? codeBlocks[codeBlocks.length - 1] : msg;
411
411
  },
412
412
 
413
- async isIdle() {
413
+ async isIdle(timeout = null) {
414
414
  const obsConfig = { childList: true, subtree: true },
415
415
  selectors = { msgDiv: 'div[data-message-author-role]',
416
416
  replyDiv: 'div[data-message-author-role="assistant"]' };
417
417
 
418
- await new Promise(resolve => { // when in conversation page
419
- if (document.querySelector(selectors.msgDiv)) resolve();
420
- else new MutationObserver((_, obs) => {
421
- if (document.querySelector(selectors.msgDiv)) { obs.disconnect(); resolve(); }
422
- }).observe(document.body, obsConfig);
423
- });
424
- await new Promise(resolve => { // when reply starts generating
425
- new MutationObserver((_, obs) => {
426
- if (!chatgpt.getRegenerateBtn()) { obs.disconnect(); resolve(); }
427
- }).observe(document.body, obsConfig);
428
- });
429
- const lastReplyDiv = await new Promise(resolve => { // when code starts generating
430
- new MutationObserver((_, obs) => {
431
- const replyDivs = document.querySelectorAll(selectors.replyDiv),
432
- lastReplyDiv = replyDivs[replyDivs.length - 1];
433
- if (lastReplyDiv?.querySelector('pre')) { obs.disconnect(); resolve(lastReplyDiv); }
434
- }).observe(document.body, obsConfig);
435
- });
436
- await new Promise(resolve => { // when code stops generating
437
- new MutationObserver((_, obs) => {
438
- if (lastReplyDiv?.querySelector('pre').nextElementSibling // code block not last child of reply div
439
- || chatgpt.getRegenerateBtn() // ...or reply outright stopped generating
440
- ) { obs.disconnect(); resolve(); }
441
- }).observe(document.body, obsConfig);
442
- });
418
+ // Create promises
419
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
420
+ const isIdlePromise = (async () => {
421
+ await new Promise(resolve => { // when on convo page
422
+ if (document.querySelector(selectors.msgDiv)) resolve();
423
+ else new MutationObserver((_, obs) => {
424
+ if (document.querySelector(selectors.msgDiv)) { obs.disconnect(); resolve(); }
425
+ }).observe(document.body, obsConfig);
426
+ });
427
+ await new Promise(resolve => { // when reply starts generating
428
+ new MutationObserver((_, obs) => {
429
+ if (chatgpt.getStopBtn()) { obs.disconnect(); resolve(); }
430
+ }).observe(document.body, { childList: true, subtree: true });
431
+ });
432
+ const replyDivs = document.querySelectorAll(selectors.replyDiv),
433
+ lastReplyDiv = replyDivs[replyDivs.length - 1];
434
+ await new Promise(resolve => { // when code starts generating
435
+ new MutationObserver((_, obs) => {
436
+ if (lastReplyDiv?.querySelector('pre')) { obs.disconnect(); resolve(); }
437
+ }).observe(document.body, obsConfig);
438
+ });
439
+ return new Promise(resolve => { // when code stops generating
440
+ new MutationObserver((_, obs) => {
441
+ if (lastReplyDiv?.querySelector('pre')?.nextElementSibling // code block not last child of reply div
442
+ || !chatgpt.getStopBtn() // ...or reply outright stopped generating
443
+ ) { obs.disconnect(); resolve(true); }
444
+ }).observe(document.body, obsConfig);
445
+ });
446
+ })();
447
+
448
+ return await (timeoutPromise ? Promise.race([isIdlePromise, timeoutPromise]) : isIdlePromise);
443
449
  },
444
450
 
445
451
  async minify(code) {
@@ -614,6 +620,24 @@ const chatgpt = { // eslint-disable-line no-redeclare
614
620
  extractCode() { chatgpt.code.extract(); },
615
621
  focusChatbar() { chatgpt.getChatBox()?.focus(); },
616
622
 
623
+ footer: {
624
+ get() { return document.querySelector('main form')?.parentNode.parentNode.nextElementSibling; },
625
+
626
+ hide() {
627
+ const footer = chatgpt.footer.get();
628
+ if (!footer) return console.error('Footer element not found!');
629
+ if (footer.style.visibility == 'hidden') return console.info('Footer already hidden!');
630
+ footer.style.visibility = 'hidden'; footer.style.height = '3px';
631
+ },
632
+
633
+ show() {
634
+ const footer = chatgpt.footer.get();
635
+ if (!footer) return console.error('Footer element not found!');
636
+ if (footer.style.visibility != 'hidden') return console.info('Footer already shown!');
637
+ footer.style.visibility = footer.style.height = 'inherit';
638
+ }
639
+ },
640
+
617
641
  generateRandomIP() {
618
642
  const ip = Array.from({length: 4}, () => Math.floor(chatgpt.randomFloat() * 256)).join('.');
619
643
  console.info('IP generated: ' + ip);
@@ -859,32 +883,19 @@ const chatgpt = { // eslint-disable-line no-redeclare
859
883
  },
860
884
 
861
885
  getChatInput() { return chatgpt.getChatBox().value; },
862
-
863
- getContinueGeneratingButton() {
864
- for (const formBtnSVG of document.querySelectorAll('form button svg')) {
865
- if (formBtnSVG.querySelector('path[d*="M4.472 2.5a1"]'))
866
- return formBtnSVG.parentNode.parentNode;
867
- }},
868
-
869
- getFooterDiv() { return document.querySelector('main form')?.parentNode.parentNode.nextElementSibling; },
870
- getHeaderDiv() { return document.querySelector('main .sticky'); },
886
+ getContinueButton() { return document.querySelector('button:has([d^="M4.47189"])'); },
887
+ getFooterDiv() { return chatgpt.footer.get(); },
888
+ getHeaderDiv() { return chatgpt.header.get(); },
871
889
  getLastPrompt() { return chatgpt.getChatData('active', 'msg', 'user', 'latest'); },
872
890
  getLastResponse() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
873
891
 
874
892
  getNewChatButton() {
875
- for (const navBtnSVG of document.querySelectorAll('nav button svg'))
876
- if (navBtnSVG.querySelector('path[d^="M15.6729"], ' // pencil-on-pad icon
877
- + 'path[d^="M3.06957"]')) // refresh icon if temp chat
878
- return navBtnSVG.parentNode;
893
+ return document.querySelector('button:has([d*="M15.6729"],' // pencil-on-pad icon
894
+ + '[d^="M3.06957"])'); // refresh icon if temp chat
879
895
  },
880
896
 
881
897
  getNewChatLink() { return document.querySelector('nav a[href="/"]'); },
882
-
883
- getRegenerateButton() {
884
- for (const mainSVG of document.querySelectorAll('main svg')) {
885
- if (mainSVG.querySelector('path[d^="M3.06957"]')) // regen icon found
886
- return mainSVG.parentNode;
887
- }},
898
+ getRegenerateButton() { return document.querySelector('button:has([d^="M3.06957"])'); },
888
899
 
889
900
  getResponse() {
890
901
  // * Returns response via DOM by index arg if OpenAI chat page is active, otherwise uses API w/ following args:
@@ -904,33 +915,32 @@ const chatgpt = { // eslint-disable-line no-redeclare
904
915
  || document.querySelector('path[d*="M15.192 8.906a1.143"]')?.parentNode.parentNode; // post-GPT-4o
905
916
  },
906
917
 
907
- getStopGeneratingButton() {
908
- for (const svg of document.querySelectorAll('form button svg')) {
909
- if (svg.querySelector('path[d*="2 0 0 1 2"], rect'))
910
- return svg.parentNode;
911
- }},
918
+ getStopButton() { return document.querySelector('button:has([d*="2 0 0 1 2"], rect)'); },
912
919
 
913
920
  getUserLanguage() {
914
921
  return navigator.languages[0] || navigator.language || navigator.browserLanguage ||
915
- navigator.systemLanguage || navigator.userLanguage || ''; },
922
+ navigator.systemLanguage || navigator.userLanguage || '';
923
+ },
916
924
 
917
- hideFooter() {
918
- const footer = chatgpt.getFooterDiv();
919
- if (!footer) return console.error('Footer element not found!');
920
- if (footer.style.visibility == 'hidden') return console.info('Footer already hidden!');
921
- footer.style.visibility = 'hidden'; footer.style.height = '3px';
925
+ header: {
926
+ get() { return document.querySelector('main .sticky'); },
927
+ hide() { chatgpt.header.get().style.display = 'none'; },
928
+ show() { chatgpt.header.get().style.display = 'flex'; }
922
929
  },
923
930
 
924
- hideHeader() { chatgpt.getHeaderDiv().style.display = 'none'; },
931
+ hideFooter() { chatgpt.footer.hide(); },
932
+ hideHeader() { chatgpt.header.hide(); },
925
933
 
926
934
  history: {
927
- isLoaded() {
928
- return new Promise(resolve => {
935
+ async isLoaded(timeout = null) {
936
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
937
+ const isLoadedPromise = new Promise(resolve => {
929
938
  if (document.querySelector('nav')) resolve(true);
930
939
  else new MutationObserver((_, obs) => {
931
940
  if (document.querySelector('nav')) { obs.disconnect(); resolve(true); }
932
941
  }).observe(document.body, { childList: true, subtree: true });
933
942
  });
943
+ return await ( timeoutPromise ? Promise.race([isLoadedPromise, timeoutPromise]) : isLoadedPromise );
934
944
  }
935
945
  },
936
946
 
@@ -1062,22 +1072,43 @@ const chatgpt = { // eslint-disable-line no-redeclare
1062
1072
  isDarkMode() { return document.documentElement.classList.toString().includes('dark'); },
1063
1073
  isFullScreen() { return chatgpt.browser.isFullScreen(); },
1064
1074
 
1065
- isIdle() {
1066
- return new Promise(resolve => {
1067
- if (chatgpt.getRegenerateBtn()) resolve(true);
1068
- else new MutationObserver((_, obs) => {
1069
- if (chatgpt.getRegenerateBtn()) { obs.disconnect(); resolve(true); }
1070
- }).observe(document.body, { childList: true, subtree: true });
1071
- });
1075
+ async isIdle(timeout = null) {
1076
+ const obsConfig = { childList: true, subtree: true },
1077
+ msgDivSelector = 'div[data-message-author-role]';
1078
+
1079
+ // Create promises
1080
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
1081
+ const isIdlePromise = (async () => {
1082
+ await new Promise(resolve => { // when on convo page
1083
+ if (document.querySelector(msgDivSelector)) resolve();
1084
+ else new MutationObserver((_, obs) => {
1085
+ if (document.querySelector(msgDivSelector)) { obs.disconnect(); resolve(); }
1086
+ }).observe(document.body, obsConfig);
1087
+ });
1088
+ await new Promise(resolve => { // when reply starts generating
1089
+ new MutationObserver((_, obs) => {
1090
+ if (chatgpt.getStopBtn()) { obs.disconnect(); resolve(); }
1091
+ }).observe(document.body, obsConfig);
1092
+ });
1093
+ return new Promise(resolve => { // when reply stops generating
1094
+ new MutationObserver((_, obs) => {
1095
+ if (!chatgpt.getStopBtn()) { obs.disconnect(); resolve(true); }
1096
+ }).observe(document.body, obsConfig);
1097
+ });
1098
+ })();
1099
+
1100
+ return await (timeoutPromise ? Promise.race([isIdlePromise, timeoutPromise]) : isIdlePromise);
1072
1101
  },
1073
1102
 
1074
- isLoaded() {
1075
- return new Promise(resolve => {
1103
+ async isLoaded(timeout = null) {
1104
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
1105
+ const isLoadedPromise = new Promise(resolve => {
1076
1106
  if (chatgpt.getNewChatBtn()) resolve(true);
1077
1107
  else new MutationObserver((_, obs) => {
1078
1108
  if (chatgpt.getNewChatBtn()) { obs.disconnect(); resolve(true); }
1079
1109
  }).observe(document.body, { childList: true, subtree: true });
1080
1110
  });
1111
+ return await ( timeoutPromise ? Promise.race([isLoadedPromise, timeoutPromise]) : isLoadedPromise );
1081
1112
  },
1082
1113
 
1083
1114
  isLightMode() { return document.documentElement.classList.toString().includes('light'); },
@@ -1499,7 +1530,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1499
1530
  return console.error(`Argument ${ i + 1 } must be a string!`);
1500
1531
  const textArea = chatgpt.getChatBox();
1501
1532
  if (!textArea) return console.error('Chatbar element not found!');
1502
- textArea.value = msg;
1533
+ const msgP = document.createElement('p'); msgP.textContent = msg;
1534
+ textArea.replaceChild(msgP, textArea.querySelector('p'));
1503
1535
  textArea.dispatchEvent(new Event('input', { bubbles: true })); // enable send button
1504
1536
  setTimeout(function delaySend() {
1505
1537
  const sendBtn = chatgpt.getSendButton();
@@ -1512,10 +1544,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1512
1544
 
1513
1545
  sendInNewChat(msg) {
1514
1546
  if (typeof msg !== 'string') return console.error('Message must be a string!');
1515
- for (const navLink of document.querySelectorAll('nav a')) {
1516
- if (/(new|clear) chat/i.test(navLink.text)) {
1517
- navLink.click(); break;
1518
- }} setTimeout(() => { chatgpt.send(msg); }, 500);
1547
+ try { chatgpt.getNewChatBtn().click(); } catch (err) { return console.error(err.message); }
1548
+ setTimeout(() => { chatgpt.send(msg); }, 500);
1519
1549
  },
1520
1550
 
1521
1551
  settings: {
@@ -1639,14 +1669,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1639
1669
  });});});});});
1640
1670
  },
1641
1671
 
1642
- showFooter() {
1643
- const footer = chatgpt.getFooterDiv();
1644
- if (!footer) return console.error('Footer element not found!');
1645
- if (footer.style.visibility != 'hidden') return console.info('Footer already shown!');
1646
- footer.style.visibility = footer.style.height = 'inherit';
1647
- },
1648
-
1649
- showHeader() { chatgpt.getHeaderDiv().style.display = 'flex'; },
1672
+ showFooter() { chatgpt.footer.show(); },
1673
+ showHeader() { chatgpt.header.show(); },
1650
1674
 
1651
1675
  sidebar: {
1652
1676
  elements: [], observer: {},
@@ -1759,13 +1783,15 @@ const chatgpt = { // eslint-disable-line no-redeclare
1759
1783
  return newElement.id; // Return the element id
1760
1784
  },
1761
1785
 
1786
+ exists() { return !!chatgpt.getNewChatLink(); },
1762
1787
  hide() { this.isOn() ? this.toggle() : console.info('Sidebar already hidden!'); },
1763
1788
  show() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!'); },
1764
1789
  isOff() { return !this.isOn(); },
1765
1790
  isOn() {
1766
- const sidebar = document.querySelector('body script + div > div');
1767
- if (!sidebar) return console.error('Sidebar element not found!');
1768
- return chatgpt.browser.isMobile() ?
1791
+ const sidebar = (() => {
1792
+ return chatgpt.sidebar.exists() ? document.querySelector('[class*="sidebar"]') : null; })();
1793
+ if (!sidebar) { console.error('Sidebar element not found!'); return false; }
1794
+ else return chatgpt.browser.isMobile() ?
1769
1795
  document.documentElement.style.overflow == 'hidden'
1770
1796
  : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px';
1771
1797
  },
@@ -1777,19 +1803,19 @@ const chatgpt = { // eslint-disable-line no-redeclare
1777
1803
  : btn => btn.querySelector('svg path[d^="M8.857"]');
1778
1804
  for (const btn of document.querySelectorAll(navBtnSelector))
1779
1805
  if (isToggleBtn(btn)) { btn.click(); return; }
1806
+ console.error('Sidebar toggle not found!');
1780
1807
  },
1781
1808
 
1782
- async isLoaded() {
1809
+ async isLoaded(timeout = 5000) {
1783
1810
  await chatgpt.isLoaded();
1784
- return Promise.race([
1785
- new Promise(resolve => {
1786
- if (chatgpt.getNewChatLink()) resolve(true);
1787
- else new MutationObserver((_, obs) => {
1788
- if (chatgpt.getNewChatLink()) { obs.disconnect(); resolve(true); }
1789
- }).observe(document.body, { childList: true, subtree: true });
1790
- }),
1791
- new Promise(resolve => setTimeout(resolve, 5000)) // since New Chat link not always present
1792
- ]);
1811
+ const timeoutPromise = new Promise(resolve => setTimeout(() => { resolve(false); }, timeout));
1812
+ const isLoadedPromise = new Promise(resolve => {
1813
+ if (chatgpt.getNewChatLink()) resolve(true);
1814
+ else new MutationObserver((_, obs) => {
1815
+ if (chatgpt.getNewChatLink()) { obs.disconnect(); resolve(true); }
1816
+ }).observe(document.body, { childList: true, subtree: true });
1817
+ });
1818
+ return await Promise.race([isLoadedPromise, timeoutPromise]);
1793
1819
  }
1794
1820
  },
1795
1821
 
@@ -1902,13 +1928,14 @@ const cjsFuncAliases = [
1902
1928
  ['deactivateAutoRefresh', 'deactivateAutoRefresher', 'deactivateRefresher', 'deactivateSessionRefresher'],
1903
1929
  ['detectLanguage', 'getLanguage'],
1904
1930
  ['executeCode', 'codeExecute'],
1931
+ ['exists', 'isAvailable', 'isExistent', 'isPresent'],
1905
1932
  ['exportChat', 'chatExport', 'export'],
1906
1933
  ['getFooterDiv', 'getFooter'],
1907
1934
  ['getHeaderDiv', 'getHeader'],
1908
1935
  ['getLastPrompt', 'getLastQuery', 'getMyLastMsg', 'getMyLastQuery'],
1909
- ['getContinueGeneratingButton', 'getContinueButton'],
1936
+ ['getContinueButton', 'getContinueGeneratingButton'],
1910
1937
  ['getScrollToBottomButton', 'getScrollButton'],
1911
- ['getStopGeneratingButton', 'getStopButton'],
1938
+ ['getStopButton', 'getStopGeneratingButton'],
1912
1939
  ['getTextarea', 'getTextArea', 'getChatbar', 'getChatBar', 'getChatbox', 'getChatBox'],
1913
1940
  ['isFullScreen', 'isFullscreen', 'isfullscreen'],
1914
1941
  ['isLoaded', 'isloaded'],
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "name": "ChatGPT Extension",
4
4
  "description": "A Chrome template to start using chatgpt.js like a boss!",
5
- "version": "2024.9.10",
5
+ "version": "2024.9.16",
6
6
  "author": "chatgpt.js",
7
7
  "icons": {
8
8
  "16": "icons/icon16.png",
@@ -3,13 +3,13 @@
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 2024.9.10
6
+ // @version 2024.9.15
7
7
  // @license MIT
8
8
  // @match *://chatgpt.com/*
9
9
  // @match *://chat.openai.com/*
10
- // @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.2.1/starters/greasemonkey/media/images/icons/robot/icon48.png
11
- // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.2.1/starters/greasemonkey/media/images/icons/robot/icon64.png
12
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.2.1/dist/chatgpt.min.js
10
+ // @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.3.1/starters/greasemonkey/media/images/icons/robot/icon48.png
11
+ // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.3.1/starters/greasemonkey/media/images/icons/robot/icon64.png
12
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.3.1/dist/chatgpt.min.js
13
13
  // @grant GM_getValue
14
14
  // @grant GM_setValue
15
15
  // @noframes