@vacantthinker/firefox-addon-framework-easy 2026.5.2212 → 2026.524.1751

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.
@@ -0,0 +1,61 @@
1
+ import {tabOpCreate} from './opTab.js';
2
+ import {browserNotificationCreate} from './browserNotification.js';
3
+
4
+ export function browserRuntimeReload() {
5
+ browser.runtime.reload();
6
+ }
7
+
8
+ /**
9
+ *
10
+ * @param url{string}
11
+ */
12
+ export async function browserRuntimeSetUninstallURL(
13
+ url = 'https://addons.mozilla.org/en-US/firefox/user/17783213/',
14
+ ) {
15
+ await browser.runtime.setUninstallURL(url);
16
+ }
17
+
18
+ /**
19
+ *
20
+ * @param doWhat{function}
21
+ */
22
+ export function browserRuntimeOnUpdateAvailable(doWhat = null) {
23
+ browser.runtime.onUpdateAvailable.addListener(async (details) => {
24
+ if (doWhat) {
25
+ await doWhat(details);
26
+ }
27
+ else {
28
+ try {
29
+ let id = await browserNotificationCreate(
30
+ 'There is a new version!',
31
+ );
32
+ browser.notifications.onClicked.addListener(async (notificationId) => {
33
+ if (notificationId === id) {
34
+ await tabOpCreate('https://addons.mozilla.org/en-US/firefox/user/17783213/');
35
+ }
36
+ });
37
+ } catch (e) {
38
+ console.error(e);
39
+ }
40
+ }
41
+ });
42
+ }
43
+
44
+ /**
45
+ * @returns {browser._manifest.ExtensionID}
46
+ */
47
+ export function browserRuntimeGeckoId() {
48
+ return browser.runtime.getManifest().browser_specific_settings.gecko.id;
49
+ }
50
+
51
+ /**
52
+ *
53
+ * @returns {Promise<browser.runtime.PlatformInfo>}
54
+ */
55
+ export async function browserRuntimePlatformInfo() {
56
+ return await browser.runtime.getPlatformInfo();
57
+ }
58
+
59
+ export function browserRuntimeManifestVersion() {
60
+ return browser.runtime.getManifest().version;
61
+ }
@@ -0,0 +1,146 @@
1
+ import {stoOpGet, stoOpSet} from './opStorage.js';
2
+
3
+ /**
4
+ * this function can use when you use serviceUserSettings.js
5
+ *
6
+ *
7
+ * searchEngine: {
8
+ * optionType: 'checkbox',
9
+ * options: ['Searcher1', 'Searcher2'],
10
+ * selected: ['Searcher1', 'Searcher2'],
11
+ * queryTitle: {
12
+ * 'Searcher1': 'https://y2down.cc/',
13
+ * 'Searcher2': 'https://ssyou.online',
14
+ * },
15
+ * },
16
+ * videoQuality: {
17
+ * options: ['360', '480', '720', '1080', '1440', '2160'],
18
+ * selected: '720',
19
+ * },
20
+ * @param userSettings{{}}
21
+ * @param radioItemClickFn{function}
22
+ * @returns {HTMLFieldSetElement[]}
23
+ */
24
+ export function generateHtmlByUserSettings(
25
+ userSettings,
26
+ radioItemClickFn,
27
+ ) {
28
+
29
+ // todo generate html by data
30
+ return Object.keys(userSettings).map(
31
+ /**
32
+ *
33
+ * @param k{string}
34
+ * @returns {HTMLFieldSetElement}
35
+ */
36
+ (k) => {
37
+ /**
38
+ * @type{{optionType:'checkbox'|'radio',options:[string], selected: string, }}
39
+ */
40
+ let v = userSettings[k];
41
+
42
+ let optionType = v.optionType;
43
+ if (optionType === undefined) {
44
+ optionType = 'radio';
45
+ }
46
+
47
+ /**
48
+ *
49
+ * @type {string[]}
50
+ */
51
+ let options = v.options;
52
+ // /**
53
+ // *
54
+ // * @type {string}
55
+ // */
56
+ // let selected = v.selected;
57
+
58
+ let eleWrap = document.createElement('fieldset');
59
+
60
+ let eleTitle = document.createElement('legend');
61
+ eleTitle.textContent = k;
62
+ eleWrap.append(eleTitle);
63
+
64
+ // console.info(`optionType=${optionType} options=${options}`)
65
+ options.map(
66
+ /**
67
+ *
68
+ * @param option{string}
69
+ */
70
+ option => {
71
+
72
+ let eleLabel = document.createElement('label');
73
+ eleLabel.textContent = option;
74
+
75
+ let eleInput = document.createElement('input');
76
+ eleInput.name = k;
77
+ eleInput.type = optionType;
78
+ eleInput.value = option;
79
+
80
+ if (optionType === 'checkbox') {
81
+ stoOpGet(k).then(
82
+ /**
83
+ *
84
+ * @param v{string}
85
+ */
86
+ v => {
87
+ let strings = Array.from(v);
88
+ console.info(`strings=${strings} option=${option}`);
89
+ const set = new Set(strings);
90
+ eleInput.checked = set.has(option);
91
+
92
+ });
93
+ }
94
+ else if (optionType === 'radio') {
95
+ stoOpGet(k).then(
96
+ /**
97
+ *
98
+ * @param v{string}
99
+ */
100
+ v => {
101
+ if (option === v) {
102
+ eleInput.checked = true;
103
+ }
104
+ });
105
+ }
106
+
107
+ eleLabel.append(eleInput);
108
+
109
+ if (optionType === 'checkbox') {
110
+ eleInput.addEventListener('change', async () => {
111
+ let textCurrent = eleLabel.textContent;
112
+
113
+ let optionsCurrent = await stoOpGet(k);
114
+ console.info('optionsCurrent=', optionsCurrent);
115
+
116
+ let optionsArr = Array.from(optionsCurrent);
117
+ let set = new Set(optionsArr);
118
+ if (eleInput.checked) {
119
+ set.add(textCurrent);
120
+ }
121
+ else {
122
+ set.delete(textCurrent);
123
+ }
124
+
125
+ let valueNew = Array.from(set);
126
+ console.info(
127
+ `k=${k} text=${textCurrent} eleInput.checked=${eleInput.checked} valueNew=${valueNew}`);
128
+ await stoOpSet(k, valueNew);
129
+
130
+ });
131
+ }
132
+ else if (optionType === 'radio') {
133
+ eleLabel.onclick = function() {
134
+ stoOpSet(k, option).then(() => {
135
+ console.info(`k=${k} option=${option}`);
136
+ radioItemClickFn(k, option);
137
+ });
138
+ };
139
+ }
140
+ return eleLabel;
141
+
142
+ }).forEach(ele => eleWrap.append(ele));
143
+
144
+ return eleWrap;
145
+ });
146
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ *
3
+ * @param k{string}
4
+ * @returns {Promise<boolean>}
5
+ */
6
+ export async function stoOpCheck(k) {
7
+ try {
8
+ let key = k.toString();
9
+
10
+ let objGet = await browser.storage.local.get(key);
11
+ let b = objGet.hasOwnProperty(key);
12
+ console.info(`key=${key} exists ${b}`);
13
+ return b;
14
+ } catch (e) {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ /**
20
+ *
21
+ * @param k{string}
22
+ * @returns {Promise<any|null>}
23
+ */
24
+ export async function stoOpGet(k) {
25
+ try {
26
+ let key = k.toString();
27
+ let objGet = await browser.storage.local.get(key);
28
+ let v = objGet[key];
29
+ console.info(`key=${k} value=\n`, v);
30
+ return v;
31
+ } catch (e) {
32
+ return null;
33
+ }
34
+ }
35
+
36
+ /**
37
+ *
38
+ * @returns {Promise<{[p: string]: any}|null>}
39
+ */
40
+ export async function stoOpGetAll() {
41
+ try {
42
+ return await browser.storage.local.get();
43
+ } catch (e) {
44
+ console.error(e);
45
+ return null;
46
+ }
47
+ }
48
+
49
+ /**
50
+ *
51
+ * @param k{string}
52
+ * @returns {Promise<string[]|null>}
53
+ */
54
+ export async function stoOpQueryStartWith(k) {
55
+ try {
56
+ let objAll = await browser.storage.local.get();
57
+ let keys = Object.keys(objAll);
58
+ return keys.filter(value => value.startsWith(k.toString()));
59
+ } catch (e) {
60
+ console.error(e);
61
+ return null;
62
+ }
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @param k{string}
68
+ * @param v{any}
69
+ * @returns {Promise<void>}
70
+ */
71
+ export async function stoOpSet(k, v) {
72
+ let key = k.toString();
73
+
74
+ let objNew = {};
75
+ objNew[key] = v;
76
+ await browser.storage.local.set(objNew);
77
+ }
78
+
79
+ /**
80
+ *
81
+ * @param k{string}
82
+ * @returns {Promise<void>}
83
+ */
84
+ export async function stoOpRem(k) {
85
+ try {
86
+ let key = k.toString();
87
+ await browser.storage.local.remove(key);
88
+ } catch (e) {
89
+ }
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @param k{string}
95
+ * @returns {Promise<void>}
96
+ */
97
+ export async function stoOpSetNull(k) {
98
+ await stoOpSet(k, null);
99
+ }
package/src/opTab.js ADDED
@@ -0,0 +1,178 @@
1
+ /**
2
+ *
3
+ * @param tabId{number}
4
+ * @return {Promise<browser.tabs.Tab>}
5
+ */
6
+ export async function tabOpGet(tabId) {
7
+ return await browser.tabs.get(tabId);
8
+ }
9
+
10
+ /**
11
+ *
12
+ * @returns {Promise<browser.tabs.Tab[]>}
13
+ */
14
+ export async function tabOpQueryAll() {
15
+ return await browser.tabs.query({});
16
+ }
17
+
18
+ /**
19
+ *
20
+ * @param urlQuery{string}
21
+ * @returns {Promise<number[]>}
22
+ */
23
+ export async function tabOpQueryUrl(urlQuery) {
24
+ let tabs = await browser.tabs.query({url: urlQuery});
25
+ return tabs.map(v => v.id);
26
+ }
27
+
28
+ /**
29
+ *
30
+ * @param urlQuery{string}
31
+ * @returns {Promise<void>}
32
+ */
33
+ export async function tabOpQueryUrlThenRemove(urlQuery) {
34
+ let ids = await tabOpQueryUrl(urlQuery);
35
+ ids.map(id => tabOpRemove(id));
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @param tabId{number}
41
+ * @returns {Promise<void>}
42
+ */
43
+ export async function tabOpReload(tabId) {
44
+ await browser.tabs.reload(tabId);
45
+ }
46
+
47
+ /**
48
+ * {active: false, muted: true}
49
+ * Creates a normal tab using either a URL string or a properties object.
50
+ * @param urlOrArgs{string|browser.tabs._CreateCreateProperties}
51
+ * @returns {Promise<(browser.tabs.Tab & {tabId: number})>}
52
+ */
53
+ export async function tabOpCreate(urlOrArgs) {
54
+ try {
55
+ /**
56
+ * @type {browser.tabs._CreateCreateProperties}
57
+ */
58
+ let source = {active: false, muted: true};
59
+ // If it's a string, wrap it in an object
60
+ if (typeof urlOrArgs === 'string') {
61
+ let tab = await browser.tabs.create(Object.assign(
62
+ {url: urlOrArgs}, source,
63
+ ));
64
+ return tabOpEnhance(tab);
65
+ }
66
+ Object.assign(urlOrArgs, source);
67
+ let tab = await browser.tabs.create(urlOrArgs);
68
+ return tabOpEnhance(tab)
69
+ } catch (e) {
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Creates a normal tab using either a URL string or a properties object.
75
+ *
76
+ * @param {string|browser.tabs._CreateCreateProperties} urlOrArgs
77
+ * @returns {Promise<(browser.tabs.Tab & {tabId: number})>}
78
+ */
79
+ export async function tabOpCreateNormal(urlOrArgs) {
80
+ // If it's a string, wrap it in an object
81
+ if (typeof urlOrArgs === 'string') {
82
+ let tab = await browser.tabs.create({url: urlOrArgs});
83
+ return tabOpEnhance(tab)
84
+ }
85
+
86
+ // Otherwise, assume it is already a properties object
87
+ let tab = await browser.tabs.create(urlOrArgs);
88
+ return tabOpEnhance(tab)
89
+ }
90
+
91
+ /**
92
+ *
93
+ * @param tabId{number}
94
+ * @returns {Promise<void>}
95
+ */
96
+ export async function tabOpRemove(tabId) {
97
+ try {
98
+ await browser.tabs.remove(tabId);
99
+ } catch (e) {
100
+ console.error(e);
101
+ }
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @param tabId{number}
107
+ * @returns {Promise<void>}
108
+ */
109
+ export async function tabOpHide(tabId) {
110
+ try {
111
+ await browser.tabs.hide(tabId);
112
+ } catch (e) {
113
+ console.error(e);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Creates a normal tab using either a URL string or a properties object.
119
+ *
120
+ * @param tab{browser.tabs.Tab}
121
+ * @returns {Promise<(browser.tabs.Tab & {tabId: number})>}
122
+ */
123
+ async function tabOpEnhance(tab) {
124
+ return Object.assign(tab, {tabId: tab.id});
125
+ }
126
+
127
+ /**
128
+ *
129
+ * @param {number}tabId
130
+ * @param {browser.tabs._UpdateUpdateProperties}updateProperties
131
+ * @returns {Promise<browser.tabs.Tab&{tabId: number}>}
132
+ */
133
+ export async function tabOpUpdate(tabId, updateProperties) {
134
+ let tab = await browser.tabs.update(tabId, updateProperties);
135
+ return tabOpEnhance(tab);
136
+ }
137
+
138
+ /**
139
+ * active: false, muted: true
140
+ * @param tabId{number}
141
+ * @returns {Promise<browser.tabs.Tab&{tabId: number}>}
142
+ */
143
+ export async function tabOpUpdateActiveFalse(tabId) {
144
+ return await tabOpUpdate(tabId, {active: false, muted: true});
145
+ }
146
+
147
+ /**
148
+ * @param tabId
149
+ */
150
+ export async function tabOpFocus(tabId) {
151
+ let tab = await tabOpGet(tabId);
152
+ let windowId = tab.windowId;
153
+ await browser.windows.update(windowId, {focused: true});
154
+
155
+ let updateProperties = {active: true, highlighted: true};
156
+ let tabUpdated = await tabOpUpdate(tabId, updateProperties);
157
+ return tabOpEnhance(tabUpdated)
158
+ }
159
+
160
+ /**
161
+ *
162
+ * @param{number} tabId
163
+ * @param {string}code
164
+ * @returns {Promise<void>}
165
+ */
166
+ export async function tabOpInsertCssCode(tabId, code) {
167
+ await browser.tabs.insertCSS(tabId, {code});
168
+ }
169
+
170
+ /**
171
+ *
172
+ * @param{number} tabId
173
+ * @param {string}code
174
+ * @returns {Promise<void>}
175
+ */
176
+ export async function tabOpRemoveCssCode(tabId, code) {
177
+ await browser.tabs.removeCSS(tabId, {code});
178
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ *
3
+ * @param serverUrl{string}
4
+ * @param message{{}}
5
+ * @param handleError{function}
6
+ * @returns {Promise<Response>}
7
+ */
8
+ export async function servicePostJson(
9
+ serverUrl,
10
+ message,
11
+ handleError,
12
+ ) {
13
+
14
+ try {
15
+ let body = JSON.stringify(message);
16
+ const fetchResponse = await fetch(serverUrl, {
17
+ method: 'POST',
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ },
21
+ body: body,
22
+ });
23
+
24
+ console.info('fetchResponse');
25
+ console.info(fetchResponse);
26
+ return fetchResponse;
27
+ } catch (e) {
28
+ handleError(e);
29
+ }
30
+
31
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ *
3
+ * @param url{string}
4
+ * @returns {string}
5
+ */
6
+ export function serviceGetDomainByUrl(url) {
7
+ let urlWrap = new URL(url);
8
+ let domain = urlWrap.hostname;
9
+ console.info('serviceGetDomainByUrl()', `domain=\n`,
10
+ domain);
11
+
12
+ return domain;
13
+ }
14
+
15
+ /**
16
+ * eg 2222_12_25_11h_47m_24s_302
17
+ * @return {string}
18
+ */
19
+ export function serviceGetCurrentDateYYYYMMDDHHMMSS() {
20
+ let date = new Date();
21
+ let m = [
22
+ [date.getFullYear(), ''].join(''),
23
+ [date.getMonth() + 1, ''].join(''),
24
+ [date.getDate(), ''].join(''),
25
+
26
+ [date.getHours(), 'h'].join(''),
27
+ [date.getMinutes(), 'm'].join(''),
28
+ [date.getSeconds(), 's'].join(''),
29
+ date.getMilliseconds(),
30
+ ];
31
+ let r = m.join('_');
32
+ return r;
33
+ }
34
+
@@ -0,0 +1,48 @@
1
+
2
+ /**
3
+ *
4
+ * @param{string} content
5
+ */
6
+ export function serviceCopyContentToClipboard(content) {
7
+ window.navigator.clipboard.writeText(content).then(r => null);
8
+ }
9
+
10
+ /**
11
+ * eg: fnName('this is content', 'this is a filename without ext', 'txt')
12
+ * @param {string} content
13
+ * @param {string} filename eg: abc
14
+ * @param {string} ext txt json cmd js ...
15
+ */
16
+ export function serviceSaveContentToLocal(content, filename, ext = 'txt') {
17
+ const eleBtn = document.createElement('button');
18
+ eleBtn.addEventListener(
19
+ 'click',
20
+ function() {
21
+ const eleA = document.createElement('a');
22
+ let type = 'text/plain';
23
+ // let type = 'application/json';
24
+
25
+ const file = new Blob([content], {type});
26
+ eleA.href = URL.createObjectURL(file);
27
+ eleA.download = [filename, ext].join('.');
28
+ eleA.click();
29
+ URL.revokeObjectURL(eleA.href);
30
+ },
31
+ false,
32
+ );
33
+ eleBtn.click();
34
+ // eleBtn.previousElementSibling
35
+ }
36
+
37
+ /**
38
+ *
39
+ * @param {string} value
40
+ * @returns {string}
41
+ */
42
+ export function serviceRemoveIllegalWord(value) {
43
+ let searchValue = /[\/\\\[\]\-"『』<>›::;❗”“'|丨|⦇⦈??!!「」【】─\(\)()《》*#$@&%、,,。+·•]/g;
44
+ let name0 = value.trim().split(/\r?\n/).shift();
45
+ let name1 = name0.replace(searchValue, ' ');
46
+ let name2 = name1.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, ' ');
47
+ return name2;
48
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ *
3
+ * @param {string}videolinkOrigin
4
+ * @returns {{
5
+ * videolink: string,
6
+ * vid: string
7
+ *
8
+ * }|null}
9
+ */
10
+ export function servicePureVideolinkYTB(videolinkOrigin) {
11
+ if (!videolinkOrigin) {
12
+ return null;
13
+ }
14
+
15
+ const u = new URL(videolinkOrigin);
16
+ let vid = u.searchParams.get('v');
17
+
18
+ let searchValue = '/shorts/';
19
+ if (u.pathname.startsWith(searchValue)) {
20
+ vid = u.pathname.replace(searchValue, '');
21
+ }
22
+ let videolink = `https://www.youtube.com/watch?v=${vid}`;
23
+ return {videolink, vid};
24
+ }