mirror of
https://git.maid.zone/stuff/soundcloak.git
synced 2025-12-10 05:39:38 +05:00
350 lines
11 KiB
Plaintext
350 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 track.Policy == sc.PolicySnip {
|
|
<div style="margin-top: 2rem">
|
|
<p>⚠ Only a 30-second snippet is available.</p>
|
|
</div>
|
|
}
|
|
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 *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 loading="lazy" fetchpriority="low" src={ track.Artwork }/>
|
|
} else {
|
|
<img loading="lazy" fetchpriority="low" 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]) {
|
|
<div class="duopanel-container">
|
|
<div class="duopanel-l">
|
|
if t.Artwork != "" {
|
|
<img loading="lazy" fetchpriority="low" src={ t.Artwork } width="300px"/>
|
|
}
|
|
<h1>{ t.Title }</h1>
|
|
@UserItem(&t.Author)
|
|
@TrackPlayer(prefs, t, stream, displayErr, autoplay, nextTrack, playlist, volume, mode, audio)
|
|
<br/>
|
|
<br/>
|
|
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>
|
|
}
|
|
</div>
|
|
<div class="duopanel-r">
|
|
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>
|
|
}
|
|
@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)
|
|
<div style="display: flex; gap: 2rem;">
|
|
<p title="Likes">♥ { strconv.FormatInt(t.Likes, 10) }</p>
|
|
<p title="Plays">▶ { strconv.FormatInt(t.Played, 10) }</p>
|
|
<p title="Reposts">↻ { strconv.FormatInt(t.Reposted, 10) }</p>
|
|
</div>
|
|
<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>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
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>
|
|
}
|
|
}
|
|
}
|