Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 20 additions & 41 deletions editor/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<html xmlns="http://www.w3.org/1999/html" lang="pl">
<head>
<meta charset="UTF-8">
<script src="./pdf_renderer.js"></script>
<script type="module" src="./songbook.js"></script>
<link rel="stylesheet" href="./song.css"/>
<link rel="stylesheet" href="./ch.css"/>
Expand Down Expand Up @@ -232,7 +233,6 @@ <h2>Musisz się zalogować</h2>
}

async function renderPdf(songbook) {
notice("Generowanie PDF... Proszę czekać (może potrwać do kilkunastu sekund)", songbook);
const {serialized, title} = songbook.SerializeWithChange();
const {branch} = parseParams();

Expand All @@ -244,48 +244,27 @@ <h2>Musisz się zalogować</h2>
branch: branch || "main"
};

try {
const response = await fetch("https://songbook-pdf-render-177765940460.europe-west1.run.app/api/render/song_xml", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
// Open blank window immediately to satisfy popup blocker
const pdfWindow = window.open('about:blank', '_blank');
if (pdfWindow) {
pdfWindow.document.write("<div style='font-family: sans-serif; padding: 20px;'>Trwa generowanie PDF... Proszę czekać (zwykle około 10-20 sekund).</div>");
}

if (!response.ok) {
alert("Błąd połączenia z serwerem PDF.");
return;
renderPdfCloudRun(
payload,
"/api/render/song_xml",
() => notice("Generowanie PDF... Proszę czekać (może potrwać do kilkunastu sekund)", songbook),
(url) => {
notice("PDF wygenerowany!", songbook);
if (pdfWindow) pdfWindow.location.href = url;
else window.open(url, '_blank');
},
(err, errUrl) => {
alert(err);
if (pdfWindow && errUrl) pdfWindow.location.href = errUrl;
else if (pdfWindow) pdfWindow.close();
}

const data = await response.json();
const jobId = data.job_id;

// Poll for completion
const pollInterval = setInterval(async () => {
try {
const statusRes = await fetch(`https://songbook-pdf-render-177765940460.europe-west1.run.app/api/jobs/${jobId}`);
if (statusRes.ok) {
const statusData = await statusRes.json();
if (statusData.status === "done") {
clearInterval(pollInterval);
notice("PDF wygenerowany!", songbook);
window.open(`https://songbook-pdf-render-177765940460.europe-west1.run.app${statusData.url}`, "_blank");
} else if (statusData.status === "error") {
clearInterval(pollInterval);
alert("Błąd generowania PDF. Zobacz logi.");
window.open(`https://songbook-pdf-render-177765940460.europe-west1.run.app${statusData.url}`, "_blank");
}
}
} catch (e) {
console.error("Polling error", e);
}
}, 2000);

} catch (error) {
console.error("PDF render error", error);
alert("Błąd wysyłania do serwera PDF.");
}
);
}


Expand Down
47 changes: 47 additions & 0 deletions editor/pdf_renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Shared PDF rendering logic for Cloud Run
async function renderPdfCloudRun(payload, endpoint, onLoading, onSuccess, onError) {
onLoading();

try {
const response = await fetch(`https://songbook-pdf-render-177765940460.europe-west1.run.app${endpoint}`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});

if (!response.ok) {
onError("Błąd połączenia z serwerem PDF.");
return;
}

const data = await response.json();
const jobId = data.job_id;

// Poll for completion
const pollInterval = setInterval(async () => {
try {
const statusRes = await fetch(`https://songbook-pdf-render-177765940460.europe-west1.run.app/api/jobs/${jobId}`);
if (statusRes.ok) {
const statusData = await statusRes.json();
if (statusData.status === "done") {
clearInterval(pollInterval);
const finalUrl = `https://songbook-pdf-render-177765940460.europe-west1.run.app${statusData.url}`;
onSuccess(finalUrl);
} else if (statusData.status === "error") {
clearInterval(pollInterval);
const errorUrl = `https://songbook-pdf-render-177765940460.europe-west1.run.app${statusData.url}`;
onError("Błąd generowania PDF. Zobacz logi.", errorUrl);
}
}
} catch (e) {
console.error("Polling error", e);
}
}, 2000);

} catch (error) {
console.error("PDF render error", error);
onError("Błąd wysyłania do serwera PDF.");
}
}
6 changes: 6 additions & 0 deletions src/html/index_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ def main():
os.remove(common_js_path)
os.symlink(os.path.join(sb.repo_dir(), 'src', 'html', 'templates', "common.js"), common_js_path)

# Create symlink for pdf_renderer.js
pdf_renderer_js_path = os.path.join(target_dir, "pdf_renderer.js")
if os.path.exists(pdf_renderer_js_path):
os.remove(pdf_renderer_js_path)
os.symlink(os.path.join(sb.repo_dir(), 'editor', "pdf_renderer.js"), pdf_renderer_js_path)

# Create symlinks for songbook_edit files
songbook_edit_files = ["songbook_edit.html", "songbook_edit.js", "songbook_edit.css"]
for filename in songbook_edit_files:
Expand Down
31 changes: 22 additions & 9 deletions src/html/templates/songbook_edit/songbook_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,35 @@ <h3>Wybrane piosenki</h3>

<div class="action-buttons">
<button class="btn btn-secondary" onclick="clearSelection()">Wyczyść</button>
<button class="btn btn-primary" onclick="generateYAML()">Generuj YAML</button>
<button class="btn btn-primary" id="btnRenderPdf" onclick="renderPDF()">Generuj Śpiewnik (PDF)</button>
</div>

<div class="output-area" id="outputArea" style="display: none;">
<label><strong>Wygenerowany plik YAML:</strong></label>
<textarea id="yamlOutput" readonly></textarea>
<div class="action-buttons">
<button class="btn btn-primary" onclick="downloadYAML()">Pobierz plik .yaml</button>
<button class="btn btn-secondary" onclick="copyToClipboard()">Kopiuj do schowka</button>
<button class="btn btn-primary" onclick="renderPDF()">Podgląd PDF</button>
</div>
<div class="output-area" id="pdfOutputArea" style="display: none; text-align: center; margin-top: 15px;">
<p id="pdfStatusText">Trwa generowanie śpiewnika... Proszę czekać (zwykle około 15-30 sekund).</p>
<a id="pdfDownloadLink" href="#" target="_blank" class="btn btn-primary" style="display: none; width: 100%; box-sizing: border-box; text-align: center; text-decoration: none; padding: 15px; font-size: 1.1em; background-color: #2e7d32;">Gotowe! Kliknij tutaj, aby pobrać i otworzyć PDF</a>
</div>

<details style="margin-top: 30px; border-top: 1px solid #eee; padding-top: 10px;">
<summary style="cursor: pointer; color: #666; font-size: 0.9em; padding: 5px 0;">Opcje dla zaawansowanych (YAML)</summary>
<div style="margin-top: 10px;">
<div class="action-buttons">
<button class="btn btn-secondary" onclick="generateYAML()">Wyświetl kod YAML</button>
</div>
<div class="output-area" id="outputArea" style="display: none;">
<label><strong>Wygenerowany plik YAML:</strong></label>
<textarea id="yamlOutput" readonly></textarea>
<div class="action-buttons">
<button class="btn btn-primary" onclick="downloadYAML()">Pobierz plik .yaml</button>
<button class="btn btn-secondary" onclick="copyToClipboard()">Kopiuj do schowka</button>
</div>
</div>
</div>
</details>
</div>
</div>
</div>

<script src="pdf_renderer.js"></script>
<script src="common.js"></script>
<script src="songbook_edit.js"></script>
</body>
Expand Down
116 changes: 55 additions & 61 deletions src/html/templates/songbook_edit/songbook_edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ function renderDynamicFilters() {
`}).join('');
}

function generateYAML() {
function generateYAMLString() {
const songbookId = document.getElementById('songbookId').value.trim();
const songbookTitle = document.getElementById('songbookTitle').value.trim();
const songbookSubtitle = document.getElementById('songbookSubtitle').value.trim();
Expand All @@ -512,17 +512,17 @@ function generateYAML() {

if (!songbookId) {
alert('Proszę podać ID śpiewnika');
return;
return null;
}

if (!songbookTitle) {
alert('Proszę podać tytuł śpiewnika');
return;
return null;
}

if (selectedSongIds.size === 0 && dynamicFilters.length === 0) {
alert('Proszę wybrać przynajmniej jedną piosenkę lub dodać filtr');
return;
return null;
}

// Generate UUID
Expand Down Expand Up @@ -568,9 +568,15 @@ function generateYAML() {
}
});

const yaml = JSON.stringify({ songbook }, null, 2);
document.getElementById('yamlOutput').value = yaml;
document.getElementById('outputArea').style.display = 'block';
return JSON.stringify({ songbook }, null, 2);
}

function generateYAML() {
const yaml = generateYAMLString();
if (yaml) {
document.getElementById('yamlOutput').value = yaml;
document.getElementById('outputArea').style.display = 'block';
}
}

function generateUUID() {
Expand Down Expand Up @@ -612,7 +618,7 @@ function copyToClipboard() {
}

async function renderPDF() {
const yaml = document.getElementById('yamlOutput').value;
const yaml = generateYAMLString();
if (!yaml) return;

// Get branch from URL or default to main
Expand All @@ -625,64 +631,52 @@ async function renderPDF() {
papersize: "a4"
};

try {
// Show loading notice
const btn = document.querySelector('button[onclick="renderPDF()"]');
const originalText = btn.textContent;
btn.textContent = "Generowanie...";
btn.disabled = true;

const response = await fetch("https://songbook-pdf-render-177765940460.europe-west1.run.app/api/render/songbook_yaml", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const btn = document.getElementById('btnRenderPdf');
const pdfOutputArea = document.getElementById('pdfOutputArea');
const pdfStatusText = document.getElementById('pdfStatusText');
const pdfDownloadLink = document.getElementById('pdfDownloadLink');

if (pdfOutputArea) pdfOutputArea.style.display = 'block';
if (pdfStatusText) {
pdfStatusText.style.display = 'block';
pdfStatusText.textContent = "Trwa generowanie śpiewnika... Proszę czekać (zwykle około 15-30 sekund).";
}
if (pdfDownloadLink) pdfDownloadLink.style.display = 'none';

if (!response.ok) {
alert("Błąd połączenia z serwerem PDF.");
btn.textContent = originalText;
btn.disabled = false;
return;
// Open blank window immediately to satisfy popup blocker
let pdfWindow = null;
try {
pdfWindow = window.open('about:blank', '_blank');
if (pdfWindow) {
pdfWindow.document.write("<div style='font-family: sans-serif; padding: 20px; text-align: center; margin-top: 50px;'>Trwa generowanie śpiewnika PDF... Proszę czekać (zwykle około 15-30 sekund).</div>");
}
} catch (e) {
console.warn("Could not open new window automatically", e);
}

const data = await response.json();
const jobId = data.job_id;

// Poll for completion
const pollInterval = setInterval(async () => {
try {
const statusRes = await fetch(`https://songbook-pdf-render-177765940460.europe-west1.run.app/api/jobs/${jobId}`);
if (statusRes.ok) {
const statusData = await statusRes.json();
if (statusData.status === "done") {
clearInterval(pollInterval);
btn.textContent = originalText;
btn.disabled = false;
window.open(`https://songbook-pdf-render-177765940460.europe-west1.run.app${statusData.url}`, "_blank");
} else if (statusData.status === "error") {
clearInterval(pollInterval);
alert("Błąd generowania PDF. Sprawdź logi.");
btn.textContent = originalText;
btn.disabled = false;
window.open(`https://songbook-pdf-render-177765940460.europe-west1.run.app${statusData.url}`, "_blank");
}
}
} catch (e) {
console.error("Polling error", e);
renderPdfCloudRun(
payload,
"/api/render/songbook_yaml",
() => {
if (btn) btn.disabled = true;
},
(url) => {
if (btn) btn.disabled = false;
if (pdfStatusText) pdfStatusText.style.display = 'none';
if (pdfDownloadLink) {
pdfDownloadLink.href = url;
pdfDownloadLink.style.display = 'block';
}
}, 2000);

} catch (error) {
console.error("PDF render error", error);
alert("Błąd wysyłania do serwera PDF.");
const btn = document.querySelector('button[onclick="renderPDF()"]');
if (btn) {
btn.textContent = "Podgląd PDF";
btn.disabled = false;
if (pdfWindow) pdfWindow.location.href = url;
},
(err, errUrl) => {
alert(err);
if (btn) btn.disabled = false;
if (pdfStatusText) pdfStatusText.textContent = err;
if (pdfWindow && errUrl) pdfWindow.location.href = errUrl;
else if (pdfWindow) pdfWindow.close();
}
}
);
}

// Auto-generate songbook ID from title
Expand Down
Loading