Auto_Award_Muli

Steam自动打赏 — 极速多账户版

目前為 2023-05-16 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Auto_Award_Muli
  3. // @name:zh-CN Steam自动打赏【极速多账户版】
  4. // @namespace https://blog.chrxw.com
  5. // @version 1.7
  6. // @description Steam自动打赏 — 极速多账户版
  7. // @description:zh-CN Steam自动打赏 — 极速多账户版
  8. // @author Chr_
  9. // @include /^https:\/\/steamcommunity\.com\/id\/[^/]+/?$/
  10. // @include /^https:\/\/steamcommunity\.com\/profiles\/\d+/?$/
  11. // @connect steamcommunity.com
  12. // @connect steampowered.com
  13. // @license AGPL-3.0
  14. // @icon https://blog.chrxw.com/favicon.ico
  15. // @grant GM_setValue
  16. // @grant GM_getValue
  17. // @grant GM_xmlhttpRequest
  18. // @grant GM_addStyle
  19. // @grant GM_setClipboard
  20. // @grant GM_registerMenuCommand
  21. // ==/UserScript==
  22.  
  23. (() => {
  24. 'use strict';
  25.  
  26. // 多语言
  27. const LANG = {
  28. 'ZH': {
  29. 'done': '完成',
  30. 'changeLang': '修改语言',
  31. 'langName': '中文',
  32. 'operating': '操作进行中……',
  33. 'runningLog': '运行日志',
  34. 'close': '关闭',
  35. 'logWaring': '【日志不会保存, 打赏记录可以在【打赏历史】中查看】',
  36. 'botListTitle': '【机器人账户管理】【ID | 账户名 | SteamID | 点数余额】',
  37. 'addCurrentAccount': '添加当前账号',
  38. 'delSelectAccount': '删除选中账号',
  39. 'reloadAccountPoints': '刷新所有账号点数',
  40. 'historyTitle': '【点数打赏历史记录】【ID | 昵称 | SteamID | 收到点数】',
  41. 'profile': '个人资料',
  42. 'deleteSelectedHistory': '删除选中',
  43. 'clearHistory': '清空历史',
  44. 'reloadHistory': '刷新历史',
  45. 'feedBack': '作者',
  46. 'feedBackTitle': '觉得好用也欢迎给我打赏',
  47. 'notSelected': '---未选择---',
  48. 'steamID64': 'Steam 64位 ID',
  49. 'awardPoints': '打赏点数(收到)',
  50. 'recommands': '评测',
  51. 'screenshots': '截图',
  52. 'artworks': '艺术作品',
  53. 'setToCurrentUser': '设置为当前用户',
  54. 'calculator': '打赏计算器',
  55. 'save': '保存',
  56. 'reset': '重置',
  57. 'awardHistory': '打赏历史',
  58. 'startAward': '开始打赏',
  59. 'stopAward': '停止打赏',
  60. 'stop': '停止',
  61. 'senderBotAccount': '打赏机器人账户: ',
  62. 'receverAccount': '被打赏人SteamID: ',
  63. 'sendPoints': '打赏点数(收到): ',
  64. 'awardPrefer': '打赏类型(优先级从上到下从左到右): ',
  65. 'botList': '机器人列表',
  66. 'fetchLoginAccount': '获取登陆账户……',
  67. 'fetchToken': '获取Token……',
  68. 'fetchPoints': '获取点数信息……',
  69. 'success': '成功',
  70. 'failure': '失败',
  71. 'error': '错误',
  72. 'confirm': '确认',
  73. 'tips': '提示',
  74. 'addAccountSuccessTips1': '添加账户成功',
  75. 'addAccountSuccessTips2': '当前账户可用点数',
  76. 'deleteAccountConfirmTips': '确定要删除选定的账号吗?',
  77. 'deleteAccountDoneTips1': '删除了',
  78. 'deleteAccountDoneTips2': '个机器人',
  79. 'notSelectedAnyBotsTips': '尚未选中任何机器人!',
  80. 'currentProcess': '当前进度',
  81. 'updateFailed': '更新出错',
  82. 'fetchingAccountPoints': '读取账户点数中……',
  83. 'allDataLoaded': '所有数据刷新完毕',
  84. 'someDataLoadFailed': '部分数据刷新失败, 如果点数显示为【-1】,代表数据刷新失败',
  85. 'botListEmpty': '机器人列表为空',
  86. 'noBotAccountTips': '-- 无机器人账号, 请使用【➕添加当前账号】自动添加 --',
  87. 'awardTaskWasResetTips': '机器人账号已修改, 打赏设置已重置!',
  88. 'noHistoryTips': '-- 无历史记录, 执行打赏任务后会自动记录 --',
  89. 'steamIDisEmpty': '未填入SteamID!',
  90. 'fetchingProfile': '获取个人资料中……',
  91. 'fetchingAwardableItems': '获取可打赏项目……',
  92. 'fetchError': '读取出错',
  93. 'awardableAmount': '可打赏约',
  94. 'nickName': '用户名',
  95. 'totalPoints': '总计点数',
  96. 'calcTips': '根据项目数量计算所得, 不准确',
  97. 'profileNotExistsTips': '个人资料不存在, 请检查SteamID是否正确, 或者使用【🤵设置为当前用户】自动获取。',
  98. 'profileLoadFailedTips': '网络错误, 读取个人资料失败',
  99. 'notSelectedAnyHistoryTips': '未选中历史记录!',
  100. 'clearHistoryConfirmTips': '确定要清除打赏历史记录吗?',
  101. 'clearHistorySuccess': '清除成功',
  102. 'historyListEmpty': '历史记录是空的!',
  103. 'deleteHistoryConfirmTips': '确定要删除选定的打赏历史记录吗?',
  104. 'deleteResultTips1': '删除了',
  105. 'deleteResultTips2': '条打赏历史记录',
  106. 'notSelectedAwardBotsTips': '尚未选择打赏机器人!',
  107. 'steamIDEmptyWithTips': '未填写【被打赏人SteamID】, 建议使用【🤵设置为当前用户】功能!',
  108. 'steamIDErrorWithTips': '【被打赏人SteamID】格式有误, 建议使用【🤵设置为当前用户】功能!',
  109. 'pointsErrorWithTips': '【打赏点数】格式有误, 只能为整数!',
  110. 'awardTypeEmptyTips': '请选择【打赏类型】!',
  111. 'awardReadyToStartTips': '设置保存成功, 可以【✅开始打赏】了',
  112. 'resetConfigConfirmTips': '确定要重置设定吗?',
  113. 'configResetSuccessTips': '设置已清除',
  114. 'awardTaskDataInvalid': '任务数据非法',
  115. 'fetchingTargetProfile': '读取被打赏人个人资料……',
  116. 'awardConfig': '打赏设置',
  117. 'targetNickName': '被打赏人昵称',
  118. 'targetReceivePoints': '预计收到点数',
  119. 'targetBot': '打赏机器人',
  120. 'taskReadyToStartTips': '打赏任务【2秒】后开始, 点击【⛔停止打赏】可以提前终止操作!',
  121. 'taskFailedProfileNotFound': '未找到个人资料, 打赏进程停止!',
  122. 'taskAlreadyStartTips': '打赏任务已经开始了!',
  123. 'taskEndManually': '打赏任务手动终止, 点击【❌关闭】可以关闭面板.',
  124. 'taskNotStart': '打赏任务未开始!',
  125. 'running': '运行',
  126. 'taskStartPointsSummary': '开始打赏, 剩余打赏 / 预计打赏',
  127. 'fetchAwardItemFailedRetry': '获取打赏项目失败, 重试……',
  128. 'fetchNoAwardItemSkip': '没有合适的打赏, 跳过……',
  129. 'beforeSendAward': '将要打赏',
  130. 'itemAndTotal': '项, 总计',
  131. 'points': '点',
  132. 'sendingAwards': '发送打赏中……',
  133. 'fetchSuccessAndFailed': '请求成功 / 请求失败',
  134. 'fetchAwardItemFailedRetryIn2Min': '获取打赏项目失败, 【2秒】后重试……',
  135. 'awardSuccess': '成功打赏',
  136. 'taskFinishedPointsSummary': '打赏完成, 剩余打赏 / 预计打赏',
  137. 'updateBotPointsBalance': '更新机器人点数余额……',
  138. 'bot': '机器人',
  139. 'pointsBalanceUpdateSuccess': '点数余额更新成功, 可用点数',
  140. 'lackOfPointsTaskEnd': '点数余额不足, 终止操作',
  141. 'pointBalanceUpdateFailed': '点数余额更新失败',
  142. 'fetchAwardItemFailedSkip': '获取打赏项目失败, 跳过……',
  143. 'taskEndListEmpty': '列表为空, 结束',
  144. 'fetchCompletedTotal': '获取成功, 共',
  145. 'entries': '个',
  146. 'objectID': '项目ID',
  147. 'noAwardableObjectSkip': '没有合适的打赏, 跳过',
  148. 'willAward': '将要打赏',
  149. 'requestsSummary': '请求成功 / 请求失败',
  150. 'wait2Seconds': '*等待2秒,防止打赏过多*',
  151. 'botDataError': '机器人数据错误, 无法开始打赏!',
  152. 'awardTaskFinish': '✅打赏任务完成, 点击【❌关闭】可以关闭面板。',
  153. 'awardTaskNotFinish': '⛔打赏任务未完成, 点击【❌关闭】可以关闭面板。',
  154. 'cancel': '取消',
  155. 'steamStoreNotLogin': '【STEAM商店】未登录(不可用),请重新登录(不可用)',
  156. 'parseDataFailedMaybeNetworkError': '解析数据失败, 可能是Token失效或者网络错误',
  157. 'typeError': 'type错误',
  158. 'networkError': '网络错误',
  159. 'parseError': '解析出错',
  160. 'importAccount': '手动导入账号',
  161. 'importAccountSteamId64': '请输入Steam64位ID',
  162. 'importAccountInvalidSteamId64': '请输入正确的SteamID',
  163. 'importAccountGetToken': '请访问【 https://store.steampowered.com/pointssummary/ajaxgetasyncconfig 】,并把所有内容粘贴到下面',
  164. 'importAccountNickName': '请输入机器人显示昵称',
  165. 'importAccountNickNameTips': '手动添加',
  166. 'importAccountSuccess': '添加账号成功, 请手动刷新点数',
  167. },
  168. 'EN': {
  169. 'done': 'Done',
  170. 'changeLang': 'Change Language',
  171. 'langName': 'English',
  172. 'operating': 'Operating……',
  173. 'runningLog': 'Log',
  174. 'close': 'Close',
  175. 'logWaring': '【Log will not save, award history will list in【History】】',
  176. 'botListTitle': '【Bot Accounts】【ID | NickName | SteamID | Points Balance】',
  177. 'addCurrentAccount': 'Add Account',
  178. 'delSelectAccount': 'Del Selected',
  179. 'reloadAccountPoints': 'Refresh Points',
  180. 'historyTitle': '【History】【ID | NickName | SteamID | Received Points】',
  181. 'profile': 'Profile',
  182. 'deleteSelectedHistory': 'Del Selected',
  183. 'clearHistory': 'Clear',
  184. 'reloadHistory': 'Reload',
  185. 'feedBack': 'Author',
  186. 'feedBackTitle': '觉得好用也欢迎给我打赏',
  187. 'notSelected': '---Not Selected---',
  188. 'steamID64': 'Steam 64 ID',
  189. 'awardPoints': 'Points (Receive)',
  190. 'recommands': 'Recommands',
  191. 'screenshots': 'Screenshots',
  192. 'artworks': 'Artworks',
  193. 'setToCurrentUser': 'Set to page\'s user',
  194. 'calculator': 'Calculator',
  195. 'save': 'Save',
  196. 'reset': 'Reset',
  197. 'awardHistory': 'History',
  198. 'startAward': 'Start Award',
  199. 'stopAward': 'Stop',
  200. 'stop': 'Stopped',
  201. 'senderBotAccount': 'Award Bot: ',
  202. 'receverAccount': 'Target SteamID: ',
  203. 'sendPoints': 'Points (Receive): ',
  204. 'awardPrefer': 'Award Type (Up to down left to right): ',
  205. 'botList': 'Bots List',
  206. 'fetchLoginAccount': 'Fetching current logined account……',
  207. 'fetchToken': 'Fetching token……',
  208. 'fetchPoints': 'Fetching points balance……',
  209. 'success': 'Success',
  210. 'failure': 'Failure',
  211. 'error': 'Error',
  212. 'confirm': 'Confirm',
  213. 'tips': 'Tips',
  214. 'addAccountSuccessTips1': 'Add account successful',
  215. 'addAccountSuccessTips2': 'Current account\'s points balance',
  216. 'deleteAccountConfirmTips': 'Are sure to delete selected bots?',
  217. 'deleteAccountDoneTips1': 'Deleted',
  218. 'deleteAccountDoneTips2': 'bots',
  219. 'notSelectedAnyBotsTips': 'You have not selected any bot!',
  220. 'currentProcess': 'Current process',
  221. 'updateFailed': 'Update Failed',
  222. 'fetchingAccountPoints': 'Fetching points balance……',
  223. 'allDataLoaded': 'All data loaded',
  224. 'someDataLoadFailed': 'Some data loaded failed, if some bot\'s balance is 【-1】, it means fetch error',
  225. 'botListEmpty': 'Bot list is empty',
  226. 'noBotAccountTips': '-- No Bot Account, you can add via【➕Add ACcount】(Loginin required) --',
  227. 'awardTaskWasResetTips': 'Bot account had been modified, Award config reseted!',
  228. 'noHistoryTips': '-- No History Records, It Will Record When Awarding --',
  229. 'steamIDisEmpty': 'You must specify SteamID!',
  230. 'fetchingProfile': 'Fetching profile……',
  231. 'fetchingAwardableItems': 'Fetching awardable items……',
  232. 'fetchError': 'Fetch error',
  233. 'awardableAmount': '可打赏约',
  234. 'nickName': 'Nickname',
  235. 'totalPoints': 'Total points',
  236. 'calcTips': 'According to the total number of the items, inaccurate',
  237. 'profileNotExistsTips': 'Profile not found, please check if the steamID is correct, or use 【🤵Set to page\'s user】 instead',
  238. 'profileLoadFailedTips': 'Network error, fetch profile failed',
  239. 'notSelectedAnyHistoryTips': 'No records selected!',
  240. 'clearHistoryConfirmTips': 'Are you sure to clear all award records?',
  241. 'clearHistorySuccess': 'History cleared',
  242. 'historyListEmpty': 'History is empty!',
  243. 'deleteHistoryConfirmTips': 'Are you sure to delete seleted award records?',
  244. 'deleteResultTips1': 'Deleted',
  245. 'deleteResultTips2': 'history records',
  246. 'notSelectedAwardBotsTips': 'No bots selected!',
  247. 'steamIDEmptyWithTips': '【Target SteamID】is empty, It is recommended to use【🤵Set to page\'s user】!',
  248. 'steamIDErrorWithTips': '【Target SteamID】is invalid, It is recommended to use【🤵Set to page\'s user】!',
  249. 'pointsErrorWithTips': '【Points】is invalid, only integers are accepted!',
  250. 'awardTypeEmptyTips': 'Please select【Award Type】!',
  251. 'awardReadyToStartTips': 'Config saved, it is ready to【✅Start Award】',
  252. 'resetConfigConfirmTips': 'Are you sure to reset the config?',
  253. 'configResetSuccessTips': 'Config reseted!',
  254. 'awardTaskDataInvalid': 'Task data invalid',
  255. 'fetchingTargetProfile': 'Fetching target user\'s profile……',
  256. 'awardConfig': 'Award config',
  257. 'targetNickName': 'Target user\'s nickname',
  258. 'targetReceivePoints': 'Expected points received',
  259. 'targetBot': 'Selected bot',
  260. 'taskReadyToStartTips': 'Award task will start in 【2 seconds】, click【⛔Stop】to interrupt award task!',
  261. 'taskFailedProfileNotFound': 'Profile not found, award task end!',
  262. 'taskAlreadyStartTips': 'Award task is already running!',
  263. 'taskEndManually': 'Award task interrupted manually, click【❌Close】to hide the log panel.',
  264. 'taskNotStart': 'Award task not running!',
  265. 'running': 'Running',
  266. 'taskStartPointsSummary': 'Start sending award, points left / points expected',
  267. 'fetchAwardItemFailedRetry': 'Fetch awardable items failed, retry……',
  268. 'fetchNoAwardItemSkip': 'No suitable award items, skip……',
  269. 'beforeSendAward': 'Will send award',
  270. 'itemAndTotal': 'items, total',
  271. 'points': 'points',
  272. 'sendingAwards': 'Sending awards……',
  273. 'fetchSuccessAndFailed': 'Success / Failure',
  274. 'fetchAwardItemFailedRetryIn2Min': 'Fetch awardable items failed, will retry in【2 seconds】……',
  275. 'awardSuccess': 'Successful send award',
  276. 'taskFinishedPointsSummary': 'Award task complete, points left / points expected',
  277. 'updateBotPointsBalance': 'Update bot\'s points balance……',
  278. 'bot': 'bots',
  279. 'pointsBalanceUpdateSuccess': 'points balance, avilable points',
  280. 'lackOfPointsTaskEnd': 'Lack of points balance, stop operation',
  281. 'pointBalanceUpdateFailed': 'Update points balance failed',
  282. 'fetchAwardItemFailedSkip': 'Fetch awardable items failed, skip……',
  283. 'taskEndListEmpty': 'Award items list is empty, end',
  284. 'fetchCompletedTotal': 'Fetch success, total',
  285. 'entries': 'entries',
  286. 'objectID': 'Target ID',
  287. 'noAwardableObjectSkip': 'No suitable award items, skip...',
  288. 'willAward': 'Will send award',
  289. 'requestsSummary': 'Success / Failure',
  290. 'wait2Seconds': '*Delay 2 seconds, to avoid exceed award*',
  291. 'botDataError': 'Bot data error, can\'t start award task!',
  292. 'awardTaskFinish': '✅Award task completed, click【❌Close】to hide the log panel',
  293. 'awardTaskNotFinish': '⛔Award task not completed, click【❌close】to hide the log panel',
  294. 'cancel': 'Cancel',
  295. 'steamStoreNotLogin': '【STEAM Store】not logined, please sign in first',
  296. 'parseDataFailedMaybeNetworkError': 'Parse data failed, maybe token expired or network error',
  297. 'typeError': 'Type Error',
  298. 'networkError': 'Network Error',
  299. 'parseError': 'Parse Error',
  300. 'importAccount': '手动导入账号',
  301. 'importAccountSteamId64': '请输入Steam64位ID',
  302. 'importAccountInvalidSteamId64': '请输入正确的SteamID',
  303. 'importAccountGetToken': '请访问【 https://store.steampowered.com/pointssummary/ajaxgetasyncconfig 】,并把所有内容粘贴到下面',
  304. 'importAccountNickName': '请输入机器人显示昵称',
  305. 'importAccountNickNameTips': '手动添加',
  306. 'importAccountSuccess': '添加账号成功, 请手动刷新点数',
  307. }
  308. }
  309.  
  310. // 判断语言
  311. let language = GM_getValue("lang", null);
  312. if (!(language in LANG)) {
  313. showAlert('申明', `<p>本脚本现已免费提供</p><p>如果你在<a href="https://afdian.net/a/chr233">爱发电</a>以外的地方购买了本脚本, 请申请退款</p><p>觉得好用也欢迎给 <a href="https://steamcommunity.com/id/Chr_">作者</a> 打赏</p>`, true);
  314. language = "ZH";
  315. GM_setValue("lang", language);
  316. }
  317. // 获取翻译文本
  318. function t(key) {
  319. return LANG[language][key] || key;
  320. }
  321. {// 自动弹出提示
  322. const languageTips = GM_getValue("languageTips", true);
  323. if (languageTips && language === "ZH") {
  324. if (!document.querySelector("html").lang.startsWith("zh")) {
  325. ShowConfirmDialog("tips", "Auto Award now support English, switch?", "Using English", "Don't show again")
  326. .done(() => {
  327. GM_setValue("lang", "EN");
  328. GM_setValue("languageTips", false);
  329. window.location.reload();
  330. })
  331. .fail((bool) => {
  332. if (bool) {
  333. showAlert("", "You can switch the plugin's language using TamperMonkey's menu.");
  334. GM_setValue("languageTips", false);
  335. }
  336. });
  337. }
  338. }
  339. }
  340. GM_registerMenuCommand(`${t("changeLang")} (${t("langName")})`, () => {
  341. switch (language) {
  342. case "EN":
  343. language = "ZH";
  344. break;
  345. case "ZH":
  346. language = "EN";
  347. break;
  348. }
  349. GM_setValue("lang", language);
  350. window.location.reload();
  351. });
  352.  
  353. GM_registerMenuCommand(t("importAccount"), () => {
  354. const steamID = prompt(t("importAccountSteamId64"));
  355. const v_steamID = parseInt(steamID);
  356. if (v_steamID !== v_steamID) {
  357. alert(t("importAccountInvalidSteamId64"));
  358. return;
  359. }
  360. const ajaxJson = prompt(t("importAccountGetToken"));
  361. const json = JSON.parse(ajaxJson);
  362. const token = json?.data?.webapi_token;
  363. if (!token) {
  364. alert(t("parseError"));
  365. return;
  366. }
  367.  
  368. let botCount = 0;
  369. for (let _ in GBots) {
  370. botCount++;
  371. }
  372. const nick = prompt(t("importAccountNickName"), `${t("importAccountNickNameTips")} ${botCount}`);
  373.  
  374. alert(t("importAccountSuccess"));
  375. GBots[steamID] = { nick, token, points: -1 }
  376. GM_setValue('bots', GBots);
  377. flashBotList();
  378. });
  379.  
  380. //机器人账号
  381. let GBots = {};
  382. //打赏历史记录
  383. let GHistory = {};
  384. //打赏任务
  385. let GTask = {};
  386. //面板状态
  387. let GPanel = {};
  388. //控件字典
  389. let GObjs = {};
  390.  
  391. //初始化
  392. (() => {
  393. loadConf();
  394.  
  395. graphGUI();
  396. flashBotList();
  397. flashHistoryList();
  398.  
  399. const { panelMain, panelLeft } = GPanel;
  400. if (panelMain) {
  401. GPanel.panelMain = false;
  402. panelSwitch();
  403. }
  404. if (panelLeft) {
  405. GPanel.panelLeft = false;
  406. leftPanelSwitch();
  407. }
  408. if (!isEmptyObject(GTask)) {
  409. GTask.work = false;
  410. }
  411. appllyTask();
  412. })();
  413.  
  414. //====================================================================================
  415. //添加控制面板
  416. function graphGUI() {
  417. function genButton(text, foo, enable = true) {
  418. const b = document.createElement('button');
  419. b.textContent = text;
  420. b.className = 'aam_button';
  421. b.disabled = !enable;
  422. b.addEventListener('click', foo);
  423. return b;
  424. }
  425. function genDiv(cls = 'aam_div') {
  426. const d = document.createElement('div');
  427. d.className = cls;
  428. return d;
  429. }
  430. function genA(text, url) {
  431. const a = document.createElement('a');
  432. a.textContent = text;
  433. a.className = 'aam_a';
  434. a.target = '_blank';
  435. a.href = url;
  436. return a;
  437. }
  438. function genInput(value, tips, number = false) {
  439. const i = document.createElement('input');
  440. i.className = 'aam_input';
  441. if (value) { i.value = value; }
  442. if (tips) { i.placeholder = tips; }
  443. if (number) {
  444. i.type = 'number';
  445. i.step = 100;
  446. i.min = 0;
  447. }
  448. return i;
  449. }
  450. function genTextArea(value, tips) {
  451. const i = document.createElement('textarea');
  452. i.className = 'aam_textarea';
  453. if (value) { i.value = value; }
  454. if (tips) { i.placeholder = tips; }
  455. return i;
  456. }
  457. function genCheckbox(name, checked = false) {
  458. const l = document.createElement('label');
  459. const i = document.createElement('input');
  460. const s = genSpace(name);
  461. i.textContent = name;
  462. i.title = name;
  463. i.type = 'checkbox';
  464. i.className = 'aam_checkbox';
  465. i.checked = checked;
  466. l.appendChild(i);
  467. l.appendChild(s);
  468. return [l, i];
  469. }
  470. function genSelect(choose = [], choice = null) {
  471. const s = document.createElement('select');
  472. s.className = 'aam_select';
  473. choose.forEach(([text, value]) => {
  474. s.options.add(new Option(text, value));
  475. });
  476. if (choice) { s.value = choice; }
  477. return s;
  478. }
  479. function genList(choose = [], choice = null) {
  480. const s = genSelect(choose, choice);
  481. s.className = 'aam_list';
  482. s.setAttribute('multiple', 'multiple');
  483. return s;
  484. }
  485. function genP(text) {
  486. const p = document.createElement('p');
  487. p.textContent = text;
  488. return p;
  489. }
  490. function genSpan(text = ' ') {
  491. const s = document.createElement('span');
  492. s.textContent = text;
  493. return s;
  494. }
  495. const genSpace = genSpan;
  496. function genBr() {
  497. return document.createElement('br');
  498. }
  499. function genHr() {
  500. return document.createElement('hr');
  501. }
  502. function genMidBtn(text, foo) {
  503. const a = document.createElement('a');
  504. const s = genSpan(text);
  505. a.className = 'btn_profile_action btn_medium';
  506. a.addEventListener('click', foo);
  507. a.appendChild(s);
  508. return [a, s];
  509. }
  510.  
  511. const btnArea = document.querySelector('.profile_header_actions');
  512. const [btnSwitch, bSwitch] = genMidBtn('⭕', panelSwitch);
  513. btnArea.appendChild(genSpace());
  514. btnArea.appendChild(btnSwitch);
  515. btnArea.appendChild(genSpace());
  516.  
  517. const panelArea = document.querySelector('.profile_leftcol');
  518. const panelMain = genDiv('aam_panel profile_customization');
  519. panelMain.style.display = 'none';
  520. panelArea.insertBefore(panelMain, panelArea.firstChild);
  521.  
  522. const busyPanel = genDiv('aam_busy');
  523. const busyPanelContent = genDiv('aam_busy_content');
  524. const busyMessage = genP(t('operating'));
  525. const busyImg = new Image();
  526. busyImg.src = 'https://steamcommunity-a.akamaihd.net/public/images/login/throbber.gif';
  527.  
  528. busyPanelContent.appendChild(busyMessage);
  529. busyPanelContent.appendChild(busyImg);
  530.  
  531. busyPanel.appendChild(busyPanelContent);
  532.  
  533. panelMain.appendChild(busyPanel);
  534.  
  535. const workPanel = genDiv('aam_busy aam_work');
  536. const workLog = genTextArea('', t('runningLog'),);
  537. const workHide = genButton(`❌${t('close')}`, () => { workScreen(false, null); }, true);
  538.  
  539. workPanel.appendChild(workLog);
  540. workPanel.appendChild(genSpan(t('logWaring')));
  541. workPanel.appendChild(workHide);
  542.  
  543. panelMain.appendChild(workPanel);
  544.  
  545. const leftPanel = genDiv('aam_left');
  546. const accountPanel = genDiv('aam_account');
  547. const accountTitle = genSpan(t('botListTitle'));
  548. const accountList = genList([], null);
  549. const accountBtns = genDiv('aam_btns');
  550. const acAdd = genButton(`➕${t('addCurrentAccount')}`, accountAdd);
  551. const acDel = genButton(`➖${t('delSelectAccount')}`, accountDel);
  552. const acUpdate = genButton(`🔄${t('reloadAccountPoints')}`, flashAllAccounts);
  553.  
  554. accountBtns.appendChild(acAdd);
  555. accountBtns.appendChild(acDel);
  556. accountBtns.appendChild(acUpdate);
  557.  
  558. accountPanel.appendChild(accountTitle);
  559. accountPanel.appendChild(genBr());
  560. accountPanel.appendChild(accountList);
  561. accountPanel.appendChild(accountBtns);
  562.  
  563. leftPanel.appendChild(accountPanel);
  564.  
  565. const historyPanel = genDiv('aam_history');
  566. historyPanel.style.display = 'none';
  567.  
  568. const historyTitle = genSpan(t('historyTitle'));
  569. const historyList = genList([], null);
  570. const historyBtns = genDiv('aam_btns');
  571. const hsProfile = genButton(`🌏${t('profile')}`, showProfile);
  572. const hsDelete = genButton(`➖${t('deleteSelectedHistory')}`, deleteHistory);
  573. const hsClear = genButton(`🗑️${t('clearHistory')}`, clearHistory);
  574. const hsReload = genButton(`🔄${t('reloadHistory')}`, flashHistoryList);
  575.  
  576. historyBtns.appendChild(hsProfile);
  577. historyBtns.appendChild(hsDelete);
  578. historyBtns.appendChild(hsClear);
  579. historyBtns.appendChild(hsReload);
  580.  
  581. historyPanel.appendChild(historyTitle);
  582. historyPanel.appendChild(genBr());
  583. historyPanel.appendChild(historyList);
  584. historyPanel.appendChild(historyBtns);
  585.  
  586. leftPanel.appendChild(historyPanel);
  587. panelMain.appendChild(leftPanel);
  588.  
  589. const awardPanel = genDiv('aam_award');
  590. const feedbackLink = genA(t('feedBack'), 'https://steamcommunity.com/id/Chr_/');
  591. feedbackLink.title = t('feedBackTitle');
  592. const awardBot = genSelect([[t('notSelected'), '']], null);
  593. const awardSteamID = genInput('', t('steamID64'), false);
  594. const awardPoints = genInput('', t('awardPoints'), true);
  595. const [awardCProfile, awardProfile] = genCheckbox(t('profile'), true);
  596. const [awardCRecommand, awardRecommand] = genCheckbox(t('recommands'), true);
  597. const [awardCScreenshot, awardScreenshot] = genCheckbox(t('screenshots'), true);
  598. const [awardCImage, awardImage] = genCheckbox(t('artworks'), true);
  599. const awardBtns1 = genDiv('aam_btns');
  600. const awardBtnCurrent = genButton(`🤵${t('setToCurrentUser')}`, getCurrentProfile);
  601. const awardBtnCalc = genButton(`📊${t('calculator')}`, calcAwardItems);
  602. const awardBtns2 = genDiv('aam_btns');
  603. const awardBtnSet = genButton(`💾${t('save')}`, applyAwardConfig);
  604. const awardBtnReset = genButton(`🔨${t('reset')}`, restoreAwardConfig);
  605. const hSwitch = genButton(`🕒${t('awardHistory')}`, leftPanelSwitch);
  606. const awardBtns3 = genDiv('aam_btns aam_award_btns');
  607. const awardBtnStart = genButton(`✅${t('startAward')}`, startAward, false);
  608. const awardBtnStop = genButton(`⛔${t('stopAward')}`, stopAward, false);
  609. const awardStatus = genSpan(`🟥 ${t('stop')}`);
  610.  
  611. awardBtns1.appendChild(awardBtnCurrent);
  612. awardBtns1.appendChild(awardBtnCalc);
  613.  
  614. awardBtns2.appendChild(awardBtnSet);
  615. awardBtns2.appendChild(awardBtnReset);
  616. awardBtns2.appendChild(hSwitch);
  617.  
  618. awardBtns3.appendChild(awardBtnStart);
  619. awardBtns3.appendChild(awardBtnStop);
  620. awardBtns3.appendChild(awardStatus);
  621.  
  622. awardPanel.appendChild(genSpan(t('senderBotAccount')));
  623. awardPanel.appendChild(feedbackLink);
  624. awardPanel.appendChild(genBr());
  625. awardPanel.appendChild(awardBot);
  626. awardPanel.appendChild(genSpan(t('receverAccount')));
  627. awardPanel.appendChild(genBr());
  628. awardPanel.appendChild(awardSteamID);
  629. awardPanel.appendChild(awardBtns1);
  630. awardPanel.appendChild(genSpan(t('sendPoints')));
  631. awardPanel.appendChild(genBr());
  632. awardPanel.appendChild(awardPoints);
  633. awardPanel.appendChild(genSpan(t('awardPrefer')));
  634. awardPanel.appendChild(genBr());
  635. awardPanel.appendChild(awardCProfile);
  636. awardPanel.appendChild(awardCRecommand);
  637. awardPanel.appendChild(genBr());
  638. awardPanel.appendChild(awardCScreenshot);
  639. awardPanel.appendChild(awardCImage);
  640. awardPanel.appendChild(genBr());
  641. awardPanel.appendChild(awardBtns2);
  642. awardPanel.appendChild(genHr());
  643. awardPanel.appendChild(awardBtns3);
  644.  
  645. panelMain.appendChild(awardPanel);
  646.  
  647. Object.assign(GObjs, {
  648. bSwitch, hSwitch, panelMain,
  649. busyPanel, busyMessage, workPanel, workLog, workHide,
  650. accountPanel, accountList, historyPanel, historyList,
  651. awardBot, awardSteamID, awardPoints, awardStatus,
  652. awardProfile, awardRecommand, awardScreenshot, awardImage,
  653. awardBtnStart, awardBtnStop, awardBtnSet, awardBtnReset
  654. });
  655. }
  656. //面板显示开关
  657. function panelSwitch() {
  658. const { bSwitch, panelMain } = GObjs;
  659.  
  660. if (GPanel.panelMain !== true) {
  661. panelMain.style.display = '';
  662. bSwitch.textContent = '🔴';
  663. GPanel.panelMain = true;
  664. } else {
  665. panelMain.style.display = 'none';
  666. bSwitch.textContent = '⭕';
  667. GPanel.panelMain = false;
  668. }
  669. GM_setValue('panel', GPanel);
  670. }
  671. //左侧面板切换
  672. function leftPanelSwitch() {
  673. const { hSwitch, accountPanel, historyPanel } = GObjs;
  674. if (GPanel.panelLeft !== true) {
  675. accountPanel.style.display = 'none';
  676. historyPanel.style.display = '';
  677. hSwitch.textContent = `🤖${t('botList')}`;
  678. GPanel.panelLeft = true;
  679. } else {
  680. historyPanel.style.display = 'none';
  681. accountPanel.style.display = '';
  682. hSwitch.textContent = `🕒${t('awardHistory')}`;
  683. GPanel.panelLeft = false;
  684. }
  685. GM_setValue('panel', GPanel);
  686. }
  687. //添加账户
  688. function accountAdd() {
  689. let v_nick, v_token, v_steamID;
  690. loadScreen(true, t('fetchLoginAccount'));
  691. getMySteamID()
  692. .then(({ nick, steamID }) => {
  693. v_nick = nick;
  694. v_steamID = steamID;
  695. loadScreen(true, t('fetchToken'));
  696. return getToken();
  697. })
  698. .then((tk) => {
  699. v_token = tk;
  700. loadScreen(true, t('fetchPoints'));
  701. return getPoints(v_steamID, tk);
  702. })
  703. .then((points) => {
  704. showAlert(t('success'), `<p>${t('addAccountSuccessTips1')}</p><p>${t('addAccountSuccessTips2')}: ${points} ${t('points')}</p>`, true);
  705. GBots[v_steamID] = { nick: v_nick, token: v_token, points }
  706. GM_setValue('bots', GBots);
  707. flashBotList();
  708. })
  709. .catch((reason) => {
  710. showAlert(t('error'), reason, false);
  711. }).finally(() => {
  712. loadScreen(false, null);
  713. });
  714. }
  715. //删除账户
  716. function accountDel() {
  717. const { accountList } = GObjs;
  718. if (accountList.selectedIndex >= 0) {
  719. showConfirm(t('confirm'), t('deleteAccountConfirmTips'), () => {
  720. let i = 0;
  721. for (const opt of accountList.selectedOptions) {
  722. delete GBots[opt.value];
  723. i++;
  724. }
  725. flashBotList();
  726. GM_setValue('bots', GBots);
  727. showAlert(t('tips'), `${t('deleteAccountDoneTips1')} ${i} ${t('deleteAccountDoneTips2')}`, true);
  728. }, null);
  729. } else {
  730. showAlert(t('tips'), t('notSelectedAnyBotsTips'), false);
  731. }
  732. }
  733. //刷新账户点数
  734. async function flashAllAccounts() {
  735. //刷新点数
  736. function makePromise(sid, tk) {
  737. return new Promise((resolve, reject) => {
  738. getPoints(sid, tk)
  739. .then((points) => {
  740. GBots[sid].points = points;
  741. loadScreen(true, `${t('currentProcess')}: ${++fin} / ${count}`);
  742. }).catch((reason) => {
  743. GBots[sid].points = -1;
  744. // GBots[sid].nick = '读取失败';
  745. loadScreen(true, `${sid} ${t('updateFailed')}: ${reason}`);
  746. }).finally(() => {
  747. GM_setValue('bots', GBots);
  748. resolve();
  749. });
  750. });
  751. }
  752. let count = 0, fin = 0;
  753. for (const _ in GBots) {
  754. count++;
  755. }
  756. if (count > 0) {
  757. loadScreen(true, t('fetchingAccountPoints'));
  758. const pList = [];
  759. for (const steamID in GBots) {
  760. const { token } = GBots[steamID];
  761. pList.push(makePromise(steamID, token));
  762. }
  763. Promise.all(pList)
  764. .finally(() => {
  765. loadScreen(false, null);
  766. flashBotList();
  767. if (fin >= count) {
  768. showAlert(t('done'), t('allDataLoaded'), true);
  769. } else {
  770. showAlert(t('done'), t('someDataLoadFailed'), true);
  771. }
  772. });
  773. } else {
  774. showAlert(t('error'), t('botListEmpty'), false);
  775. }
  776. }
  777. //刷新账户列表
  778. function flashBotList() {
  779. const { bot } = GTask;
  780. const { accountList, awardBot } = GObjs;
  781. accountList.options.length = 0;
  782. awardBot.options.length = 0;
  783. awardBot.options.add(new Option(t('notSelected'), ''))
  784. let i = 1;
  785. let flag = false;
  786. if (!isEmptyObject(GBots)) {
  787. for (const steamID in GBots) {
  788. const { nick, points } = GBots[steamID];
  789. const pointsStr = parseInt(points).toLocaleString();
  790. accountList.options.add(new Option(`${i} | ${nick} | ${steamID} | ${pointsStr} 点`, steamID));
  791. awardBot.options.add(new Option(`${i++} | ${nick} | ${pointsStr} 点`, steamID))
  792. if (steamID === bot) {
  793. flag = true;
  794. awardBot.selectedIndex = i - 1;
  795. }
  796. }
  797. } else {
  798. accountList.options.add(new Option(t('noBotAccountTips'), ''));
  799. }
  800. if ((!isEmptyObject(GTask)) && (!flag)) {
  801. GTask = {};
  802. GM_setValue('task', GTask);
  803. appllyTask();
  804. showAlert(t('tips'), t('awardTaskWasResetTips'), false);
  805. }
  806. }
  807. //刷新历史记录列表
  808. function flashHistoryList() {
  809. const { historyList } = GObjs;
  810. historyList.options.length = 0;
  811. let i = 1;
  812. if (!isEmptyObject(GHistory)) {
  813. for (const steamID in GHistory) {
  814. const [nick, points] = GHistory[steamID];
  815. const pointsStr = parseInt(points).toLocaleString();
  816. historyList.options.add(new Option(`${i++} | ${nick} | ${steamID} | ${pointsStr} 点`, steamID));
  817. }
  818. } else {
  819. historyList.options.add(new Option(t('noHistoryTips'), ''));
  820. }
  821. }
  822. //历史记录增加点数
  823. function addHistory(steamID, nick, points) {
  824. if (GHistory[steamID] !== undefined) {
  825. GHistory[steamID] = [nick, GHistory[steamID][1] + points];
  826. } else {
  827. GHistory[steamID] = [nick, points];
  828. }
  829. GM_setValue('history', GHistory);
  830. }
  831. //获取当前个人资料
  832. function getCurrentProfile() {
  833. const { awardSteamID } = GObjs;
  834. awardSteamID.value = g_rgProfileData.steamid;
  835. }
  836. //计算可打赏项目
  837. function calcAwardItems() {
  838. const { awardSteamID } = GObjs;
  839. const steamID = awardSteamID.value.trim();
  840. if (steamID === '') {
  841. showAlert(t('error'), t('steamIDisEmpty!'), false);
  842. } else {
  843. loadScreen(true, t('fetchingProfile'));
  844. getProfile(steamID)
  845. .then(([succ, nick]) => {
  846. if (succ) {
  847. loadScreen(true, t('fetchingAwardableItems'));
  848. const pList = [
  849. getAwardCounts(steamID, 'r'),
  850. getAwardCounts(steamID, 's'),
  851. getAwardCounts(steamID, 'i')
  852. ];
  853. Promise.all(pList)
  854. .then((result) => {
  855. const data = {};
  856. let sum = 0;
  857. for (const [type, succ, count] of result) {
  858. if (succ) {
  859. const points = count * 6600;
  860. data[type] = `${count} , ${t('awardableAmount')}: ${points.toLocaleString()} ${t('points')}`;
  861. sum += points;
  862. } else {
  863. data[type] = t('fetchError');
  864. }
  865. }
  866. let text = `<p>${t('nickName')}: ${nick}</p><p>${t('recommands')}: ${data.r}</p><p>${t('screenshots')}: ${data.s}</p><p>${t('artworks')}: ${data.i}</p><p>${t('totalPoints')}: ${sum.toLocaleString()}</p><p>*${t('calcTips')}*</p>`
  867. showAlert(t('tips'), text, true);
  868. })
  869. .finally(() => {
  870. loadScreen(false, null);
  871. });
  872. } else {
  873. showAlert(t('error'), t('profileNotExistsTips'), false);
  874. loadScreen(false, null);
  875. }
  876. })
  877. .catch((reason) => {
  878. showAlert(t('error'), `<p>${t('profileLoadFailedTips')}</p><p>${reason}</p>`, false)
  879. loadScreen(false, null);
  880. });
  881. }
  882. }
  883. //查看个人资料
  884. function showProfile() {
  885. const { historyList } = GObjs;
  886. const i = historyList.selectedIndex;
  887. if (i > -1) {
  888. const { value } = historyList.options[i];
  889. if (value != '') {
  890. window.open(`https://steamcommunity.com/profiles/${value}`);
  891. }
  892. } else {
  893. showAlert(t('tips'), t('notSelectedAnyHistoryTips'), false);
  894. }
  895. }
  896. //清除历史
  897. function clearHistory() {
  898. if (!isEmptyObject(GHistory)) {
  899. showConfirm(t('confirm'), t('clearHistoryConfirmTips'), () => {
  900. GHistory = {};
  901. flashHistoryList();
  902. GM_setValue('history', GHistory);
  903. showAlert(t('tips'), t('clearHistorySuccess'), true);
  904. }, null);
  905. } else {
  906. showAlert(t('tips'), t('historyListEmpty'), false);
  907. }
  908. }
  909. //删除历史
  910. function deleteHistory() {
  911. const { historyList } = GObjs;
  912. if (historyList.selectedIndex >= 0) {
  913. showConfirm(t('confirm'), t('deleteHistoryConfirmTips'), () => {
  914. let i = 0;
  915. for (const opt of historyList.selectedOptions) {
  916. delete GHistory[opt.value];
  917. i++;
  918. }
  919. flashHistoryList();
  920. GM_setValue('history', GHistory);
  921. showAlert(t('tips'), `${t('deleteResultTips1')} ${i} ${t('deleteResultTips2')}`, true);
  922. }, null);
  923. } else {
  924. showAlert(t('tips'), t('notSelectedAnyHistoryTips'), false);
  925. }
  926. }
  927. //保存打赏设置
  928. function applyAwardConfig() {
  929. const {
  930. awardBtnStart, awardBtnStop,
  931. awardBot, awardSteamID, awardPoints,
  932. awardProfile, awardRecommand, awardScreenshot, awardImage
  933. } = GObjs;
  934.  
  935. awardBtnStart.disabled = awardBtnStop.disabled = true;
  936.  
  937. let bot = awardBot.value;
  938. let points = parseInt(awardPoints.value);
  939. let steamID = String(awardSteamID.value).trim();
  940.  
  941. let type = 0;
  942. if (!awardProfile.checked) { type += 1; }
  943. if (!awardRecommand.checked) { type += 2; }
  944. if (!awardScreenshot.checked) { type += 4; }
  945. if (!awardImage.checked) { type += 8; }
  946.  
  947. if (bot == '') {
  948. showAlert(t('error'), t('notSelectedAwardBotsTips'), false);
  949. } else if (steamID === '') {
  950. showAlert(t('error'), t('steamIDEmptyWithTips'), false);
  951. } else if (!steamID.match(/^\d+$/)) {
  952. showAlert(t('error'), t('steamIDErrorWithTips'), false);
  953. } else if (points !== points || points < 100) {
  954. showAlert(t('error'), t('pointsErrorWithTips'), false);
  955. } else if (type === 15) {
  956. showAlert(t('error'), t('awardTypeEmptyTips'), false);
  957. } else {
  958. points = Math.ceil(points / 100) * 100;
  959. GTask = { bot, steamID, points, type, work: false, nick: null };
  960. awardBtnStart.disabled = awardBtnStop.disabled = false;
  961. GM_setValue('task', GTask);
  962. showAlert(t('tips'), t('awardReadyToStartTips'), true);
  963. }
  964. }
  965. //重置打赏设置
  966. function restoreAwardConfig() {
  967. showConfirm(t('confirm'), t('resetConfigConfirmTips'), () => {
  968. GTask = {};
  969. GM_setValue('task', GTask);
  970. appllyTask();
  971. showAlert(t('tips'), t('configResetSuccessTips'), true);
  972. }, null);
  973. }
  974. //读取设置到界面
  975. function appllyTask() {
  976. const {
  977. awardBtnStart, awardBtnStop,
  978. awardBot, awardSteamID, awardPoints,
  979. awardProfile, awardRecommand, awardScreenshot, awardImage
  980. } = GObjs;
  981. const { bot, steamID, points, type } = GTask;
  982.  
  983. awardBtnStart.disabled = awardBtnStop.disabled = isEmptyObject(GTask);
  984.  
  985. awardBot.value = bot ? bot : '';
  986. awardSteamID.value = steamID ? steamID : '';
  987. awardPoints.value = points ? points : '';
  988.  
  989. awardProfile.checked = !Boolean(type & 1);
  990. awardRecommand.checked = !Boolean(type & 2);
  991. awardScreenshot.checked = !Boolean(type & 4);
  992. awardImage.checked = !Boolean(type & 8);
  993. }
  994. //开始自动打赏
  995. async function startAward() {
  996. if (isEmptyObject(GTask)) {
  997. showAlert(t('error'), t('awardTaskDataInvalid'), false);
  998. return;
  999. }
  1000. const { steamID, work, points, bot, nick: taskNick } = GTask;
  1001. const { nick: botNick } = GBots[bot];
  1002. const pointsStr = parseInt(points).toLocaleString();
  1003.  
  1004. if (!work) {
  1005. spaceLine(1);
  1006. if (!taskNick) {
  1007. loadScreen(true, t('fetchingTargetProfile'));
  1008. getProfile(steamID)
  1009. .then(([succ, nickName]) => {
  1010. if (succ) {
  1011. GTask.work = true;
  1012. GTask.nick = nickName;
  1013. GM_setValue('task', GTask);
  1014. print(`${t('awardConfig')}:\n${t('targetNickName')}: ${nickName}, ${t('targetReceivePoints')}: ${pointsStr}, ${t('targetBot')}: ${botNick}〗`);
  1015. print(t('taskReadyToStartTips'));
  1016. workScreen(true);
  1017. setTimeout(() => {
  1018. autoAward();
  1019. }, 2000);
  1020. } else {
  1021. print(t('taskFailedProfileNotFound'), 'E');
  1022. showAlert(t('error'), t('profileNotExistsTips'), false);
  1023. }
  1024. })
  1025. .catch((reason) => {
  1026. showAlert(t('error'), `<p>${t('profileLoadFailedTips')}</p><p>${reason}</p>`, false)
  1027. }).finally(() => {
  1028. loadScreen(false, null);
  1029. });
  1030. } else {
  1031. GTask.work = true;
  1032. GM_setValue('task', GTask);
  1033. print(`〖${t('targetNickName')}: ${taskNick}, ${t('targetReceivePoints')}: ${pointsStr}, ${t('targetBot')}: ${botNick}〗`);
  1034. print(t('taskReadyToStartTips'));
  1035. workScreen(true);
  1036. setTimeout(() => {
  1037. autoAward();
  1038. }, 2000);
  1039. }
  1040. } else {
  1041. print(t('taskAlreadyStartTips'));
  1042. }
  1043. }
  1044. //停止自动打赏
  1045. async function stopAward() {
  1046. if (isEmptyObject(GTask)) {
  1047. showAlert(t('error'), t('awardTaskDataInvalid'), false);
  1048. return;
  1049. }
  1050. const { work } = GTask;
  1051. if (work) {
  1052. spaceLine(4);
  1053. print(t('taskEndManually'));
  1054. GTask.work = false;
  1055. GM_setValue('task', GTask);
  1056. showStatus(t('stop'), false);
  1057. } else {
  1058. showAlert(t('error'), t('taskNotStart'), false);
  1059. }
  1060. }
  1061. //打赏项目
  1062. const reactionsDict = {
  1063. 1: 300, 2: 300, 3: 300, 4: 300, 5: 300, 6: 300, 7: 300, 8: 300, 9: 600,
  1064. 10: 1200, 11: 2400, 12: 300, 13: 2400, 14: 600, 15: 1200, 16: 600,
  1065. 17: 4800, 18: 300, 19: 600, 20: 1200, 21: 300, 22: 600, 23: 300
  1066. };
  1067. const reactionValues = [
  1068. 300, 300, 300, 300, 300, 300, 300, 300, 600, 1200, 2400, 300,
  1069. 2400, 600, 1200, 600, 4800, 300, 600, 1200, 300, 600, 300
  1070. ];
  1071. const reactionIDs = [
  1072. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
  1073. 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
  1074. ];
  1075. //自动打赏
  1076. async function autoAward() {
  1077. //打赏类型
  1078. const reactionType = {
  1079. 'p': ['3', t('profile')], 'r': ['1', t('recommands')], 's': ['2', t('screenshots')], 'i': ['2', t('artworks')]
  1080. };
  1081. const { bot, steamID, type, points: pointsGoal, nick: taskNick } = GTask;
  1082. const { nick: botNick, token } = GBots[bot];
  1083.  
  1084. appllyTask();
  1085. addHistory(steamID, taskNick, 0);
  1086. showStatus(t('running'), true);
  1087. let pointsLeft = pointsGoal;
  1088.  
  1089. if (token) {
  1090. const workflow = [];
  1091. if (!Boolean(type & 8)) { workflow.push('i') };
  1092. if (!Boolean(type & 4)) { workflow.push('s') };
  1093. if (!Boolean(type & 2)) { workflow.push('r') };
  1094. if (!Boolean(type & 1)) { workflow.push('p') };
  1095.  
  1096. while (GTask.work && workflow.length > 0) {
  1097. const award_type = workflow.pop();
  1098. const [target_type, target_name] = reactionType[award_type];
  1099. let process = genProgressBar((pointsGoal - pointsLeft) / pointsGoal * 100);
  1100.  
  1101. spaceLine(3);
  1102. print(`【${target_name}】${t('taskStartPointsSummary')}: ${pointsLeft.toLocaleString()} / ${pointsGoal.toLocaleString()} ${t('points')}`);
  1103. print(`${t('currentProcess')}: ${process}`);
  1104. spaceLine(3);
  1105.  
  1106. let coast = 0;
  1107.  
  1108. if (target_type === '3') { //个人资料
  1109. let GoldReactions = null;
  1110. for (let i = 0; i < 3; i++) { //重试3次
  1111. if (GoldReactions === null) { //旧打赏列表为空,重新读取并打赏
  1112. const [succOld, oldReactions] = await getAwardRecords(token, target_type, steamID);
  1113. if (!succOld) {
  1114. print(t('fetchAwardItemFailedRetry'));
  1115. continue;
  1116. }
  1117. GoldReactions = oldReactions;
  1118. const todoReactions = selectFitableReactions(pointsLeft, GoldReactions);
  1119. if (todoReactions.length === 0) {
  1120. print(`【${target_name}】${t('fetchNoAwardItemSkip')}`);
  1121. break;
  1122. }
  1123. coast = sumReactionsPoints(todoReactions);
  1124. print(`【${target_name}】${t('beforeSendAward')}: ${todoReactions.length} ${t('itemAndTotal')}: ${coast.toLocaleString()} ${t('points')}`)
  1125. const plist = [];
  1126. for (const id of todoReactions) {
  1127. plist.push(sendAwardReaction(token, target_type, steamID, id));
  1128. }
  1129. print(t('sendingAwards'));
  1130. const result = await Promise.all(plist);
  1131. const [succ, fail] = countSuccess(result);
  1132. print(`${t('fetchSuccessAndFailed')}: ${succ} / ${fail}`);
  1133. }
  1134. //统计新的打赏列表,计算打赏点数
  1135. const [succNew, newReactions] = await getAwardRecords(token, target_type, steamID);
  1136. if (!succNew) {
  1137. print(t('fetchAwardItemFailedRetryIn2Min'));
  1138. await aiosleep(2000);
  1139. continue;
  1140. }
  1141. const diffReactions = filterDiffReactions(newReactions, GoldReactions);
  1142. coast = sumReactionsPoints(diffReactions);
  1143. pointsLeft -= coast;
  1144. addHistory(steamID, taskNick, coast);
  1145. print(`【${target_name}】${t('awardSuccess')}: ${diffReactions.length} ${t('itemAndTotal')}: ${coast.toLocaleString()} ${t('points')}`);
  1146. break;
  1147. }
  1148. GTask.points = pointsLeft;
  1149. if (pointsLeft <= 0) {
  1150. GTask.work = false;
  1151. }
  1152. GM_setValue('task', GTask);
  1153. process = genProgressBar((pointsGoal - pointsLeft) / pointsGoal * 100);
  1154.  
  1155. spaceLine(3);
  1156. print(`【${target_name}】${t('taskFinishedPointsSummary')}: ${pointsLeft.toLocaleString()} / ${pointsGoal.toLocaleString()} ${t('points')}`);
  1157. print(`${t('currentProcess')}: ${process}`);
  1158. spaceLine(3);
  1159.  
  1160. print(t('updateBotPointsBalance'));
  1161.  
  1162. await getPoints(bot, token)
  1163. .then((p) => {
  1164. GBots[bot].points = p;
  1165. GM_setValue('bots', GBots);
  1166. print(`${t('bot')}【${botNick}】${t('pointsBalanceUpdateSuccess')}: ${p.toLocaleString()} ${t('points')}`);
  1167. if (p < 300) {
  1168. print(`${t('bot')}【${botNick}】${t('lackOfPointsTaskEnd')}`);
  1169. GTask.work = false;
  1170. }
  1171. }).catch((r) => {
  1172. print(`${t('bot')}【${botNick}】${t('pointBalanceUpdateFailed')}: ${r}`);
  1173. });
  1174.  
  1175.  
  1176. } else { //截图
  1177. let page = 1;
  1178. while (GTask.work) {
  1179. let j = 0;
  1180. print(t('fetchingAwardableItems'));
  1181. const [succ, items] = await getAwardItems(steamID, award_type, page++);
  1182. if (!succ) {
  1183. page--;
  1184. if (++j < 3) {
  1185. print(t('fetchAwardItemFailedRetryIn2Min'));
  1186. await aiosleep(2000);
  1187. continue;
  1188. } else {
  1189. print(t('fetchAwardItemFailedSkip'));
  1190. break;
  1191. }
  1192. }
  1193. if (items.length === 0) {
  1194. print(`【${target_name}】${t('taskEndListEmpty')}`);
  1195. break;
  1196. }
  1197.  
  1198. print(`【${target_name}】${t('fetchCompletedTotal')} ${items.length} ${t('entries')}`);
  1199.  
  1200. for (const itemID of items) {
  1201.  
  1202. print(`【${target_name}】${t('objectID')}: ${itemID}`);
  1203. let GoldReactions = null;
  1204.  
  1205. for (let i = 0; i < 3; i++) {
  1206. if (GoldReactions === null) { //旧打赏列表为空,重新读取并打赏
  1207. const [succOld, oldReactions] = await getAwardRecords(token, target_type, itemID);
  1208. if (!succOld) {
  1209. print(t('fetchAwardItemFailedRetry'));
  1210. continue;
  1211. }
  1212. GoldReactions = oldReactions;
  1213. const todoReactions = selectFitableReactions(pointsLeft, GoldReactions);
  1214. if (todoReactions.length === 0) {
  1215. print(`【${target_name}】${t('noAwardableObjectSkip')}`);
  1216. break;
  1217. }
  1218. coast = sumReactionsPoints(todoReactions);
  1219. print(`【${target_name}】${t('willAward')}: ${todoReactions.length} ${t('itemAndTotal')}: ${coast.toLocaleString()} ${t('points')}`)
  1220. const plist = [];
  1221. for (const id of todoReactions) {
  1222. plist.push(sendAwardReaction(token, target_type, itemID, id));
  1223. }
  1224. print(t('sendingAwards'));
  1225. const result = await Promise.all(plist);
  1226. const [succ, fail] = countSuccess(result);
  1227. print(`${t('requestsSummary')}: ${succ} / ${fail}`);
  1228. }
  1229. print(t('wait2Seconds'));
  1230. await asleep(2000);
  1231. //统计新的打赏列表,计算打赏点数
  1232. const [succNew, newReactions] = await getAwardRecords(token, target_type, itemID);
  1233. if (!succNew) {
  1234. print(t('fetchAwardItemFailedRetry'));
  1235. continue;
  1236. }
  1237. const diffReactions = filterDiffReactions(newReactions, GoldReactions);
  1238. coast = sumReactionsPoints(diffReactions);
  1239. pointsLeft -= coast;
  1240. addHistory(steamID, taskNick, coast);
  1241. print(`【${target_name}】${t('awardSuccess')}: ${diffReactions.length} ${t('itemAndTotal')}: ${coast.toLocaleString()} ${t('points')}`);
  1242. break;
  1243. }
  1244. GTask.points = pointsLeft;
  1245. if (pointsLeft <= 0) {
  1246. GTask.work = false;
  1247. }
  1248. GM_setValue('task', GTask);
  1249. process = genProgressBar((pointsGoal - pointsLeft) / pointsGoal * 100);
  1250.  
  1251. spaceLine(3);
  1252. print(`【${target_name}】${t('taskFinishedPointsSummary')}: ${pointsLeft.toLocaleString()} / ${pointsGoal.toLocaleString()} ${t('points')}`);
  1253. print(`${t('currentProcess')}: ${process}`);
  1254. spaceLine(3);
  1255.  
  1256. print(t('updateBotPointsBalance'));
  1257.  
  1258. await getPoints(bot, token)
  1259. .then((p) => {
  1260. GBots[bot].points = p;
  1261. GM_setValue('bots', GBots);
  1262. print(`${t('bot')}【${botNick}】${t('pointsBalanceUpdateSuccess')}: ${p.toLocaleString()} ${t('points')}`);
  1263. if (p < 300) {
  1264. print(`${t('bot')}【${botNick}】${t('lackOfPointsTaskEnd')}`);
  1265. GTask.work = false;
  1266. }
  1267. }).catch((r) => {
  1268. print(`${t('bot')}【${botNick}】${t('pointBalanceUpdateFailed')}: ${r}`);
  1269. });
  1270.  
  1271. if (!GTask.work) {
  1272. break;
  1273. }
  1274. }
  1275. }
  1276. }
  1277. if (workflow.length > 0) {
  1278. await aiosleep(1000);
  1279. }
  1280. }
  1281. } else {
  1282. delete GBots[bot];
  1283. GM_setValue('bots', GBots);
  1284. print(t('botDataError'));
  1285. showAlert(t('error'), t('botDataError'), false);
  1286. }
  1287. spaceLine(4);
  1288. if (pointsLeft <= 0) {
  1289. GTask = {};
  1290. print(t('awardTaskFinish'));
  1291. } else {
  1292. GTask.work = false;
  1293. print(t('awardTaskNotFinish'));
  1294. }
  1295. GM_setValue('task', GTask);
  1296. appllyTask();
  1297. showStatus(t('stop'), false);
  1298. flashHistoryList();
  1299. }
  1300. //====================================================================================
  1301. //显示提示
  1302. function showAlert(title, text, succ = true) {
  1303. ShowAlertDialog(`${succ ? '✅' : '❌'}${title}`, `<div>${text}</div>`);
  1304. }
  1305. //显示确认
  1306. function showConfirm(title, text, done = null, cancel = null) {
  1307. ShowConfirmDialog(`⚠️${title}`, `<div>${text}</div>`, t('confirm'), t('cancel'))
  1308. .done(() => {
  1309. if (done) { done(); }
  1310. })
  1311. .fail(() => {
  1312. if (cancel) { cancel(); }
  1313. })
  1314. }
  1315. //显示状态
  1316. function showStatus(text, run = true) {
  1317. const { awardStatus, workHide } = GObjs;
  1318. workHide.disabled = run;
  1319. awardStatus.textContent = `${run ? '🟩' : '🟥'} ${text}`;
  1320. }
  1321. //读取设置
  1322. function loadConf() {
  1323. const bots = GM_getValue('bots');
  1324. GBots = isEmptyObject(bots) ? {} : bots;
  1325. const hs = GM_getValue('history');
  1326. GHistory = isEmptyObject(hs) ? {} : hs;
  1327. const task = GM_getValue('task');
  1328. GTask = isEmptyObject(task) ? {} : task;
  1329. const panel = GM_getValue('panel');
  1330. GPanel = isEmptyObject(panel) ? {} : panel;
  1331. }
  1332. //保存设置
  1333. function saveConf() {
  1334. GM_setValue('bots', GBots);
  1335. GM_setValue('history', GHistory);
  1336. GM_setValue('task', GTask);
  1337. GM_setValue('panel', GPanel);
  1338. }
  1339. //是不是空对象
  1340. function isEmptyObject(obj) {
  1341. for (const _ in obj) { return false; }
  1342. return true;
  1343. }
  1344. //显示加载面板
  1345. function loadScreen(show = true, msg = t('operating')) {
  1346. const { busyPanel, busyMessage } = GObjs;
  1347. if (show) {
  1348. busyPanel.style.opacity = '1';
  1349. busyPanel.style.visibility = 'visible';
  1350. if (msg) {
  1351. busyMessage.textContent = msg;
  1352. }
  1353. } else {
  1354. busyPanel.style.opacity = '0';
  1355. busyPanel.style.visibility = 'hidden';
  1356. }
  1357. }
  1358. //显示日志面板
  1359. function workScreen(show = true) {
  1360. const { workPanel } = GObjs;
  1361. if (show) {
  1362. workPanel.style.opacity = '1';
  1363. workPanel.style.visibility = 'visible';
  1364. } else {
  1365. workPanel.style.opacity = '0';
  1366. workPanel.style.visibility = 'hidden';
  1367. }
  1368. }
  1369. //生成进度条
  1370. const BAR_STYLE = '⣀⣄⣤⣦⣶⣷⣿';
  1371. function genProgressBar(percent) {
  1372. const full_symbol = '⣿';
  1373. const none_symbol = '⣀';
  1374. const percentStr = ` ${percent.toFixed(2)}%`
  1375. if (percent >= 100) {
  1376. return full_symbol.repeat(40) + percentStr;
  1377. } else {
  1378. percent = percent / 100;
  1379. let full = Math.floor(percent * 40);
  1380. let rest = percent * 40 - full;
  1381. let middle = Math.floor(rest * 6);
  1382. if (percent !== 0 && full === 0 && middle === 0) { middle = 1; }
  1383. let d = Math.abs(percent - (full + middle / 6) / 40) * 100;
  1384. if (d < Number.POSITIVE_INFINITY) {
  1385. let m = BAR_STYLE[middle];
  1386. if (full === 40) { m = ""; }
  1387. return full_symbol.repeat(full) + m + BAR_STYLE[0].repeat(39 - full) + percentStr;
  1388. }
  1389. return none_symbol.repeat(40) + percentStr;
  1390. }
  1391. }
  1392. //日志时间
  1393. function formatTime() {
  1394. const date = new Date();
  1395. return `${date.toLocaleDateString()} ${date.toTimeString().substr(0, 8)}`;
  1396. }
  1397. //输出日志
  1398. function print(msg, level = 'I') {
  1399. const { workLog } = GObjs;
  1400. const time = formatTime();
  1401. workLog.value += `${time} - ${level} - ${msg}\n`;
  1402. workLog.scrollTop = workLog.scrollHeight;
  1403. console.log(`${time} - ${level} - ${msg}`);
  1404. }
  1405. //画分割线
  1406. function spaceLine(style = 1) {
  1407. switch (style) {
  1408. case 1:
  1409. print('#'.repeat(68));
  1410. return
  1411. case 2:
  1412. print('='.repeat(68));
  1413. return
  1414. case 3:
  1415. print('+'.repeat(68));
  1416. return
  1417. case 4:
  1418. print('~'.repeat(68));
  1419. return
  1420. }
  1421. }
  1422. //异步延时
  1423. function asleep(ms) {
  1424. return new Promise(resolve => setTimeout(resolve, ms));
  1425. }
  1426. //====================================================================================
  1427. //计算合适的打赏项目
  1428. function selectFitableReactions(goal, doneList) {
  1429. const fitableList = [];
  1430. const aviableList = [];
  1431. for (const id of reactionIDs) {
  1432. if (doneList.indexOf(id) === -1) {
  1433. aviableList.push(id);
  1434. }
  1435. }
  1436. aviableList.sort((a, b) => { return reactionsDict[a] - reactionsDict[b]; });
  1437. for (const id of aviableList) {
  1438. if (goal < 100) {
  1439. break;
  1440. }
  1441. const value = reactionsDict[id] / 3;
  1442. if (goal >= value) {
  1443. fitableList.push(id);
  1444. goal -= value;
  1445. }
  1446. }
  1447. return fitableList;
  1448. }
  1449. //获取新增打赏项目
  1450. function filterDiffReactions(newList, oldList) {
  1451. const diffList = [];
  1452. for (const id of newList) {
  1453. if (oldList.indexOf(id) === -1) {
  1454. diffList.push(id);
  1455. }
  1456. }
  1457. return diffList;
  1458. }
  1459. //计算打赏项目点数开销
  1460. function sumReactionsPoints(reactions) {
  1461. let points = 0;
  1462. for (const id of reactions) {
  1463. points += reactionsDict[id];
  1464. }
  1465. return points / 3;
  1466. }
  1467. //统计成功失败
  1468. function countSuccess(result) {
  1469. let succ = 0, fail = 0;
  1470. for (const r of result) {
  1471. if (r) {
  1472. succ++;
  1473. } else {
  1474. fail++;
  1475. }
  1476. }
  1477. return ([succ, fail]);
  1478. }
  1479. //异步延时
  1480. function aiosleep(ms) {
  1481. return new Promise(resolve => setTimeout(resolve, ms))
  1482. }
  1483. //====================================================================================
  1484. function getMySteamID() {
  1485. return new Promise((resolve, reject) => {
  1486. $http.getText('https://store.steampowered.com/account/?l=english')
  1487. .then((text) => {
  1488. let match1 = text.match(/pageheader">([\s\S]+)'s account/);
  1489. let match2 = text.match(/Steam ID: (\d+)/);
  1490.  
  1491. if (match1 && match2) {
  1492. resolve({ nick: match1[1], steamID: match2[1] });
  1493. } else {
  1494. reject(t('steamStoreNotLogin'));
  1495. }
  1496. })
  1497. .catch((reason) => {
  1498. reject(reason);
  1499. });
  1500. });
  1501. }
  1502. function getToken() {
  1503. return new Promise((resolve, reject) => {
  1504. $http.get('https://store.steampowered.com/pointssummary/ajaxgetasyncconfig')
  1505. .then(({ data }) => {
  1506. if (isEmptyObject(data)) {
  1507. reject(t('steamStoreNotLogin'));
  1508. }
  1509. resolve(data.webapi_token);
  1510. })
  1511. .catch((reason) => {
  1512. reject(reason);
  1513. });
  1514. });
  1515. }
  1516. function getPoints(steamID, token) {
  1517. return new Promise((resolve, reject) => {
  1518. $http.get(`https://api.steampowered.com/ILoyaltyRewardsService/GetSummary/v1/?access_token=${token}&steamid=${steamID}`)
  1519. .then(({ response }) => {
  1520. if (isEmptyObject(response)) {
  1521. reject(t('steamStoreNotLogin'));
  1522. }
  1523. try {
  1524. const points = parseInt(response.summary.points);
  1525. if (points === points) {
  1526. resolve(points);
  1527. } else {
  1528. reject(t('parseDataFailedMaybeNetworkError'));
  1529. }
  1530. } catch (e) {
  1531. reject(t('parseDataFailedMaybeNetworkError'));
  1532. }
  1533. })
  1534. .catch((reason) => {
  1535. reject(reason);
  1536. });
  1537. });
  1538. }
  1539. function getProfile(steamID) {
  1540. return new Promise((resolve, reject) => {
  1541. $http.getText(`https://steamcommunity.com/profiles/${steamID}/?xml=1`)
  1542. .then((text) => {
  1543. try {
  1544. const match = text.match(/<steamID><!\[CDATA\[([\s\S]*)\]\]><\/steamID>/) ||
  1545. text.match(/<steamID>([\s\S]*)<\/steamID>/);
  1546. if (match) {
  1547. resolve([true, match[1].substring()]);
  1548. } else {
  1549. resolve([false, null]);
  1550. }
  1551. } catch (e) {
  1552. reject(e);
  1553. }
  1554. })
  1555. .catch((reason) => {
  1556. reject(reason);
  1557. });
  1558. });
  1559. }
  1560. function getAwardCounts(steamID, type) {
  1561. let subPath, preg;
  1562. switch (type) {
  1563. case 'r':
  1564. subPath = 'recommended/?l=schinese';
  1565. preg = /共 (\d+) 项条目/;
  1566. break;
  1567. case 's':
  1568. subPath = 'screenshots/?l=schinese';
  1569. preg = /共 (\d+) 张/;
  1570. break;
  1571. case 'i':
  1572. subPath = 'images/?l=schinese';
  1573. preg = /共 (\d+) 张/;
  1574. break;
  1575. default:
  1576. throw 'type错误';
  1577. }
  1578. return new Promise((resolve, reject) => {
  1579. $http.getText(`https://steamcommunity.com/profiles/${steamID}/${subPath}`)
  1580. .then((text) => {
  1581. try {
  1582. const match = text.match(preg);
  1583. const count = match ? Number(match[1]) : 0;
  1584. resolve([type, true, count]);
  1585. } catch (e) {
  1586. resolve([type, false, 0]);
  1587. }
  1588. })
  1589. .catch((reason) => {
  1590. console.error(reason);
  1591. resolve([type, false, 0]);
  1592. });
  1593. });
  1594. }
  1595. function getAwardItems(steamID, type, p = 1) {
  1596. let subPath, preg;
  1597. switch (type) {
  1598. case 'r':
  1599. subPath = `recommended/?p=${p}&l=schinese`;
  1600. preg = /id="RecommendationVoteUpBtn(\d+)"/g;
  1601. break;
  1602. case 's':
  1603. subPath = `screenshots/?p=${p}&view=grid&l=schinese`;
  1604. preg = /id="imgWallHover(\d+)"/g;
  1605. break;
  1606. case 'i':
  1607. subPath = `images/?p=${p}&view=grid&l=schinese`;
  1608. preg = /id="imgWallHover(\d+)"/g;
  1609. break;
  1610. default:
  1611. throw t('typeError');
  1612. }
  1613. return new Promise((resolve, reject) => {
  1614. $http.getText(`https://steamcommunity.com/profiles/${steamID}/${subPath}`)
  1615. .then((text) => {
  1616. try {
  1617. const result = [];
  1618. const matches = text.matchAll(preg);
  1619. for (const match of matches) {
  1620. result.push(match[1]);
  1621. }
  1622. resolve([true, result]);
  1623. } catch (e) {
  1624. console.error(e);
  1625. resolve([false, e]);
  1626. }
  1627. })
  1628. .catch((reason) => {
  1629. console.error(reason);
  1630. resolve([false, reason]);
  1631. });
  1632. });
  1633. }
  1634. function getAwardRecords(token, targetType, targetID) {
  1635. return new Promise((resolve, reject) => {
  1636. const params = `access_token=${token}&target_type=${targetType}&targetid=${targetID}`;
  1637. $http.get('https://api.steampowered.com/ILoyaltyRewardsService/GetReactions/v1/?' + params)
  1638. .then(({ response }) => {
  1639. const { reactionids } = response;
  1640. resolve([true, reactionids || []]);
  1641. })
  1642. .catch((reason) => {
  1643. console.error(reason);
  1644. resolve([false, null]);
  1645. });
  1646. });
  1647. }
  1648. function sendAwardReaction(token, targetType, targetID, reactionID) {
  1649. return new Promise((resolve, reject) => {
  1650. const params = `access_token=${token}&target_type=${targetType}&targetid=${targetID}&reactionid=${reactionID}`;
  1651. $http.post('https://api.steampowered.com/ILoyaltyRewardsService/AddReaction/v1/?' + params)
  1652. .then((json) => {
  1653. console.log(json);
  1654. resolve(true);
  1655. })
  1656. .catch((reason) => {
  1657. console.error(reason);
  1658. resolve(false);
  1659. });
  1660. });
  1661. }
  1662. })();
  1663. //====================================================================================
  1664. class Request {
  1665. constructor(timeout = 3000) {
  1666. this.timeout = timeout;
  1667. }
  1668. get(url, opt = {}) {
  1669. return this.baseRequest(url, 'GET', opt, 'json');
  1670. }
  1671. getHtml(url, opt = {}) {
  1672. return this.baseRequest(url, 'GET', opt, '');
  1673. }
  1674. getText(url, opt = {}) {
  1675. return this.baseRequest(url, 'GET', opt, 'text');
  1676. }
  1677. post(url, data, opt = {}) {
  1678. opt.data = JSON.stringify(data);
  1679. return this.baseRequest(url, 'POST', opt, 'json');
  1680. }
  1681. baseRequest(url, method = 'GET', opt = {}, responseType = 'json') {
  1682. Object.assign(opt, {
  1683. url, method, responseType, timeout: this.timeout
  1684. });
  1685. return new Promise((resolve, reject) => {
  1686. opt.ontimeout = opt.onerror = reject;
  1687. opt.onload = ({ readyState, status, response, responseText }) => {
  1688. if (readyState === 4 && status === 200) {
  1689. if (responseType == 'json') {
  1690. resolve(response);
  1691. } else if (responseType == 'text') {
  1692. resolve(responseText);
  1693. }
  1694. } else {
  1695. console.error(t('networkError'));
  1696. console.log(readyState);
  1697. console.log(status);
  1698. console.log(response);
  1699. reject(t('parseError'));
  1700. }
  1701. }
  1702. GM_xmlhttpRequest(opt);
  1703. });
  1704. }
  1705. }
  1706. const $http = new Request();
  1707.  
  1708. //CSS表
  1709. GM_addStyle(`.aam_panel,
  1710. .aam_work {
  1711. padding: 10px;
  1712. display: flex;
  1713. }
  1714. .aam_work {
  1715. z-index: 500 !important;
  1716. }
  1717. .aam_busy {
  1718. width: 100%;
  1719. height: 100%;
  1720. z-index: 700;
  1721. position: absolute;
  1722. top: 0;
  1723. left: 0;
  1724. background: rgba(0, 0, 0, 0.7);
  1725. display: table;
  1726. visibility: hidden;
  1727. opacity: 0;
  1728. transition: all 0.1s;
  1729. }
  1730. .aam_busy_content {
  1731. display: table-cell;
  1732. vertical-align: middle;
  1733. text-align: center;
  1734. }
  1735. .aam_left {
  1736. width: 61%;
  1737. padding-right: 10px;
  1738. }
  1739. .aam_award {
  1740. width: 39%;
  1741. }
  1742. .aam_list,
  1743. .aam_select,
  1744. .aam_input,
  1745. .aam_textarea {
  1746. background-color: #fff !important;
  1747. color: #000 !important;
  1748. border: none !important;
  1749. border-radius: 0 !important;
  1750. }
  1751. .aam_input {
  1752. width: 98% !important;
  1753. text-align: center;
  1754. }
  1755. .aam_list {
  1756. height: 230px;
  1757. }
  1758. .aam_textarea {
  1759. height: calc(100% - 85px);
  1760. width: calc(100% - 45px);
  1761. resize: none;
  1762. font-size: 12px;
  1763. }
  1764. .aam_left > div > *,
  1765. .aam_award:not(span, button) > * {
  1766. width: 100%;
  1767. margin-bottom: 5px;
  1768. }
  1769. .aam_btns > button:not(:last-child) {
  1770. margin-right: 4px;
  1771. }
  1772. .aam_award_btns {
  1773. z-index: 600;
  1774. bottom: 10px;
  1775. position: absolute;
  1776. }
  1777. .aam_work > * {
  1778. position: absolute;
  1779. }
  1780. .aam_work > span {
  1781. bottom: 12%;
  1782. left: 70px;
  1783. }
  1784. .aam_work > button {
  1785. bottom: 11%;
  1786. }
  1787. .aam_a {
  1788. margin-left: 110px;
  1789. }`);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址