diff --git a/admin/components/release/release-list-item.html b/admin/components/release/release-list-item.html
index 4b8f41e..677318d 100644
--- a/admin/components/release/release-list-item.html
+++ b/admin/components/release/release-list-item.html
@@ -7,7 +7,7 @@
{{.Title}}
- {{.ReleaseDate.Year}}
+ {{.GetReleaseYear}}
{{if not .Visible}}(hidden){{end}}
diff --git a/cursor/cursor.go b/cursor/cursor.go
index 4ed59e3..4e4504f 100644
--- a/cursor/cursor.go
+++ b/cursor/cursor.go
@@ -88,13 +88,13 @@ func handleClient(client *CursorClient) {
client.Route = args[1]
mutex.Lock()
- for otherClientID, otherClient := range clients {
- if otherClientID == client.ID || otherClient.Route != client.Route { continue }
- client.Send([]byte(fmt.Sprintf("join:%d", otherClientID)))
- client.Send([]byte(fmt.Sprintf("pos:%d:%f:%f", otherClientID, otherClient.X, otherClient.Y)))
+ for _, otherClient := range clients {
+ if otherClient.ID == client.ID { continue }
+ if otherClient.Route != client.Route { continue }
+ client.Send([]byte(fmt.Sprintf("join:%d", otherClient.ID)))
+ client.Send([]byte(fmt.Sprintf("pos:%d:%f:%f", otherClient.ID, otherClient.X, otherClient.Y)))
}
mutex.Unlock()
-
broadcast <- CursorMessage{
[]byte(fmt.Sprintf("join:%d", client.ID)),
client.Route,
diff --git a/model/artist.go b/model/artist.go
index 63871c7..733e537 100644
--- a/model/artist.go
+++ b/model/artist.go
@@ -9,6 +9,10 @@ type (
}
)
+func (artist Artist) GetWebsite() string {
+ return artist.Website
+}
+
func (artist Artist) GetAvatar() string {
if artist.Avatar == "" {
return "/img/default-avatar.png"
diff --git a/model/artist_test.go b/model/artist_test.go
deleted file mode 100644
index feb9a18..0000000
--- a/model/artist_test.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package model
-
-import (
- "testing"
-)
-
-func Test_Artist_GetAvatar(t *testing.T) {
- want := "testavatar.png"
- artist := Artist{ Avatar: want }
-
- got := artist.GetAvatar()
- if want != got {
- t.Errorf(`correct value not returned when avatar is populated (want "%s", got "%s")`, want, got)
- }
-
- artist = Artist{}
-
- want = "/img/default-avatar.png"
- got = artist.GetAvatar()
- if want != got {
- t.Errorf(`default value not returned when avatar is empty (want "%s", got "%s")`, want, got)
- }
-}
diff --git a/model/link.go b/model/link.go
index 1a5bb8f..8b48ced 100644
--- a/model/link.go
+++ b/model/link.go
@@ -11,6 +11,6 @@ type Link struct {
}
func (link Link) NormaliseName() string {
- rgx := regexp.MustCompile(`[^a-z0-9\-]`)
- return rgx.ReplaceAllString(strings.ToLower(link.Name), "")
+ rgx := regexp.MustCompile(`[^a-z0-9]`)
+ return strings.ToLower(rgx.ReplaceAllString(link.Name, ""))
}
diff --git a/model/link_test.go b/model/link_test.go
deleted file mode 100644
index b368094..0000000
--- a/model/link_test.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package model
-
-import (
- "testing"
-)
-
-func Test_Link_NormaliseName(t *testing.T) {
- link := Link{
- Name: "!c@o#o$l%-^a&w*e(s)o_m=e+-[l{i]n}k-0123456789ABCDEF",
- }
-
- want := "cool-awesome-link-0123456789abcdef"
- got := link.NormaliseName()
- if want != got {
- t.Errorf(`name with invalid characters not properly formatted (want "%s", got "%s")`, want, got)
- }
-
- link.Name = want
- got = link.NormaliseName()
- if want != got {
- t.Errorf(`valid name mangled by formatter (want "%s", got "%s")`, want, got)
- }
-}
diff --git a/model/release.go b/model/release.go
index afaacca..42d6fba 100644
--- a/model/release.go
+++ b/model/release.go
@@ -50,6 +50,10 @@ func (release Release) PrintReleaseDate() string {
return release.ReleaseDate.Format("02 January 2006")
}
+func (release Release) GetReleaseYear() int {
+ return release.ReleaseDate.Year()
+}
+
func (release Release) GetArtwork() string {
if release.Artwork == "" {
return "/img/default-cover-art.png"
diff --git a/model/release_test.go b/model/release_test.go
deleted file mode 100644
index 11a58a1..0000000
--- a/model/release_test.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package model
-
-import (
- "testing"
- "time"
-)
-
-func Test_Release_DescriptionHTML(t *testing.T) {
- release := Release{
- Description: "this is\na test\ndescription!",
- }
-
- // descriptions are set by privileged users,
- // so we'll allow HTML injection here
- want := "this is
a test
description!"
- got := release.GetDescriptionHTML()
- if want != string(got) {
- t.Errorf(`release description incorrectly formatted (want "%s", got "%s")`, want, got)
- }
-}
-
-func Test_Release_ReleaseDate(t *testing.T) {
- release := Release{
- ReleaseDate: time.Date(2025, time.July, 26, 16, 0, 0, 0, time.UTC),
- }
-
- want := "2025-07-26T16:00"
- got := release.TextReleaseDate()
- if want != got {
- t.Errorf(`release date incorrectly formatted (want "%s", got "%s")`, want, got)
- }
-
- want = "26 July 2025"
- got = release.PrintReleaseDate()
- if want != got {
- t.Errorf(`release date (print) incorrectly formatted (want "%s", got "%s")`, want, got)
- }
-}
-
-func Test_Release_Artwork(t *testing.T) {
- want := "testartwork.png"
- release := Release{ Artwork: want }
-
- got := release.GetArtwork()
- if want != got {
- t.Errorf(`correct value not returned when artwork is populated (want "%s", got "%s")`, want, got)
- }
-
- release = Release{}
-
- want = "/img/default-cover-art.png"
- got = release.GetArtwork()
- if want != got {
- t.Errorf(`default value not returned when artwork is empty (want "%s", got "%s")`, want, got)
- }
-}
-
-func Test_Release_IsSingle(t *testing.T) {
- release := Release{
- Tracks: []*Track{},
- }
-
- if release.IsSingle() {
- t.Errorf("IsSingle() == true when no tracks are present")
- }
-
- release.Tracks = append(release.Tracks, &Track{})
- if !release.IsSingle() {
- t.Errorf("IsSingle() == false when one track is present")
- }
-
- release.Tracks = append(release.Tracks, &Track{})
- if release.IsSingle() {
- t.Errorf("IsSingle() == true when >1 tracks are present")
- }
-}
-
-func Test_Release_IsReleased(t *testing.T) {
- release := Release {
- ReleaseDate: time.Now(),
- }
-
- if !release.IsReleased() {
- t.Errorf("IsRelease() == false when release date in the past")
- }
-
- release.ReleaseDate = time.Now().Add(time.Hour)
- if release.IsReleased() {
- t.Errorf("IsRelease() == true when release date in the future")
- }
-}
-
-func Test_Release_PrintArtists(t *testing.T) {
- artist1 := "ari melody"
- artist2 := "aridoodle"
- artist3 := "idk"
- artist4 := "guest"
-
- release := Release {
- Credits: []*Credit{
- { Artist: Artist{ Name: artist1 }, Primary: true },
- { Artist: Artist{ Name: artist2 }, Primary: true },
- { Artist: Artist{ Name: artist3 }, Primary: false },
- { Artist: Artist{ Name: artist4 }, Primary: true },
- },
- }
-
- {
- want := []string{ artist1, artist2, artist4 }
- got := release.GetUniqueArtistNames(true)
- if len(want) != len(got) {
- t.Errorf(`len(GetUniqueArtistNames) (primary only) == %d, want %d`, len(got), len(want))
- }
- for i := range got {
- if want[i] != got[i] {
- t.Errorf(`GetUniqueArtistNames[%d] (primary only) == %s, want %s`, i, got[i], want[i])
- }
- }
-
- want = []string{ artist1, artist2, artist3, artist4 }
- got = release.GetUniqueArtistNames(false)
- if len(want) != len(got) {
- t.Errorf(`len(GetUniqueArtistNames) == %d, want %d`, len(got), len(want))
- }
- for i := range got {
- if want[i] != got[i] {
- t.Errorf(`GetUniqueArtistNames[%d] == %s, want %s`, i, got[i], want[i])
- }
- }
- }
-
- {
- want := "ari melody, aridoodle & guest"
- got := release.PrintArtists(true, true)
- if want != got {
- t.Errorf(`PrintArtists (primary only, ampersand) == "%s", want "%s"`, want, got)
- }
-
- want = "ari melody, aridoodle, guest"
- got = release.PrintArtists(true, false)
- if want != got {
- t.Errorf(`PrintArtists (primary only) == "%s", want "%s"`, want, got)
- }
-
- want = "ari melody, aridoodle, idk & guest"
- got = release.PrintArtists(false, true)
- if want != got {
- t.Errorf(`PrintArtists (all, ampersand) == "%s", want "%s"`, want, got)
- }
-
- want = "ari melody, aridoodle, idk, guest"
- got = release.PrintArtists(false, false)
- if want != got {
- t.Errorf(`PrintArtists (all) == "%s", want "%s"`, want, got)
- }
- }
-}
diff --git a/model/track_test.go b/model/track_test.go
deleted file mode 100644
index fd500d7..0000000
--- a/model/track_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package model
-
-import (
- "testing"
-)
-
-func Test_Track_DescriptionHTML(t *testing.T) {
- track := Track{
- Description: "this is\na test\ndescription!",
- }
-
- // descriptions are set by privileged users,
- // so we'll allow HTML injection here
- want := "this is
a test
description!"
- got := track.GetDescriptionHTML()
- if want != string(got) {
- t.Errorf(`track description incorrectly formatted (want "%s", got "%s")`, want, got)
- }
-}
-
-func Test_Track_LyricsHTML(t *testing.T) {
- track := Track{
- Lyrics: "these are\ntest\nlyrics!",
- }
-
- // lyrics are set by privileged users,
- // so we'll allow HTML injection here
- want := "these are
test
lyrics!"
- got := track.GetLyricsHTML()
- if want != string(got) {
- t.Errorf(`track lyrics incorrectly formatted (want "%s", got "%s")`, want, got)
- }
-}
-
-func Test_Track_Add(t *testing.T) {
- track := Track{}
-
- want := 4
- got := track.Add(2, 2)
- if want != got {
- t.Errorf(`somehow, we screwed up addition. (want %d, got %d)`, want, got)
- }
-}
diff --git a/public/script/config.js b/public/script/config.js
index 402a74b..1ab8b5a 100644
--- a/public/script/config.js
+++ b/public/script/config.js
@@ -55,7 +55,6 @@ class Config {
get crt() { return this._crt }
set crt(/** @type boolean */ enabled) {
this._crt = enabled;
- this.save();
if (enabled) {
document.body.classList.add("crt");
@@ -67,24 +66,26 @@ class Config {
this.#listeners.get('crt').forEach(callback => {
callback(this._crt);
})
+
+ this.save();
}
get cursor() { return this._cursor }
set cursor(/** @type boolean */ value) {
this._cursor = value;
- this.save();
this.#listeners.get('cursor').forEach(callback => {
callback(this._cursor);
})
+ this.save();
}
get cursorFunMode() { return this._cursorFunMode }
set cursorFunMode(/** @type boolean */ value) {
this._cursorFunMode = value;
- this.save();
this.#listeners.get('cursorFunMode').forEach(callback => {
callback(this._cursorFunMode);
})
+ this.save();
}
}
diff --git a/public/script/cursor.js b/public/script/cursor.js
index 79637fe..188cdbb 100644
--- a/public/script/cursor.js
+++ b/public/script/cursor.js
@@ -328,7 +328,7 @@ function cursorSetup() {
switch (args[0]) {
case 'id': {
- myCursor.id = id;
+ myCursor.id = Number(args[1]);
break;
}
case 'join': {
@@ -385,6 +385,8 @@ function cursorDestroy() {
cursors.clear();
myCursor = null;
+ cursorContainer.remove();
+
console.log(`Cursor no longer tracking.`);
running = false;
}
diff --git a/views/music-gateway.html b/views/music-gateway.html
index 0f4441c..1bf3a2f 100644
--- a/views/music-gateway.html
+++ b/views/music-gateway.html
@@ -4,7 +4,7 @@
-
+
@@ -54,7 +54,7 @@
{{.Title}}
- {{.ReleaseDate.Year}}
+ {{.GetReleaseYear}}
{{.PrintArtists true true}}
{{if .IsReleased}}
@@ -91,7 +91,7 @@
{{end}}
{{if and .Copyright .CopyrightURL}}
-
{{.Title}} © {{.ReleaseDate.Year}} by {{.PrintArtists true true}} is licensed under {{.Copyright}}
+
{{.Title}} © {{.GetReleaseYear}} by {{.PrintArtists true true}} is licensed under {{.Copyright}}
{{end}}
@@ -105,8 +105,8 @@
{{range .Credits}}
{{$Artist := .Artist}}
- {{if $Artist.Website}}
- - {{$Artist.Name}}: {{.Role}}
+ {{if $Artist.GetWebsite}}
+ - {{$Artist.Name}}: {{.Role}}
{{else}}
- {{$Artist.Name}}: {{.Role}}
{{end}}