Fanatical Get Key

F站刮key

目前为 2021-08-06 提交的版本。查看 最新版本

// ==UserScript==
// @name         Fanatical Get Key
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  F站刮key
// @author       Ku Mi
// @match        https://www.fanatical.com/*
// @icon         https://cdn.fanatical.com/production/icons/favicon-32x32.png
// @grant        GM_addStyle
// ==/UserScript==
(function() {
    let gameCount = 0
    let isRun = false
    const render = (obj, flag) => {
      let str = ''
      Object.keys(obj).forEach(bundleName => {
        if(Array.isArray(obj[bundleName])) {
          const arr = obj[bundleName]
          str += bundleName + (flag ? '\t' : '\n') + arr.reduce((a, b, idx) => a + b.key + (flag ? idx === arr.length - 1 ? '\n' : '\t' : '\n'), '')
        } else {
          str += (str ? '\n' : '') + '【' + bundleName + '】\n'
          Object.keys(obj[bundleName]).forEach(item => {
           const arr = obj[bundleName][item]
           str += item + (flag ? '\t' : '\n') + arr.reduce((a, b, idx) => a + b.key + (flag ? idx === arr.length - 1 ? '\n' : '\t' : '\n'), '')
          })
        }
      })
      const input = document.createElement('textarea')
      document.documentElement.appendChild(input)
      input.value = str
      input.select()
      document.execCommand('copy')
      input.remove()
      alert('复制成功')
    }
    const myPromise = (item) => {
      return new Promise((resolve) => {
        if(item.key) {
          item.key += `(已刮过)`
          resolve(item)
        }else {
          delete item.key
          resolve(request(`https://www.fanatical.com/api/user/orders/redeem`, { method: 'POST', body: JSON.stringify(item) }))
        }
      })
    }
    const redeem = (data, obj, div, count, ele) => {
        data.forEach(item => {
            myPromise(item).then(res => {
                item.key = res.key
            }).catch(() => (item.key = '请求失败')).finally(() => {
              ele.innerHTML = `一键刮key(${count} / ${count - --gameCount})`
              if(gameCount <= 0) {
                render(obj, div.firstElementChild === ele)
                gameCount = 0
                isRun = false
              }
            })
        })
    }
    const getData = async ({status, _id : order_id, items: orderList}, div, ele) => {
      if(status !== 'COMPLETE') return alert('订单未完成')
      const obj = {}
      const atok = window.localStorage.bsatok
      orderList.forEach(item => {
          if(item.status === 'refunded') return
          if(item.pickAndMix) {
              if(!obj[item.pickAndMix]) {
                  obj[item.pickAndMix] = {}
              }
              if(!obj[item.pickAndMix][item.name]) {
                  obj[item.pickAndMix][item.name] = []
              }
              gameCount++
              obj[item.pickAndMix][item.name].push({
                  atok,
                  oid: order_id,
                  iid: item.iid,
                  serialId: item.serialId,
                  key: item.key
              })
          } else {
              if(!obj[item.name]) {
                  obj[item.name] = item.bundles.length ? {} : []
              }
              if(item.bundles.length) {
                  item.bundles.forEach(item2 => {
                      item2.games.forEach(item3 => {
                          if(item3.status === 'refunded') return
                          if(!obj[item.name][item3.name]){
                              obj[item.name][item3.name] = []
                          }
                          item3.bid = item._id
                          item3.oid = order_id
                          gameCount++
                          obj[item.name][item3.name].push({
                              atok,
                              bid: item._id,
                              oid: order_id,
                              iid: item3.iid,
                              serialId: item3.serialId,
                              key: item3.key
                          })
                      })
                  })
              } else {
                  gameCount++
                  obj[item.name].push({
                      atok,
                      oid: order_id,
                      iid: item.iid,
                      serialId: item.serialId,
                      key: item.key
                  })
              }
          }
      })
      ele.innerHTML = `一键刮key(${gameCount} / 0)`
      Object.keys(obj).forEach(name => {
        if(Array.isArray(obj[name])) {
          redeem(obj[name], obj, div, gameCount, ele)
        } else {
           Object.keys(obj[name]).forEach(item => {
             redeem(obj[name][item], obj, div, gameCount, ele)
           })
        }
      })
    }
    const request = async (url, {method = 'GET', body = null} = {}) => {
        const result = await fetch(url, {
            method,
            body,
            headers: {
                anonid: JSON.parse(window.localStorage.bsanonymous).id,
                authorization: JSON.parse(window.localStorage.bsauth).token,
                'content-type': 'application/json; charset=utf-8'
            }
        })
        return await result.json()
    }
    async function clickEvent(ele) {
        if(isRun) return
        const [, order] = this.previousElementSibling.href.match(/orders\/(\w+)/)
        if(!order) return alert('order出错')
        isRun = true
        ele.innerHTML = `一键刮key中...`
        getData(await request(`https://www.fanatical.com/api/user/orders/${order}`), this, ele)
     }
    const init = (list) => {
      list.forEach(item => {
        if(item.previousElementSibling.innerText === 'COMPLETE' && item.childElementCount === 1) {
          item.classList.add('zf-has')
          const div = document.createElement('div')
          div.innerHTML = '<div class="zf-coustom">刮key(横向序列)</div><div class="zf-coustom">刮key(纵向序列)</div>'
          div.firstElementChild.onclick = clickEvent.bind(div, div.firstElementChild)
          div.lastElementChild.onclick = clickEvent.bind(div, div.lastElementChild)
          item.appendChild(div)
        }
      })
    }
    const content = document.querySelector('#root')
    const observer = new MutationObserver((mutationsList) => {
        for(let mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length) {
                 const list = mutation.target.querySelectorAll('.d-none.d-md-block.action-col:not(.zf-has)')
                 if(list.length) init(list)
            }
        }
    })
    const config = { childList: true, subtree: true }
    observer.observe(content, config)
GM_addStyle(`
 .zf-coustom {
   padding: 5px 15px;
   border-radius: 5px;
   background-color: #212121;
   cursor: pointer;
   font-size: 14px;
   text-align: center;
   color: #fff;
   margin-top: 10px;
 }
 .zf-coustom:hover {
   opacity: 0.5;
 }
`)
})();

QingJ © 2025

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