// ==UserScript==
// @name bilibiliGetExpV2
// @namespace https://iconquestion.github.io
// @version 2.22
// @description (The 2nd version) Automatically finish DAU task at bilibili to get experience point.
// @author ICONQUESTION
// @match https://t.bilibili.com/*
// @icon https://bilibili.com/favicon.ico
// @grant none
// @require https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js
// ==/UserScript==
var urlList = {
checkTasks: 'https://api.bilibili.com/x/member/web/exp/reward',
watchVideo: 'https://api.bilibili.com/x/click-interface/web/heartbeat',
shareVideo: 'https://api.biliapi.net/x/share/finish',
dynamic: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=video&page=1',
videoProperty: 'https://api.bilibili.com/x/player/pagelist',
getAccess_key: 'https://passport.bilibili.com/login/app/third?appkey=1d8b6e7d45233436&api=http://link.acg.tv/forum.php&sign=5f9c0a5c2360c80b858d546a23a4a9dd',
}
//将document.cookie中的'; '替换为'&', 从而满足生成URL对象的条件, 再利用URL对象的searchParam功能完成cookie检索
var cookies = new URL('http://hello.world/test?' + document.cookie.replaceAll('; ', '&'))
var shareVideoDone = cookies.searchParams.get('shareVideoDone'), watchVideoDone = cookies.searchParams.get('watchVideoDone')
var csrftoken = cookies.searchParams.get('bili_jct')
var mid = cookies.searchParams.get('DedeUserID')
var access_key = cookies.searchParams.get('access_key')
//date用来设置记录性cookies过期时间为第二天0:0:0
var date = new Date()
var currentTime = parseInt((date.getTime()) / 1000);
date.setTime(date.getTime() + 3600 * 24 * 1000)
date.setHours(0, 0, 0, 0)
//调试性开关
/*
var debugMode = {
'true': '无论返回数据显示任务是否完成, 都再执行一次',
'false': '根据返回数据情况, 有选择地执行(默认值)'
}
*/
var debugMode = localStorage && localStorage.getItem('debugMode') != undefined ? localStorage.getItem('debugMode') : false
/*
var cookieRecordComesFirst={
'true':'以cookies中的任务完成记录为准(默认值)',
'false':'以fetch请求返回的数据为准'
}
*/
var cookieRecordComesFirst = localStorage && localStorage.getItem('cookieRecordComesFirst') != undefined ? localStorage.getItem('cookieRecordComesFirst') : true
//从这里开始执行
window.onload = async function () {
//1.检查登录态
if (!csrftoken || !mid) {
console.log('csrf或mid不存在, 请登录。如果您已经登录, 请尝试清空cookies后重新登录。')
return;
}
//2.检查可完成的任务, 存储到taskList
if (debugMode) console.log('debug模式已开启')
if (cookieRecordComesFirst) {
console.log('当前模式:cookies记录优先')
var taskList = { 'share': shareVideoDone, 'watch': watchVideoDone }
} else {
console.log('当前模式:fetch请求优先')
var taskList = await checkTasks()
}
console.log(taskList)
if (!debugMode && taskList.share && taskList.watch) {
console.log('所有任务已经完成!')
return
}
//3.从动态列表拉取视频
var videoProp = await grabVideo()
//console.log(videoProp)
//4.1 完成观看视频任务
if (!taskList.watch || debugMode) {
setTimeout(function(){
watchVideo(videoProp)
}, Math.random() * 100000)
} else {
console.log('观看视频任务已经完成!')
}
//4.2 完成分享视频任务
if (!taskList.share || debugMode) {
if (!access_key || access_key == 'null') {
//4.2.1 获取access_key
getAccessKey()
} else {
//4.2.1 分享视频
setTimeout(function(){
shareVideo(videoProp)
}, Math.random() * 100000)
}
} else {
console.log('分享视频任务已经完成!')
}
}
//检查可获得经验值的任务
async function checkTasks() {
console.log('正在检查任务列表')
var data = await fetch(urlList.checkTasks, {
credentials: 'include',
headers: {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
},
}).then(function (res) {
return res.headers.get('Content-Type').search('application/json') != -1 ? res.json() : undefined
}).then(function (data) {
//console.log(data)
if (!data || !data.data) {
throw 'fetch(urlList.checkTasks) 返回数据异常。'
} else {
//传回最内层data(对象)
return data.data
}
})
return data
}
//抓取视频
async function grabVideo() {
console.log('正在抓取视频')
//获取aid,bvid
var videoProp = []
await fetch(urlList.dynamic, {
credentials: 'include',
}).then(function (res) {
return res.headers.get('Content-Type').search('application/json') != -1 ? res.json() : undefined
}).then(function (data) {
//console.log(data)
if (!data || !data.data || !data.data.items || !data.data.items[0].basic.comment_id_str || !data.data.items[0].modules.module_dynamic.major.archive.bvid) {
throw ('fetch(urlList.dynamic) 返回数据类型异常, 或返回列表为空, 或相应数据不存在')
}
videoProp[0] = data.data.items[0].basic.comment_id_str
videoProp[1] = data.data.items[0].modules.module_dynamic.major.archive.bvid
})
//获取cid
await fetch(urlList.videoProperty + '?bvid=' + videoProp[1] + '&jsonp=jsonp', {
method: 'GET',
credentials: 'include',
headers: {
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
},
}).then(function (res) {
return res.headers.get('Content-Type').search('application/json') != -1 ? res.json() : undefined
}).then(function (data) {
//console.log(data)
if (!data || !data.data || !data.data[0].cid) {
throw 'fetch(urlList.videoProperty) 返回数据类型异常, 或相应数据不存在'
}
videoProp[2] = data.data[0].cid
})
console.log('获取到以下视频数据: aid=' + videoProp[0] + ', bvid=' + videoProp[1] + ', cid=' + videoProp[2])
return videoProp
}
//获取access_key
async function getAccessKey() {
console.log('access_key不存在, 正在获取新access_key');
await fetch(urlList.getAccess_key, {
credentials: 'include',
}).then(function (res) {
return res.headers.get('Content-Type').search('application/json') != -1 ? res.json() : undefined
}).then(function (data) {
//console.log(data)
if (!data || !data.data || !data.data.confirm_uri) {
throw 'fetch(urlList.getAccess_key) 返回数据异常'
}
console.log('请右键以下链接, 点击"在新标签页中打开", 然后复制查询字符串中的access_key字段, 粘贴到对话框中')
console.log(data.data.confirm_uri)
var input1 = prompt('请打开浏览器控制台, 右键最下方的链接, 点击"在新标签页中打开", 然后复制查询字符串中的access_key字段, 粘贴到这里');
if (input1) {
document.cookie = 'access_key=' + input1 + '; max-age=15552000; domain=.bilibili.com';
console.log('access_key已存储. 请刷新此页面以重新运行该脚本. 若需再次更改access_key, 您可手动访问浏览器的Cookies存储设置.')
} else {
console.log('用户已取消操作。')
}
})
}
//这个...不用解释了吧
function shareVideo(videoProp) {
if (!access_key) {
console.log('缺少access_key, 无法分享视频')
return;
}
var aid = videoProp[0], bvid = videoProp[1], cid = videoProp[2]
//share_session_id生成方式和作用未知, 欢迎补充!
var body = 'access_key=' + access_key + '&appkey=1d8b6e7d45233436&build=6800300&c_locale=zh_CN&channel=bili&disable_rcmd=0&from_spmid=dt.dt.video.0&mobi_app=android&oid=' + aid + '&panel_type=1&platform=android&s_locale=zh_CN&share_channel=biliDynamic&share_id=main.ugc-video-detail.0.0.pv&share_origin=vinfo_share&share_session_id=' + '6609bb15-ac05-4118-8f12-cb' + currentTime + '&sid=' + cid + '&spm_id=main.ugc-video-detail.0.0&statistics=%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%226.80.0%22%2C%22abtest%22%3A%22%22%7D&success=true&ts=' + currentTime + '&sign='
body = body + md5(body + '560c52ccd288fed045859ed18bffd973')
console.log('正在分享视频, aid=' + aid)
fetch(urlList.shareVideo, {
method: 'post',
mode: 'cors',
//referrer: "no-referrer",
headers: {
//'Buvid': 'XXAF685A25ED66209F45C4248C26054E197A8',
//'Fp_local': '9ca222f943ae8680669b6cdf2da959e120220715131357006bc66326e8302881',
//'Fp_remote': '9ca222f943ae8680669b6cdf2da959e1202207131056235c836389e254a11b4e',
//'Session_id': '831ec2b1',//暂时不知道如何处理
//'Env': 'prod',
//'App-Key': 'android',
//'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/109.0.0.0',
//'X-Bili-Trace-Id': '390743e355a59747842729ca1962d222:8427c9ca1962d222:0:0',//暂时不知道如何处理
//'X-Bili-Aurora-Eid': 'UlYITlUAD1ID',
//'X-Bili-Mid': mid,
//'X-Bili-Aurora-Zone': '',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
//'Accept-Encoding': 'gzip',
},
body: body,
}).then(function (res) {
return res.headers.get('Content-Type').search('application/json') != -1 ? res.json() : undefined
}).then(function (data) {
//console.log(data)
if (!data) {
console.log('fetch(urlList.shareVideo) 返回数据异常')
return
}
//每天第一次分享, 返回的toast不为空, 之后的分享toast为空
console.log(data.data.toast ? data.data.toast : '分享视频任务成功完成')
document.cookie = 'shareVideoDone=true; expires=' + date.toGMTString()
})
}
//观看视频
function watchVideo(videoProp) {
var aid = videoProp[0], bvid = videoProp[1], cid = videoProp[2]
console.log('正在观看视频, aid=' + aid + ', bvid=' + bvid + ', cid=' + cid)
fetch(urlList.watchVideo, {
method: 'post',
credentials: 'include',
headers: {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Content-Type': 'application/x-www-form-urlencoded'
},
body:
'aid=' + aid + '&cid=' + cid + '&bvid=' + bvid + '&mid=' + mid + '&csrf=' + csrftoken + '&played_time=11&real_played_time=12&realtime=11&start_ts=' + currentTime + '&type=3&dt=2&play_type=2&from_spmid=444.41.list.card_archive.click&spmid=333.788.0.0&auto_continued_play=0&refer_url=https%3A%2F%2Ft.bilibili.com%2F%3Ftab%3Dvideo&bsource='
}).then(function (res) {
return res.headers.get('Content-Type').search('application/json') != -1 ? res.json() : undefined
}).then(function (data) {
//console.log(data)
if (!data) {
console.log('fetch(urlList.watchVideo) 返回数据异常')
return
}
//正常情况返回string'0', 否则返回具体信息
console.log(data.message == '0' ? '观看视频任务成功完成' : data.message)
document.cookie = 'watchVideoDone=true; expires=' + date.toGMTString()
})
}