implement ytdl

This commit is contained in:
raziman 2020-06-27 17:16:49 +08:00
parent ca92b98583
commit be28266224
3 changed files with 155 additions and 10 deletions

View File

@ -78,6 +78,21 @@ func InitPlaylist() *Playlist {
audioFile := currNode.GetReference().(*AudioFile)
switch e.Rune() {
case 'Y':
if pages.HasPage("download-popup") {
pages.RemovePage("download-popup")
} else {
if audioFile.IsAudioFile {
downloadMusic(currNode)
} else {
downloadMusic(audioFile.Parent)
}
downloadMusic(playlist.GetCurrentNode())
}
case 'l':
playlist.addToQueue(audioFile)
@ -228,7 +243,7 @@ func (playlist *Playlist) addAllToQueue(root *tview.TreeNode) {
for _, v := range childrens {
currNode := v.GetReference().(*AudioFile)
playlist.addToQueue(currNode)
go playlist.addToQueue(currNode)
}
}

View File

@ -55,7 +55,6 @@ func topRight(p tview.Primitive, width, height int) tview.Primitive {
func timeoutPopup(title string, desc string, timeout time.Duration) {
textView := tview.NewTextView().
SetText(fmt.Sprintf("%s", desc)).
SetTextColor(accentColor)
@ -66,6 +65,7 @@ func timeoutPopup(title string, desc string, timeout time.Duration) {
box.SetTitle(title).SetBorder(true).SetBackgroundColor(popupBg)
popupId := fmt.Sprintf("%s %d", "timeout-popup", popupCounter)
popupCounter++
pages.AddPage(popupId, topRight(box, 70, 7), true, true)
app.SetFocus(prevPanel.(tview.Primitive))
@ -77,10 +77,9 @@ func timeoutPopup(title string, desc string, timeout time.Duration) {
}()
}
func volumePopup(volume float64) {
vol := int(volume * 10) + 50
vol := int(volume*10) + 50
progress := fmt.Sprintf("\n%d |%s%s| %s",
vol,
@ -89,7 +88,7 @@ func volumePopup(volume float64) {
"50",
)
timeoutPopup(" Volume ", progress, time.Second * 5)
timeoutPopup(" Volume ", progress, time.Second*5)
}
@ -109,19 +108,19 @@ func helpPopup() {
"+ volume up",
"- volume down",
"? toggle help",
"Y download audio",
}
list := tview.NewList().ShowSecondaryText(false)
list.SetBackgroundColor(popupBg).SetTitle(" Help ").
SetBorder(true)
SetBorder(true)
list.SetSelectedBackgroundColor(popupBg).
SetSelectedTextColor(accentColor)
SetSelectedTextColor(accentColor)
for _, v := range helpText {
list.AddItem(v, "", 0, nil)
}
prev := func() {
currIndex := list.GetCurrentItem()
list.SetCurrentItem(currIndex - 1)
@ -143,8 +142,6 @@ func helpPopup() {
next()
case 'k':
prev()
case 'd':
queue.deleteItem(queue.GetCurrentItem())
}
return nil
@ -153,3 +150,32 @@ func helpPopup() {
pages.AddPage("help-page", center(list, 50, 30), true, true)
app.SetFocus(list)
}
func downloadMusic(selPlaylist *tview.TreeNode) {
inputField := tview.NewInputField().
SetLabel("Enter a url: ").
SetFieldWidth(0).
SetAcceptanceFunc(tview.InputFieldMaxLength(50))
inputField.SetBackgroundColor(popupBg).SetBorder(true).SetTitle(" Ytdl ")
inputField.SetFieldBackgroundColor(accentColor).SetFieldTextColor(tcell.ColorBlack)
inputField.SetDoneFunc(func(key tcell.Key) {
switch key {
case tcell.KeyEnter:
url := inputField.GetText()
Ytdl(url, selPlaylist)
pages.RemovePage("download-popup")
case tcell.KeyEscape:
pages.RemovePage("download-popup")
}
})
pages.AddPage("download-popup", center(inputField, 50, 4), true, true)
app.SetFocus(inputField)
}

104
utils.go
View File

@ -3,13 +3,19 @@
package main
import (
"bytes"
"fmt"
"net/http"
"os"
"os/exec"
"path"
"regexp"
"strings"
"time"
"github.com/faiface/beep/mp3"
"github.com/rivo/tview"
"github.com/spf13/viper"
)
func log(text string) {
@ -112,3 +118,101 @@ func GetFileContentType(out *os.File) (string, error) {
func GetName(fn string) string {
return strings.TrimSuffix(path.Base(fn), path.Ext(fn))
}
// download audio from youtube audio and adds the song to the selected playlist
func Ytdl(url string, selPlaylist *tview.TreeNode) {
dir := viper.GetString("music_dir")
selAudioFile := selPlaylist.GetReference().(*AudioFile)
selPlaylistName := selAudioFile.Name
timeoutPopup(" Ytdl ", "Downloading", time.Second*5)
// specify the output path for ytdl
outputDir := fmt.Sprintf(
"%s/%s/%%(artist)s - %%(track)s.%%(ext)s",
dir,
selPlaylistName)
args := []string{
"--extract-audio",
"--audio-format",
"mp3",
"--output",
outputDir,
url,
}
cmd := exec.Command("youtube-dl", args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
go func() {
err := cmd.Run()
if err != nil {
timeoutPopup(" Error ", "An error occured when downloading", time.Second*5)
return
}
if cmd.Stderr != nil {
timeoutPopup(" Error ", "An error occured when downloading", time.Second*5)
return
}
playlistPath := fmt.Sprintf("%s/%s", expandTilde(dir), selPlaylistName)
downloadedAudioPath := downloadedFilePath(
stdout.Bytes(), playlistPath)
f, err := os.Open(downloadedAudioPath)
if err != nil {
log(err.Error())
}
defer f.Close()
node := tview.NewTreeNode(path.Base(f.Name()))
audioFile := &AudioFile{
Name: f.Name(),
Path: downloadedAudioPath,
IsAudioFile: true,
Parent: selPlaylist,
}
node.SetReference(audioFile)
selPlaylist.AddChild(node)
app.Draw()
timeoutPopup(
" Ytdl ",
fmt.Sprintf("Finished downloading\n%s",
path.Base(downloadedAudioPath)), time.Second*5)
}()
}
// this just parsing the output from the ytdl to get the audio path
// this is used because we need to get the song name
// example ~/path/to/song/song.mp3
func downloadedFilePath(output []byte, dir string) string {
regexSearch := fmt.Sprintf(`\[ffmpeg\] Destination: %s\/.*.mp3`,
escapeBackSlash(dir))
parseAudioPathOnly := regexp.MustCompile(`\/.*mp3$`)
re := regexp.MustCompile(regexSearch)
return string(parseAudioPathOnly.Find(re.Find(output)))
}
func escapeBackSlash(input string) string {
return strings.ReplaceAll(input, "/", `\/`)
}