@kudoai/chatgpt.js 3.3.5 → 3.5.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.
Files changed (40) hide show
  1. package/README.md +29 -21
  2. package/chatgpt.js +149 -94
  3. package/dist/chatgpt.min.js +3 -3
  4. package/docs/README.md +29 -21
  5. package/docs/SECURITY.md +1 -3
  6. package/docs/USERGUIDE.md +3 -3
  7. package/package.json +18 -11
  8. package/starters/chrome/docs/README.md +10 -8
  9. package/starters/chrome/extension/components/icons.js +31 -0
  10. package/starters/chrome/extension/components/modals.js +148 -0
  11. package/starters/chrome/extension/content.js +108 -47
  12. package/starters/chrome/extension/icons/faded/icon128.png +0 -0
  13. package/starters/chrome/extension/icons/faded/icon16.png +0 -0
  14. package/starters/chrome/extension/icons/faded/icon32.png +0 -0
  15. package/starters/chrome/extension/icons/faded/icon64.png +0 -0
  16. package/starters/chrome/extension/lib/chatgpt.js +149 -94
  17. package/starters/chrome/extension/lib/dom.js +35 -0
  18. package/starters/chrome/extension/lib/settings.js +30 -0
  19. package/starters/chrome/extension/manifest.json +22 -22
  20. package/starters/chrome/extension/popup/controller.js +140 -0
  21. package/starters/chrome/extension/popup/index.html +7 -44
  22. package/starters/chrome/extension/popup/style.css +33 -10
  23. package/starters/chrome/extension/service-worker.js +41 -0
  24. package/starters/greasemonkey/chatgpt.js-greasemonkey-starter.user.js +12 -12
  25. package/starters/greasemonkey/docs/README.md +2 -0
  26. package/starters/chrome/extension/background.js +0 -14
  27. package/starters/chrome/extension/lib/settings-utils.js +0 -24
  28. package/starters/chrome/extension/popup/popup.js +0 -92
  29. package/starters/chrome/media/images/icons/refresh/icon16.png +0 -0
  30. package/starters/chrome/media/images/icons/refresh/icon50.png +0 -0
  31. /package/starters/chrome/{media/images → images}/icons/question-mark/icon16.png +0 -0
  32. /package/starters/chrome/{media/images → images}/icons/question-mark/icon512.png +0 -0
  33. /package/starters/chrome/{media/images → images}/screenshots/chatgpt-extension-in-list.png +0 -0
  34. /package/starters/chrome/{media/images → images}/screenshots/developer-mode-toggle.png +0 -0
  35. /package/starters/chrome/{media/images → images}/screenshots/developer-mode-toggle.psd +0 -0
  36. /package/starters/chrome/{media/images → images}/screenshots/extension-loaded.png +0 -0
  37. /package/starters/chrome/{media/images → images}/screenshots/load-unpacked-button.png +0 -0
  38. /package/starters/chrome/{media/images → images}/screenshots/reload-extension-button.png +0 -0
  39. /package/starters/chrome/{media/images → images}/screenshots/reload-page-button.png +0 -0
  40. /package/starters/chrome/{media/images → images}/screenshots/select-extension-folder.png +0 -0
@@ -1,24 +1,24 @@
1
1
  {
2
- "manifest_version": 3,
3
- "name": "ChatGPT Extension",
4
- "description": "A Chrome template to start using chatgpt.js like a boss!",
5
- "version": "2024.10.11",
6
- "author": "chatgpt.js",
7
- "icons": {
8
- "16": "icons/icon16.png",
9
- "32": "icons/icon32.png",
10
- "64": "icons/icon64.png",
11
- "128": "icons/icon128.png"
12
- },
13
- "permissions": [ "storage", "tabs" ],
14
- "action": { "default_popup": "popup/index.html" },
15
- "web_accessible_resources": [{
16
- "matches": ["<all_urls>"],
17
- "resources": ["lib/settings-utils.js", "lib/chatgpt.js"]
18
- }],
19
- "content_scripts": [{
20
- "matches": ["https://chatgpt.com/*", "https://chat.openai.com/*"],
21
- "js": ["content.js"]
22
- }],
23
- "background": { "service_worker": "background.js" }
2
+ "manifest_version": 3,
3
+ "name": "ChatGPT Extension",
4
+ "short_name": "ChatGPT 🧩",
5
+ "description": "A Chromium extension template to start using chatgpt.js like a boss!",
6
+ "version": "2024.12.29",
7
+ "author": "KudoAI",
8
+ "homepage_url": "https://github.com/KudoAI/chatgpt.js-chrome-starter",
9
+ "icons": {
10
+ "16": "icons/icon16.png",
11
+ "32": "icons/icon32.png",
12
+ "64": "icons/icon64.png",
13
+ "128": "icons/icon128.png"
14
+ },
15
+ "permissions": [ "activeTab", "storage" ],
16
+ "action": { "default_popup": "popup/index.html" },
17
+ "web_accessible_resources": [{
18
+ "matches": [ "<all_urls>" ],
19
+ "resources": [ "components/modals.js", "lib/chatgpt.js", "lib/dom.js", "lib/settings.js" ]
20
+ }],
21
+ "content_scripts": [{ "matches": [ "https://chatgpt.com/*" ], "js": [ "content.js" ] }],
22
+ "background": { "service_worker": "service-worker.js" },
23
+ "minimum_chrome_version": "88"
24
24
  }
@@ -0,0 +1,140 @@
1
+ (async () => {
2
+
3
+ // Import JS resources
4
+ for (const resource of ['components/icons.js', 'lib/dom.js', 'lib/settings.js'])
5
+ await import(chrome.runtime.getURL(resource))
6
+
7
+ // Init ENV context
8
+ const env = { site: /([^.]+)\.[^.]+$/.exec(new URL((await chrome.tabs.query(
9
+ { active: true, currentWindow: true }))[0].url).hostname)?.[1] }
10
+
11
+ // Import APP data
12
+ const { app } = await chrome.storage.sync.get('app')
13
+ icons.imports.import({ app }) // for src's using app.urls.assetHost
14
+
15
+ // Define FUNCTIONS
16
+
17
+ async function sendMsgToActiveTab(action, options) {
18
+ const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true })
19
+ return await chrome.tabs.sendMessage(activeTab.id, { action: action, options: { ...options }})
20
+ }
21
+
22
+ function notify(msg, pos = 'bottom-right') { sendMsgToActiveTab('notify', { msg, pos }) }
23
+
24
+ const sync = {
25
+ fade() {
26
+
27
+ // Update toolbar icon
28
+ const iconDimensions = [16, 32, 64, 128], iconPaths = {}
29
+ iconDimensions.forEach(dimension => iconPaths[dimension] = `../icons/${
30
+ config.extensionDisabled ? 'faded/' : '' }icon${dimension}.png` )
31
+ chrome.action.setIcon({ path: iconPaths })
32
+
33
+ // Update menu contents
34
+ document.querySelectorAll('div.logo, div.menu-title, div.menu')
35
+ .forEach(elem => {
36
+ elem.classList.remove(masterToggle.checked ? 'disabled' : 'enabled')
37
+ elem.classList.add(masterToggle.checked ? 'enabled' : 'disabled')
38
+ })
39
+ },
40
+
41
+ configToUI(options) { return sendMsgToActiveTab('syncConfigToUI', options) }
42
+ }
43
+
44
+ // Run MAIN routine
45
+
46
+ // Init MASTER TOGGLE
47
+ const masterToggle = document.querySelector('input')
48
+ await settings.load('extensionDisabled')
49
+ masterToggle.checked = !config.extensionDisabled ; sync.fade()
50
+ masterToggle.onchange = () => {
51
+ settings.save('extensionDisabled', !config.extensionDisabled)
52
+ Object.keys(sync).forEach(key => sync[key]()) // sync fade + storage to UI
53
+ notify(`${chrome.runtime.getManifest().name} ${ this.checked ? 'ON' : 'OFF' }`)
54
+ }
55
+
56
+ // Create CHILD menu entries on chatgpt.com
57
+ if (env.site == 'chatgpt') {
58
+ await settings.load(Object.keys(settings.controls))
59
+
60
+ // Create/insert child section
61
+ const togglesDiv = dom.create.elem('div', { class: 'menu' })
62
+ document.querySelector('.menu-header').insertAdjacentElement('afterend', togglesDiv)
63
+
64
+ // Create/insert child entries
65
+ Object.keys(settings.controls).forEach(key => {
66
+
67
+ // Init elems
68
+ const menuItemDiv = dom.create.elem('div', {
69
+ class: 'menu-item menu-area', title: settings.controls[key].helptip || '' })
70
+ const menuLabel = dom.create.elem('label', { class: 'menu-icon' })
71
+ const menuLabelSpan = dom.create.elem('span')
72
+ let menuInput, menuSlider
73
+ menuLabelSpan.textContent = settings.controls[key].label
74
+ if (settings.controls[key].type == 'toggle') {
75
+ menuInput = dom.create.elem('input', { type: 'checkbox' })
76
+ menuInput.checked = /disabled|hidden/i.test(key) ^ config[key]
77
+ menuSlider = dom.create.elem('span', { class: 'slider' })
78
+ menuLabel.append(menuInput, menuSlider)
79
+ menuLabel.classList.add('toggle-switch')
80
+ } else if (settings.controls[key].type == 'prompt') {
81
+ menuLabel.innerText = settings.controls[key].symbol
82
+ menuLabel.classList.add('menu-prompt')
83
+ }
84
+
85
+ // Assemble/append elems
86
+ menuItemDiv.append(menuLabel, menuLabelSpan)
87
+ togglesDiv.append(menuItemDiv)
88
+
89
+ // Add listeners
90
+ if (settings.controls[key].type == 'toggle') {
91
+ menuItemDiv.onclick = () => menuInput.click()
92
+ menuInput.onclick = menuSlider.onclick = event => // prevent double toggle
93
+ event.stopImmediatePropagation()
94
+ menuInput.onchange = () => {
95
+ settings.save(key, !config[key]) ; sync.configToUI({ updatedKey: key })
96
+ notify(`${settings.controls[key].label} ${
97
+ /disabled|hidden/i.test(key) != config[key] ? 'ON' : 'OFF' }`)
98
+ }
99
+ } else if (settings.controls[key].type == 'prompt') {
100
+ // custom logic for each prompt based on key name
101
+ }
102
+ })
103
+
104
+ sync.fade() // in case master toggle off
105
+ }
106
+
107
+ // Create/append FOOTER container
108
+ const footer = dom.create.elem('footer') ; document.body.append(footer)
109
+
110
+ // Create/append CHATGPT.JS footer logo
111
+ const cjsDiv = dom.create.elem('div', { class: 'chatgpt-js' })
112
+ const cjsLogo = dom.create.elem('img', {
113
+ title: 'Powered by chatgpt.js',
114
+ src: `${app.urls.cjsMediaHost}/images/badges/powered-by-chatgpt.js-faded.png?b2a1975` })
115
+ cjsLogo.onmouseover = cjsLogo.onmouseout = event => cjsLogo.src = `${
116
+ app.urls.cjsMediaHost}/images/badges/powered-by-chatgpt.js${
117
+ event.type == 'mouseover' ? '' : '-faded' }.png?b2a1975`
118
+ cjsLogo.onclick = () => chrome.tabs.create({ url: app.urls.chatgptJS })
119
+ cjsDiv.append(cjsLogo) ; footer.append(cjsDiv)
120
+
121
+ // Create/append ABOUT footer button
122
+ const aboutSpan = dom.create.elem('span', {
123
+ title: 'About ChatGPT Extension',
124
+ class: 'menu-icon menu-area', style: 'right:30px ; padding-top: 2px' })
125
+ const aboutIcon = icons.create({ name: 'questionMark', width: 15, height: 13, style: 'margin-bottom: 0.04rem' })
126
+ aboutSpan.onclick = () => { chrome.runtime.sendMessage({ action: 'showAbout' }) ; close() }
127
+ aboutSpan.append(aboutIcon) ; footer.append(aboutSpan)
128
+
129
+ // Create/append RELATED EXTENSIONS footer button
130
+ const moreExtensionsSpan = dom.create.elem('span', {
131
+ title: 'More AI Extensions',
132
+ class: 'menu-icon menu-area', style: 'right:2px ; padding-top: 2px' })
133
+ const moreExtensionsIcon = icons.create({ name: 'plus', size: 16 })
134
+ moreExtensionsSpan.onclick = () => { chrome.tabs.create({ url: app.urls.relatedExtensions }) ; close() }
135
+ moreExtensionsSpan.append(moreExtensionsIcon) ; footer.append(moreExtensionsSpan)
136
+
137
+ // Remove loading spinner
138
+ document.querySelectorAll('[class^=loading]').forEach(elem => elem.remove())
139
+
140
+ })()
@@ -1,9 +1,13 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html lang="en">
3
3
  <head>
4
- <link href="/popup/style.css" rel="stylesheet">
4
+ <link href="style.css" rel="stylesheet">
5
+ <meta charset="UTF-8">
5
6
  </head>
6
7
  <body>
8
+ <div class="loading-bg">
9
+ <span class="loading-spinner"></span>
10
+ </div>
7
11
  <div class="menu-header">
8
12
  <div class="logo">
9
13
  <img width=26 src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@f0cdfc9/starters/chrome/extension/icons/icon32.png">
@@ -16,47 +20,6 @@
16
20
  </label>
17
21
  </div>
18
22
  </div>
19
- <!-- Sub-menu items
20
- <div class="menu">
21
- <div class="menu-item menu-area">
22
- <label class="toggle-switch menu-icon">
23
- <input type="checkbox">
24
- <span class="slider"></span>
25
- </label>
26
- <span >Toggle Label 1</span>
27
- </div>
28
- <div class="menu-item menu-area">
29
- <label class="toggle-switch menu-icon">
30
- <input type="checkbox">
31
- <span class="slider"></span>
32
- </label>
33
- <span >Toggle Label 2</span>
34
- </div>
35
- <div class="menu-item menu-area">
36
- <label class="toggle-switch menu-icon">
37
- <input type="checkbox">
38
- <span class="slider"></span>
39
- </label>
40
- <span >Toggle Label 3</span>
41
- </div>
42
- </div>
43
- -->
44
- <footer>
45
- <div class="chatgpt-js"><a title="Powered by chatgpt.js" href="https://chatgpt.js.org" target="_blank" rel="noopener"><img src="https://media.chatgptjs.org/images/badges/powered-by-chatgpt.js-faded.png?main"></a></div>
46
- <span title="Check for Updates" class="menu-icon menu-area" style="right:58px ; padding-top: 7px" >
47
- <img width=15 height=15 src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@258bec1/starters/chrome/media/images/icons/refresh/icon16.png" style="margin-top: 0.04rem">
48
- </span>
49
- <span title="Support" class="menu-icon menu-area" style="right:30px ; padding-top: 9px " >
50
- <a title="Support" href="https://github.com/KudoAI/chatgpt.js-chrome-starter/issues" target="_blank" rel="noopener">
51
- <img width=15 height=13 src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@258bec1/starters/chrome/media/images/icons/question-mark/icon16.png" style="margin-bottom: 0.04rem">
52
- </a>
53
- </span>
54
- <span title="More ChatGPT add-ons" class="menu-icon menu-area" style="right:2px ; padding-top: 7px " >
55
- <a title="More ChatGPT add-ons" href="https://github.com/adamlui/chatgpt-userscripts" target="_blank" rel="noopener">
56
- <svg width=16 height=16 viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M899.901 600.38H600.728v299.173c0 74.383-179.503 74.383-179.503 0V600.38H122.051c-74.384 0-74.384-179.503 0-179.503h299.173V121.703c0-74.384 179.503-74.384 179.503 0v299.174H899.9c74.385 0 74.385 179.503.001 179.503z"/></svg>
57
- </a>
58
- </span>
59
- </footer>
60
- <script src="popup.js"></script>
23
+ <script src="controller.js"></script>
61
24
  </body>
62
25
  </html>
@@ -1,20 +1,44 @@
1
1
  /* General size */
2
- html { height: fit-content }
3
- body { width: max-content ; height: 85px !important ; margin: 0 }
2
+ html { height: fit-content ; min-height: 50px }
3
+ body { width: max-content ; margin: 0 ; overflow: clip }
4
4
 
5
5
  /* General font */
6
6
  body, button, input, select, textarea {
7
- font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;
7
+ font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
8
+ "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;
8
9
  font-size: .905rem ; user-select: none
9
10
  }
10
11
  a { color: #999 ; text-decoration: none }
11
12
  a:focus, a:hover { text-decoration: underline ; color: inherit }
12
13
 
14
+ /* Loader */
15
+ .loading-bg {
16
+ background-color: white ; width: 100% ; height: 100% ; position: absolute ; z-index: 1111 ;
17
+ display: inline-grid ; align-content: center ; justify-content: center /* center spinner */
18
+ }
19
+ .loading-spinner {
20
+ width: 11px ; aspect-ratio: 1 ; border-radius: 50% ; border: 5px solid #000 ;
21
+ animation: loader-move-head-tail 0.8s infinite linear alternate, loader-rotate 1.6s infinite linear
22
+ }
23
+ @keyframes loader-move-head-tail {
24
+ 0% { clip-path: polygon(50% 50%, 0 0, 50% 0, 50% 0, 50% 0, 50% 0, 50% 0) }
25
+ 12.5% { clip-path: polygon(50% 50%, 0 0, 50% 0, 100% 0, 100% 0, 100% 0, 100% 0) }
26
+ 25% { clip-path: polygon(50% 50%, 0 0, 50% 0, 100% 0, 100% 100%, 100% 100%, 100% 100%) }
27
+ 50% { clip-path: polygon(50% 50%, 0 0, 50% 0, 100% 0, 100% 100%, 50% 100%, 0 100%) }
28
+ 62.5% { clip-path: polygon(50% 50%, 100% 0, 100% 0%, 100% 0, 100% 100%, 50% 100%, 0 100%) }
29
+ 75% { clip-path: polygon(50% 50%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 50% 100%, 0 100%) }
30
+ 100% { clip-path: polygon(50% 50%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 0 100%) }
31
+ }
32
+ @keyframes loader-rotate {
33
+ 0% { transform: scaleY(1) rotate(0deg) } 49.99% { transform: scaleY(1) rotate(135deg) }
34
+ 50% { transform: scaleY(-1) rotate(0deg) } 100% { transform: scaleY(-1) rotate(-135deg) }
35
+ }
36
+
13
37
  /* Header */
14
38
  .menu-header {
15
39
  border-bottom: solid 1px lightgrey ; padding: 5px 5px 5px 0; margin: 0 ;
16
40
  display: flex; background: white ; align-items: center }
17
- .logo { margin: 4px 10px 4px 12px }
41
+ .logo { margin: 4px 8px 4px 12px ; position: relative ; top: 3px }
18
42
  .menu-title { font-size: 0.85rem ; font-weight: 600 ; padding-right: 3px }
19
43
  .menu-icons > .toggle-switch { transform: scale(1.1) } /* make master toggle bigger */
20
44
  .main-toggle { margin-left: auto ; display: flex }
@@ -27,8 +51,7 @@ a:focus, a:hover { text-decoration: underline ; color: inherit }
27
51
  .menu-icon { padding: 8px }
28
52
  .menu-area:focus, .menu-area:hover { /* add hover color/cursor */
29
53
  color: var(--bg) ; background: rgb(100, 149, 237) ; cursor: pointer }
30
- .menu-item:hover .toggle-switch .slider, .menu-item:hover span { filter: invert(1) } /* invert toggle switch + label */
31
- .menu-item:hover .menu-icon { filter: none } /* ...but not non-toggle icons */
54
+ .menu-item:hover span:not(.slider) { filter: invert(1) } /* invert setting labels on hover */
32
55
  .menu-item > label > .slider { transform: scale(0.95) ; top: 1px } /* make child toggles smaller */
33
56
  .menu-prompt { margin-left: 2px } /* align non-toggle items */
34
57
 
@@ -43,12 +66,12 @@ a:focus, a:hover { text-decoration: underline ; color: inherit }
43
66
  border: 1px solid black ; border-radius: 50% ; background-color: white ; content: ""
44
67
  }
45
68
  .toggle-switch input[type="checkbox"]:checked + .slider { background-color: black } /* color active slider */
46
- .toggle-switch input[type="checkbox"]:checked + .slider::before { transform: translateX(9px) } /* move knob right when toggled */
69
+ .toggle-switch input[type="checkbox"]:checked + .slider::before { transform: translateX(9px) } /* toggle knob right */
47
70
 
48
71
  /* Footer */
49
- footer { font-size: 12px ; text-align: center ; color: #999 ; background: #f5f5f5 ; height: 40px ; padding-top: 3px }
50
- footer > .menu-icon { position: absolute ; bottom: 4px ; opacity: 0.7 }
51
- .chatgpt-js { position: absolute ; bottom: 0.65rem ; left: 0.7rem }
72
+ footer { font-size: 12px ; text-align: center ; color: #999 ; background: #f5f5f5 ; height: 40px ; line-height: 40px }
73
+ footer > .menu-icon { position: absolute ; bottom: -10px ; opacity: 0.7 }
74
+ .chatgpt-js { position: absolute ; bottom: -.25rem ; left: 0.7rem ; cursor: pointer }
52
75
 
53
76
  /* Master toggle effects */
54
77
  .disabled { opacity: 0.3 ; pointer-events: none }
@@ -0,0 +1,41 @@
1
+ // Init APP data
2
+ const app = {
3
+ version: chrome.runtime.getManifest().version, symbol: '🤖', cssPrefix: 'chatgpt-extension',
4
+ author: { name: 'KudoAI', url: 'https://kudoai.com' },
5
+ urls: {
6
+ assetHost: 'https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js-chrome-starter',
7
+ chatgptJS: 'https://chatgptjs.org',
8
+ cjsMediaHost: 'https://media.chatgptjs.org',
9
+ contributors: 'https://docs.chatgptjs.org/#-contributors',
10
+ gitHub: 'https://github.com/KudoAI/chatgpt.js-chrome-starter',
11
+ relatedExtensions: 'https://aiwebextensions.com',
12
+ support: 'https://github.com/KudoAI/chatgpt.js-chrome-starter/issues'
13
+ }
14
+ }
15
+ chrome.storage.sync.set({ app }) // save to Chrome storage
16
+
17
+ // Launch CHATGPT on install
18
+ chrome.runtime.onInstalled.addListener(details => {
19
+ if (details.reason == 'install')
20
+ chrome.tabs.create({ url: 'https://chatgpt.com/' })
21
+ })
22
+
23
+ // Sync SETTINGS to activated tabs
24
+ chrome.tabs.onActivated.addListener(activeInfo =>
25
+ chrome.tabs.sendMessage(activeInfo.tabId, { action: 'syncConfigToUI' }))
26
+
27
+ // Show ABOUT modal on ChatGPT when toolbar button clicked
28
+ chrome.runtime.onMessage.addListener(async req => {
29
+ if (req.action == 'showAbout') {
30
+ const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true })
31
+ const chatgptTab = new URL(activeTab.url).hostname == 'chatgpt.com' ? activeTab
32
+ : await chrome.tabs.create({ url: 'https://chatgpt.com/' })
33
+ if (activeTab != chatgptTab) await new Promise(resolve => // after new tab loads
34
+ chrome.tabs.onUpdated.addListener(async function statusListener(tabId, info) {
35
+ if (tabId == chatgptTab.id && info.status == 'complete') {
36
+ chrome.tabs.onUpdated.removeListener(statusListener)
37
+ setTimeout(resolve, 2500)
38
+ }}))
39
+ chrome.tabs.sendMessage(chatgptTab.id, { action: 'showAbout' })
40
+ }
41
+ })
@@ -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.10.11
6
+ // @version 2024.12.29
7
7
  // @license MIT
8
+ // @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.5.0/starters/greasemonkey/media/images/icons/robot/icon48.png
9
+ // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.5.0/starters/greasemonkey/media/images/icons/robot/icon64.png
8
10
  // @match *://chatgpt.com/*
9
11
  // @match *://chat.openai.com/*
10
- // @icon https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.3.5/starters/greasemonkey/media/images/icons/robot/icon48.png
11
- // @icon64 https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@3.3.5/starters/greasemonkey/media/images/icons/robot/icon64.png
12
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.3.5/dist/chatgpt.min.js
12
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.5.0/dist/chatgpt.min.js
13
13
  // @grant GM_getValue
14
14
  // @grant GM_setValue
15
15
  // @noframes
@@ -22,22 +22,22 @@
22
22
  (async () => {
23
23
 
24
24
  // Init config
25
- const config = { prefix: 'chatgptScript' }; loadSetting('skipAlert');
25
+ const config = { prefix: 'chatgptScript' } ; loadSetting('skipAlert')
26
26
 
27
27
  // Print chatgpt.js methods
28
- await chatgpt.isLoaded(); chatgpt.printAllFunctions(); // to console
28
+ await chatgpt.isLoaded() ; chatgpt.printAllFunctions() // to console
29
29
 
30
30
  // Show alert
31
- if (!config.skipAlert) {
31
+ if (!config.skipAlert)
32
32
  chatgpt.alert('≫ ChatGPT script loaded! 🚀', // title
33
33
  'Success! Press Ctrl+Shift+' // msg
34
34
  + ( navigator.userAgent.indexOf('Firefox') > -1 ? 'K' : 'J' )
35
35
  + ' to view all chatgpt.js functions.',
36
36
  function getHelp() { // button
37
- window.open('https://github.kudoai.com/chatgpt.js-greasemonkey-starter/issues', '_blank', 'noopener'); },
37
+ window.open('https://github.kudoai.com/chatgpt.js-greasemonkey-starter/issues', '_blank', 'noopener') },
38
38
  function dontShowAgain() { // checkbox
39
- saveSetting('skipAlert', !config.skipAlert); });
40
- }
39
+ saveSetting('skipAlert', !config.skipAlert) }
40
+ )
41
41
 
42
42
  // Your code here...
43
43
  // Your code here...
@@ -47,7 +47,7 @@
47
47
  // Your code here...
48
48
 
49
49
  // Define HELPER functions
50
- function loadSetting(...keys) { keys.forEach(key => { config[key] = GM_getValue(config.prefix + '_' + key, false); });}
51
- function saveSetting(key, value) { GM_setValue(config.prefix + '_' + key, value); config[key] = value; }
50
+ function loadSetting(...keys) { keys.forEach(key => config[key] = GM_getValue(config.prefix + '_' + key, false)) }
51
+ function saveSetting(key, value) { GM_setValue(config.prefix + '_' + key, value) ; config[key] = value }
52
52
 
53
53
  })();
@@ -5,3 +5,5 @@
5
5
  <br>
6
6
 
7
7
  <img src="../media/images/screenshots/chatgpt-userscript-on.png">
8
+
9
+ _For advanced Greasemonkey API methods, see: https://wiki.greasespot.net/Greasemonkey_Manual:API_
@@ -1,14 +0,0 @@
1
- const allowedHosts = ['chatgpt.com', 'chat.openai.com'];
2
-
3
- // Add install/update actions
4
- chrome.runtime.onInstalled.addListener((details) => {
5
- chrome.storage.local.set({ 'chatgptJS_extensionDisabled': false }); // auto-enable
6
- if (details.reason == 'install') chrome.tabs.create({ url: 'https://chatgpt.com/' }); // open ChatGPT
7
- });
8
-
9
- // Sync extension state/settings when ChatGPT tab active
10
- chrome.tabs.onActivated.addListener((activeInfo) => {
11
- chrome.tabs.get(activeInfo.tabId, (tab) => {
12
- if (allowedHosts.includes(new URL(tab.url).hostname)) {
13
- chrome.tabs.sendMessage(tab.id, { action: 'syncExtension' });
14
- }});});
@@ -1,24 +0,0 @@
1
- const config = {
2
- prefix: 'chatgptJS', appSymbol: '🤖', appName: 'ChatGPT Extension',
3
- ghRepoURL: 'https://github.kudoai.com/chatgpt.js-chrome-starter' };
4
-
5
- const settings = {
6
-
7
- load: function() {
8
- const keys = ( // original array if array, else new array from multiple args
9
- Array.isArray(arguments[0]) ? arguments[0] : Array.from(arguments));
10
- return Promise.all(keys.map((key) => { // resolve promise when all keys load
11
- return new Promise((resolve) => { // resolve promise when single key value loads
12
- chrome.storage.local.get(config.prefix + '_' + key, (result) => { // load from Chrome
13
- config[key] = result[config.prefix + '_' + key] || false; resolve();
14
- });});}));},
15
-
16
- save: function(key, value) {
17
- const obj = {} ; obj[config.prefix + '_' + key] = value;
18
- chrome.storage.local.set(obj); // save to Chrome
19
- config[key] = value; // save to memory
20
- }
21
-
22
- };
23
-
24
- export { config, settings };
@@ -1,92 +0,0 @@
1
- (async () => {
2
-
3
- // Import settings-utils.js
4
- const { config, settings } = await import(chrome.runtime.getURL('lib/settings-utils.js'));
5
-
6
- // Initialize popup toggles
7
- settings.load('extensionDisabled')
8
- .then(function() { // restore extension/toggle states
9
- masterToggle.checked = !config.extensionDisabled;
10
- updateGreyness();
11
- });
12
-
13
- // Add main toggle click-listener
14
- const toggles = document.querySelectorAll('input'),
15
- masterToggle = toggles[0];
16
- masterToggle.addEventListener('change', function() {
17
- settings.save('extensionDisabled', !this.checked);
18
- syncExtension() ; updateGreyness();
19
- notify(config.appName + ( this.checked ? ' ON' : ' OFF' ));
20
- });
21
-
22
- // Add update-check span click-listener
23
- const updateSpan = document.querySelector('span[title*="update" i]');
24
- updateSpan.addEventListener('click', () => {
25
- window.close(); // popup
26
- chrome.runtime.requestUpdateCheck((status, details) => {
27
- alertToUpdate(status === 'update_available' ? details.version : '');
28
- });});
29
-
30
- // Add Support span click-listener
31
- const supportLink = document.querySelector('a[title*="support" i]'),
32
- supportSpan = supportLink.parentNode;
33
- supportSpan.addEventListener('click', (event) => {
34
- if (event.target == supportSpan) supportLink.click(); // to avoid double-toggle
35
- });
36
-
37
- // Add More Add-ons span click-listener
38
- const moreAddOnsLink = document.querySelector('a[title*="more" i]'),
39
- moreAddOnsSpan = moreAddOnsLink.parentNode;
40
- moreAddOnsSpan.addEventListener('click', (event) => {
41
- if (event.target == moreAddOnsSpan) moreAddOnsLink.click(); // to avoid double-toggle
42
- });
43
-
44
- // Add Powered by chatgpt.js hover-listener
45
- const chatGPTjsHostPath = 'https://media.chatgptjs.org/images/badges/',
46
- chatGPTjsImg = document.querySelector('.chatgpt-js img');
47
- chatGPTjsImg.addEventListener('mouseover', () => {
48
- chatGPTjsImg.src = chatGPTjsHostPath + 'powered-by-chatgpt.js.png'; });
49
- chatGPTjsImg.addEventListener('mouseout', () => {
50
- chatGPTjsImg.src = chatGPTjsHostPath + 'powered-by-chatgpt.js-faded.png'; });
51
-
52
- // Define FEEDBACK functions
53
-
54
- function notify(msg, position) {
55
- chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
56
- chrome.tabs.sendMessage(tabs[0].id, {
57
- action: 'notify', msg: msg, position: position || 'bottom-right' });
58
- });}
59
-
60
- function alertToUpdate(version) {
61
- chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
62
- chrome.tabs.sendMessage(tabs[0].id, {
63
- action: 'alertToUpdate', args: version });
64
- });}
65
-
66
- // Define SYNC functions
67
-
68
- function syncExtension() {
69
- chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
70
- chrome.tabs.sendMessage(tabs[0].id, { action: 'syncExtension' });
71
- });}
72
-
73
- function updateGreyness() {
74
-
75
- // Updated toolbar icon
76
- const iconDimensions = [16, 32, 64, 128], iconPaths = {};
77
- iconDimensions.forEach((dimension) => {
78
- iconPaths[dimension] = '../icons/'
79
- + (config.extensionDisabled ? 'faded/' : '')
80
- + 'icon' + dimension + '.png';
81
- });
82
- chrome.action.setIcon({ path: iconPaths });
83
-
84
- // Update menu contents
85
- document.querySelectorAll('div.logo, div.menu-title, div.menu')
86
- .forEach((elem) => {
87
- elem.classList.remove(masterToggle.checked ? 'disabled' : 'enabled');
88
- elem.classList.add(masterToggle.checked ? 'enabled' : 'disabled');
89
- });
90
- }
91
-
92
- })();