feat: serve audio as local Hugo page resources instead of Jellyfin

Download all 20 track MP3s from Jellyfin and store them as page bundle
resources (track.mp3). Update templates to use .Resources.GetMatch
instead of .Params.audio, removing external API key dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 22:51:30 +01:00
parent 4508596010
commit 3bccbdf82d
47 changed files with 25 additions and 44 deletions

View File

@@ -4,8 +4,6 @@ date: {{ .Date }}
draft: true draft: true
description: "" description: ""
# Audio
audio: ""
duration: "" duration: ""
# Metadata # Metadata

View File

@@ -2,10 +2,6 @@ description = "Valknar's Pivoine.Art"
author = "Valknar" author = "Valknar"
email = "valknar@pivoine.art" email = "valknar@pivoine.art"
[jellyfin]
baseURL = "https://jellyfin.media.pivoine.art"
# API key via environment variable: HUGO_PARAMS_JELLYFIN_APIKEY
[umami] [umami]
enabled = true enabled = true
websiteID = "" # Set your Umami website ID websiteID = "" # Set your Umami website ID

View File

@@ -4,7 +4,6 @@ date: 2025-12-10
draft: false draft: false
description: "Black heart, black soul" description: "Black heart, black soul"
audio: "https://jellyfin.media.pivoine.art/Items/ac825a429c2485545b557567c704d93c/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "0:53" duration: "0:53"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-11-30
draft: false draft: false
description: "Djane" description: "Djane"
audio: "https://jellyfin.media.pivoine.art/Items/5e09032deaaeb222b4de117b2e0233af/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "6:46" duration: "6:46"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-09-10
draft: false draft: false
description: "Again..." description: "Again..."
audio: "https://jellyfin.media.pivoine.art/Items/ebd4e9f45b9dda1cada560af5e6cb7a8/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "4:07" duration: "4:07"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-09
draft: false draft: false
description: "At the gate" description: "At the gate"
audio: "https://jellyfin.media.pivoine.art/Items/7fbd8a967c7b89c7b8aad91b056ad27a/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "5:03" duration: "5:03"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-08-21
draft: false draft: false
description: "Motown Madness" description: "Motown Madness"
audio: "https://jellyfin.media.pivoine.art/Items/4002348ba445a02db3b48cd9e1562936/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "4:35" duration: "4:35"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-08
draft: false draft: false
description: "28 days later" description: "28 days later"
audio: "https://jellyfin.media.pivoine.art/Items/4f7487b2006b02a9901a1a56b3c2e516/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "3:43" duration: "3:43"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-08-16
draft: false draft: false
description: "Flamingo Hyperloop" description: "Flamingo Hyperloop"
audio: "https://jellyfin.media.pivoine.art/Items/2d87945379960133e08a8a1077b3bc7b/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "3:33" duration: "3:33"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-11-30
draft: false draft: false
description: "Posing" description: "Posing"
audio: "https://jellyfin.media.pivoine.art/Items/ed71ecad292dc60ea3475cf9029974c3/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "5:57" duration: "5:57"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-07
draft: false draft: false
description: "Soul Survivor VIII" description: "Soul Survivor VIII"
audio: "https://jellyfin.media.pivoine.art/Items/9a541705578deef7d3e98870fadfaa61/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "4:50" duration: "4:50"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-31
draft: false draft: false
description: "Roxette" description: "Roxette"
audio: "https://jellyfin.media.pivoine.art/Items/7665d067afb622eef70db5fa65ab8829/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "4:23" duration: "4:23"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-04
draft: false draft: false
description: "गाँडकामसूत्र" description: "गाँडकामसूत्र"
audio: "https://jellyfin.media.pivoine.art/Items/b19ac1b009d55d22b0f0ece91135e027/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "2:19" duration: "2:19"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2026-02-05
draft: false draft: false
description: "Mon amour" description: "Mon amour"
audio: "https://jellyfin.media.pivoine.art/Items/2b5b7d9aa75221808a979f3a3094dd82/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "5:29" duration: "5:29"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2026-02-05
draft: false draft: false
description: "Mon amour" description: "Mon amour"
audio: "https://jellyfin.media.pivoine.art/Items/5d2d5d627e16279623761a8c04b92580/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "5:56" duration: "5:56"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2026-02-05
draft: false draft: false
description: "Mon amour" description: "Mon amour"
audio: "https://jellyfin.media.pivoine.art/Items/3ec5441bc936501684ebd8bdde9f71c0/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "5:08" duration: "5:08"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-31
draft: false draft: false
description: "Du Bisch" description: "Du Bisch"
audio: "https://jellyfin.media.pivoine.art/Items/f1050f982226566de6ef11f4f2edbf33/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "0:31" duration: "0:31"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-31
draft: false draft: false
description: "Honor Et Virtus" description: "Honor Et Virtus"
audio: "https://jellyfin.media.pivoine.art/Items/9f4b3b6e523b3488c850e2d50fbe157f/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea"
duration: "3:57" duration: "3:57"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-11-06
draft: false draft: false
description: "In my shadow" description: "In my shadow"
audio: "https://jellyfin.media.pivoine.art/Items/aada4e4ac0320e258595976a9edb6a09/Download?api_key=53d58826a49b4026a815d13db5e38ff7"
duration: "3:26" duration: "3:26"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-11-16
draft: false draft: false
description: "The end of all is just the beginning" description: "The end of all is just the beginning"
audio: "https://jellyfin.media.pivoine.art/Items/60d39ab0aad880627e8fb85cf1ee7b40/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "4:35" duration: "4:35"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-08-19
draft: false draft: false
description: "Because we are the last" description: "Because we are the last"
audio: "https://jellyfin.media.pivoine.art/Items/d91333f9c7c4d8251174c86a81588cbd/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "3:44" duration: "3:44"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -4,7 +4,6 @@ date: 2025-12-04
draft: false draft: false
description: "Death Tank" description: "Death Tank"
audio: "https://jellyfin.media.pivoine.art/Items/a5594979b65378601cb50fe890bd8389/Download?api_key=64d0a008577f49a4aa276d4bbe5c5d60"
duration: "4:39" duration: "4:39"
artist: "Valknar" artist: "Valknar"

Binary file not shown.

View File

@@ -30,10 +30,10 @@
"@type": "Person", "@type": "Person",
"name": "{{ .Params.artist | default .Site.Params.author }}" "name": "{{ .Params.artist | default .Site.Params.author }}"
} }
{{- if .Params.audio }}, {{- with .Resources.GetMatch "track.*" }},
"audio": { "audio": {
"@type": "AudioObject", "@type": "AudioObject",
"contentUrl": "{{ .Params.audio }}" "contentUrl": "{{ .Permalink }}"
} }
{{- end }} {{- end }}
{{- if .Params.genre }}, {{- if .Params.genre }},

View File

@@ -30,13 +30,15 @@
{{- end }} {{- end }}
{{/* Audio-specific OpenGraph tags */}} {{/* Audio-specific OpenGraph tags */}}
{{- if and (eq .Section "tracks") .Params.audio }} {{- if eq .Section "tracks" }}
<meta property="og:audio" content="{{ .Params.audio }}"> {{- with .Resources.GetMatch "track.*" }}
<meta property="og:audio" content="{{ .Permalink }}">
<meta property="og:audio:type" content="audio/mpeg"> <meta property="og:audio:type" content="audio/mpeg">
{{- if .Params.duration }}
<meta property="music:duration" content="{{ .Params.duration }}">
{{- end }} {{- end }}
{{- if .Params.artist }} {{- if $.Params.duration }}
<meta property="music:musician" content="{{ .Params.artist }}"> <meta property="music:duration" content="{{ $.Params.duration }}">
{{- end }}
{{- if $.Params.artist }}
<meta property="music:musician" content="{{ $.Params.artist }}">
{{- end }} {{- end }}
{{- end }} {{- end }}

View File

@@ -1,6 +1,3 @@
{{/* Preconnect to external domains */}}
<link rel="preconnect" href="https://jellyfin.media.pivoine.art" crossorigin>
{{/* DNS prefetch */}} {{/* DNS prefetch */}}
<link rel="dns-prefetch" href="https://unpkg.com"> <link rel="dns-prefetch" href="https://unpkg.com">

View File

@@ -1,10 +1,14 @@
{{- $tracks := slice -}} {{- $tracks := slice -}}
{{- range .Pages -}} {{- range .Pages -}}
{{- $audio := "" -}}
{{- with .Resources.GetMatch "track.*" -}}
{{- $audio = .RelPermalink -}}
{{- end -}}
{{- $track := dict {{- $track := dict
"title" .Title "title" .Title
"url" .Permalink "url" .Permalink
"slug" .File.ContentBaseName "slug" .File.ContentBaseName
"audio" .Params.audio "audio" $audio
"duration" .Params.duration "duration" .Params.duration
"genre" .Params.genre "genre" .Params.genre
"image" "" "image" ""

View File

@@ -1,4 +1,8 @@
{{ define "main" }} {{ define "main" }}
{{- $audio := "" -}}
{{- with .Resources.GetMatch "track.*" -}}
{{- $audio = .RelPermalink -}}
{{- end -}}
<article class="py-16"> <article class="py-16">
<div class="container-wide"> <div class="container-wide">
{{/* Content area with offset */}} {{/* Content area with offset */}}
@@ -31,15 +35,15 @@
{{- $img := .Resize "400x webp q90" }} {{- $img := .Resize "400x webp q90" }}
<figure <figure
class="overflow-hidden rounded-lg group cursor-pointer relative aspect-square border border-border" class="overflow-hidden rounded-lg group cursor-pointer relative aspect-square border border-border"
{{- if $.Params.audio }} {{- if $audio }}
x-data x-data
@click=" @click="
$store.audio.currentTrack = { $store.audio.currentTrack = {
title: '{{ $.Title }}', title: '{{ $.Title }}',
url: '{{ $.Params.audio }}', url: '{{ $audio }}',
image: '{{ with $.Resources.GetMatch "cover.*" }}{{ (.Resize "200x webp q85").RelPermalink }}{{ end }}' image: '{{ with $.Resources.GetMatch "cover.*" }}{{ (.Resize "200x webp q85").RelPermalink }}{{ end }}'
}; };
window.__pivoine?.audioManager?.play('{{ $.Params.audio }}'); window.__pivoine?.audioManager?.play('{{ $audio }}');
$store.audio.isPlaying = true; $store.audio.isPlaying = true;
" "
{{- end }} {{- end }}
@@ -66,16 +70,16 @@
{{- end }} {{- end }}
{{/* Play Widget - 2 columns */}} {{/* Play Widget - 2 columns */}}
{{- if .Params.audio }} {{- if $audio }}
<div <div
x-data x-data
@click=" @click="
$store.audio.currentTrack = { $store.audio.currentTrack = {
title: '{{ .Title }}', title: '{{ .Title }}',
url: '{{ .Params.audio }}', url: '{{ $audio }}',
image: '{{ with .Resources.GetMatch "cover.*" }}{{ (.Resize "200x webp q85").RelPermalink }}{{ end }}' image: '{{ with .Resources.GetMatch "cover.*" }}{{ (.Resize "200x webp q85").RelPermalink }}{{ end }}'
}; };
window.__pivoine?.audioManager?.play('{{ .Params.audio }}'); window.__pivoine?.audioManager?.play('{{ $audio }}');
$store.audio.isPlaying = true; $store.audio.isPlaying = true;
" "
class="md:col-span-2 flex items-center gap-4 cursor-pointer group" class="md:col-span-2 flex items-center gap-4 cursor-pointer group"