lyric in progress

This commit is contained in:
tramhao 2021-02-19 14:45:20 +08:00
commit 92d8885385
5 changed files with 167 additions and 15 deletions

View File

@ -475,10 +475,17 @@ func (c Command) defineCommands() {
replPopup()
})
c.define("edit_tags", func() {
audioFile := gomu.playlist.getCurrentFile()
tagPopup(audioFile)
})
for name, cmd := range c.commands {
err := gomu.anko.Define(name, cmd)
if err != nil {
logError(err)
}
}
}

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/issadarkthing/gomu
go 1.14
require (
github.com/bogem/id3v2 v1.2.0
github.com/faiface/beep v1.0.2
github.com/gdamore/tcell/v2 v2.1.0
github.com/hajimehoshi/go-mp3 v0.3.1 // indirect

19
go.sum
View File

@ -1,5 +1,7 @@
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/bogem/id3v2 v1.2.0 h1:hKDF+F1gOgQ5r1QmBCEZUk4MveJbKxCeIDSBU7CQ4oI=
github.com/bogem/id3v2 v1.2.0/go.mod h1:t78PK5AQ56Q47kizpYiV6gtjj3jfxlz87oFpty8DYs8=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/faiface/beep v1.0.2 h1:UB5DiRNmA4erfUYnHbgU4UB6DlBOrsdEFRtcc8sCkdQ=
@ -30,10 +32,6 @@ github.com/hajimehoshi/oto v0.6.1 h1:7cJz/zRQV4aJvMSSRqzN2TImoVVMpE0BCY4nrNJaDOM
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
github.com/issadarkthing/anko v1.0.0 h1:CP5SI/C51kWQvufFEzJL9udui0fxt42yffaipG0mg/A=
github.com/issadarkthing/anko v1.0.0/go.mod h1:UE75FVFortpN/0PUWsp+kekz2MsIeMrhg769xLhi880=
github.com/issadarkthing/anko v1.0.1 h1:F0y32Dtlh0KaNgkJ0lIlOkIQysOsSdJnPPN7HhiI2Do=
github.com/issadarkthing/anko v1.0.1/go.mod h1:UE75FVFortpN/0PUWsp+kekz2MsIeMrhg769xLhi880=
github.com/jfreymuth/oggvorbis v1.0.0/go.mod h1:abe6F9QRjuU9l+2jek3gj46lu40N4qlYxh2grqkLEDM=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
@ -71,13 +69,11 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y=
github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
@ -97,14 +93,11 @@ golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -112,13 +105,10 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -127,11 +117,10 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa h1:5E4dL8+NgFOgjwbTKz+OOEGGhP+ectTmF842l6KjupQ=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -64,6 +64,7 @@ func (p *Playlist) help() []string {
"p paste file",
"/ find in playlist",
"s search audio from youtube",
"t edit mp3 tags",
}
}
@ -170,6 +171,7 @@ func newPlaylist(args Args) *Playlist {
'y': "yank",
'p': "paste",
'/': "playlist_search",
't': "edit_tags",
}
for key, cmd := range cmds {
@ -549,12 +551,18 @@ func ytdl(url string, selPlaylist *tview.TreeNode) error {
"%s/%%(title)s.%%(ext)s",
dir)
metaData := fmt.Sprintf("%%(artist)s - %%(title)s")
args := []string{
"--extract-audio",
"--audio-format",
"mp3",
"--output",
outputDir,
"--add-metadata",
"--embed-thumbnail",
"--metadata-from-title",
metaData,
// "--cookies",
// "~/Downloads/youtube.com_cookies.txt",
url,
@ -600,6 +608,65 @@ func ytdl(url string, selPlaylist *tview.TreeNode) error {
return nil
}
// Download audio subtitle from youtube audio
func ytdlSubtitle(url string, selPlaylist *tview.TreeNode) error {
// lookup if youtube-dl exists
_, err := exec.LookPath("youtube-dl")
if err != nil {
defaultTimedPopup(" Error ", "youtube-dl is not in your $PATH")
return tracerr.Wrap(err)
}
selAudioFile := selPlaylist.GetReference().(*AudioFile)
dir := selAudioFile.path
// defaultTimedPopup(" Ytdl ", "Downloading subtitles")
// specify the output path for ytdl
outputDir := fmt.Sprintf(
"%s/%%(title)s.%%(ext)s",
dir)
langSubtitle := "en,zh-Hans"
args := []string{
"--skip-download",
"--output",
outputDir,
"--write-sub",
"--sub-lang",
langSubtitle,
"--convert-subs",
"lrc",
url,
}
cmd := exec.Command("youtube-dl", args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
// blocking
err = cmd.Run()
if err != nil {
defaultTimedPopup(" Error ", "Error running youtube-dl")
return tracerr.Wrap(err)
}
playlistPath := dir
audioPath := extractFilePath(stdout.Bytes(), playlistPath)
downloadFinishedMessage := fmt.Sprintf("Finished downloading subtitles\n%s", getName(audioPath))
defaultTimedPopup(" Ytdl ", downloadFinishedMessage)
gomu.app.Draw()
return nil
}
// Add songs and their directories in Playlist panel
func populate(root *tview.TreeNode, rootPath string) error {

View File

@ -4,11 +4,14 @@ package main
import (
"fmt"
"io/ioutil"
"path/filepath"
"regexp"
"strings"
"time"
"unicode/utf8"
"github.com/bogem/id3v2"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/sahilm/fuzzy"
@ -297,6 +300,11 @@ func downloadMusicPopup(selPlaylist *tview.TreeNode) {
logError(err)
}
}()
go func() {
if err := ytdlSubtitle(url, selPlaylist); err != nil {
logError(err)
}
}()
} else {
defaultTimedPopup("Invalid url", "Invalid youtube url was given")
}
@ -662,3 +670,83 @@ func replPopup() {
gomu.pages.AddPage(popupId, center(flex, 90, 30), true, true)
gomu.popups.push(flex)
}
func tagPopup(node *AudioFile) bool {
var tag *id3v2.Tag
var err error
if node.isAudioFile {
tag, err = id3v2.Open(node.path, id3v2.Options{Parse: true})
if err != nil {
logError(err)
return false
}
defer tag.Close()
} else {
return false
}
popupID := "tag-input-popup"
var lyricsAvailable []string
pathToFile, _ := filepath.Split(node.path)
files, err := ioutil.ReadDir(pathToFile)
if err != nil {
logError(err)
return false
}
for _, file := range files {
if filepath.Ext(file.Name()) == ".lrc" {
lyricsAvailable = append(lyricsAvailable, file.Name())
}
}
form := tview.NewForm().
AddInputField("Artist", tag.Artist(), 20, nil, nil).
AddInputField("Title", tag.Title(), 20, nil, nil).
AddInputField("Album", tag.Album(), 20, nil, nil).
AddCheckbox("Embed Lyrics", false, nil).
AddDropDown("Lyrics Available", lyricsAvailable, 0, nil)
form.SetBackgroundColor(gomu.colors.popup).
SetBackgroundColor(gomu.colors.popup).
SetTitle(node.name).
SetTitleAlign(tview.AlignLeft).
SetBorder(true).
SetBorderPadding(1, 0, 2, 2)
gomu.pages.
AddPage(popupID, center(form, 60, 30), true, true)
gomu.popups.push(form)
form.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
switch e.Key() {
case tcell.KeyEnter:
tag, err = id3v2.Open(node.path, id3v2.Options{Parse: true})
if err != nil {
logError(err)
}
defer tag.Close()
tag.SetArtist(form.GetFormItemByLabel("Artist").(*tview.InputField).GetText())
tag.SetTitle(form.GetFormItemByLabel("Title").(*tview.InputField).GetText())
tag.SetAlbum(form.GetFormItemByLabel("Album").(*tview.InputField).GetText())
// Write tag to mp3.
if err := tag.Save(); err != nil {
defaultTimedPopup(" Error ", err.Error())
logError(err)
}
defaultTimedPopup(" Success ", "Tag update successfully")
gomu.pages.RemovePage(popupID)
gomu.popups.pop()
case tcell.KeyEsc:
gomu.pages.RemovePage(popupID)
gomu.popups.pop()
}
return e
})
return true
}