@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.
- package/README.md +29 -21
- package/chatgpt.js +149 -94
- package/dist/chatgpt.min.js +3 -3
- package/docs/README.md +29 -21
- package/docs/SECURITY.md +1 -3
- package/docs/USERGUIDE.md +3 -3
- package/package.json +18 -11
- package/starters/chrome/docs/README.md +10 -8
- package/starters/chrome/extension/components/icons.js +31 -0
- package/starters/chrome/extension/components/modals.js +148 -0
- package/starters/chrome/extension/content.js +108 -47
- package/starters/chrome/extension/icons/faded/icon128.png +0 -0
- package/starters/chrome/extension/icons/faded/icon16.png +0 -0
- package/starters/chrome/extension/icons/faded/icon32.png +0 -0
- package/starters/chrome/extension/icons/faded/icon64.png +0 -0
- package/starters/chrome/extension/lib/chatgpt.js +149 -94
- package/starters/chrome/extension/lib/dom.js +35 -0
- package/starters/chrome/extension/lib/settings.js +30 -0
- package/starters/chrome/extension/manifest.json +22 -22
- package/starters/chrome/extension/popup/controller.js +140 -0
- package/starters/chrome/extension/popup/index.html +7 -44
- package/starters/chrome/extension/popup/style.css +33 -10
- package/starters/chrome/extension/service-worker.js +41 -0
- package/starters/greasemonkey/chatgpt.js-greasemonkey-starter.user.js +12 -12
- package/starters/greasemonkey/docs/README.md +2 -0
- package/starters/chrome/extension/background.js +0 -14
- package/starters/chrome/extension/lib/settings-utils.js +0 -24
- package/starters/chrome/extension/popup/popup.js +0 -92
- package/starters/chrome/media/images/icons/refresh/icon16.png +0 -0
- package/starters/chrome/media/images/icons/refresh/icon50.png +0 -0
- /package/starters/chrome/{media/images → images}/icons/question-mark/icon16.png +0 -0
- /package/starters/chrome/{media/images → images}/icons/question-mark/icon512.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/chatgpt-extension-in-list.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/developer-mode-toggle.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/developer-mode-toggle.psd +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/extension-loaded.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/load-unpacked-button.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/reload-extension-button.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/reload-page-button.png +0 -0
- /package/starters/chrome/{media/images → images}/screenshots/select-extension-folder.png +0 -0
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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="
|
|
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
|
-
|
|
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 ;
|
|
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,
|
|
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
|
|
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 .
|
|
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) } /*
|
|
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 ;
|
|
50
|
-
footer > .menu-icon { position: absolute ; bottom:
|
|
51
|
-
.chatgpt-js { position: absolute ; bottom:
|
|
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.
|
|
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
|
-
// @
|
|
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()
|
|
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 =>
|
|
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
|
})();
|
|
@@ -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
|
-
})();
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|