to it.
291 | const nav = document.querySelector("nav");
292 | nav.appendChild(aElement);
293 |
294 | // Listen to messages from the background script.
295 | browser.runtime.onMessage.addListener((request) => {
296 | switch(request.type) {
297 | case "download":
298 | download(false);
299 | break;
300 | case "copy":
301 | download(true);
302 | break;
303 | }
304 | });
305 | }, 1000);
306 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "ChatGPT ConvDown",
4 | "description": "Downloads the current thread from your conversation with ChatGPT as plain text.",
5 | "version": "7.2",
6 | "homepage_url": "https://github.com/esteinmann/chatgpt-convdown",
7 |
8 | "background": {
9 | "scripts": ["background.js"]
10 | },
11 | "web_accessible_resources": [
12 | "media/*"
13 | ],
14 | "options_ui": {
15 | "page": "options.html"
16 | },
17 | "permissions": [
18 | "clipboardWrite",
19 | "storage",
20 | "webNavigation",
21 | "*://chat.openai.com/chat/*",
22 | "*://chatgpt.com/**"
23 | ],
24 | "browser_specific_settings": {
25 | "gecko": {
26 | "id": "{6d166753-6d4d-42aa-b190-5bdddde63688}"
27 | }
28 | },
29 | "commands": {
30 | "download": {
31 | "description": "Downloads the conversation",
32 | "suggested_key": {
33 | "default": "Ctrl+Alt+S"
34 | }
35 | },
36 | "copy": {
37 | "description": "Copy the conversation to clipboard",
38 | "suggested_key": {
39 | "default": "Ctrl+Alt+C"
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/media/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esteinmann/chatgpt-convdown/ad4ff4335b4569c0c0010ed5837c85672f080b68/src/media/download.png
--------------------------------------------------------------------------------
/src/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/options.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2023 Erik Steinmann
3 | *
4 | * SPDX-License-Identifier: GPL-3.0-or-later
5 | */
6 |
7 | // Add shim to make chrome supported when browser is used
8 | var isChrome = false;
9 | if (typeof browser === "undefined") {
10 | isChrome = true;
11 | browser = chrome;
12 | }
13 |
14 | function saveOptions(e) {
15 | e.preventDefault();
16 | const formData = new FormData(document.querySelector("form"));
17 | browser.storage.local.set({
18 | iconType: formData.get("iconType")
19 | });
20 | }
21 |
22 | function restoreOptions() {
23 | function setCurrentChoice(result) {
24 | if (result.iconType) {
25 | // Check radio button from iconType value.
26 | document.querySelector("#radio_" + result.iconType).checked = true;
27 | } else {
28 | // Check first radio button.
29 | document.querySelector("#radio_green").checked = true;
30 | }
31 | }
32 |
33 | function onError(error) {
34 | console.log(`Error: ${error}`);
35 | }
36 |
37 | if (isChrome) {
38 | // Chrome (probably) pass callback to get().
39 | browser.storage.local.get("iconType", setCurrentChoice);
40 | } else {
41 | // On Firefox (probably) handle promise.
42 | browser.storage.local.get("iconType").then(setCurrentChoice, onError);
43 | }
44 | }
45 |
46 | document.addEventListener("DOMContentLoaded", restoreOptions);
47 | document.querySelector("form").addEventListener("submit", saveOptions);
--------------------------------------------------------------------------------