ditty/library.go

122 lines
2.5 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
Path string
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 {
p := path.Join(scanPath, fileInfo.Name())
b := path.Base(fileInfo.Name())
if fileInfo.IsDir() {
if b != "" && (b[0] != '.' || showHiddenFolders) {
entries = append(entries, &libraryEntry{File: fileInfo, Path: p, Metadata: &metadata{Title: fileInfo.Name()}})
}
continue
} else if !supportedFormat(b) {
continue
}
f, err := os.Open(p)
if err != nil {
continue
}
metadata := readMetadata(f)
f.Close()
entries = append(entries, &libraryEntry{File: fileInfo, Path: p, 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
}
func scanFolderRecursively(path string) []*libraryEntry {
var entries []*libraryEntry
scanFiles := scanFolder(path)
for _, entry := range scanFiles {
if !entry.File.IsDir() {
continue
}
entries = append(entries, scanFolderRecursively(entry.Path)...)
}
for _, entry := range scanFiles {
if entry.File.IsDir() {
continue
}
entries = append(entries, entry)
}
return entries
}