Sigrid Solveig Haflínudóttirallow "FLAC" file type79025724 years agoHistory
211 lines · 4.8 KB · Go
RawDownload
package main import (	"bytes"	"fmt"	"io"	"io/ioutil"	"os"	"path/filepath"	"strconv"	"strings" 	"git.sr.ht/~ft/cue"	"github.com/gammazero/workerpool") type Input struct {	Path  string       `json:"path"`	Audio []*AudioFile `json:"audio"` 	TrackNumberFmt string `json:"-"` 	Composer    string `json:"composer,omitempty"`	Performer   string `json:"performer,omitempty"`	SongWriter  string `json:"songWriter,omitempty"`	Title       string `json:"title,omitempty"`	Genre       string `json:"genre,omitempty"`	Date        string `json:"date,omitempty"`	TotalTracks int    `json:"totalTracks,omitempty"`	TotalDisks  int    `json:"totalDisks,omitempty"`} func NewInput(path string) (in *Input, err error) {	in = &Input{Path: path} 	var cueReader io.ReadCloser	if cueReader, err = openFileUTF8(path); err != nil {		return	}	defer cueReader.Close() 	cueRaw, _ := ioutil.ReadAll(cueReader)	cueRaw = bytes.TrimPrefix(cueRaw, []byte{0xef, 0xbb, 0xbf}) // remove the nasty BOM	var sheet *cue.Sheet	if sheet, err = cueSheetFromBytes(cueRaw); err != nil {		return	} 	dirPath := filepath.Dir(path)	var audio *AudioFile	var filesFromCue []*cue.File	for _, f := range sheet.Files {		if f.Type != cue.FileTypeWave && f.Type != cue.FileTypeFlac {			continue		} else if audio, err = NewAudio(filepath.Join(dirPath, f.Name)); err != nil {			err = fmt.Errorf("%s: %s", f.Name, err)			return		}		in.Audio = append(in.Audio, audio)		filesFromCue = append(filesFromCue, f)	}	if len(in.Audio) < 1 {		return nil, fmt.Errorf("no audio files")	} 	in.Performer = sheet.Performer	in.SongWriter = sheet.Songwriter	in.Title = sheet.Title 	var diskNumber int	for _, c := range sheet.Comments {		if words := strings.SplitN(c, " ", 2); len(words) < 2 {			continue		} else {			switch words[0] {			case "DATE":				in.Date = words[1]			case "GENRE":				in.Genre = words[1]			case "COMPOSER":				in.Composer = words[1]			case "DISCNUMBER":				if len(in.Audio) == 1 {					// FIXME no idea what to do with several discnumber comments in a cue sheet					if diskNumber, err = strconv.Atoi(words[1]); err != nil {						return					}				}			case "TOTALDISCS":				in.TotalDisks, err = strconv.Atoi(words[1])			}		}	} 	for i, file := range filesFromCue {		audio = in.Audio[i] 		var prevAudioTrack *Track		audio.Tracks = make([]*Track, 0)		for _, ft := range file.Tracks {			if prevAudioTrack != nil && prevAudioTrack.EndAtSample == 0 {				prevAudioTrack.SetNextIndexes(audio.SampleRate, ft.Indexes)				prevAudioTrack = nil			}			if ft.DataType != cue.DataTypeAudio {				continue			} 			t := &Track{				Number:      ft.Number,				Title:       ft.Title,				Performer:   ft.Performer,				SongWriter:  ft.Songwriter,				Album:       in.Title,				Genre:       in.Genre,				Date:        in.Date,				TotalTracks: &in.TotalTracks,				TotalDisks:  in.TotalDisks,				DiskNumber:  diskNumber,			}			for _, c := range ft.Comments {				if strings.HasPrefix(c, "COMPOSER") {					words := strings.SplitAfterN(c, " ", 2)					t.Composer = words[1]				}			}			if t.Performer == "" {				t.Performer = in.Performer			}			if t.SongWriter == "" {				t.SongWriter = in.SongWriter			} 			audio.Tracks = append(audio.Tracks, t)			in.TotalTracks++			if t.Number == 0 {				t.Number = len(audio.Tracks)			}			if err = t.SetIndexes(audio.SampleRate, ft.Indexes); err != nil {				return			}			prevAudioTrack = t		}	} 	if in.TotalTracks > 99 {		in.TrackNumberFmt = "%03d"	} else {		in.TrackNumberFmt = "%02d"	} 	return} func (in *Input) Artist() string {	switch {	case in.Composer != "":		return in.Composer	case in.SongWriter != "":		return in.SongWriter	case in.Performer != "":		return in.Performer	} 	var artist string	for _, a := range in.Audio {		for _, t := range a.Tracks[1:] {			if t.Artist() != artist && artist != "" {				return "Various Artists"			}			artist = t.Artist()		}	} 	return "Unknown Artist"} func (in *Input) Split(pool *workerpool.WorkerPool, firstErr chan<- error) (err error) {	for _, a := range in.Audio {		for _, t := range a.Tracks {			if len(trackArgs) > 0 && !trackArgs.Has(t.Number) {				continue			} 			trackPathBuilder := new(strings.Builder)			err = nameTmpl.Execute(trackPathBuilder, &struct {				Input *Input				Track *Track			}{in, t})			if err != nil {				return			}			trackPath := filepath.Join(*outputDir, trackPathBuilder.String()+"."+*format)			if err = os.MkdirAll(filepath.Dir(trackPath), 0755); err != nil {				return			} 			pool.Submit(func(a *AudioFile, t *Track, trackPath string) func() {				return func() {					if err = a.Extract(t, trackPath); err != nil {						firstErr <- fmt.Errorf("%s: %s", trackPath, err)					} else if !*quiet {						fmt.Printf("%s\n", trackPath)					}				}			}(a, t, trackPath))		}	} 	return}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t