diff options
Diffstat (limited to 'downloader/downloader.go')
| -rw-r--r-- | downloader/downloader.go | 180 |
1 files changed, 0 insertions, 180 deletions
diff --git a/downloader/downloader.go b/downloader/downloader.go deleted file mode 100644 index b7645da..0000000 --- a/downloader/downloader.go +++ /dev/null @@ -1,180 +0,0 @@ -package downloader - -import ( - "io/ioutil" - "os" - "os/exec" - "strconv" - "sync" - "time" - - "github.com/mammothbane/thulani-go/wav" -) - -// downloader handles a download for a particular song. -type downloader struct { - Url string - - StartTime time.Duration - Duration time.Duration - EndTime time.Duration - - once sync.Once - done chan struct{} - pb chan *wavBundle - - info videoInfo -} - -const clipTime = 10 * time.Second -const preloadCount = 5 - -func newDownload(url string, startTime, dur time.Duration) (*downloader, error) { - vInfo, err := info(url) - if err != nil { - return nil, err - } - - if dur == 0 { - dur = vInfo.Duration - startTime - } - - dl := &downloader{ - Url: url, - - StartTime: startTime, - Duration: dur, - EndTime: startTime + dur, - - done: make(chan struct{}, 1), - pb: make(chan *wavBundle, preloadCount), - info: *vInfo, - } - - go dl.schedule() - - return dl, nil -} - -func (d *downloader) Stop() { - d.once.Do(func() { - close(d.done) - }) -} - -func (d *downloader) Start() <-chan []byte { - out := make(chan []byte, 1024) - - go func() { - defer close(out) - select { - case <-d.done: - for wavB := range d.pb { - wavB.wav.Stop() - wavB.cleanup() - } - return - default: - } - - for wavB := range d.pb { - wavB.wav.Start(out) - - select { - case <-d.done: - wavB.wav.Stop() - wavB.cleanup() - - case <-wavB.wav.Done: - } - } - }() - - return out -} - -func (d *downloader) schedule() { - defer close(d.pb) - for i := 0; ; i++ { - select { - case <-d.done: - return - default: - } - - clipStart := time.Duration(i)*clipTime + d.StartTime - clipEnd := time.Duration(i+1)*clipTime + d.StartTime - - if clipStart >= d.EndTime { - return - } - - dur := clipTime - if clipEnd > d.EndTime { - dur = d.EndTime - clipStart - } - - wavb, err := d.downloadSegment(clipStart, dur) - if err != nil { - log.Errorf("error setting up download: %q", err) - return - } - - select { - case d.pb <- wavb: - case <-d.done: - return - } - } -} - -func (d *downloader) downloadSegment(startTime, duration time.Duration) (*wavBundle, error) { - startSecond := int(startTime.Seconds()) - args := []string{ - "-ss", strconv.Itoa(startSecond), - "-i", d.info.Url.String(), - "-c:a", "pcm_s16le", - "-f", "wav", - "-ar", "48000", - "-ac", "2", - "-vn", "-y", - } - - dur := int(duration.Seconds()) - if dur > 0 && startTime+duration < d.info.Duration { - args = append(args, "-t", strconv.Itoa(dur)) - } - - file, err := ioutil.TempFile("", "thulani_") - if err != nil { - return nil, err - } - - clearTemp := func() { - if err := file.Close(); err != nil { - log.Errorf("error closing temp file: %q", err) - } - - if err := os.Remove(file.Name()); err != nil { - log.Errorf("unable to remove temp file: %q", err) - } - } - - args = append(args, file.Name()) - - dl := exec.Command(`ffmpeg`, args...) - b, err := dl.CombinedOutput() - if err != nil { - clearTemp() - log.Errorf("ffmpeg failed: \n%v", string(b)) - return nil, err - } - - wv, err := wav.New(file.Name()) - if err != nil { - clearTemp() - return nil, err - } - - return &wavBundle{wav: wv, cleanup: clearTemp}, err -} |
