Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
042d00292b |
|
|
@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|||
|
||||
[project]
|
||||
name = "forgejo-blog-manager"
|
||||
version = "0.1.4"
|
||||
description = "Blog-Manager für Uberspace 8 mit Marvin API und Pelican sowie DOCX-Konvertierung"
|
||||
version = "0.1.5"
|
||||
description = "Blog-Manager für Uberspace 8 mit Marvin API, Pelican und DOCX-Konvertierung"
|
||||
authors = [{name = "Ihre Autorin", email = "autorin@example.com"}]
|
||||
license = {text = "MIT"}
|
||||
readme = "README.md"
|
||||
|
|
@ -30,4 +30,7 @@ package-dir = {"" = "src"}
|
|||
packages = ["dlw"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"dlw" = ["ssg_config/*", "ssg_config/templates/*"]
|
||||
"dlw" = [
|
||||
"ssg_config/*",
|
||||
"templates/**/*.j2"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
"""
|
||||
DLW Frontend - Web-Interface für die DOCX-zu-PDF Konvertierung.
|
||||
|
||||
Dieses Modul stellt eine Flask-App bereit, die es Autorinnen ermöglicht,
|
||||
Word-Dokumente hochzuladen und direkt als PDF im Browser zurückzuerhalten.
|
||||
Genutzt werden dafür Mammoth (Struktur) und WeasyPrint (Layout).
|
||||
"""
|
||||
|
||||
from flask import Flask, render_template, request, send_file
|
||||
from dlw.convert import convert_docx_to_pdf_stream
|
||||
import os
|
||||
|
||||
# --- Konfiguration der Verzeichnisstruktur ---
|
||||
# Wir ermitteln den absoluten Pfad zum zentralen Template-Ordner,
|
||||
# damit Flask die Jinja2-Dateien auch dann findet, wenn die App
|
||||
# aus einem anderen Verzeichnis gestartet wird.
|
||||
base_dir = os.path.dirname(__file__)
|
||||
template_dir = os.path.abspath(os.path.join(base_dir, 'templates'))
|
||||
|
||||
app = Flask(__name__, template_folder=template_dir)
|
||||
|
||||
# Begrenzung der Upload-Größe auf 16 Megabyte, um den Server zu schützen.
|
||||
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def index():
|
||||
"""
|
||||
Haupt-Route für den Konverter.
|
||||
|
||||
GET: Zeigt das Upload-Formular an.
|
||||
POST: Verarbeitet das hochgeladene DOCX, konvertiert es in ein PDF-Stream
|
||||
und sendet dieses als Download an den Client zurück.
|
||||
"""
|
||||
if request.method == 'POST':
|
||||
# 1. Validierung: Prüfen, ob überhaupt ein Datei-Teil im Request ist
|
||||
if 'file' not in request.files:
|
||||
return "Fehler: Kein Datei-Feld im Formular gefunden.", 400
|
||||
|
||||
file = request.files['file']
|
||||
|
||||
# 2. Validierung: Prüfen, ob eine Datei ausgewählt wurde
|
||||
if file.filename == '':
|
||||
return "Fehler: Es wurde keine Datei zum Hochladen ausgewählt.", 400
|
||||
|
||||
# 3. Verarbeitung: Nur .docx Dateien zulassen
|
||||
if file and file.filename.endswith('.docx'):
|
||||
try:
|
||||
# Wir lesen die Datei direkt in den Arbeitsspeicher (Bytes)
|
||||
docx_bytes = file.read()
|
||||
|
||||
# Konvertierung via Mammoth & WeasyPrint (gibt BytesIO Stream zurück)
|
||||
pdf_stream = convert_docx_to_pdf_stream(docx_bytes)
|
||||
|
||||
# Dynamische Generierung des Dateinamens (aus .docx wird .pdf)
|
||||
download_name = file.filename.replace('.docx', '.pdf')
|
||||
|
||||
# PDF-Stream als Download an den Browser senden
|
||||
return send_file(
|
||||
pdf_stream,
|
||||
mimetype='application/pdf',
|
||||
as_attachment=True,
|
||||
download_name=download_name
|
||||
)
|
||||
except Exception as e:
|
||||
# Grobe Fehlerbehandlung für den MVP-Status
|
||||
return f"Interner Fehler bei der Konvertierung: {str(e)}", 500
|
||||
|
||||
# Falls GET-Request oder fehlerhafter Dateityp: Zeige das Formular
|
||||
# Der Pfad 'app/converter.html.j2' bezieht sich auf den template_folder
|
||||
return render_template('app/converter.html.j2')
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Startet den lokalen Entwicklungs-Server.
|
||||
# 'debug=True' sorgt für automatisches Neuladen bei Code-Änderungen.
|
||||
app.run(debug=True, port=5000)
|
||||
|
|
@ -1,3 +1,14 @@
|
|||
import os
|
||||
|
||||
# --- Dynamische Pfadberechnung ---
|
||||
# Ermittelt den absoluten Pfad zum Verzeichnis dieser Datei (src/dlw/ssg_config)
|
||||
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Setzt den Theme-Pfad auf den neuen zentralen Ort (src/dlw/templates/ssg)
|
||||
# Wir gehen eine Ebene hoch (..) und dann in den templates/ssg Ordner
|
||||
THEME = os.path.join(CURRENT_DIR, '..', 'templates', 'ssg')
|
||||
|
||||
# --- Allgemeine Website-Einstellungen ---
|
||||
AUTHOR = 'Ihre Autorin'
|
||||
SITENAME = 'Forgejo Blog'
|
||||
SITEURL = ''
|
||||
|
|
@ -5,11 +16,12 @@ PATH = 'content'
|
|||
TIMEZONE = 'Europe/Berlin'
|
||||
DEFAULT_LANG = 'de'
|
||||
|
||||
# --- URL-Struktur ---
|
||||
ARTICLE_URL = 'blog/{slug}/'
|
||||
ARTICLE_SAVE_AS = 'blog/{slug}/index.html'
|
||||
STATIC_PATHS = ['downloads', 'images']
|
||||
THEME = 'ssg_config/templates'
|
||||
|
||||
# --- Markdown-Konfiguration ---
|
||||
MARKDOWN = {
|
||||
'extension_configs': {
|
||||
'markdown.extensions.extra': {},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DLW - DOCX zu PDF</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, system-ui, sans-serif;
|
||||
max-width: 500px;
|
||||
margin: 100px auto;
|
||||
background: #f4f7f6;
|
||||
color: #2c3e50;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
padding: 40px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.05);
|
||||
}
|
||||
h1 { font-size: 1.25rem; margin-bottom: 20px; text-align: center; }
|
||||
.upload-area {
|
||||
border: 2px dashed #cbd5e0;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
background: #4a90e2;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover { background: #357abd; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Word-Konverter für Autorinnen</h1>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="upload-area">
|
||||
<input type="file" name="file" accept=".docx" required>
|
||||
</div>
|
||||
<button type="submit">PDF generieren</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue