feat: traefik config

This commit is contained in:
Araozu 2024-11-23 16:27:26 -05:00
parent f262e92e09
commit 004d3de8d7
5 changed files with 93 additions and 59 deletions

View File

@ -7,4 +7,19 @@ services:
ports: ports:
- "8007:8007" - "8007:8007"
restart: unless-stopped restart: unless-stopped
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.music.rule=Host(`music.araozu.dev`)"
- "traefik.http.routers.music.entrypoints=websecure"
- "traefik.http.routers.music.tls=true"
- "traefik.http.routers.music.tls.certresolver=araozu-wildcard"
- "traefik.http.routers.music.tls.domains[0].main=araozu.dev"
- "traefik.http.routers.music.tls.domains[0].sans=*.araozu.dev"
networks:
proxy:
external: true

View File

@ -52,6 +52,7 @@ func allAlbumsPage(c echo.Context) error {
func albumPage(c echo.Context) error { func albumPage(c echo.Context) error {
token, server := utils.Credentials(c) token, server := utils.Credentials(c)
isHtmxRequest := c.Request().Header.Get("HX-Request") == "true"
albumId := c.Param("id") albumId := c.Param("id")
// load album info and song list on the background // load album info and song list on the background
@ -110,5 +111,9 @@ func albumPage(c echo.Context) error {
} }
clientSongsJson := buff.String() clientSongsJson := buff.String()
if isHtmxRequest {
return utils.RenderTempl(c, http.StatusOK, albumTemplFragment(albumId, album, songs, string(clientSongsJson)))
} else {
return utils.RenderTempl(c, http.StatusOK, albumTempl(albumId, album, songs, string(clientSongsJson))) return utils.RenderTempl(c, http.StatusOK, albumTempl(albumId, album, songs, string(clientSongsJson)))
} }
}

View File

@ -59,6 +59,12 @@ templ albumsFragment(albums []utils.Album) {
// Renders the page of a single Album // Renders the page of a single Album
templ albumTempl(albumId string, album *utils.Album, songs []utils.Song, songsJson string) { templ albumTempl(albumId string, album *utils.Album, songs []utils.Song, songsJson string) {
@utils.SkeletonTempl() { @utils.SkeletonTempl() {
@albumTemplFragment(albumId, album, songs, songsJson)
}
}
// Renders the page of a single album, but as a fragment without a skeleton
templ albumTemplFragment(albumId string, album *utils.Album, songs []utils.Song, songsJson string) {
<div <div
class="text-center" class="text-center"
_={ fmt.Sprintf("init set $songsJson to %s", songsJson) } _={ fmt.Sprintf("init set $songsJson to %s", songsJson) }
@ -84,6 +90,4 @@ templ albumTempl(albumId string, album *utils.Album, songs []utils.Song, songsJs
} }
</div> </div>
</div> </div>
@utils.MusicPlayer()
}
} }

View File

@ -23,7 +23,6 @@ templ IndexTempl(albums []utils.Album) {
@AlbumCard(album) @AlbumCard(album)
} }
</div> </div>
@utils.MusicPlayer()
} }
} }

View File

@ -16,13 +16,15 @@ templ SkeletonTempl() {
<script src="/public/js/htmx.min.js" defer></script> <script src="/public/js/htmx.min.js" defer></script>
<script src="/public/js/_hyperscript.min.js" defer></script> <script src="/public/js/_hyperscript.min.js" defer></script>
<script src="/public/js/howler.min.js" defer></script> <script src="/public/js/howler.min.js" defer></script>
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://unpkg.com/htmx-ext-response-targets@2.0.0/response-targets.js" defer></script> <script src="https://unpkg.com/htmx-ext-response-targets@2.0.0/response-targets.js" defer></script>
</head> </head>
<body> <body>
<main class="pb-16"> <main hx-boost="true" hx-target="this" hx-swap="innerHTML" id="boost-target" class="pb-16">
{ children... } { children... }
</main> </main>
@MusicPlayer()
</body> </body>
</html> </html>
} }
@ -31,6 +33,7 @@ templ MusicPlayer() {
<div <div
id="music-player" id="music-player"
class="fixed bottom-0 left-0 w-screen border-t bg-c-bg text-c-on-bg border-sky-500 grid grid-cols-[3rem_auto_3rem_3rem] gap-2 p-1" class="fixed bottom-0 left-0 w-screen border-t bg-c-bg text-c-on-bg border-sky-500 grid grid-cols-[3rem_auto_3rem_3rem] gap-2 p-1"
hx-preserve
x-data="player" x-data="player"
> >
<div <div
@ -76,20 +79,27 @@ templ MusicPlayer() {
</button> </button>
@fullMusicPlayer() @fullMusicPlayer()
<script> <script>
console.log("I'm being re-run :o");
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data("player", () => ({ Alpine.data("player", function() {
init() { return {
window.replaceQueueAndPlayAt = (...params) => this.replaceQueueAndPlayAt(...params); queue: this.$persist([]),
}, idx: this.$persist(0),
queue: [], volume: this.$persist(0.1),
idx: 0, playing: this.$persist(false),
currentSound: null, loading: this.$persist(false),
nextSound: null, progress: this.$persist(0),
volume: 0.1, // These cannot be persisted because they cannot be stored in localstorage
playing: false,
loading: false,
progress: 0,
listenerInterval: 0, listenerInterval: 0,
//currentSound: null,
//nextSound: null,
init() {
console.log("calling alpine init method...")
window.replaceQueueAndPlayAt = (...params) => this.replaceQueueAndPlayAt(...params);
window.currentSound = null;
window.nextSound = null;
},
// sets the queue, and plays the song at idx // sets the queue, and plays the song at idx
replaceQueueAndPlayAt(queue, idx) { replaceQueueAndPlayAt(queue, idx) {
@ -109,30 +119,30 @@ templ MusicPlayer() {
// If preloaded=true, this function will assume that it is the // If preloaded=true, this function will assume that it is the
// next song. It will trust that idx is correct. // next song. It will trust that idx is correct.
async play(idx) { async play(idx) {
const preloaded = this.nextSound !== null && idx === this.idx + 1; const preloaded = window.nextSound !== null && idx === this.idx + 1;
// if a song is currently playing // if a song is currently playing
// then fade it out before playing the next sound // then fade it out before playing the next sound
if (this.playing === true if (this.playing === true
&& this.currentSound !== null && window.currentSound !== null
) { ) {
// this will not trigger when next() is called, // this will not trigger when next() is called,
// because next() sets this.playing=false // because next() sets this.playing=false
this.currentSound.fade(this.volume, 0.0, 250); window.currentSound.fade(this.volume, 0.0, 250);
await wait(250); await wait(250);
} }
this.currentSound?.unload?.(); window.currentSound?.unload?.();
this.playing = false; this.playing = false;
this.currentSound = null; window.currentSound = null;
this.idx = idx; this.idx = idx;
// if a song is preloaded, assume it's the next song and play it // if a song is preloaded, assume it's the next song and play it
if (preloaded === true && this.nextSound !== null) { if (preloaded === true && window.nextSound !== null) {
this.currentSound = this.nextSound; window.currentSound = window.nextSound;
this.nextSound = null; window.nextSound = null;
this.currentSound.play(); window.currentSound.play();
this.playing = true; this.playing = true;
} else { } else {
// otherwise, load the song at idx and play it // otherwise, load the song at idx and play it
@ -143,7 +153,7 @@ templ MusicPlayer() {
html5: true, html5: true,
volume: this.volume, volume: this.volume,
}); });
this.currentSound = sound; window.currentSound = sound;
this.loading = true; this.loading = true;
sound.play(); sound.play();
sound.once("load", () => { sound.once("load", () => {
@ -153,7 +163,7 @@ templ MusicPlayer() {
} }
// set-up preloading for the next song // set-up preloading for the next song
const sound = this.currentSound; const sound = window.currentSound;
sound.once("play", () => { sound.once("play", () => {
const length = sound.duration(); const length = sound.duration();
const targetLength = length - 5; const targetLength = length - 5;
@ -172,14 +182,14 @@ templ MusicPlayer() {
this.playing = false; this.playing = false;
this.next(); this.next();
}); });
this.currentSound = sound; window.currentSound = sound;
}, },
// checks the duration of the playing song and: // checks the duration of the playing song and:
// - updates the song progress (0-100%) // - updates the song progress (0-100%)
// - begins preloading // - begins preloading
checkDuration() { checkDuration() {
const sound = this.currentSound; const sound = window.currentSound;
if (this.playing) { if (this.playing) {
const length = sound.duration(); const length = sound.duration();
if (length <= 0) return; if (length <= 0) return;
@ -187,7 +197,7 @@ templ MusicPlayer() {
const position = sound.seek(); const position = sound.seek();
// preload 5s before the song ends // preload 5s before the song ends
if (position >= length - 5 && this.nextSound === null) { if (position >= length - 5 && window.nextSound === null) {
this.preload(); this.preload();
} }
@ -199,10 +209,10 @@ templ MusicPlayer() {
togglePlayPause() { togglePlayPause() {
if (this.playing === true) { if (this.playing === true) {
this.playing = false; this.playing = false;
this.currentSound?.pause(); window.currentSound?.pause();
} else { } else {
this.playing = true; this.playing = true;
this.currentSound?.play(); window.currentSound?.play();
} }
}, },
next() { next() {
@ -236,9 +246,10 @@ templ MusicPlayer() {
nextSound.seek(0); nextSound.seek(0);
nextSound.volume(this.volume); nextSound.volume(this.volume);
}); });
this.nextSound = nextSound; window.nextSound = nextSound;
} }
})); }
});
}) })
function wait(ms) { function wait(ms) {