mirror of
https://github.com/issadarkthing/gomu.git
synced 2025-04-26 13:49:21 +08:00
refactor lyric.go
This commit is contained in:
parent
112bb338a4
commit
01b4c3f692
@ -19,32 +19,9 @@ type SongTag struct {
|
|||||||
LyricID string
|
LyricID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLyric return the actual function based on lang
|
type GetLyrics interface {
|
||||||
func GetLyric(lang string, songTag *SongTag) (string, error) {
|
GetLyric(songTag *SongTag) (string, error)
|
||||||
|
GetLyricOptions(search string) ([]*SongTag, error)
|
||||||
switch lang {
|
|
||||||
case "en":
|
|
||||||
return getLyricEn(songTag)
|
|
||||||
case "zh-CN":
|
|
||||||
return getLyricCn(songTag)
|
|
||||||
default:
|
|
||||||
return getLyricEn(songTag)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLyricOptions return the actual function based on lang
|
|
||||||
func GetLyricOptions(lang string, search string) ([]*SongTag, error) {
|
|
||||||
|
|
||||||
switch lang {
|
|
||||||
case "en":
|
|
||||||
return getLyricOptionsEn(search)
|
|
||||||
case "zh-CN":
|
|
||||||
return getLyricOptionsCn(search)
|
|
||||||
default:
|
|
||||||
return getLyricOptionsEn(search)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanHTML parses html text to valid utf-8 text
|
// cleanHTML parses html text to valid utf-8 text
|
||||||
|
@ -42,8 +42,10 @@ type tagLyric struct {
|
|||||||
Tlyric string `json:"tlyric"`
|
Tlyric string `json:"tlyric"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLyricOptionsCn queries available song lyrics. It returns slice of SongTag
|
type GetLyricCn struct{}
|
||||||
func getLyricOptionsCn(search string) ([]*SongTag, error) {
|
|
||||||
|
// GetLyricOptions queries available song lyrics. It returns slice of SongTag
|
||||||
|
func (cn GetLyricCn) GetLyricOptions(search string) ([]*SongTag, error) {
|
||||||
|
|
||||||
serviceProvider := "netease"
|
serviceProvider := "netease"
|
||||||
results, err := getLyricOptionsCnByProvider(search, serviceProvider)
|
results, err := getLyricOptionsCnByProvider(search, serviceProvider)
|
||||||
@ -61,9 +63,9 @@ func getLyricOptionsCn(search string) ([]*SongTag, error) {
|
|||||||
return results, err
|
return results, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLyricCn should receive songTag that was returned from getLyricOptionsCn
|
// GetLyric should receive songTag that was returned from getLyricOptions
|
||||||
// and returns lyric of the queried song.
|
// and returns lyric of the queried song.
|
||||||
func getLyricCn(songTag *SongTag) (lyricString string, err error) {
|
func (cn GetLyricCn) GetLyric(songTag *SongTag) (lyricString string, err error) {
|
||||||
|
|
||||||
urlSearch := "http://api.sunyj.xyz"
|
urlSearch := "http://api.sunyj.xyz"
|
||||||
|
|
||||||
|
@ -8,9 +8,11 @@ import (
|
|||||||
"github.com/gocolly/colly"
|
"github.com/gocolly/colly"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getLyricEn should receive SongTag that was returned from GetLyricOptions, and
|
type GetLyricEn struct{}
|
||||||
|
|
||||||
|
// GetLyric should receive SongTag that was returned from GetLyricOptions, and
|
||||||
// returns lyric of the queried song.
|
// returns lyric of the queried song.
|
||||||
func getLyricEn(songTag *SongTag) (string, error) {
|
func (en GetLyricEn) GetLyric(songTag *SongTag) (string, error) {
|
||||||
|
|
||||||
var lyric string
|
var lyric string
|
||||||
c := colly.NewCollector()
|
c := colly.NewCollector()
|
||||||
@ -37,8 +39,8 @@ func getLyricEn(songTag *SongTag) (string, error) {
|
|||||||
return "", fmt.Errorf("lyric not compatible")
|
return "", fmt.Errorf("lyric not compatible")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLyricOptionsEn queries available song lyrics. It returns slice of SongTag
|
// GetLyricOptions queries available song lyrics. It returns slice of SongTag
|
||||||
func getLyricOptionsEn(search string) ([]*SongTag, error) {
|
func (en GetLyricEn) GetLyricOptions(search string) ([]*SongTag, error) {
|
||||||
|
|
||||||
var songTags []*SongTag
|
var songTags []*SongTag
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ func TestCleanHTML(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, string(clean), got)
|
assert.Equal(t, string(clean), got)
|
||||||
|
|
||||||
_, err = NewFromLRC(got)
|
var lyric Lyric
|
||||||
|
err = lyric.NewFromLRC(got)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
12
popup.go
12
popup.go
@ -850,7 +850,15 @@ func ytSearchPopup() {
|
|||||||
func lyricPopup(lang string, audioFile *AudioFile, wg *sync.WaitGroup) error {
|
func lyricPopup(lang string, audioFile *AudioFile, wg *sync.WaitGroup) error {
|
||||||
|
|
||||||
var titles []string
|
var titles []string
|
||||||
results, err := lyric.GetLyricOptions(lang, audioFile.name)
|
var getLyric lyric.GetLyrics
|
||||||
|
if lang == "zh-CN" {
|
||||||
|
getLyric = lyric.GetLyricCn{}
|
||||||
|
} else if lang == "en" {
|
||||||
|
getLyric = lyric.GetLyricEn{}
|
||||||
|
} else {
|
||||||
|
getLyric = lyric.GetLyricEn{}
|
||||||
|
}
|
||||||
|
results, err := getLyric.GetLyricOptions(audioFile.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tracerr.Wrap(err)
|
return tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
@ -873,7 +881,7 @@ func lyricPopup(lang string, audioFile *AudioFile, wg *sync.WaitGroup) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lyricContent, err := lyric.GetLyric(results[selectedIndex].LangExt, results[selectedIndex])
|
lyricContent, err := getLyric.GetLyric(results[selectedIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorPopup(err)
|
errorPopup(err)
|
||||||
gomu.app.Draw()
|
gomu.app.Draw()
|
||||||
|
127
tageditor.go
127
tageditor.go
@ -17,10 +17,11 @@ import (
|
|||||||
"github.com/issadarkthing/gomu/lyric"
|
"github.com/issadarkthing/gomu/lyric"
|
||||||
)
|
)
|
||||||
|
|
||||||
// myFlex extend the flex control to modify the Focus item
|
// lyricFlex extend the flex control to modify the Focus item
|
||||||
type myFlex struct {
|
type lyricFlex struct {
|
||||||
*tview.Flex
|
*tview.Flex
|
||||||
FocusedItem tview.Primitive
|
FocusedItem tview.Primitive
|
||||||
|
inputs []tview.Primitive
|
||||||
}
|
}
|
||||||
|
|
||||||
var box *tview.Box = tview.NewBox()
|
var box *tview.Box = tview.NewBox()
|
||||||
@ -29,7 +30,7 @@ var box *tview.Box = tview.NewBox()
|
|||||||
func tagPopup(node *AudioFile) (err error) {
|
func tagPopup(node *AudioFile) (err error) {
|
||||||
|
|
||||||
popupID := "tag-editor-input-popup"
|
popupID := "tag-editor-input-popup"
|
||||||
tag, popupLyricMap, options, err := loadTagMap(node)
|
tag, popupLyricMap, options, err := node.loadTagMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tracerr.Wrap(err)
|
return tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
@ -67,51 +68,53 @@ func tagPopup(node *AudioFile) (err error) {
|
|||||||
getTagButton.SetSelectedFunc(func() {
|
getTagButton.SetSelectedFunc(func() {
|
||||||
var titles []string
|
var titles []string
|
||||||
audioFile := node
|
audioFile := node
|
||||||
lang := "zh-CN"
|
|
||||||
results, err := lyric.GetLyricOptions(lang, audioFile.name)
|
|
||||||
if err != nil {
|
|
||||||
errorPopup(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, v := range results {
|
|
||||||
titles = append(titles, v.TitleForPopup)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
searchPopup(" Song Tags ", titles, func(selected string) {
|
var getLyric lyric.GetLyricCn
|
||||||
if selected == "" {
|
results, err := getLyric.GetLyricOptions(audioFile.name)
|
||||||
return
|
if err != nil {
|
||||||
}
|
errorPopup(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, v := range results {
|
||||||
|
titles = append(titles, v.TitleForPopup)
|
||||||
|
}
|
||||||
|
|
||||||
var selectedIndex int
|
go func() {
|
||||||
for i, v := range results {
|
searchPopup(" Song Tags ", titles, func(selected string) {
|
||||||
if v.TitleForPopup == selected {
|
if selected == "" {
|
||||||
selectedIndex = i
|
return
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
newTag := results[selectedIndex]
|
var selectedIndex int
|
||||||
artistInputField.SetText(newTag.Artist)
|
for i, v := range results {
|
||||||
titleInputField.SetText(newTag.Title)
|
if v.TitleForPopup == selected {
|
||||||
albumInputField.SetText(newTag.Album)
|
selectedIndex = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tag, err = id3v2.Open(node.path, id3v2.Options{Parse: true})
|
newTag := results[selectedIndex]
|
||||||
if err != nil {
|
artistInputField.SetText(newTag.Artist)
|
||||||
errorPopup(err)
|
titleInputField.SetText(newTag.Title)
|
||||||
return
|
albumInputField.SetText(newTag.Album)
|
||||||
}
|
|
||||||
defer tag.Close()
|
tag, err = id3v2.Open(node.path, id3v2.Options{Parse: true})
|
||||||
tag.SetArtist(newTag.Artist)
|
if err != nil {
|
||||||
tag.SetTitle(newTag.Title)
|
errorPopup(err)
|
||||||
tag.SetAlbum(newTag.Album)
|
return
|
||||||
err = tag.Save()
|
}
|
||||||
if err != nil {
|
defer tag.Close()
|
||||||
errorPopup(err)
|
tag.SetArtist(newTag.Artist)
|
||||||
return
|
tag.SetTitle(newTag.Title)
|
||||||
}
|
tag.SetAlbum(newTag.Album)
|
||||||
defaultTimedPopup(" Success ", "Tag update successfully")
|
err = tag.Save()
|
||||||
})
|
if err != nil {
|
||||||
|
errorPopup(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defaultTimedPopup(" Success ", "Tag update successfully")
|
||||||
|
})
|
||||||
|
}()
|
||||||
}()
|
}()
|
||||||
}).
|
}).
|
||||||
SetBackgroundColorActivated(gomu.colors.popup).
|
SetBackgroundColorActivated(gomu.colors.popup).
|
||||||
@ -247,7 +250,7 @@ func tagPopup(node *AudioFile) (err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
// This is to ensure that the above go routine finish.
|
// This is to ensure that the above go routine finish.
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
_, popupLyricMap, newOptions, err := loadTagMap(audioFile)
|
_, popupLyricMap, newOptions, err := audioFile.loadTagMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorPopup(err)
|
errorPopup(err)
|
||||||
gomu.app.Draw()
|
gomu.app.Draw()
|
||||||
@ -328,18 +331,19 @@ func tagPopup(node *AudioFile) (err error) {
|
|||||||
rightFlex.SetDirection(tview.FlexColumn).
|
rightFlex.SetDirection(tview.FlexColumn).
|
||||||
AddItem(lyricTextView, 0, 1, true)
|
AddItem(lyricTextView, 0, 1, true)
|
||||||
|
|
||||||
lyricFlex := &myFlex{
|
lyricFlex := &lyricFlex{
|
||||||
tview.NewFlex().SetDirection(tview.FlexColumn).
|
tview.NewFlex().SetDirection(tview.FlexColumn).
|
||||||
AddItem(leftGrid, 0, 2, true).
|
AddItem(leftGrid, 0, 2, true).
|
||||||
AddItem(rightFlex, 0, 3, true),
|
AddItem(rightFlex, 0, 3, true),
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
lyricFlex.
|
lyricFlex.
|
||||||
SetTitle(node.name).
|
SetTitle(node.name).
|
||||||
SetBorderPadding(1, 1, 2, 2)
|
SetBorderPadding(1, 1, 2, 2)
|
||||||
|
|
||||||
inputs := []tview.Primitive{
|
lyricFlex.inputs = []tview.Primitive{
|
||||||
getTagButton,
|
getTagButton,
|
||||||
artistInputField,
|
artistInputField,
|
||||||
titleInputField,
|
titleInputField,
|
||||||
@ -363,13 +367,13 @@ func tagPopup(node *AudioFile) (err error) {
|
|||||||
gomu.pages.RemovePage(popupID)
|
gomu.pages.RemovePage(popupID)
|
||||||
gomu.popups.pop()
|
gomu.popups.pop()
|
||||||
case tcell.KeyTab:
|
case tcell.KeyTab:
|
||||||
lyricFlex.cycleFocus(gomu.app, inputs, false)
|
lyricFlex.cycleFocus(gomu.app, false)
|
||||||
case tcell.KeyBacktab:
|
case tcell.KeyBacktab:
|
||||||
lyricFlex.cycleFocus(gomu.app, inputs, true)
|
lyricFlex.cycleFocus(gomu.app, true)
|
||||||
case tcell.KeyRight:
|
case tcell.KeyRight:
|
||||||
lyricFlex.cycleFocus(gomu.app, inputs, false)
|
lyricFlex.cycleFocus(gomu.app, false)
|
||||||
case tcell.KeyLeft:
|
case tcell.KeyLeft:
|
||||||
lyricFlex.cycleFocus(gomu.app, inputs, true)
|
lyricFlex.cycleFocus(gomu.app, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch e.Rune() {
|
switch e.Rune() {
|
||||||
@ -387,8 +391,8 @@ func tagPopup(node *AudioFile) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a hack to cycle Focus in a flex
|
// This is a hack to cycle Focus in a flex
|
||||||
func (f *myFlex) cycleFocus(app *tview.Application, elements []tview.Primitive, reverse bool) {
|
func (f *lyricFlex) cycleFocus(app *tview.Application, reverse bool) {
|
||||||
for i, el := range elements {
|
for i, el := range f.inputs {
|
||||||
if !el.HasFocus() {
|
if !el.HasFocus() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -396,22 +400,23 @@ func (f *myFlex) cycleFocus(app *tview.Application, elements []tview.Primitive,
|
|||||||
if reverse {
|
if reverse {
|
||||||
i = i - 1
|
i = i - 1
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = len(elements) - 1
|
i = len(f.inputs) - 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i = i + 1
|
i = i + 1
|
||||||
i = i % len(elements)
|
i = i % len(f.inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.SetFocus(elements[i])
|
app.SetFocus(f.inputs[i])
|
||||||
f.FocusedItem = elements[i]
|
f.FocusedItem = f.inputs[i]
|
||||||
if elements[9].HasFocus() {
|
// below code is setting the border highlight of left and right flex
|
||||||
elements[9].(*tview.TextView).SetBorderColor(gomu.colors.accent).
|
if f.inputs[9].HasFocus() {
|
||||||
|
f.inputs[9].(*tview.TextView).SetBorderColor(gomu.colors.accent).
|
||||||
SetTitleColor(gomu.colors.accent)
|
SetTitleColor(gomu.colors.accent)
|
||||||
box.SetBorderColor(gomu.colors.background).
|
box.SetBorderColor(gomu.colors.background).
|
||||||
SetTitleColor(gomu.colors.background)
|
SetTitleColor(gomu.colors.background)
|
||||||
} else {
|
} else {
|
||||||
elements[9].(*tview.TextView).SetBorderColor(gomu.colors.background).
|
f.inputs[9].(*tview.TextView).SetBorderColor(gomu.colors.background).
|
||||||
SetTitleColor(gomu.colors.background)
|
SetTitleColor(gomu.colors.background)
|
||||||
box.SetBorderColor(gomu.colors.accent).
|
box.SetBorderColor(gomu.colors.accent).
|
||||||
SetTitleColor(gomu.colors.accent)
|
SetTitleColor(gomu.colors.accent)
|
||||||
@ -423,7 +428,7 @@ func (f *myFlex) cycleFocus(app *tview.Application, elements []tview.Primitive,
|
|||||||
// Focus is an override of Focus function in tview.flex.
|
// Focus is an override of Focus function in tview.flex.
|
||||||
// This is to ensure that the focus of flex remain unchanged
|
// This is to ensure that the focus of flex remain unchanged
|
||||||
// when returning from popups or search lists
|
// when returning from popups or search lists
|
||||||
func (f *myFlex) Focus(delegate func(p tview.Primitive)) {
|
func (f *lyricFlex) Focus(delegate func(p tview.Primitive)) {
|
||||||
if f.FocusedItem != nil {
|
if f.FocusedItem != nil {
|
||||||
gomu.app.SetFocus(f.FocusedItem)
|
gomu.app.SetFocus(f.FocusedItem)
|
||||||
} else {
|
} else {
|
||||||
@ -432,7 +437,7 @@ func (f *myFlex) Focus(delegate func(p tview.Primitive)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loadTagMap will load from tag and return a map of langExt to lyrics
|
// loadTagMap will load from tag and return a map of langExt to lyrics
|
||||||
func loadTagMap(node *AudioFile) (tag *id3v2.Tag, popupLyricMap map[string]string, options []string, err error) {
|
func (node *AudioFile) loadTagMap() (tag *id3v2.Tag, popupLyricMap map[string]string, options []string, err error) {
|
||||||
|
|
||||||
popupLyricMap = make(map[string]string)
|
popupLyricMap = make(map[string]string)
|
||||||
|
|
||||||
|
@ -127,7 +127,8 @@ func TestEmbedLyric(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
lyric, err := lyric.NewFromLRC(lyricString)
|
var lyric lyric.Lyric
|
||||||
|
err = lyric.NewFromLRC(lyricString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user