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