add custom listenbrainz url support and make ui "consistent"
Co-authored-by: spezifisch <spezifisch@users.noreply.github.com> Co-authored-by: Alex McGrath <amk@amk.ie>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -5,15 +5,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="block-right">
|
<div class="block-right">
|
||||||
<table id="stats" class="text-right">
|
<table id="stats" class="text-right">
|
||||||
<tr>
|
<tr><td>artists:</td> <td>{{ .ArtistCount }}</td></tr>
|
||||||
<td>artists:</td> <td>{{ .ArtistCount }}</td>
|
<tr><td>albums:</td> <td>{{ .AlbumCount }}</td></tr>
|
||||||
</tr>
|
<tr><td>tracks:</td> <td>{{ .TrackCount }}</td></tr>
|
||||||
<tr>
|
|
||||||
<td>albums:</td> <td>{{ .AlbumCount }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>tracks:</td> <td>{{ .TrackCount }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,13 +22,12 @@
|
|||||||
{{ if .CurrentLastFMAPIKey }}
|
{{ if .CurrentLastFMAPIKey }}
|
||||||
<span class="text-light">current status</span>
|
<span class="text-light">current status</span>
|
||||||
{{ if .User.LastFMSession }}
|
{{ if .User.LastFMSession }}
|
||||||
linked
|
<span>linked</span><br/>
|
||||||
<span class="text-light">|</span>
|
|
||||||
<form action="{{ path "/admin/unlink_lastfm_do" }}" method="post">
|
<form action="{{ path "/admin/unlink_lastfm_do" }}" method="post">
|
||||||
<input type="submit" value="unlink">
|
<input type="submit" value="unlink">
|
||||||
</form>
|
</form>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<span class="angry">unlinked</span>
|
<span class="angry">unlinked</span><br/>
|
||||||
{{ $cbPath := path "/admin/link_lastfm_do" }}
|
{{ $cbPath := path "/admin/link_lastfm_do" }}
|
||||||
{{ $cbURL := printf "%s%s" .RequestRoot $cbPath }}
|
{{ $cbURL := printf "%s%s" .RequestRoot $cbPath }}
|
||||||
<a href="https://www.last.fm/api/auth/?api_key={{ .CurrentLastFMAPIKey }}&cb={{ $cbURL }}">link…</a>
|
<a href="https://www.last.fm/api/auth/?api_key={{ .CurrentLastFMAPIKey }}&cb={{ $cbURL }}">link…</a>
|
||||||
@@ -52,31 +45,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="padded box">
|
<div class="padded box">
|
||||||
<div class="box-title">
|
<div class="box-title">
|
||||||
<i class="mdi mdi-brain"></i> ListenBrainz
|
<i class="mdi mdi-brain"></i> listenbrainz
|
||||||
</div>
|
</div>
|
||||||
<div class="box-description text-light">
|
<div class="box-description text-light">
|
||||||
<p>gonic can scrobble to <a href="https://listenbrainz.org/" target="_blank">ListenBrainz</a> and compatible sites.</p>
|
<p>gonic can scrobble to <a href="https://listenbrainz.org/" target="_blank">listenbrainz</a> and compatible sites</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<span class="text-light">current status</span>
|
<span class="text-light">current status</span>
|
||||||
{{ if .User.ListenBrainzSession }}
|
{{ if .User.ListenBrainzToken }}
|
||||||
linked
|
<span>linked</span><br/>
|
||||||
<span class="text-light">|</span>
|
|
||||||
<form action="{{ path "/admin/unlink_listenbrainz_do" }}" method="post">
|
<form action="{{ path "/admin/unlink_listenbrainz_do" }}" method="post">
|
||||||
<input type="submit" value="unlink">
|
<input type="submit" value="unlink">
|
||||||
</form>
|
</form>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<span class="angry">unlinked</span>
|
<span class="angry">unlinked</span>
|
||||||
<form id="listenbrainz-pref-set" action="{{ path "/admin/link_listenbrainz_do" }}" method="post"></form>
|
<form class="block" action="{{ path "/admin/link_listenbrainz_do" }}" method="post">
|
||||||
<table id="listenbrainz-pref">
|
<input type="text" name="url" placeholder="server addr" value="{{ default .DefaultListenBrainzURL .User.ListenBrainzURL }}">
|
||||||
<tr>
|
<input type="text" name="token" placeholder="e199b311abd01f0d" value="{{ .User.ListenBrainzToken }}">
|
||||||
<td><label for="listenbrainz-token">Token:</label></td>
|
<input type="submit" value="update">
|
||||||
<td><input form="listenbrainz-pref-set" id="listenbrainz-token" type="text" name="token" value="{{ default "" .User.ListenBrainzSession }}"></td>
|
</form>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2"><input form="listenbrainz-pref-set" type="submit" value="save"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,7 +128,7 @@
|
|||||||
<p class="text-light" title="{{ .LastScanTime }}">scanned {{ .LastScanTime | dateHuman }}</p>
|
<p class="text-light" title="{{ .LastScanTime }}">scanned {{ .LastScanTime | dateHuman }}</p>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<form action="{{ path "/admin/start_scan_inc_do" }}" method="post">
|
<form action="{{ path "/admin/start_scan_inc_do" }}" method="post">
|
||||||
<input type="submit" title="start a incremental scan" value="scan now"><br/>
|
<input type="submit" title="start a incremental scan" value="scan now">
|
||||||
</form>
|
</form>
|
||||||
<form action="{{ path "/admin/start_scan_full_do" }}" method="post">
|
<form action="{{ path "/admin/start_scan_full_do" }}" method="post">
|
||||||
<input type="submit" title="start a full scan (takes longer, and shouldn't usually be necessary)" value="scan full (!)">
|
<input type="submit" title="start a full scan (takes longer, and shouldn't usually be necessary)" value="scan full (!)">
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ html {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: var(--size);
|
font-size: var(--size);
|
||||||
color: black;
|
color: black;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -37,10 +38,12 @@ button,
|
|||||||
textarea {
|
textarea {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: calc(var(--size)*0.33) 0 0 0;;
|
margin: 0;
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
vertical-align: middle;
|
border: none;
|
||||||
|
outline: 1px solid #ccc;
|
||||||
|
height: var(--size);
|
||||||
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type] {
|
input[type] {
|
||||||
@@ -54,10 +57,6 @@ input[type="password"] {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.block {
|
form.block {
|
||||||
max-width: var(--width-form);
|
max-width: var(--width-form);
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@@ -171,8 +170,3 @@ a:hover {
|
|||||||
.angry {
|
.angry {
|
||||||
background-color: #f4433669;
|
background-color: #f4433669;
|
||||||
}
|
}
|
||||||
|
|
||||||
#listenbrainz-pref {
|
|
||||||
width: 100%;
|
|
||||||
margin: calc(var(--size)*0.5) 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ type templateData struct {
|
|||||||
//
|
//
|
||||||
CurrentLastFMAPIKey string
|
CurrentLastFMAPIKey string
|
||||||
CurrentLastFMAPISecret string
|
CurrentLastFMAPISecret string
|
||||||
|
DefaultListenBrainzURL string
|
||||||
SelectedUser *db.User
|
SelectedUser *db.User
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"go.senan.xyz/gonic/server/encode"
|
"go.senan.xyz/gonic/server/encode"
|
||||||
"go.senan.xyz/gonic/server/scanner"
|
"go.senan.xyz/gonic/server/scanner"
|
||||||
"go.senan.xyz/gonic/server/scrobble/lastfm"
|
"go.senan.xyz/gonic/server/scrobble/lastfm"
|
||||||
|
"go.senan.xyz/gonic/server/scrobble/listenbrainz"
|
||||||
)
|
)
|
||||||
|
|
||||||
func firstExisting(or string, strings ...string) string {
|
func firstExisting(or string, strings ...string) string {
|
||||||
@@ -58,6 +59,7 @@ func (c *Controller) ServeHome(r *http.Request) *Response {
|
|||||||
)
|
)
|
||||||
data.RequestRoot = fmt.Sprintf("%s://%s", scheme, host)
|
data.RequestRoot = fmt.Sprintf("%s://%s", scheme, host)
|
||||||
data.CurrentLastFMAPIKey = c.DB.GetSetting("lastfm_api_key")
|
data.CurrentLastFMAPIKey = c.DB.GetSetting("lastfm_api_key")
|
||||||
|
data.DefaultListenBrainzURL = listenbrainz.BaseURL
|
||||||
// ** begin users box
|
// ** begin users box
|
||||||
c.DB.Find(&data.AllUsers)
|
c.DB.Find(&data.AllUsers)
|
||||||
// ** begin recent folders box
|
// ** begin recent folders box
|
||||||
@@ -163,21 +165,24 @@ func (c *Controller) ServeUnlinkLastFMDo(r *http.Request) *Response {
|
|||||||
|
|
||||||
func (c *Controller) ServeLinkListenBrainzDo(r *http.Request) *Response {
|
func (c *Controller) ServeLinkListenBrainzDo(r *http.Request) *Response {
|
||||||
token := r.FormValue("token")
|
token := r.FormValue("token")
|
||||||
if token == "" {
|
url := r.FormValue("url")
|
||||||
|
if token == "" || url == "" {
|
||||||
return &Response{
|
return &Response{
|
||||||
err: "please provide a token",
|
redirect: r.Referer(),
|
||||||
code: 400,
|
flashW: []string{"please provide a url and token"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user := r.Context().Value(CtxUser).(*db.User)
|
user := r.Context().Value(CtxUser).(*db.User)
|
||||||
user.ListenBrainzSession = token
|
user.ListenBrainzURL = url
|
||||||
|
user.ListenBrainzToken = token
|
||||||
c.DB.Save(&user)
|
c.DB.Save(&user)
|
||||||
return &Response{redirect: "/admin/home"}
|
return &Response{redirect: "/admin/home"}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) ServeUnlinkListenBrainzDo(r *http.Request) *Response {
|
func (c *Controller) ServeUnlinkListenBrainzDo(r *http.Request) *Response {
|
||||||
user := r.Context().Value(CtxUser).(*db.User)
|
user := r.Context().Value(CtxUser).(*db.User)
|
||||||
user.ListenBrainzSession = ""
|
user.ListenBrainzURL = ""
|
||||||
|
user.ListenBrainzToken = ""
|
||||||
c.DB.Save(&user)
|
c.DB.Save(&user)
|
||||||
return &Response{redirect: "/admin/home"}
|
return &Response{redirect: "/admin/home"}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,10 @@ func (c *Controller) ServeScrobble(r *http.Request) *spec.Response {
|
|||||||
optSubmission := params.GetOrBool("submission", true)
|
optSubmission := params.GetOrBool("submission", true)
|
||||||
scrobbleErrs := []error{}
|
scrobbleErrs := []error{}
|
||||||
for _, scrobbler := range c.Scrobblers {
|
for _, scrobbler := range c.Scrobblers {
|
||||||
err = scrobbler.Scrobble(user, track, optStampMili, optSubmission)
|
if err := scrobbler.Scrobble(user, track, optStampMili, optSubmission); err != nil {
|
||||||
scrobbleErrs = append(scrobbleErrs, err)
|
scrobbleErrs = append(scrobbleErrs, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if len(scrobbleErrs) != 0 {
|
if len(scrobbleErrs) != 0 {
|
||||||
return spec.NewError(0, "error when submitting: %v", scrobbleErrs)
|
return spec.NewError(0, "error when submitting: %v", scrobbleErrs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ type User struct {
|
|||||||
Name string `gorm:"not null; unique_index" sql:"default: null"`
|
Name string `gorm:"not null; unique_index" sql:"default: null"`
|
||||||
Password string `gorm:"not null" sql:"default: null"`
|
Password string `gorm:"not null" sql:"default: null"`
|
||||||
LastFMSession string `sql:"default: null"`
|
LastFMSession string `sql:"default: null"`
|
||||||
ListenBrainzSession string `sql:"default: null"`
|
ListenBrainzURL string `sql:"default: null"`
|
||||||
|
ListenBrainzToken string `sql:"default: null"`
|
||||||
IsAdmin bool `sql:"default: null"`
|
IsAdmin bool `sql:"default: null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
baseURL = "https://api.listenbrainz.org"
|
BaseURL = "https://api.listenbrainz.org"
|
||||||
submitPath = "/1/submit-listens"
|
|
||||||
|
|
||||||
|
submitPath = "/1/submit-listens"
|
||||||
listenTypeSingle = "single"
|
listenTypeSingle = "single"
|
||||||
listenTypePlayingNow = "playing_now"
|
listenTypePlayingNow = "playing_now"
|
||||||
)
|
)
|
||||||
@@ -47,7 +47,7 @@ type Scrobble struct {
|
|||||||
type Scrobbler struct{}
|
type Scrobbler struct{}
|
||||||
|
|
||||||
func (s *Scrobbler) Scrobble(user *db.User, track *db.Track, stampMili int, submission bool) error {
|
func (s *Scrobbler) Scrobble(user *db.User, track *db.Track, stampMili int, submission bool) error {
|
||||||
if user.ListenBrainzSession == "" {
|
if user.ListenBrainzURL == "" || user.ListenBrainzToken == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
payload := Payload{
|
payload := Payload{
|
||||||
@@ -72,9 +72,9 @@ func (s *Scrobbler) Scrobble(user *db.User, track *db.Track, stampMili int, subm
|
|||||||
if err := json.NewEncoder(&payloadBuf).Encode(scrobble); err != nil {
|
if err := json.NewEncoder(&payloadBuf).Encode(scrobble); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
submitURL := fmt.Sprintf("%s%s", baseURL, submitPath)
|
submitURL := fmt.Sprintf("%s%s", user.ListenBrainzURL, submitPath)
|
||||||
authHeader := fmt.Sprintf("Token %s", user.ListenBrainzSession)
|
authHeader := fmt.Sprintf("Token %s", user.ListenBrainzToken)
|
||||||
req, _ := http.NewRequest("POST", submitURL, &payloadBuf)
|
req, _ := http.NewRequest(http.MethodPost, submitURL, &payloadBuf)
|
||||||
req.Header.Add("Authorization", authHeader)
|
req.Header.Add("Authorization", authHeader)
|
||||||
res, err := http.DefaultClient.Do(req)
|
res, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user