<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<title>Songtext-PDF – Fuxxi Music</title>
<!-- jsPDF von CDN laden -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"
integrity="sha512-vvZ4O7OZKQ23T7q2whh6H60HWnYGsAlv+HYcH9WiZ6Ni5xU0y6v7fBBf2pWZfHqN7spqVWAxqN2Zp2jQm7U5BA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
max-width: 900px;
margin: 40px auto;
padding: 0 20px;
line-height: 1.4;
}
h1 {
font-size: 1.6rem;
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.25rem;
font-weight: 600;
}
input[type="text"] {
width: 100%;
padding: 0.5rem;
margin-bottom: 0.75rem;
font-size: 1rem;
}
textarea {
width: 100%;
min-height: 260px;
padding: 0.5rem;
font-size: 0.95rem;
font-family: "Courier New", monospace;
white-space: pre-wrap;
margin-bottom: 1rem;
}
.buttons {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
button {
padding: 0.5rem 1rem;
font-size: 0.95rem;
border-radius: 4px;
border: none;
cursor: pointer;
}
button.primary {
background: #0b2140;
color: #fff;
}
button.secondary {
background: #e0e4ec;
color: #0b2140;
}
.status {
font-size: 0.9rem;
color: #444;
min-height: 1.2em;
}
.logo-preview {
margin-top: 10px;
text-align: right;
}
.logo-preview img {
max-height: 60px;
}
</style>
</head>
<body>
<h1>Songtext & PDF-Generator – Fuxxi Music</h1>
<form id="songForm" onsubmit="return false;">
<label for="songTitle">Songtitel</label>
<input type="text" id="songTitle" placeholder="z.B. Imagine" />
<div class="buttons">
<button type="button" class="secondary" onclick="onFetchLyrics()">Songtext automatisch holen</button>
<button type="button" class="primary" onclick="onGeneratePdf()">PDF mit Text erstellen</button>
</div>
<label for="lyrics">Songtext (kann nach dem Laden noch bearbeitet werden)</label>
<textarea id="lyrics" placeholder="Hier erscheint der Text, oder du fügst ihn manuell ein."></textarea>
<div class="status" id="status"></div>
<div class="logo-preview">
<!-- Nur Vorschau im Browser; Pfad anpassen -->
<img src="fuxxi-music-logo.png" alt="Fuxxi Music Logo" />
</div>
</form>
<script>
const statusEl = document.getElementById("status");
function setStatus(msg, isError = false) {
statusEl.textContent = msg || "";
statusEl.style.color = isError ? "darkred" : "#444";
}
/**
* HIER musst du deine eigene Lyrics-Quelle eintragen.
* Erwartet wird ein JSON: { lyrics: "Text..." }
*/
async function fetchLyricsFromServer(title) {
// Beispiel: eigenes Backend:
// GET /lyrics?song=TITLE
// Das ist nur ein Platzhalter – bitte anpassen!
const response = await fetch("/lyrics?song=" + encodeURIComponent(title.trim()));
if (!response.ok) {
throw new Error("Serverantwort: " + response.status);
}
const data = await response.json();
if (!data.lyrics) {
throw new Error("Kein Songtext im Antwort-JSON gefunden (Feld 'lyrics').");
}
return data.lyrics;
}
async function onFetchLyrics() {
const titleInput = document.getElementById("songTitle");
const lyricsArea = document.getElementById("lyrics");
const title = titleInput.value.trim();
if (!title) {
setStatus("Bitte zuerst einen Songtitel eingeben.", true);
return;
}
setStatus("Songtext wird gesucht …");
try {
const lyrics = await fetchLyricsFromServer(title);
lyricsArea.value = lyrics.trim();
setStatus("Songtext geladen. Du kannst ihn jetzt noch bearbeiten.");
} catch (err) {
console.error(err);
setStatus("Fehler beim Laden des Songtextes: " + err.message, true);
}
}
/**
* Ermittelt, ob Hoch- oder Querformat besser passt.
* Hier relativ simpel: ab ca. 45 Zeilen -> Querformat.
*/
function chooseOrientation(lyrics) {
const lineCount = lyrics.split(/\r?\n/).length;
return lineCount > 45 ? "landscape" : "portrait";
}
/**
* Lädt das Logo-Bild, damit jsPDF es verwenden kann.
* Pfad zur Bilddatei ggf. anpassen.
*/
function loadLogoImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "anonymous"; // falls Logo auf gleicher Domain, egal
img.onload = () => resolve(img);
img.onerror = (e) => reject(new Error("Logo konnte nicht geladen werden: " + src));
img.src = src;
});
}
async function onGeneratePdf() {
const { jsPDF } = window.jspdf;
const title = document.getElementById("songTitle").value.trim();
const lyrics = document.getElementById("lyrics").value.trim();
if (!title) {
setStatus("Bitte einen Songtitel eingeben.", true);
return;
}
if (!lyrics) {
setStatus("Es ist kein Songtext vorhanden. Hole zuerst den Text oder füge ihn ein.", true);
return;
}
setStatus("PDF wird erstellt …");
try {
const orientation = chooseOrientation(lyrics);
const doc = new jsPDF({
orientation: orientation,
unit: "mm",
format: "a4"
});
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const margin = 15;
// Logo laden und oben rechts einfügen
try {
const logoImg = await loadLogoImage("fuxxi-music-logo.png"); // Pfad anpassen
const logoWidth = 30; // in mm
const logoHeight = 30;
const logoX = pageWidth - margin - logoWidth;
const logoY = 10;
doc.addImage(logoImg, "PNG", logoX, logoY, logoWidth, logoHeight);
} catch (logoError) {
console.warn(logoError.message);
// Kein harter Fehler – PDF wird auch ohne Logo erstellt
}
// Titel
doc.setFont("helvetica", "bold");
doc.setFontSize(18);
// Titel nicht unter das Logo schreiben
const titleY = 20;
doc.text(title, margin, titleY, { baseline: "top" });
// Songtext
doc.setFont("helvetica", "normal");
doc.setFontSize(12);
const textStartY = 45; // unterhalb Logo/Titel
const maxWidth = pageWidth - margin * 2;
const textLines = doc.splitTextToSize(lyrics, maxWidth);
let cursorY = textStartY;
const lineHeight = 5; // mm pro Zeile
for (let i = 0; i < textLines.length; i++) {
if (cursorY > pageHeight - margin) {
doc.addPage();
cursorY = margin;
}
doc.text(textLines[i], margin, cursorY);
cursorY += lineHeight;
}
const fileName = `$Testformular für Songtextsuche KTS.pdf`;
doc.save(fileName);
setStatus("PDF erstellt: " + fileName);
} catch (err) {
console.error(err);
setStatus("Fehler beim Erstellen des PDFs: " + err.message, true);
}
}
</script>
</body>
</html>
