From 0619e8245563335095cfcecaf00ec83e60062778 Mon Sep 17 00:00:00 2001 From: lzghzr Date: Mon, 29 Jan 2018 17:02:08 +0800 Subject: [PATCH] fix #56 --- bilive/lib/app_client.ts | 85 ++++++++++++++++++++++++++++++++++------ bilive/lib/tools.ts | 35 +++++++---------- bilive/listener.ts | 2 +- bilive/online.ts | 2 +- package.json | 2 +- 5 files changed, 92 insertions(+), 34 deletions(-) diff --git a/bilive/lib/app_client.ts b/bilive/lib/app_client.ts index 0257647..2ca8485 100644 --- a/bilive/lib/app_client.ts +++ b/bilive/lib/app_client.ts @@ -31,7 +31,7 @@ class AppClient { // bilibili 客户端 private static readonly __secretKey: string = '560c52ccd288fed045859ed18bffd973' public static readonly appKey: string = '1d8b6e7d45233436' - public static readonly build: string = '521200' + public static readonly build: string = '5220000' public static readonly mobiApp: string = 'android' // bilibili 国际版 // private static readonly __secretKey: string = '36efcfed79309338ced0380abd824ac1' @@ -85,17 +85,19 @@ class AppClient { */ public static get baseQuery(): string { return `actionKey=${this.actionKey}&appkey=${this.appKey}&build=${this.build}\ -&mobi_app=${this.mobiApp}&platform=${this.platform}&ts=${this.TS}` +&mobi_app=${this.mobiApp}&platform=${this.platform}` } /** * 对参数签名 * * @static - * @param {string} params - * @returns {string} + * @param {string} params + * @param {boolean} [ts=true] + * @returns {string} * @memberof AppClient */ - public static signQuery(params: string): string { + public static signQuery(params: string, ts = true): string { + if (ts) params = `${params}&ts=${this.TS}` const paramsSecret = params + this.__secretKey const paramsHash = tools.Hash('md5', paramsSecret) return `${params}&sign=${paramsHash}` @@ -176,9 +178,9 @@ class AppClient { * @memberof AppClient */ public headers: request.Headers = { - 'Buvid': '7A4C4919-20A6-4012-BBA4-6FAA1561542845107infoc', 'Connection': 'Keep-Alive', - 'User-Agent': 'Mozilla/5.0 BiliDroid/5.21.0 (bbcallen@gmail.com)' + 'Device-ID': 'Pwc3BzUCYwJjUWAGegZ6', + 'User-Agent': 'Mozilla/5.0 BiliDroid/5.22.0 (bbcallen@gmail.com)' } /** * cookieJar @@ -240,7 +242,7 @@ class AppClient { const auth: request.Options = { method: 'POST', uri: 'https://passport.bilibili.com/api/v2/oauth2/login', - body: AppClient.signQuery(authQuery), + body: AppClient.signQuery(authQuery, false), jar: this.__jar, json: true, headers: this.headers @@ -272,9 +274,22 @@ class AppClient { * @memberof AppClient */ public async init() { - const buvid = await tools.XHR({ uri: 'http://data.bilibili.com/gv/' }, 'Android') - if (buvid !== undefined && buvid.response.statusCode === 200 && buvid.body.length === 46) + // 设置 Buvid + const buvid = await tools.XHR({ + uri: 'http://data.bilibili.com/gv/', + headers: this.headers + }, 'Android') + if (buvid !== undefined && buvid.response.statusCode === 200 && buvid.body.endsWith('infoc')) this.headers['Buvid'] = buvid.body + // 设置 Display-ID + const displayid = await tools.XHR<{ code: number, data: { id: string } }>({ + uri: 'http://app.bilibili.com/x/v2/display/id?' + AppClient.signQueryBase(), + json: true, + headers: this.headers + }, 'Android') + if (displayid !== undefined && displayid.response.statusCode === 200 + && displayid.body.code === 0 && displayid.body.data.id.length > 20) + this.headers['Display-ID'] = displayid.body.data.id } /** * 获取验证码 @@ -316,6 +331,28 @@ class AppClient { } return { status: status.httpError, data: getKeyResponse } } + /** + * 客户端登出 + * + * @returns {Promise} + * @memberof AppClient + */ + public async logout(): Promise { + const revokeQuery = `${this.cookieString.replace(/; */g, '&')}&access_token=${this.accessToken}` + const revoke: request.Options = { + method: 'POST', + uri: 'https://passport.bilibili.com/api/v2/oauth2/revoke', + body: AppClient.signQueryBase(revokeQuery), + json: true, + headers: this.headers + } + const revokeResponse = await tools.XHR(revoke, 'Android') + if (revokeResponse !== undefined && revokeResponse.response.statusCode === 200) { + if (revokeResponse.body.code === 0) return { status: status.success, data: revokeResponse.body } + return { status: status.error, data: revokeResponse.body } + } + return { status: status.httpError, data: revokeResponse } + } /** * 更新access_token * @@ -324,7 +361,7 @@ class AppClient { */ public async refresh(): Promise { const refreshQuery = `access_token=${this.accessToken}&appkey=${AppClient.appKey}&build=${AppClient.build}\ -&mobi_app=${AppClient.mobiApp}&platform=${AppClient.platform}&refresh_token=${this.refreshToken}&ts=${AppClient.TS}` +&mobi_app=${AppClient.mobiApp}&platform=${AppClient.platform}&refresh_token=${this.refreshToken}` const refresh: request.Options = { method: 'POST', uri: 'https://passport.bilibili.com/api/v2/oauth2/refresh_token', @@ -388,6 +425,16 @@ interface authResponseTokeninfo { refresh_token: string expires_in: number } +/** + * 注销返回 + * + * @interface revokeResponse + */ +interface revokeResponse { + message: string + ts: number + code: number +} /** * 登录返回信息 */ @@ -408,6 +455,22 @@ interface loginResponseHttp { status: status.httpError data: tools.response | tools.response | undefined } +/** + * 登出返回信息 + */ +type logoutResponse = revokeResponseSuccess | revokeResponseError | revokeResponseHttp +interface revokeResponseSuccess { + status: status.success + data: revokeResponse +} +interface revokeResponseError { + status: status.error + data: revokeResponse +} +interface revokeResponseHttp { + status: status.httpError + data: tools.response | undefined +} /** * 验证码返回信息 */ diff --git a/bilive/lib/tools.ts b/bilive/lib/tools.ts index be4956d..7284df0 100644 --- a/bilive/lib/tools.ts +++ b/bilive/lib/tools.ts @@ -1,7 +1,4 @@ import * as fs from 'fs' -import * as dns from 'dns' -import * as net from 'net' -import * as http from 'http' import * as util from 'util' import * as crypto from 'crypto' import * as request from 'request' @@ -18,7 +15,7 @@ function getHeaders(platform: string): request.Headers { case 'Android': return { 'Connection': 'Keep-Alive', - 'User-Agent': 'Mozilla/5.0 BiliDroid/5.21.0 (bbcallen@gmail.com)' + 'User-Agent': 'Mozilla/5.0 BiliDroid/5.22.0 (bbcallen@gmail.com)' } case 'WebView': return { @@ -27,7 +24,7 @@ function getHeaders(platform: string): request.Headers { 'Connection': 'keep-alive', 'Cookie': 'l=v', 'Origin': liveOrigin, - 'User-Agent': 'Mozilla/5.0 (Linux; Android 7.1.1; E6883 Build/32.4.A.1.54; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36 BiliApp/1', + 'User-Agent': 'Mozilla/5.0 (Linux; Android 7.1.1; E6883 Build/32.4.A.1.54; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.119 Mobile Safari/537.36 BiliApp/5220000', 'X-Requested-With': 'tv.danmaku.bili' } default: @@ -38,7 +35,7 @@ function getHeaders(platform: string): request.Headers { 'Cookie': 'l=v', 'DNT': '1', 'Origin': liveOrigin, - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36' } } } @@ -49,20 +46,9 @@ function getHeaders(platform: string): request.Headers { */ class IP { constructor() { - // @ts-ignore 此处为d.ts错误 - this.httpAgent.createConnection = (options: net.NetConnectOpts, callback: Function): net.Socket => { - // @ts-ignore ts对于联合类型的推断还在讨论中 - options.lookup = (hostname, options, callback) => { - const ip = this.ip - if (ip === '') return dns.lookup(hostname, options, callback) - return callback(null, ip, 4) - } - return net.createConnection(options, callback) - } } public IPs: Set = new Set() private __IPiterator: IterableIterator = this.IPs.values() - public httpAgent = new http.Agent() public get ip(): string { if (this.IPs.size === 0) return '' const ip = this.__IPiterator.next() @@ -78,8 +64,9 @@ const api = new IP() * 测试可用ip * * @param {string[]} apiIPs + * @returns {Promise} */ -async function testIP(apiIPs: string[]) { +async function testIP(apiIPs: string[]): Promise { const test: Promise[] = [] apiIPs.forEach(ip => { const headers = getHeaders('PC') @@ -98,7 +85,9 @@ async function testIP(apiIPs: string[]) { })) }) await Promise.all(test) - Log('可用ip数量为', api.IPs.size) + const num = api.IPs.size + Log('可用ip数量为', num) + return num } const shortRoomID = new Map() const longRoomID = new Map() @@ -133,7 +122,13 @@ function XHR(options: request.OptionsWithUri, platform: 'PC' | 'Android' | 'W return new Promise | undefined>(resolve => { options.gzip = true // 添加用户代理 - if (typeof options.uri === 'string' && options.uri.startsWith(apiLiveOrigin)) options.agent = api.httpAgent + if (typeof options.uri === 'string' && options.uri.startsWith(apiLiveOrigin)) { + const ip = api.ip + if (ip !== '') { + options.proxy = `http://${ip}/` + options.tunnel = false + } + } // 添加头信息 const headers = getHeaders(platform) options.headers = options.headers === undefined ? headers : Object.assign(headers, options.headers) diff --git a/bilive/listener.ts b/bilive/listener.ts index 74dc4e0..eaaa407 100644 --- a/bilive/listener.ts +++ b/bilive/listener.ts @@ -3,7 +3,7 @@ import { EventEmitter } from 'events' import * as tools from './lib/tools' import AppClient from './lib/app_client' import DMclient from './dm_client_re' -import { liveOrigin, apiLiveOrigin, smallTVPathname, rafflePathname, _options, _user } from './index' +import { liveOrigin, apiLiveOrigin, smallTVPathname, rafflePathname, _options } from './index' /** * 监听服务器消息 * diff --git a/bilive/online.ts b/bilive/online.ts index 64c043e..f6ff10a 100644 --- a/bilive/online.ts +++ b/bilive/online.ts @@ -93,7 +93,7 @@ class Online extends AppClient { */ public async getOnlineInfo(roomID = _options.config.defaultRoomID): Promise<'captcha' | 'stop' | void> { const isLogin = await tools.XHR<{ code: number }>({ - uri: 'https://live.bilibili.com/user/getuserinfo', + uri: `${liveOrigin}/user/getuserinfo`, jar: this.jar, json: true, headers: { 'Referer': `${liveOrigin}/${tools.getShortRoomID(roomID)}` } diff --git a/package.json b/package.json index 6234882..d0d08b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bilive_client", - "version": "1.3.3", + "version": "1.3.4", "description": "基于Node.JS的bilibili直播挂机系统", "main": "index.js", "scripts": {