Fanatical Get Key

F站刮key

当前为 2021-09-21 提交的版本,查看 最新版本

// ==UserScript==
// @name         Fanatical Get Key
// @namespace    http://tampermonkey.net/
// @version      0.5
// @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 => {
        str += (str ? '\n' : '') + '【' + bundleName + '】\n'
        const arr = Object.keys(obj[bundleName])
        if(flag) {
            let longArrName = arr.reduce((a, b) => {
                return obj[bundleName][a].length >= obj[bundleName][b].length ? a : b
            })
            arr.splice(arr.findIndex(item => item === longArrName), 1)
            str += [longArrName, ...arr].join('\t') + '\n'
            const longArr = obj[bundleName][longArrName]
            longArr.forEach((item, index) => {
                const keyArr = []
                keyArr.push(item.key)
                arr.forEach(item2 => {
                    const data = obj[bundleName][item2][index]
                    if(data) {
                        keyArr.push(data.key || '')
                    } else {
                        keyArr.push('')
                    }
                })
                str += keyArr.join('\t') + '\n'
            })
        } else {
          arr.forEach(item => {
            const gameArr = obj[bundleName][item]
            const temp = [item]
            gameArr.forEach(item2 => temp.push(item2.key))
            str += temp.join('\n') + '\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 func = (obj, name, item, atok, order_id, bid) => {
      if(item.status === 'refunded') return
      if(!obj[name][item.name]) {
          obj[name][item.name] = []
      }
      gameCount++
      obj[name][item.name].push(Object.assign({
          atok,
          oid: order_id,
          iid: item.iid,
          serialId: item.serialId,
          key: item.key
      }, bid ? {bid} : null))
  }
  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(item.bundles.length) {
                item.bundles.forEach(gameList => {
                    gameList.games.forEach(item2 => {
                        func(obj, item.pickAndMix, item2, atok, order_id)
                    })
                })
            } else {
                func(obj, item.pickAndMix, item, atok, order_id)
            }

        } else {
            if(item.bundles.length) {
                if(!obj[item.name]) {
                    obj[item.name] = {}
                }
                item.bundles.forEach(item2 => {
                    item2.games.forEach(item3 => {
                        func(obj, item.name, item3, atok, order_id, item._id)
                    })
                })
            } else {
                if(!obj['单个游戏']) {
                    obj['单个游戏'] = {}
                }
                func(obj, '单个游戏', item, atok, order_id)
            }
        }
    })
    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, item, order) {
      if(isRun) return
      isRun = true
      ele.innerHTML = `一键刮key中...`
      getData(await request(`https://www.fanatical.com/api/user/orders/${order}`), this, ele)
   }
  const init = (list) => {
      setTimeout(() => {
          list.forEach(item => {
              if(item.previousElementSibling.innerText === 'COMPLETE' && item.childElementCount === 1) {
                  item.classList.add('zf-has')
                  const [, order] = item.parentElement.parentElement.href.match(/orders\/(\w+)/)
                  const me = document.querySelector(`.v-${order}`)
                  if(me) return
                  const div = document.createElement('div')
                  div.className = `zf-wrap v-${order}`
                  div.style = `position: absolute;right: 20px;top: ${item.offsetTop}px;`
                  div.innerHTML = '<div class="zf-coustom">刮key(横向序列)</div><div class="zf-coustom">刮key(纵向序列)</div>'
                  div.firstElementChild.onclick = clickEvent.bind(div, div.firstElementChild, item, order)
                  div.lastElementChild.onclick = clickEvent.bind(div, div.lastElementChild, item, order)
                  document.documentElement.appendChild(div)
              }
          })
      }, 1000)
  }
      const content = document.querySelector('#root')
      const observer = new MutationObserver((mutationsList) => {
          if(/orders\/\w+/.test(location.pathname)) {
            document.querySelectorAll('.zf-wrap').forEach(item => item.remove())
          }
          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)
              } else if(mutation.type === 'childList' && mutation.removedNodes.length) {
                 mutation.removedNodes.forEach(item => {
                     console.log(item.firstElementChild)
                   if(item.className = 'table-item' && item.firstElementChild && item.firstElementChild.nodeName === 'A') {
                     const [, order] = item.firstElementChild.href.match(/orders\/(\w+)/)
                     const me = document.querySelector(`.v-${order}`)
                     if(me) me.remove()
                   }
                 })
              }
          }
      })
      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或关注我们的公众号极客氢云获取最新地址