feat(options,popup,background): add per-page aria2 dir option and popup toggle
- Options: add default toggle and base path () - Popup: allow per-send enable + preview; passes AGENTS.md LICENSE node_modules package-lock.json releases src dist manifest.json package.json README.md scripts to aria2 - Background: quick actions honor default, set AGENTS.md LICENSE node_modules package-lock.json releases src dist manifest.json package.json README.md scripts to <base>/<identifier> - Storage: new prefs and
This commit is contained in:
parent
56035451df
commit
0d944892d8
5 changed files with 89 additions and 7 deletions
|
|
@ -74,6 +74,8 @@ async function getPrefs() {
|
|||
return {
|
||||
defaultAction: prefs?.defaultAction || 'download',
|
||||
allIncludeMeta: !!prefs?.allIncludeMeta,
|
||||
perPageDirEnabled: !!prefs?.perPageDirEnabled,
|
||||
perPageDirBase: prefs?.perPageDirBase || '/aria2/data',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +110,7 @@ async function rebuildContextSubmenu(tab) {
|
|||
let items = [];
|
||||
try { items = await collectFromTab(tab.id); } catch (_) { items = []; }
|
||||
const identifier = parseIdentifierFromUrl(tab.url || '');
|
||||
const { defaultAction, allIncludeMeta } = await getPrefs();
|
||||
const { defaultAction, allIncludeMeta, perPageDirEnabled, perPageDirBase } = await getPrefs();
|
||||
const verb = defaultAction === 'copy' ? 'Copy' : 'Download';
|
||||
|
||||
const top = computeTopTypes(items, identifier, 4);
|
||||
|
|
@ -256,7 +258,7 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => {
|
|||
const action = dynamicActions.get(String(info.menuItemId));
|
||||
if (!action || !tab?.id) return;
|
||||
try {
|
||||
const { defaultAction, allIncludeMeta } = await getPrefs();
|
||||
const { defaultAction, allIncludeMeta, perPageDirEnabled, perPageDirBase } = await getPrefs();
|
||||
const identifier = parseIdentifierFromUrl(tab.url || '');
|
||||
const items = await collectFromTab(tab.id);
|
||||
let selected = items || [];
|
||||
|
|
@ -276,10 +278,19 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => {
|
|||
color: '#10b981',
|
||||
title: `Copied ${count} link(s)`
|
||||
});
|
||||
} else {
|
||||
} else {
|
||||
const { endpoint, secret } = await getAria2();
|
||||
if (!endpoint) { console.warn('aria2 endpoint not set'); return; }
|
||||
try { await globalThis.addUrisBatch({ endpoint, secret, uris }); } catch (e) { console.warn('aria2 send failed', e); }
|
||||
// Build aria2 options (dir) based on prefs
|
||||
let options = {};
|
||||
try {
|
||||
if (perPageDirEnabled && perPageDirBase) {
|
||||
const base = String(perPageDirBase).replace(/\/+$/, '');
|
||||
const dir = identifier ? `${base}/${identifier}` : base;
|
||||
if (dir) options.dir = dir;
|
||||
}
|
||||
} catch (_) { /* noop */ }
|
||||
try { await globalThis.addUrisBatch({ endpoint, secret, uris, options }); } catch (e) { console.warn('aria2 send failed', e); }
|
||||
await setBadgeForTab(tab.id, {
|
||||
text: String(count),
|
||||
color: '#3b82f6',
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@
|
|||
<div class="row">
|
||||
<label class="chk"><input type="checkbox" id="include-meta" /> Include metadata in “All”</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="chk"><input type="checkbox" id="per-page-dir-enabled" /> Use per‑page download directory by default</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Base directory <input id="per-page-dir-base" placeholder="/aria2/data" /></label>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<script type="module" src="index.js"></script>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ const els = {
|
|||
secret: document.getElementById('rpc-secret'),
|
||||
defaultAction: document.getElementById('default-action'),
|
||||
includeMeta: document.getElementById('include-meta'),
|
||||
perPageDirEnabled: document.getElementById('per-page-dir-enabled'),
|
||||
perPageDirBase: document.getElementById('per-page-dir-base'),
|
||||
btnSave: document.getElementById('btn-save'),
|
||||
btnReset: document.getElementById('btn-reset'),
|
||||
btnTest: document.getElementById('btn-test'),
|
||||
|
|
@ -19,8 +21,12 @@ async function restore() {
|
|||
const { prefs } = await browser.storage.local.get('prefs');
|
||||
const defaultAction = prefs?.defaultAction || 'download';
|
||||
const includeMeta = !!prefs?.allIncludeMeta;
|
||||
const perPageDirEnabled = !!prefs?.perPageDirEnabled;
|
||||
const perPageDirBase = prefs?.perPageDirBase || '/aria2/data';
|
||||
els.defaultAction.value = defaultAction;
|
||||
els.includeMeta.checked = includeMeta;
|
||||
els.perPageDirEnabled.checked = perPageDirEnabled;
|
||||
els.perPageDirBase.value = perPageDirBase;
|
||||
}
|
||||
|
||||
async function save() {
|
||||
|
|
@ -28,9 +34,11 @@ async function save() {
|
|||
const secret = els.secret.value.trim();
|
||||
const defaultAction = els.defaultAction.value;
|
||||
const allIncludeMeta = !!els.includeMeta.checked;
|
||||
const perPageDirEnabled = !!els.perPageDirEnabled.checked;
|
||||
const perPageDirBase = els.perPageDirBase.value.trim() || '/aria2/data';
|
||||
await browser.storage.local.set({
|
||||
aria2: { endpoint, secret },
|
||||
prefs: { defaultAction, allIncludeMeta }
|
||||
prefs: { defaultAction, allIncludeMeta, perPageDirEnabled, perPageDirBase }
|
||||
});
|
||||
els.status.textContent = 'Saved.';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@
|
|||
<div class="row">
|
||||
<label>Secret <input id="rpc-secret" type="password" placeholder="your-token" /></label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="chk"><input type="checkbox" id="use-perpage-dir" /> Use per‑page download directory</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<small id="dir-preview"></small>
|
||||
</div>
|
||||
<div class="row actions">
|
||||
<button id="btn-copy">Copy Links</button>
|
||||
<button id="btn-send">Send to aria2</button>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ const els = {
|
|||
btnSend: document.getElementById('btn-send'),
|
||||
rpcEndpoint: document.getElementById('rpc-endpoint'),
|
||||
rpcSecret: document.getElementById('rpc-secret'),
|
||||
usePerPageDir: document.getElementById('use-perpage-dir'),
|
||||
dirPreview: document.getElementById('dir-preview'),
|
||||
count: document.getElementById('count'),
|
||||
status: document.getElementById('status'),
|
||||
openOptions: document.getElementById('open-options'),
|
||||
|
|
@ -42,6 +44,21 @@ async function getActiveTabId() {
|
|||
return tabs[0]?.id;
|
||||
}
|
||||
|
||||
function parseIdentifierFromUrl(url) {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
const parts = u.pathname.split('/').filter(Boolean);
|
||||
const idx = parts.indexOf('download');
|
||||
if (idx >= 0 && parts[idx + 1]) return parts[idx + 1];
|
||||
} catch (_) {}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function getActiveTabUrl() {
|
||||
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
||||
return tabs[0]?.url || '';
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
els.status.textContent = '';
|
||||
try {
|
||||
|
|
@ -58,6 +75,7 @@ async function refresh() {
|
|||
}
|
||||
allItems = items || [];
|
||||
await updateCount();
|
||||
await updateDirPreview();
|
||||
} catch (e) {
|
||||
els.status.textContent = String(e?.message || e);
|
||||
}
|
||||
|
|
@ -95,10 +113,21 @@ async function sendToAria2() {
|
|||
// Persist settings
|
||||
await browser.storage.local.set({ aria2: { endpoint, secret } });
|
||||
els.status.textContent = 'Sending to aria2…';
|
||||
|
||||
// aria2 options
|
||||
let options = {};
|
||||
try {
|
||||
if (els.usePerPageDir?.checked) {
|
||||
const { prefs } = await browser.storage.local.get('prefs');
|
||||
const base = (prefs?.perPageDirBase || '/aria2/data').replace(/\/+$/, '');
|
||||
const url = await getActiveTabUrl();
|
||||
const id = parseIdentifierFromUrl(url);
|
||||
const dir = id ? `${base}/${id}` : base;
|
||||
if (dir) options.dir = dir;
|
||||
}
|
||||
} catch (_) {}
|
||||
const res = await browser.runtime.sendMessage({
|
||||
type: 'aria2.send',
|
||||
payload: { endpoint, secret, uris }
|
||||
payload: { endpoint, secret, uris, options }
|
||||
});
|
||||
if (res?.ok) {
|
||||
els.status.textContent = `Sent ${uris.length} link(s) to aria2.`;
|
||||
|
|
@ -115,6 +144,11 @@ async function restoreSettings() {
|
|||
} else {
|
||||
els.rpcEndpoint.value = 'http://localhost:6800/jsonrpc';
|
||||
}
|
||||
try {
|
||||
const { prefs } = await browser.storage.local.get('prefs');
|
||||
const enabled = !!prefs?.perPageDirEnabled;
|
||||
els.usePerPageDir.checked = enabled;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function wire() {
|
||||
|
|
@ -126,6 +160,9 @@ function wire() {
|
|||
els.fType, els.fTypeRe, els.fName, els.fNameRe, els.fSizeMin, els.fSizeMax,
|
||||
els.fDateFrom, els.fDateTo, els.fCase
|
||||
].forEach(el => el.addEventListener('input', () => { updateCount(); }));
|
||||
if (els.usePerPageDir) {
|
||||
els.usePerPageDir.addEventListener('change', () => { updateDirPreview(); });
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
|
@ -150,3 +187,17 @@ function renderPreview() {
|
|||
els.preview.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateDirPreview() {
|
||||
if (!els.dirPreview) return;
|
||||
try {
|
||||
const { prefs } = await browser.storage.local.get('prefs');
|
||||
const base = (prefs?.perPageDirBase || '/aria2/data').replace(/\/+$/, '');
|
||||
const url = await getActiveTabUrl();
|
||||
const id = parseIdentifierFromUrl(url);
|
||||
const dir = id ? `${base}/${id}` : base;
|
||||
els.dirPreview.textContent = els.usePerPageDir?.checked ? `Will set aria2 dir: ${dir}` : '';
|
||||
} catch (_) {
|
||||
els.dirPreview.textContent = '';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue