Add GTK application implementation
This commit is contained in:
parent
d1bb505e0a
commit
b7c0307f6b
29 changed files with 2564 additions and 266 deletions
188
internal/gui/coverloader.go
Normal file
188
internal/gui/coverloader.go
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
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()
|
||||
}
|
||||
Loading…
Reference in a new issue