import{_ as t,c as y,b as s,a as o,e as a,d as n,w as p,r as D,o as i}from"./app-Dgsdh8A6.js";const C={};function d(u,l){const e=D("RouteLink"),c=D("CodeGroupItem"),r=D("CodeGroup");return i(),y("div",null,[l[32]||(l[32]=s("h1",{id:"wbi-签名",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#wbi-签名"},[s("span",null,"WBI 签名")])],-1)),s("p",null,[l[1]||(l[1]=n("自 2023 年 3 月起,Bilibili Web 端部分接口开始采用 WBI 签名鉴权,表现在 REST API 请求时在 Query param 中添加了 ")),l[2]||(l[2]=s("code",null,"w_rid",-1)),l[3]||(l[3]=n(" 和 ")),l[4]||(l[4]=s("code",null,"wts",-1)),l[5]||(l[5]=n(" 字段。WBI 签名鉴权独立于 ")),a(e,{to:"/docs/misc/sign/APP.html"},{default:p(()=>l[0]||(l[0]=[n("APP 鉴权")])),_:1,__:[0]}),l[6]||(l[6]=n(" 与其他 Cookie 鉴权,目前被认为是一种 Web 端风控手段。"))]),s("p",null,[l[8]||(l[8]=n("经持续观察,大部分查询性接口都已经或准备采用 WBI 签名鉴权,请求 WBI 签名鉴权接口时,若签名参数 ")),l[9]||(l[9]=s("code",null,"w_rid",-1)),l[10]||(l[10]=n(" 与时间戳 ")),l[11]||(l[11]=s("code",null,"wts",-1)),l[12]||(l[12]=n(" 缺失、错误,会返回 ")),a(e,{to:"/docs/misc/sign/v_voucher.html"},{default:p(()=>l[7]||(l[7]=[s("code",null,"v_voucher",-1)])),_:1,__:[7]}),l[13]||(l[13]=n(",如:"))]),l[33]||(l[33]=o('
{"code":0,"message":"0","ttl":1,"data":{"v_voucher":"voucher_******"}}

感谢 #631 的研究与逆向工程。

细节更新:#885

最新进展: #919

WBI 签名算法

',5)),s("ol",null,[s("li",null,[l[27]||(l[27]=s("p",null,[n("获取实时口令 "),s("code",null,"img_key"),n("、"),s("code",null,"sub_key")],-1)),s("p",null,[l[16]||(l[16]=n("从 ")),a(e,{to:"/docs/login/login_info.html#%E5%AF%BC%E8%88%AA%E6%A0%8F%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF"},{default:p(()=>l[14]||(l[14]=[n("nav 接口")])),_:1,__:[14]}),l[17]||(l[17]=n(" 中获取 ")),l[18]||(l[18]=s("code",null,"img_url",-1)),l[19]||(l[19]=n("、")),l[20]||(l[20]=s("code",null,"sub_url",-1)),l[21]||(l[21]=n(" 两个字段的参数。 或从 ")),a(e,{to:"/docs/misc/sign/bili_ticket.html#%E6%8E%A5%E5%8F%A3"},{default:p(()=>l[15]||(l[15]=[n("bili_ticket 接口")])),_:1,__:[15]}),l[22]||(l[22]=n(" 中获取 ")),l[23]||(l[23]=s("code",null,"img",-1)),l[24]||(l[24]=n()),l[25]||(l[25]=s("code",null,"sub",-1)),l[26]||(l[26]=n(" 两个字段的参数。"))]),l[28]||(l[28]=o('

注:img_urlsub_url 两个字段的值看似为存于 BFS 中的 png 图片 url,实则只是经过伪装的实时 Token,故无需且不能试图访问这两个 url

{"code":-101,"message":"账号未登录","ttl":1,"data":{"isLogin":false,"wbi_img":{"img_url":"https://i0.hdslb.com/bfs/wbi/7cd084941338484aae1ad9425b84077c.png","sub_url":"https://i0.hdslb.com/bfs/wbi/4932caff0ff746eab6f01bf08b70ac45.png"}}}

截取其文件名,分别记为 img_keysub_key,如上述例子中的 7cd084941338484aae1ad9425b84077c4932caff0ff746eab6f01bf08b70ac45

img_keysub_key 全站统一使用,观测知应为每日更替,使用时建议做好缓存和刷新处理。

特别地,发现部分接口将 img_keysub_key 硬编码进 JavaScript 文件内,如搜索接口 https://s1.hdslb.com/bfs/static/laputa-search/client/assets/index.1ea39bea.js,暂不清楚原因及影响。 同时, 部分页面会在 SSR 的 __INITIAL_STATE__ 包含 wbiImgKeywbiSubKey, 具体可用性与区别尚不明确

',5))]),l[29]||(l[29]=o(`
  • 打乱重排实时口令获得 mixin_key

    把上一步获取到的 sub_key 拼接在 img_key 后面(下例记为 raw_wbi_key),遍历重排映射表 MIXIN_KEY_ENC_TAB,取出 raw_wbi_key 中对应位置的字符拼接得到新的字符串,截取前 32 位,即为 mixin_key

    重排映射表 MIXIN_KEY_ENC_TAB 长为 64,内容如下:

    const MIXIN_KEY_ENC_TAB: [u8; 64] = [
        46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
        33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
        61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
        36, 20, 34, 44, 52
    ]

    重排操作如下例:

     fn gen_mixin_key(raw_wbi_key: impl AsRef<[u8]>) -> String {
         const MIXIN_KEY_ENC_TAB: [u8; 64] = [
             46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42,
             19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60,
             51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52,
         ];
         let raw_wbi_key = raw_wbi_key.as_ref();
         let mut mixin_key = {
             let binding = MIXIN_KEY_ENC_TAB
                 .iter()
                 // 此步操作即遍历 MIXIN_KEY_ENC_TAB,取出 raw_wbi_key 中对应位置的字符
                 .map(|n| raw_wbi_key[*n as usize])
                 // 并收集进数组内
                 .collect::<Vec<u8>>();
             unsafe { String::from_utf8_unchecked(binding) }
         };
         let _ = mixin_key.split_off(32); // 截取前 32 位字符
         mixin_key
     }

    img_key -> 7cd084941338484aae1ad9425b84077csub_key -> 4932caff0ff746eab6f01bf08b70ac45 经过上述操作后得到 mixin_key -> ea1db124af3c7062474693fa704f4ff8

  • 计算签名(即 w_rid

    若下方内容为欲签名的原始请求参数(以 JavaScript Object 为例)

    {
      foo: '114',
      bar: '514',
      zab: 1919810
    }

    wts 字段的值应为当前以秒为单位的 Unix 时间戳,如 1702204169

    复制一份参数列表,添加 wts 参数,即:

    {
         foo: '114',
         bar: '514',
         zab: 1919810,
         wts: 1702204169
    }

    随后按键名升序排序后百分号编码 URL Query,拼接前面得到的 mixin_key,如 bar=514&foo=114&wts=1702204169&zab=1919810ea1db124af3c7062474693fa704f4ff8,计算其 MD5 即为 w_rid

    需要注意的是:如果参数值含中文或特殊字符等,编码字符字母应当大写 (部分库会错误编码为小写字母),空格应当编码为 %20(部分库按 application/x-www-form-urlencoded 约定编码为 +), 具体正确行为可参考 encodeURIComponent 函数

    例如:

    {
      foo: 'one one four',
      bar: '五一四',
      baz: 1919810
    }

    应该被编码为 bar=%E4%BA%94%E4%B8%80%E5%9B%9B&baz=1919810&foo=one%20one%20four

  • 向原始请求参数中添加 w_ridwts 字段

    将上一步得到的 w_rid 以及前面的 wts 追加到原始请求参数编码得到的 URL Query 后即可,目前看来无需对原始请求参数排序。

    如前例最终得到 bar=514&foo=114&zab=1919810&w_rid=8f6f2b5b3d485fe1886cec6a0be8c5d4&wts=1702204169

  • `,3))]),l[34]||(l[34]=o(`

    Demo

    PythonJavaScriptGolangC#JavaKotlinSwiftC++RustHaskell 语言编写的 Demo

    Python

    需要requests依赖

    from functools import reduce
    from hashlib import md5
    import urllib.parse
    import time
    import requests
    
    mixinKeyEncTab = [
        46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
        33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
        61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
        36, 20, 34, 44, 52
    ]
    
    def getMixinKey(orig: str):
        '对 imgKey 和 subKey 进行字符顺序打乱编码'
        return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32]
    
    def encWbi(params: dict, img_key: str, sub_key: str):
        '为请求参数进行 wbi 签名'
        mixin_key = getMixinKey(img_key + sub_key)
        curr_time = round(time.time())
        params['wts'] = curr_time                                   # 添加 wts 字段
        params = dict(sorted(params.items()))                       # 按照 key 重排参数
        # 过滤 value 中的 "!'()*" 字符
        params = {
            k : ''.join(filter(lambda chr: chr not in "!'()*", str(v)))
            for k, v 
            in params.items()
        }
        query = urllib.parse.urlencode(params)                      # 序列化参数
        wbi_sign = md5((query + mixin_key).encode()).hexdigest()    # 计算 w_rid
        params['w_rid'] = wbi_sign
        return params
    
    def getWbiKeys() -> tuple[str, str]:
        '获取最新的 img_key 和 sub_key'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
            'Referer': 'https://www.bilibili.com/'
        }
        resp = requests.get('https://api.bilibili.com/x/web-interface/nav', headers=headers)
        resp.raise_for_status()
        json_content = resp.json()
        img_url: str = json_content['data']['wbi_img']['img_url']
        sub_url: str = json_content['data']['wbi_img']['sub_url']
        img_key = img_url.rsplit('/', 1)[1].split('.')[0]
        sub_key = sub_url.rsplit('/', 1)[1].split('.')[0]
        return img_key, sub_key
    
    img_key, sub_key = getWbiKeys()
    
    signed_params = encWbi(
        params={
            'foo': '114',
            'bar': '514',
            'baz': 1919810
        },
        img_key=img_key,
        sub_key=sub_key
    )
    query = urllib.parse.urlencode(signed_params)
    print(signed_params)
    print(query)

    输出内容分别是进行 Wbi 签名的后参数的 key-Value 以及 url query 形式

    {'bar': '514', 'baz': '1919810', 'foo': '114', 'wts': '1702204169', 'w_rid': 'd3cbd2a2316089117134038bf4caf442'}
    bar=514&baz=1919810&foo=114&wts=1702204169&w_rid=d3cbd2a2316089117134038bf4caf442

    JavaScript

    需要 fetch(浏览器、NodeJS等环境自带)、md5 依赖

    `,9)),a(r,null,{default:p(()=>[a(c,{title:"JavaScript"},{default:p(()=>l[30]||(l[30]=[s("div",{class:"language-javascript line-numbers-mode","data-highlighter":"shiki","data-ext":"javascript",style:{"background-color":"#1E1E1E",color:"#D4D4D4"}},[s("pre",{class:"shiki dark-plus vp-code"},[s("code",{class:"language-javascript"},[s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}},"import"),s("span",{style:{color:"#9CDCFE"}}," md5"),s("span",{style:{color:"#C586C0"}}," from"),s("span",{style:{color:"#CE9178"}}," 'md5'")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"const"),s("span",{style:{color:"#4FC1FF"}}," mixinKeyEncTab"),s("span",{style:{color:"#D4D4D4"}}," = [")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 46"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"47"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"18"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"2"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"53"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"8"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"23"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"32"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"15"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"50"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"10"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"31"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"58"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"3"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"45"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"35"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"27"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"43"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"5"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"49"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 33"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"9"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"42"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"19"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"29"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"28"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"14"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"39"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"12"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"38"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"41"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"13"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"37"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"48"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"7"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"16"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"24"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"55"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"40"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 61"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"26"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"17"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"0"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"1"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"60"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"51"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"30"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"4"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"22"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"25"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"54"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"21"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"56"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"59"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"6"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"63"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"57"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"62"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"11"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 36"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"20"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"34"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"44"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"52")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"]")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},"// 对 imgKey 和 subKey 进行字符顺序打乱编码")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"const"),s("span",{style:{color:"#DCDCAA"}}," getMixinKey"),s("span",{style:{color:"#D4D4D4"}}," = ("),s("span",{style:{color:"#9CDCFE"}},"orig"),s("span",{style:{color:"#D4D4D4"}},") "),s("span",{style:{color:"#569CD6"}},"=>"),s("span",{style:{color:"#9CDCFE"}}," mixinKeyEncTab"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"map"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"n"),s("span",{style:{color:"#569CD6"}}," =>"),s("span",{style:{color:"#9CDCFE"}}," orig"),s("span",{style:{color:"#D4D4D4"}},"["),s("span",{style:{color:"#9CDCFE"}},"n"),s("span",{style:{color:"#D4D4D4"}},"])."),s("span",{style:{color:"#DCDCAA"}},"join"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"''"),s("span",{style:{color:"#D4D4D4"}},")."),s("span",{style:{color:"#DCDCAA"}},"slice"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#B5CEA8"}},"0"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"32"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},"// 为请求参数进行 wbi 签名")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"function"),s("span",{style:{color:"#DCDCAA"}}," encWbi"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"sub_key"),s("span",{style:{color:"#D4D4D4"}},") {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," mixin_key"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#DCDCAA"}},"getMixinKey"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#9CDCFE"}},"sub_key"),s("span",{style:{color:"#D4D4D4"}},"),")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," curr_time"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"Math"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"round"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"Date"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"now"),s("span",{style:{color:"#D4D4D4"}},"() / "),s("span",{style:{color:"#B5CEA8"}},"1000"),s("span",{style:{color:"#D4D4D4"}},"),")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," chr_filter"),s("span",{style:{color:"#D4D4D4"}}," ="),s("span",{style:{color:"#D16969"}}," /"),s("span",{style:{color:"#CE9178"}},"["),s("span",{style:{color:"#D16969"}},"!'()*"),s("span",{style:{color:"#CE9178"}},"]"),s("span",{style:{color:"#D16969"}},"/"),s("span",{style:{color:"#569CD6"}},"g")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," Object"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"assign"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},", { "),s("span",{style:{color:"#9CDCFE"}},"wts:"),s("span",{style:{color:"#9CDCFE"}}," curr_time"),s("span",{style:{color:"#D4D4D4"}}," }) "),s("span",{style:{color:"#6A9955"}},"// 添加 wts 字段")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}}," // 按照 key 重排参数")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," query"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"Object")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"keys"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"sort"),s("span",{style:{color:"#D4D4D4"}},"()")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"map"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#569CD6"}}," =>"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},` // 过滤 value 中的 "!'()*" 字符`)]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," value"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},"["),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#D4D4D4"}},"]."),s("span",{style:{color:"#DCDCAA"}},"toString"),s("span",{style:{color:"#D4D4D4"}},"()."),s("span",{style:{color:"#DCDCAA"}},"replace"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"chr_filter"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#CE9178"}},"''"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}}," return"),s("span",{style:{color:"#CE9178"}}," `"),s("span",{style:{color:"#569CD6"}},"${"),s("span",{style:{color:"#DCDCAA"}},"encodeURIComponent"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#D4D4D4"}},")"),s("span",{style:{color:"#569CD6"}},"}"),s("span",{style:{color:"#CE9178"}},"="),s("span",{style:{color:"#569CD6"}},"${"),s("span",{style:{color:"#DCDCAA"}},"encodeURIComponent"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"value"),s("span",{style:{color:"#D4D4D4"}},")"),s("span",{style:{color:"#569CD6"}},"}"),s("span",{style:{color:"#CE9178"}},"`")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," })")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"join"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'&'"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," wbi_sign"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#DCDCAA"}},"md5"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"query"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#9CDCFE"}},"mixin_key"),s("span",{style:{color:"#D4D4D4"}},") "),s("span",{style:{color:"#6A9955"}},"// 计算 w_rid")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}}," return"),s("span",{style:{color:"#9CDCFE"}}," query"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#CE9178"}},"'&w_rid='"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#9CDCFE"}},"wbi_sign")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"}")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},"// 获取最新的 img_key 和 sub_key")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"async"),s("span",{style:{color:"#569CD6"}}," function"),s("span",{style:{color:"#DCDCAA"}}," getWbiKeys"),s("span",{style:{color:"#D4D4D4"}},"() {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," res"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#C586C0"}},"await"),s("span",{style:{color:"#DCDCAA"}}," fetch"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'https://api.bilibili.com/x/web-interface/nav'"),s("span",{style:{color:"#D4D4D4"}},", {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," headers:"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}}," // SESSDATA 字段")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," Cookie:"),s("span",{style:{color:"#CE9178"}}," 'SESSDATA=xxxxxx'"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#CE9178"}}," 'User-Agent'"),s("span",{style:{color:"#9CDCFE"}},":"),s("span",{style:{color:"#CE9178"}}," 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," Referer:"),s("span",{style:{color:"#CE9178"}}," 'https://www.bilibili.com/'"),s("span",{style:{color:"#6A9955"}},"//对于直接浏览器调用可能不适用")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," }")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," })")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#D4D4D4"}}," { "),s("span",{style:{color:"#9CDCFE"}},"data"),s("span",{style:{color:"#D4D4D4"}},": { "),s("span",{style:{color:"#9CDCFE"}},"wbi_img"),s("span",{style:{color:"#D4D4D4"}},": { "),s("span",{style:{color:"#4FC1FF"}},"img_url"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#4FC1FF"}},"sub_url"),s("span",{style:{color:"#D4D4D4"}}," } } } = "),s("span",{style:{color:"#C586C0"}},"await"),s("span",{style:{color:"#9CDCFE"}}," res"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"json"),s("span",{style:{color:"#D4D4D4"}},"()")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}}," return"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_key:"),s("span",{style:{color:"#9CDCFE"}}," img_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"slice"),s("span",{style:{color:"#D4D4D4"}},"(")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'/'"),s("span",{style:{color:"#D4D4D4"}},") + "),s("span",{style:{color:"#B5CEA8"}},"1"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'.'"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ),")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_key:"),s("span",{style:{color:"#9CDCFE"}}," sub_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"slice"),s("span",{style:{color:"#D4D4D4"}},"(")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'/'"),s("span",{style:{color:"#D4D4D4"}},") + "),s("span",{style:{color:"#B5CEA8"}},"1"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'.'"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," )")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," }")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"}")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"async"),s("span",{style:{color:"#569CD6"}}," function"),s("span",{style:{color:"#DCDCAA"}}," main"),s("span",{style:{color:"#D4D4D4"}},"() {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," web_keys"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#C586C0"}},"await"),s("span",{style:{color:"#DCDCAA"}}," getWbiKeys"),s("span",{style:{color:"#D4D4D4"}},"()")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," params"),s("span",{style:{color:"#D4D4D4"}}," = { "),s("span",{style:{color:"#9CDCFE"}},"foo:"),s("span",{style:{color:"#CE9178"}}," '114'"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"bar:"),s("span",{style:{color:"#CE9178"}}," '514'"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"baz:"),s("span",{style:{color:"#B5CEA8"}}," 1919810"),s("span",{style:{color:"#D4D4D4"}}," },")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," img_key"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"web_keys"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," sub_key"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"web_keys"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#9CDCFE"}},"sub_key")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," query"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#DCDCAA"}},"encWbi"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"sub_key"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," console"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"log"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"query"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"}")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#DCDCAA"}},"main"),s("span",{style:{color:"#D4D4D4"}},"()")])])]),s("div",{class:"line-numbers","aria-hidden":"true",style:{"counter-reset":"line-number 0"}},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1)])),_:1,__:[30]}),a(c,{title:"TypeScript"},{default:p(()=>l[31]||(l[31]=[s("div",{class:"language-typescript line-numbers-mode","data-highlighter":"shiki","data-ext":"typescript",style:{"background-color":"#1E1E1E",color:"#D4D4D4"}},[s("pre",{class:"shiki dark-plus vp-code"},[s("code",{class:"language-typescript"},[s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}},"import"),s("span",{style:{color:"#9CDCFE"}}," md5"),s("span",{style:{color:"#C586C0"}}," from"),s("span",{style:{color:"#CE9178"}}," 'md5'")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"const"),s("span",{style:{color:"#4FC1FF"}}," mixinKeyEncTab"),s("span",{style:{color:"#D4D4D4"}}," = [")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 46"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"47"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"18"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"2"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"53"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"8"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"23"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"32"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"15"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"50"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"10"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"31"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"58"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"3"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"45"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"35"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"27"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"43"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"5"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"49"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 33"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"9"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"42"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"19"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"29"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"28"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"14"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"39"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"12"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"38"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"41"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"13"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"37"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"48"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"7"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"16"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"24"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"55"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"40"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 61"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"26"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"17"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"0"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"1"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"60"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"51"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"30"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"4"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"22"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"25"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"54"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"21"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"56"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"59"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"6"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"63"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"57"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"62"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"11"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#B5CEA8"}}," 36"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"20"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"34"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"44"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"52")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"]")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},"// 对 imgKey 和 subKey 进行字符顺序打乱编码")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"const"),s("span",{style:{color:"#DCDCAA"}}," getMixinKey"),s("span",{style:{color:"#D4D4D4"}}," = ("),s("span",{style:{color:"#9CDCFE"}},"orig"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}},") "),s("span",{style:{color:"#569CD6"}},"=>")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," mixinKeyEncTab")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"map"),s("span",{style:{color:"#D4D4D4"}},"(("),s("span",{style:{color:"#9CDCFE"}},"n"),s("span",{style:{color:"#D4D4D4"}},") "),s("span",{style:{color:"#569CD6"}},"=>"),s("span",{style:{color:"#9CDCFE"}}," orig"),s("span",{style:{color:"#D4D4D4"}},"["),s("span",{style:{color:"#9CDCFE"}},"n"),s("span",{style:{color:"#D4D4D4"}},"])")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"join"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},'""'),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"slice"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#B5CEA8"}},"0"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#B5CEA8"}},"32"),s("span",{style:{color:"#D4D4D4"}},");")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},"// 为请求参数进行 wbi 签名")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"function"),s("span",{style:{color:"#DCDCAA"}}," encWbi"),s("span",{style:{color:"#D4D4D4"}},"(")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," params"),s("span",{style:{color:"#D4D4D4"}},": { ["),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}},"]: "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}}," | "),s("span",{style:{color:"#4EC9B0"}},"number"),s("span",{style:{color:"#D4D4D4"}}," | "),s("span",{style:{color:"#4EC9B0"}},"object"),s("span",{style:{color:"#D4D4D4"}}," },")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_key"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_key"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},") {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," mixin_key"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#DCDCAA"}},"getMixinKey"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#9CDCFE"}},"sub_key"),s("span",{style:{color:"#D4D4D4"}},"),")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," curr_time"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"Math"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"round"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"Date"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"now"),s("span",{style:{color:"#D4D4D4"}},"() / "),s("span",{style:{color:"#B5CEA8"}},"1000"),s("span",{style:{color:"#D4D4D4"}},"),")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," chr_filter"),s("span",{style:{color:"#D4D4D4"}}," ="),s("span",{style:{color:"#D16969"}}," /"),s("span",{style:{color:"#CE9178"}},"["),s("span",{style:{color:"#D16969"}},"!'()*"),s("span",{style:{color:"#CE9178"}},"]"),s("span",{style:{color:"#D16969"}},"/"),s("span",{style:{color:"#569CD6"}},"g"),s("span",{style:{color:"#D4D4D4"}},";")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," Object"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"assign"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},", { "),s("span",{style:{color:"#9CDCFE"}},"wts:"),s("span",{style:{color:"#9CDCFE"}}," curr_time"),s("span",{style:{color:"#D4D4D4"}}," }); "),s("span",{style:{color:"#6A9955"}},"// 添加 wts 字段")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}}," // 按照 key 重排参数")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," query"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"Object"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"keys"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"sort"),s("span",{style:{color:"#D4D4D4"}},"()")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"map"),s("span",{style:{color:"#D4D4D4"}},"(("),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#D4D4D4"}},") "),s("span",{style:{color:"#569CD6"}},"=>"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},` // 过滤 value 中的 "!'()*" 字符`)]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," value"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},"["),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#D4D4D4"}},"]."),s("span",{style:{color:"#DCDCAA"}},"toString"),s("span",{style:{color:"#D4D4D4"}},"()."),s("span",{style:{color:"#DCDCAA"}},"replace"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"chr_filter"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#CE9178"}},'""'),s("span",{style:{color:"#D4D4D4"}},");")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}}," return"),s("span",{style:{color:"#CE9178"}}," `"),s("span",{style:{color:"#569CD6"}},"${"),s("span",{style:{color:"#DCDCAA"}},"encodeURIComponent"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"key"),s("span",{style:{color:"#D4D4D4"}},")"),s("span",{style:{color:"#569CD6"}},"}"),s("span",{style:{color:"#CE9178"}},"="),s("span",{style:{color:"#569CD6"}},"${"),s("span",{style:{color:"#DCDCAA"}},"encodeURIComponent"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"value"),s("span",{style:{color:"#D4D4D4"}},")"),s("span",{style:{color:"#569CD6"}},"}"),s("span",{style:{color:"#CE9178"}},"`"),s("span",{style:{color:"#D4D4D4"}},";")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," })")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ."),s("span",{style:{color:"#DCDCAA"}},"join"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},'"&"'),s("span",{style:{color:"#D4D4D4"}},");")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," wbi_sign"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#DCDCAA"}},"md5"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"query"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#9CDCFE"}},"mixin_key"),s("span",{style:{color:"#D4D4D4"}},"); "),s("span",{style:{color:"#6A9955"}},"// 计算 w_rid")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}}," return"),s("span",{style:{color:"#9CDCFE"}}," query"),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#CE9178"}},'"&w_rid="'),s("span",{style:{color:"#D4D4D4"}}," + "),s("span",{style:{color:"#9CDCFE"}},"wbi_sign"),s("span",{style:{color:"#D4D4D4"}},";")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"}")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}},"// 获取最新的 img_key 和 sub_key")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"async"),s("span",{style:{color:"#569CD6"}}," function"),s("span",{style:{color:"#DCDCAA"}}," getWbiKeys"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"SESSDATA"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}},") {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," res"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#C586C0"}},"await"),s("span",{style:{color:"#DCDCAA"}}," fetch"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'https://api.bilibili.com/x/web-interface/nav'"),s("span",{style:{color:"#D4D4D4"}},", {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," headers:"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#6A9955"}}," // SESSDATA 字段")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," Cookie:"),s("span",{style:{color:"#CE9178"}}," `SESSDATA="),s("span",{style:{color:"#569CD6"}},"${"),s("span",{style:{color:"#4FC1FF"}},"SESSDATA"),s("span",{style:{color:"#569CD6"}},"}"),s("span",{style:{color:"#CE9178"}},"`"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#CE9178"}}," 'User-Agent'"),s("span",{style:{color:"#9CDCFE"}},":"),s("span",{style:{color:"#CE9178"}}," 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," Referer:"),s("span",{style:{color:"#CE9178"}}," 'https://www.bilibili.com/'"),s("span",{style:{color:"#6A9955"}},"//对于直接浏览器调用可能不适用")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," }")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," })")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," data"),s("span",{style:{color:"#D4D4D4"}},": {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," wbi_img"),s("span",{style:{color:"#D4D4D4"}},": { "),s("span",{style:{color:"#4FC1FF"}},"img_url"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#4FC1FF"}},"sub_url"),s("span",{style:{color:"#D4D4D4"}}," },")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," },")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," } = ("),s("span",{style:{color:"#C586C0"}},"await"),s("span",{style:{color:"#9CDCFE"}}," res"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"json"),s("span",{style:{color:"#D4D4D4"}},"()) "),s("span",{style:{color:"#C586C0"}},"as"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," data"),s("span",{style:{color:"#D4D4D4"}},": {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," wbi_img"),s("span",{style:{color:"#D4D4D4"}},": { "),s("span",{style:{color:"#9CDCFE"}},"img_url"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}},"; "),s("span",{style:{color:"#9CDCFE"}},"sub_url"),s("span",{style:{color:"#D4D4D4"}},": "),s("span",{style:{color:"#4EC9B0"}},"string"),s("span",{style:{color:"#D4D4D4"}}," };")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," };")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," };")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#C586C0"}}," return"),s("span",{style:{color:"#D4D4D4"}}," {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_key:"),s("span",{style:{color:"#9CDCFE"}}," img_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"slice"),s("span",{style:{color:"#D4D4D4"}},"(")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'/'"),s("span",{style:{color:"#D4D4D4"}},") + "),s("span",{style:{color:"#B5CEA8"}},"1"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," img_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'.'"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," ),")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_key:"),s("span",{style:{color:"#9CDCFE"}}," sub_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"slice"),s("span",{style:{color:"#D4D4D4"}},"(")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'/'"),s("span",{style:{color:"#D4D4D4"}},") + "),s("span",{style:{color:"#B5CEA8"}},"1"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," sub_url"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"lastIndexOf"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},"'.'"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," )")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}}," }")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"}")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}},"async"),s("span",{style:{color:"#569CD6"}}," function"),s("span",{style:{color:"#DCDCAA"}}," main"),s("span",{style:{color:"#D4D4D4"}},"() {")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," web_keys"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#C586C0"}},"await"),s("span",{style:{color:"#DCDCAA"}}," getWbiKeys"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#CE9178"}},'"SESSDATA的值"'),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," params"),s("span",{style:{color:"#D4D4D4"}}," = { "),s("span",{style:{color:"#9CDCFE"}},"foo:"),s("span",{style:{color:"#CE9178"}}," '114'"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"bar:"),s("span",{style:{color:"#CE9178"}}," '514'"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"baz:"),s("span",{style:{color:"#B5CEA8"}}," 1919810"),s("span",{style:{color:"#D4D4D4"}}," },")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," img_key"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"web_keys"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}},",")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#4FC1FF"}}," sub_key"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#9CDCFE"}},"web_keys"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#9CDCFE"}},"sub_key")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#569CD6"}}," const"),s("span",{style:{color:"#4FC1FF"}}," query"),s("span",{style:{color:"#D4D4D4"}}," = "),s("span",{style:{color:"#DCDCAA"}},"encWbi"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"params"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"img_key"),s("span",{style:{color:"#D4D4D4"}},", "),s("span",{style:{color:"#9CDCFE"}},"sub_key"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#9CDCFE"}}," console"),s("span",{style:{color:"#D4D4D4"}},"."),s("span",{style:{color:"#DCDCAA"}},"log"),s("span",{style:{color:"#D4D4D4"}},"("),s("span",{style:{color:"#9CDCFE"}},"query"),s("span",{style:{color:"#D4D4D4"}},")")]),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#D4D4D4"}},"}")]),n(` `),s("span",{class:"line"}),n(` `),s("span",{class:"line"},[s("span",{style:{color:"#DCDCAA"}},"main"),s("span",{style:{color:"#D4D4D4"}},"()")])])]),s("div",{class:"line-numbers","aria-hidden":"true",style:{"counter-reset":"line-number 0"}},[s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"}),s("div",{class:"line-number"})])],-1)])),_:1,__:[31]})]),_:1}),l[35]||(l[35]=o(`

    输出内容为进行 Wbi 签名的后参数的 url query 形式

    bar=514&baz=1919810&foo=114&wts=1684805578&w_rid=bb97e15f28edf445a0e4420d36f0157e

    Golang

    无第三方库

    package main
    
    import (
        "bytes"
        "crypto/md5"
        "encoding/hex"
        "encoding/json"
        "fmt"
        "io"
        "net/http"
        "net/url"
        "strconv"
        "strings"
        "time"
    )
    
    func main() {
        u, err := url.Parse("https://api.bilibili.com/x/space/wbi/acc/info?mid=1850091")
        if err != nil {
            panic(err)
        }
        fmt.Printf("orig: %s\\n", u.String())
        err = Sign(u)
        if err != nil {
            panic(err)
        }
        fmt.Printf("signed: %s\\n", u.String())
    
        // 获取 wbi 时未修改 header
        // 但实际使用签名后的 url 时发现风控较为严重
    }
    
    // Sign 为链接签名
    func Sign(u *url.URL) error {
        return wbiKeys.Sign(u)
    }
    
    // Update 无视过期时间更新
    func Update() error {
        return wbiKeys.Update()
    }
    
    func Get() (wk WbiKeys, err error) {
        if err = wk.update(false); err != nil {
            return WbiKeys{}, err
        }
        return wbiKeys, nil
    }
    
    var wbiKeys WbiKeys
    
    type WbiKeys struct {
        Img            string
        Sub            string
        Mixin          string
        lastUpdateTime time.Time
    }
    
    // Sign 为链接签名
    func (wk *WbiKeys) Sign(u *url.URL) (err error) {
        if err = wk.update(false); err != nil {
            return err
        }
    
        values := u.Query()
    
        values = removeUnwantedChars(values, '!', '\\'', '(', ')', '*') // 必要性存疑?
    
        values.Set("wts", strconv.FormatInt(time.Now().Unix(), 10))
    
        // [url.Values.Encode] 内会对参数排序,
        // 且遍历 map 时本身就是无序的
        hash := md5.Sum([]byte(values.Encode() + wk.Mixin)) // Calculate w_rid
        values.Set("w_rid", hex.EncodeToString(hash[:]))
        u.RawQuery = values.Encode()
        return nil
    }
    
    // Update 无视过期时间更新
    func (wk *WbiKeys) Update() (err error) {
        return wk.update(true)
    }
    
    // update 按需更新
    func (wk *WbiKeys) update(purge bool) error {
        if !purge && time.Since(wk.lastUpdateTime) < time.Hour {
            return nil
        }
    
        // 测试下来不用修改 header 也能过
        resp, err := http.Get("https://api.bilibili.com/x/web-interface/nav")
        if err != nil {
            return err
        }
        defer resp.Body.Close()
        body, err := io.ReadAll(resp.Body)
        if err != nil {
            return err
        }
    
        nav := Nav{}
        err = json.Unmarshal(body, &nav)
        if err != nil {
            return err
        }
    
        if nav.Code != 0 && nav.Code != -101 { // -101 未登录时也会返回两个 key
            return fmt.Errorf("unexpected code: %d, message: %s", nav.Code, nav.Message)
        }
        img := nav.Data.WbiImg.ImgUrl
        sub := nav.Data.WbiImg.SubUrl
        if img == "" || sub == "" {
            return fmt.Errorf("empty image or sub url: %s", body)
        }
    
        // https://i0.hdslb.com/bfs/wbi/7cd084941338484aae1ad9425b84077c.png
        imgParts := strings.Split(img, "/")
        subParts := strings.Split(sub, "/")
    
        // 7cd084941338484aae1ad9425b84077c.png
        imgPng := imgParts[len(imgParts)-1]
        subPng := subParts[len(subParts)-1]
    
        // 7cd084941338484aae1ad9425b84077c
        wbiKeys.Img = strings.TrimSuffix(imgPng, ".png")
        wbiKeys.Sub = strings.TrimSuffix(subPng, ".png")
    
        wbiKeys.mixin()
        wbiKeys.lastUpdateTime = time.Now()
        return nil
    }
    
    func (wk *WbiKeys) mixin() {
        var mixin [32]byte
        wbi := wk.Img + wk.Sub
        for i := range mixin { // for i := 0; i < len(mixin); i++ {
            mixin[i] = wbi[mixinKeyEncTab[i]]
        }
        wk.Mixin = string(mixin[:])
    }
    
    var mixinKeyEncTab = [...]int{
        46, 47, 18, 2, 53, 8, 23, 32,
        15, 50, 10, 31, 58, 3, 45, 35,
        27, 43, 5, 49, 33, 9, 42, 19,
        29, 28, 14, 39, 12, 38, 41, 13,
        37, 48, 7, 16, 24, 55, 40, 61,
        26, 17, 0, 1, 60, 51, 30, 4,
        22, 25, 54, 21, 56, 59, 6, 63,
        57, 62, 11, 36, 20, 34, 44, 52,
    }
    
    func removeUnwantedChars(v url.Values, chars ...byte) url.Values {
        b := []byte(v.Encode())
        for _, c := range chars {
            b = bytes.ReplaceAll(b, []byte{c}, nil)
        }
        s, err := url.ParseQuery(string(b))
        if err != nil {
            panic(err)
        }
        return s
    }
    
    type Nav struct {
        Code    int    \`json:"code"\`
        Message string \`json:"message"\`
        Ttl     int    \`json:"ttl"\`
        Data    struct {
            WbiImg struct {
                ImgUrl string \`json:"img_url"\`
                SubUrl string \`json:"sub_url"\`
            } \`json:"wbi_img"\`
    
            // ......
        } \`json:"data"\`
    }

    CSharp

    无需依赖外部库

    using System.Security.Cryptography;
    using System.Text;
    using System.Text.Json.Nodes;
    
    class Program
    {
        private static HttpClient _httpClient = new();
    
        private static readonly int[] MixinKeyEncTab =
        {
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39,
            12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63,
            57, 62, 11, 36, 20, 34, 44, 52
        };
    
        //对 imgKey 和 subKey 进行字符顺序打乱编码
        private static string GetMixinKey(string orig)
        {
            return MixinKeyEncTab.Aggregate("", (s, i) => s + orig[i])[..32];
        }
    
        private static Dictionary<string, string> EncWbi(Dictionary<string, string> parameters, string imgKey,
            string subKey)
        {
            string mixinKey = GetMixinKey(imgKey + subKey);
            string currTime = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
            //添加 wts 字段
            parameters["wts"] = currTime;
            // 按照 key 重排参数
            parameters = parameters.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
            //过滤 value 中的 "!'()*" 字符
            parameters = parameters.ToDictionary(
                kvp => kvp.Key,
                kvp => new string(kvp.Value.Where(chr => !"!'()*".Contains(chr)).ToArray())
            );
            // 序列化参数
            string query = new FormUrlEncodedContent(parameters).ReadAsStringAsync().Result;
            //计算 w_rid
            using MD5 md5 = MD5.Create();
            byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query + mixinKey));
            string wbiSign = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
            parameters["w_rid"] = wbiSign;
    
            return parameters;
        }
    
        // 获取最新的 img_key 和 sub_key
          private static async Task<(string, string)> GetWbiKeys()
          {
              var httpClient = new HttpClient();
              httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
              httpClient.DefaultRequestHeaders.Referrer = new Uri("https://www.bilibili.com/");
          
              HttpResponseMessage responseMessage = await httpClient.SendAsync(new HttpRequestMessage
              {
                  Method = HttpMethod.Get,
                  RequestUri = new Uri("https://api.bilibili.com/x/web-interface/nav"),
              });
          
              JsonNode response = JsonNode.Parse(await responseMessage.Content.ReadAsStringAsync())!;
          
              string imgUrl = (string)response["data"]!["wbi_img"]!["img_url"]!;
              imgUrl = imgUrl.Split("/")[^1].Split(".")[0];
          
              string subUrl = (string)response["data"]!["wbi_img"]!["sub_url"]!;
              subUrl = subUrl.Split("/")[^1].Split(".")[0];
              return (imgUrl, subUrl);
          }
    
    
        public static async Task Main()
        {
            var (imgKey, subKey) = await GetWbiKeys();
    
            Dictionary<string, string> signedParams = EncWbi(
                parameters: new Dictionary<string, string>
                {
                    { "foo", "114" },
                    { "bar", "514" },
                    { "baz", "1919810" }
                },
                imgKey: imgKey,
                subKey: subKey
            );
    
            string query = await new FormUrlEncodedContent(signedParams).ReadAsStringAsync();
    
            Console.WriteLine(query);
        }
    }

    输出内容为进行 Wbi 签名的后参数的 url query 形式

    bar=514&baz=1919810&foo=114&wts=1687541921&w_rid=26e82b1b9b3a11dbb1807a9228a40d3b

    Java

    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.*;
    import java.util.stream.Collectors;
    
    public class WbiTest {
        private static final int[] mixinKeyEncTab = new int[]{
                46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
                33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
                61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
                36, 20, 34, 44, 52
        };
    
        private static final char[] hexDigits = "0123456789abcdef".toCharArray();
    
        public static String md5(String input) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
                char[] result = new char[messageDigest.length * 2];
                for (int i = 0; i < messageDigest.length; i++) {
                    result[i * 2] = hexDigits[(messageDigest[i] >> 4) & 0xF];
                    result[i * 2 + 1] = hexDigits[messageDigest[i] & 0xF];
                }
                return new String(result);
            } catch (NoSuchAlgorithmException e) {
                return null;
            }
        }
    
        public static String getMixinKey(String imgKey, String subKey) {
            String s = imgKey + subKey;
            StringBuilder key = new StringBuilder();
            for (int i = 0; i < 32; i++)
                key.append(s.charAt(mixinKeyEncTab[i]));
            return key.toString();
        }
    
        public static String encodeURIComponent(Object o) {
            return URLEncoder.encode(o.toString(), StandardCharsets.UTF_8).replace("+", "%20");
        }
    
        public static void main(String[] args) {
            String imgKey = "653657f524a547ac981ded72ea172057";
            String subKey = "6e4909c702f846728e64f6007736a338";
            String mixinKey = getMixinKey(imgKey, subKey);
            System.out.println(mixinKey); // 72136226c6a73669787ee4fd02a74c27
    
            // 用TreeMap自动排序
            TreeMap<String, Object> map = new TreeMap<>();
            map.put("foo", "one one four");
            map.put("bar", "五一四");
            map.put("baz", 1919810);
            map.put("wts", System.currentTimeMillis() / 1000);
            String param = map.entrySet().stream()
                    .map(it -> String.format("%s=%s", it.getKey(), encodeURIComponent(it.getValue())))
                    .collect(Collectors.joining("&"));
            String s = param + mixinKey;
    
            String wbiSign = md5(s);
            System.out.println(wbiSign);
            String finalParam = param + "&w_rid=" + wbiSign;
            System.out.println(finalParam);
        }
    }

    Kotlin

    说明: 为了便于使用和缓存, 重新编写为实体类形式, 并拆分了多个文件. 使用官方的JSON序列化. (可以根据需要换成其他的)

    WbiParams.kt

    import kotlinx.serialization.Serializable
    import kotlinx.serialization.json.JsonElement
    import kotlinx.serialization.json.JsonObject
    import kotlinx.serialization.json.jsonPrimitive
    
    private fun JsonElement?.get(): String {
        check(this != null) { "No contents found" }
        return this.jsonPrimitive.content.split('/').last().removeSuffix(".png")
    }
    
    private val mixinKeyEncTab = intArrayOf(
        46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
        33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
        61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
        36, 20, 34, 44, 52
    )
    
    @Serializable
    data class WbiParams(
        val imgKey: String,
        val subKey: String,
    ) {
        // 此处整合了切分参数(直接传入{img_url:string, sub_url:string}即可), 不需要可以删掉
        constructor(wbiImg: JsonObject) : this(wbiImg["img_url"].get(), wbiImg["sub_url"].get())
    
        private val mixinKey: String
            get() = (imgKey + subKey).let { s ->
                buildString {
                    repeat(32) {
                        append(s[mixinKeyEncTab[it]])
                    }
                }
            }
    
        // 创建对象(GET获取或者读缓存, 比如Redis)之后, 直接调用此函数处理
        fun enc(params: Map<String, Any?>): String {
            val sorted = params.filterValues { it != null }.toSortedMap()
            return buildString {
                append(sorted.toQueryString())
                val wts = System.currentTimeMillis() / 1000
                sorted["wts"] = wts
                append("&wts=")
                append(wts)
                append("&w_rid=")
                append((sorted.toQueryString() + mixinKey).toMD5())
            }
        }
    }

    Extensions.kt

    import java.security.MessageDigest
    
    private val hexDigits = "0123456789abcdef".toCharArray()
    
    fun ByteArray.toHexString() = buildString(this.size shl 1) {
        this@toHexString.forEach { byte ->
            append(hexDigits[byte.toInt() ushr 4 and 15])
            append(hexDigits[byte.toInt() and 15])
        }
    }
    
    fun String.toMD5(): String {
        val md = MessageDigest.getInstance("MD5")
        val digest = md.digest(this.toByteArray())
        return digest.toHexString()
    }
    
    fun Map<String, Any?>.toQueryString() = this.filterValues { it != null }.entries.joinToString("&") { (k, v) ->
        "\${k.encodeURIComponent()}=\${v!!.encodeURIComponent()}"
    }

    获取和使用案例略

    PHP

    来自SocialSisterYi/bilibili-API-collect#813

    <?php
    /**
     * B站 Wbi 测试
     * @author Prk
     */
    
    
    class Bilibili {
    
        private $mixinKeyEncTab = [
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
            33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
            61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
            36, 20, 34, 44, 52
        ];
    
        function __construct() {
        }
    
        public function reQuery(array $query) {
            $wbi_keys = $this->getWbiKeys();
            return $this->encWbi($query, $wbi_keys['img_key'], $wbi_keys['sub_key']);
        }
    
        private function getMixinKey($orig) {
            $t = '';
            foreach ($this->mixinKeyEncTab as $n) $t .= $orig[$n];
            return substr($t, 0, 32);
        }
    
        private function encWbi($params, $img_key, $sub_key) {
            $mixin_key = $this->getMixinKey($img_key . $sub_key);
            $curr_time = time();
            $chr_filter = "/[!'()*]/";
    
            $query = [];
            $params['wts'] = $curr_time;
    
            ksort($params);
    
            foreach ($params as $key => $value) {
                $value = preg_replace($chr_filter, '', $value);
                $query[] = urlencode($key) . '=' . urlencode($value);
            }
    
            $query = implode('&', $query);
            $wbi_sign = md5($query . $mixin_key);
    
            return $query . '&w_rid=' . $wbi_sign;
        }
    
        private function getWbiKeys() {
            $resp = @json_decode(
                $this->curl_get(
                    'https://api.bilibili.com/x/web-interface/nav',
                    null,
                    'https://www.bilibili.com/'
                ), true
            );
    
            if (!$resp) throw new Exception('请求失败');
    
            $img_url = $resp['data']['wbi_img']['img_url'];
            $sub_url = $resp['data']['wbi_img']['sub_url'];
    
            return [
                'img_key' => substr(basename($img_url), 0, strpos(basename($img_url), '.')),
                'sub_key' => substr(basename($sub_url), 0, strpos(basename($sub_url), '.'))
            ];
        }
    
        private function curl_get($url, $cookies = null, $referer = 'https://www.bilibili.com/', $ua = null, $proxy = null, $header = []) {
            $ch = curl_init();
            $header[] = "Accept: */*";
            $header[] = "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7";
            $header[] = "Connection: close";
            $header[]="Referer:https://www.bilibili.com/";
            $header[] = "Cache-Control: max-age=0";
            curl_setopt_array($ch, [
                CURLOPT_HTTPGET         =>  1,
                CURLOPT_CUSTOMREQUEST   =>  'GET',
                CURLOPT_RETURNTRANSFER  =>  1,
                CURLOPT_HTTPHEADER      =>  $header,
                CURLOPT_ENCODING        =>  '',
                CURLOPT_URL             =>  $url,
                CURLOPT_USERAGENT       =>  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.39',
                CURLOPT_TIMEOUT         =>  15
            ]);
    
            if ($cookies) curl_setopt(
                $ch,
                CURLOPT_COOKIE,
                $cookies
            );
    
            if ($referer) curl_setopt_array($ch, [
                CURLOPT_AUTOREFERER =>  $referer,
                CURLOPT_REFERER     =>  $referer
            ]);
    
            $content = curl_exec($ch);
            curl_close($ch);
            return $content;
        }
    }
    
    $c = new Bilibili();
    echo $c->reQuery(['foo' => '114', 'bar' => '514', 'baz' => 1919810]);
    // bar=514&baz=1919810&foo=114&wts=1700384803&w_rid=4614cb98d60a43e50c3a3033fe3d116b

    Rust

    需要 serde、serde_json、reqwest、tokio 以及 md5

    use reqwest::header::USER_AGENT;
    use serde::Deserialize;
    use std::time::{SystemTime, UNIX_EPOCH};
    
    const MIXIN_KEY_ENC_TAB: [usize; 64] = [
        46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29,
        28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25,
        54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52,
    ];
    
    #[derive(Deserialize)]
    struct WbiImg {
        img_url: String,
        sub_url: String,
    }
    
    #[derive(Deserialize)]
    struct Data {
        wbi_img: WbiImg,
    }
    
    #[derive(Deserialize)]
    struct ResWbi {
        data: Data,
    }
    
    // 对 imgKey 和 subKey 进行字符顺序打乱编码
    fn get_mixin_key(orig: &[u8]) -> String {
        MIXIN_KEY_ENC_TAB
            .iter()
            .take(32)
            .map(|&i| orig[i] as char)
            .collect::<String>()
    }
    
    fn get_url_encoded(s: &str) -> String {
        s.chars()
            .filter_map(|c| match c.is_ascii_alphanumeric() || "-_.~".contains(c) {
                true => Some(c.to_string()),
                false => {
                    // 过滤 value 中的 "!'()*" 字符
                    if "!'()*".contains(c) {
                        return None;
                    }
                    let encoded = c
                        .encode_utf8(&mut [0; 4])
                        .bytes()
                        .fold("".to_string(), |acc, b| acc + &format!("%{:02X}", b));
                    Some(encoded)
                }
            })
            .collect::<String>()
    }
    
    // 为请求参数进行 wbi 签名
    fn encode_wbi(params: Vec<(&str, String)>, (img_key, sub_key): (String, String)) -> String {
        let cur_time = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(t) => t.as_secs(),
            Err(_) => panic!("SystemTime before UNIX EPOCH!"),
        };
        _encode_wbi(params, (img_key, sub_key), cur_time)
    }
    
    fn _encode_wbi(
        mut params: Vec<(&str, String)>,
        (img_key, sub_key): (String, String),
        timestamp: u64,
    ) -> String {
        let mixin_key = get_mixin_key((img_key + &sub_key).as_bytes());
        // 添加当前时间戳
        params.push(("wts", timestamp.to_string()));
        // 重新排序
        params.sort_by(|a, b| a.0.cmp(b.0));
        // 拼接参数
        let query = params
            .iter()
            .map(|(k, v)| format!("{}={}", get_url_encoded(k), get_url_encoded(v)))
            .collect::<Vec<_>>()
            .join("&");
        // 计算签名
        let web_sign = format!("{:?}", md5::compute(query.clone() + &mixin_key));
        // 返回最终的 query
        query + &format!("&w_rid={}", web_sign)
    }
    
    async fn get_wbi_keys() -> Result<(String, String), reqwest::Error> {
        let client = reqwest::Client::new();
        let ResWbi { data:Data{wbi_img} } = client
        .get("https://api.bilibili.com/x/web-interface/nav")
        .header(USER_AGENT,"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36")
        .header("Referer","https://www.bilibili.com/")
         // SESSDATA=xxxxx
        .header("Cookie", "SESSDATA=xxxxx")
        .send()
        .await?
        .json::<ResWbi>()
        .await?;
        Ok((
            take_filename(wbi_img.img_url).unwrap(),
            take_filename(wbi_img.sub_url).unwrap(),
        ))
    }
    
    fn take_filename(url: String) -> Option<String> {
        url.rsplit_once('/')
            .and_then(|(_, s)| s.rsplit_once('.'))
            .map(|(s, _)| s.to_string())
    }
    
    #[tokio::main]
    async fn main() {
        let keys = get_wbi_keys().await.unwrap();
        let params = vec![
            ("foo", String::from("114")),
            ("bar", String::from("514")),
            ("baz", String::from("1919810")),
        ];
        let query = encode_wbi(params, keys);
        println!("{}", query);
    }
    
    // 取自文档描述的测试用例
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_get_filename() {
            assert_eq!(
                take_filename(
                    "https://i0.hdslb.com/bfs/wbi/7cd084941338484aae1ad9425b84077c.png".to_string()
                ),
                Some("7cd084941338484aae1ad9425b84077c".to_string())
            );
        }
    
        #[test]
        fn test_get_mixin_key() {
            let concat_key =
                "7cd084941338484aae1ad9425b84077c".to_string() + "4932caff0ff746eab6f01bf08b70ac45";
            assert_eq!(
                get_mixin_key(concat_key.as_bytes()),
                "ea1db124af3c7062474693fa704f4ff8"
            );
        }
    
        #[test]
        fn test_encode_wbi() {
            let params = vec![
                ("foo", String::from("114")),
                ("bar", String::from("514")),
                ("zab", String::from("1919810")),
            ];
            assert_eq!(
                _encode_wbi(
                    params,
                    (
                        "7cd084941338484aae1ad9425b84077c".to_string(),
                        "4932caff0ff746eab6f01bf08b70ac45".to_string()
                    ),
                    1702204169
                ),
                "bar=514&foo=114&wts=1702204169&zab=1919810&w_rid=8f6f2b5b3d485fe1886cec6a0be8c5d4"
                    .to_string()
            )
        }
    }

    Swift

    需要 AlamofireSwiftyJSON

    import Alamofire
    import CommonCrypto
    import Foundation
    import SwiftyJSON
    
    func biliWbiSign(param: String, completion: @escaping (String?) -> Void) {
        func getMixinKey(orig: String) -> String {
            return String(mixinKeyEncTab.map { orig[orig.index(orig.startIndex, offsetBy: $0)] }.prefix(32))
        }
        
        func encWbi(params: [String: Any], imgKey: String, subKey: String) -> [String: Any] {
            var params = params
            let mixinKey = getMixinKey(orig: imgKey + subKey)
            let currTime = Int(Date().timeIntervalSince1970)
            params["wts"] = currTime
            let query = params.sorted {
                $0.key < $1.key
            }.map { (key, value) -> String in
                let stringValue: String
                if let doubleValue = value as? Double, doubleValue.truncatingRemainder(dividingBy: 1) == 0 {
                    stringValue = String(Int(doubleValue))
                } else {
                    stringValue = String(describing: value)
                }
                let filteredValue = stringValue.filter { !"!'()*".contains($0) }
                return "\\(key)=\\(filteredValue)"
            }.joined(separator: "&")
            let wbiSign = calculateMD5(string: query + mixinKey)
            params["w_rid"] = wbiSign
            return params
        }
        
        func getWbiKeys(completion: @escaping (Result<(imgKey: String, subKey: String), Error>) -> Void) {
            let headers: HTTPHeaders = [
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
                "Referer": "https://www.bilibili.com/"
            ]
           
            AF.request("https://api.bilibili.com/x/web-interface/nav", headers: headers).responseJSON { response in
                switch response.result {
                case .success(let value):
                    let json = JSON(value)
                    let imgURL = json["data"]["wbi_img"]["img_url"].string ?? ""
                    let subURL = json["data"]["wbi_img"]["sub_url"].string ?? ""
                    let imgKey = imgURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
                    let subKey = subURL.components(separatedBy: "/").last?.components(separatedBy: ".").first ?? ""
                    completion(.success((imgKey, subKey)))
                case .failure(let error):
                    completion(.failure(error))
                }
            }
        }
    
        func calculateMD5(string: String) -> String {
            let data = Data(string.utf8)
            var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
            _ = data.withUnsafeBytes {
                CC_MD5($0.baseAddress, CC_LONG(data.count), &digest)
            }
            return digest.map { String(format: "%02hhx", $0) }.joined()
        }
        
        let mixinKeyEncTab = [
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
            33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
            61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
            36, 20, 34, 44, 52
        ]
        
        getWbiKeys { result in
            switch result {
            case .success(let keys):
                let spdParam = param.components(separatedBy: "&")
                var spdDicParam = [String: String]()
                for pair in spdParam {
                    let components = pair.components(separatedBy: "=")
                    if components.count == 2 {
                        spdDicParam[components[0]] = components[1]
                    }
                }
                
                let signedParams = encWbi(params: spdDicParam, imgKey: keys.imgKey, subKey: keys.subKey)
                let query = signedParams.map { "\\($0.key)=\\($0.value)" }.joined(separator: "&")
                completion(query)
            case .failure(let error):
                print("Error getting keys: \\(error)")
                completion(nil)
            }
        }
    }
    
    // 使用示例
    biliWbiSign(param: "bar=514&foo=114&zab=1919810") {
        signedQuery in
        if let signedQuery = signedQuery {
            print("签名后的参数: \\(signedQuery)")
        } else {
            print("签名失败")
        }
    }
    
    RunLoop.main.run()//程序类型为命令行程序时需要添加这行代码
    签名后的参数: bar=514&wts=1741082093&foo=114&zab=1919810&w_rid=04775bb3debbb45bab86a93a1c08d12a

    CPlusPlus

    需要 c++ 23 标准库,cprcryptoppnlohmann/json 等依赖

    #include <array>    // std::array
    #include <locale>   // std::locale
    #include <print>    // std::println
    
    /// thrid party libraries
    #include <cpr/cpr.h>
    #include <cryptopp/md5.h>
    #include <cryptopp/hex.h>
    #include <nlohmann/json.hpp>
    
    /*
     * 注意,假定不会发生错误!
     */
    class Wbi {
        constexpr static std::array<uint8_t, 64> MIXIN_KEY_ENC_TAB_ = {
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35,
            27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13,
            37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4,
            22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52
        };
    
        /* 获取 md5 hex(lower) */
        static std::string Get_md5_hex(const std::string &Input_str) {
            CryptoPP::Weak1::MD5 hash;
            std::string          md5_hex;
    
            CryptoPP::StringSource ss(Input_str, true,
                new CryptoPP::HashFilter(hash,
                    new CryptoPP::HexEncoder(
                        new CryptoPP::StringSink(md5_hex)
                    )
                )
            );
    
            std::ranges::for_each(md5_hex, [](char &x) { x = std::tolower(x); });
            return md5_hex;
        }
    
    public:
        /* 将 json 转换为 url 编码字符串 */
        static std::string Json_to_url_encode_str(const nlohmann::json &Json) {
            std::string encode_str;
            for (const auto &[key, value]: Json.items()) {
                encode_str.append(key).append("=").append(cpr::util::urlEncode(value.is_string() ? value.get<std::string>() : to_string(value))).append("&");
            }
    
            // remove the last '&'
            encode_str.resize(encode_str.size() - 1, '\\0');
            return encode_str;
        }
    
        /* 获取 wbi key */
        static std::pair<std::string, std::string> Get_wbi_key() {
            const auto url    = cpr::Url {"https://api.bilibili.com/x/web-interface/nav"};
            const auto cookie = cpr::Cookies {
                {"SESSDATA", "xxxxxxxxxxxx"},
            };
            const auto header = cpr::Header {
                {"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"},
                {"Referer", "https://www.bilibili.com/"},
            };
            const auto response = cpr::Get(url, cookie, header);
    
            nlohmann::json json = nlohmann::json::parse(response.text);
    
            const std::string img_url = json["data"]["wbi_img"]["img_url"];
            const std::string sub_url = json["data"]["wbi_img"]["sub_url"];
    
            std::string img_key = img_url.substr(img_url.find("wbi/") + 4, img_url.find(".png") - img_url.find("wbi/") - 4);
            std::string sub_key = sub_url.substr(sub_url.find("wbi/") + 4, sub_url.find(".png") - sub_url.find("wbi/") - 4);
            return {img_key, sub_key};
        }
    
        /* 获取 mixin key */
        static std::string Get_mixin_key(const std::string &Img_key, const std::string &Sub_key) {
            std::string raw_wbi_key_str = Img_key + Sub_key;
            std::string result;
    
            std::ranges::for_each(MIXIN_KEY_ENC_TAB_, [&result, &raw_wbi_key_str](const uint8_t x) {
                result.push_back(raw_wbi_key_str.at(x));
            });
    
            return result.substr(0, 32);
        }
    
        /* 计算签名(w_rid) */
        static std::string Calc_sign(nlohmann::json &Params, const std::string &Mixin_key) {
            Params["wts"] = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    
            const std::string encode_str = Json_to_url_encode_str(Params).append(Mixin_key);
            return Get_md5_hex(encode_str);
        }
    };
    
    
    int main() {
        nlohmann::json Params;
        // qn=32&fnver=0&fnval=4048&fourk=1&avid=1755630705&cid=1574294582
        Params["qn"]    = 32;
        Params["fnver"] = 0;
        Params["fnval"] = 4048;
        Params["fourk"] = 1;
        Params["avid"]  = 1755630705;
        Params["cid"]   = 1574294582;
    
        auto       [img_key, sub_key] = Wbi::Get_wbi_key();
        const auto mixin_key          = Wbi::Get_mixin_key(img_key, sub_key);
        const auto w_rid              = Wbi::Calc_sign(Params, mixin_key);
        std::println("{}", Wbi::Json_to_url_encode_str(Params) + "&w_rid=" + w_rid);
    }
    avid=1755630705&cid=1574294582&fnval=4048&fnver=0&fourk=1&qn=32&wts=1717922933&w_rid=43571b838a1611fa121189083cfc1784

    Haskell

    无第三方依赖: base, Cabal-syntax, bytestring, containers
    注: 此处使用自写的 URI 编码模块, 实际可用别的第三方库替代

    Main.hs:

    module Main (wbi, main) where
    
    import Data.ByteString.Char8 (pack)
    import qualified Data.Map.Strict as Map
    import Distribution.Utils.MD5 (md5, showMD5)
    import URIEncoder (encodeURIComponent)
    import Data.Time.Clock.System (getSystemTime, systemSeconds)
    
    mixinKeyEncTab :: [Int]
    mixinKeyEncTab = [
      46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
      33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
      61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
      36, 20, 34, 44, 52
      ]
    
    getMixinKey :: String -> String -> String
    getMixinKey imgKey subKey =
      let s = imgKey ++ subKey
      in map (\\i -> s !! (mixinKeyEncTab !! i)) [0..31]
    
    join :: [String] -> String -> String
    join arr ins = concatMap (++ ins) (init arr) ++ last arr
    
    wbi :: String -> String -> Integer -> Map.Map String String -> String
    wbi imgKey subKey wts params =
      let orig = join (map (\\(k, v) -> encodeURIComponent k ++ "=" ++ encodeURIComponent v) (Map.toList $ Map.insert "wts" (show wts) params)) "&"
      in orig ++ "&w_rid=" ++ showMD5 (md5 $ pack $ orig ++ getMixinKey imgKey subKey)
    
    main :: IO ()
    main = do -- hard encode for test
      let params1 = Map.fromList [("aid", "2")]
          params2 = Map.fromList [("foo", "114")
                                ,("bar", "514")
                                ,("hello", "世 界")
                                ]
          imgKey = "7cd084941338484aae1ad9425b84077c"
          subKey = "4932caff0ff746eab6f01bf08b70ac45"
      wts1 <- getSystemTime 
      putStrLn $ wbi imgKey subKey (toInteger $ systemSeconds wts1) params1
      wts2 <- getSystemTime 
      putStrLn $ wbi imgKey subKey (toInteger $ systemSeconds wts2) params2

    URIEncoder.hs:

    module URIEncoder (encodeURIComponent) where
    
    import Data.Char (ord, chr, intToDigit)
    import Data.Bits (shiftL, shiftR, (.&.))
    import Data.List (isInfixOf)
    
    -- ES 19.2.6.4 encodeURIComponent ( uriComponent )
    encodeURIComponent :: String -> String
    encodeURIComponent input = case encode input "" of
      Right result -> result
      Left err -> error err
    
    -- ES 19.2.6.5 Encode ( string, extraUnescaped )
    encode :: String -> String -> Either String String
    encode string extraUnescaped = loop 0 string
      where
        alwaysUnescaped = ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "-.!~*'()"
        unescapedSet = alwaysUnescaped ++ extraUnescaped
        
        loop k str
          | k >= length str = Right []
          | otherwise = case codePointAt str k of
              (Nothing, _) -> Left "Unpaired surrogate"
              (Just (cp, _), newK) ->
                if [str !! k] \`isInfixOf\` unescapedSet
                then (str !! k :) <$> loop (k + 1) str
                else do
                  bytes <- utf8Encode cp
                  let escaped = concatMap percentEncode bytes
                  rest <- loop newK str
                  Right (escaped ++ rest)
    
    codePointAt :: String -> Int -> (Maybe (Int, Int), Int)
    codePointAt s k
      | k >= length s = (Nothing, k)
      | otherwise =
          let c1 = ord (s !! k)
          in if 0xD800 <= c1 && c1 <= 0xDBFF && k+1 < length s
             then let c2 = ord (s !! (k+1))
                  in if 0xDC00 <= c2 && c2 <= 0xDFFF
                     then ( Just (0x10000 + ((c1 - 0xD800) \`shiftL\` 10) + (c2 - 0xDC00), 2)
                         , k + 2 )
                     else (Just (c1, 1), k + 1)
             else (Just (c1, 1), k + 1)
    
    utf8Encode :: Int -> Either String [Int]
    utf8Encode cp
      | cp < 0 = Left "Invalid code point"
      | cp <= 0x007F = Right [cp]
      | cp <= 0x07FF = Right
          [ 0xC0 + (cp \`shiftR\` 6)
          , 0x80 + (cp .&. 0x3F) ]
      | cp <= 0xFFFF = Right
          [ 0xE0 + (cp \`shiftR\` 12)
          , 0x80 + ((cp \`shiftR\` 6) .&. 0x3F)
          , 0x80 + (cp .&. 0x3F) ]
      | cp <= 0x10FFFF = Right
          [ 0xF0 + (cp \`shiftR\` 18)
          , 0x80 + ((cp \`shiftR\` 12) .&. 0x3F)
          , 0x80 + ((cp \`shiftR\` 6) .&. 0x3F)
          , 0x80 + (cp .&. 0x3F) ]
      | otherwise = Left "Code point out of range"
    
    percentEncode :: Int -> String
    percentEncode byte = '%' : toHex byte
      where
        toHex n = [hexDigit (n \`div\` 16), hexDigit (n \`mod\` 16)]
        hexDigit x
          | x < 10 = intToDigit x
          | otherwise = chr (x - 10 + ord 'A')

    输出:

    aid=2&wts=1744823207&w_rid=a3cd246bd42c066932752b24694eaf0d
    bar=514&foo=114&hello=%E4%B8%96%20%E7%95%8C&wts=1744823207&w_rid=93acf59d85f74453e40cea00056c3daf
    `,41))])}const E=t(C,[["render",d]]),m=JSON.parse('{"path":"/docs/misc/sign/wbi.html","title":"WBI 签名","lang":"zh-CN","frontmatter":{},"git":{"updatedTime":1758034754000,"contributors":[{"name":"SocialSisterYi","username":"SocialSisterYi","email":"1440239038@qq.com","commits":3,"url":"https://github.com/SocialSisterYi"},{"name":"THMonster","username":"THMonster","email":"me@isoasflus.com","commits":1,"url":"https://github.com/THMonster"},{"name":"Jianqi Pan","username":"","email":"jannchie@gmail.com","commits":1},{"name":"ywmoyue","username":"ywmoyue","email":"ywmoyue@163.com","commits":1,"url":"https://github.com/ywmoyue"},{"name":"vapehacker","username":"vapehacker","email":"62145553+vapehacker@users.noreply.github.com","commits":1,"url":"https://github.com/vapehacker"},{"name":"7rikka","username":"7rikka","email":"takanashirikkax@gmail.com","commits":2,"url":"https://github.com/7rikka"},{"name":"lanyeeee","username":"lanyeeee","email":"73207840+lanyeeee@users.noreply.github.com","commits":1,"url":"https://github.com/lanyeeee"},{"name":"xiaoyv404","username":"xiaoyv404","email":"63290381+xiaoyv404@users.noreply.github.com","commits":1,"url":"https://github.com/xiaoyv404"},{"name":"PACI","username":"PACI","email":"emkqson@outlook.com","commits":1,"url":"https://github.com/PACI"},{"name":"188102836","username":"188102836","email":"69347367+188102836@users.noreply.github.com","commits":1,"url":"https://github.com/188102836"},{"name":"ud2","username":"ud2","email":"sjx233@qq.com","commits":2,"url":"https://github.com/ud2"},{"name":"LaMerChiang","username":"LaMerChiang","email":"catlair@qq.com","commits":1,"url":"https://github.com/LaMerChiang"},{"name":"fwqaaq","username":"fwqaaq","email":"fwqaaq@gmail.com","commits":1,"url":"https://github.com/fwqaaq"},{"name":"WindowsMEMZ","username":"WindowsMEMZ","email":"45706356+WindowsMEMZ@users.noreply.github.com","commits":1,"url":"https://github.com/WindowsMEMZ"},{"name":"cxw620","username":"cxw620","email":"70561268+cxw620@users.noreply.github.com","commits":1,"url":"https://github.com/cxw620"},{"name":"Ivan Hanloth","username":"","email":"ivan@hanloth.com","commits":1},{"name":"YuHuanTin","username":"YuHuanTin","email":"51024916+YuHuanTin@users.noreply.github.com","commits":1,"url":"https://github.com/YuHuanTin"},{"name":"stmtc233","username":"stmtc233","email":"69023595+stmtc233@users.noreply.github.com","commits":1,"url":"https://github.com/stmtc233"},{"name":"xrz-cloud","username":"xrz-cloud","email":"62951481+xrz-cloud@users.noreply.github.com","commits":1,"url":"https://github.com/xrz-cloud"},{"name":"ᴀᴍᴛᴏᴀᴇʀ","username":"","email":"amtoaer@outlook.com","commits":1},{"name":"SessionHu","username":"SessionHu","email":"102411014+SessionHu@users.noreply.github.com","commits":7,"url":"https://github.com/SessionHu"},{"name":"MukjepScarlet","username":"MukjepScarlet","email":"93977077+MukjepScarlet@users.noreply.github.com","commits":2,"url":"https://github.com/MukjepScarlet"},{"name":"Miuzarte","username":"Miuzarte","email":"982809597@qq.com","commits":1,"url":"https://github.com/Miuzarte"},{"name":"Seamain","username":"Seamain","email":"quanminjun37@gmail.com","commits":1,"url":"https://github.com/Seamain"},{"name":"xjbeta","username":"xjbeta","email":"11794321+xjbeta@users.noreply.github.com","commits":1,"url":"https://github.com/xjbeta"}],"changelog":[{"hash":"3299dde4c877c8c5cc16f7dba4fec857d67fceaa","time":1758034754000,"email":"11794321+xjbeta@users.noreply.github.com","author":"xjbeta","message":"fix(doc/misc/sign/wbi.md): swift demo (#1389)"},{"hash":"22c19c917ea5eb11aa2835780ffac101a90fbfaf","time":1745004257000,"email":"102411014+SessionHu@users.noreply.github.com","author":"SessionHu","message":"feat(misc/sign/wbi.md): add details"},{"hash":"17b0e43ec2573a3b7f99d5c4c204a4f3b7f9641b","time":1744996652000,"email":"102411014+SessionHu@users.noreply.github.com","author":"SessionHu","message":"feat: add details"},{"hash":"526b0374c0ba58c7a1266762f464f5a5579b02ce","time":1744823327000,"email":"102411014+SessionHu@users.noreply.github.com","author":"SessionHu","message":"feat(misc/sign/wbi.md): update haskell demo data"},{"hash":"ad1d2dd96dc3285e0ed3941796fb2ed2ed237536","time":1744819234000,"email":"102411014+SessionHu@users.noreply.github.com","author":"SessionHu","message":"feat(misc/sign/wbi.md): haskell demo"},{"hash":"4abf38f2aa66f38fc4041cb8eb9ad850679281a7","time":1744514563000,"email":"quanminjun37@gmail.com","author":"Seamain","message":"优化wbi.md里的Swift代码 (#1208)"},{"hash":"724e618babe94dcc1ddd557ae33fa3f9f176cf12","time":1743773185000,"email":"982809597@qq.com","author":"Miuzarte","message":"重构 wbi golang 实现"},{"hash":"1e24c6b1889160c4c35c01416aa4239501accf5f","time":1726759053000,"email":"102411014+SessionHu@users.noreply.github.com","author":"Session小胡","message":"调整部分接口描述与错误修复 (#1088)","coAuthors":[{"name":"社会易姐QwQ","email":"45892418+SocialSisterYi@users.noreply.github.com"}]},{"hash":"1ab70f7914d82214aa1a1b8e732a4ac5c37322a4","time":1726676140000,"email":"93977077+MukjepScarlet@users.noreply.github.com","author":"木葉 Scarlet","message":"fix: 优化Kotlin样例 (#1096)"},{"hash":"60a0c5d1a2f44fe61335da04571305fa7727a968","time":1724238159000,"email":"102411014+SessionHu@users.noreply.github.com","author":"Session小胡","message":"feat: 各种接口补充与错误修正 (#1066)"},{"hash":"cb4f767d4ee3f4f66b6caff04c9c40164ea4af54","time":1722218589000,"email":"93977077+MukjepScarlet@users.noreply.github.com","author":"木葉 Scarlet","message":"feat: 添加wbi加签的Kotlin实现, 优化Java实现 (#1068)"},{"hash":"18c1efbc102ae6b44c8f5314c90e5e64f0d926cd","time":1721909032000,"email":"102411014+SessionHu@users.noreply.github.com","author":"Session小胡","message":"feat: bili_ticket 算法 Java 实现 及 信息补充 及 错误修正 (#1061)"},{"hash":"8f419c1c9cdb9b32d6441c735647332ccdb21dd4","time":1721469205000,"email":"amtoaer@outlook.com","author":"ᴀᴍᴛᴏᴀᴇʀ","message":"fix: 修复获取 wbi 签名的 rust 实现 (#1059)"},{"hash":"20940eefcd80ce9e414c8cc3f4d75be1e2db1148","time":1718245920000,"email":"62951481+xrz-cloud@users.noreply.github.com","author":"xrz","message":"feat. wbi签名算法添加typescript实现 (#1031)"},{"hash":"767cb93264eb5d741aff70d35ce12313e7218c15","time":1718245814000,"email":"69023595+stmtc233@users.noreply.github.com","author":"stmtc233","message":"Update wbi.md (#1034)"},{"hash":"e7ab2d770b423a891ed7e663d94bfe1f0f59501d","time":1718245563000,"email":"51024916+YuHuanTin@users.noreply.github.com","author":"YuHuanTin","message":"wbi、av2bv、bv2av 的 c++ 实现 (#1035)"},{"hash":"64e1bde5be5bba4e8c98da4945c08a48d375e437","time":1712071300000,"email":"ivan@hanloth.com","author":"Ivan Hanloth","message":"修复Demo访问/x/web-interface/nav被ban的问题 (#991)"},{"hash":"24397b6601e6249bab15b8f9c17481fbfb4e6d40","time":1702290813000,"email":"70561268+cxw620@users.noreply.github.com","author":"陈寒彤","message":"update wbi sign description (#892)"},{"hash":"27308c22c83e14bb67ac39425574dfbe32aa0b89","time":1702173833000,"email":"45706356+WindowsMEMZ@users.noreply.github.com","author":"Mark Chan","message":"为avid-bvid转换和Wbi签名添加Swift实现 (#890)"},{"hash":"56bfa77a70bab7c14cd829fd9726e560ed122e7f","time":1701615703000,"email":"fwqaaq@gmail.com","author":"fwqaaq","message":"Update wbi.md about rust and javascript code examples for wbi signature implementation (#884)"},{"hash":"86ba55259dfbed8e076a572a4ef416a5b29d4a96","time":1700385876000,"email":"catlair@qq.com","author":"LaMerChiang","message":"Update wbi.md (#866)"},{"hash":"542359a54f9abb4e4a6979088c9d9f75c84a98de","time":1691929891000,"email":"69347367+188102836@users.noreply.github.com","author":"188102836","message":"优化示例代码 (#777)","coAuthors":[{"name":"ud2","email":"sjx233@qq.com"},{"name":"ud2","email":"sjx233@qq.com"}]},{"hash":"56d0126d5d35ac3b02e96edeb751d5a656b8f27e","time":1691719236000,"email":"emkqson@outlook.com","author":"PACI","message":"update io and time (#769)"},{"hash":"d023b55918b3d171eca0e9092f7e55a20a10cf0b","time":1688290621000,"email":"63290381+xiaoyv404@users.noreply.github.com","author":"小宇","message":"Fix language list error (#731)"},{"hash":"fd313b8c1cd2dcbcaf22c5aa68930dbf9354b690","time":1688099263000,"email":"takanashirikkax@gmail.com","author":"7rikka","message":"添加Wbi签名的Java实现 (#726)"},{"hash":"63deb66605188519d6a22b8e9bc396aca72182ad","time":1687947513000,"email":"73207840+lanyeeee@users.noreply.github.com","author":"kurisu_u","message":"给Wbi签名算法的Demo添加C#实现 (#719)","coAuthors":[{"name":"社会易姐QwQ","email":"45892418+SocialSisterYi@users.noreply.github.com"}]},{"hash":"a8742859fc4a41d6a4fabccf56bb70063a15c942","time":1687946222000,"email":"takanashirikkax@gmail.com","author":"7rikka","message":"添加Wbi签名的Java实现 (#722)"},{"hash":"0abdd4b847c8a90e628d41c6fbc4f0a21227b1a5","time":1687499343000,"email":"62145553+vapehacker@users.noreply.github.com","author":"icyu","message":"修改wbi文档中的流程描述 (#718)"},{"hash":"3aaf9679c51eec05c28fe505cd26238e6c2ac303","time":1687307987000,"email":"ywmoyue@163.com","author":"ywmoyue","message":"补充wbi文档 (#706)"},{"hash":"fc0c6874d94f45d97b74c624fa61baeacdace2ca","time":1685870545000,"email":"jannchie@gmail.com","author":"Jianqi Pan","message":"✨ feat: add golang wbi demo (#696)"},{"hash":"7b5ac3f50375310176709dc531d61a1761b6f5d8","time":1685064391000,"email":"me@isoasflus.com","author":"THMonster","message":"修正wbi文档中的一些描述错误 (#684)"},{"hash":"05ac3d5e2a9e28be3bf129ae8c78ffdbebaa161c","time":1684805901000,"email":"1440239038@qq.com","author":"SocialSisterYi","message":"添加文档【Wbi 接口签名】,修改目录结构"}]},"filePathRelative":"docs/misc/sign/wbi.md"}');export{E as comp,m as data};