This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ssdomei232/goodBaby/internal/meta"
|
||||
@@ -15,7 +14,7 @@ func (v *BilibiliAccountConfigValidator) GetType() string {
|
||||
}
|
||||
|
||||
func (v *BilibiliAccountConfigValidator) Validate(config string) error {
|
||||
cfg, err := parseAccount(config)
|
||||
cfg, err := ParseAccountConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -29,7 +28,7 @@ func (v *BilibiliAccountConfigValidator) Validate(config string) error {
|
||||
|
||||
// Test 用 cookie 拉一次账号信息,验证 cookie 是否还有效
|
||||
func (v *BilibiliAccountConfigValidator) Test(config string) error {
|
||||
cfg, err := parseAccount(config)
|
||||
cfg, err := ParseAccountConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -64,11 +63,3 @@ func (v *BilibiliAccountConfigValidator) Meta() meta.AccountMeta {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func parseAccount(config string) (*BiliAccount, error) {
|
||||
var cfg BiliAccount
|
||||
if err := json.Unmarshal([]byte(config), &cfg); err != nil {
|
||||
return nil, fmt.Errorf("解析B站账号配置失败: %v", err)
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
@@ -6,32 +6,22 @@ import (
|
||||
|
||||
"github.com/CuteReimu/bilibili/v2"
|
||||
"github.com/ssdomei232/goodBaby/internal/retry"
|
||||
"github.com/ssdomei232/goodBaby/model"
|
||||
)
|
||||
|
||||
// SendBiliDynamicMsg 在 Bilibili 动态发送消息
|
||||
// SendDynamic 用给定账号发送一条 B 站动态
|
||||
//
|
||||
// 暂时没有处理 429 和 403 的区别对待
|
||||
func SendBiliDynamicMsg(ctx context.Context, rule *model.Rule) error {
|
||||
biliClient, err := getBiliClient(rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取B站客户端失败: %w", err)
|
||||
}
|
||||
|
||||
biliDynamicConfig, err := getBiliDynamicConfig(rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取B站动态配置失败: %w", err)
|
||||
}
|
||||
|
||||
dynamicParams := bilibili.CreateDynamicParam{
|
||||
func SendDynamic(ctx context.Context, account *BiliAccount, config *BiliDynamicConfig) error {
|
||||
client := newClient(account.RawCookies)
|
||||
params := bilibili.CreateDynamicParam{
|
||||
DynamicId: 0,
|
||||
Type: 4,
|
||||
Rid: 0,
|
||||
Content: biliDynamicConfig.Msg,
|
||||
Content: config.Msg,
|
||||
}
|
||||
|
||||
if err := retry.Do(ctx, func() error {
|
||||
_, err := biliClient.CreateDynamic(dynamicParams)
|
||||
_, err := client.CreateDynamic(params)
|
||||
return err
|
||||
}); err != nil {
|
||||
return fmt.Errorf("发送B站动态失败: %w", err)
|
||||
|
||||
@@ -2,54 +2,34 @@ package bilibili
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/CuteReimu/bilibili/v2"
|
||||
"github.com/ssdomei232/goodBaby/internal/retry"
|
||||
"github.com/ssdomei232/goodBaby/model"
|
||||
)
|
||||
|
||||
// 私信消息类型:1 为文字
|
||||
// privateMsgTypeText 私信消息类型:1 为文字
|
||||
const privateMsgTypeText = 1
|
||||
|
||||
// SendBiliPrivateMessage 向配置中的每个 UID 发送一条 B 站私信
|
||||
func SendBiliPrivateMessage(ctx context.Context, rule *model.Rule) error {
|
||||
client, err := getBiliClient(rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取B站客户端失败: %w", err)
|
||||
}
|
||||
// SendPrivateMessage 用给定账号向配置中的每个 UID 发送一条 B 站私信
|
||||
//
|
||||
// 每个接收者单独重试、互不阻塞,最后汇总失败信息交给上层记录。
|
||||
func SendPrivateMessage(ctx context.Context, account *BiliAccount, config *BiliPrivateMessageConfig) error {
|
||||
client := newClient(account.RawCookies)
|
||||
|
||||
config, err := getPrivateMessageConfig(rule)
|
||||
// 发私信需要带上自己的 UID,从账号信息里取
|
||||
selfUID, err := fetchSelfUID(ctx, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发私信需要带上自己的 UID,从账号信息里取
|
||||
account, err := client.GetAccountInformation()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取B站账号信息失败(cookie 可能已失效): %w", err)
|
||||
}
|
||||
if account == nil || account.Mid == 0 {
|
||||
return fmt.Errorf("B站 cookie 无效或已过期")
|
||||
}
|
||||
|
||||
var fails []string
|
||||
for _, uid := range config.ReceiverUids {
|
||||
err := retry.Do(ctx, func() error {
|
||||
_, err := client.SendPrivateMessage(bilibili.SendPrivateMessageParam{
|
||||
SenderUid: account.Mid,
|
||||
ReceiverId: int(uid),
|
||||
ReceiverType: 1,
|
||||
MsgType: privateMsgTypeText,
|
||||
Timestamp: int(time.Now().Unix()),
|
||||
Content: buildTextContent(config.Msg),
|
||||
})
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
if err := retry.Do(ctx, func() error {
|
||||
return sendPrivateMessage(client, selfUID, uid, config.Msg)
|
||||
}); err != nil {
|
||||
fails = append(fails, fmt.Sprintf("UID %d: %v", uid, err))
|
||||
}
|
||||
}
|
||||
@@ -61,20 +41,34 @@ func SendBiliPrivateMessage(ctx context.Context, rule *model.Rule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildTextContent 文字私信的 content 是一个 JSON 字符串 {"content":"..."}
|
||||
func buildTextContent(msg string) string {
|
||||
payload, err := json.Marshal(map[string]string{"content": msg})
|
||||
if err != nil {
|
||||
// msg 是普通字符串,序列化不会失败;兜底也返回合法 JSON
|
||||
return `{"content":""}`
|
||||
// fetchSelfUID 取当前账号的 UID,私信接口需要它
|
||||
func fetchSelfUID(ctx context.Context, client *bilibili.Client) (int, error) {
|
||||
var selfUID int
|
||||
if err := retry.Do(ctx, func() error {
|
||||
info, err := client.GetAccountInformation()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info == nil || info.Mid == 0 {
|
||||
return retry.Permanent(fmt.Errorf("B站 cookie 无效或已过期"))
|
||||
}
|
||||
selfUID = info.Mid
|
||||
return nil
|
||||
}); err != nil {
|
||||
return 0, fmt.Errorf("获取B站账号信息失败: %w", err)
|
||||
}
|
||||
return string(payload)
|
||||
return selfUID, nil
|
||||
}
|
||||
|
||||
func getPrivateMessageConfig(rule *model.Rule) (*BiliPrivateMessageConfig, error) {
|
||||
var config BiliPrivateMessageConfig
|
||||
if err := json.Unmarshal([]byte(rule.ConfigJson), &config); err != nil {
|
||||
return nil, fmt.Errorf("解析B站私信规则配置失败: %w", err)
|
||||
}
|
||||
return &config, nil
|
||||
// sendPrivateMessage 发送一条私信
|
||||
func sendPrivateMessage(client *bilibili.Client, senderUID int, receiverUID int64, msg string) error {
|
||||
_, err := client.SendPrivateMessage(bilibili.SendPrivateMessageParam{
|
||||
SenderUid: senderUID,
|
||||
ReceiverId: int(receiverUID),
|
||||
ReceiverType: 1,
|
||||
MsgType: privateMsgTypeText,
|
||||
Timestamp: int(time.Now().Unix()),
|
||||
Content: buildTextContent(msg),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ssdomei232/goodBaby/internal/meta"
|
||||
@@ -15,9 +14,9 @@ func (v *BilibiliDynamicRuleValidator) GetType() string {
|
||||
}
|
||||
|
||||
func (v *BilibiliDynamicRuleValidator) Validate(configJSON string) error {
|
||||
var config BiliDynamicConfig
|
||||
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
|
||||
return fmt.Errorf("解析B站动态规则配置失败: %v", err)
|
||||
config, err := ParseDynamicConfig(configJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.Msg == "" {
|
||||
@@ -39,9 +38,9 @@ func (v *BilibiliPrivateMessageRuleValidator) GetType() string {
|
||||
}
|
||||
|
||||
func (v *BilibiliPrivateMessageRuleValidator) Validate(configJSON string) error {
|
||||
var config BiliPrivateMessageConfig
|
||||
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
|
||||
return fmt.Errorf("解析B站私信规则配置失败: %v", err)
|
||||
config, err := ParsePrivateMessageConfig(configJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.Msg == "" {
|
||||
@@ -77,7 +76,7 @@ func (v *BilibiliPrivateMessageRuleValidator) Meta() meta.RuleMeta {
|
||||
Placeholder: "2",
|
||||
Help: "对方空间地址 space.bilibili.com/ 后面的那串数字",
|
||||
},
|
||||
{Key: "msg", Label: "私信内容", Type: meta.FieldTextarea, Required: true},
|
||||
{Key: "msg", Label: "私信内容", Type: meta.FieldTextarea, Required: true, GatewayMessage: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -91,11 +90,12 @@ func (v *BilibiliDynamicRuleValidator) Meta() meta.RuleMeta {
|
||||
AccountType: AccountType,
|
||||
Fields: []meta.Field{
|
||||
{
|
||||
Key: "msg",
|
||||
Label: "动态内容",
|
||||
Type: meta.FieldTextarea,
|
||||
Required: true,
|
||||
Placeholder: "要发送的动态正文",
|
||||
Key: "msg",
|
||||
Label: "动态内容",
|
||||
Type: meta.FieldTextarea,
|
||||
Required: true,
|
||||
GatewayMessage: true,
|
||||
Placeholder: "要发送的动态正文",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package bilibili
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/ssdomei232/goodBaby/model"
|
||||
)
|
||||
@@ -14,10 +13,18 @@ func (e *BilibiliDynamicExecutor) GetType() string {
|
||||
return RuleTypeDynamic
|
||||
}
|
||||
|
||||
func (e *BilibiliDynamicExecutor) Execute(ctx context.Context, rule *model.Rule) error {
|
||||
log.Printf("执行B站动态规则: %s (ID: %d)", rule.Name, rule.ID)
|
||||
func (e *BilibiliDynamicExecutor) Execute(ctx context.Context, task *model.RuleTask) error {
|
||||
account, err := ParseAccountConfig(task.AccountConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SendBiliDynamicMsg(ctx, rule)
|
||||
config, err := ParseDynamicConfig(task.Rule.ConfigJson)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SendDynamic(ctx, account, config)
|
||||
}
|
||||
|
||||
// BilibiliPrivateMessageExecutor B站私信执行器
|
||||
@@ -27,8 +34,16 @@ func (e *BilibiliPrivateMessageExecutor) GetType() string {
|
||||
return RuleTypePrivateMessage
|
||||
}
|
||||
|
||||
func (e *BilibiliPrivateMessageExecutor) Execute(ctx context.Context, rule *model.Rule) error {
|
||||
log.Printf("执行B站私信规则: %s (ID: %d)", rule.Name, rule.ID)
|
||||
func (e *BilibiliPrivateMessageExecutor) Execute(ctx context.Context, task *model.RuleTask) error {
|
||||
account, err := ParseAccountConfig(task.AccountConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SendBiliPrivateMessage(ctx, rule)
|
||||
config, err := ParsePrivateMessageConfig(task.Rule.ConfigJson)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SendPrivateMessage(ctx, account, config)
|
||||
}
|
||||
|
||||
+40
-19
@@ -2,34 +2,55 @@ package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/CuteReimu/bilibili/v2"
|
||||
"github.com/ssdomei232/goodBaby/handler/db"
|
||||
"github.com/ssdomei232/goodBaby/model"
|
||||
)
|
||||
|
||||
// ParseAccountConfig 解析 B 站账号配置
|
||||
func ParseAccountConfig(config string) (*BiliAccount, error) {
|
||||
if config == "" {
|
||||
return nil, fmt.Errorf("解析B站账号配置失败: 规则没有关联账号")
|
||||
}
|
||||
|
||||
var account BiliAccount
|
||||
if err := json.Unmarshal([]byte(config), &account); err != nil {
|
||||
return nil, fmt.Errorf("解析B站账号配置失败: %v", err)
|
||||
}
|
||||
return &account, nil
|
||||
}
|
||||
|
||||
// ParseDynamicConfig 解析 B 站动态规则配置
|
||||
func ParseDynamicConfig(configJSON string) (*BiliDynamicConfig, error) {
|
||||
var config BiliDynamicConfig
|
||||
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
|
||||
return nil, fmt.Errorf("解析B站动态规则配置失败: %v", err)
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// ParsePrivateMessageConfig 解析 B 站私信规则配置
|
||||
func ParsePrivateMessageConfig(configJSON string) (*BiliPrivateMessageConfig, error) {
|
||||
var config BiliPrivateMessageConfig
|
||||
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
|
||||
return nil, fmt.Errorf("解析B站私信规则配置失败: %v", err)
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// newClient 按账号配置创建 B 站客户端
|
||||
func newClient(rawCookies string) *bilibili.Client {
|
||||
client := bilibili.New()
|
||||
client.SetRawCookies(rawCookies)
|
||||
return client
|
||||
}
|
||||
|
||||
// 获取 Bilibili Client
|
||||
func getBiliClient(rule *model.Rule) (*bilibili.Client, error) {
|
||||
var accountConfig BiliAccount
|
||||
if err := db.LoadAccountConfig(rule.AccountID, &accountConfig); err != nil {
|
||||
return nil, err
|
||||
// buildTextContent 文字私信的 content 是一个 JSON 字符串 {"content":"..."}
|
||||
func buildTextContent(msg string) string {
|
||||
payload, err := json.Marshal(map[string]string{"content": msg})
|
||||
if err != nil {
|
||||
// msg 是普通字符串,序列化不会失败;兜底也返回合法 JSON
|
||||
return `{"content":""}`
|
||||
}
|
||||
|
||||
return newClient(accountConfig.RawCookies), nil
|
||||
}
|
||||
|
||||
// 获取 Bilibili Dynamic Config
|
||||
func getBiliDynamicConfig(rule *model.Rule) (*BiliDynamicConfig, error) {
|
||||
var biliDynamicConfig BiliDynamicConfig
|
||||
if err := json.Unmarshal([]byte(rule.ConfigJson), &biliDynamicConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &biliDynamicConfig, nil
|
||||
return string(payload)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user