@kudoai/chatgpt.js 3.2.0 → 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,32 +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() {
414
- await new Promise(resolve => { // when in conversation page
415
- (function checkConvoPage() {
416
- document.querySelector('div[data-message-author-role]') ? resolve(true)
417
- : setTimeout(checkConvoPage, 200); })();
418
- });
419
- await new Promise(resolve => { // when reply starts generating
420
- (function checkReplyExists() {
421
- const msgDivs = document.querySelectorAll('div[data-message-author-role]');
422
- msgDivs[msgDivs.length - 1]?.dataset.messageAuthorRole == 'assistant' ? resolve(true)
423
- : setTimeout(checkReplyExists, 200); })();
424
- });
425
- const lastReplyDiv = await new Promise(resolve => { // when code starts generating
426
- (function checkPreExists() {
427
- const replyDivs = document.querySelectorAll('div[data-message-author-role="assistant"]'),
428
- lastReplyDiv = replyDivs[replyDivs.length - 1];
429
- lastReplyDiv?.querySelector('pre') ? resolve(lastReplyDiv)
430
- : setTimeout(checkPreExists, 200); })();
431
- });
432
- return Promise.race([
433
- new Promise(resolve => { // when code block not last child of reply div
434
- (function checkPreNotLast() {
435
- lastReplyDiv?.querySelector('pre').nextElementSibling ? resolve(true)
436
- : setTimeout(checkPreNotLast, 200); })();
437
- }), chatgpt.isIdle() // ...or reply stopped generating
438
- ]);
413
+ async isIdle(timeout = null) {
414
+ const obsConfig = { childList: true, subtree: true },
415
+ selectors = { msgDiv: 'div[data-message-author-role]',
416
+ replyDiv: 'div[data-message-author-role="assistant"]' };
417
+
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);
439
449
  },
440
450
 
441
451
  async minify(code) {
@@ -610,6 +620,24 @@ const chatgpt = { // eslint-disable-line no-redeclare
610
620
  extractCode() { chatgpt.code.extract(); },
611
621
  focusChatbar() { chatgpt.getChatBox()?.focus(); },
612
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
+
613
641
  generateRandomIP() {
614
642
  const ip = Array.from({length: 4}, () => Math.floor(chatgpt.randomFloat() * 256)).join('.');
615
643
  console.info('IP generated: ' + ip);
@@ -862,16 +890,14 @@ const chatgpt = { // eslint-disable-line no-redeclare
862
890
  return formBtnSVG.parentNode.parentNode;
863
891
  }},
864
892
 
865
- getFooterDiv() { return document.querySelector('main form')?.parentNode.parentNode.nextElementSibling; },
866
- getHeaderDiv() { return document.querySelector('main .sticky'); },
893
+ getFooterDiv() { return chatgpt.footer.get(); },
894
+ getHeaderDiv() { return chatgpt.header.get(); },
867
895
  getLastPrompt() { return chatgpt.getChatData('active', 'msg', 'user', 'latest'); },
868
896
  getLastResponse() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
869
897
 
870
898
  getNewChatButton() {
871
- for (const navBtnSVG of document.querySelectorAll('nav button svg'))
872
- if (navBtnSVG.querySelector('path[d^="M15.6729"], ' // pencil-on-pad icon
873
- + 'path[d^="M3.06957"]')) // refresh icon if temp chat
874
- 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
875
901
  },
876
902
 
877
903
  getNewChatLink() { return document.querySelector('nav a[href="/"]'); },
@@ -908,18 +934,29 @@ const chatgpt = { // eslint-disable-line no-redeclare
908
934
 
909
935
  getUserLanguage() {
910
936
  return navigator.languages[0] || navigator.language || navigator.browserLanguage ||
911
- navigator.systemLanguage || navigator.userLanguage || ''; },
937
+ navigator.systemLanguage || navigator.userLanguage || '';
938
+ },
912
939
 
913
- hideFooter() { chatgpt.getFooterDiv().style.display = 'none'; },
914
- hideHeader() { chatgpt.getHeaderDiv().style.display = 'none'; },
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'; }
944
+ },
945
+
946
+ hideFooter() { chatgpt.footer.hide(); },
947
+ hideHeader() { chatgpt.header.hide(); },
915
948
 
916
949
  history: {
917
- isLoaded() {
918
- return new Promise(resolve => {
919
- (function checkChatHistory() {
920
- document.querySelector('nav') ? resolve(true) : setTimeout(checkChatHistory, 200);
921
- })();
922
- });}
950
+ async isLoaded(timeout = null) {
951
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
952
+ const isLoadedPromise = new Promise(resolve => {
953
+ if (document.querySelector('nav')) resolve(true);
954
+ else new MutationObserver((_, obs) => {
955
+ if (document.querySelector('nav')) { obs.disconnect(); resolve(true); }
956
+ }).observe(document.body, { childList: true, subtree: true });
957
+ });
958
+ return await ( timeoutPromise ? Promise.race([isLoadedPromise, timeoutPromise]) : isLoadedPromise );
959
+ }
923
960
  },
924
961
 
925
962
  instructions: {
@@ -1050,19 +1087,44 @@ const chatgpt = { // eslint-disable-line no-redeclare
1050
1087
  isDarkMode() { return document.documentElement.classList.toString().includes('dark'); },
1051
1088
  isFullScreen() { return chatgpt.browser.isFullScreen(); },
1052
1089
 
1053
- isIdle() {
1054
- return new Promise(resolve => {
1055
- (function checkIsIdle() {
1056
- chatgpt.getRegenerateButton() ? resolve(true) : setTimeout(checkIsIdle, 200);
1057
- })();
1058
- });},
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
+ })();
1059
1114
 
1060
- isLoaded() {
1061
- return new Promise(resolve => {
1062
- (function checkIsLoaded() {
1063
- chatgpt.getNewChatButton() ? resolve(true) : setTimeout(checkIsLoaded, 200);
1064
- })();
1065
- });},
1115
+ return await (timeoutPromise ? Promise.race([isIdlePromise, timeoutPromise]) : isIdlePromise);
1116
+ },
1117
+
1118
+ async isLoaded(timeout = null) {
1119
+ const timeoutPromise = timeout ? new Promise(resolve => setTimeout(() => resolve(false), timeout)) : null;
1120
+ const isLoadedPromise = new Promise(resolve => {
1121
+ if (chatgpt.getNewChatBtn()) resolve(true);
1122
+ else new MutationObserver((_, obs) => {
1123
+ if (chatgpt.getNewChatBtn()) { obs.disconnect(); resolve(true); }
1124
+ }).observe(document.body, { childList: true, subtree: true });
1125
+ });
1126
+ return await ( timeoutPromise ? Promise.race([isLoadedPromise, timeoutPromise]) : isLoadedPromise );
1127
+ },
1066
1128
 
1067
1129
  isLightMode() { return document.documentElement.classList.toString().includes('light'); },
1068
1130
 
@@ -1483,7 +1545,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1483
1545
  return console.error(`Argument ${ i + 1 } must be a string!`);
1484
1546
  const textArea = chatgpt.getChatBox();
1485
1547
  if (!textArea) return console.error('Chatbar element not found!');
1486
- textArea.value = msg;
1548
+ const msgP = document.createElement('p'); msgP.textContent = msg;
1549
+ textArea.replaceChild(msgP, textArea.querySelector('p'));
1487
1550
  textArea.dispatchEvent(new Event('input', { bubbles: true })); // enable send button
1488
1551
  setTimeout(function delaySend() {
1489
1552
  const sendBtn = chatgpt.getSendButton();
@@ -1496,10 +1559,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1496
1559
 
1497
1560
  sendInNewChat(msg) {
1498
1561
  if (typeof msg !== 'string') return console.error('Message must be a string!');
1499
- for (const navLink of document.querySelectorAll('nav a')) {
1500
- if (/(new|clear) chat/i.test(navLink.text)) {
1501
- navLink.click(); break;
1502
- }} setTimeout(() => { chatgpt.send(msg); }, 500);
1562
+ try { chatgpt.getNewChatBtn().click(); } catch (err) { return console.error(err.message); }
1563
+ setTimeout(() => { chatgpt.send(msg); }, 500);
1503
1564
  },
1504
1565
 
1505
1566
  settings: {
@@ -1623,8 +1684,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
1623
1684
  });});});});});
1624
1685
  },
1625
1686
 
1626
- showFooter() { chatgpt.getFooterDiv().style.display = 'revert'; },
1627
- showHeader() { chatgpt.getHeaderDiv().style.display = 'flex'; },
1687
+ showFooter() { chatgpt.footer.show(); },
1688
+ showHeader() { chatgpt.header.show(); },
1628
1689
 
1629
1690
  sidebar: {
1630
1691
  elements: [], observer: {},
@@ -1737,13 +1798,15 @@ const chatgpt = { // eslint-disable-line no-redeclare
1737
1798
  return newElement.id; // Return the element id
1738
1799
  },
1739
1800
 
1801
+ exists() { return !!chatgpt.getNewChatLink(); },
1740
1802
  hide() { this.isOn() ? this.toggle() : console.info('Sidebar already hidden!'); },
1741
1803
  show() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!'); },
1742
1804
  isOff() { return !this.isOn(); },
1743
1805
  isOn() {
1744
- const sidebar = document.querySelector('body script + div > div');
1745
- if (!sidebar) return console.error('Sidebar element not found!');
1746
- 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() ?
1747
1810
  document.documentElement.style.overflow == 'hidden'
1748
1811
  : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px';
1749
1812
  },
@@ -1755,18 +1818,19 @@ const chatgpt = { // eslint-disable-line no-redeclare
1755
1818
  : btn => btn.querySelector('svg path[d^="M8.857"]');
1756
1819
  for (const btn of document.querySelectorAll(navBtnSelector))
1757
1820
  if (isToggleBtn(btn)) { btn.click(); return; }
1821
+ console.error('Sidebar toggle not found!');
1758
1822
  },
1759
1823
 
1760
- async isLoaded() {
1824
+ async isLoaded(timeout = 5000) {
1761
1825
  await chatgpt.isLoaded();
1762
- return Promise.race([
1763
- new Promise(resolve => {
1764
- (function checkNewChatLink() {
1765
- chatgpt.getNewChatLink() ? resolve(true) : setTimeout(checkNewChatLink, 200);
1766
- })();
1767
- }),
1768
- new Promise(resolve => setTimeout(resolve, 5000)) // since New Chat link not always present
1769
- ]);
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]);
1770
1834
  }
1771
1835
  },
1772
1836
 
@@ -1879,6 +1943,7 @@ const cjsFuncAliases = [
1879
1943
  ['deactivateAutoRefresh', 'deactivateAutoRefresher', 'deactivateRefresher', 'deactivateSessionRefresher'],
1880
1944
  ['detectLanguage', 'getLanguage'],
1881
1945
  ['executeCode', 'codeExecute'],
1946
+ ['exists', 'isAvailable', 'isExistent', 'isPresent'],
1882
1947
  ['exportChat', 'chatExport', 'export'],
1883
1948
  ['getFooterDiv', 'getFooter'],
1884
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.8.29",
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.8.29.1
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.0/starters/greasemonkey/media/images/icons/robot/icon48.png
11
- // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.2.0/starters/greasemonkey/media/images/icons/robot/icon64.png
12
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.2.0/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