3 Commits

Author SHA1 Message Date
Aynakeya
dd46c167ff add i18n 2022-06-26 01:44:26 -07:00
Aynakeya
8c6ea48ad4 update README.md 2022-06-25 14:27:47 -07:00
Aynakeya
6fc2773b12 fix 2022-06-25 14:23:59 -07:00
17 changed files with 417 additions and 59 deletions

14
README.md Normal file
View File

@@ -0,0 +1,14 @@
# AynaLivePlayer
Bilibili Audio Bot. Written by Golang.
Provider By Aynakeya
QQ group: 621035845
## build
```
go build -ldflags -H=windowsgui app/gui/main.go
```

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/gui" "AynaLivePlayer/gui"
"AynaLivePlayer/i18n"
"AynaLivePlayer/logger" "AynaLivePlayer/logger"
"AynaLivePlayer/plugin/diange" "AynaLivePlayer/plugin/diange"
"AynaLivePlayer/plugin/qiege" "AynaLivePlayer/plugin/qiege"
@@ -32,6 +33,7 @@ func main() {
defer func() { defer func() {
controller.Destroy() controller.Destroy()
config.SaveToConfigFile(config.CONFIG_PATH) config.SaveToConfigFile(config.CONFIG_PATH)
i18n.SaveTranslation()
}() }()
gui.Initialize() gui.Initialize()
gui.MainWindow.ShowAndRun() gui.MainWindow.ShowAndRun()

220
assets/translation.json Normal file
View File

@@ -0,0 +1,220 @@
{
"Languages": [
"en",
"zh-CN"
],
"Messages": {
"gui.player.button.lrc": {
"en": "lrc",
"zh-CN": "歌词"
},
"gui.player.playlist.artist": {
"en": "Artist",
"zh-CN": "歌手"
},
"gui.player.playlist.op.delete": {
"en": "Delete",
"zh-CN": "删除"
},
"gui.player.playlist.op.top": {
"en": "Top",
"zh-CN": "置顶"
},
"gui.player.playlist.ops": {
"en": "OPs",
"zh-CN": "操作"
},
"gui.player.playlist.title": {
"en": "Title",
"zh-CN": "歌名"
},
"gui.player.playlist.user": {
"en": "User",
"zh-CN": "用户"
},
"gui.playlist.add.cancel": {
"en": "Cancel",
"zh-CN": "取消"
},
"gui.playlist.add.confirm": {
"en": "Confirm",
"zh-CN": "确认"
},
"gui.playlist.add.id_url": {
"en": "ID/URL",
"zh-CN": "ID/网址"
},
"gui.playlist.add.prompt": {
"en": "Please enter the ID or URL of the song you want to add.",
"zh-CN": "输入歌单ID或者歌单网址。"
},
"gui.playlist.add.title": {
"en": "Add Playlist",
"zh-CN": "添加歌单"
},
"gui.playlist.button.add": {
"en": "Add",
"zh-CN": "添加"
},
"gui.playlist.button.refresh": {
"en": "Refresh",
"zh-CN": "刷新"
},
"gui.playlist.button.remove": {
"en": "Remove",
"zh-CN": "移除"
},
"gui.playlist.button.set_as_system": {
"en": "SetAsSystem",
"zh-CN": "设为默认歌单"
},
"gui.playlist.current": {
"en": "Current: ",
"zh-CN": "当前为: "
},
"gui.playlist.current.none": {
"en": "Current: None",
"zh-CN": "当前为: 无"
},
"gui.room.btn.connect": {
"en": "Connect",
"zh-CN": "连接"
},
"gui.room.btn.disconnect": {
"en": "Disconnect",
"zh-CN": "断开"
},
"gui.room.id": {
"en": "Room ID: ",
"zh-CN": "房间号: "
},
"gui.room.status.connected": {
"en": "Connected",
"zh-CN": "已连接"
},
"gui.room.status.disconnected": {
"en": "Disconnected",
"zh-CN": "已断开"
},
"gui.room.status.failed": {
"en": "Set Failed",
"zh-CN": "设置失败"
},
"gui.room.waiting": {
"en": "Waiting",
"zh-CN": "等待连接"
},
"gui.search.artist": {
"en": "Artist",
"zh-CN": "歌手"
},
"gui.search.filter": {
"en": "Source Filter: ",
"zh-CN": "选择源: "
},
"gui.search.operation": {
"en": "Operation",
"zh-CN": "操作 "
},
"gui.search.placeholder": {
"en": "Keyword",
"zh-CN": "Keyword"
},
"gui.search.search": {
"en": "Search",
"zh-CN": "搜索"
},
"gui.search.source": {
"en": "Source",
"zh-CN": "歌源"
},
"gui.search.title": {
"en": "Title",
"zh-CN": "歌名"
},
"gui.tab.config": {
"en": "Config",
"zh-CN": "设置"
},
"gui.tab.player": {
"en": "Player",
"zh-CN": "播放器"
},
"gui.tab.playlist": {
"en": "Playlist",
"zh-CN": "播放列表"
},
"gui.tab.room": {
"en": "Room",
"zh-CN": "直播间"
},
"gui.tab.search": {
"en": "Search",
"zh-CN": "搜索"
},
"plugin.diange.admin": {
"en": "Admin",
"zh-CN": "管理员"
},
"plugin.diange.cooldown": {
"en": "Cooldown",
"zh-CN": "点歌冷却"
},
"plugin.diange.custom_cmd": {
"en": "Custom Command (Default one still works)",
"zh-CN": "自定义命令 (默认的依然可用)"
},
"plugin.diange.description": {
"en": "Basic Diange Configuration",
"zh-CN": "点歌基本设置"
},
"plugin.diange.permission": {
"en": "Permission",
"zh-CN": "点歌权限"
},
"plugin.diange.privilege": {
"en": "Privilege",
"zh-CN": "舰长"
},
"plugin.diange.queue_max": {
"en": "Max Queue",
"zh-CN": "最大点歌数"
},
"plugin.diange.title": {
"en": "Diange",
"zh-CN": "点歌"
},
"plugin.diange.user": {
"en": "User",
"zh-CN": "普通用户"
},
"plugin.qiege.admin": {
"en": "Admin",
"zh-CN": "管理员"
},
"plugin.qiege.custom_cmd": {
"en": "Custom Command (Default one still works)",
"zh-CN": "自定义命令 (默认的依然可用)"
},
"plugin.qiege.description": {
"en": "Basic Qiege configuration",
"zh-CN": "基础切歌设置"
},
"plugin.qiege.permission": {
"en": "Permission",
"zh-CN": "切歌权限"
},
"plugin.qiege.privilege": {
"en": "Privilege",
"zh-CN": "舰长"
},
"plugin.qiege.title": {
"en": "Qiege",
"zh-CN": "切歌"
},
"plugin.qiege.user": {
"en": "User",
"zh-CN": "切自己"
}
}
}

View File

@@ -6,7 +6,7 @@ import (
"path" "path"
) )
const VERSION = "alpha 0.6" const VERSION = "alpha 0.6.5"
const CONFIG_PATH = "./config.ini" const CONFIG_PATH = "./config.ini"
const Assests_PATH = "./assets" const Assests_PATH = "./assets"
@@ -38,7 +38,7 @@ func init() {
fmt.Println("config not found, using default config") fmt.Println("config not found, using default config")
ConfigFile = ini.Empty() ConfigFile = ini.Empty()
} }
for _, cfg := range []Config{Log, LiveRoom, Player, Provider} { for _, cfg := range []Config{Log, LiveRoom, Player, Provider, General} {
LoadConfig(cfg) LoadConfig(cfg)
} }
} }

13
config/config_general.go Normal file
View File

@@ -0,0 +1,13 @@
package config
type _GeneralConfig struct {
Language string
}
func (c *_GeneralConfig) Name() string {
return "General"
}
var General = &_GeneralConfig{
Language: "en",
}

View File

@@ -2,7 +2,9 @@ package gui
import ( import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/i18n"
"AynaLivePlayer/logger" "AynaLivePlayer/logger"
"fmt"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/app" "fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -29,22 +31,22 @@ func l() *logrus.Entry {
func Initialize() { func Initialize() {
os.Setenv("FYNE_FONT", config.GetAssetPath("msyh.ttc")) os.Setenv("FYNE_FONT", config.GetAssetPath("msyh.ttc"))
App = app.New() App = app.New()
MainWindow = App.NewWindow("AynaLivePlayer") MainWindow = App.NewWindow(fmt.Sprintf("AynaLivePlayer Ver.%s", config.VERSION))
tabs := container.NewAppTabs( tabs := container.NewAppTabs(
container.NewTabItem("Player", container.NewTabItem(i18n.T("gui.tab.player"),
newPaddedBoarder(nil, createPlayController(), nil, nil, createPlaylist()), newPaddedBoarder(nil, createPlayController(), nil, nil, createPlaylist()),
), ),
container.NewTabItem("Search", container.NewTabItem(i18n.T("gui.tab.search"),
newPaddedBoarder(createSearchBar(), nil, nil, nil, createSearchList()), newPaddedBoarder(createSearchBar(), nil, nil, nil, createSearchList()),
), ),
container.NewTabItem("Room", container.NewTabItem(i18n.T("gui.tab.room"),
newPaddedBoarder(createRoomController(), nil, nil, nil, createRoomLogger()), newPaddedBoarder(createRoomController(), nil, nil, nil, createRoomLogger()),
), ),
container.NewTabItem("Playlist", container.NewTabItem(i18n.T("gui.tab.playlist"),
newPaddedBoarder(nil, nil, createPlaylists(), nil, createPlaylistMedias()), newPaddedBoarder(nil, nil, createPlaylists(), nil, createPlaylistMedias()),
), ),
container.NewTabItem("Config", container.NewTabItem(i18n.T("gui.tab.config"),
newPaddedBoarder(nil, nil, nil, nil, createConfigLayout()), newPaddedBoarder(nil, nil, nil, nil, createConfigLayout()),
), ),
) )

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/event" "AynaLivePlayer/event"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player" "AynaLivePlayer/player"
"AynaLivePlayer/util" "AynaLivePlayer/util"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
@@ -64,7 +65,7 @@ func createPlayController() fyne.CanvasObject {
PlayController.Volume = widget.NewSlider(0, 100) PlayController.Volume = widget.NewSlider(0, 100)
volumeIcon := widget.NewIcon(theme.VolumeMuteIcon()) volumeIcon := widget.NewIcon(theme.VolumeMuteIcon())
PlayController.ButtonLrc = widget.NewButton("lrc", func() {}) PlayController.ButtonLrc = widget.NewButton(i18n.T("gui.player.button.lrc"), func() {})
volumeControl := container.NewBorder(nil, nil, container.NewHBox(widget.NewLabel(" "), volumeIcon), nil, volumeControl := container.NewBorder(nil, nil, container.NewHBox(widget.NewLabel(" "), volumeIcon), nil,
container.NewGridWithColumns(3, container.NewMax(PlayController.Volume), PlayController.ButtonLrc)) container.NewGridWithColumns(3, container.NewMax(PlayController.Volume), PlayController.ButtonLrc))

View File

@@ -3,6 +3,7 @@ package gui
import ( import (
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/event" "AynaLivePlayer/event"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player" "AynaLivePlayer/player"
"fmt" "fmt"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
@@ -23,10 +24,10 @@ func (b *playlistOperationButton) Tapped(e *fyne.PointEvent) {
func newPlaylistOperationButton() *playlistOperationButton { func newPlaylistOperationButton() *playlistOperationButton {
b := &playlistOperationButton{Index: 0} b := &playlistOperationButton{Index: 0}
deleteItem := fyne.NewMenuItem("Delete", func() { deleteItem := fyne.NewMenuItem(i18n.T("gui.player.playlist.op.delete"), func() {
fmt.Println("delete", b.Index) fmt.Println("delete", b.Index)
}) })
topItem := fyne.NewMenuItem("Top", func() { topItem := fyne.NewMenuItem(i18n.T("gui.player.playlist.op.top"), func() {
controller.UserPlaylist.Move(b.Index, 0) controller.UserPlaylist.Move(b.Index, 0)
}) })
m := fyne.NewMenu("", deleteItem, topItem) m := fyne.NewMenu("", deleteItem, topItem)
@@ -72,8 +73,11 @@ func createPlaylist() fyne.CanvasObject {
registerPlaylistHandler() registerPlaylistHandler()
return container.NewBorder( return container.NewBorder(
container.NewBorder(nil, nil, container.NewBorder(nil, nil,
widget.NewLabel("#"), widget.NewLabel("OPs"), widget.NewLabel("#"), widget.NewLabel(i18n.T("gui.player.playlist.ops")),
container.NewGridWithColumns(3, widget.NewLabel("Title"), widget.NewLabel("Artist"), widget.NewLabel("User"))), container.NewGridWithColumns(3,
widget.NewLabel(i18n.T("gui.player.playlist.title")),
widget.NewLabel(i18n.T("gui.player.playlist.artist")),
widget.NewLabel(i18n.T("gui.player.playlist.user")))),
widget.NewSeparator(), widget.NewSeparator(),
nil, nil, nil, nil,
UserPlaylist.List, UserPlaylist.List,

View File

@@ -3,6 +3,7 @@ package gui
import ( import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/i18n"
"fmt" "fmt"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -25,9 +26,9 @@ type PlaylistManagerContainer struct {
func (p *PlaylistManagerContainer) UpdateCurrentSystemPlaylist() { func (p *PlaylistManagerContainer) UpdateCurrentSystemPlaylist() {
if config.Player.PlaylistIndex >= len(controller.PlaylistManager) { if config.Player.PlaylistIndex >= len(controller.PlaylistManager) {
p.CurrentSystemPlaylist.SetText("Current: None") p.CurrentSystemPlaylist.SetText(i18n.T("gui.playlist.current.none"))
} }
p.CurrentSystemPlaylist.SetText("Current: " + controller.PlaylistManager[config.Player.PlaylistIndex].Name) p.CurrentSystemPlaylist.SetText(i18n.T("gui.playlist.current") + controller.PlaylistManager[config.Player.PlaylistIndex].Name)
} }
var PlaylistManager = &PlaylistManagerContainer{} var PlaylistManager = &PlaylistManagerContainer{}
@@ -44,22 +45,22 @@ func createPlaylists() fyne.CanvasObject {
object.(*widget.Label).SetText( object.(*widget.Label).SetText(
controller.PlaylistManager[id].Name) controller.PlaylistManager[id].Name)
}) })
PlaylistManager.AddBtn = widget.NewButton("Add", func() { PlaylistManager.AddBtn = widget.NewButton(i18n.T("gui.playlist.button.add"), func() {
providerEntry := widget.NewSelect(config.Provider.Priority, nil) providerEntry := widget.NewSelect(config.Provider.Priority, nil)
idEntry := widget.NewEntry() idEntry := widget.NewEntry()
dia := dialog.NewCustomConfirm( dia := dialog.NewCustomConfirm(
"Add Playlist", i18n.T("gui.playlist.add.title"),
"Add", i18n.T("gui.playlist.add.confirm"),
"Cancel", i18n.T("gui.playlist.add.cancel"),
container.NewVBox( container.NewVBox(
container.New( container.New(
layout.NewFormLayout(), layout.NewFormLayout(),
widget.NewLabel("Provider"), widget.NewLabel(i18n.T("gui.playlist.add.confirm")),
providerEntry, providerEntry,
widget.NewLabel("ID/URL"), widget.NewLabel(i18n.T("gui.playlist.add.id_url")),
idEntry, idEntry,
), ),
widget.NewLabel("Please Enter playlist id or playlist url"), widget.NewLabel(i18n.T("gui.playlist.add.prompt")),
), ),
func(b bool) { func(b bool) {
if b && len(providerEntry.Selected) > 0 && len(idEntry.Text) > 0 { if b && len(providerEntry.Selected) > 0 && len(idEntry.Text) > 0 {
@@ -73,7 +74,7 @@ func createPlaylists() fyne.CanvasObject {
dia.Resize(fyne.NewSize(512, 256)) dia.Resize(fyne.NewSize(512, 256))
dia.Show() dia.Show()
}) })
PlaylistManager.RemoveBtn = widget.NewButton("Remove", func() { PlaylistManager.RemoveBtn = widget.NewButton(i18n.T("gui.playlist.button.remove"), func() {
controller.RemovePlaylist(PlaylistManager.Index) controller.RemovePlaylist(PlaylistManager.Index)
//PlaylistManager.Index = 0 //PlaylistManager.Index = 0
PlaylistManager.Playlists.Select(0) PlaylistManager.Playlists.Select(0)
@@ -95,13 +96,13 @@ func createPlaylists() fyne.CanvasObject {
func createPlaylistMedias() fyne.CanvasObject { func createPlaylistMedias() fyne.CanvasObject {
PlaylistManager.RefreshBtn = createAsyncButton( PlaylistManager.RefreshBtn = createAsyncButton(
widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), nil), widget.NewButtonWithIcon(i18n.T("gui.playlist.button.refresh"), theme.ViewRefreshIcon(), nil),
func() { func() {
controller.PreparePlaylistByIndex(PlaylistManager.Index) controller.PreparePlaylistByIndex(PlaylistManager.Index)
PlaylistManager.PlaylistMedia.Refresh() PlaylistManager.PlaylistMedia.Refresh()
}) })
PlaylistManager.SetAsSystemBtn = createAsyncButton( PlaylistManager.SetAsSystemBtn = createAsyncButton(
widget.NewButton("SetAsSystem", nil), widget.NewButton(i18n.T("gui.playlist.button.set_as_system"), nil),
func() { func() {
controller.SetSystemPlaylist(PlaylistManager.Index) controller.SetSystemPlaylist(PlaylistManager.Index)
PlaylistManager.PlaylistMedia.Refresh() PlaylistManager.PlaylistMedia.Refresh()
@@ -143,7 +144,7 @@ func createPlaylistMedias() fyne.CanvasObject {
} }
}) })
return container.NewBorder( return container.NewBorder(
container.NewHBox(PlaylistManager.RefreshBtn, PlaylistManager.SetAsSystemBtn), nil, container.NewHBox(PlaylistManager.RefreshBtn, PlaylistManager.SetAsSystemBtn, PlaylistManager.CurrentSystemPlaylist), nil,
nil, nil, nil, nil,
PlaylistManager.PlaylistMedia) PlaylistManager.PlaylistMedia)
} }

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/event" "AynaLivePlayer/event"
"AynaLivePlayer/i18n"
"AynaLivePlayer/liveclient" "AynaLivePlayer/liveclient"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -21,11 +22,11 @@ var RoomController = &RoomControllerContainer{}
func createRoomController() fyne.CanvasObject { func createRoomController() fyne.CanvasObject {
RoomController.Input = widget.NewSelectEntry(config.LiveRoom.History) RoomController.Input = widget.NewSelectEntry(config.LiveRoom.History)
RoomController.ConnectBtn = widget.NewButton("Connect", func() { RoomController.ConnectBtn = widget.NewButton(i18n.T("gui.room.btn.connect"), func() {
RoomController.ConnectBtn.Disable() RoomController.ConnectBtn.Disable()
controller.SetDanmuClient(RoomController.Input.Text) controller.SetDanmuClient(RoomController.Input.Text)
if controller.LiveClient == nil { if controller.LiveClient == nil {
RoomController.Status.SetText("Set Failed") RoomController.Status.SetText(i18n.T("gui.room.status.failed"))
RoomController.ConnectBtn.Enable() RoomController.ConnectBtn.Enable()
RoomController.Status.Refresh() RoomController.Status.Refresh()
return return
@@ -34,9 +35,9 @@ func createRoomController() fyne.CanvasObject {
controller.LiveClient.Handler().RegisterA(liveclient.EventStatusChange, "gui.liveclient.status", func(event *event.Event) { controller.LiveClient.Handler().RegisterA(liveclient.EventStatusChange, "gui.liveclient.status", func(event *event.Event) {
d := event.Data.(liveclient.StatusChangeEvent) d := event.Data.(liveclient.StatusChangeEvent)
if d.Connected { if d.Connected {
RoomController.Status.SetText("Connected") RoomController.Status.SetText(i18n.T("gui.room.status.connected"))
} else { } else {
RoomController.Status.SetText("Disconnected") RoomController.Status.SetText(i18n.T("gui.room.status.disconnected"))
} }
RoomController.Status.Refresh() RoomController.Status.Refresh()
}) })
@@ -45,13 +46,13 @@ func createRoomController() fyne.CanvasObject {
RoomController.ConnectBtn.Enable() RoomController.ConnectBtn.Enable()
}() }()
}) })
RoomController.DisConnectBtn = widget.NewButton("Disconnect", func() { RoomController.DisConnectBtn = widget.NewButton(i18n.T("gui.room.btn.disconnect"), func() {
controller.ResetDanmuClient() controller.ResetDanmuClient()
}) })
RoomController.Status = widget.NewLabel("Waiting") RoomController.Status = widget.NewLabel(i18n.T("gui.room.waiting"))
return container.NewBorder( return container.NewBorder(
nil, nil, nil, nil,
widget.NewLabel("Room ID:"), container.NewHBox(RoomController.ConnectBtn, RoomController.DisConnectBtn), widget.NewLabel(i18n.T("gui.room.id")), container.NewHBox(RoomController.ConnectBtn, RoomController.DisConnectBtn),
container.NewBorder(nil, nil, nil, RoomController.Status, RoomController.Input), container.NewBorder(nil, nil, nil, RoomController.Status, RoomController.Input),
) )
} }

View File

@@ -3,6 +3,7 @@ package gui
import ( import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player" "AynaLivePlayer/player"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
@@ -20,8 +21,8 @@ var SearchBar = &SearchBarContainer{}
func createSearchBar() fyne.CanvasObject { func createSearchBar() fyne.CanvasObject {
SearchBar.Input = widget.NewEntry() SearchBar.Input = widget.NewEntry()
SearchBar.Input.SetPlaceHolder("Keyword") SearchBar.Input.SetPlaceHolder(i18n.T("gui.search.placeholder"))
SearchBar.Button = widget.NewButton("Search", nil) SearchBar.Button = widget.NewButton(i18n.T("gui.search.search"), nil)
SearchBar.Button.OnTapped = createAsyncOnTapped(SearchBar.Button, func() { SearchBar.Button.OnTapped = createAsyncOnTapped(SearchBar.Button, func() {
keyword := SearchBar.Input.Text keyword := SearchBar.Input.Text
s := make([]string, len(SearchBar.UseSource.Selected)) s := make([]string, len(SearchBar.UseSource.Selected))
@@ -44,10 +45,10 @@ func createSearchBar() fyne.CanvasObject {
SearchBar.UseSource.Horizontal = true SearchBar.UseSource.Horizontal = true
SearchBar.UseSource.SetSelected(s) SearchBar.UseSource.SetSelected(s)
searchInput := container.NewBorder( searchInput := container.NewBorder(
nil, nil, widget.NewLabel("Search"), SearchBar.Button, nil, nil, widget.NewLabel(i18n.T("gui.search.search")), SearchBar.Button,
SearchBar.Input) SearchBar.Input)
return container.NewVBox( return container.NewVBox(
searchInput, searchInput,
container.NewHBox(widget.NewLabel("Source filter: "), SearchBar.UseSource), container.NewHBox(widget.NewLabel(i18n.T("gui.search.filter")), SearchBar.UseSource),
widget.NewSeparator()) widget.NewSeparator())
} }

View File

@@ -2,6 +2,7 @@ package gui
import ( import (
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player" "AynaLivePlayer/player"
"AynaLivePlayer/provider" "AynaLivePlayer/provider"
"fmt" "fmt"
@@ -53,11 +54,11 @@ func createSearchList() fyne.CanvasObject {
}) })
return container.NewBorder( return container.NewBorder(
container.NewBorder(nil, nil, container.NewBorder(nil, nil,
widget.NewLabel("#"), widget.NewLabel("Operation"), widget.NewLabel("#"), widget.NewLabel(i18n.T("gui.search.operation")),
container.NewGridWithColumns(3, container.NewGridWithColumns(3,
widget.NewLabel("title"), widget.NewLabel(i18n.T("gui.search.title")),
widget.NewLabel("artist"), widget.NewLabel(i18n.T("gui.search.artist")),
widget.NewLabel("source"))), widget.NewLabel(i18n.T("gui.search.source")))),
nil, nil, nil, nil, nil, nil,
SearchResult.List, SearchResult.List,
) )

63
i18n/i18n.go Normal file
View File

@@ -0,0 +1,63 @@
package i18n
import (
"AynaLivePlayer/config"
"AynaLivePlayer/util"
"encoding/json"
"io/ioutil"
)
const FILENAME = "translation.json"
type Translation struct {
Languages []string
Messages map[string]map[string]string
}
func (t *Translation) HasLanguage(lang string) bool {
for _, l := range t.Languages {
if l == lang {
return true
}
}
return false
}
var TranslationMap Translation
var CurrentLanguage string
func init() {
TranslationMap = Translation{make([]string, 0), make(map[string]map[string]string)}
file, err := ioutil.ReadFile(config.GetAssetPath(FILENAME))
if err == nil {
_ = json.Unmarshal([]byte(file), &TranslationMap)
}
LoadLanguage(config.General.Language)
}
func LoadLanguage(lang string) {
CurrentLanguage = lang
if TranslationMap.HasLanguage(lang) {
return
}
TranslationMap.Languages = append(TranslationMap.Languages, lang)
for id, m := range TranslationMap.Messages {
m[lang] = id
}
}
func T(id string) string {
if x, ok := TranslationMap.Messages[id]; ok {
return x[CurrentLanguage]
}
TranslationMap.Messages[id] = make(map[string]string)
for _, l := range TranslationMap.Languages {
TranslationMap.Messages[id][l] = id
}
return id
}
func SaveTranslation() {
content, _ := util.MarshalIndentUnescape(TranslationMap, "", " ")
_ = ioutil.WriteFile(config.GetAssetPath(FILENAME), []byte(content), 0666)
}

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/gui" "AynaLivePlayer/gui"
"AynaLivePlayer/i18n"
"AynaLivePlayer/liveclient" "AynaLivePlayer/liveclient"
"AynaLivePlayer/logger" "AynaLivePlayer/logger"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
@@ -91,11 +92,11 @@ func (d *Diange) Execute(command string, args []string, danmu *liveclient.DanmuM
} }
func (d *Diange) Title() string { func (d *Diange) Title() string {
return "Diange" return i18n.T("plugin.diange.title")
} }
func (d *Diange) Description() string { func (d *Diange) Description() string {
return "Basic diange configuration" return i18n.T("plugin.diange.description")
} }
func (d *Diange) CreatePanel() fyne.CanvasObject { func (d *Diange) CreatePanel() fyne.CanvasObject {
@@ -103,21 +104,21 @@ func (d *Diange) CreatePanel() fyne.CanvasObject {
return d.panel return d.panel
} }
dgPerm := container.NewHBox( dgPerm := container.NewHBox(
widget.NewLabel("点歌权限"), widget.NewLabel(i18n.T("plugin.diange.permission")),
widget.NewCheckWithData("用户", binding.BindBool(&d.UserPermission)), widget.NewCheckWithData(i18n.T("plugin.diange.user"), binding.BindBool(&d.UserPermission)),
widget.NewCheckWithData("舰长", binding.BindBool(&d.PrivilegePermission)), widget.NewCheckWithData(i18n.T("plugin.diange.privilege"), binding.BindBool(&d.PrivilegePermission)),
widget.NewCheckWithData("管理员", binding.BindBool(&d.AdminPermission)), widget.NewCheckWithData(i18n.T("plugin.diange.admin"), binding.BindBool(&d.AdminPermission)),
) )
dgQueue := container.NewBorder(nil, nil, dgQueue := container.NewBorder(nil, nil,
widget.NewLabel("最大点歌数"), nil, widget.NewLabel(i18n.T("plugin.diange.queue_max")), nil,
widget.NewEntryWithData(binding.IntToString(binding.BindInt(&d.QueueMax))), widget.NewEntryWithData(binding.IntToString(binding.BindInt(&d.QueueMax))),
) )
dgCoolDown := container.NewBorder(nil, nil, dgCoolDown := container.NewBorder(nil, nil,
widget.NewLabel("点歌冷却时间"), nil, widget.NewLabel(i18n.T("plugin.diange.cooldown")), nil,
widget.NewEntryWithData(binding.IntToString(binding.BindInt(&d.UserCoolDown))), widget.NewEntryWithData(binding.IntToString(binding.BindInt(&d.UserCoolDown))),
) )
dgShortCut := container.NewBorder(nil, nil, dgShortCut := container.NewBorder(nil, nil,
widget.NewLabel("自定义命令 (默认的依然可用)"), nil, widget.NewLabel(i18n.T("plugin.diange.custom_cmd")), nil,
widget.NewEntryWithData(binding.BindString(&d.CustomCMD)), widget.NewEntryWithData(binding.BindString(&d.CustomCMD)),
) )
d.panel = container.NewVBox(dgPerm, dgQueue, dgCoolDown, dgShortCut) d.panel = container.NewVBox(dgPerm, dgQueue, dgCoolDown, dgShortCut)

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config" "AynaLivePlayer/config"
"AynaLivePlayer/controller" "AynaLivePlayer/controller"
"AynaLivePlayer/gui" "AynaLivePlayer/gui"
"AynaLivePlayer/i18n"
"AynaLivePlayer/liveclient" "AynaLivePlayer/liveclient"
"AynaLivePlayer/logger" "AynaLivePlayer/logger"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
@@ -74,26 +75,25 @@ func (d *Qiege) Execute(command string, args []string, danmu *liveclient.DanmuMe
} }
func (d *Qiege) Title() string { func (d *Qiege) Title() string {
return "Qiege" return i18n.T("plugin.qiege.title")
} }
func (d *Qiege) Description() string { func (d *Qiege) Description() string {
return "Basic Qiege configuration" return i18n.T("plugin.qiege.description")
} }
func (d *Qiege) CreatePanel() fyne.CanvasObject { func (d *Qiege) CreatePanel() fyne.CanvasObject {
if d.panel != nil { if d.panel != nil {
return d.panel return d.panel
} }
dgPerm := container.NewHBox( dgPerm := container.NewHBox(
widget.NewLabel("切歌权限"), widget.NewLabel(i18n.T("plugin.qiege.permission")),
widget.NewCheckWithData("切自己", binding.BindBool(&d.UserPermission)), widget.NewCheckWithData(i18n.T("plugin.qiege.user"), binding.BindBool(&d.UserPermission)),
widget.NewCheckWithData("舰长", binding.BindBool(&d.PrivilegePermission)), widget.NewCheckWithData(i18n.T("plugin.qiege.privilege"), binding.BindBool(&d.PrivilegePermission)),
widget.NewCheckWithData("管理员", binding.BindBool(&d.AdminPermission)), widget.NewCheckWithData(i18n.T("plugin.qiege.admin"), binding.BindBool(&d.AdminPermission)),
) )
qgShortCut := container.NewBorder(nil, nil, qgShortCut := container.NewBorder(nil, nil,
widget.NewLabel("自定义命令 (默认的依然可用)"), nil, widget.NewLabel(i18n.T("plugin.qiege.custom_cmd")), nil,
widget.NewEntryWithData(binding.BindString(&d.CustomCMD)), widget.NewEntryWithData(binding.BindString(&d.CustomCMD)),
) )
d.panel = container.NewVBox(dgPerm, qgShortCut) d.panel = container.NewVBox(dgPerm, qgShortCut)

View File

@@ -5,7 +5,7 @@
- @5 delete optimization - @5 delete optimization
- 歌词来源 - 歌词来源
- kuwo歌单
- 文本输出 - 文本输出
- web输出 - web输出
- 进入beta版本 - 进入beta版本
@@ -14,6 +14,7 @@
---- ----
Finished Finished
- 2022.6.25: kuwo歌单
- 2022.6.25: 设置界面 - 2022.6.25: 设置界面
- 2022.6.25: @6 bug, race condition, playlist size changed during playlist update. - 2022.6.25: @6 bug, race condition, playlist size changed during playlist update.
- 2022.6.23: 用户歌单操作 - 2022.6.23: 用户歌单操作

33
util/json.go Normal file
View File

@@ -0,0 +1,33 @@
package util
import (
"bytes"
"encoding/json"
)
func MarshalUnescape(v interface{}) (string, error) {
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
err := jsonEncoder.Encode(v)
if err != nil {
return "", err
}
return bf.String(), nil
}
func MarshalIndentUnescape(v interface{}, prefix, indent string) (string, error) {
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
err := jsonEncoder.Encode(v)
if err != nil {
return "", err
}
var buf bytes.Buffer
err = json.Indent(&buf, bf.Bytes(), prefix, indent)
if err != nil {
return "", err
}
return buf.String(), nil
}