Compare commits
2 Commits
c06bd71a1a
...
37aabb3dfc
Author | SHA1 | Date |
---|---|---|
Martyn | 37aabb3dfc | |
Martyn | 7f1393c72d |
|
@ -6,7 +6,7 @@ replicaCount: 1
|
|||
|
||||
image:
|
||||
repository: imartyn/twitchsingstools
|
||||
pullPolicy: IfNotPresent
|
||||
pullPolicy: Always
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package webserver
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"sort"
|
||||
"unicode"
|
||||
|
||||
irc "git.martyn.berlin/martyn/twitchsingstools/internal/irc"
|
||||
"github.com/dustin/go-humanize"
|
||||
|
@ -249,6 +251,12 @@ func AdminHandler(response http.ResponseWriter, request *http.Request) {
|
|||
} else {
|
||||
fmt.Printf("Cache of %d performances is younger than an hour - %.1f hours old to be precise... not fetching.\n", len(ircBot.ChannelData[vars["channel"]].VideoCache), time.Now().Sub(ircBot.ChannelData[vars["channel"]].VideoCacheUpdated).Hours())
|
||||
}
|
||||
updateCalculatedFields(channelData.VideoCache)
|
||||
for _, song := range channelData.VideoCache {
|
||||
if song.Duet && song.OtherSinger == "" {
|
||||
fmt.Printf("WARNING: found duet with no other singer! %s", song.SongTitle) // should never happen but debug in case it does!
|
||||
}
|
||||
}
|
||||
topNSongs := calculateTopNSongs(channelData.VideoCache, 10)
|
||||
topNSingers := calculateTopNSingers(channelData.VideoCache, 10)
|
||||
var td = TemplateData{channelData.Name, channelData.Command, channelData.ExtraStrings, channelData.JoinTime, channelData.JoinTime.Format(irc.UTCFormat), false, channelData.HasLeft, AugmentSingsVideoStructSlice(channelData.VideoCache), topNSongs, topNSingers, vars["key"]}
|
||||
|
@ -408,28 +416,102 @@ func calculateTopNSongs(songCache []irc.SingsVideoStruct, howMany int) []SongSin
|
|||
return ret
|
||||
}
|
||||
|
||||
func IsLower(s string) bool {
|
||||
for _, r := range s {
|
||||
if !unicode.IsLower(r) && unicode.IsLetter(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func unmangleSingerName(MangledCaseName string, songCache []irc.SingsVideoStruct) string {
|
||||
options := make(map[string]string, 0)
|
||||
for _, record := range songCache {
|
||||
if strings.ToUpper(MangledCaseName) == strings.ToUpper(record.OtherSinger) {
|
||||
options[record.OtherSinger] = "WHATEVER"
|
||||
}
|
||||
}
|
||||
// One answer means we don't care upper, lower, mixed.
|
||||
if len(options) == 1 {
|
||||
for key := range options {
|
||||
return key
|
||||
}
|
||||
}
|
||||
// More than one is probably closed-beta where the name was lowercased.
|
||||
for key := range options {
|
||||
if !IsLower(key) {
|
||||
return key
|
||||
}
|
||||
}
|
||||
// Eep, we shouldn't get here, let's just return something.
|
||||
for key := range options {
|
||||
return key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func prependSong(x []SingerSings, y SingerSings) []SingerSings {
|
||||
x = append(x, SingerSings{})
|
||||
copy(x[1:], x)
|
||||
x[0] = y
|
||||
return x
|
||||
}
|
||||
|
||||
type kv struct {
|
||||
Key string
|
||||
Value int
|
||||
}
|
||||
|
||||
func getHeap(m map[string]int) *KVHeap {
|
||||
h := &KVHeap{}
|
||||
heap.Init(h)
|
||||
for k, v := range m {
|
||||
heap.Push(h, kv{k, v})
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
type KVHeap []kv
|
||||
|
||||
func (h KVHeap) Len() int { return len(h) }
|
||||
func (h KVHeap) Less(i, j int) bool { return h[i].Value > h[j].Value }
|
||||
func (h KVHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||
|
||||
func (h *KVHeap) Push(x interface{}) {
|
||||
*h = append(*h, x.(kv))
|
||||
}
|
||||
|
||||
func (h *KVHeap) Pop() interface{} {
|
||||
old := *h
|
||||
n := len(old)
|
||||
x := old[n-1]
|
||||
*h = old[0 : n-1]
|
||||
return x
|
||||
}
|
||||
|
||||
func calculateTopNSingers(songCache []irc.SingsVideoStruct, howMany int) []SingerSings {
|
||||
songMap := map[string]int{}
|
||||
songCount := 0
|
||||
for _, record := range songCache {
|
||||
if record.Duet {
|
||||
sings := songMap[record.OtherSinger]
|
||||
sings += 1
|
||||
songMap[record.OtherSinger] = sings
|
||||
sings := songMap[strings.ToUpper(record.OtherSinger)]
|
||||
sings++
|
||||
songCount++
|
||||
songMap[strings.ToUpper(record.OtherSinger)] = sings
|
||||
}
|
||||
}
|
||||
slice := make([]SingerSings, 0)
|
||||
for key, value := range songMap {
|
||||
ss := SingerSings{key, value}
|
||||
h := getHeap(songMap)
|
||||
for i := 0; i < howMany; i++ {
|
||||
deets := heap.Pop(h)
|
||||
position := i + 1
|
||||
fmt.Printf("%d) %#v\n", position, deets)
|
||||
ss := SingerSings{unmangleSingerName(deets.(kv).Key, songCache), deets.(kv).Value}
|
||||
slice = append(slice, ss)
|
||||
}
|
||||
sort.SliceStable(slice, func(i, j int) bool {
|
||||
return slice[i].Sings > slice[j].Sings
|
||||
})
|
||||
var ret []SingerSings
|
||||
for i := 1; i <= howMany; i++ {
|
||||
ret = append(ret, slice[i])
|
||||
}
|
||||
return ret
|
||||
fmt.Printf("Considered %d songs, Shan has %d\n", songCount, songMap["SHANXOX_"])
|
||||
return slice
|
||||
}
|
||||
|
||||
func calculateLastSungSongDate(songCache []irc.SingsVideoStruct, SongTitle string) time.Time {
|
||||
|
@ -450,6 +532,9 @@ func calculateLastSungSingerDate(songCache []irc.SingsVideoStruct, Singer string
|
|||
if strings.ToUpper(record.OtherSinger) == strings.ToUpper(Singer) {
|
||||
if record.Date.After(t) {
|
||||
t = record.Date
|
||||
if strings.ToUpper(Singer) == "SHANXOX_" {
|
||||
fmt.Printf("Last sang with %s (%s) %s", Singer, record.OtherSinger, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@
|
|||
</div>
|
||||
<div style="width: 100%; overflow-y: scroll; display: none;" id="datapanel" class="controlpanel">
|
||||
<table>
|
||||
<thead><tr><th>Published</th><th>Who</th><th>What</th><th>Last sang this song</th><th>Last dueted with performer</th></th></thead>
|
||||
<thead><tr><th>Published</th><th>What</th><th>Who</th><th>Last sang this song</th><th>Last dueted with performer</th></th></thead>
|
||||
{{ range .SongData }}
|
||||
<tr><td title="{{ .Date }}">{{ .NiceDate }}</td><td>{{ .SongTitle }}</td><td>{{ .OtherSinger }}</td><td title="{{ .LastSungSong }}">{{ .NiceLastSungSong }}</td><td title="{{ .LastSungSinger }}">{{ .NiceLastSungSinger }}</td></tr>
|
||||
{{ end }}
|
||||
|
@ -164,6 +164,7 @@
|
|||
<h3>Excel is not very good at handling CSV format it seems...</h3>
|
||||
<p>It is important to "Import Data" not "Open" the csv in many cases (8 year old discussion of this behaviour here) - from that post the instructions are : </p>
|
||||
<blockquote>In Excel, DATA tab, in the Get External Data subsection, click "From Text" and import your CSV in the Wizard.</blockquote>
|
||||
<p>LibreOffice calc kinda just works...just sayin' ;-)</p>
|
||||
</div>
|
||||
<div style="width: 100%; overflow-y: scroll; display: none;" id="botpanel" class="controlpanel">
|
||||
<h2>The bot isn't really ready yet... it just has the old Karaokards facility at the moment. I woudn't bother inviting it yet.</h2>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Published,Who,What,Last sang this song,Last dueted with performer
|
||||
Published,What,Who,Last sang this song,Last dueted with performer
|
||||
{{ range .SongData -}}
|
||||
{{- .NiceDate }},"{{ .SongTitle }}",{{ .OtherSinger }},{{ .NiceLastSungSong }},{{ .NiceLastSungSinger }}
|
||||
{{ end }}
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
@ -1,4 +1,4 @@
|
|||
Published Who What Last sang this song Last dueted with performer
|
||||
Published What Who Last sang this song Last dueted with performer
|
||||
{{ range .SongData -}}
|
||||
{{- .NiceDate }} "{{ .SongTitle }}" {{ .OtherSinger }} {{ .NiceLastSungSong }} {{ .NiceLastSungSinger }}
|
||||
{{ end }}
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
Loading…
Reference in New Issue