mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 13:59:39 +08:00
✨ 添加txt转midi,优化midi转txt (#267)
* 🐛 长字符串发文件 * ✨ 添加txt转midi * ✨ 音色自定义 * ✨ 添加windows脚本说明 * 🐛 修复某些midi读取不了的问题 * ✨ 多音轨转换 Co-authored-by: haibaraguo <haibaraguo@yeahka.com>
This commit is contained in:
parent
92c913e3eb
commit
0dd447e270
@ -650,9 +650,13 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 团队听音练习
|
- [x] 团队听音练习
|
||||||
|
|
||||||
- [x] *.mid (解析上传的mid文件)
|
- [x] *.mid (midi 转 txt)
|
||||||
|
|
||||||
- [x] 注: 该插件需要安装timidity,安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh
|
- [x] midi制作*.txt (txt 转 midi)
|
||||||
|
|
||||||
|
- [x] 设置音色40 (0~127)
|
||||||
|
|
||||||
|
- [x] 注: 该插件需要安装timidity,linux安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh,,windows安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.bat,windows需要管理员模式运行
|
||||||
|
|
||||||
- [x] 符号说明: C5是中央C,后面不写数字,默认接5,Cb6<1,b代表降调,#代表升调,6比5高八度,<1代表音长×2,<3代表音长×8,<-1代表音长×0.5,<-3代表音长×0.125,R是休止符
|
- [x] 符号说明: C5是中央C,后面不写数字,默认接5,Cb6<1,b代表降调,#代表升调,6比5高八度,<1代表音长×2,<3代表音长×8,<-1代表音长×0.5,<-3代表音长×0.125,R是休止符
|
||||||
|
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -28,7 +28,6 @@ require (
|
|||||||
github.com/tidwall/gjson v1.14.1
|
github.com/tidwall/gjson v1.14.1
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||||
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220610070647-9eeffcb277ee
|
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220610070647-9eeffcb277ee
|
||||||
gitlab.com/gomidi/midi v1.23.7
|
|
||||||
gitlab.com/gomidi/midi/v2 v2.0.17
|
gitlab.com/gomidi/midi/v2 v2.0.17
|
||||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd
|
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -259,8 +259,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
gitlab.com/gomidi/midi v1.23.7 h1:I6qKoIk9s9dcX+pNf0jC+tziCzJFn82bMpuntRkLeik=
|
|
||||||
gitlab.com/gomidi/midi v1.23.7/go.mod h1:3ohtNOhqoSakkuLG/Li1OI6I3J1c2LErnJF5o/VBq1c=
|
|
||||||
gitlab.com/gomidi/midi/v2 v2.0.17 h1:kf16wNwFFOskl0trvarOwMuZUQICdIGn37LP9QqIRuo=
|
gitlab.com/gomidi/midi/v2 v2.0.17 h1:kf16wNwFFOskl0trvarOwMuZUQICdIGn37LP9QqIRuo=
|
||||||
gitlab.com/gomidi/midi/v2 v2.0.17/go.mod h1:quTyMKSQ4Klevxu6gY4gy2USbeZra0fV5SalndmPfsY=
|
gitlab.com/gomidi/midi/v2 v2.0.17/go.mod h1:quTyMKSQ4Klevxu6gY4gy2USbeZra0fV5SalndmPfsY=
|
||||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/binary"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
"github.com/FloatTech/zbputils/file"
|
"github.com/FloatTech/zbputils/file"
|
||||||
@ -22,7 +23,6 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
"gitlab.com/gomidi/midi/gm"
|
|
||||||
"gitlab.com/gomidi/midi/v2"
|
"gitlab.com/gomidi/midi/v2"
|
||||||
"gitlab.com/gomidi/midi/v2/smf"
|
"gitlab.com/gomidi/midi/v2/smf"
|
||||||
)
|
)
|
||||||
@ -30,11 +30,13 @@ import (
|
|||||||
func init() {
|
func init() {
|
||||||
engine := control.Register("midicreate", &ctrl.Options[*zero.Ctx]{
|
engine := control.Register("midicreate", &ctrl.Options[*zero.Ctx]{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Help: "midi音乐制作,该插件需要安装timidity,安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh\n" +
|
Help: "midi音乐制作,该插件需要安装timidity,linux安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh,windows安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.bat,windows需要管理员模式运行\n" +
|
||||||
"- midi制作 CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR\n" +
|
"- midi制作 CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR\n" +
|
||||||
"- 个人听音练习\n" +
|
"- 个人听音练习\n" +
|
||||||
"- 团队听音练习\n" +
|
"- 团队听音练习\n" +
|
||||||
"- *.mid (解析上传的mid文件)",
|
"- *.mid (midi 转 txt)\n" +
|
||||||
|
"- midi制作*.txt (txt 转 midi)\n" +
|
||||||
|
"- 设置音色40 (0~127)",
|
||||||
PrivateDataFolder: "midicreate",
|
PrivateDataFolder: "midicreate",
|
||||||
})
|
})
|
||||||
cachePath := engine.DataFolder() + "cache/"
|
cachePath := engine.DataFolder() + "cache/"
|
||||||
@ -48,7 +50,7 @@ func init() {
|
|||||||
uid := ctx.Event.UserID
|
uid := ctx.Event.UserID
|
||||||
input := ctx.State["args"].(string)
|
input := ctx.State["args"].(string)
|
||||||
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||||
cmidiFile, err := str2music(input, midiFile)
|
cmidiFile, err := str2music(ctx, input, midiFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if file.IsExist(midiFile) {
|
if file.IsExist(midiFile) {
|
||||||
ctx.UploadThisGroupFile(file.BOTPATH+"/"+midiFile, filepath.Base(midiFile), "")
|
ctx.UploadThisGroupFile(file.BOTPATH+"/"+midiFile, filepath.Base(midiFile), "")
|
||||||
@ -87,7 +89,7 @@ func init() {
|
|||||||
target := uint8(55 + rand.Intn(34))
|
target := uint8(55 + rand.Intn(34))
|
||||||
answer := name(target) + strconv.Itoa(int(target/12))
|
answer := name(target) + strconv.Itoa(int(target/12))
|
||||||
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||||
cmidiFile, err := str2music(answer, midiFile)
|
cmidiFile, err := str2music(ctx, answer, midiFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR:听音练习结束, 无法转换midi文件, ", err))
|
ctx.SendChain(message.Text("ERROR:听音练习结束, 无法转换midi文件, ", err))
|
||||||
return
|
return
|
||||||
@ -137,7 +139,7 @@ func init() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||||
cmidiFile, err = str2music(c.Event.Message.String(), midiFile)
|
cmidiFile, err = str2music(ctx, c.Event.Message.String(), midiFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: can't convert midi file,", err))
|
ctx.SendChain(message.Text("ERROR: can't convert midi file,", err))
|
||||||
return
|
return
|
||||||
@ -172,7 +174,7 @@ func init() {
|
|||||||
target = uint8(55 + rand.Intn(34))
|
target = uint8(55 + rand.Intn(34))
|
||||||
answer = name(target) + strconv.Itoa(int(target/12))
|
answer = name(target) + strconv.Itoa(int(target/12))
|
||||||
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||||
cmidiFile, err = str2music(answer, midiFile)
|
cmidiFile, err = str2music(ctx, answer, midiFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR:听音练习结束, 无法转换midi文件, ", err))
|
ctx.SendChain(message.Text("ERROR:听音练习结束, 无法转换midi文件, ", err))
|
||||||
return
|
return
|
||||||
@ -193,7 +195,7 @@ func init() {
|
|||||||
)
|
)
|
||||||
time.Sleep(time.Millisecond * 500)
|
time.Sleep(time.Millisecond * 500)
|
||||||
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||||
cmidiFile, err = str2music(c.Event.Message.String(), midiFile)
|
cmidiFile, err = str2music(ctx, c.Event.Message.String(), midiFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: can't convert midi file,", err))
|
ctx.SendChain(message.Text("ERROR: can't convert midi file,", err))
|
||||||
return
|
return
|
||||||
@ -231,8 +233,54 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("ERROR:", err))
|
ctx.SendChain(message.Text("ERROR:", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
midStr := mid2txt(data)
|
s, err := smf.ReadFrom(bytes.NewReader(data))
|
||||||
ctx.SendChain(message.Text("文件名:", ctx.Event.File.Name, "\n转化的midi字符:", midStr))
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR:", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i < int(s.NumTracks()); i++ {
|
||||||
|
midStr := mid2txt(data, i)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR:", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileName := strings.ReplaceAll(cachePath+"/"+ctx.Event.File.Name, ".mid", fmt.Sprintf("-%d.txt", i))
|
||||||
|
_ = os.WriteFile(fileName, binary.StringToBytes(midStr), 0666)
|
||||||
|
ctx.UploadThisGroupFile(file.BOTPATH+"/"+fileName, filepath.Base(fileName), "")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
engine.On("notice/group_upload", func(ctx *zero.Ctx) bool {
|
||||||
|
return path.Ext(ctx.Event.File.Name) == ".txt" && strings.Contains(ctx.Event.File.Name, "midi制作")
|
||||||
|
}).SetBlock(false).Limit(ctxext.LimitByGroup).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
fileURL := ctx.GetThisGroupFileUrl(ctx.Event.File.BusID, ctx.Event.File.ID)
|
||||||
|
data, err := web.GetData(fileURL)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR:", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uid := ctx.Event.UserID
|
||||||
|
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||||
|
cmidiFile, err := str2music(ctx, binary.BytesToString(data), midiFile)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR:无法转换midi文件,", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + cmidiFile))
|
||||||
|
})
|
||||||
|
engine.OnPrefix("设置音色").SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
param := ctx.State["args"].(string)
|
||||||
|
timbre, err := strconv.Atoi(param)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR:", err))
|
||||||
|
}
|
||||||
|
err = setTimbreMode(ctx, int64(timbre))
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,8 +301,8 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func str2music(input, midiFile string) (cmidiFile string, err error) {
|
func str2music(ctx *zero.Ctx, input, midiFile string) (cmidiFile string, err error) {
|
||||||
err = mkMidi(midiFile, input)
|
err = mkMidi(ctx, midiFile, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -264,7 +312,7 @@ func str2music(input, midiFile string) (cmidiFile string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkMidi(filePath, input string) error {
|
func mkMidi(ctx *zero.Ctx, filePath, input string) error {
|
||||||
if file.IsExist(filePath) {
|
if file.IsExist(filePath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -276,7 +324,8 @@ func mkMidi(filePath, input string) error {
|
|||||||
tr.Add(0, smf.MetaMeter(4, 4))
|
tr.Add(0, smf.MetaMeter(4, 4))
|
||||||
tr.Add(0, smf.MetaTempo(72))
|
tr.Add(0, smf.MetaTempo(72))
|
||||||
tr.Add(0, smf.MetaInstrument("Violin"))
|
tr.Add(0, smf.MetaInstrument("Violin"))
|
||||||
tr.Add(0, midi.ProgramChange(0, gm.Instr_Violin.Value()))
|
timbre := getTimbreMode(ctx)
|
||||||
|
tr.Add(0, midi.ProgramChange(0, uint8(timbre)))
|
||||||
|
|
||||||
k := strings.ReplaceAll(input, " ", "")
|
k := strings.ReplaceAll(input, " ", "")
|
||||||
|
|
||||||
@ -410,46 +459,43 @@ func processOne(note string) uint8 {
|
|||||||
return o(base, level)
|
return o(base, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mid2txt(midBytes []byte) (midStr string) {
|
func mid2txt(midBytes []byte, trackNo int) (midStr string) {
|
||||||
var (
|
var (
|
||||||
absTicksStart float64
|
absTicksStart float64
|
||||||
absTicksEnd float64
|
absTicksEnd float64
|
||||||
startNote byte
|
startNote byte
|
||||||
endNote byte
|
endNote byte
|
||||||
defaultMetric = 960.0
|
defaultMetric = 960.0
|
||||||
defaultTrackNo = 0
|
|
||||||
)
|
)
|
||||||
_ = smf.ReadTracksFrom(bytes.NewReader(midBytes)).
|
_ = smf.ReadTracksFrom(bytes.NewReader(midBytes), trackNo).
|
||||||
Do(
|
Do(
|
||||||
func(te smf.TrackEvent) {
|
func(te smf.TrackEvent) {
|
||||||
if !te.Message.IsMeta() && te.TrackNo == defaultTrackNo {
|
if !te.Message.IsMeta() {
|
||||||
b := te.Message.Bytes()
|
b := te.Message.Bytes()
|
||||||
if len(b) == 3 {
|
if te.Message.Is(midi.NoteOnMsg) && b[2] > 0 {
|
||||||
if b[0] == 0x90 && b[2] > 0 {
|
absTicksStart = float64(te.AbsTicks)
|
||||||
absTicksStart = float64(te.AbsTicks)
|
startNote = b[1]
|
||||||
startNote = b[1]
|
}
|
||||||
}
|
if te.Message.Is(midi.NoteOffMsg) || (te.Message.Is(midi.NoteOnMsg) && b[2] == 0x00) {
|
||||||
if b[0] == 0x80 || (b[0] == 0x90 && b[2] == 0x00) {
|
absTicksEnd = float64(te.AbsTicks)
|
||||||
absTicksEnd = float64(te.AbsTicks)
|
endNote = b[1]
|
||||||
endNote = b[1]
|
if startNote == endNote {
|
||||||
|
sign := name(b[1])
|
||||||
|
level := b[1] / 12
|
||||||
|
length := (absTicksEnd - absTicksStart) / defaultMetric
|
||||||
|
midStr += sign
|
||||||
|
if level != 5 {
|
||||||
|
midStr += strconv.Itoa(int(level))
|
||||||
|
}
|
||||||
|
pow := int(math.Round(math.Log2(length)))
|
||||||
|
if pow >= -4 && pow != 0 {
|
||||||
|
midStr += "<" + strconv.Itoa(pow)
|
||||||
|
}
|
||||||
|
startNote = 0
|
||||||
|
endNote = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (b[0] == 0x80 || (b[0] == 0x90 && b[2] == 0x00)) && startNote == endNote {
|
if (te.Message.Is(midi.NoteOnMsg) && b[2] > 0) && absTicksStart > absTicksEnd {
|
||||||
sign := name(b[1])
|
|
||||||
level := b[1] / 12
|
|
||||||
length := (absTicksEnd - absTicksStart) / defaultMetric
|
|
||||||
midStr += sign
|
|
||||||
if level != 5 {
|
|
||||||
midStr += strconv.Itoa(int(level))
|
|
||||||
}
|
|
||||||
pow := int(math.Round(math.Log2(length)))
|
|
||||||
if pow >= -4 && pow != 0 {
|
|
||||||
midStr += "<" + strconv.Itoa(pow)
|
|
||||||
}
|
|
||||||
startNote = 0
|
|
||||||
endNote = 0
|
|
||||||
}
|
|
||||||
if (b[0] == 0x90 && b[2] > 0) && absTicksStart > absTicksEnd {
|
|
||||||
length := (absTicksStart - absTicksEnd) / defaultMetric
|
length := (absTicksStart - absTicksEnd) / defaultMetric
|
||||||
pow := int(math.Round(math.Log2(length)))
|
pow := int(math.Round(math.Log2(length)))
|
||||||
if pow == 0 {
|
if pow == 0 {
|
||||||
@ -463,3 +509,31 @@ func mid2txt(midBytes []byte) (midStr string) {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setTimbreMode(ctx *zero.Ctx, timbre int64) error {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
if timbre < 0 || timbre > 127 {
|
||||||
|
return errors.New("音色应该在0~127之间")
|
||||||
|
}
|
||||||
|
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
return errors.New("no such plugin")
|
||||||
|
}
|
||||||
|
return m.SetData(gid, timbre)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimbreMode(ctx *zero.Ctx) (index int64) {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if ok {
|
||||||
|
index := m.GetData(gid)
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
return 40
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user