@@ -3,38 +3,56 @@ package bilibili
3
3
4
4
import (
5
5
"bytes"
6
+ "crypto/md5"
7
+ "encoding/hex"
6
8
"encoding/json"
7
9
"fmt"
8
10
"net/http"
11
+ "net/url"
12
+ "path/filepath"
13
+ "sort"
9
14
"strconv"
15
+ "strings"
10
16
"time"
11
17
12
- "github.com/pkg/errors"
13
- "github.com/tidwall/gjson"
14
- zero "github.com/wdvxdr1123/ZeroBot"
15
- "github.com/wdvxdr1123/ZeroBot/message"
16
-
17
18
bz "github.com/FloatTech/AnimeAPI/bilibili"
18
19
"github.com/FloatTech/floatbox/binary"
19
20
"github.com/FloatTech/floatbox/web"
20
21
ctrl "github.com/FloatTech/zbpctrl"
21
22
"github.com/FloatTech/zbputils/control"
22
23
"github.com/FloatTech/zbputils/img/text"
24
+ "github.com/RomiChan/syncx"
25
+ "github.com/pkg/errors"
26
+ "github.com/tidwall/gjson"
27
+ zero "github.com/wdvxdr1123/ZeroBot"
28
+ "github.com/wdvxdr1123/ZeroBot/message"
29
+ "github.com/wdvxdr1123/ZeroBot/utils/helper"
23
30
)
24
31
25
32
const (
26
33
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
27
- referer = "https://www.bilibili.com/"
28
- infoURL = "https://api.bilibili.com/x/space/acc/info?mid=%v"
34
+ referer = "https://space.bilibili.com/%v"
35
+ infoURL = "https://api.bilibili.com/x/space/wbi/acc/info?mid=%v&token=&platform=web&web_location=1550101"
36
+ navURL = "https://api.bilibili.com/x/web-interface/nav"
29
37
)
30
38
31
39
// bdb bilibili推送数据库
32
40
var bdb * bilibilipushdb
33
41
34
42
var (
35
- lastTime = map [int64 ]int64 {}
36
- liveStatus = map [int64 ]int {}
37
- upMap = map [int64 ]string {}
43
+ lastTime = map [int64 ]int64 {}
44
+ liveStatus = map [int64 ]int {}
45
+ upMap = map [int64 ]string {}
46
+ mixinKeyEncTab = [... ]int {
47
+ 46 , 47 , 18 , 2 , 53 , 8 , 23 , 32 , 15 , 50 , 10 , 31 , 58 , 3 , 45 , 35 , 27 , 43 , 5 , 49 ,
48
+ 33 , 9 , 42 , 19 , 29 , 28 , 14 , 39 , 12 , 38 , 41 , 13 , 37 , 48 , 7 , 16 , 24 , 55 , 40 ,
49
+ 61 , 26 , 17 , 0 , 1 , 60 , 51 , 30 , 4 , 22 , 25 , 54 , 21 , 56 , 59 , 6 , 63 , 57 , 62 , 11 ,
50
+ 36 , 20 , 34 , 44 , 52 ,
51
+ }
52
+ cache syncx.Map [string , string ]
53
+ lastUpdateTime time.Time
54
+
55
+ replacements = [... ]string {"!" , "'" , "(" , ")" , "*" }
38
56
)
39
57
40
58
func init () {
@@ -60,7 +78,7 @@ func init() {
60
78
en .OnRegex (`^添加[B|b]站订阅\s?(.{1,25})$` , zero .UserOrGrpAdmin , getPara ).SetBlock (true ).Handle (func (ctx * zero.Ctx ) {
61
79
buid , _ := strconv .ParseInt (ctx .State ["uid" ].(string ), 10 , 64 )
62
80
name , err := getName (buid )
63
- if err != nil {
81
+ if err != nil || name == "" {
64
82
ctx .SendChain (message .Text ("ERROR: " , err ))
65
83
return
66
84
}
@@ -175,27 +193,17 @@ func init() {
175
193
func getName (buid int64 ) (name string , err error ) {
176
194
var ok bool
177
195
if name , ok = upMap [buid ]; ! ok {
178
- var data []byte
179
- data , err = web .RequestDataWithHeaders (web .NewDefaultClient (), fmt .Sprintf (infoURL , buid ), "GET" , func (r * http.Request ) error {
180
- r .Header .Set ("refer" , referer )
181
- r .Header .Set ("user-agent" , ua )
182
- cookie := ""
183
- if cfg != nil {
184
- cookie , err = cfg .Load ()
185
- if err != nil {
186
- return err
187
- }
188
- }
189
- r .Header .Set ("cookie" , cookie )
196
+ data , err := web .RequestDataWithHeaders (web .NewDefaultClient (), signURL (fmt .Sprintf (infoURL , buid )), "GET" , func (r * http.Request ) error {
197
+ r .Header .Set ("User-Agent" , ua )
190
198
return nil
191
199
}, nil )
192
200
if err != nil {
193
- return
201
+ return "" , err
194
202
}
195
203
status := int (gjson .Get (binary .BytesToString (data ), "code" ).Int ())
196
204
if status != 0 {
197
205
err = errors .New (gjson .Get (binary .BytesToString (data ), "message" ).String ())
198
- return
206
+ return "" , err
199
207
}
200
208
name = gjson .Get (binary .BytesToString (data ), "data.name" ).String ()
201
209
bdb .insertBilibiliUp (buid , name )
@@ -204,6 +212,103 @@ func getName(buid int64) (name string, err error) {
204
212
return
205
213
}
206
214
215
+ func getMixinKey (orig string ) string {
216
+ var str strings.Builder
217
+ t := 0
218
+ for _ , v := range mixinKeyEncTab {
219
+ if v < len (orig ) {
220
+ str .WriteByte (orig [v ])
221
+ t ++
222
+ }
223
+ if t > 31 {
224
+ break
225
+ }
226
+ }
227
+ return str .String ()
228
+ }
229
+
230
+ func wbiSign (params map [string ]string , imgKey string , subKey string ) map [string ]string {
231
+ mixinKey := getMixinKey (imgKey + subKey )
232
+ currTime := strconv .FormatInt (time .Now ().Unix (), 10 )
233
+ params ["wts" ] = currTime
234
+ // Sort keys
235
+ keys := make ([]string , 0 , len (params ))
236
+ for k , v := range params {
237
+ keys = append (keys , k )
238
+ for _ , old := range replacements {
239
+ v = strings .ReplaceAll (v , old , "" )
240
+ }
241
+ params [k ] = v
242
+ }
243
+ sort .Strings (keys )
244
+ h := md5 .New ()
245
+ for k , v := range keys {
246
+ h .Write ([]byte (v ))
247
+ h .Write ([]byte {'=' })
248
+ h .Write ([]byte (params [v ]))
249
+ if k < len (keys )- 1 {
250
+ h .Write ([]byte {'&' })
251
+ }
252
+ }
253
+ h .Write ([]byte (mixinKey ))
254
+ params ["w_rid" ] = hex .EncodeToString (h .Sum (make ([]byte , 0 , md5 .Size )))
255
+ return params
256
+ }
257
+
258
+ func getWbiKeysCached () (string , string ) {
259
+ if time .Since (lastUpdateTime ).Minutes () > 10 {
260
+ imgKey , subKey := getWbiKeys ()
261
+ cache .Store ("imgKey" , imgKey )
262
+ cache .Store ("subKey" , subKey )
263
+ lastUpdateTime = time .Now ()
264
+ return imgKey , subKey
265
+ }
266
+ imgKeyI , _ := cache .Load ("imgKey" )
267
+ subKeyI , _ := cache .Load ("subKey" )
268
+ return imgKeyI , subKeyI
269
+ }
270
+
271
+ func getWbiKeys () (string , string ) {
272
+ data , _ := web .RequestDataWithHeaders (web .NewDefaultClient (), navURL , "GET" , func (r * http.Request ) error {
273
+ if cfg != nil {
274
+ cookie , err := cfg .Load ()
275
+ if err == nil {
276
+ r .Header .Set ("cookie" , cookie )
277
+ return nil
278
+ }
279
+ return err
280
+ }
281
+ return errors .New ("未配置-cookie" )
282
+ }, nil )
283
+ json := helper .BytesToString (data )
284
+ imgURL := gjson .Get (json , "data.wbi_img.img_url" ).String ()
285
+ subURL := gjson .Get (json , "data.wbi_img.sub_url" ).String ()
286
+ imgKey := imgURL [strings .LastIndex (imgURL , "/" )+ 1 :]
287
+ imgKey = strings .TrimSuffix (imgKey , filepath .Ext (imgKey ))
288
+ subKey := subURL [strings .LastIndex (subURL , "/" )+ 1 :]
289
+ subKey = strings .TrimSuffix (subKey , filepath .Ext (subKey ))
290
+ return imgKey , subKey
291
+ }
292
+
293
+ func signURL (urlStr string ) string {
294
+ urlObj , _ := url .Parse (urlStr )
295
+ imgKey , subKey := getWbiKeysCached ()
296
+ query := urlObj .Query ()
297
+ params := map [string ]string {}
298
+ for k , v := range query {
299
+ if len (v ) > 0 {
300
+ params [k ] = v [0 ]
301
+ }
302
+ }
303
+ newParams := wbiSign (params , imgKey , subKey )
304
+ for k , v := range newParams {
305
+ query .Set (k , v )
306
+ }
307
+ urlObj .RawQuery = query .Encode ()
308
+ newURL := urlObj .String ()
309
+ return newURL
310
+ }
311
+
207
312
// subscribe 订阅
208
313
func subscribe (buid , groupid int64 ) (err error ) {
209
314
bpMap := map [string ]any {
@@ -276,7 +381,7 @@ func sendDynamic(ctx *zero.Ctx) error {
276
381
return err
277
382
}
278
383
if len (cardList ) == 0 {
279
- return errors . Errorf ( "%v的历史动态数为0" , buid )
384
+ return nil
280
385
}
281
386
t , ok := lastTime [buid ]
282
387
// 第一次先记录时间,啥也不做
0 commit comments