1
0

icecastLastPlayedSongs was replaced by icecastCurrentSong that fetch only one song at the very end of a playlist.log. Also added a benchmark for this func.

This commit is contained in:
Alexander Andreev 2023-09-15 04:19:28 +04:00
parent 7bb91cfcbe
commit 60045d4ca2
Signed by: Arav
GPG Key ID: D22A817D95815393
2 changed files with 50 additions and 50 deletions

View File

@ -19,7 +19,9 @@ const (
IcecastPlaylistDateFormat = "02/Jan/2006:15:04:05 -0700" IcecastPlaylistDateFormat = "02/Jan/2006:15:04:05 -0700"
SongTimeFormat = "2006 15:04-0700" SongTimeFormat = "2006 15:04-0700"
bufferSizePerLine = 320 bufferSizePerLine = 512
separatorOne = 26
separatorTwo = 38 + 1
) )
var ( var (
@ -96,61 +98,46 @@ func IcecastLastSong(playlistPath string) *Song {
return nil return nil
} }
func icecastLastPlayedSongs(playlistPath string, n int) ([]Song, error) { func icecastCurrentSong(playlistPath string) (*Song, error) {
var buf []byte fd, err := os.Open(playlistPath)
var offset int64 = 0
var bufferSize int64 = int64(n) * bufferSizePerLine
playlist, err := os.Open(playlistPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer playlist.Close() defer fd.Close()
playlist_stat, _ := playlist.Stat() fdSize, _ := fd.Seek(0, io.SeekEnd)
if fdSize == 0 {
if playlist_stat.Size() == 0 {
return nil, nil return nil, nil
} }
if playlist_stat.Size() < bufferSize { var bufSize int64 = bufferSizePerLine
buf = make([]byte, playlist_stat.Size()) if fdSize < bufferSizePerLine {
} else { bufSize = fdSize
buf = make([]byte, bufferSize)
offset = playlist_stat.Size() - bufferSize
} }
_, err = playlist.ReadAt(buf, offset) _, err = fd.Seek(-bufSize, io.SeekEnd)
if err != nil && err != io.EOF { if err != nil {
return nil, err return nil, err
} }
lines := bytes.Split(buf, []byte("\n")) buf := make([]byte, bufSize)
if len(lines) < 2 { _, err = fd.Read(buf)
return nil, nil if err != nil {
return nil, err
} }
lines = lines[:len(lines)-1] curSongEnd := bytes.LastIndexByte(buf, '\n')
line := buf[bytes.LastIndexByte(buf[:curSongEnd], '\n')+1 : curSongEnd]
if len(lines) > n { songTime, _ := time.Parse(IcecastPlaylistDateFormat, string(line[:separatorOne]))
lines = lines[len(lines)-n:]
}
songs := make([]Song, 0, len(lines)) separatorThree := bytes.LastIndexByte(line, '|')
for _, line := range lines { return &Song{
fields := bytes.Split(line, []byte("|")) Time: songTime.Format(SongTimeFormat),
Listeners: string(line[separatorTwo:separatorThree]),
tim, _ := time.Parse(IcecastPlaylistDateFormat, string(fields[0])) Song: string(line[separatorThree+1:])}, nil
songs = append(songs, Song{
Time: tim.Format(SongTimeFormat),
Listeners: string(fields[2]),
Song: string(fields[3])})
}
return songs, nil
} }
type PlaylistLogWatcher struct { type PlaylistLogWatcher struct {
@ -180,13 +167,14 @@ func (pw *PlaylistLogWatcher) Watch(playlistPath string, n int) (err error) {
pw.watcher.WatchForMask(pw.changed, watcher.ModIgnMask) pw.watcher.WatchForMask(pw.changed, watcher.ModIgnMask)
if lastPlayedCache == nil { if lastPlayedCache == nil {
lastPlayedCache = make([]Song, n) lastPlayedCache = make([]Song, 0, n)
songs, err := icecastLastPlayedSongs(playlistPath, n) }
if err == nil && len(songs) > 0 {
copy(lastPlayedCache, songs) cur, err := icecastCurrentSong(playlistPath)
} else if err != nil { if err != nil {
log.Fatalln("failed to retrieve last songs:", err) log.Println("failed to fetch current song:", err)
} } else if cur != nil && currentlyPlaying.Time != "" {
currentlyPlaying = *cur
} }
go func() { go func() {
@ -195,19 +183,19 @@ func (pw *PlaylistLogWatcher) Watch(playlistPath string, n int) (err error) {
if mask&syscall.IN_MODIFY > 0 { if mask&syscall.IN_MODIFY > 0 {
lastPlayedCacheMutex.Lock() lastPlayedCacheMutex.Lock()
songs, err := icecastLastPlayedSongs(playlistPath, 1) song, err := icecastCurrentSong(playlistPath)
if err == nil && len(songs) > 0 { if err == nil && song != nil {
CheckAndUpdateMostListenedSong(song, &currentlyPlaying) CheckAndUpdateMostListenedSong(song, &currentlyPlaying)
if currentlyPlaying.Time == "" { if currentlyPlaying.Time == "" {
currentlyPlaying = songs[0] currentlyPlaying = *song
} else { } else {
currentlyPlaying.Listeners = songs[0].Listeners currentlyPlaying.Listeners = song.Listeners
if len(lastPlayedCache) == n { if len(lastPlayedCache) == n {
lastPlayedCache = append(lastPlayedCache[1:], currentlyPlaying) lastPlayedCache = append(lastPlayedCache[1:], currentlyPlaying)
} else { } else {
lastPlayedCache = append(lastPlayedCache, currentlyPlaying) lastPlayedCache = append(lastPlayedCache, currentlyPlaying)
} }
currentlyPlaying = songs[0] currentlyPlaying = *song
} }
} else if err != nil { } else if err != nil {
log.Println("failed to retrieve last songs:", err) log.Println("failed to retrieve last songs:", err)

View File

@ -0,0 +1,12 @@
package radio
import "testing"
const playlistPath = "../../p.log"
func BenchmarkIcecastCurrentSong(b *testing.B) {
for i := 0; i < b.N; i++ {
s, err := icecastCurrentSong(playlistPath)
b.Log(s, err)
}
}