You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
11 KiB
300 lines
11 KiB
class DownloadTool {
|
|
constructor() {
|
|
this.form = document.getElementById('downloadForm');
|
|
this.output = document.getElementById('output');
|
|
this.loadUrlsBtn = document.getElementById('loadUrls');
|
|
this.urlListTextarea = document.getElementById('urlList');
|
|
this.downloadUrlBtn = document.getElementById('downloadUrl');
|
|
this.cleanFilesBtn = document.getElementById('cleanFiles');
|
|
this.downloadImageBtn = document.getElementById('downloadImage');
|
|
this.checkIncompleteBtn = document.getElementById('checkIncomplete');
|
|
this.clearOutputBtn = document.getElementById('clearOutput');
|
|
this.proxySelect = document.getElementById('proxy');
|
|
|
|
this.websocket = null;
|
|
this.isConnected = false;
|
|
|
|
this.initEvents();
|
|
this.connectWebSocket();
|
|
}
|
|
|
|
initEvents() {
|
|
// 读取URL按钮
|
|
this.loadUrlsBtn.addEventListener('click', () => {
|
|
this.loadTargetUrls();
|
|
});
|
|
|
|
// 下载URL按钮
|
|
this.downloadUrlBtn.addEventListener('click', () => {
|
|
this.downloadUrls()
|
|
});
|
|
|
|
// 下载图片按钮
|
|
this.downloadImageBtn.addEventListener('click', () => {
|
|
this.downloadImages()
|
|
});
|
|
|
|
// 检查未完成按钮
|
|
this.checkIncompleteBtn.addEventListener('click', () => {
|
|
this.checkIncomplete();
|
|
});
|
|
|
|
// 清理文件按钮
|
|
this.cleanFilesBtn.addEventListener('click', () => {
|
|
this.cleanFiles();
|
|
});
|
|
|
|
// 清除输出按钮
|
|
this.clearOutputBtn.addEventListener('click', () => {
|
|
this.clearOutput();
|
|
});
|
|
}
|
|
|
|
connectWebSocket() {
|
|
try {
|
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const wsUrl = `${protocol}//${window.location.host}/ws`;
|
|
this.websocket = new WebSocket(wsUrl);
|
|
|
|
this.websocket.onopen = () => {
|
|
this.isConnected = true;
|
|
this.showOutput('WebSocket连接已建立,可以接收实时日志', 'success');
|
|
console.log('WebSocket连接已建立');
|
|
};
|
|
|
|
this.websocket.onmessage = (event) => {
|
|
try {
|
|
const logEntry = JSON.parse(event.data);
|
|
this.appendRealtimeLog(logEntry);
|
|
} catch (e) {
|
|
console.error('解析WebSocket消息失败:', e);
|
|
}
|
|
};
|
|
|
|
this.websocket.onclose = () => {
|
|
this.isConnected = false;
|
|
this.showOutput('WebSocket连接已断开,正在尝试重连...', 'error');
|
|
console.log('WebSocket连接已断开');
|
|
// 5秒后尝试重连
|
|
setTimeout(() => this.connectWebSocket(), 5000);
|
|
};
|
|
|
|
this.websocket.onerror = (error) => {
|
|
console.error('WebSocket错误:', error);
|
|
this.showOutput('WebSocket连接错误', 'error');
|
|
};
|
|
} catch (error) {
|
|
console.error('创建WebSocket连接失败:', error);
|
|
this.showOutput('WebSocket连接失败', 'error');
|
|
}
|
|
}
|
|
|
|
appendRealtimeLog(logEntry) {
|
|
const timestamp = logEntry.time || new Date().toLocaleTimeString();
|
|
const level = logEntry.level || 'INFO';
|
|
const source = logEntry.source || 'system';
|
|
const message = logEntry.message || '';
|
|
|
|
const logLine = `[${timestamp}] [${level}] [${source}] ${message}`;
|
|
|
|
// 追加到输出框
|
|
if (this.output.textContent) {
|
|
this.output.textContent += '\n' + logLine;
|
|
} else {
|
|
this.output.textContent = logLine;
|
|
}
|
|
|
|
// 自动滚动到底部
|
|
this.output.scrollTop = this.output.scrollHeight;
|
|
|
|
// 根据日志级别设置样式
|
|
if (level === 'ERROR') {
|
|
this.output.classList.add('error');
|
|
} else if (level === 'SUCCESS') {
|
|
this.output.classList.add('success');
|
|
} else {
|
|
this.output.classList.remove('error', 'success');
|
|
}
|
|
}
|
|
|
|
async loadTargetUrls() {
|
|
try {
|
|
this.setLoading(true);
|
|
this.showOutput('正在读取 targets.txt...', 'info');
|
|
|
|
const response = await fetch('/load_urls', {
|
|
method: 'POST'
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
// 在URL列表文本框中显示读取的URL
|
|
this.urlListTextarea.value = result.urls.join('\n');
|
|
this.showOutput(`成功读取 ${result.urls.length} 个URL\n\nURL列表:\n${result.urls.join('\n')}`, 'success');
|
|
} else {
|
|
this.showOutput(`读取失败: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showOutput(`读取URL时出错: ${error.message}`, 'error');
|
|
} finally {
|
|
this.setLoading(false);
|
|
}
|
|
}
|
|
|
|
async clearOutput() {
|
|
try {
|
|
const response = await fetch('/clear', {
|
|
method: 'POST'
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.success) {
|
|
this.showOutput('', 'success');
|
|
this.urlListTextarea.value = ''; // 同时清空URL列表
|
|
}
|
|
} catch (error) {
|
|
this.showOutput(`清除失败: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
async downloadUrls() {
|
|
try {
|
|
const proxy = this.proxySelect.value;
|
|
|
|
this.showOutput(`正在抓取画廊链接...\n代理: ${proxy}\n\n注意:此操作可能需要较长时间,请耐心等待...`, 'info');
|
|
|
|
// 使用setTimeout确保UI不被阻塞
|
|
setTimeout(async () => {
|
|
try {
|
|
const res = await fetch('/download_urls', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ proxy })
|
|
});
|
|
const data = await res.json();
|
|
this.showOutput(data.message, data.success ? 'success' : 'error');
|
|
} catch (error) {
|
|
this.showOutput(`抓取画廊链接时出错: ${error.message}`, 'error');
|
|
}
|
|
}, 100);
|
|
|
|
} catch (error) {
|
|
this.showOutput(`抓取画廊链接时出错: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
async downloadImages() {
|
|
try {
|
|
const proxy = this.proxySelect.value;
|
|
|
|
this.showOutput(`正在下载图片...\n代理: ${proxy}\n\n注意:此操作可能需要较长时间,请耐心等待...`, 'info');
|
|
|
|
// 使用setTimeout确保UI不被阻塞
|
|
setTimeout(async () => {
|
|
try {
|
|
const res = await fetch('/download_images', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ proxy })
|
|
});
|
|
const data = await res.json();
|
|
this.showOutput(data.message, data.success ? 'success' : 'error');
|
|
} catch (error) {
|
|
this.showOutput(`下载图片时出错: ${error.message}`, 'error');
|
|
}
|
|
}, 100);
|
|
|
|
} catch (error) {
|
|
this.showOutput(`下载图片时出错: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
async checkIncomplete() {
|
|
try {
|
|
this.setLoading(true);
|
|
this.showOutput('正在检查未完成文件...', 'info');
|
|
|
|
const response = await fetch('/check_incomplete', {
|
|
method: 'POST'
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
let message = `检查完成!\n\n`;
|
|
message += `${result.data}`;
|
|
this.showOutput(message, 'success');
|
|
} else {
|
|
this.showOutput(`检查失败: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showOutput(`检查未完成文件时出错: ${error.message}`, 'error');
|
|
} finally {
|
|
this.setLoading(false);
|
|
}
|
|
}
|
|
|
|
async cleanFiles() {
|
|
try {
|
|
this.setLoading(true);
|
|
this.showOutput('正在清理日志和JSON文件...', 'info');
|
|
|
|
const response = await fetch('/clean_files', {
|
|
method: 'POST'
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
let message = `清理完成!成功删除 ${result.deleted_count} 个文件\n\n`;
|
|
if (result.deleted_files && result.deleted_files.length > 0) {
|
|
message += "已删除的文件:\n" + result.deleted_files.join('\n');
|
|
}
|
|
this.showOutput(message, 'success');
|
|
} else {
|
|
let message = `清理完成,但有 ${result.error_count} 个文件删除失败\n\n`;
|
|
if (result.deleted_files && result.deleted_files.length > 0) {
|
|
message += "已删除的文件:\n" + result.deleted_files.join('\n') + '\n\n';
|
|
}
|
|
if (result.error_files && result.error_files.length > 0) {
|
|
message += "删除失败的文件:\n" + result.error_files.join('\n');
|
|
}
|
|
this.showOutput(message, 'error');
|
|
}
|
|
} catch (error) {
|
|
this.showOutput(`清理文件时出错: ${error.message}`, 'error');
|
|
} finally {
|
|
this.setLoading(false);
|
|
}
|
|
}
|
|
|
|
showOutput(message, type = '') {
|
|
this.output.textContent = message;
|
|
this.output.className = 'output-area';
|
|
if (type) {
|
|
this.output.classList.add(type);
|
|
}
|
|
|
|
// 自动滚动到底部
|
|
this.output.scrollTop = this.output.scrollHeight;
|
|
}
|
|
|
|
setLoading(loading) {
|
|
const buttons = this.form.querySelectorAll('button');
|
|
buttons.forEach(button => {
|
|
button.disabled = loading;
|
|
});
|
|
|
|
if (loading) {
|
|
document.body.classList.add('loading');
|
|
} else {
|
|
document.body.classList.remove('loading');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 初始化应用
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
new DownloadTool();
|
|
}); |