// ==UserScript==
// @name Fanatical批量刮key
// @namespace kb1000fx
// @version 0.2
// @description 批量提取整理F站key
// @author kb1000fx
// @include /https://www\.fanatical\.com/[\S]*((/orders)|(/orders\?page=[0-9]))$/
// @icon https://cdn.fanatical.com/production/icons/favicon-32x32.png
// @grant GM_addStyle
// @grant GM_setClipboard
// @grant unsafeWindow
// @grant window.onload
// @require https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.slim.min.js
// @downloadURL none
// ==/UserScript==
(function(){
'use strict';
unsafeWindow.$ = $;
const cbxHTML = `
`;
const css = `
.table-item{
display: flex;
flex-direction: row;
}
.checkbox{
display: flex;
justify-content:center;
width: 5%;
align-items: center;
}
.table-item a{
width: 95%
}
.tm-panel{
margin-bottom: 24px;
}
.tm-btn{
margin-right: 20px;
}
`;
const panelHTML = `
`;
let orderIDList = [];
let unrevealedList = [];
let revealedList = [];
let sortedJson ={};
let str = "";
const getRes = async ()=>{
orderIDList = [];
unrevealedList = [];
revealedList = [];
$("input[name='ordercbx']:checked").each(function (i,e){
const orderStr = $(e).parent("div").next().attr("href");
orderIDList.push( orderStr.split("/")[3] );
});
console.log(`已选择 ${orderIDList.length}个订单`);
for (let index = 0; index < orderIDList.length; index++) {
const ID = orderIDList[index];
await fetch(`https://www.fanatical.com/api/user/orders/${ID}`, {
method: 'GET',
headers: {
'anonid': JSON.parse(window.localStorage.bsanonymous).id,
'authorization': JSON.parse(window.localStorage.bsauth).token,
'content-type': 'application/json; charset=utf-8'
}
}).then(res => res.json()).then(res => {
if (res.status == "COMPLETE") {
for (const item of res.items) {
if (item.status == "fulfilled") {
unrevealedList.push(item)
} else if(item.status == "revealed") {
if (item.type == "game") {
revealedList.push({
name: item.name,
key: item.key,
})
} else if (item.type == "bundle") {
let gameList = [];
for (const tier of item.bundles) {
gameList = [...gameList, ...tier.games]
}
for (const game of gameList) {
revealedList.push({
name: game.name,
key: game.key,
})
}
}
} else {
console.log(item)
}
}
} else {
console.log(`Order ${res._id} is ${res.status}`)
}
})
}
};
const revealKey = async ()=>{
for (const item of unrevealedList) {
let e = {};
e["name"] = item.name;
await fetch(`https://www.fanatical.com/api/user/orders/redeem`, {
method: 'POST',
body: JSON.stringify(item),
headers: {
'anonid': JSON.parse(window.localStorage.bsanonymous).id,
'authorization': JSON.parse(window.localStorage.bsauth).token,
'content-type': 'application/json; charset=utf-8'
}
}).then(res => res.json()).then(res => {
e["key"] = res.key;
revealedList.push(e);
})
}
};
const sortRes = ()=>{
sortedJson ={};
str = "";
for (const e of revealedList) {
if(!(e.name in sortedJson)) {
sortedJson[e.name] = [];
};
sortedJson[e.name].push(e.key);
}
console.log(sortedJson);
for (const name in sortedJson) {
const lst = sortedJson[name];
str += `\n${name}:\n`;
for (const key of lst) {
str += `${key}\n`
}
}
copyRes();
};
const copyRes = ()=>{
console.log(str);
GM_setClipboard(str);
alert("结果已导出至剪切板")
};
const initUI = ()=>{
$(".table-item").prepend(cbxHTML);
$(".order-search").after(panelHTML);
GM_addStyle(css);
};
const addListeners = ()=>{
$("#redeem-btn").click(async ()=>{
await getRes();
await revealKey();
sortRes();
});
$("#get-btn").click(async ()=>{
await getRes();
sortRes();
});
$("#copy-btn").click(()=>{
copyRes();
});
};
window.onload = function(){
initUI();
addListeners();
};
})();