diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 3f8642b..983a1d8 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -13,7 +13,8 @@ "WebSearch", "WebFetch(domain:htmx.org)", "Bash(cat:*)", - "Bash(git remote:*)" + "Bash(git remote:*)", + "Bash(ls:*)" ], "deny": [], "ask": [] diff --git a/.gitignore b/.gitignore index 37282ca..6dc1ca1 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ npm-debug.log* # Cache .cache/ + +# Claude +.claude/ \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index a57061e..54b488e 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -16,6 +16,53 @@ class AudioManager { this.source = null; this.frequencyData = null; this.isInitialized = false; + this.tracks = []; + this.autoplayEnabled = true; + } + + async fetchTracks() { + if (this.tracks.length > 0) return this.tracks; + + try { + const response = await fetch('/tracks/index.json'); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + const data = await response.json(); + this.tracks = data.tracks || []; + } catch (e) { + console.error('Failed to fetch tracks:', e); + this.tracks = []; + } + return this.tracks; + } + + getRandomTrack(excludeUrl = null) { + const available = this.tracks.filter((t) => t.audio !== excludeUrl); + if (available.length === 0) return null; + return available[Math.floor(Math.random() * available.length)]; + } + + async playRandomTrack() { + await this.fetchTracks(); + + const currentUrl = window.Alpine?.store('audio')?.currentTrack?.url; + const nextTrack = this.getRandomTrack(currentUrl); + + if (nextTrack) { + // Store pending track info for auto-play on page load + sessionStorage.setItem( + 'pivoine-autoplay', + JSON.stringify({ + title: nextTrack.title, + url: nextTrack.audio, + image: nextTrack.image + }) + ); + + // Navigate to the new track page + window.location.href = nextTrack.url; + } } async init() { @@ -46,6 +93,10 @@ class AudioManager { if (window.Alpine) { Alpine.store('audio').isPlaying = false; } + // Auto-play next random track + if (this.autoplayEnabled) { + this.playRandomTrack(); + } }); this.audio.addEventListener('play', () => { @@ -135,6 +186,32 @@ if (!window.__pivoine) { logo: null }; + // Check for auto-play from shuffle/random track + const checkAutoplay = () => { + const autoplayData = sessionStorage.getItem('pivoine-autoplay'); + if (autoplayData) { + sessionStorage.removeItem('pivoine-autoplay'); + try { + const track = JSON.parse(autoplayData); + // Update Alpine store + if (window.Alpine) { + Alpine.store('audio').currentTrack = track; + } + // Start playback + audioManager.play(track.url); + } catch (e) { + console.error('Failed to auto-play track:', e); + } + } + }; + + // Run autoplay check after Alpine is ready + document.addEventListener('alpine:initialized', checkAutoplay); + // Fallback if Alpine is already initialized + if (window.Alpine) { + setTimeout(checkAutoplay, 100); + } + // Initialize WebGL components after DOM is ready const initWebGL = () => { // Main visualizer (fullscreen background) diff --git a/config/_default/hugo.toml b/config/_default/hugo.toml index 144ff05..561f624 100644 --- a/config/_default/hugo.toml +++ b/config/_default/hugo.toml @@ -14,7 +14,7 @@ title = "Valknar's" [outputs] home = ["HTML", "RSS"] - section = ["HTML", "RSS"] + section = ["HTML", "RSS", "JSON"] [sitemap] changefreq = "weekly" diff --git a/content/tracks/listen-to-your-heart/Listen To Your Heart.mp3 b/content/tracks/listen-to-your-heart/Listen To Your Heart.mp3 deleted file mode 100644 index d0b2586..0000000 Binary files a/content/tracks/listen-to-your-heart/Listen To Your Heart.mp3 and /dev/null differ diff --git a/content/tracks/listen-to-your-heart/index.md b/content/tracks/listen-to-your-heart/index.md index 10cb0f9..97332fc 100644 --- a/content/tracks/listen-to-your-heart/index.md +++ b/content/tracks/listen-to-your-heart/index.md @@ -4,7 +4,7 @@ date: 2025-12-31 draft: false description: "Roxette" -audio: "https://pivoine.art/tracks/listen-to-your-heart/Listen To Your Heart.mp3" +audio: "https://jellyfin.media.pivoine.art/Items/7665d067afb622eef70db5fa65ab8829/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea" duration: "4:23" artist: "Valknar" diff --git a/content/tracks/paule/Paule.mp3 b/content/tracks/paule/Paule.mp3 deleted file mode 100644 index d546d2d..0000000 Binary files a/content/tracks/paule/Paule.mp3 and /dev/null differ diff --git a/content/tracks/paule/index.md b/content/tracks/paule/index.md index 4ee6be0..27eb0b1 100644 --- a/content/tracks/paule/index.md +++ b/content/tracks/paule/index.md @@ -4,7 +4,7 @@ date: 2025-12-31 draft: false description: "Du Bisch" -audio: "https://pivoine.art/tracks/paule/Paule.mp3" +audio: "https://jellyfin.media.pivoine.art/Items/f1050f982226566de6ef11f4f2edbf33/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea" duration: "0:31" artist: "Valknar" diff --git a/content/tracks/rome/Rome.mp3 b/content/tracks/rome/Rome.mp3 deleted file mode 100644 index ab62fee..0000000 Binary files a/content/tracks/rome/Rome.mp3 and /dev/null differ diff --git a/content/tracks/rome/index.md b/content/tracks/rome/index.md index 0ff892e..8fe1649 100644 --- a/content/tracks/rome/index.md +++ b/content/tracks/rome/index.md @@ -4,7 +4,7 @@ date: 2025-12-31 draft: false description: "Honor Et Virtus" -audio: "https://pivoine.art/tracks/rome/Rome.mp3" +audio: "https://jellyfin.media.pivoine.art/Items/9f4b3b6e523b3488c850e2d50fbe157f/Download?api_key=8db4f88966fd4feb9308dfff68e9eeea" duration: "3:57" artist: "Valknar" diff --git a/layouts/tracks/list.json.json b/layouts/tracks/list.json.json new file mode 100644 index 0000000..0ed5472 --- /dev/null +++ b/layouts/tracks/list.json.json @@ -0,0 +1,18 @@ +{{- $tracks := slice -}} +{{- range .Pages -}} + {{- $track := dict + "title" .Title + "url" .Permalink + "slug" .File.ContentBaseName + "audio" .Params.audio + "duration" .Params.duration + "genre" .Params.genre + "image" "" + -}} + {{- with .Resources.GetMatch "cover.*" -}} + {{- $img := .Resize "200x webp q85" -}} + {{- $track = merge $track (dict "image" $img.RelPermalink) -}} + {{- end -}} + {{- $tracks = $tracks | append $track -}} +{{- end -}} +{{- dict "tracks" $tracks | jsonify (dict "indent" " ") -}} diff --git a/static/css/main.css b/static/css/main.css index cbd5306..94c6558 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -907,14 +907,6 @@ } } } - .hover\:grayscale-0 { - &:hover { - @media (hover: hover) { - --tw-grayscale: grayscale(0%); - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } - } - } .hover\:after\:w-full { &:hover { @media (hover: hover) {