188 lines
4 KiB
Go
188 lines
4 KiB
Go
package gui
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"sync"
|
|
|
|
"github.com/diamondburned/gotk4/pkg/core/gerror"
|
|
"github.com/diamondburned/gotk4/pkg/gdkpixbuf/v2"
|
|
"github.com/diamondburned/gotk4/pkg/glib/v2"
|
|
"suruatoel.xyz/mcg/internal/client"
|
|
"suruatoel.xyz/mcg/internal/common"
|
|
)
|
|
|
|
type CoverLoader struct {
|
|
hostDir string
|
|
size int
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
func NewCoverLoader(host string) *CoverLoader {
|
|
loader := CoverLoader{}
|
|
loader.hostDir = loader.getHostDir(host)
|
|
loader.size = loader.readCacheSize()
|
|
|
|
return &loader
|
|
}
|
|
|
|
func (l *CoverLoader) SetSize(size int) {
|
|
if l.size != size {
|
|
log.Println("cache size has changed from", l.size, "to", size)
|
|
l.clearCache()
|
|
l.writeCacheSize(size)
|
|
l.size = size
|
|
}
|
|
}
|
|
|
|
func (l *CoverLoader) LoadThumbnail(album *common.Album) *gdkpixbuf.Pixbuf {
|
|
// Load cover from cache
|
|
pixbuf := l.getCached(album)
|
|
if pixbuf != nil {
|
|
return pixbuf
|
|
}
|
|
|
|
// Load cover from server
|
|
albumart := client.Instance().LoadAlbumartNow(album)
|
|
if albumart != nil {
|
|
pixbuf = l.loadImage(albumart)
|
|
}
|
|
if pixbuf != nil {
|
|
pixbuf = pixbuf.ScaleSimple(l.size, l.size, gdkpixbuf.InterpHyper)
|
|
if pixbuf != nil {
|
|
l.setCached(album, pixbuf)
|
|
}
|
|
}
|
|
|
|
return pixbuf
|
|
}
|
|
|
|
func (l *CoverLoader) getHostDir(host string) string {
|
|
cacheDir, cacheDirErr := os.UserCacheDir()
|
|
if cacheDirErr != nil {
|
|
log.Println("failed to detect user cache directory:", cacheDirErr)
|
|
return ""
|
|
}
|
|
|
|
hostDir := filepath.Join(cacheDir, "mcg", host)
|
|
|
|
return hostDir
|
|
}
|
|
|
|
func (l *CoverLoader) ensureHostDir() {
|
|
hostDirErr := os.MkdirAll(l.hostDir, 0o750)
|
|
if hostDirErr != nil {
|
|
log.Println("failed to create cache folder for host", l.hostDir, ":", hostDirErr)
|
|
}
|
|
}
|
|
|
|
func (l *CoverLoader) readCacheSize() int {
|
|
sizeFile := l.getCacheSizeFile()
|
|
if sizeFile == "" {
|
|
return 100
|
|
}
|
|
|
|
l.mutex.Lock()
|
|
defer l.mutex.Unlock()
|
|
|
|
content, readErr := os.ReadFile(sizeFile)
|
|
if readErr != nil {
|
|
log.Println("failed to read cache size file for host", l.hostDir, ":", readErr)
|
|
return 100
|
|
}
|
|
|
|
size, sizeErr := strconv.Atoi(string(content[:]))
|
|
if sizeErr != nil {
|
|
log.Println("invalid content of cache size file for host", l.hostDir, ":", readErr)
|
|
}
|
|
|
|
return size
|
|
}
|
|
|
|
func (l *CoverLoader) writeCacheSize(size int) {
|
|
l.ensureHostDir()
|
|
sizeFile := l.getCacheSizeFile()
|
|
if sizeFile == "" {
|
|
return
|
|
}
|
|
|
|
writeErr := os.WriteFile(sizeFile, []byte(fmt.Sprintf("%d", size)), 0o644)
|
|
if writeErr != nil {
|
|
log.Println("failed to write cache size file for host", l.hostDir, ":", writeErr)
|
|
}
|
|
}
|
|
|
|
func (l *CoverLoader) getCacheFile(album *common.Album) string {
|
|
if l.hostDir == "" {
|
|
return ""
|
|
}
|
|
|
|
return filepath.Join(l.hostDir, album.ID())
|
|
}
|
|
|
|
func (l *CoverLoader) getCacheSizeFile() string {
|
|
if l.hostDir == "" {
|
|
return ""
|
|
}
|
|
|
|
return filepath.Join(l.hostDir, "size")
|
|
}
|
|
|
|
func (l *CoverLoader) clearCache() {
|
|
if l.hostDir == "" {
|
|
return
|
|
}
|
|
|
|
removeErr := os.RemoveAll(l.hostDir)
|
|
if removeErr != nil {
|
|
log.Println("failed to clear cache folder for host", l.hostDir, ":", removeErr)
|
|
}
|
|
}
|
|
|
|
func (l *CoverLoader) getCached(album *common.Album) *gdkpixbuf.Pixbuf {
|
|
cacheFile := l.getCacheFile(album)
|
|
if cacheFile == "" {
|
|
return nil
|
|
}
|
|
|
|
pixbuf, pixbufErr := gdkpixbuf.NewPixbufFromFile(cacheFile)
|
|
if pixbufErr != nil {
|
|
if !isFileNotFoundError(pixbufErr) {
|
|
log.Println("failed to read cached thumbnail for host", l.hostDir, ":", pixbufErr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
return pixbuf
|
|
}
|
|
|
|
func isFileNotFoundError(err error) bool {
|
|
if gerr, isGerror := err.(*gerror.GError); isGerror {
|
|
return gerr.Quark() == uint32(glib.FileErrorQuark()) && gerr.ErrorCode() == int(glib.FileErrorNoent)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (l *CoverLoader) setCached(album *common.Album, pixbuf *gdkpixbuf.Pixbuf) {
|
|
cacheFile := l.getCacheFile(album)
|
|
if cacheFile == "" {
|
|
return
|
|
}
|
|
|
|
l.ensureHostDir()
|
|
pixbuf.Savev(cacheFile, "jpeg", []string{}, []string{})
|
|
}
|
|
|
|
func (l *CoverLoader) loadImage(file []byte) *gdkpixbuf.Pixbuf {
|
|
pixbufLoader, loaderErr := loadPixbuf(file)
|
|
if loaderErr != nil {
|
|
log.Println("failed to load image:", loaderErr)
|
|
return nil
|
|
}
|
|
|
|
return pixbufLoader.Pixbuf()
|
|
}
|