@kudoai/chatgpt.js 3.2.1 → 3.3.0

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);
@@ -866,16 +890,14 @@ const chatgpt = { // eslint-disable-line no-redeclare
866
890
  return formBtnSVG.parentNode.parentNode;
867
891
  }},
868
892
 
869
- getFooterDiv() { return document.querySelector('main form')?.parentNode.parentNode.nextElementSibling; },
870
- getHeaderDiv() { return document.querySelector('main .sticky'); },
893
+ getFooterDiv() { return chatgpt.footer.get(); },
894
+ getHeaderDiv() { return chatgpt.header.get(); },
871
895
  getLastPrompt() { return chatgpt.getChatData('active', 'msg', 'user', 'latest'); },
872
896
  getLastResponse() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
873
897
 
874
898
  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;
899
+ return document.querySelector('button:has([d*="M15.6729"],' // pencil-on-pad icon
900
+ + '[d^="M3.06957"])'); // refresh icon if temp chat
879
901
  },
880
902
 
881
903
  getNewChatLink() { return document.querySelector('nav a[href="/"]'); },
@@ -912,25 +934,28 @@ const chatgpt = { // eslint-disable-line no-redeclare
912
934
 
913
935
  getUserLanguage() {
914
936
  return navigator.languages[0] || navigator.language || navigator.browserLanguage ||
915
- navigator.systemLanguage || navigator.userLanguage || ''; },
937
+ navigator.systemLanguage || navigator.userLanguage || '';
938
+ },
916
939
 
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';
940
+ header: {
941
+ get() { return document.querySelector('main .sticky'); },
942
+ hide() { chatgpt.header.get().style.display = 'none'; },
943
+ show() { chatgpt.header.get().style.display = 'flex'; }
922
944
  },
923
945
 
924
- hideHeader() { chatgpt.getHeaderDiv().style.display = 'none'; },
946
+ hideFooter() { chatgpt.footer.hide(); },
947
+ hideHeader() { chatgpt.header.hide(); },
925
948
 
926
949
  history: {
927
- isLoaded() {
928
- return new Promise(resolve => {
950
+ async isLoaded(timeout = null) {
951
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
952
+ const isLoadedPromise = new Promise(resolve => {
929
953
  if (document.querySelector('nav')) resolve(true);
930
954
  else new MutationObserver((_, obs) => {
931
955
  if (document.querySelector('nav')) { obs.disconnect(); resolve(true); }
932
956
  }).observe(document.body, { childList: true, subtree: true });
933
957
  });
958
+ return await ( timeoutPromise ? Promise.race([isLoadedPromise, timeoutPromise]) : isLoadedPromise );
934
959
  }
935
960
  },
936
961
 
@@ -1062,22 +1087,43 @@ const chatgpt = { // eslint-disable-line no-redeclare
1062
1087
  isDarkMode() { return document.documentElement.classList.toString().includes('dark'); },
1063
1088
  isFullScreen() { return chatgpt.browser.isFullScreen(); },
1064
1089
 
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
- });
1090
+ async isIdle(timeout = null) {
1091
+ const obsConfig = { childList: true, subtree: true },
1092
+ msgDivSelector = 'div[data-message-author-role]';
1093
+
1094
+ // Create promises
1095
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
1096
+ const isIdlePromise = (async () => {
1097
+ await new Promise(resolve => { // when on convo page
1098
+ if (document.querySelector(msgDivSelector)) resolve();
1099
+ else new MutationObserver((_, obs) => {
1100
+ if (document.querySelector(msgDivSelector)) { obs.disconnect(); resolve(); }
1101
+ }).observe(document.body, obsConfig);
1102
+ });
1103
+ await new Promise(resolve => { // when reply starts generating
1104
+ new MutationObserver((_, obs) => {
1105
+ if (chatgpt.getStopBtn()) { obs.disconnect(); resolve(); }
1106
+ }).observe(document.body, obsConfig);
1107
+ });
1108
+ return new Promise(resolve => { // when reply stops generating
1109
+ new MutationObserver((_, obs) => {
1110
+ if (!chatgpt.getStopBtn()) { obs.disconnect(); resolve(true); }
1111
+ }).observe(document.body, obsConfig);
1112
+ });
1113
+ })();
1114
+
1115
+ return await (timeoutPromise ? Promise.race([isIdlePromise, timeoutPromise]) : isIdlePromise);
1072
1116
  },
1073
1117
 
1074
- isLoaded() {
1075
- return new Promise(resolve => {
1118
+ async isLoaded(timeout = null) {
1119
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
1120
+ const isLoadedPromise = new Promise(resolve => {
1076
1121
  if (chatgpt.getNewChatBtn()) resolve(true);
1077
1122
  else new MutationObserver((_, obs) => {
1078
1123
  if (chatgpt.getNewChatBtn()) { obs.disconnect(); resolve(true); }
1079
1124
  }).observe(document.body, { childList: true, subtree: true });
1080
1125
  });
1126
+ return await ( timeoutPromise ? Promise.race([isLoadedPromise, timeoutPromise]) : isLoadedPromise );
1081
1127
  },
1082
1128
 
1083
1129
  isLightMode() { return document.documentElement.classList.toString().includes('light'); },
@@ -1499,7 +1545,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1499
1545
  return console.error(`Argument ${ i + 1 } must be a string!`);
1500
1546
  const textArea = chatgpt.getChatBox();
1501
1547
  if (!textArea) return console.error('Chatbar element not found!');
1502
- textArea.value = msg;
1548
+ const msgP = document.createElement('p'); msgP.textContent = msg;
1549
+ textArea.replaceChild(msgP, textArea.querySelector('p'));
1503
1550
  textArea.dispatchEvent(new Event('input', { bubbles: true })); // enable send button
1504
1551
  setTimeout(function delaySend() {
1505
1552
  const sendBtn = chatgpt.getSendButton();
@@ -1512,10 +1559,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1512
1559
 
1513
1560
  sendInNewChat(msg) {
1514
1561
  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);
1562
+ try { chatgpt.getNewChatBtn().click(); } catch (err) { return console.error(err.message); }
1563
+ setTimeout(() => { chatgpt.send(msg); }, 500);
1519
1564
  },
1520
1565
 
1521
1566
  settings: {
@@ -1639,14 +1684,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1639
1684
  });});});});});
1640
1685
  },
1641
1686
 
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'; },
1687
+ showFooter() { chatgpt.footer.show(); },
1688
+ showHeader() { chatgpt.header.show(); },
1650
1689
 
1651
1690
  sidebar: {
1652
1691
  elements: [], observer: {},
@@ -1759,13 +1798,15 @@ const chatgpt = { // eslint-disable-line no-redeclare
1759
1798
  return newElement.id; // Return the element id
1760
1799
  },
1761
1800
 
1801
+ exists() { return !!chatgpt.getNewChatLink(); },
1762
1802
  hide() { this.isOn() ? this.toggle() : console.info('Sidebar already hidden!'); },
1763
1803
  show() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!'); },
1764
1804
  isOff() { return !this.isOn(); },
1765
1805
  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() ?
1806
+ const sidebar = (() => {
1807
+ return chatgpt.sidebar.exists() ? document.querySelector('body script + div > div') : null; })();
1808
+ if (!sidebar) { console.error('Sidebar element not found!'); return false; }
1809
+ else return chatgpt.browser.isMobile() ?
1769
1810
  document.documentElement.style.overflow == 'hidden'
1770
1811
  : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px';
1771
1812
  },
@@ -1777,19 +1818,19 @@ const chatgpt = { // eslint-disable-line no-redeclare
1777
1818
  : btn => btn.querySelector('svg path[d^="M8.857"]');
1778
1819
  for (const btn of document.querySelectorAll(navBtnSelector))
1779
1820
  if (isToggleBtn(btn)) { btn.click(); return; }
1821
+ console.error('Sidebar toggle not found!');
1780
1822
  },
1781
1823
 
1782
- async isLoaded() {
1824
+ async isLoaded(timeout = 5000) {
1783
1825
  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
- ]);
1826
+ const timeoutPromise = new Promise(resolve => setTimeout(() => { resolve(false); }, timeout));
1827
+ const isLoadedPromise = new Promise(resolve => {
1828
+ if (chatgpt.getNewChatLink()) resolve(true);
1829
+ else new MutationObserver((_, obs) => {
1830
+ if (chatgpt.getNewChatLink()) { obs.disconnect(); resolve(true); }
1831
+ }).observe(document.body, { childList: true, subtree: true });
1832
+ });
1833
+ return await Promise.race([isLoadedPromise, timeoutPromise]);
1793
1834
  }
1794
1835
  },
1795
1836
 
@@ -1902,6 +1943,7 @@ const cjsFuncAliases = [
1902
1943
  ['deactivateAutoRefresh', 'deactivateAutoRefresher', 'deactivateRefresher', 'deactivateSessionRefresher'],
1903
1944
  ['detectLanguage', 'getLanguage'],
1904
1945
  ['executeCode', 'codeExecute'],
1946
+ ['exists', 'isAvailable', 'isExistent', 'isPresent'],
1905
1947
  ['exportChat', 'chatExport', 'export'],
1906
1948
  ['getFooterDiv', 'getFooter'],
1907
1949
  ['getHeaderDiv', 'getHeader'],
@@ -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.12",
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.12
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.0/starters/greasemonkey/media/images/icons/robot/icon48.png
11
+ // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.3.0/starters/greasemonkey/media/images/icons/robot/icon64.png
12
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.3.0/dist/chatgpt.min.js
13
13
  // @grant GM_getValue
14
14
  // @grant GM_setValue
15
15
  // @noframes