// ==UserScript== // @name EPIC白嫖小助手 // @description 每1小时检测一次是否有可以白嫖的epic游戏 // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.1.9 // @author CodFrm,Cosil // @grant GM_xmlhttpRequest // @grant GM_notification // @grant GM_closeNotification // @grant GM_openInTab // @grant GM_getValue // @grant GM_setValue // @storageName find_epic_free_games // @connect store-site-backend-static.ak.epicgames.com // @connect www.epicgames.com // @crontab 0 * * * * // @license GPLv3 // ==/UserScript== let url = "https://store-site-backend-static.ak.epicgames.com/freeGamesPromotions?locale=zh-Hant&country=CN&allowCountries=CN,HK"; function request(option) { return new Promise((resolve, reject) => { option.onload = (res) => { if (res.status != 200) { reject(); } resolve(res) }; option.onerror = () => { reject() }; GM_xmlhttpRequest(option); }) } return new Promise((resolve, reject) => { GM_xmlhttpRequest({ url: url, responseType: "json", onload: async (resp) => { if (resp.status != 200) { GM_notification("epic白嫖失败,网站检测错误:" + resp.status); resolve(); } else { let games = []; let msg = "" let elements = resp.response.data.Catalog.searchStore.elements; let itemInLibrary = GM_getValue("item_in_library", {}); console.log("get::item_in_library", itemInLibrary, Object.keys(itemInLibrary).length); //超过10个清空存储 itemInLibrary = Object.keys(itemInLibrary).length > 10 ? {} : itemInLibrary; console.log("now_item_in_library", itemInLibrary); for (const key in elements) { //本身不免费,现在免费了 if (elements[key].price.totalPrice.originalPrice && !elements[key].price.totalPrice.discountPrice) { //活动还在且未购买 if (elements[key].status == "ACTIVE" && !Object.keys(itemInLibrary).includes(elements[key].id)) { msg += elements[key].title + "; " let img = ""; for (const imgkey in elements[key].keyImages) { if (elements[key].keyImages[imgkey].type == "DieselStoreFrontWide") { img = elements[key].keyImages[imgkey].url; break; } } games.push({ title: elements[key].title, url: "https://www.epicgames.com/store/zh-Hant/p/" + elements[key].urlSlug, id: elements[key].id, image: img, }); } } } console.log("found_games", games); let parser = new DOMParser(); console.log("req_start"); await Promise.all(games.map(game => request({ url: game.url }))).then(resArr => { console.log("req_end", resArr); for (let i in resArr) { //已购标识 let match = /(?<="diesel.common.button.in_library"\s*:\s*")[^,"]+(?=",)/.exec(resArr[i].responseText); let in_library_ctx = "\error"; if (match) { in_library_ctx = match[0]; } //购买状态 let status = parser.parseFromString(resArr[i].response, "text/html").querySelector("[data-component=PurchaseCTA]")?.innerText; console.log(resArr[i].finalUrl, in_library_ctx, status); if (in_library_ctx === status) { itemInLibrary[games[i].id] = games[i].title; } } }) //更新已购列表 GM_setValue("item_in_library", itemInLibrary); console.log("update_value", GM_getValue("item_in_library")); //删选已购买 games = games.filter(game => !Object.keys(itemInLibrary).includes(game.id)); if (!games.length) { return resolve(); } console.log(games[0].image); GM_notification({ title: "今日白嫖名单", text: msg, buttons: [{ title: "我知道了" }, { title: "马上去白嫖" }], onclick(id, btn) { if (btn === 1) { for (let key in games) { GM_openInTab(games[key].url); } } GM_closeNotification(id); resolve(); }, timeout: 10 * 1000, ondone(click, id) { if (!click) { resolve(); } } }); } }, onerror() { GM_notification("epic白嫖失败,网络异常"); resolve(); } }); });