ditty/library.go

93 lines
2.0 KiB
Go

package main
import (
"io/ioutil"
"log"
"os"
"path"
"sort"
"strings"
"github.com/dhowden/tag"
)
type Metadata struct {
Title string
Artist string
Album string
Track int
}
func readMetadata(f *os.File) *Metadata {
var metadata Metadata
m, err := tag.ReadFrom(f)
if err != nil || m.Title() == "" {
metadata.Title = path.Base(f.Name())
} else {
metadata.Title = m.Title()
metadata.Artist = m.Artist()
metadata.Album = m.Album()
metadata.Track, _ = m.Track()
}
return &metadata
}
type LibraryEntry struct {
File os.FileInfo
Metadata *Metadata
}
func (e *LibraryEntry) String() string {
if e.Metadata.Title != "" {
if e.Metadata.Artist != "" {
return e.Metadata.Artist + " - " + e.Metadata.Title
}
return e.Metadata.Title
}
return e.File.Name()
}
func scanFolder(scanPath string) []*LibraryEntry {
files, err := ioutil.ReadDir(scanPath)
if err != nil {
log.Fatalf("failed to scan %s: %s", scanPath, err)
}
var entries []*LibraryEntry
for _, fileInfo := range files {
if fileInfo.IsDir() {
entries = append(entries, &LibraryEntry{File: fileInfo, Metadata: &Metadata{Title: fileInfo.Name()}})
continue
} else if !supportedFormat(fileInfo.Name()) {
continue
}
f, err := os.Open(path.Join(scanPath, fileInfo.Name()))
if err != nil {
continue
}
metadata := readMetadata(f)
f.Close()
entries = append(entries, &LibraryEntry{File: fileInfo, Metadata: metadata})
}
sort.Slice(entries, func(i, j int) bool {
if entries[i].File.IsDir() != entries[j].File.IsDir() {
return entries[i].File.IsDir()
}
if entries[i].Metadata.Album != "" && strings.ToLower(entries[i].Metadata.Album) == strings.ToLower(entries[j].Metadata.Album) && (entries[i].Metadata.Track > 0 || entries[j].Metadata.Track > 0) {
return entries[i].Metadata.Track < entries[j].Metadata.Track
}
return strings.ToLower(entries[i].Metadata.Album) < strings.ToLower(entries[j].Metadata.Album) && strings.ToLower(entries[i].File.Name()) < strings.ToLower(entries[j].File.Name())
})
return entries
}