aboutsummaryrefslogtreecommitdiff
path: root/downloader
diff options
context:
space:
mode:
Diffstat (limited to 'downloader')
-rw-r--r--downloader/download_manager.go112
-rw-r--r--downloader/downloader.go180
-rw-r--r--downloader/downloader_test.go22
-rw-r--r--downloader/util.go77
4 files changed, 0 insertions, 391 deletions
diff --git a/downloader/download_manager.go b/downloader/download_manager.go
deleted file mode 100644
index 16054ae..0000000
--- a/downloader/download_manager.go
+++ /dev/null
@@ -1,112 +0,0 @@
-package downloader
-
-import (
- "time"
-
- "github.com/bwmarrin/discordgo"
-)
-
-type DlMessage int
-
-const (
- Clear DlMessage = iota
- Pause
- Play
- Skip
-)
-
-type playBundle struct {
- data <-chan []byte
- conn *discordgo.VoiceConnection
-}
-
-type DownloadManager struct {
- session *discordgo.Session
- guildID string
- voiceID string
- dls chan *downloader
-
- PlayState chan DlMessage
-}
-
-func NewManager(s *discordgo.Session, guildID string, voiceChanID string) *DownloadManager {
- dm := &DownloadManager{
- session: s,
- dls: make(chan *downloader),
- PlayState: make(chan DlMessage),
- guildID: guildID,
- voiceID: voiceChanID,
- }
-
- go dm.playFromQueue()
-
- return dm
-}
-
-func (m *DownloadManager) playFromQueue() {
- for {
- select {
- case <-m.PlayState: // ignore play state updates while not playing anything
- case dl := <-m.dls:
- conn, err := m.session.ChannelVoiceJoin(m.guildID, m.voiceID, false, false)
- if err != nil {
- log.Errorf("unable to connect to the voice channel: %q", err)
- time.Sleep(1 * time.Second)
- break
- }
-
- m.session.UpdateStatus(0, dl.info.Url.Host)
- out := dl.Start()
-
- playState := Play
- conn.Speaking(true)
-
- cleanup := func() {
- conn.Speaking(false)
- conn.Disconnect()
- m.session.UpdateStatus(0, "literally nothing")
- }
-
- inner:
- for {
- switch playState {
- case Clear:
- dl.Stop()
- for {
- select {
- case dl := <-m.dls:
- dl.Stop()
- dl.Start() // this is a hacky way of ensuring all the wavs are closed and cleaned up
- default:
- }
- }
- break inner
- case Skip:
- break inner
- case Pause:
- playState = <-m.PlayState
- case Play:
- select { // first check if we have a state update message coming in
- case playState = <-m.PlayState:
- case elem, ok := <-out:
- if !ok {
- break inner
- }
-
- conn.OpusSend <- elem
- }
- }
- }
- cleanup()
- }
- }
-}
-
-func (m *DownloadManager) Enqueue(url string, startTime, duration time.Duration) error {
- dl, err := newDownload(url, startTime, duration)
- if err != nil {
- return err
- }
- m.dls <- dl
- return nil
-}
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
-}
diff --git a/downloader/downloader_test.go b/downloader/downloader_test.go
deleted file mode 100644
index f38e1d0..0000000
--- a/downloader/downloader_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package downloader
-
-import (
- "fmt"
- "testing"
- "time"
-)
-
-func TestGetUrl(t *testing.T) {
- u, err := getUrl("https://www.youtube.com/watch?v=_K13GJkGvDw")
- if err != nil {
- t.Fatal(err)
- }
-
- fmt.Println(u)
-}
-
-func TestDownload(t *testing.T) {
- if _, err := Download("https://www.youtube.com/watch?v=_K13GJkGvDw", 10*time.Second, 10*time.Second); err != nil {
- t.Fatal(err)
- }
-}
diff --git a/downloader/util.go b/downloader/util.go
deleted file mode 100644
index f744fad..0000000
--- a/downloader/util.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package downloader
-
-import (
- "encoding/json"
- "io/ioutil"
- "net/url"
- "os/exec"
- "time"
-
- "github.com/mammothbane/thulani-go/wav"
- "github.com/op/go-logging"
-)
-
-var log = logging.MustGetLogger("downloader")
-
-// responsible for decoding from youtube
-type videoInfo struct {
- Title string `json:"fulltitle"`
- UrlStr string `json:"url"`
- DurationSec int `json:"duration"`
- Url *url.URL `json:"-"`
- Duration time.Duration `json:"-"`
-}
-
-func info(inUrl string) (*videoInfo, error) {
- dl := exec.Command("youtube-dl", "-f", "bestaudio", "-x", "-j", inUrl)
-
- outpipe, err := dl.StdoutPipe()
- if err != nil {
- return nil, err
- }
-
- errpipe, err := dl.StderrPipe()
- if err != nil {
- return nil, err
- }
-
- err = dl.Start()
- if err != nil {
- log.Errorf("starting youtube-dl failed")
- return nil, err
- }
-
- o, ierr := ioutil.ReadAll(outpipe)
- if ierr != nil {
- log.Errorf("unable to read from output pipe")
- return nil, err
- }
-
- e, ierr := ioutil.ReadAll(errpipe)
- if ierr != nil {
- log.Errorf("unable to read from error pipe")
- return nil, err
- }
-
- if err := dl.Wait(); err != nil {
- log.Errorf("error:\n%v", string(e))
- return nil, err
- }
-
- v := videoInfo{}
- if err := json.Unmarshal(o, &v); err != nil {
- return nil, err
- }
-
- v.Duration = time.Duration(v.DurationSec) * time.Second
- v.Url, err = url.Parse(v.UrlStr)
-
- //tgt, err := url.Parse(string(o))
- //out := tgt.Scheme + "://" + tgt.Host + tgt.Path + "?" + tgt.Query().Encode()
- return &v, err
-}
-
-type wavBundle struct {
- wav *wav.Wav
- cleanup func()
-}