BilibiliExp

B 站经验助手,自动投币视频、模拟移动端分享、经验获取统计、升级时间估计

目前为 2019-11-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name BilibiliExp
  3. // @namespace BilibiliExp
  4. // @match *://www.bilibili.com/video/*
  5. // @version 1.0
  6. // @author Dreace
  7. // @license GPL-3.0
  8. // @description B 站经验助手,自动投币视频、模拟移动端分享、经验获取统计、升级时间估计
  9. // @grant GM.xmlHttpRequest
  10. // @grant unsafeWindow
  11. // @require https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
  12. // @require https://static.hdslb.com/js/md5.js
  13. // ==/UserScript==
  14. // file:///C:/WorkSpace/JavaScript/BilibiliExp/main.js
  15. (function () {
  16. 'use strict';
  17. const coinUrl = "https://api.bilibili.com/x/web-interface/nav?build=0&mobi_app=web"
  18. const addCoinUrl = "https://api.bilibili.com/x/web-interface/coin/add"
  19. const shareUrl = "https://app.bilibili.com/x/v2/view/share/complete"
  20. const shareUrlPre = "https://app.bilibili.com/x/v2/view/share/click"
  21. const rewardUrl = "https://account.bilibili.com/home/reward"
  22. let totalCoin = 0
  23. let expToday = 0
  24. let aid = ""
  25. let bili_jct = getCookie("bili_jct")
  26. try {
  27. aid = unsafeWindow.vd ? unsafeWindow.vd.aid : unsafeWindow.aid
  28. } catch (error) {
  29. console.log("aid 获取失败")
  30. return
  31. }
  32. function addCoin() {
  33. return biliAjax({
  34. url: addCoinUrl,
  35. type: 'POST',
  36. dataType: 'json',
  37. data: {
  38. aid: aid,
  39. multiply: "1",
  40. select_like: 0,
  41. cross_domain: true,
  42. csrf: bili_jct
  43. },
  44. })
  45. }
  46. if (aid) {
  47. gmAjax({
  48. url: rewardUrl,
  49. methon: 'GET',
  50. }).then((res) => {
  51. if (res.code == 0) {
  52. expToday = 50 - res.data.coins_av
  53. } else {
  54. console.log("等级信息获取失败");
  55. return
  56. }
  57. })
  58. gmAjax({
  59. url: rewardUrl,
  60. methon: 'GET',
  61. }).then((res) => {
  62. if (res.code == 0) {
  63. expToday = 50 - res.data.coins_av
  64. if (!res.data.share_av) {
  65. let shareData = {
  66. access_key: bili_jct,
  67. actionKey: "appkey",
  68. aid: aid,
  69. appkey: "27eb53fc9058f8c3",
  70. build: "8960",
  71. device: "phone",
  72. epid: "",
  73. from: "711",
  74. mobi_app: "iphone",
  75. platform: "ios",
  76. season_id: "",
  77. share_channel: "qq",
  78. share_trace_id: hex_md5(new Date()),
  79. statistics: "%7B%22appId%22%3A1%2C%22version%22%3A%225.50.1%22%2C%22abtest%22%3A%22890%22%2C%22platform%22%3A1%7D",
  80. ts: new Date().getTime(),
  81. }
  82. let signed = get_sign(shareData, "c2ed53a74eeefe3cf99fbd01d8c9c375")
  83. GM.xmlHttpRequest({
  84. method: "POST",
  85. url: shareUrl,
  86. data: signed.data + "&sign=" + signed.sign,
  87. headers: {
  88. "Content-Type": "application/x-www-form-urlencoded"
  89. },
  90. onload: function (response) {
  91. let res = JSON.parse(response.responseText)
  92. if (res.code == 0) {
  93. GM.xmlHttpRequest({
  94. method: "POST",
  95. url: shareUrlPre,
  96. data: signed.data + "&sign=" + signed.sign,
  97. headers: {
  98. "Content-Type": "application/x-www-form-urlencoded"
  99. },
  100. onload: function (response) {
  101. let res = JSON.parse(response.responseText)
  102. console.log(res.data.toast)
  103. }
  104. });
  105. }
  106. }
  107. });
  108.  
  109. }
  110. } else {
  111. console.log("等级信息获取失败");
  112. }
  113. }).then(() => {
  114. return biliAjax({
  115. url: coinUrl,
  116. type: 'GET',
  117. dataType: 'json',
  118. })
  119. }).then((res) => {
  120. totalCoin = res.data.money
  121. console.log("当前硬币 " + totalCoin + " 个")
  122. if (totalCoin < 50) {
  123. console.log("硬币小于 50,暂不投币")
  124. } else {
  125. if (expToday == 0) {
  126. console.log("今日已获取全部经验")
  127. }
  128. return new Promise(function (resolve, reject) {
  129. setTimeout(() => {
  130. resolve()
  131. }, 10000);
  132. })
  133. }
  134. }).then(() => {
  135. if (totalCoin >= 50 && expToday > 0) {
  136. console.log("准备投币")
  137. return addCoin()
  138. }
  139. }).then((res) => {
  140. if (res && res.code == 0) {
  141. console.log("投了一个币")
  142. expToday -= 10
  143. if (expToday > 0) {
  144. return addCoin()
  145. }
  146. }
  147. }).then((res) => {
  148. if (res && res.code == 0) {
  149. console.log("又投了一个币")
  150. }
  151. return gmAjax({
  152. url: rewardUrl,
  153. methon: 'GET',
  154. })
  155. }).then((res) => {
  156. if (res.code == 0) {
  157. let rewardInfo = res.data
  158. let link = document.createElement('link');
  159. link.rel = 'stylesheet';
  160. link.href = "//at.alicdn.com/t/font_1537779_4srood2g1uk.css";
  161. document.body.appendChild(link);
  162. let style = "color: inherit;display: inline-block;line-height: 1;"
  163. let spansData = []
  164. let total = 0
  165. total += rewardInfo.login ? 5 : 0
  166. spansData.push({
  167. ok: rewardInfo.login,
  168. name: "每日登录",
  169. text: `${rewardInfo.login ? 5 : 0}/5`,
  170. className: "icon-login"
  171. })
  172. total += rewardInfo.share_av ? 5 : 0
  173. spansData.push({
  174. ok: rewardInfo.share_av,
  175. name: "分享视频",
  176. text: `${rewardInfo.share_av ? 5 : 0}/5`,
  177. className: "icon-share"
  178. })
  179. total += rewardInfo.watch_av ? 5 : 0
  180. spansData.push({
  181. ok: rewardInfo.watch_av,
  182. name: "观看视频",
  183. text: `${rewardInfo.watch_av ? 5 : 0}/5`,
  184. className: "icon-play"
  185. })
  186. total += rewardInfo.coins_av
  187. spansData.push({
  188. ok: rewardInfo.coins_av == 50,
  189. name: "视频投币",
  190. text: `${rewardInfo.coins_av}/50`,
  191. className: "icon-coin"
  192. })
  193. spansData.push({
  194. ok: total == 65,
  195. name: "总计",
  196. text: `${total}/65`,
  197. className: "icon-total"
  198. })
  199. spansData.push({
  200. ok: false,
  201. name: `最快到 ${rewardInfo.level_info.current_level + 1} 级剩余天数`,
  202. text: `${Math.ceil((rewardInfo.level_info.next_exp - rewardInfo.level_info.current_exp) / 65)} 天`,
  203. className: "icon-day"
  204. })
  205. let bar = document.getElementById("arc_toolbar_report")
  206. bar.style.height = "60px"
  207. let ops = document.createElement('div')
  208. ops.className = "ops"
  209.  
  210. spansData.forEach((item) => {
  211. let span = document.createElement("span")
  212. if (item.ok) {
  213. span.style = "color:rgb(251, 114, 153);"
  214. } else {
  215. span.style = "color:rgb(80, 80, 80);"
  216. }
  217. span.title = item.name
  218. span.innerHTML = `<i class="${item.className} iconfont" style="${style}"></i>${item.text}`
  219. ops.appendChild(span.cloneNode(true))
  220. })
  221. ops.style.marginTop = "10px"
  222. bar.appendChild(ops)
  223. }
  224. })
  225. }
  226. })();
  227. function gmAjax(opt) {
  228. return new Promise((resolve, reject) => {
  229. GM.xmlHttpRequest({
  230. method: opt.methon,
  231. url: opt.url,
  232. data: opt.data ? opt.data : "",
  233. headers: opt.headers ? opt.headers : "",
  234. onload: function (response) {
  235. let res = JSON.parse(response.responseText)
  236. resolve(res)
  237. },
  238. onError: function (error) {
  239. reject(error)
  240. }
  241. });
  242. })
  243. }
  244. function request(opt) {
  245. return $.ajax(opt)
  246. }
  247. function createPromise() {
  248. return $.Deferred()
  249. }
  250. function biliAjax(opt) {
  251. let req
  252. opt.xhrFields = {
  253. withCredentials: true
  254. }
  255. opt.crossDomain = true
  256. let defer = createPromise()
  257. req = request(opt)
  258. req.done(function (d) {
  259. defer.resolve(d)
  260. })
  261. req.fail(d => {
  262. defer.reject(d)
  263. })
  264.  
  265. return defer
  266. }
  267. function get_sign(params, key) {
  268. var s_keys = []
  269. for (var i in params) {
  270. s_keys.push(i)
  271. }
  272. s_keys.sort()
  273. var data = ""
  274. for (var i = 0; i < s_keys.length; i++) {
  275. data += (data ? "&" : "") + s_keys[i] + "=" + params[s_keys[i]]
  276. }
  277. return { sign: hex_md5(data + key), data: data }
  278. }
  279. function getCookie(cname) {
  280. var name = cname + "=";
  281. var ca = document.cookie.split(';');
  282. for (var i = 0; i < ca.length; i++) {
  283. var c = ca[i].trim();
  284. if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
  285. }
  286. return "";
  287. }