Compare commits
18 Commits
d62e71bafb
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 544d6c866c | |||
| 2d93109831 | |||
| ba9d4afaa6 | |||
| c10bfaa87c | |||
| fa5e52f185 | |||
| 5b031095fa | |||
| 501855ee87 | |||
| 8cf7b70fad | |||
| 3faa7c6ee0 | |||
| e94bd7eb29 | |||
| 4db8a7f103 | |||
| 42c5b4f345 | |||
| c409ecc888 | |||
| b85c765015 | |||
| c767765986 | |||
| b1a4697769 | |||
| 7caadb048a | |||
| 6a445bf1b4 |
@@ -0,0 +1,4 @@
|
||||
public/
|
||||
resources/
|
||||
.hugo_build.lock
|
||||
.idea/
|
||||
@@ -1,3 +1,6 @@
|
||||
[submodule "themes/gallery"]
|
||||
path = themes/gallery
|
||||
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/
|
||||
@@ -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"]
|
||||
@@ -175,6 +175,58 @@ section.hero {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
/* ── Gallery page header title ────────────────────────── */
|
||||
|
||||
body > header {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
font-size: 1.5rem;
|
||||
letter-spacing: 0.15em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-1);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
width: 3rem;
|
||||
display: flex;
|
||||
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 ──────────────────────────────────── */
|
||||
|
||||
.card > div > h2 {
|
||||
font-weight: 400;
|
||||
font-size: 0.9375rem;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.card > div > p {
|
||||
font-size: 0.6875rem;
|
||||
letter-spacing: 0.15em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ── Albums divider ───────────────────────────────────── */
|
||||
|
||||
.home-divider {
|
||||
@@ -226,6 +278,56 @@ section.hero {
|
||||
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 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 3rem 1.5rem 2rem;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.gallery-back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.15em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-2);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.gallery-back-link:hover {
|
||||
color: var(--text-1);
|
||||
}
|
||||
|
||||
/* ── Keyframes ────────────────────────────────────────── */
|
||||
|
||||
@keyframes hero-fade-up {
|
||||
@@ -240,11 +342,19 @@ section.hero {
|
||||
}
|
||||
|
||||
@keyframes hero-fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hero-bounce {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(7px); }
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(7px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
// Background at 55%, text at 80% — both slower than normal, image slowest
|
||||
if (heroBg) heroBg.style.transform = 'translateY(' + (s * 0.25) + 'px)';
|
||||
if (heroFg) heroFg.style.transform = 'translateY(' + (s * 0.15) + 'px)';
|
||||
if (heroFg) heroFg.style.transform = 'translateY(' + (s * 0.05) + 'px)';
|
||||
|
||||
// Scroll arrow fades out over the first 30% of hero height
|
||||
if (heroScroll) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"paths": {
|
||||
"*": [
|
||||
"*",
|
||||
"../themes/gallery/assets/*"
|
||||
"..\\themes\\gallery\\assets\\*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
---
|
||||
title: "Herzlich Willkommen"
|
||||
title: "Lina & Marlin"
|
||||
params:
|
||||
tagline: "Schön, dass ihr da seid."
|
||||
tagline: "Alles Liebe zu eurer Hochzeit"
|
||||
albums_label: "Alben"
|
||||
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!
|
||||
|
||||
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 458 KiB |
@@ -1,4 +0,0 @@
|
||||
---
|
||||
title: "Cats"
|
||||
date: 2026-06-18
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: "Empfang"
|
||||
date: 2026-06-10
|
||||
weight: 2
|
||||
resources:
|
||||
- src: IMG_1574.png
|
||||
params:
|
||||
cover: true
|
||||
---
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: "Feier"
|
||||
date: 2026-06-10
|
||||
weight: 4
|
||||
resources:
|
||||
- src: IMG_1625.png
|
||||
params:
|
||||
cover: true
|
||||
---
|
||||
|
Before Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 74 MiB |
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: "Standesamt"
|
||||
date: 2026-02-14
|
||||
weight: 1
|
||||
resources:
|
||||
- src: IMG_1570.png
|
||||
params:
|
||||
cover: true
|
||||
---
|
||||
|
||||
{{< video src="test.mp4" >}}
|
||||
|
||||
{{< video src="test2.mp4" >}}
|
||||
|
Before Width: | Height: | Size: 56 KiB |
@@ -1,4 +1,9 @@
|
||||
---
|
||||
title: "Zeremonie"
|
||||
date: 2026-06-18
|
||||
date: 2026-06-10
|
||||
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/"
|
||||
title = "Hochzeit"
|
||||
theme = "gallery"
|
||||
theme = ["hugo-video", "gallery"]
|
||||
defaultContentLanguage = "de"
|
||||
disableKinds = ["taxonomy"]
|
||||
enableRobotsTXT = true
|
||||
@@ -10,7 +10,8 @@ timeout = "120s"
|
||||
|
||||
[params]
|
||||
defaultTheme = "light"
|
||||
description = "Hochzeit"
|
||||
description = "Fotos von Linas und Marlins Hochzeit"
|
||||
images = ["content/hero.png"]
|
||||
title = "Hochzeit"
|
||||
[params.author]
|
||||
name = "Yannis Vierkoetter"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{{ define "main" }}
|
||||
<section class="galleries">
|
||||
{{ range where .Pages "Params.private" "ne" true }}
|
||||
{{ partial "album-card.html" . }}
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,17 @@
|
||||
{{ define "main" }}
|
||||
{{ partial "gallery.html" . }}
|
||||
{{ partial "related.html" . }}
|
||||
{{ with .Content }}
|
||||
<section class="prose">
|
||||
{{ . }}
|
||||
</section>
|
||||
{{ end }}
|
||||
<div class="gallery-back">
|
||||
<a href="{{ .Site.Home.RelPermalink }}" class="gallery-back-link">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M19 12H5M5 12l7 7M5 12l7-7"/>
|
||||
</svg>
|
||||
Zurück zur Startseite
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,30 +0,0 @@
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garant';
|
||||
src: url('/fonts/CormorantGarant-Light.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garant';
|
||||
src: url('/fonts/CormorantGarant-LightItalic.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garant';
|
||||
src: url('/fonts/CormorantGarant-Regular.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cormorant Garant';
|
||||
src: url('/fonts/CormorantGarant-Italic.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
</svg>
|
||||
</a>
|
||||
{{ else }}
|
||||
<a class="btn" href="{{ .Site.Home.RelPermalink }}">
|
||||
{{ .Site.Title }}
|
||||
<a class="btn btn-square" href="{{ .Site.Home.RelPermalink }}" title="{{ .Site.Title }}">
|
||||
<svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path clip-rule="evenodd" fill-rule="evenodd" d="M11.03 3.97a.75.75 0 0 1 0 1.06l-6.22 6.22H21a.75.75 0 0 1 0 1.5H4.81l6.22 6.22a.75.75 0 1 1-1.06 1.06l-7.5-7.5a.75.75 0 0 1 0-1.06l7.5-7.5a.75.75 0 0 1 1.06 0Z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{{ end }}
|
||||
<h1 class="header-title">{{ .Title }}</h1>
|
||||
<div class="header-right">
|
||||
{{ if site.Menus.main }}
|
||||
<ul>
|
||||
<li>
|
||||
<button class="btn btn-square" id="menu-toggle" aria-expanded="false" type="button" title="{{ T "menu" }}">
|
||||
<svg class="icon-menu" width="24" height="24" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path clip-rule="evenodd" fill-rule="evenodd" d="M3 6.75A.75.75 0 0 1 3.75 6h16.5a.75.75 0 0 1 0 1.5H3.75A.75.75 0 0 1 3 6.75ZM3 12a.75.75 0 0 1 .75-.75h16.5a.75.75 0 0 1 0 1.5H3.75A.75.75 0 0 1 3 12Zm0 5.25a.75.75 0 0 1 .75-.75h16.5a.75.75 0 0 1 0 1.5H3.75a.75.75 0 0 1-.75-.75Z"></path>
|
||||
@@ -22,9 +24,8 @@
|
||||
<path clip-rule="evenodd" fill-rule="evenodd" d="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{ end }}
|
||||
</div>
|
||||
</header>
|
||||
{{ partial "menu.html" . }}
|
||||
{{ end }}
|
||||
|
||||
@@ -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()
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
@@ -0,0 +1,35 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
|
||||
User-agent: GPTBot
|
||||
Disallow: /
|
||||
|
||||
User-agent: Google-Extended
|
||||
Disallow: /
|
||||
|
||||
User-agent: ClaudeBot
|
||||
Disallow: /
|
||||
|
||||
User-agent: anthropic-ai
|
||||
Disallow: /
|
||||
|
||||
User-agent: CCBot
|
||||
Disallow: /
|
||||
|
||||
User-agent: Bytespider
|
||||
Disallow: /
|
||||
|
||||
User-agent: PerplexityBot
|
||||
Disallow: /
|
||||
|
||||
User-agent: FacebookBot
|
||||
Disallow: /
|
||||
|
||||
User-agent: Applebot-Extended
|
||||
Disallow: /
|
||||
|
||||
User-agent: cohere-ai
|
||||
Disallow: /
|
||||
|
||||
User-agent: Amazonbot
|
||||
Disallow: /
|
||||