fix: doodstream login redirect handling + queue only adds files after confirm

- Fix doodstream login: handle redirect on success (server returns HTML dashboard instead of JSON)
- Fix sess_id extraction: match hidden input field format
- Files are now only added to queue after clicking "Uebernehmen" in hoster modal
- Cancel/Escape/click-outside discards pending files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-11 01:36:50 +01:00
parent d94156943b
commit b8b8158abb
2 changed files with 74 additions and 34 deletions

View File

@ -84,23 +84,45 @@ class DoodstreamUploader {
loginotp: ''
});
const res = await this._fetch(BASE_URL + '/', {
// Use raw fetch with redirect: 'manual' to detect success redirects
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': BASE_URL + '/',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': USER_AGENT
};
if (this.cookies.size > 0) {
headers['Cookie'] = this._cookieHeader();
}
const res = await fetch(BASE_URL + '/', {
method: 'POST',
body: loginData.toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': BASE_URL + '/',
'X-Requested-With': 'XMLHttpRequest'
}
headers,
redirect: 'manual'
});
const body = await res.text();
let json;
try { json = JSON.parse(body); } catch { json = null; }
this._parseCookiesFromHeaders(res.headers);
if (!json || json.status !== 'success') {
const msg = (json && json.message) || 'Login fehlgeschlagen';
throw new Error(`Doodstream Login: ${msg}`);
// On successful login, server may redirect (3xx) to dashboard
if ([301, 302, 303, 307, 308].includes(res.status)) {
try { await res.text(); } catch {}
// Redirect means login succeeded
} else {
const body = await res.text();
let json;
try { json = JSON.parse(body); } catch { json = null; }
if (json && json.status === 'success') {
// Explicit success response
} else if (json && json.status === 'fail') {
throw new Error(`Doodstream Login: ${json.message || 'Login fehlgeschlagen'}`);
} else if (body.includes('Dashboard')) {
// Got dashboard HTML directly — login worked
} else {
const msg = (json && json.message) || 'Login fehlgeschlagen';
throw new Error(`Doodstream Login: ${msg}`);
}
}
// Extract sess_id from the upload page
@ -111,14 +133,21 @@ class DoodstreamUploader {
const res = await this._fetch(BASE_URL + '/?op=upload');
const html = await res.text();
// Look for sess_id in the page (Vue component prop or hidden field)
// Hidden input: <input type="hidden" name="sess_id" value="xxx">
const hiddenMatch = html.match(/name=["']sess_id["'][^>]*value=["']([a-zA-Z0-9]+)["']/);
if (hiddenMatch) {
this.sessId = hiddenMatch[1];
return;
}
// Vue component prop or JS: sess_id: "xxx" or sess_id="xxx"
const sessMatch = html.match(/sess_id['":\s]+['"]([a-zA-Z0-9]+)['"]/);
if (sessMatch) {
this.sessId = sessMatch[1];
return;
}
// Alternative: look in script or data attributes
// Assignment: sess_id = 'xxx'
const altMatch = html.match(/sess_id\s*=\s*['"]([a-zA-Z0-9]+)['"]/);
if (altMatch) {
this.sessId = altMatch[1];

View File

@ -193,10 +193,19 @@ function closeHosterModal() {
function applyHosterSelection() {
selectedUploadHosters = Array.from(document.querySelectorAll('input[data-hoster-modal]:checked'))
.map(input => input.dataset.hosterModal);
// Move pending files to selectedFiles on confirm
if (_pendingFiles.length > 0) {
selectedFiles.push(..._pendingFiles);
_pendingFiles = [];
}
renderHosterSummary();
if (!uploading && selectedFiles.length > 0) buildQueuePreview();
updateStartButton();
updateUploadView();
persistQueueStateSoon();
document.getElementById('hosterModal').style.display = 'none';
}
function cancelHosterModal() {
_pendingFiles = [];
closeHosterModal();
}
@ -337,34 +346,36 @@ function setupDragDrop() {
});
}
let _pendingFiles = []; // Files waiting for hoster modal confirmation
function addDroppedFiles(fileList) {
let added = 0;
const files = Array.from(fileList);
const newFiles = [];
for (const file of files) {
if (!selectedFiles.find(f => f.path === file.path)) {
selectedFiles.push({ path: file.path, name: file.name, size: file.size });
added++;
if (!selectedFiles.find(f => f.path === file.path) && !_pendingFiles.find(f => f.path === file.path)) {
newFiles.push({ path: file.path, name: file.name, size: file.size });
}
}
updateUploadView();
persistQueueStateSoon();
if (added > 0) openHosterModal();
if (newFiles.length > 0) {
_pendingFiles.push(...newFiles);
openHosterModal();
}
}
async function pickFiles() {
const paths = await window.api.selectFiles();
if (!paths) return;
let added = 0;
const newFiles = [];
for (const p of paths) {
if (!selectedFiles.find(f => f.path === p)) {
if (!selectedFiles.find(f => f.path === p) && !_pendingFiles.find(f => f.path === p)) {
const name = p.split('\\').pop().split('/').pop();
selectedFiles.push({ path: p, name, size: null }); // size resolved by upload-manager
added++;
newFiles.push({ path: p, name, size: null });
}
}
updateUploadView();
persistQueueStateSoon();
if (added > 0) openHosterModal();
if (newFiles.length > 0) {
_pendingFiles.push(...newFiles);
openHosterModal();
}
}
function updateUploadView() {
@ -675,7 +686,7 @@ document.addEventListener('click', (e) => {
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
hideContextMenu();
closeHosterModal();
cancelHosterModal();
}
});
@ -1517,8 +1528,8 @@ function setupListeners() {
retrySelectedJobs();
});
document.getElementById('confirmHosterModalBtn').addEventListener('click', applyHosterSelection);
document.getElementById('cancelHosterModalBtn').addEventListener('click', closeHosterModal);
document.getElementById('closeHosterModalBtn').addEventListener('click', closeHosterModal);
document.getElementById('cancelHosterModalBtn').addEventListener('click', cancelHosterModal);
document.getElementById('closeHosterModalBtn').addEventListener('click', cancelHosterModal);
document.getElementById('selectAllHostersBtn').addEventListener('click', () => {
document.querySelectorAll('input[data-hoster-modal]').forEach(input => {
input.checked = true;
@ -1577,7 +1588,7 @@ function setupListeners() {
});
document.getElementById('hosterModal').addEventListener('click', (e) => {
if (e.target.id === 'hosterModal') closeHosterModal();
if (e.target.id === 'hosterModal') cancelHosterModal();
});
// Account management