Skip to content

MatchaCake/bilibili_dm_lib

Repository files navigation

bilibili_dm_lib

Go library for subscribing to and sending Bilibili live room danmaku (弹幕) via WebSocket and HTTP API.

Features

  • Pub/Sub API — typed callbacks (OnDanmaku, OnGift, etc.) and channel-based subscription
  • Send danmaku — send messages via Client.SendDanmaku or standalone Sender
  • Auto-split — long messages split into chunks with rate limiting
  • Multiple rooms — subscribe to many rooms with a single client
  • Auto-reconnect — exponential backoff on disconnect
  • Brotli + Zlib — handles all Bilibili compression formats
  • Thread-safe — register handlers and send from any goroutine
  • Cookie support — optional authenticated access for richer data
  • Clean shutdown — context cancellation propagates everywhere

Install

go get github.com/MatchaCake/bilibili_dm_lib

Quick Start

Callback-based

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"

    dm "github.com/MatchaCake/bilibili_dm_lib"
)

func main() {
    client := dm.NewClient(
        dm.WithRoomID(510), // short room IDs are resolved automatically
    )

    client.OnDanmaku(func(d *dm.Danmaku) {
        fmt.Printf("[弹幕] %s: %s\n", d.Sender, d.Content)
    })

    client.OnGift(func(g *dm.Gift) {
        fmt.Printf("[礼物] %s %s %s x%d\n", g.User, g.Action, g.GiftName, g.Num)
    })

    client.OnSuperChat(func(sc *dm.SuperChat) {
        fmt.Printf("[SC ¥%d] %s: %s\n", sc.Price, sc.User, sc.Message)
    })

    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
    defer stop()

    client.Start(ctx)
}

Channel-based

client := dm.NewClient(dm.WithRoomID(21452505))
events := client.Subscribe()

go client.Start(ctx)

for ev := range events {
    switch d := ev.Data.(type) {
    case *dm.Danmaku:
        fmt.Printf("%s: %s\n", d.Sender, d.Content)
    case *dm.Gift:
        fmt.Printf("Gift: %s x%d from %s\n", d.GiftName, d.Num, d.User)
    }
}

Multiple Rooms

client := dm.NewClient(
    dm.WithRoomID(510),
    dm.WithRoomID(21452505),
)

// Or add rooms dynamically after Start:
client.AddRoom(12345)
client.RemoveRoom(510)

Authenticated (with cookies)

Providing cookies enables richer danmaku data (full medal info, etc.):

client := dm.NewClient(
    dm.WithRoomID(510),
    dm.WithCookie("your_SESSDATA", "your_bili_jct"),
)

Sending Danmaku

Via Client

client := dm.NewClient(
    dm.WithRoomID(510),
    dm.WithCookie("your_SESSDATA", "your_bili_jct"),
)

// Send after the client is started.
go func() {
    ctx := context.Background()
    err := client.SendDanmaku(ctx, 510, "Hello from Go!")
    if err != nil {
        log.Println("send failed:", err)
    }
}()

client.Start(ctx)

Standalone Sender

Use NewSender when you only need to send without subscribing:

sender := dm.NewSender(
    dm.WithSenderCookie("your_SESSDATA", "your_bili_jct"),
    dm.WithMaxLength(30), // UL20+ users can send up to 30 chars
    dm.WithCooldown(3 * time.Second),
)

ctx := context.Background()

// Send with default scroll mode.
err := sender.Send(ctx, 510, "Hello!")

// Send with specific display mode.
err = sender.SendWithMode(ctx, 510, "Pinned!", dm.ModeTop)

Long messages are automatically split into chunks and sent with rate-limiting pauses between each chunk.

Event Types

CMD Callback Struct Description
DANMU_MSG OnDanmaku Danmaku Chat messages
SEND_GIFT OnGift Gift Gift events
SUPER_CHAT_MESSAGE OnSuperChat SuperChat Super Chat messages
GUARD_BUY OnGuardBuy GuardBuy Captain/Admiral/Governor purchases
LIVE OnLive LiveEvent Room goes live
PREPARING OnPreparing LiveEvent Room goes offline
INTERACT_WORD OnInteractWord InteractWord Entry, follow, share
(any) OnRawEvent []byte Catch-all for unrecognised commands

Running the Example

go run ./cmd/example -room 510

With cookies:

go run ./cmd/example -room 510 -sessdata YOUR_SESSDATA -bili-jct YOUR_BILI_JCT

Architecture

Client (pub/sub hub + sender)
├── roomConn (room 510)     ← goroutine: connect → auth → read loop
│   ├── heartbeat goroutine ← sends heartbeat every 30s
│   └── auto-reconnect      ← exponential backoff on failure
├── roomConn (room 21452505)
│   └── ...
├── dispatch
│   ├── typed callbacks (OnDanmaku, OnGift, ...)
│   ├── raw event callback (OnRawEvent)
│   └── channel subscribers (Subscribe)
└── Sender (lazy init)      ← SendDanmaku → HTTP POST /msg/send
    ├── auto-split long messages
    └── per-room rate limiting

Protocol

This library implements the Bilibili live WebSocket danmaku protocol:

  1. Resolve short room ID → real room ID via HTTP API
  2. Fetch WSS server host + auth token via HTTP API
  3. Connect to wss://{host}:{port}/sub
  4. Send auth packet (16-byte header + JSON body, protover=3)
  5. Send heartbeat every 30 seconds
  6. Receive command packets (raw JSON, Brotli, or Zlib compressed)

Packets use a 16-byte big-endian header:

  • [0:4] Total size, [4:6] Header size (16), [6:8] Protocol version, [8:12] Operation type, [12:16] Sequence

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages