Skip to content

Commit

Permalink
fix: 迁移 bilibili 用户信息获取接口到可用版本 (#1131)
Browse files Browse the repository at this point in the history
* fix: 迁移 bilibili 用户信息获取接口到可用版本

* fix: 获取 playlist 成功后手动触发脏检查

* fix: 使用 $timeout 替代 $digest 避免同步变更场景下报错

* fix: 改为使用 forge 提供 md5 计算

---------

Co-authored-by: wuhao.igno <wuhao.igno@bytedance.com>
  • Loading branch information
wuhao-igno and wuhao.igno committed Mar 29, 2024
1 parent 50d37c4 commit 29ea74a
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 30 deletions.
5 changes: 4 additions & 1 deletion js/controller/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,10 @@ angular.module('listenone').controller('NavigationController', [
$scope.is_local = data.info.id.slice(0, 2) === 'lm';

MediaService.queryPlaylist(data.info.id, 'favorite').success((res) => {
$scope.is_favorite = res.result;
// success 函数可能在异步回调中执行,需要手动触发脏检查
$timeout(() => {
$scope.is_favorite = res.result;
}, 0);
});

$scope.window_type = 'list';
Expand Down
173 changes: 144 additions & 29 deletions js/provider/bilibili.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
let wbi_key = null;
/* global getParameterByName */
// eslint-disable-next-line no-unused-vars
/* global cookieSet cookieGet */
Expand All @@ -8,6 +9,106 @@ class bilibili {
return parser.parseFromString(value, 'text/html').body.textContent;
}

static fetch_wbi_key() {
return axios({
url: 'https://api.bilibili.com/x/web-interface/nav',
method: 'get',
responseType: 'json',
}).then((resp) => {
const json_content = resp.data;
const { img_url } = json_content.data.wbi_img;
const { sub_url } = json_content.data.wbi_img;
return {
img_key: img_url.slice(
img_url.lastIndexOf('/') + 1,
img_url.lastIndexOf('.')
),
sub_key: sub_url.slice(
sub_url.lastIndexOf('/') + 1,
sub_url.lastIndexOf('.')
),
};
});
}

static clear_wbi_key() {
wbi_key = null;
}

static get_wbi_key() {
if (wbi_key) {
return Promise.resolve(wbi_key);
}
return bilibili.fetch_wbi_key().then((key) => {
wbi_key = key;
return key;
});
}

static enc_wbi(params) {
return bilibili.get_wbi_key().then(({ img_key, sub_key }) => {
const 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 进行字符顺序打乱编码
function get_mixin_key(original) {
let temp = '';
mixinKeyEncTab.forEach((n) => {
temp += original[n];
});
return temp.slice(0, 32);
}

const mixin_key = get_mixin_key(img_key + sub_key);
const curr_time = Math.round(Date.now() / 1000);
const chr_filter = /[!'()*]/g;
const query = [];
Object.assign(params, { wts: curr_time }); // 添加 wts 字段
// 按照 key 重排参数
Object.keys(params)
.sort()
.forEach((key) => {
query.push(
`${encodeURIComponent(key)}=${encodeURIComponent(
// 过滤 value 中的 "!'()*" 字符
params[key].toString().replace(chr_filter, '')
)}`
);
});
const query_string = query.join('&');
const wbi_sign = window.forge.md5
.create()
.update(window.forge.util.encodeUtf8(query_string + mixin_key))
.digest()
.toHex();
return `${query_string}&w_rid=${wbi_sign}`;
});
}

static wrap_wbi_request(url, params) {
return bilibili
.enc_wbi(params)
.then((query_string) => {
const target_url = `${url}?${query_string}`;
return axios.get(target_url);
})
.catch(() => {
// 失败时进行一次清空 wbi_key 后的重试,避免因为 wbi_key 过期导致的错误
bilibili.clear_wbi_key();
return bilibili
.enc_wbi(params)
.then((query_string) => {
const target_url = `${url}?${query_string}`;
return axios.get(target_url);
})
.catch(() => undefined);
});
}

static bi_convert_song(song_info) {
const track = {
id: `bitrack_${song_info.id}`,
Expand Down Expand Up @@ -131,7 +232,7 @@ class bilibili {
const author = response.data.data.owner;
const default_img = response.data.data.pic;
const tracks = response.data.data.pages.map((item) =>
this.bi_convert_song3(item,track_id,author,default_img)
this.bi_convert_song3(item, track_id, author, default_img)
);
return fn({
tracks,
Expand All @@ -142,9 +243,9 @@ class bilibili {
};
}

static bi_convert_song3(song_info,bvid,author,default_img) {
static bi_convert_song3(song_info, bvid, author, default_img) {
let imgUrl = song_info.first_frame;
if (imgUrl === undefined){
if (imgUrl === undefined) {
imgUrl = default_img;
} else if (imgUrl.startsWith('//')) {
imgUrl = `https:${imgUrl}`;
Expand All @@ -166,37 +267,51 @@ class bilibili {

return {
success: (fn) => {
let target_url = `https://api.bilibili.com/x/space/acc/info?mid=${artist_id}&jsonp=jsonp`;
axios.get(target_url).then((response) => {
const info = {
cover_img_url: response.data.data.face,
title: response.data.data.name,
id: `biartist_${artist_id}`,
source_url: `https://space.bilibili.com/${artist_id}/#/audio`,
};
if (getParameterByName('list_id', url).split('_').length === 3) {
target_url = `https://api.bilibili.com/x/space/arc/search?mid=${artist_id}&pn=1&ps=25&order=click&index=1&jsonp=jsonp`;
let target_url;
bilibili
.wrap_wbi_request('https://api.bilibili.com/x/space/wbi/acc/info', {
mid: artist_id,
})
.then((response) => {
const info = {
cover_img_url: response.data.data.face,
title: response.data.data.name,
id: `biartist_${artist_id}`,
source_url: `https://space.bilibili.com/${artist_id}/#/audio`,
};
if (getParameterByName('list_id', url).split('_').length === 3) {
return bilibili
.wrap_wbi_request(
'https://api.bilibili.com/x/space/wbi/arc/search',
{
mid: artist_id,
pn: 1,
ps: 25,
order: 'click',
index: 1,
}
)
.then((res) => {
const tracks = res.data.data.list.vlist.map((item) =>
this.bi_convert_song2(item)
);
return fn({
tracks,
info,
});
});
}
target_url = `https://api.bilibili.com/audio/music-service-c/web/song/upper?pn=1&ps=0&order=2&uid=${artist_id}`;
return axios.get(target_url).then((res) => {
const tracks = res.data.data.list.vlist.map((item) =>
this.bi_convert_song2(item)
const tracks = res.data.data.data.map((item) =>
this.bi_convert_song(item)
);
return fn({
tracks,
info,
});
});
}
target_url = `https://api.bilibili.com/audio/music-service-c/web/song/upper?pn=1&ps=0&order=2&uid=${artist_id}`;
return axios.get(target_url).then((res) => {
const tracks = res.data.data.data.map((item) =>
this.bi_convert_song(item)
);
return fn({
tracks,
info,
});
});
});
},
};
}
Expand Down Expand Up @@ -225,14 +340,14 @@ class bilibili {
let bvid = track.id.slice('bitrack_v_'.length);

const trackIdCheck = trackId.split('-');
if(trackIdCheck.length > 1){
if (trackIdCheck.length > 1) {
bvid = trackIdCheck[0].slice('bitrack_v_'.length);
}
const target_url = `https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`;
return axios.get(target_url).then((response) => {
let { cid } = response.data.data.pages[0];
if(trackIdCheck.length > 1){
[,cid] = trackIdCheck;
if (trackIdCheck.length > 1) {
[, cid] = trackIdCheck;
}
const target_url2 = `http://api.bilibili.com/x/player/playurl?fnval=16&bvid=${bvid}&cid=${cid}`;
axios.get(target_url2).then((response2) => {
Expand Down

1 comment on commit 29ea74a

@listen1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems that bilibili api has changed and artist page is invalid again.

Please sign in to comment.