-
Notifications
You must be signed in to change notification settings - Fork 0
/
bundle.go
154 lines (130 loc) · 4.08 KB
/
bundle.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package audioc
import (
"os"
"fmt"
"image"
"regexp"
"strings"
"strconv"
"io/ioutil"
"path/filepath"
"github.com/jamlib/libaudio/fsutil"
"github.com/jamlib/audioc/metadata"
"github.com/jamlib/audioc/albumart"
)
// process each bundle or folder of audio files
func (a *audioc) processBundle(indexes []int) error {
var err error
fullDir := filepath.Dir(filepath.Join(a.Config.Dir, a.Files[indexes[0]]))
// skip folder if possible (unless --force)
if !a.Config.Force && a.skipFolder(a.Files[indexes[0]]) {
return nil
}
fmt.Printf("\nProcessing: %v ...\n", fullDir)
if a.Config.Write {
// create new random workdir within current path
a.Workdir, err = ioutil.TempDir(fullDir, "")
if err != nil {
return err
}
}
// process artwork once per folder
err = a.processArtwork(a.Files[indexes[0]])
if err != nil {
return err
}
// process folder via threads returning the resulting metadata slice
// a.processThreaded (thread.go) calls a.processFile(file.go) for each index
mdSlice, err := a.processThreaded(indexes)
if err != nil {
return err
}
if a.Config.Write {
// explicitly remove workdir (before folder is possibly renamed)
os.RemoveAll(a.Workdir)
// TODO: iterate through mdSlice moving each file individually instead of
// assuming all belong to same resulting directory
fullResultD := filepath.Dir(filepath.Join(a.Config.Dir, mdSlice[0].Resultpath))
// if not same dir, rename directory to target dir
if fullDir != fullResultD {
_, err = fsutil.MergeFolder(fullDir, fullResultD, mergeFolderFunc)
if err != nil {
return err
}
}
// remove parent folder if no longer contains audio files
parentDir := filepath.Dir(fullDir)
if info, err := os.Stat(parentDir); err == nil && info.IsDir() {
if len(fsutil.FilesAudio(parentDir)) == 0 {
// is a directory (not symlink) and contains no audio files
err = os.RemoveAll(parentDir)
if err != nil {
return err
}
}
}
}
return nil
}
// helper to determine if bundle should be skipped by analyzing the
// first audio files album folder
func (a *audioc) skipFolder(path string) bool {
pa := strings.Split(path, fsutil.PathSep)
// determine which folder in path is the album name
var alb string
if a.Config.Collection {
// true if --collection & artist path contains " - "
if strings.Index(pa[0], " - ") != -1 {
return true
}
if len(pa) > 3 {
// Artist / Year / Album / File
alb = pa[2]
}
} else {
// if --artist, set to innermost dir
if len(pa) > 1 {
alb = pa[len(pa)-2]
}
}
// true if album folder matches metadata.ToAlbum
if len(alb) > 0 {
if a.Config.Album != "" {
// if --album matches album folder
if a.Config.Album == alb {
return true
}
} else {
// derive metadata from album folder and see if it matches
m := metadata.New(alb)
if m.Info.ToAlbum() == alb {
return true
}
}
}
return false
}
// process album art once per folder of files
func (a *audioc) processArtwork(file string) error {
art := &albumart.AlbumArt{ Ffmpeg: a.Ffmpeg, Ffprobe: a.Ffprobe,
ImgDecode: image.DecodeConfig, WithParentDir: true,
Fullpath: filepath.Join(a.Config.Dir, file) }
var err error
a.Image = ""
if a.Config.Write {
a.Image, err = albumart.Process(art)
}
return err
}
// passed to fsutil.MergeFolder, this only merges files into the same folder
// if the disc and track number don't already exist in a current file, else it
// creates an equivalent folder with (1) appended to end, copying conflicting
// files to this location. {Info.title} is currently not used, only disc/track.
func mergeFolderFunc(f string) (int, string) {
// use metadata to obtain info from filename
m := metadata.New(f)
disc, _ := strconv.Atoi(regexp.MustCompile(`^\d+`).FindString(m.Info.Disc))
track, _ := strconv.Atoi(regexp.MustCompile(`^\d+`).FindString(m.Info.Track))
// combine disc & track into unique integer
return (disc*1000)+track, m.Info.Title
}