Files
soundcloak/templates/track.templ
2025-02-03 19:43:16 +02:00

340 lines
11 KiB
Plaintext

package templates
import (
"git.maid.zone/stuff/soundcloak/lib/cfg"
"git.maid.zone/stuff/soundcloak/lib/sc"
"net/url"
"strconv"
"strings"
)
func toExt(audio string) string {
switch audio {
case cfg.AudioAAC:
return "m4a"
case cfg.AudioOpus:
return "ogg"
case cfg.AudioMP3:
return "mp3"
}
return ""
}
templ TrackButtons(current string, track sc.Track) {
<div class="btns">
for _, b := range [...]btn{{"related tracks", "/recommended", false, false},{"in albums", "/albums", false, false},{"in playlists", "/sets", false, false},{"track station", "/discover/sets/"+track.Station, true, false},{"view on soundcloud", "https://soundcloud.com"+track.Href(), true, true}} {
if b.text == current {
<a class="btn active">{ b.text }</a>
} else {
if b.external {
<a class="btn" href={ templ.SafeURL(b.href) } referrerpolicy="no-referrer" rel="external nofollow noopener noreferrer" target="_blank">{ b.text }</a>
} else {
if b.override {
<a class="btn" href={ templ.SafeURL(b.href) }>{ b.text }</a>
} else {
<a class="btn" href={ templ.SafeURL(track.Href() + b.href) }>{ b.text }</a>
}
}
}
}
</div>
}
templ TrackHeader(prefs cfg.Preferences, t sc.Track, needPlayer bool) {
<meta name="og:site_name" content={ t.Author.Username + " ~ soundcloak" }/>
<meta name="og:title" content={ t.Title }/>
<meta name="og:description" content={ t.FormatDescription() }/>
<meta name="og:image" content={ t.Artwork }/>
<link rel="icon" type="image/x-icon" href={ t.Artwork }/>
if needPlayer && *prefs.Player == cfg.HLSPlayer {
<script src="/_/static/js/hls.light.min.js"></script>
}
}
func next(t *sc.Track, p *sc.Playlist, autoplay bool, mode string, volume string) string {
r := t.Href() + "?playlist=" + p.Href()[1:]
if autoplay {
r += "&autoplay=true"
}
if mode != "" {
r += "&mode=" + mode
}
if volume != "" {
r += "&volume=" + volume
}
return r
}
templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayErr string, autoplay bool, nextTrack *sc.Track, playlist *sc.Playlist, volume string, mode string, audio string) {
if *prefs.Player == cfg.NonePlayer {
{{ return }}
}
if displayErr == "" {
{{ var audioPref string }}
if cfg.Restream && *prefs.Player == cfg.RestreamPlayer {
{{ audioPref = *prefs.RestreamAudio }}
if nextTrack != nil {
<audio id="track" src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay } data-next={ next(nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
<script async src="/_/static/restream.js"></script>
} else {
<audio src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay }></audio>
}
} else if stream != "" {
{{ audioPref = *prefs.HLSAudio }}
if nextTrack != nil {
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={ next(nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
} else {
<audio id="track" src={ stream } controls autoplay?={ autoplay }></audio>
}
if *prefs.FullyPreloadTrack {
<script async src="/_/static/player_preload.js"></script>
} else {
<script async src="/_/static/player.js"></script>
}
<noscript>
<br/>
JavaScript is disabled! Audio playback may not work without it enabled.
if cfg.Restream {
<br/>
<a class="link" href="/_/preferences">You can enable Restream player in the preferences. It works without JavaScript.</a>
}
</noscript>
}
if track.Policy == sc.PolicySnip {
<div>
<p>Only a 30-second snippet is available.</p>
</div>
}
if *prefs.ShowAudio {
<div>
if audioPref == cfg.AudioBest {
<p>Audio: best ({ audio })</p>
} else {
<p>Audio: { audio }</p>
}
</div>
}
} else {
<div>
<p style="white-space: pre-wrap;">{ displayErr }</p>
</div>
}
}
templ TrackItem(track *sc.Track, showUsername bool, overrideHref string) {
if track.Title != "" {
{{
if overrideHref == "" {
overrideHref = track.Href()
}
}}
<a class="listing" href={ templ.SafeURL(overrideHref) }>
if track.Artwork != "" {
<img src={ track.Artwork }/>
} else {
<img src="/_/static/placeholder.jpg"/>
}
<div class="meta">
<h3>{ track.Title }</h3>
if showUsername {
<span>{ track.Author.Username }</span>
}
</div>
</a>
}
}
templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string, autoplay bool, playlist *sc.Playlist, nextTrack *sc.Track, volume string, mode string, audio string, downloadAudio *string, comments *sc.Paginated[*sc.Comment]) {
if t.Artwork != "" {
<img src={ t.Artwork } width="300px"/>
}
<h1>{ t.Title }</h1>
@TrackPlayer(prefs, t, stream, displayErr, autoplay, nextTrack, playlist, volume, mode, audio)
if cfg.Restream {
<div style="display: flex; margin-bottom: 1rem;">
<a class="btn" href={ templ.SafeURL("/_/restream" + t.Href() + "?metadata=true") } download={ t.Permalink + "." + toExt(*downloadAudio) }>download</a>
</div>
}
if t.Genre != "" {
<a href={ templ.SafeURL("/tags/" + t.Genre) }><p class="tag">{ t.Genre }</p></a>
}
if playlist != nil {
<details open style="margin-bottom: 1rem;">
<summary>Playback info</summary>
<h2>In playlist:</h2>
@PlaylistItem(playlist, true)
<h2>Next track:</h2>
@TrackItem(nextTrack, true, next(nextTrack, playlist, true, mode, volume))
<div style="display: flex; gap: 1rem">
<a href={ templ.SafeURL(t.Href()) } class="btn">Stop playlist playback</a>
if mode != cfg.AutoplayRandom {
<a href={ templ.SafeURL(next(&t, playlist, false, cfg.AutoplayRandom, volume)) } class="btn">Switch to random mode</a>
} else {
<a href={ templ.SafeURL(next(&t, playlist, false, cfg.AutoplayNormal, volume)) } class="btn">Switch to normal mode</a>
}
</div>
</details>
}
@UserItem(&t.Author)
@TrackButtons("", t)
// <div style="display: flex; gap: 1rem">
// <a class="btn" href={ templ.SafeURL("https://soundcloud.com" + t.Href()) }>view on soundcloud</a>
// if cfg.Restream {
// <a class="btn" href={ templ.SafeURL("/_/restream" + t.Href() + "?metadata=true") } download={t.Permalink + "." + toExt(audio)}>download</a>
// }
// </div>
<br/>
@Description(prefs, t.Description, nil)
<p>{ strconv.FormatInt(t.Likes, 10) } likes</p>
<p>{ strconv.FormatInt(t.Played, 10) } plays</p>
<p>{ strconv.FormatInt(t.Reposted, 10) } reposts</p>
<p>Created: { t.CreatedAt }</p>
<p>Last modified: { t.LastModified }</p>
if t.License != "" {
<p>License: { t.License }</p>
}
if t.TagList != "" {
<p>Tags: { strings.Join(sc.TagListParser(t.TagList), ", ") }</p>
}
<h1>Comments</h1>
if *prefs.DynamicLoadComments {
if comments != nil {
<div id="comments">
@Comments(comments)
</div>
<script async src="/_/static/comments.js"></script>
if comments.Next != "" {
<a class="btn" href={ templ.SafeURL("?pagination=" + url.QueryEscape(comments.Next[sc.H+len("/tracks/")+len(string(t.ID))+len("/comments"):])) } rel="noreferrer" onclick="event.preventDefault(); comments(this)" data-id={ string(t.ID) }>more comments</a>
}
} else {
<div id="comments"></div>
<script async src="/_/static/comments.js"></script>
<a class="btn" href="?pagination=%3Flimit%3D20%26threaded%3D1" data-id={ string(t.ID) } onclick="event.preventDefault(); comments(this)">load comments</a>
}
} else {
if comments != nil {
<div>
@Comments(comments)
</div>
if comments.Next != "" {
<a class="btn" href={ templ.SafeURL("?pagination=" + url.QueryEscape(comments.Next[sc.H+len("/tracks/")+len(string(t.ID))+len("/comments"):])) } rel="noreferrer">more comments</a>
}
} else {
<a class="btn" href="?pagination=%3Flimit%3D20%26threaded%3D1">load comments</a>
}
}
}
templ Comments(comments *sc.Paginated[*sc.Comment]) {
for _, c := range comments.Collection {
<div class="listing">
if c.Author.Avatar != "" {
<img src={ c.Author.Avatar }/>
} else {
<img src="/_/static/placeholder.jpg"/>
}
<div class="comment">
<h3 class="link"><a href={ templ.SafeURL("/" + c.Author.Permalink) }>{ c.Author.Username }</a></h3>
<p>{ c.Body }</p>
</div>
</div>
}
}
templ TrackEmbed(prefs cfg.Preferences, t sc.Track, stream string, displayErr string) {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="/_/static/global.css"/>
<title>soundcloak</title>
if *prefs.Player == cfg.HLSPlayer && stream != "" {
<script src="/_/static/js/hls.light.js"></script>
}
</head>
<body>
if t.Artwork != "" {
<img src={ t.Artwork } width="300px"/>
}
<h1>{ t.Title }</h1>
@TrackPlayer(prefs, t, stream, displayErr, false, nil, nil, "", "", "")
@UserItem(&t.Author)
</body>
</html>
}
templ SearchTracks(p *sc.Paginated[*sc.Track]) {
<span>Found { strconv.FormatInt(p.Total, 10) } tracks</span>
<br/>
<br/>
if len(p.Collection) == 0 && p.Total != 0 {
<p>no more results</p>
} else {
for _, track := range p.Collection {
@TrackItem(track, true, "")
}
if p.Next != "" && len(p.Collection) != int(p.Total) {
<a class="btn" href={ templ.SafeURL("?type=tracks&pagination=" + url.QueryEscape(p.Next[sc.H+len("/search/tracks"):])) } rel="noreferrer">more tracks</a>
}
}
}
templ RelatedTracks(t sc.Track, p *sc.Paginated[*sc.Track]) {
if t.Artwork != "" {
<img src={ t.Artwork } width="300px"/>
}
<h1><a href={ templ.SafeURL(t.Href()) }>{ t.Title }</a></h1>
@TrackButtons("related tracks", t)
<br/>
if len(p.Collection) == 0 {
<p>no more results</p>
} else {
for _, track := range p.Collection {
@TrackItem(track, true, "")
}
if p.Next != "" {
<a class="btn" href={ templ.SafeURL("?pagination=" + url.QueryEscape(p.Next[sc.H+len("/tracks/")+len(string(t.ID))+len("/related"):])) } rel="noreferrer">more tracks</a>
}
}
}
templ TrackInAlbums(t sc.Track, p *sc.Paginated[*sc.Playlist]) {
if t.Artwork != "" {
<img src={ t.Artwork } width="300px"/>
}
<h1><a href={ templ.SafeURL(t.Href()) }>{ t.Title }</a></h1>
@TrackButtons("in albums", t)
<br/>
if len(p.Collection) == 0 {
<p>no more albums</p>
} else {
for _, playlist := range p.Collection {
@PlaylistItem(playlist, true)
}
if p.Next != "" {
<a class="btn" href={ templ.SafeURL("?pagination=" + url.QueryEscape(p.Next[sc.H+len("/tracks/")+len(string(t.ID))+len("/albums"):])) } rel="noreferrer">more albums</a>
}
}
}
templ TrackInPlaylists(t sc.Track, p *sc.Paginated[*sc.Playlist]) {
if t.Artwork != "" {
<img src={ t.Artwork } width="300px"/>
}
<h1><a href={ templ.SafeURL(t.Href()) }>{ t.Title }</a></h1>
@TrackButtons("in playlists", t)
<br/>
if len(p.Collection) == 0 {
<p>no more playlists</p>
} else {
for _, playlist := range p.Collection {
@PlaylistItem(playlist, true)
}
if p.Next != "" {
<a class="btn" href={ templ.SafeURL("?pagination=" + url.QueryEscape(p.Next[sc.H+len("/tracks/")+len(string(t.ID))+len("/playlists_without_albums"):])) } rel="noreferrer">more playlists</a>
}
}
}