lyric in progress

This commit is contained in:
tramhao 2021-02-21 15:21:08 +08:00
commit d9dfd29e95
5 changed files with 130 additions and 79 deletions

1
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/hajimehoshi/oto v0.7.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/martinlindhe/subtitles v0.0.0-20210219114018-c133f18cfb3d
github.com/mattn/anko v0.1.8
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/tview v0.0.0-20210125085121-dbc1f32bb1d0

22
go.sum
View File

@ -1,9 +1,13 @@
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/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/faiface/beep v1.0.2 h1:UB5DiRNmA4erfUYnHbgU4UB6DlBOrsdEFRtcc8sCkdQ=
github.com/faiface/beep v1.0.2/go.mod h1:1yLb5yRdHMsovYYWVqYLioXkVuziCSITW1oarTeduQM=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
@ -34,6 +38,8 @@ github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
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/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k=
@ -43,6 +49,10 @@ github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/z
github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/martinlindhe/subtitles v0.0.0-20210219114018-c133f18cfb3d h1:7pTPyGn1BlepA/DoNsDKuhDovj5cGdIiQpRjHwPHNlk=
github.com/martinlindhe/subtitles v0.0.0-20210219114018-c133f18cfb3d/go.mod h1:EjV1EvmBWHZGVRjE+IolE0t6LnkbhyRiwD7SlXDQsuw=
github.com/mattn/anko v0.1.8 h1:wDGM0Rwgbzhk1h8xE6qAR4n+PO/9clzf3tLGtrwsqJg=
github.com/mattn/anko v0.1.8/go.mod h1:C5D2zw4NIv/sB2SrQ3qs5wqPw0wKiA2GZqexy4ctNH0=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@ -64,7 +74,11 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
@ -97,6 +111,8 @@ golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hM
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-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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=
@ -105,10 +121,14 @@ 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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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=
@ -120,7 +140,9 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
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=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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

@ -3,11 +3,16 @@
package main
import (
// "bytes"
"fmt"
"log"
"strconv"
"strings"
"time"
// "github.com/asticode/go-astisub"
"github.com/bogem/id3v2"
"github.com/martinlindhe/subtitles"
"github.com/rivo/tview"
"github.com/ztrue/tracerr"
)
@ -19,8 +24,18 @@ type PlayingBar struct {
_progress int
skip bool
text *tview.TextView
hasTag bool
tag *id3v2.Tag
}
type lyricParsed struct {
timestart time.Duration
timeend time.Duration
lyricText string
}
var lyricsParsed []lyricParsed
func (p *PlayingBar) help() []string {
return []string{}
}
@ -71,13 +86,21 @@ func (p *PlayingBar) run() error {
_, _, width, _ := p.GetInnerRect()
progressBar := progresStr(p._progress, p.full, width/2, "█", "━")
// our progress bar
p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s",
fmtDuration(start),
progressBar,
fmtDuration(end),
))
if p.hasTag {
p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s\n%s",
fmtDuration(start),
progressBar,
fmtDuration(end),
p.tag.Title(),
))
} else {
p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s",
fmtDuration(start),
progressBar,
fmtDuration(end),
))
}
gomu.app.Draw()
}
return nil
@ -95,6 +118,35 @@ func (p *PlayingBar) newProgress(songTitle string, full int) {
p.full = full
p._progress = 0
p.setSongTitle(songTitle)
var tag *id3v2.Tag
var err error
tag, err = id3v2.Open(gomu.player.currentSong.path, id3v2.Options{Parse: true})
if tag == nil || err != nil {
logError(err)
} else {
p.hasTag = true
p.tag = tag
usltFrames := tag.GetFrames(tag.CommonID("Unsynchronised lyrics/text transcription"))
for _, f := range usltFrames {
uslf, ok := f.(id3v2.UnsynchronisedLyricsFrame)
if !ok {
log.Fatal("USLT error!")
}
/* subtitleLyric, err := astisub.ReadFromWebVTT(bytes.NewBufferString(uslf.Lyrics))
if err != nil {
logError(err)
}
_ = subtitleLyric */
res, err := subtitles.NewFromSRT(uslf.Lyrics)
if err != nil {
logError(err)
}
fmt.Println(res.Captions[3])
}
}
defer tag.Close()
}
// Sets default title and progress bar

View File

@ -553,6 +553,8 @@ func ytdl(url string, selPlaylist *tview.TreeNode) error {
metaData := fmt.Sprintf("%%(artist)s - %%(title)s")
langSubtitle := "en,zh-Hans"
args := []string{
"--extract-audio",
"--audio-format",
@ -563,6 +565,11 @@ func ytdl(url string, selPlaylist *tview.TreeNode) error {
"--embed-thumbnail",
"--metadata-from-title",
metaData,
"--write-sub",
"--sub-lang",
langSubtitle,
"--convert-subs",
"srt",
// "--cookies",
// "~/Downloads/youtube.com_cookies.txt",
url,
@ -608,65 +615,6 @@ 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

@ -303,11 +303,6 @@ 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")
}
@ -826,7 +821,7 @@ func tagPopup(node *AudioFile) bool {
for _, file := range files {
if filepath.Ext(file.Name()) == ".lrc" {
if filepath.Ext(file.Name()) == ".srt" {
lyricsAvailable = append(lyricsAvailable, file.Name())
}
}
@ -834,13 +829,12 @@ func tagPopup(node *AudioFile) bool {
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)
AddDropDown("Lyrics Available", lyricsAvailable, 0, nil).
AddCheckbox("Embed Lyrics", true, nil)
form.SetBackgroundColor(gomu.colors.popup).
SetBackgroundColor(gomu.colors.popup).
SetTitle(node.name).
SetTitleAlign(tview.AlignLeft).
SetBorder(true).
SetBorderPadding(1, 0, 2, 2)
@ -856,17 +850,51 @@ func tagPopup(node *AudioFile) bool {
logError(err)
}
defer tag.Close()
tag.SetArtist(form.GetFormItemByLabel("Artist").(*tview.InputField).GetText())
tag.SetTitle(form.GetFormItemByLabel("Title").(*tview.InputField).GetText())
tagArtist := form.GetFormItemByLabel("Artist").(*tview.InputField).GetText()
tagTitle := form.GetFormItemByLabel("Title").(*tview.InputField).GetText()
tag.SetArtist(tagArtist)
tag.SetTitle(tagTitle)
tag.SetAlbum(form.GetFormItemByLabel("Album").(*tview.InputField).GetText())
if form.GetFormItemByLabel("Embed Lyrics").(*tview.Checkbox).IsChecked() {
_, fileName := form.GetFormItemByLabel("Lyrics Available").(*tview.DropDown).GetCurrentOption()
lyricFileName := filepath.Join(pathToFile, fileName)
// Read entire file content, giving us little control but
// making it very simple. No need to close the file.
content, err := ioutil.ReadFile(lyricFileName)
if err != nil {
logError(err)
}
// Convert []byte to string and print to screen
lyric := string(content)
tag.AddUnsynchronisedLyricsFrame(id3v2.UnsynchronisedLyricsFrame{
Encoding: id3v2.EncodingUTF8,
Language: "eng",
ContentDescriptor: tagArtist + "-" + tagTitle,
Lyrics: lyric,
})
// lyrics := "'first line',12343\n\r'secondline',23455\n\r"
/* tag.AddSynchronisedLyricsFrame(id3v2.SynchronisedLyricsFrame{
Encoding: id3v2.EncodingUTF8,
Language: "eng",
TimeStampFormat: 2,
ContentType: 1,
ContentDescriptor: tagArtist + "-" + tagTitle,
SynchronizedTextSpec: lyric,
}) */
}
// Write tag to mp3.
if err := tag.Save(); err != nil {
defaultTimedPopup(" Error ", err.Error())
logError(err)
} else {
defaultTimedPopup(" Success ", "Tag update successfully")
gomu.pages.RemovePage(popupID)
gomu.popups.pop()
}
defaultTimedPopup(" Success ", "Tag update successfully")
gomu.pages.RemovePage(popupID)
gomu.popups.pop()
case tcell.KeyEsc:
gomu.pages.RemovePage(popupID)