Send UI downloads into Movies library and harden queue API.
UI grabs write Movies/<Title (Year)>/; chown to 1000:1000; CORS and safer /api/queue handling for the Web UI.
This commit is contained in:
@@ -1,6 +1,25 @@
|
||||
// Same origin as the page (works for LAN IP / hostname). Avoid relative issues
|
||||
// when the app is served with a non-root base path later.
|
||||
const API_BASE = window.location.origin;
|
||||
let queuePoll = null;
|
||||
|
||||
async function apiFetch(path, opts) {
|
||||
const res = await fetch(`${API_BASE}${path}`, {
|
||||
...opts,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
...(opts && opts.headers),
|
||||
},
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '');
|
||||
throw new Error(text || `HTTP ${res.status}`);
|
||||
}
|
||||
const ct = res.headers.get('content-type') || '';
|
||||
if (ct.includes('application/json')) return res.json();
|
||||
return res.text();
|
||||
}
|
||||
|
||||
// ── Tabs ────────────────────────────────────────────────────────────────────
|
||||
|
||||
function startQueuePoll() {
|
||||
@@ -51,9 +70,7 @@ async function doSearch() {
|
||||
if (!q) return;
|
||||
searchResults.innerHTML = '<div class="spinner">Searching...</div>';
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/search?q=${encodeURIComponent(q)}&limit=30`);
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
const data = await res.json();
|
||||
const data = await apiFetch(`/api/search?q=${encodeURIComponent(q)}&limit=30`);
|
||||
renderSearchResults(data);
|
||||
} catch (err) {
|
||||
searchResults.innerHTML = `<div class="empty">Search failed: ${err.message}</div>`;
|
||||
@@ -116,12 +133,11 @@ function renderSearchResults(files) {
|
||||
const addedIdents = {};
|
||||
|
||||
async function addDownload(ident, name, size) {
|
||||
const res = await fetch(`${API_BASE}/api/queue/add`, {
|
||||
await apiFetch('/api/queue/add', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ident, name, size }),
|
||||
});
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
addedIdents[ident] = true;
|
||||
}
|
||||
|
||||
@@ -130,9 +146,7 @@ async function addDownload(ident, name, size) {
|
||||
const queueList = document.getElementById('queueList');
|
||||
|
||||
async function fetchQueue() {
|
||||
const res = await fetch(`${API_BASE}/api/queue`);
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
return res.json();
|
||||
return apiFetch('/api/queue');
|
||||
}
|
||||
|
||||
function renderQueue() {
|
||||
@@ -175,7 +189,7 @@ function renderQueue() {
|
||||
btn.disabled = true;
|
||||
btn.textContent = '[…]';
|
||||
try {
|
||||
await fetch(`${API_BASE}/api/queue/cancel`, {
|
||||
await apiFetch('/api/queue/cancel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ hash }),
|
||||
|
||||
Reference in New Issue
Block a user