Compare commits
9 Commits
e94bd7eb29
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 544d6c866c | |||
| 2d93109831 | |||
| ba9d4afaa6 | |||
| c10bfaa87c | |||
| fa5e52f185 | |||
| 5b031095fa | |||
| 501855ee87 | |||
| 8cf7b70fad | |||
| 3faa7c6ee0 |
@@ -0,0 +1,4 @@
|
|||||||
|
public/
|
||||||
|
resources/
|
||||||
|
.hugo_build.lock
|
||||||
|
.idea/
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
[submodule "themes/gallery"]
|
[submodule "themes/gallery"]
|
||||||
path = themes/gallery
|
path = themes/gallery
|
||||||
url = https://github.com/nicokaiser/hugo-theme-gallery.git
|
url = https://github.com/nicokaiser/hugo-theme-gallery.git
|
||||||
|
[submodule "themes/hugo-video"]
|
||||||
|
path = themes/hugo-video
|
||||||
|
url = https://github.com/martignoni/hugo-video.git
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# rsync -arzP --exclude-from='.rsyncignore' ./ netadmin@4koetter.com:~/plassonke.de
|
||||||
|
|
||||||
|
.git/
|
||||||
|
public/
|
||||||
|
resources/
|
||||||
|
.hugo_build.lock
|
||||||
|
.idea/
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
FROM hugomods/hugo:exts AS builder
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY archetypes/ archetypes/
|
||||||
|
COPY themes/ themes/
|
||||||
|
COPY layouts/ layouts/
|
||||||
|
COPY static/ static/
|
||||||
|
COPY assets/ assets/
|
||||||
|
COPY content/ content/
|
||||||
|
COPY hugo.toml .
|
||||||
|
|
||||||
|
RUN hugo --gc --minify
|
||||||
|
|
||||||
|
FROM alpine:3.20 AS video-posters
|
||||||
|
|
||||||
|
RUN apk add --no-cache python3 ffmpeg
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
COPY --from=builder /src/public /src/public
|
||||||
|
COPY scripts/add-video-posters.py /add-video-posters.py
|
||||||
|
|
||||||
|
RUN python3 /add-video-posters.py /src/public
|
||||||
|
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
RUN apk add --no-cache openssl
|
||||||
|
|
||||||
|
COPY --from=video-posters /src/public /usr/share/nginx/html
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||||
|
|
||||||
|
RUN chmod +x /docker-entrypoint.sh
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
@@ -199,6 +199,20 @@ body > header {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Album card hover ─────────────────────────────────── */
|
||||||
|
|
||||||
|
section.galleries .card figure {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.galleries .card img {
|
||||||
|
transition: transform 0.6s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.galleries .card img:hover {
|
||||||
|
transform: scale(1.06);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Album card text ──────────────────────────────────── */
|
/* ── Album card text ──────────────────────────────────── */
|
||||||
|
|
||||||
.card > div > h2 {
|
.card > div > h2 {
|
||||||
@@ -264,6 +278,30 @@ body > header {
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Videos ────────────────────────────────── */
|
||||||
|
|
||||||
|
.prose {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
padding: 0;
|
||||||
|
padding-top: 4rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
max-width: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 500px) {
|
||||||
|
.prose {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose video {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Gallery back link ────────────────────────────────── */
|
/* ── Gallery back link ────────────────────────────────── */
|
||||||
|
|
||||||
.gallery-back {
|
.gallery-back {
|
||||||
|
|||||||
+16
-4
@@ -1,11 +1,23 @@
|
|||||||
---
|
---
|
||||||
title: "Herzlich Willkommen"
|
title: "Lina & Marlin"
|
||||||
params:
|
params:
|
||||||
tagline: "Schön, dass ihr da seid."
|
tagline: "Alles Liebe zu eurer Hochzeit"
|
||||||
albums_label: "Alben"
|
albums_label: "Alben"
|
||||||
closing: "20. Juni 2026"
|
closing: "20. Juni 2026"
|
||||||
---
|
---
|
||||||
|
|
||||||
Hier findet ihr die Erinnerungen an unseren besonderen Tag — festgehalten in Bildern, die für immer bleiben.
|
Liebe Lina, lieber Marlin,
|
||||||
|
|
||||||
Schreibt euch diesen Moment ins Gedächtnis: die Musik, das Lachen, die Umarmungen. Wir freuen uns, ihn mit euch geteilt zu haben.
|
vielleicht habt ihr euren Fehler bereits gefunden?
|
||||||
|
Die Domain `z.app` als Geschenk zu verbieten ist nicht genug, wenn `plassonke.de` noch verfügbar ist.
|
||||||
|
Deshalb bekommt ihr diese jetzt als Teil eures Geschenkes.
|
||||||
|
|
||||||
|
Da ihr dieses Geschenk erst im Nachhinein bekommt, können wir uns Linas große Freude über die erste eigene Domain wohl nur vorstellen.
|
||||||
|
Da es leider kein `z.app` für Marlin gibt, kannst du diese Freude aber teilen.
|
||||||
|
Wenn ihr schon keinen Doppelnamen nehmt, kann man stattdessen vielleicht `zapp.plassonke.de` nutzen.
|
||||||
|
Dann ist auch für Marlin etwas dabei.
|
||||||
|
|
||||||
|
Falls die Freude über die Domain irgendwann doch etwas abebbt,
|
||||||
|
könnt ihr euch hoffentlich mit den Bildern an einen tollen Tag zurückerinnern.
|
||||||
|
|
||||||
|
Wir wünschen euch alles Gute für eure gemeinsame Zukunft!
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: "Empfang"
|
title: "Empfang"
|
||||||
date: 2026-06-20
|
date: 2026-06-10
|
||||||
weight: 2
|
weight: 2
|
||||||
|
resources:
|
||||||
|
- src: IMG_1574.png
|
||||||
|
params:
|
||||||
|
cover: true
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: "Feier"
|
title: "Feier"
|
||||||
date: 2026-06-20
|
date: 2026-06-10
|
||||||
weight: 4
|
weight: 4
|
||||||
|
resources:
|
||||||
|
- src: IMG_1625.png
|
||||||
|
params:
|
||||||
|
cover: true
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -7,3 +7,7 @@ resources:
|
|||||||
params:
|
params:
|
||||||
cover: true
|
cover: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
{{< video src="test.mp4" >}}
|
||||||
|
|
||||||
|
{{< video src="test2.mp4" >}}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: "Zeremonie"
|
title: "Zeremonie"
|
||||||
date: 2026-06-20
|
date: 2026-06-10
|
||||||
weight: 3
|
weight: 3
|
||||||
|
resources:
|
||||||
|
- src: IMG_1474.png
|
||||||
|
params:
|
||||||
|
cover: true
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
- reverse-proxy_shared
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
AUTH_USER: hochzeit
|
||||||
|
AUTH_PASS: changeme
|
||||||
|
|
||||||
|
networks:
|
||||||
|
reverse-proxy_shared:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
echo "${AUTH_USER}:$(openssl passwd -apr1 "${AUTH_PASS}")" > /etc/nginx/.htpasswd
|
||||||
|
exec nginx -g "daemon off;"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
baseURL = "https://plassonke.de/"
|
baseURL = "https://plassonke.de/"
|
||||||
title = "Hochzeit"
|
title = "Hochzeit"
|
||||||
theme = "gallery"
|
theme = ["hugo-video", "gallery"]
|
||||||
defaultContentLanguage = "de"
|
defaultContentLanguage = "de"
|
||||||
disableKinds = ["taxonomy"]
|
disableKinds = ["taxonomy"]
|
||||||
enableRobotsTXT = true
|
enableRobotsTXT = true
|
||||||
@@ -10,7 +10,8 @@ timeout = "120s"
|
|||||||
|
|
||||||
[params]
|
[params]
|
||||||
defaultTheme = "light"
|
defaultTheme = "light"
|
||||||
description = "Hochzeit"
|
description = "Fotos von Linas und Marlins Hochzeit"
|
||||||
|
images = ["content/hero.png"]
|
||||||
title = "Hochzeit"
|
title = "Hochzeit"
|
||||||
[params.author]
|
[params.author]
|
||||||
name = "Yannis Vierkoetter"
|
name = "Yannis Vierkoetter"
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
auth_basic "Hochzeit";
|
||||||
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
|
||||||
|
VIDEO_TAG_RE = re.compile(
|
||||||
|
r"<video(?P<attrs>[^>]*)>(?P<body>.*?)</video>",
|
||||||
|
re.IGNORECASE | re.DOTALL,
|
||||||
|
)
|
||||||
|
|
||||||
|
SOURCE_RE = re.compile(
|
||||||
|
r'<source[^>]+src=["\'](?P<src>[^"\']+)["\'][^>]*>',
|
||||||
|
re.IGNORECASE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_src(video_attrs: str, video_body: str) -> str | None:
|
||||||
|
"""Extract video path from either <video src=""> or nested <source src="">."""
|
||||||
|
|
||||||
|
video_src = re.search(r'src=["\']([^"\']+)["\']', video_attrs, re.IGNORECASE)
|
||||||
|
if video_src:
|
||||||
|
return video_src.group(1)
|
||||||
|
|
||||||
|
source_src = SOURCE_RE.search(video_body)
|
||||||
|
if source_src:
|
||||||
|
return source_src.group("src")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def make_poster(video_path: Path, poster_path: Path) -> None:
|
||||||
|
"""Extract a poster frame from a video using ffmpeg."""
|
||||||
|
|
||||||
|
poster_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
"ffmpeg",
|
||||||
|
"-y",
|
||||||
|
"-ss",
|
||||||
|
"00:00:01",
|
||||||
|
"-i",
|
||||||
|
str(video_path),
|
||||||
|
"-frames:v",
|
||||||
|
"1",
|
||||||
|
"-q:v",
|
||||||
|
"3",
|
||||||
|
str(poster_path),
|
||||||
|
],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def process_file(html_file: Path, root: Path) -> None:
|
||||||
|
"""Replace video preload mode and add poster attributes."""
|
||||||
|
|
||||||
|
content = html_file.read_text(encoding="utf-8")
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
def replace_video(match: re.Match[str]) -> str:
|
||||||
|
nonlocal changed
|
||||||
|
|
||||||
|
attrs = match.group("attrs")
|
||||||
|
body = match.group("body")
|
||||||
|
|
||||||
|
if 'preload="auto"' not in attrs and "preload='auto'" not in attrs:
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
src = extract_src(attrs, body)
|
||||||
|
if not src:
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
src_clean = unquote(src.split("#")[0].split("?")[0])
|
||||||
|
|
||||||
|
if src_clean.startswith(("http://", "https://", "//")):
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
video_path = (html_file.parent / src_clean).resolve()
|
||||||
|
|
||||||
|
try:
|
||||||
|
video_path.relative_to(root.resolve())
|
||||||
|
except ValueError:
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
if not video_path.exists():
|
||||||
|
print(f"Missing video: {video_path}")
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
poster_path = video_path.with_suffix(".jpg")
|
||||||
|
poster_src = src_clean.rsplit(".", 1)[0] + ".jpg"
|
||||||
|
|
||||||
|
if not poster_path.exists():
|
||||||
|
make_poster(video_path, poster_path)
|
||||||
|
|
||||||
|
attrs_new = attrs
|
||||||
|
attrs_new = attrs_new.replace('preload="auto"', 'preload="none"')
|
||||||
|
attrs_new = attrs_new.replace("preload='auto'", 'preload="none"')
|
||||||
|
|
||||||
|
if "poster=" not in attrs_new.lower():
|
||||||
|
attrs_new += f' poster="{poster_src}"'
|
||||||
|
|
||||||
|
changed = True
|
||||||
|
return f"<video{attrs_new}>{body}</video>"
|
||||||
|
|
||||||
|
new_content = VIDEO_TAG_RE.sub(replace_video, content)
|
||||||
|
|
||||||
|
if changed:
|
||||||
|
html_file.write_text(new_content, encoding="utf-8")
|
||||||
|
print(f"Updated: {html_file}")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Process all HTML files below the given root directory."""
|
||||||
|
|
||||||
|
root = Path(sys.argv[1]).resolve()
|
||||||
|
|
||||||
|
for html_file in root.rglob("*.html"):
|
||||||
|
process_file(html_file, root)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Submodule
+1
Submodule themes/hugo-video added at fb3686a015
Reference in New Issue
Block a user