Greasy Fork is available in English.

Hikari_Field_Helper

Hikari_Field入库游戏检测

Installer dette scriptet?
Skaperens foreslåtte skript

Du vil kanskje også like Auto_Sub3.

Installer dette scriptet
  1. // ==UserScript==
  2. // @name:zh-CN Hikari_Field入库检测
  3. // @name Hikari_Field_Helper
  4. // @namespace https://blog.chrxw.com
  5. // @supportURL https://blog.chrxw.com/scripts.html
  6. // @contributionURL https://afdian.com/@chr233
  7. // @version 2.19
  8. // @description Hikari_Field入库游戏检测
  9. // @description:zh-CN Hikari_Field入库游戏检测
  10. // @author Chr_
  11. // @include https://keylol.com/*
  12. // @include https://store.hikarifield.co.jp/libraries
  13. // @license AGPL-3.0
  14. // @icon https://blog.chrxw.com/favicon.ico
  15. // @resource data https://raw.chrxw.com/GM_Scripts/master/Keylol/Data/Hikari_Field_Helper.json
  16. // @grant GM_getResourceText
  17. // @grant GM_setValue
  18. // @grant GM_getValue
  19. // @grant GM_addStyle
  20. // ==/UserScript==
  21.  
  22.  
  23. (() => {
  24. "use strict";
  25.  
  26. const HFSHOP = "https://store.hikarifield.co.jp/shop/";
  27. const HFLIBARY = "https://store.hikarifield.co.jp/libraries";
  28.  
  29. const { INFO, DESC } = JSON.parse(GM_getResourceText("data"));
  30. const host = window.location.host;
  31.  
  32. if (host === "store.hikarifield.co.jp") {
  33. //更新库存
  34. const myGames = document.querySelectorAll(".game-cover>a");
  35. const ownedGames = [625760]; //魔卡魅恋(免费)
  36. for (const ele of myGames) {
  37. const key = ele.href?.replace(HFSHOP, "");
  38. if (key) {
  39. let [gameName, appID, _, __] = INFO[key] ?? [null, null, null];
  40. if (appID !== null) {
  41. ownedGames.push(appID);
  42. console.log(`已拥有 ${gameName} ${appID}`);
  43. }
  44. } else {
  45. console.error(`${ele.href} 无效`);
  46. }
  47. }
  48. //储存列表
  49. GM_setValue("ownedGames", ownedGames);
  50. GM_setValue("refreshTime", new Date().toISOString());
  51. swal({
  52. position: "top-end",
  53. text: "导入游戏列表成功",
  54. icon: "success",
  55. button: false,
  56. timer: 1200
  57. });
  58.  
  59. } else if (host.endsWith("keylol.com")) {
  60. //其乐
  61. if (document.title.search("Keylol") === -1) { return; } //跳过iframe
  62. const ownedGames = new Set(GM_getValue("ownedGames") ?? []);
  63. const refreshTime = GM_getValue("refreshTime") ?? null;
  64.  
  65. if (ownedGames.size === 0) {
  66. if (confirm("是否立即导入游戏列表?")) {
  67. window.location.href = HFLIBARY;
  68. } else {
  69. showError("【可以在悬浮窗口中进行同步】");
  70. GM_setValue("ownedGames", [0]);
  71. }
  72. }
  73.  
  74. setTimeout(() => {
  75. const steamLinks = document.querySelectorAll("a[href^='https://store.steampowered.com/'],a[href^='https://steamdb.info/app/']");
  76. const HFLinks = document.querySelectorAll("a[href^='https://store.hikarifield.co.jp/shop/'],a[href^='https://shop.hikarifield.co.jp/shop/']");
  77. let flag = HFLinks.length > 0;
  78. const grubAppid = RegExp(/app\/(\d+)\/?/);
  79. const grubHFKey = RegExp(/shop\/(\S+)\/?/);
  80. for (const ele of steamLinks) {
  81. const href = ele.href;
  82. if (href) {
  83. const appID = parseInt(grubAppid.exec(href)?.[1] ?? 0);
  84. if (appID > 0) {
  85. if (ownedGames.has(appID)) {
  86. ele.classList.add("steam-info-link");
  87. ele.classList.add("steam-info-own");
  88. flag = true;
  89. }
  90. }
  91. }
  92. }
  93. if (!flag) { return; } //未匹配到游戏,结束运行
  94. for (const ele of HFLinks) {
  95. const href = ele.href;
  96. if (href) {
  97. const key = grubHFKey.exec(href)?.[1];
  98. if (key) {
  99. let [_, appID, __, ___] = INFO[key] ?? [null, null, null, null];
  100. if (appID !== null) {
  101. if (ownedGames.has(appID)) {
  102. ele.classList.add("steam-info-link");
  103. ele.classList.add("steam-info-own");
  104. }
  105. ele.setAttribute("data-hf", key);
  106. ele.addEventListener("mouseenter", showDiag);
  107. ele.addEventListener("mouseleave", hideDiag);
  108. }
  109. } else {
  110. console.log(ele);
  111. }
  112. }
  113. }
  114. }, 1000);
  115.  
  116. const diagObjs = {}; // 小部件DOM对象
  117. let isShow = false; // 悬浮窗是否显示
  118. let timer = -1; // 隐藏计时器
  119.  
  120. //创建弹窗小部件
  121. function initDiag() {
  122. const newDiv = (cls) => { const d = document.createElement("div"); if (cls) { d.className = cls; } return d; };
  123.  
  124. const hfBox = newDiv("hf-box");
  125.  
  126. let lastRefresh;
  127. if (refreshTime !== null) {
  128. try {
  129. const t = new Date(refreshTime);
  130. lastRefresh = `账号同步于 ${t.toLocaleString()} 点击刷新`;
  131. } catch (e) {
  132. console.error(e);
  133. lastRefresh = "读取同步时间出错, 点击刷新";
  134. }
  135. } else {
  136. lastRefresh = "账号未同步, 点击刷新";
  137. }
  138.  
  139. hfBox.style.display = "none";
  140.  
  141. hfBox.innerHTML = `
  142. <div class="hf-head">
  143. <span title="">占位</span>
  144. </div>
  145. <div class="hf-body">
  146. <img src="https://cdn.cloudflare.steamstatic.com/steam/apps/1662840/header.jpg">
  147. </div>
  148. <div class="hf-foot">
  149. <div class="hf-describe">
  150. <span title="">...</span>
  151. </div>
  152. <div class="hf-line"></div>
  153. <div class="hf-detail">
  154. <div class="hf-line"></div>
  155. <div><a href="${HFLIBARY}" target="_blank">${lastRefresh}</a></div>
  156. <div class="hf-line"></div>
  157. <p class="hf-hf"><b>HF商店:</b><span class="hf-unknown">占位</span><a href="#" target="_blank" class="hf-link">前往商店</a></p>
  158. <div class="hf-line"></div>
  159. <p class="hf-steam"><b>Steam: </b><span class="hf-unknown">占位</span> <a href="#" target="_blank" class="hf-link steam-info-loaded">前往商店</a> (<a href="#" target="_blank">SteamDB</a>)</p></div>
  160. <div class="hf-line"></div>
  161. </div>
  162. </div>`
  163.  
  164. document.body.appendChild(hfBox);
  165.  
  166. const eleTitle = hfBox.querySelector("div.hf-head>span");
  167. const eleImg = hfBox.querySelector("div.hf-body>img");
  168. const eleDesc = hfBox.querySelector("div.hf-describe>span");
  169. const eleHfState = hfBox.querySelector("p.hf-hf>span");
  170. const eleHfLink = hfBox.querySelector("p.hf-hf>a");
  171. const eleSteamState = hfBox.querySelector("p.hf-steam>span");
  172. const eleSteamLink = hfBox.querySelector("p.hf-steam>a:first-of-type");
  173. const eleSteamDBLink = hfBox.querySelector("p.hf-steam>a:last-of-type");
  174.  
  175. hfBox.addEventListener("mouseenter", diagMoveIn);
  176. hfBox.addEventListener("mouseleave", hideDiag);
  177.  
  178. Object.assign(diagObjs, {
  179. hfBox, eleTitle, eleImg, eleDesc, eleHfState,
  180. eleHfLink, eleSteamState, eleSteamLink, eleSteamDBLink
  181. });
  182. }
  183.  
  184. initDiag();
  185.  
  186. const { script: { version } } = GM_info;
  187. const Tail = ` - Hikari Field Helper v${version} by Chr_』`;
  188.  
  189. //更新小部件显示
  190. function showDiag(event) {
  191. isShow = true;
  192. clearTmout();
  193.  
  194. const ele = event.target;
  195. const key = ele.getAttribute("data-hf");
  196.  
  197. const { hfBox, eleTitle, eleImg, eleDesc, eleHfState, eleHfLink, eleSteamState, eleSteamLink, eleSteamDBLink } = diagObjs;
  198.  
  199. const [gameName, appID, steamState, hfState] = INFO[key] ?? [null, null, null, null];
  200. const describe = DESC[key] ?? "";
  201.  
  202. if (!gameName) { return; }
  203.  
  204. eleTitle.title = gameName + Tail;
  205. eleTitle.textContent = gameName;
  206. eleImg.src = `https://cdn.cloudflare.steamstatic.com/steam/apps/${appID}/header.jpg`;
  207.  
  208. eleDesc.textContent = describe.substr(0, 72) + "...";
  209. eleDesc.title = describe;
  210.  
  211. switch (hfState) {
  212. case -1:
  213. eleHfState.textContent = "已下架";
  214. eleHfState.className = "hf-unavailable";
  215. break;
  216. case 1:
  217. eleHfState.textContent = "可购买";
  218. eleHfState.className = "hf-available";
  219. break;
  220. default:
  221. eleHfState.textContent = "未发售";
  222. eleHfState.className = "hf-unknown";
  223. break;
  224. }
  225. eleHfLink.href = HFSHOP + key;
  226.  
  227. switch (steamState) {
  228. case -1:
  229. eleSteamState.textContent = "已下架";
  230. eleSteamState.className = "hf-unavailable";
  231. eleSteamLink.classList.add("hf-disabled");
  232. break;
  233. case 1:
  234. eleSteamState.textContent = "可购买";
  235. eleSteamState.className = "hf-available";
  236. eleSteamLink.classList.remove("hf-disabled");
  237. break;
  238. default:
  239. eleSteamState.textContent = "未发售";
  240. eleSteamState.className = "hf-unknown";
  241. eleSteamLink.classList.remove("hf-disabled");
  242. break;
  243. }
  244. eleSteamLink.href = `https://store.steampowered.com/app/${appID}/`;
  245. eleSteamDBLink.href = `https://steamdb.info/app/${appID}/`;
  246.  
  247. const { top, right } = ele.getBoundingClientRect();
  248.  
  249. const boxHeight = 303;
  250. const boxWidth = 300;
  251.  
  252. const boxTop = Math.min(top, document.documentElement.clientHeight - boxHeight) + window.scrollY;
  253. const boxLeft = Math.min(right, document.documentElement.clientWidth - boxWidth) + window.scrollX;
  254.  
  255. hfBox.style.left = `${boxLeft}px`;
  256. hfBox.style.top = `${boxTop}px`;
  257. hfBox.style.opacity = 1;
  258. hfBox.style.display = "";
  259. }
  260. //清除计时器
  261. function clearTmout() {
  262. if (timer !== -1) {
  263. clearTimeout(timer);
  264. timer = -1;
  265. }
  266. }
  267. //对话框鼠标移入
  268. function diagMoveIn(event) {
  269. clearTmout();
  270. }
  271. //隐藏小部件
  272. function hideDiag(event) {
  273. clearTmout();
  274. const { hfBox } = diagObjs;
  275. if (isShow) {
  276. timer = setTimeout(() => {
  277. isShow = false;
  278. timer = -1;
  279. hfBox.style.opacity = 0;
  280. setTimeout(() => {
  281. hfBox.style.cssText = "display:none; opacity: 0;";
  282. }, 200);
  283. }, 900);
  284. }
  285. }
  286. }
  287.  
  288. })();
  289.  
  290. GM_addStyle(`.hf-line {
  291. margin-top: 0.5em;
  292. }
  293. .hf-available {
  294. color: #6c3;
  295. padding: 0 0.3em;
  296. }
  297. .hf-unavailable {
  298. color: #e60;
  299. padding: 0 0.3em;
  300. }
  301. .hf-unknown {
  302. color: #ccc;
  303. padding: 0 0.3em;
  304. }
  305. .hf-available::before {
  306. content: "☑";
  307. padding-right: 0.3em;
  308. }
  309. .hf-unavailable::before {
  310. content: "☒";
  311. padding-right: 0.3em;
  312. }
  313. .hf-unknown::before {
  314. content: "☐";
  315. padding-right: 0.3em;
  316. }
  317. .hf-disabled {
  318. pointer-events: none;
  319. cursor: default;
  320. text-decoration: line-through !important;
  321. }
  322. .hf-detail > div {
  323. text-align: center;
  324. }
  325. .hf-box {
  326. width: 300px;
  327. position: absolute;
  328. left: 0;
  329. top: 0;
  330. z-index: 100;
  331. background-color: #343a40;
  332. color: #ccc;
  333. border-radius: 5px;
  334. transition: all 0.2s;
  335. }
  336. .hf-box * {
  337. max-width: 100%;
  338. }
  339. .hf-head {
  340. overflow: hidden;
  341. white-space: nowrap;
  342. margin: 4px 0;
  343. }
  344. .hf-head > span {
  345. font-size: 12px;
  346. font-weight: bold;
  347. padding: 5px 16px;
  348. }
  349. .hf-head > a {
  350. position: absolute;
  351. right: 5px;
  352. cursor: pointer;
  353. }
  354. .hf-body {
  355. height: 140px;
  356. }
  357. .hf-foot {
  358. margin: 5px;
  359. }
  360. .hf-foot b {
  361. color: #8a959c;
  362. font-weight: normal;
  363. }
  364. .hf-foot a {
  365. color: #fff;
  366. text-decoration: none;
  367. }
  368.  
  369. `);