|
|
|
function debug(message) { |
|
console.log(`[Debug] ${message}`); |
|
} |
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
debug("UI initialized"); |
|
|
|
|
|
const urlForm = document.getElementById('url-form'); |
|
const pdfForm = document.getElementById('pdf-form'); |
|
const tabButtons = document.querySelectorAll('.tab-btn'); |
|
const tabPanes = document.querySelectorAll('.tab-pane'); |
|
const fileInput = document.getElementById('pdf-file'); |
|
const fileNameDisplay = document.querySelector('.file-name'); |
|
const resultsContainer = document.getElementById('results'); |
|
const resultsGrid = document.querySelector('.results-grid'); |
|
const progressContainer = document.querySelector('.progress-container'); |
|
const progressText = document.querySelector('.progress-text'); |
|
const progressFill = document.querySelector('.progress-fill'); |
|
const tryNowBtn = document.getElementById('try-now-btn'); |
|
|
|
|
|
if (tryNowBtn) { |
|
tryNowBtn.addEventListener('click', function() { |
|
const translatorSection = document.getElementById('translator'); |
|
translatorSection.scrollIntoView({ behavior: 'smooth' }); |
|
}); |
|
} |
|
|
|
|
|
tabButtons.forEach(button => { |
|
button.addEventListener('click', function() { |
|
|
|
const tabId = this.getAttribute('data-tab'); |
|
|
|
|
|
tabButtons.forEach(btn => btn.classList.remove('active')); |
|
tabPanes.forEach(pane => pane.classList.remove('active')); |
|
|
|
|
|
this.classList.add('active'); |
|
document.getElementById(tabId).classList.add('active'); |
|
|
|
debug(`Switched to tab: ${tabId}`); |
|
}); |
|
}); |
|
|
|
|
|
if (fileInput) { |
|
fileInput.addEventListener('change', function() { |
|
if (this.files.length > 0) { |
|
const fileName = this.files[0].name; |
|
fileNameDisplay.textContent = fileName; |
|
debug(`Selected file: ${fileName}`); |
|
} else { |
|
fileNameDisplay.textContent = 'No file chosen'; |
|
} |
|
}); |
|
} |
|
|
|
|
|
if (urlForm) { |
|
urlForm.addEventListener('submit', async function(e) { |
|
e.preventDefault(); |
|
|
|
|
|
const url = document.getElementById('manga-url').value; |
|
const srcLang = document.getElementById('url-src-lang').value; |
|
const tgtLang = document.getElementById('url-tgt-lang').value; |
|
|
|
debug(`Submitting URL form with url=${url}, srcLang=${srcLang}, tgtLang=${tgtLang}`); |
|
|
|
|
|
resultsGrid.innerHTML = ''; |
|
progressFill.style.width = '0%'; |
|
progressText.textContent = 'Preparing translation...'; |
|
progressContainer.style.display = 'block'; |
|
|
|
|
|
try { |
|
|
|
const requestBody = { |
|
url: url, |
|
src_lang: srcLang, |
|
tgt_lang: tgtLang, |
|
translator: 'google' |
|
}; |
|
|
|
|
|
await handleTranslation('/translate/url', requestBody); |
|
|
|
} catch (error) { |
|
debug(`Error during URL translation: ${error}`); |
|
showError("An error occurred during translation. Please try again."); |
|
} |
|
}); |
|
} |
|
|
|
|
|
if (pdfForm) { |
|
pdfForm.addEventListener('submit', async function(e) { |
|
e.preventDefault(); |
|
|
|
|
|
if (!fileInput.files[0]) { |
|
showError("Please select a PDF file first."); |
|
return; |
|
} |
|
|
|
|
|
const file = fileInput.files[0]; |
|
const srcLang = document.getElementById('pdf-src-lang').value; |
|
const tgtLang = document.getElementById('pdf-tgt-lang').value; |
|
|
|
debug(`Submitting PDF form with file=${file.name}, srcLang=${srcLang}, tgtLang=${tgtLang}`); |
|
|
|
|
|
resultsGrid.innerHTML = ''; |
|
progressFill.style.width = '0%'; |
|
progressText.textContent = 'Preparing PDF translation...'; |
|
progressContainer.style.display = 'block'; |
|
|
|
|
|
const formData = new FormData(); |
|
formData.append('file', file); |
|
formData.append('src_lang', srcLang); |
|
formData.append('tgt_lang', tgtLang); |
|
formData.append('translator', 'google'); |
|
|
|
|
|
try { |
|
|
|
await handlePdfTranslation('/translate/pdf', formData); |
|
|
|
} catch (error) { |
|
debug(`Error during PDF translation: ${error}`); |
|
showError("An error occurred during translation. Please try again."); |
|
} |
|
}); |
|
} |
|
|
|
|
|
async function handleTranslation(endpoint, requestBody) { |
|
try { |
|
const response = await fetch(endpoint, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify(requestBody) |
|
}); |
|
|
|
if (!response.ok) { |
|
throw new Error(`HTTP error! status: ${response.status}`); |
|
} |
|
|
|
const reader = response.body.getReader(); |
|
const decoder = new TextDecoder(); |
|
|
|
let receivedImages = 0; |
|
let totalImages = 5; |
|
|
|
while (true) { |
|
const { value, done } = await reader.read(); |
|
|
|
if (done) { |
|
break; |
|
} |
|
|
|
|
|
const text = decoder.decode(value, { stream: true }); |
|
const lines = text.split('\n\n'); |
|
|
|
for (const line of lines) { |
|
if (line.startsWith('data: ')) { |
|
try { |
|
const data = JSON.parse(line.substring(6)); |
|
processTranslationUpdate(data, receivedImages, totalImages); |
|
|
|
if (data.status === 'success' && data.image_url) { |
|
receivedImages++; |
|
updateProgress(receivedImages, totalImages); |
|
} else if (data.status === 'complete') { |
|
progressContainer.style.display = 'none'; |
|
} |
|
} catch (e) { |
|
debug(`Error parsing JSON: ${e}`); |
|
} |
|
} |
|
} |
|
} |
|
|
|
} catch (error) { |
|
debug(`Error during translation: ${error}`); |
|
showError("An error occurred during translation. Please try again."); |
|
} |
|
} |
|
|
|
|
|
async function handlePdfTranslation(endpoint, formData) { |
|
try { |
|
const response = await fetch(endpoint, { |
|
method: 'POST', |
|
body: formData |
|
}); |
|
|
|
if (!response.ok) { |
|
throw new Error(`HTTP error! status: ${response.status}`); |
|
} |
|
|
|
const reader = response.body.getReader(); |
|
const decoder = new TextDecoder(); |
|
|
|
let receivedImages = 0; |
|
let totalImages = 5; |
|
|
|
while (true) { |
|
const { value, done } = await reader.read(); |
|
|
|
if (done) { |
|
break; |
|
} |
|
|
|
|
|
const text = decoder.decode(value, { stream: true }); |
|
const lines = text.split('\n\n'); |
|
|
|
for (const line of lines) { |
|
if (line.startsWith('data: ')) { |
|
try { |
|
const data = JSON.parse(line.substring(6)); |
|
processTranslationUpdate(data, receivedImages, totalImages); |
|
|
|
if (data.status === 'success' && data.image_url) { |
|
receivedImages++; |
|
updateProgress(receivedImages, totalImages); |
|
} else if (data.status === 'complete') { |
|
progressContainer.style.display = 'none'; |
|
} |
|
} catch (e) { |
|
debug(`Error parsing JSON: ${e}`); |
|
} |
|
} |
|
} |
|
} |
|
|
|
} catch (error) { |
|
debug(`Error during translation: ${error}`); |
|
showError("An error occurred during translation. Please try again."); |
|
} |
|
} |
|
|
|
|
|
function processTranslationUpdate(data, currentImage, totalImages) { |
|
debug(`Received update: ${JSON.stringify(data)}`); |
|
|
|
if (data.status === 'error') { |
|
showError(data.message || "An error occurred during translation."); |
|
progressContainer.style.display = 'none'; |
|
return; |
|
} |
|
|
|
if (data.status === 'processing') { |
|
progressText.textContent = data.message || `Processing image ${currentImage + 1}/${totalImages}...`; |
|
return; |
|
} |
|
|
|
if (data.status === 'success' && data.image_url) { |
|
|
|
addImageToResults(data.image_url); |
|
} |
|
|
|
if (data.status === 'complete') { |
|
progressText.textContent = 'Translation complete!'; |
|
progressFill.style.width = '100%'; |
|
setTimeout(() => { |
|
progressContainer.style.display = 'none'; |
|
}, 1000); |
|
} |
|
} |
|
|
|
|
|
function updateProgress(current, total) { |
|
const percentage = Math.min(Math.round((current / total) * 100), 100); |
|
progressFill.style.width = `${percentage}%`; |
|
progressText.textContent = `Processing page ${current}/${total}...`; |
|
} |
|
|
|
|
|
function addImageToResults(imageUrl) { |
|
|
|
const resultCard = document.createElement('div'); |
|
resultCard.className = 'result-card'; |
|
|
|
|
|
const img = document.createElement('img'); |
|
img.className = 'result-image'; |
|
img.src = imageUrl; |
|
img.alt = 'Translated Image'; |
|
img.loading = 'lazy'; |
|
|
|
|
|
const actionsDiv = document.createElement('div'); |
|
actionsDiv.className = 'result-actions'; |
|
|
|
|
|
const downloadLink = document.createElement('a'); |
|
downloadLink.href = imageUrl; |
|
downloadLink.download = 'translated-' + imageUrl.split('/').pop(); |
|
downloadLink.className = 'btn'; |
|
downloadLink.innerHTML = '<i class="fas fa-download"></i> Download'; |
|
|
|
|
|
const viewLink = document.createElement('a'); |
|
viewLink.href = imageUrl; |
|
viewLink.target = '_blank'; |
|
viewLink.className = 'btn'; |
|
viewLink.innerHTML = '<i class="fas fa-external-link-alt"></i> View'; |
|
|
|
|
|
actionsDiv.appendChild(downloadLink); |
|
actionsDiv.appendChild(viewLink); |
|
resultCard.appendChild(img); |
|
resultCard.appendChild(actionsDiv); |
|
resultsGrid.appendChild(resultCard); |
|
} |
|
|
|
|
|
function showError(message) { |
|
resultsGrid.innerHTML = ` |
|
<div class="error-message"> |
|
<i class="fas fa-exclamation-circle"></i> |
|
<p>${message}</p> |
|
</div> |
|
`; |
|
} |
|
|
|
|
|
function createPlaceholderImage() { |
|
const placeholderUrl = '/static/ui/placeholder.png'; |
|
debug('Creating placeholder UI example'); |
|
|
|
|
|
if (resultsGrid.children.length === 0) { |
|
addImageToResults(placeholderUrl); |
|
addImageToResults(placeholderUrl); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
}); |