# README
BliveDataExportToExcel
环境准备
系统版本 Windows 11 24H2
Go version go1.23.0 windows/amd64
安装Fyne UI,快速上手 https://docs.fyne.io/started/ Fyne 需要 3 个基本元素,Go 工具(至少为 1.12 版)、C 编译器(用于连接系统图形驱动程序)和系统图形驱动程序。
$ go get fyne.io/fyne/v2@latest
$ go install fyne.io/fyne/v2/cmd/fyne@latest
C 编译器推荐安装MinGW,右侧Releases提供了压缩包,解压后,将/bin的路径添加到环境变量运行终端查看是否安装成功
g++ -v
gcc -v
bilibili 直播弹幕 golang 库
基于github.com/Akegarasu/blivedm-go库修改,增加了简单的UI和导出数据到本地的功能,保证要有d盘,默认导出到d:/excel/下,感兴趣的可以修改代码使用Fyne提供的组件自定义保存路径。
安装
go get https://github.com/AyumiLumi/BliveDataExportToExcel
功能
Home页面
输入主播房间号,输入你的Cookie,点击start按钮即可开始监听记录直播事件,点击取消或者关闭程序,会自动把程序运行期间的直播事件写入以时间+主播名为文件名的excel文件中,点击UI上的数据行,即可复制到系统粘贴板,直播事件做了如下图的分类
https://github.com/AyumiLumi/BliveDataExportToExcel/blob/main/image-20241126155655012.png
代码示例
package main
import (
"context"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
"github.com/AyumiLumi/BliveDataExportToExcel/export"
"strconv"
"time"
)
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("看看你的")
// 输入框
roomIdEntry := widget.NewEntry()
roomIdEntry.SetPlaceHolder("主播直播房间号")
cookieEntry := widget.NewMultiLineEntry()
cookieEntry.SetPlaceHolder("你的登录 Cookie")
// 状态标签
statusLabel := widget.NewLabel("准备中...")
// 消息存储与显示
messages := make([]string, 0, 10000) // 最大存储 10000 条消息
messageList := widget.NewList(
func() int {
return len(messages) // 返回消息数量
},
func() fyne.CanvasObject {
return widget.NewLabel("") // 创建一个 Label
},
func(id widget.ListItemID, item fyne.CanvasObject) {
item.(*widget.Label).SetText(messages[id])
},
)
// 自动滚动
scrollContainer := container.NewVScroll(messageList)
scrollContainer.SetMinSize(fyne.NewSize(400, 600)) // 设置滚动容器大小
// 消息追加函数
appendMessage := func(msg string) {
if len(messages) >= 10000 { // 超过 1000 条时删除最旧的一条
messages = messages[:len(messages)-1]
}
messages = append([]string{msg}, messages...) // 将新消息加到顶部
// 延迟调用 ScrollToTop 以确保刷新完成后滚动
go func() {
// 延迟触发滚动到底部
time.Sleep(60 * time.Millisecond)
scrollContainer.ScrollToBottom() // 自动滚动到底部
}()
}
// 控制按钮
var cancel context.CancelFunc
// 先声明 startButton
startButton := widget.NewButton("Start", nil)
// 设置 startButton 的功能
startButton.OnTapped = func() {
roomId := roomIdEntry.Text
cookie := cookieEntry.Text
id, _ := strconv.Atoi(roomId)
if roomId == "" || cookie == "" {
statusLabel.SetText("请填写房间号和登录 Cookie,没有Cookie将无法完整显示信息!")
//return
}
// 开始任务
statusLabel.SetText("任务进行中...")
startButton.Disable()
// 创建上下文
ctx, cancelFunc := context.WithCancel(context.Background())
cancel = cancelFunc
eventChan := make(chan string)
cancelChan := make(chan struct{})
go func() {
export.ExportExcel(ctx, id, cookie, eventChan, cancelChan)
}()
go func() {
for {
select {
case msg := <-eventChan:
appendMessage(msg) // 新消息加入滚动列表
messageList.Refresh() // 刷新列表
case <-cancelChan:
statusLabel.SetText("任务已完成") // 更新按钮状态
startButton.Enable()
return
}
}
}()
}
// Cancel按钮
cancelButton := widget.NewButton("Cancel", func() {
if cancel != nil {
cancel() // 停止监听
statusLabel.SetText("取消中,保存文件...") // 更新状态
}
})
// 版权声明
copyrightLabel := widget.NewLabel("© 2024 By 滨崎步的水钻麦克风. All rights reserved.")
copyrightContainer := container.NewCenter(copyrightLabel) // 使用 Center 来居中显示
// 设置窗口关闭时保存文件
myWindow.SetCloseIntercept(func() {
if cancel != nil {
cancel() // 取消监听
statusLabel.SetText("保存文件中...") // 更新状态
// 执行保存文件的操作
// You might need to replace this with your actual save logic
// Example: export.ExportExcel(ctx, id, cookie, eventChan, cancelChan)
}
myWindow.Close() // 关闭窗口
})
// 居中显示按钮并加入间隔
buttonsContainer := container.NewCenter(
container.NewHBox(
startButton,
cancelButton,
),
)
// 布局
content := container.NewVBox(
widget.NewLabel("房间号"),
roomIdEntry,
widget.NewLabel("登录 Cookie"),
cookieEntry,
statusLabel, // 按钮状态
scrollContainer, // 消息滚动列表
buttonsContainer,
copyrightContainer, // 版权声明
)
myWindow.SetContent(content)
myWindow.Resize(fyne.NewSize(500, 700))
myWindow.ShowAndRun()
}
b站的弹幕消息数据样例
{
cmd: "DANMU_MSG",
dm_v2: "",
info: [
[
0,
1,
25,
5816798,
1735119251294,
1244493633,
0,
"d1b9df36",
0,
0,
0,
"",
1,
{
bulge_display: 1,
emoticon_unique: "room_23945626_3367",
height: 162,
in_player_area: 1,
is_dynamic: 0,
url: "http://i0.hdslb.com/bfs/live/953617cc7ff461f52c33a8daf4b35f956e8834e7.png",
width: 162,
},
"{}",
{
extra:
'{"send_from_me":false,"mode":0,"color":5816798,"dm_type":1,"font_size":25,"player_mode":1,"show_player_type":0,"content":"狂","user_hash":"3518619446","emoticon_unique":"room_23945626_3367","bulge_display":1,"recommend_score":0,"main_state_dm_color":"","objective_state_dm_color":"","direction":0,"pk_direction":0,"quartet_direction":0,"anniversary_crowd":0,"yeah_space_type":"","yeah_space_url":"","jump_to_url":"","space_type":"","space_url":"","animation":{},"emots":null,"is_audited":false,"id_str":"4a59e96b8375d8f36def9dab60676bd19334","icon":null,"show_reply":true,"reply_mid":0,"reply_uname":"","reply_uname_color":"","reply_is_mystery":false,"reply_type_enum":0,"hit_combo":0,"esports_jump_url":""}',
mode: 0,
show_player_type: 0,
user: {
base: {
face: "https://i0.hdslb.com/bfs/face/ce02d62eb1fa99f625ab7c41ae5b66a3c9743430.webp",
is_mystery: false,
name: "滨崎步的水钻麦克风",
name_color: 0,
name_color_str: "",
official_info: { desc: "", role: 0, title: "", type: -1 },
origin_info: {
face: "https://i0.hdslb.com/bfs/face/ce02d62eb1fa99f625ab7c41ae5b66a3c9743430.webp",
name: "滨崎步的水钻麦克风",
},
risk_ctrl_info: null,
},
guard: null,
guard_leader: { is_guard_leader: false },
medal: {
color: 12478086,
color_border: 12478086,
color_end: 12478086,
color_start: 12478086,
guard_icon: "",
guard_level: 0,
honor_icon: "",
id: 541356,
is_light: 1,
level: 15,
name: "黯灭头",
ruid: 1855519979,
score: 76610,
typ: 0,
user_receive_count: 0,
v2_medal_color_border: "#C85DC499",
v2_medal_color_end: "#C85DC499",
v2_medal_color_level: "#59005699",
v2_medal_color_start: "#C85DC499",
v2_medal_color_text: "#FFFFFFFF",
},
title: { old_title_css_id: "", title_css_id: "" },
uhead_frame: null,
uid: 189194391,
wealth: null,
},
},
{ activity_identity: "", activity_source: 0, not_show: 0 },
0,
],
"狂",
[189194391, "滨崎步的水钻麦克风", 0, 0, 0, 10000, 1, ""],
[
15,
"黯灭头",
"dodo_Official",
23945626,
12478086,
"",
0,
12478086,
12478086,
12478086,
0,
1,
1855519979,
],
[21, 0, 5805790, "\u003e50000", 0],
["", ""],
0,
0,
null,
{ ct: "96156738", ts: 1735119251 },
0,
0,
null,
null,
0,
484,
[34],
null,
],
};
# Packages
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author