@vacantthinker/firefox-addon-framework-easy 2026.526.2259 → 2026.527.1212

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 CHANGED
@@ -23,6 +23,12 @@ export class BaseORM { }
23
23
 
24
24
  ```
25
25
 
26
+ ### 📄 File: `src/browserDownload.js`
27
+ ```javascript
28
+ export async function browserDownloadByDownlink({ }
29
+
30
+ ```
31
+
26
32
  ### 📄 File: `src/browserNotification.js`
27
33
  ```javascript
28
34
  export async function browserNotificationCreate(
@@ -59,6 +65,10 @@ export function generateHtmlByUserSettings(
59
65
  radioItemClickCallback,
60
66
  ) { }
61
67
 
68
+ export function generateMkvScriptForSystemWindows({ }
69
+
70
+ export function generateMkvScriptForSystemFedora({ }
71
+
62
72
  ```
63
73
 
64
74
  ### 📄 File: `src/opStorage.js`
@@ -149,6 +159,8 @@ export async function serviceCopyContentToClipboard(data) { }
149
159
 
150
160
  export function serviceSaveContentToLocal(content, filename, ext = 'txt') { }
151
161
 
162
+ export async function serviceGenerateMkvToolNixScript({ }
163
+
152
164
  export function serviceRemoveIllegalWord(value) { }
153
165
 
154
166
  ```
package/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './src/baseORM.js'
2
+ export * from './src/browserDownload.js'
2
3
  export * from './src/browserNotification.js'
3
4
  export * from './src/browserRuntime.js'
4
5
  export * from './src/generate.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vacantthinker/firefox-addon-framework-easy",
3
- "version": "2026.0526.2259",
3
+ "version": "2026.0527.1212",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -0,0 +1,11 @@
1
+ /**
2
+ *
3
+ * @param param0
4
+ * @param param0.downlink{string}
5
+ * @param param0.filename{string}
6
+ * @returns {Promise<void>}
7
+ */
8
+ export async function browserDownloadByDownlink({ downlink, filename }) {
9
+ let url = downlink;
10
+ await browser.downloads.download({url, filename});
11
+ }
package/src/generate.js CHANGED
@@ -1,4 +1,4 @@
1
- import { stoOpGet, stoOpSet } from './opStorage.js';
1
+ import {stoOpGet, stoOpSet} from './opStorage.js';
2
2
 
3
3
  /**
4
4
  * Generates HTML elements based on a user settings schema object.
@@ -51,17 +51,20 @@ export function generateHtmlByUserSettings(
51
51
  });
52
52
 
53
53
  eleInput.addEventListener('change', async () => {
54
- const optionsCurrent = await stoOpGet(storageKey) || storageValue.selected || [];
54
+ const optionsCurrent = await stoOpGet(storageKey) ||
55
+ storageValue.selected || [];
55
56
  const set = new Set(Array.from(optionsCurrent));
56
57
 
57
58
  if (eleInput.checked) {
58
59
  set.add(option);
59
- } else {
60
+ }
61
+ else {
60
62
  set.delete(option);
61
63
  }
62
64
 
63
65
  const valueNew = Array.from(set);
64
- console.info(`k=${storageKey} option=${option} eleInput.checked=${eleInput.checked} valueNew=${valueNew}`);
66
+ console.info(
67
+ `k=${storageKey} option=${option} eleInput.checked=${eleInput.checked} valueNew=${valueNew}`);
65
68
  await stoOpSet(storageKey, valueNew);
66
69
 
67
70
  // Dynamic visibility update
@@ -70,7 +73,9 @@ export function generateHtmlByUserSettings(
70
73
  }
71
74
  else if (type === 'radio') {
72
75
  stoOpGet(storageKey).then((v) => {
73
- const currentSelected = (v !== undefined && v !== null) ? v : storageValue.selected;
76
+ const currentSelected = (v !== undefined && v !== null) ?
77
+ v :
78
+ storageValue.selected;
74
79
  if (option === currentSelected) {
75
80
  eleInput.checked = true;
76
81
  }
@@ -79,7 +84,7 @@ export function generateHtmlByUserSettings(
79
84
  triggerVisibility(storageKey, currentSelected);
80
85
  });
81
86
 
82
- eleLabel.onclick = function () {
87
+ eleLabel.onclick = function() {
83
88
  stoOpSet(storageKey, option).then(() => {
84
89
  console.info(`k=${storageKey} option=${option}`);
85
90
  if (typeof radioItemClickCallback === 'function') {
@@ -104,7 +109,9 @@ export function generateHtmlByUserSettings(
104
109
 
105
110
  stoOpGet(storageKey).then((v) => {
106
111
  // Fallback to default schema configuration if no value is stored yet
107
- let currentStatus = (v !== undefined && v !== null) ? (v === true || v === 'true') : storageValue.selected;
112
+ let currentStatus = (v !== undefined && v !== null) ?
113
+ (v === true || v === 'true') :
114
+ storageValue.selected;
108
115
  eleButton.textContent = String(currentStatus);
109
116
 
110
117
  // Initial visibility evaluation
@@ -131,7 +138,9 @@ export function generateHtmlByUserSettings(
131
138
  eleInput.name = storageKey;
132
139
 
133
140
  stoOpGet(storageKey).then((v) => {
134
- const currentVal = (v !== undefined && v !== null) ? v : storageValue.selected;
141
+ const currentVal = (v !== undefined && v !== null) ?
142
+ v :
143
+ storageValue.selected;
135
144
  eleInput.value = currentVal;
136
145
 
137
146
  // Initial visibility evaluation
@@ -162,7 +171,7 @@ export function generateHtmlByUserSettings(
162
171
  function triggerVisibility(sourceKey, currentValue) {
163
172
  const config = userSettings[sourceKey];
164
173
  if (config && config.visibilityControl) {
165
- const { targetField, expectedValue } = config.visibilityControl;
174
+ const {targetField, expectedValue} = config.visibilityControl;
166
175
  const targetElement = elementsMap[targetField];
167
176
 
168
177
  if (targetElement) {
@@ -174,4 +183,173 @@ export function generateHtmlByUserSettings(
174
183
  }
175
184
 
176
185
  return fieldsets;
177
- }
186
+ }
187
+
188
+ export function generateMkvScriptForSystemWindows({vid, title}) {
189
+ let args = {vid, title};
190
+
191
+ return `if (true) {
192
+ const path = require('path');
193
+ const fs = require('fs');
194
+ const {execSync, exec} = require('node:child_process');
195
+ let pathDownload = path.join(__dirname);
196
+ let dot = '.';
197
+ let extMKV = 'mkv';
198
+
199
+ let {vid, title} = ${JSON.stringify(args)};
200
+ let playVideoAfterMerged = true;
201
+ let pathToMkvmerge = 'C:\\\\Program Files\\\\MKVToolNix\\\\mkvmerge.exe';
202
+
203
+ let pathMKVOutput = path.join(pathDownload, title.concat(dot, extMKV));
204
+ let pathOutput = path.join(pathDownload, vid.concat(dot, extMKV));
205
+ let pathInputAudio = path.join(pathDownload, vid.concat(dot, "mp3"));
206
+ let pathInputVideo = path.join(pathDownload, vid.concat(dot, "mp4"));
207
+ let pathJsFile = path.join(__filename);
208
+
209
+ if (
210
+ fs.existsSync(pathToMkvmerge)
211
+ ) {
212
+
213
+ console.log('');
214
+ console.log(['file check ok!', title].join(' '));
215
+
216
+ let cmd_merge = [
217
+ [pathToMkvmerge].map(v => '"' + v + '"').join(''),
218
+
219
+ '-o',
220
+ [pathOutput]
221
+ .map(value => '"' + value + '"')
222
+ .join(' '),
223
+
224
+ '--no-video',
225
+ [pathInputAudio]
226
+ .map(value => '"' + value + '"')
227
+ .join(' '),
228
+
229
+ '--no-audio',
230
+ [pathInputVideo]
231
+ .map(value => '"' + value + '"')
232
+ .join(' '),
233
+ ].join(' ');
234
+
235
+ console.log('execute script merge ...')
236
+ console.log(cmd_merge);
237
+
238
+ let exec_merge = exec(cmd_merge);
239
+ exec_merge.stdout.on('data', (data) => {
240
+ console.log(data);
241
+ });
242
+ exec_merge.stderr.on('data', (data) => {
243
+ console.log('error', data);
244
+ });
245
+ exec_merge.stdout.on('close', (data) => {
246
+ console.log(['merge finish!', title].join(' '));
247
+
248
+ if (true) {
249
+ console.log('remove inputFile');
250
+ fs.unlinkSync(pathInputVideo);
251
+ fs.unlinkSync(pathInputAudio);
252
+ }
253
+
254
+ console.log('rename output mkv video...');
255
+ fs.renameSync(pathOutput, pathMKVOutput);
256
+
257
+ if (playVideoAfterMerged) {
258
+ console.log('play mkv video...');
259
+ execSync('"' + pathMKVOutput + '"');
260
+ }
261
+
262
+ if (true) {
263
+ console.log('remove script file');
264
+ fs.unlinkSync(pathJsFile);
265
+ }
266
+ });
267
+
268
+ } else {
269
+ console.log('pathToMkvmerge error')
270
+
271
+ }
272
+ }
273
+ `;
274
+ }
275
+
276
+ export function generateMkvScriptForSystemFedora({vid, title}) {
277
+ let args = {vid, title};
278
+
279
+ // We wrap the Node.js script inside a Linux Shell script block
280
+ return `#!/usr/bin/env bash
281
+ # This header tells Fedora to treat this file as a runnable bash script
282
+
283
+ # Open a terminal window if not already running inside one
284
+ if [ -z "$VTE_VERSION" ] && [ -z "$ALACRITTY_WINDOW_ID" ] && [ -z "$KITTY_WINDOW_ID" ] && [ "$1" != "--child" ]; then
285
+ # Re-run this same script inside a visible terminal window so the user sees progress
286
+ gnome-terminal -- "$0" --child
287
+ exit 0
288
+ fi
289
+
290
+ # Run the embedded Node.js code below
291
+ node << 'EOF'
292
+ const path = require('path');
293
+ const fs = require('fs');
294
+ const { execSync } = require('node:child_process');
295
+
296
+ let pathDownload = path.join(__dirname);
297
+ let dot = '.';
298
+ let extMKV = 'mkv';
299
+
300
+ let {vid, title} = ${JSON.stringify(args)};
301
+ let playVideoAfterMerged = true;
302
+ let pathToMkvmerge = '/usr/bin/mkvmerge';
303
+
304
+ let pathMKVOutput = path.join(pathDownload, title.concat(dot, extMKV));
305
+ let pathOutput = path.join(pathDownload, vid.concat(dot, extMKV));
306
+ let pathInputAudio = path.join(pathDownload, vid.concat(dot, "mp3"));
307
+ let pathInputVideo = path.join(pathDownload, vid.concat(dot, "mp4"));
308
+
309
+ if (fs.existsSync(pathToMkvmerge)) {
310
+ console.log('\\nfile check ok! ' + title);
311
+
312
+ let cmd_merge = [
313
+ '"' + pathToMkvmerge + '"',
314
+ '-o', '"' + pathOutput + '"',
315
+ '--no-video', '"' + pathInputAudio + '"',
316
+ '--no-audio', '"' + pathInputVideo + '"',
317
+ ].join(' ');
318
+
319
+ console.log('execute script merge ...\\n' + cmd_merge);
320
+
321
+ try {
322
+ // Run merge synchronously so stdout pipes directly to the terminal
323
+ execSync(cmd_merge, { stdio: 'inherit' });
324
+ console.log('merge finish! ' + title);
325
+
326
+ console.log('remove inputFile');
327
+ if (fs.existsSync(pathInputVideo)) fs.unlinkSync(pathInputVideo);
328
+ if (fs.existsSync(pathInputAudio)) fs.unlinkSync(pathInputAudio);
329
+
330
+ console.log('rename output mkv video...');
331
+ fs.renameSync(pathOutput, pathMKVOutput);
332
+
333
+ if (playVideoAfterMerged) {
334
+ console.log('play mkv video...');
335
+ // xdg-open usually hands off to the player and exits immediately
336
+ execSync('xdg-open "' + pathMKVOutput + '"');
337
+ }
338
+ } catch (err) {
339
+ console.error('An error occurred during processing:', err.message);
340
+ }
341
+ } else {
342
+ console.log('pathToMkvmerge error. run: sudo dnf install mkvtoolnix')
343
+ }
344
+ EOF
345
+
346
+ # Prevent the terminal window from closing instantly so the user can read messages
347
+ echo ""
348
+ echo "Press Enter to exit and automatically delete this script..."
349
+ read unused_input
350
+
351
+ # Deletes the shell script file itself after completion
352
+ rm -- "$0"
353
+ `;
354
+ }
355
+
@@ -1,3 +1,9 @@
1
+ import {browserRuntimePlatformInfo} from './browserRuntime.js';
2
+ import {
3
+ generateMkvScriptForSystemFedora,
4
+ generateMkvScriptForSystemWindows,
5
+ } from './generate.js';
6
+
1
7
  /**
2
8
  *
3
9
  * @param data
@@ -22,8 +28,8 @@ export function serviceSaveContentToLocal(content, filename, ext = 'txt') {
22
28
 
23
29
  const extObj = {
24
30
  txt: 'text/plain',
25
- json: 'application/json'
26
- }
31
+ json: 'application/json',
32
+ };
27
33
  const type = extObj[ext];
28
34
 
29
35
  const file = new Blob([content], {type});
@@ -38,6 +44,26 @@ export function serviceSaveContentToLocal(content, filename, ext = 'txt') {
38
44
  // eleBtn.previousElementSibling
39
45
  }
40
46
 
47
+ /**
48
+ * need install nodejs mkvtoolnix
49
+ * @param message{{
50
+ * vid, title,
51
+ * }}
52
+ * @returns {Promise<void>}
53
+ */
54
+ export async function serviceGenerateMkvToolNixScript({vid, title}) {
55
+ let message = {vid, title};
56
+ const platformInfo = await browserRuntimePlatformInfo();
57
+ if (platformInfo.os === 'win') {
58
+ let content = generateMkvScriptForSystemWindows(message);
59
+ serviceSaveContentToLocal(content, title, 'js');
60
+ }
61
+ else if (platformInfo.os === 'linux') {
62
+ let content = generateMkvScriptForSystemFedora(message);
63
+ serviceSaveContentToLocal(content, title, 'sh');
64
+ }
65
+ }
66
+
41
67
  /**
42
68
  *
43
69
  * @param {string} value