AuTo Redeem Steamkey

复制网页中的Steamkey后自动激活,3.0+版本为Beta版

当前为 2020-06-18 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        AuTo Redeem Steamkey
// @namespace   HCLonely
// @author      HCLonely
// @description 复制网页中的Steamkey后自动激活,3.0+版本为Beta版
// @version     Test-3.1.0
// @supportURL  https://blog.hclonely.com/posts/71381355/
// @homepage    https://blog.hclonely.com/posts/71381355/
// @iconURL     https://blog.hclonely.com/img/avatar.jpg
// @include     *://*/*
// @exclude     *store.steampowered.com/widget/*
// @exclude     *googleads*
// @grant       GM_setClipboard
// @grant       GM_addStyle
// @grant       GM_registerMenuCommand
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_xmlhttpRequest
// @run-at      document-idle
// @require     https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require     https://cdn.jsdelivr.net/gh/HCLonely/user.js@latest/ARS/Auto_Redeem_Steamksy_static.min.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert.min.js
// @connect     *
// @compatible  chrome 没有测试其他浏览器的兼容性
// ==/UserScript==

/* global g_sessionID, swal, arsStatic */

(function ($jQuery) {
  'use strict'

  const url = window.location.href
  const defaultSetting = {
    newTab: false,
    copyListen: true,
    selectListen: true,
    clickListen: true,
    allKeyListen: false,
    asf: false,
    asfProtocol: 'http',
    asfHost: '127.0.0.1',
    asfPort: 1242,
    asfPassword: '',
    asfBot: ''
  }
  let sessionID = ''
  try {
    sessionID = g_sessionID // eslint-disable-line camelcase
  } catch (e) {
    sessionID = ''
  }
  if (Object.prototype.toString.call(GM_getValue('setting')) !== '[object Object]') GM_setValue('setting', defaultSetting)

  const asfCommands = $jQuery(arsStatic.html)[0]

  // 激活页面自动激活
  const selecter = url.includes('/account/registerkey') ? '' : '.hclonely '
  const autoDivideNum = 9
  const waitingSeconds = 20
  const ajaxTimeout = 15

  let keyCount = 0
  let recvCount = 0

  let allUnusedKeys = []

  const failureDetail = {
    14: '无效激活码',
    15: '重复激活',
    53: '次数上限',
    13: '地区限制',
    9: '已拥有',
    24: '缺少主游戏',
    36: '需要PS3?',
    50: '这是充值码'
  }

  const myTexts = {
    fail: '失败',
    success: '成功',
    network: '网络错误或超时',
    line: '——',
    nothing: '',
    others: '其他错误',
    unknown: '未知错误',
    redeeming: '激活中',
    waiting: '等待中',
    showUnusedKey: '显示未使用的Key',
    hideUnusedKey: '隐藏未使用的Key'
  }

  const unusedKeyReasons = [
    '次数上限',
    '地区限制',
    '已拥有',
    '缺少主游戏',
    '其他错误',
    '未知错误',
    '网络错误或超时'
  ]

  try {
    if (GM_getValue('setting').selectListen) {
      // 选中激活功能
      const icon = $jQuery(`<div class='icon-div' title='激活'><img src="${arsStatic.icon}" href="javascript:void(0)" class="icon-img"></div>`)[0]
      document.documentElement.appendChild(icon)
      document.addEventListener('mousedown', function (e) {
        if (e.target === icon || (e.target.parentNode && e.target.parentNode === icon) || (e.target.parentNode.parentNode && e.target.parentNode.parentNode === icon)) { // 点击了激活图标
          e.preventDefault()
        }
      })
      // 选中变化事件:当点击已经选中的文本的时候,隐藏激活图标和激活面板(此时浏览器动作是:选中的文本已经取消选中了)
      document.addEventListener('selectionchange', () => {
        if (!window.getSelection().toString().trim()) {
          icon.style.display = 'none'
        }
      })
      // 鼠标事件:防止选中的文本消失;显示、隐藏激活图标
      document.addEventListener('mouseup', function (e) {
        if (e.target === icon || (e.target.parentNode && e.target.parentNode === icon) || (e.target.parentNode.parentNode && e.target.parentNode.parentNode === icon)) { // 点击了激活图标
          e.preventDefault()
          return
        }
        const text = window.getSelection().toString().trim()
        const productKey = window.getSelection().toString().trim() || e.target.value
        if (/[\d\w]{5}(-[\d\w]{5}){2}/.test(productKey) && text && icon.style.display === 'none') {
          icon.style.top = e.pageY + 12 + 'px'
          icon.style.left = e.pageX + 18 + 'px'
          icon.style.display = 'block'
        } else if (!text) {
          icon.style.display = 'none'
        }
      })
      // 激活图标点击事件
      icon.addEventListener('click', function (e) {
        const productKey = window.getSelection().toString().trim() || e.target.value
        registerkey(productKey)
      })
    }

    // 复制激活功能
    if (!/https?:\/\/store\.steampowered\.com\/account\/registerkey[\w\W]{0,}/.test(url) && GM_getValue('setting').copyListen) { // 非激活页面
      const activateProduct = function (e) {
        const productKey = window.getSelection().toString().trim() || e.target.value
        if (/^([\w\W]*)?([\d\w]{5}(-[\d\w]{5}){2}(\r||,||,)?){1,}/.test(productKey)) {
          if (!$jQuery('div.swal-overlay').hasClass('swal-overlay--show-modal')) {
            swal({
              title: '检测到神秘key,是否激活?',
              icon: 'success',
              buttons: {
                confirm: '激活',
                cancel: '取消'
              }
            }).then((value) => {
              if (value) registerkey(productKey)
            })
          }
        } else if (/^!addlicense.*[\d]+$/gi.test(productKey)) {
          if (Object.prototype.toString.call(GM_getValue('setting')) === '[object Object]' && GM_getValue('setting').asf && !$jQuery('div.swal-overlay').hasClass('swal-overlay--show-modal')) {
            swal({
              closeOnClickOutside: false,
              className: 'swal-user',
              title: '检测到您复制了以下ASF指令,是否执行?',
              text: productKey,
              buttons: {
                confirm: '执行',
                cancel: '取消'
              }
            }).then((value) => {
              if (value) asfRedeem(productKey)
            })
          }
        }
      }
      window.addEventListener('copy', activateProduct, false)
    }

    if (/^https?:\/\/store\.steampowered\.com\/account\/registerkey*/.test(url)) {
      $jQuery('#registerkey_examples_text').html(
        '<div class="notice_box_content" id="unusedKeyArea" style="display: none">' +
                    '<b>未使用的Key:</b><a tabindex="300" class="btnv6_blue_hoverfade btn_medium" id="copyUnuseKey"><span>提取未使用key</span></a><br>' +
                    '<div><ol id="unusedKeys">' +
                    '</ol></div>' +
                    '</div>' +

                    '<div class="table-responsive table-condensed">' +
                    '<table class="table table-hover" style="display: none">' +
                    '<caption><h2>激活记录</h2></caption><thead><th>No.</th><th>Key</th>' +
                    '<th>结果</th><th>详情</th><th>Sub</th></thead><tbody></tbody>' +
                    '</table></div><br>')

      $jQuery('#copyUnuseKey').click(() => {
        GM_setClipboard(arr(getKeysByRE($jQuery('#unusedKeys').text())).join(','))
        swal({ title: '复制成功!', icon: 'success' })
      })
      $jQuery('.registerkey_input_box_text').parent().css('float', 'none')
      $jQuery('.registerkey_input_box_text').parent().append('<textarea class="form-control" rows="3"' +
          ' id="inputKey" placeholder="支持批量激活,可以把整个网页文字复制过来&#10;' +
          '若一次激活的Key的数量超过9个则会自动分批激活(等待20秒)&#10;' +
          '激活多个SUB时每个SUB之间用英文逗号隔开&#10;' +
          ' style="margin: 3px 0px 0px; width: 525px; height: 102px;"></textarea><br>');
      /^https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=[\w\W]+/.test(url) && (document.getElementById('inputKey').value = url.replace(/https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=/i, ''))
      $jQuery('.registerkey_input_box_text').hide()
      $jQuery('#purchase_confirm_ssa').hide()

      $jQuery('#register_btn').parent().css('margin', '10px 0')
      $jQuery('#register_btn').parent().append('<a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="margin-left:0"' +
          ' id="redeemKey"><span>激活key</span></a>' + ' &nbsp;&nbsp;' +
          '<a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="margin-left:0"' +
          ' id="redeemSub"><span>激活sub</span></a>' + ' &nbsp;&nbsp;' +
          '<a tabindex="300" class="btnv6_blue_hoverfade btn_medium" style="margin-left:0"' +
          ' id="changeCountry"><span>更换国家/地区</span></a>' + ' &nbsp;&nbsp;')
      $jQuery('#register_btn').remove();
      /^https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=[\w\W]+/.test(url) && (redeem(getKeysByRE(url.replace(/https?:\/\/store\.steampowered\.com\/account\/registerkey\?key=/i, '').trim())))
      $jQuery('#redeemKey').click(() => { redeemKeys() })
      $jQuery('#redeemSub').click(redeemSubs)
      $jQuery('#changeCountry').click(cc)

      toggleUnusedKeyArea()
    } else if (/https?:\/\/steamdb\.info\/freepackages\//.test(url)) { // steamdb.info点击自动跳转到激活页面
      const activateConsole = function (e) {
        const sub = []
        $('#freepackages span:visible').map(function () {
          sub.push($(this).attr('data-subid'))
        })
        const freePackages = sub.join(',')
        // const setting = GM_getValue('setting')
        window.open('https://store.steampowered.com/account/licenses/?sub=' + freePackages, '_self')
        // if(setting.asf) asfRedeem("!addlicense "+(setting.asfBot||"asf")+" "+freePackages);
        // else window.open("https://store.steampowered.com/account/licenses/?sub=" + freePackages, "_self");
      }
      const fp = setInterval(() => {
        if (document.getElementById('freepackages')) {
          document.getElementById('freepackages').onclick = activateConsole
          clearInterval(fp)
        }
      }, 1000)
    } else if (/https?:\/\/store\.steampowered\.com\/account\/licenses\/(\?sub=[\w\W]{0,})?/.test(url)) { // 自动添加sub
      $jQuery('.pageheader').parent().append('<div style="float: left;";>' +
          '<textarea class="registerkey_input_box_text" rows="1"' + 'name="product_key"' +
          ' id="gameSub" placeholder="输入SUB,多个SUB之间用英文逗号连接"' + 'value=""' + 'color:#fff;' +
          ' style="margin: 3px 0px 0px; width: 400px; height: 15px;background-color:#102634; padding: 6px 18px 6px 18px; font-weight:bold; color:#fff;"></textarea>' +
          ' &nbsp ' + '</div>' + '<a tabindex="300" class="btnv6_blue_hoverfade btn_medium"' +
          ' style="width: 95px; height: 30px;"' +
          ' id="buttonSUB"><span>激活SUB</span></a>' + '<a tabindex="300" class="btnv6_blue_hoverfade btn_medium"' +
          ' style="width: 125px; height: 30px;margin-left:5px"' +
          ' id="changeCountry"><span>更改国家/地区</span></a>')
      $jQuery('#buttonSUB').click(() => { redeemSub() })
      $jQuery('#changeCountry').click(cc)
      if (/https?:\/\/store\.steampowered\.com\/account\/licenses\/\?sub=([\d]{1,},){1,}/.test(url)) {
        setTimeout(() => { redeemSub(url) }, 2000)
      }
    } else if (GM_getValue('setting').clickListen) { // 点击添加链接
      let htmlEl
      if (window.document.body) {
        window.document.body.onclick = function (event) {
          htmlEl = event.target// 鼠标每经过一个元素,就把该元素赋值给变量htmlEl
          if ($jQuery(htmlEl).parents('.swal-overlay').length === 0 && htmlEl.tagName !== 'A' && htmlEl.tagName !== 'BUTTON' && htmlEl.getAttribute('type') !== 'button' && htmlEl.tagName !== 'TEXTAREA' && htmlEl.getAttribute('type') !== 'text') {
            if (($jQuery(htmlEl).children().length === 0 || !/([0-9,A-Z]{5}-){2,4}[0-9,A-Z]{5}/gim.test($jQuery.makeArray($jQuery(htmlEl).children().map(function () {
              return $jQuery(this).text()
            })).join(''))) && /([0-9,A-Z]{5}-){2,4}[0-9,A-Z]{5}/gim.test($jQuery(htmlEl).text())) {
              mouseClick($jQuery, event)
              arr($jQuery(htmlEl).text().match(/[\w\d]{5}(-[\w\d]{5}){2}/gim)).map(function (e) {
                $jQuery(htmlEl).html($jQuery(htmlEl).html().replace(new RegExp(e, 'gi'), `<a class="redee-key" href='javascript:void(0)' target="_self" key='${e}'>${e}</a>`))
              })
              $jQuery('.redee-key').click(function () {
                registerkey($jQuery(this).attr('key'), 1)
              })
            }
          }
        }
      }
    }
    if (GM_getValue('setting').allKeyListen) { // 激活页面内所有key
      redeemAllKey()
    }

    GM_addStyle(arsStatic.css)

    GM_registerMenuCommand('⚙设置', setting)
    GM_registerMenuCommand('执行ASF指令', asfSend)
    GM_registerMenuCommand('查看上次激活记录', showHistory)
    GM_registerMenuCommand('Key格式转换', showSwitchKey)
    GM_registerMenuCommand('新版使用说明', () => { window.open('https://keylol.com/t344489-1-1', '_blank') })
  } catch (e) {
    swal('AuTo Redeem Steamkey脚本执行出错,详情请查看控制台!', e.stack, 'error')
    console.error(e)
  }
  function redeemKey (key) {
    GM_xmlhttpRequest({
      url: 'https://store.steampowered.com/account/ajaxregisterkey/',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        Origin: 'https://store.steampowered.com',
        Referer: 'https://store.steampowered.com/account/registerkey'
      },
      data: `product_key=${key}&sessionid=${sessionID}`,
      method: 'POST',
      responseType: 'json',
      timeout: 1000 * ajaxTimeout,
      onloadstart: function () {
        if (jQuery(selecter + 'table').is(':hidden')) {
          jQuery(selecter + 'table').fadeIn()
        }
      },
      onload: function (response) {
        if (response.status === 200 && response.response) {
          const data = response.response
          if (data.success === 1) {
            tableUpdateKey(key, myTexts.success, myTexts.line,
              data.purchase_receipt_info.line_items[0].packageid,
              data.purchase_receipt_info.line_items[0].line_item_description)
            return
          } else if (data.purchase_result_details !== undefined && data.purchase_receipt_info) {
            if (!data.purchase_receipt_info.line_items[0]) {
              tableUpdateKey(key, myTexts.fail,
                failureDetail[data.purchase_result_details] ? failureDetail[data.purchase_result_details] : myTexts.others,
                0, myTexts.nothing)
            } else {
              tableUpdateKey(key, myTexts.fail,
                failureDetail[data.purchase_result_details] ? failureDetail[data.purchase_result_details] : myTexts.others,
                data.purchase_receipt_info.line_items[0].packageid,
                data.purchase_receipt_info.line_items[0].line_item_description)
            }
            return
          }
          tableUpdateKey(key, myTexts.fail, myTexts.nothing, 0, myTexts.nothing)
        } else {
          tableUpdateKey(key, myTexts.fail, myTexts.network, 0, myTexts.nothing)
        }
      }
    })
  }

  function setUnusedKeys (key, success, reason, subId, subName) {
    if (success && allUnusedKeys.includes(key)) {
      var listObject
      allUnusedKeys = allUnusedKeys.filter(function (keyItem) {
        return keyItem !== key
      })

      $jQuery(selecter + 'li').map((i, e) => {
        if ($jQuery(e).html().includes(key)) {
          listObject.remove()
        }
      })
    } else if (!success && !allUnusedKeys.includes(key) && unusedKeyReasons.includes(reason)) {
      listObject = $jQuery('<li></li>')
      listObject.html(key + ' ( ' + reason +
        (subId !== 0 ? (': <code>' + subId + '</code> ' + subName) : '') +
        ' )')
      $jQuery('#unusedKeys').append(listObject)

      allUnusedKeys.push(key)
    }
  }

  function tableInsertKey (key) {
    keyCount++
    const row = $jQuery('<tr></tr>')
    row.append('<td class="nobr">' + keyCount + '</td>')
    row.append('<td class="nobr"><code>' + key + '</code></td>')
    row.append('<td colspan="3">' + myTexts.redeeming + '...</td>')

    $jQuery(selecter + 'tbody').prepend(row)
  }

  function tableWaitKey (key) {
    keyCount++
    const row = $jQuery('<tr></tr>')
    row.append('<td class="nobr">' + keyCount + '</td>')
    row.append('<td class="nobr"><code>' + key + '</code></td>')
    row.append('<td colspan="3">' + myTexts.waiting + ' (' + waitingSeconds + '秒)...</td>')

    $jQuery(selecter + 'tbody').prepend(row)
  }

  function tableUpdateKey (key, result, detail, subId, subName) {
    setUnusedKeys(key, result === myTexts.success, detail, subId, subName)

    recvCount++
    if (!selecter && recvCount === keyCount) {
      $jQuery('#buttonRedeem').fadeIn()
      $jQuery('#inputKey').removeAttr('disabled')
    }

    var rowObjects = $jQuery(selecter + 'tr')
    for (let i = 1; i < rowObjects.length; i++) {
      const rowElement = rowObjects[i]
      const rowObject = $jQuery(rowElement)

      if (rowObject.children()[1].innerHTML.includes(key) && rowObject.children()[2].innerHTML.includes(myTexts.redeeming)) {
        rowObject.children()[2].remove()
        if (result === myTexts.fail) rowObject.append('<td class="nobr" style="color:red">' + result + '</td>')
        else rowObject.append('<td class="nobr" style="color:green">' + result + '</td>')
        rowObject.append('<td class="nobr">' + detail + '</td>')
        if (subId === 0) {
          rowObject.append('<td>——</td>')
        } else {
          rowObject.append('<td><code>' + subId + '</code> <a href="https://steamdb.info/sub/' +
            subId + '/" target="_blank">' + subName + '</a></td>')
        }
        break
      }
    }
  }

  function startTimer () {
    const timer = setInterval(function () {
      let flag = false
      let nowKey = 0

      const rowObjects = $jQuery(selecter + 'tr')
      for (let i = rowObjects.length - 1; i >= 1; i--) {
        const rowElement = rowObjects[i]
        const rowObject = $jQuery(rowElement)
        if (rowObject.children()[2].innerHTML.includes(myTexts.waiting)) {
          nowKey++
          if (nowKey <= autoDivideNum) {
            let key = rowObject.children()[1].innerHTML.substring(6)
            key = key.substring(0, key.indexOf('</code>'))
            rowObject.children()[2].innerHTML = '<td colspan="3">' + myTexts.redeeming + '...</td>'
            redeemKey(key)
          } else {
            flag = true
            break
          }
        }
      }
      if (!flag) {
        clearInterval(timer)
      }
    }, 1000 * waitingSeconds)
  }

  function redeem (keys) {
    if (keys.length <= 0) {
      return
    }

    if (!selecter) {
      $jQuery('#buttonRedeem').hide()
      $jQuery('#inputKey').attr('disabled', 'disabled')
    }

    let nowKey = 0
    keys.forEach(function (key) {
      nowKey++
      if (nowKey <= autoDivideNum) {
        tableInsertKey(key)
        redeemKey(key)
      } else {
        tableWaitKey(key)
      }
    })

    if (nowKey > autoDivideNum) {
      startTimer()
    }
  }
  function redeemKeys (key) {
    const keys = key || getKeysByRE($jQuery('#inputKey').val().trim())
    redeem(keys)
  }

  function toggleUnusedKeyArea () {
    if (!selecter) {
      if ($jQuery('#unusedKeyArea').is(':hidden')) {
        $jQuery('#unusedKeyArea').show()
      } else {
        $jQuery('#unusedKeyArea').hide()
      }
    }
  }

  function setting () {
    const setting = Object.prototype.toString.call(GM_getValue('setting')) === '[object Object]' ? GM_getValue('setting') : defaultSetting
    const div = $jQuery(`
<div id="hclonely-asf">
<input type="checkbox" name="newTab" ${setting.newTab ? 'checked=checked' : ''} title="开启ASF激活后此功能无效"/><span title="开启ASF激活后此功能无效">新标签页激活</span><br/>
<input type="checkbox" name="copyListen" ${setting.copyListen ? 'checked=checked' : ''} title="复制key时询问是否激活"/><span title="复制key时询问是否激活">开启复制捕捉</span>
<input type="checkbox" name="selectListen" ${setting.selectListen ? 'checked=checked' : ''} title="选中key时显示激活图标"/><span title="选中key时显示激活图标">开启选中捕捉</span>
<input type="checkbox" name="clickListen" ${setting.clickListen ? 'checked=checked' : ''} title="点击key时添加激活链接"/><span title="点击key时添加激活链接">开启点击捕捉</span><br/>
<input type="checkbox" name="allKeyListen" ${setting.allKeyListen ? 'checked=checked' : ''} title="匹配页面内所有符合steam key格式的内容"/><span title="匹配页面内所有符合steam key格式的内容">捕捉页面内所有key</span>
<div class="swal-title">ASF IPC设置</div>
<span>ASF IPC协议</span><input type="text" name="asfProtocol" value='${setting.asfProtocol}' placeholder="http或https,默认为http"/><br/>
<span>ASF IPC地址</span><input type="text" name="asfHost" value='${setting.asfHost}' placeholder="ip地址或域名,默认为127.0.0.1"/><br/>
<span>ASF IPC端口</span><input type="text" name="asfPort" value='${setting.asfPort}' placeholder="默认1242"/><br/>
<span>ASF IPC密码</span><input type="text" name="asfPassword" value='${setting.asfPassword}' placeholder="ASF IPC密码"/><br/>
<span>ASF Bot名字</span><input type="text" name="asfBot" value='${setting.asfBot}' placeholder="ASF Bot name,可留空"/><br/>
<input type="checkbox" name="asf" ${setting.asf ? 'checked=checked' : ''} title="此功能默认关闭新标签页激活"/><span title="此功能默认关闭新标签页激活">开启ASF激活</span>
</div>`)[0]

    swal({
      closeOnClickOutside: false,
      className: 'asf-class',
      title: '全局设置',
      content: div,
      buttons: {
        confirm: '保存',
        cancel: '取消'
      }
    })
      .then((value) => {
        if (value) {
          const setting = {}
          $jQuery('#hclonely-asf input').map(function () {
            setting[$jQuery(this).attr('name')] = this.value === 'on' ? this.checked : this.value
          })
          GM_setValue('setting', setting)
          swal({
            closeOnClickOutside: false,
            icon: 'success',
            title: '保存成功!',
            text: '刷新页面后生效!',
            buttons: {
              confirm: '确定'
            }
          })
        }
      })
  }
  function asfSend (c = '') {
    if (Object.prototype.toString.call(GM_getValue('setting')) === '[object Object]' && GM_getValue('setting').asf) {
      swal({
        closeOnClickOutside: false,
        className: 'swal-user',
        text: '请在下方输入要执行的ASF指令:',
        content: 'input',
        buttons: {
          test: '连接测试',
          redeem: '激活key',
          pause: '暂停挂卡',
          resume: '恢复挂卡',
          '2fa': '获取令牌',
          more: '更多ASF指令',
          confirm: '确定',
          cancel: '取消'
        }
      }).then((value) => {
        switch (value) {
          case 'redeem':
            swalRedeem()
            break
          case 'pause':
          case 'resume':
          case '2fa':
            asfRedeem('!' + value)
            break
          case 'test':
            asfTest()
            break
          case 'more':
            swal({
              closeOnClickOutside: false,
              className: 'swal-user',
              text: 'ASF指令',
              content: asfCommands,
              buttons: {
                confirm: '返回',
                cancel: '关闭'
              }
            }).then((value) => {
              if (value) asfSend()
            })
            $jQuery('table.hclonely button.swal-button').click(function () {
              const setting = Object.prototype.toString.call(GM_getValue('setting')) === '[object Object]' ? GM_getValue('setting') : defaultSetting
              const command = setting.asfBot ? $jQuery(this).parent().next().text().trim().replace(/<Bots>/gim, setting.asfBot) : $jQuery(this).parent().next().text().trim()
              asfSend(command)
            })
            break
          case null:
            break
          default:
            if (!$jQuery('.swal-content__input').val()) {
              swal({
                closeOnClickOutside: false,
                title: 'ASF指令不能为空!',
                icon: 'warning',
                buttons: {
                  confirm: '确定'
                }
              }).then(() => { asfSend(c) })
            } else {
              const v = value || $jQuery('.swal-content__input').val()
              if (v) asfRedeem(v)
            }
            break
        }
      })
      if (c) $jQuery('.swal-content__input').val('!' + c)
    } else {
      swal({
        closeOnClickOutside: false,
        className: 'swal-user',
        icon: 'warning',
        title: '此功能需要在设置中配置ASF IPC并开启ASF功能!',
        buttons: {
          confirm: '确定'
        }
      })
    }
  }

  function swalRedeem () {
    swal({
      closeOnClickOutside: false,
      className: 'swal-user',
      title: '请输入要激活的key:',
      content: $jQuery('<textarea id=\'keyText\' class=\'asf-output\'></textarea>')[0],
      buttons: {
        confirm: '激活',
        cancel: '返回'
      }
    }).then((value) => {
      if (value) {
        const key = getKeysByRE($jQuery('#keyText').val())
        if (key.length > 0) asfRedeem('!redeem ' + (GM_getValue('setting').asfBot ? (GM_getValue('setting').asfBot + ' ') : '') + key.join(','))
        else {
          swal({
            closeOnClickOutside: false,
            title: 'steam key不能为空!',
            icon: 'error',
            buttons: {
              confirm: '返回',
              cancel: '关闭'
            }
          }).then((value) => {
            if (value) swalRedeem()
          })
        }
      } else {
        asfSend()
      }
    })
  }
  function asfTest () {
    const setting = GM_getValue('setting') || {}
    if (setting.asf) {
      swal({
        closeOnClickOutside: false,
        title: 'ASF连接测试',
        text: '正在尝试连接 "' + setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command/"',
        buttons: {
          confirm: '确定'
        }
      })
      GM_xmlhttpRequest({
        method: 'POST',
        url: setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command/',
        data: '{"Command":"!stats"}',
        responseType: 'json',
        headers: {
          accept: 'application/json',
          'Content-Type': 'application/json',
          Authentication: setting.asfPassword,
          Host: setting.asfHost + ':' + setting.asfPort,
          Origin: setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort,
          Referer: setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/page/commands'
        },
        onload: function (data) {
          if (data.status === 200) {
            if (data.response.Success === true && data.response.Message === 'OK' && data.response.Result) {
              swal({
                closeOnClickOutside: false,
                title: 'ASF连接成功!',
                icon: 'success',
                text: '连接地址 "' + setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command/" \n返回内容 "' + data.response.Result.trim() + '"',
                buttons: {
                  confirm: '确定'
                }
              })
            } else if (data.response.Message) {
              swal({
                closeOnClickOutside: false,
                title: 'ASF连接成功?',
                icon: 'info',
                text: '连接地址 "' + setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command/" \n返回内容 "' + data.response.Message.trim() + '"',
                buttons: {
                  confirm: '确定'
                }
              })
            } else {
              swal({
                closeOnClickOutside: false,
                title: 'ASF连接失败!',
                icon: 'error',
                text: '连接地址 "' + setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command/" \n返回内容 "' + data.responseText + '"',
                buttons: {
                  confirm: '确定'
                }
              })
            }
          } else {
            swal({
              closeOnClickOutside: false,
              title: 'ASF连接失败:' + data.status,
              icon: 'error',
              text: '连接地址 "' + setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command/"',
              buttons: {
                confirm: '确定'
              }
            })
          }
        }
      })
    } else {
      swal({
        closeOnClickOutside: false,
        title: '请先在设置中开启ASF功能',
        icon: 'warning',
        buttons: {
          confirm: '确定'
        }
      })
    }
  }

  function showHistory () {
    const history = GM_getValue('history')
    if (Array.isArray(history)) {
      swal({
        closeOnClickOutside: false,
        className: 'swal-user',
        title: '上次激活记录:',
        content: $jQuery(history[0])[0],
        buttons: {
          confirm: '确定'
        }
      })
      if (history[1]) $jQuery('.swal-content textarea').val(history[1])
    } else {
      swal({
        closeOnClickOutside: false,
        title: '没有操作记录!',
        icon: 'error',
        buttons: {
          cancel: '关闭'
        }
      })
    }
  }

  function showSwitchKey () {
    swal({
      closeOnClickOutside: false,
      title: '请选择要转换成什么格式:',
      buttons: {
        confirm: '确定',
        cancel: '关闭'
      },
      content: $jQuery('<div class=\'switch-key\'><div class=\'switch-key-left\'><p>key</p><p>key</p><p>key</p><input name=\'keyType\' type=\'radio\' value=\'1\'/></div><div class=\'switch-key-right\'><p>&nbsp;</p><p>key,key,key</p><p>&nbsp;</p><input name=\'keyType\' type=\'radio\' value=\'2\'/></div></div>')[0]
    }).then((value) => {
      if (value) {
        if ($jQuery('input:radio:checked').val()) {
          showSwitchArea($jQuery('input:radio:checked').val())
        } else {
          swal({
            closeOnClickOutside: false,
            title: '请选择要将key转换成什么格式!',
            icon: 'warning'
          }).then(showSwitchKey)
        }
      }
    })
    function showSwitchArea (type) {
      swal({
        closeOnClickOutside: false,
        title: '请输入要转换的key:',
        content: $jQuery('<textarea style=\'width: 80%;height: 100px;\'></textarea>')[0],
        buttons: {
          confirm: '转换',
          back: '返回',
          cancel: '关闭'
        }
      }).then((value) => {
        if (value === 'back') {
          showSwitchKey(type)
        } else if (value) {
          switchKey($jQuery('.swal-content textarea').val(), type)
        }
      })
    }
    function switchKey (key, type) {
      switch (type) {
        case '1':
          showKey(getKeysByRE(key).join('\n'), type)
          break
        case '2':
          showKey(getKeysByRE(key).join(','), type)
          break
        default:
          break
      }
    }
    function showKey (key, type) {
      swal({
        closeOnClickOutside: false,
        icon: 'success',
        title: '转换成功!',
        content: $jQuery(`<textarea style='width: 80%;height: 100px;' value='${key}' readonly='readonly'>${key}</textarea>`)[0],
        buttons: {
          confirm: '返回',
          cancel: '关闭'
        }
      }).then((value) => {
        if (value) {
          showSwitchArea(type)
        }
      })
      $jQuery('.swal-content textarea').click(function () { this.select() })
    }
    $jQuery('.switch-key div').map(function () {
      $jQuery(this).click(function () {
        $jQuery(this).find('input')[0].click()
      })
    })
  }

  function getKeysByRE (text) {
    text = text.trim().toUpperCase()
    const reg = new RegExp('([0-9,A-Z]{5}-){2,4}[0-9,A-Z]{5}', 'g')
    const keys = []

    let result
    while (result = reg.exec(text)) { // eslint-disable-line no-cond-assign
      keys.push(result[0])
    }

    return keys
  }

  function registerkey (key) {
    const setting = GM_getValue('setting')
    const keys = getKeysByRE(key)
    if (setting.asf) asfRedeem('!redeem ' + (setting.asfBot ? (setting.asfBot + ' ') : '') + keys.join(','))
    else if (setting.newTab) window.open('https://store.steampowered.com/account/registerkey?key=' + keys.join(','), '_blank')
    else webRedeem(keys)
  }
  function asfRedeem (command) {
    const setting = GM_getValue('setting')
    const textarea = document.createElement('textarea')
    textarea.setAttribute('class', 'asf-output')
    textarea.setAttribute('readonly', 'readonly')
    const btn = /!redeem/gim.test(command) ? { confirm: '提取未使用key', cancel: '关闭' } : { confirm: '确定' }
    swal({
      closeOnClickOutside: false,
      className: 'swal-user',
      text: '正在执行ASF指令:' + command,
      content: textarea,
      buttons: btn
    }).then((v) => {
      if (/!redeem/gim.test(command)) {
        let value = ''
        if ($jQuery('.swal-content textarea').length > 0) {
          value = $jQuery('.swal-content textarea').val()
        }
        GM_setValue('history', [$jQuery('.swal-content').html(), value])
        if (v) {
          const unUseKey = $jQuery('.swal-content textarea').val().split(/[(\r\n)\r\n]+/).map(function (e) {
            if (/未使用/gim.test(e)) {
              return e
            }
          }).join(',')
          GM_setClipboard(arr(getKeysByRE(unUseKey)).join(','))
          swal({ title: '复制成功!', icon: 'success' })
        }
      }
    })
    GM_xmlhttpRequest({
      method: 'POST',
      url: setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/Api/Command',
      data: `{"Command":"${command}"}`,
      responseType: 'json',
      headers: {
        accept: 'application/json',
        'Content-Type': 'application/json',
        Authentication: setting.asfPassword,
        Host: setting.asfHost + ':' + setting.asfPort,
        Origin: setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort,
        Referer: setting.asfProtocol + '://' + setting.asfHost + ':' + setting.asfPort + '/page/commands'
      },
      onload: function (data) {
        console.log(data)
        console.log(command)
        if (data.status === 200) {
          if (data.response.Success === true && data.response.Message === 'OK' && data.response.Result) {
            textarea.value += data.response.Result.trim() + ' \n'
          } else if (data.response.Message) {
            textarea.value += data.response.Message.trim() + ' \n'
          } else {
            textarea.value += data.responseText
          }
        } else {
          swal({
            closeOnClickOutside: false,
            className: 'swal-user',
            title: '执行ASF指令(' + command + ')失败!请检查ASF配置是否正确!',
            text: data.text || data.status,
            icon: 'error',
            buttons: {
              confirm: '关闭'
            }
          })
        }
      }
    })
  }
  function webRedeem (key) {
    const div = $jQuery('<div id="registerkey_examples_text"><div class="notice_box_content" id="unusedKeyArea"> <b>未使用的Key:</b><br><div><ol id="unusedKeys" align="left"></ol></div></div><div class="table-responsive table-condensed"><table class="table table-hover hclonely"><caption><h2>激活记录</h2></caption><thead><th>No.</th><th>Key</th><th>结果</th><th>详情</th><th>Sub</th></thead><tbody></tbody></table></div><br></div>')[0]
    swal({
      closeOnClickOutside: false,
      className: 'swal-user',
      title: '正在获取sessionID...',
      buttons: {
        confirm: '关闭'
      }
    })
    if (sessionID) {
      swal({
        closeOnClickOutside: false,
        className: 'swal-user',
        title: '正在激活steam key...',
        content: div,
        buttons: {
          confirm: '提取未使用key',
          cancel: '关闭'
        }
      }).then((v) => {
        let value = ''
        if ($jQuery('.swal-content textarea').length > 0) {
          value = $jQuery('.swal-content textarea').val()
        }
        GM_setValue('history', [$jQuery('.swal-content').html(), value])
        if (v) {
          GM_setClipboard(arr(getKeysByRE($jQuery('#unusedKeys').text())).join(','))
          swal({ title: '复制成功!', icon: 'success' })
        }
      })
      redeemKeys(key)
    } else {
      GM_xmlhttpRequest({
        method: 'GET',
        url: 'https://store.steampowered.com/account/registerkey',
        onload: function (data) {
          if (data.finalUrl.includes('login')) {
            swal({
              closeOnClickOutside: false,
              icon: 'warning',
              title: '请先登录steam!',
              buttons: {
                confirm: '登录',
                cancel: '关闭'
              }
            }).then((value) => {
              if (value) window.open('https://store.steampowered.com/login/', '_blank')
            })
          } else {
            if (data.status === 200) {
              const gSessionId = data.responseText.match(/g_sessionID = "(.+?)";/)
              sessionID = gSessionId === null ? null : gSessionId[1]
              swal({
                closeOnClickOutside: false,
                className: 'swal-user',
                title: '正在激活steam key...',
                content: div,
                buttons: {
                  confirm: '提取未使用key',
                  cancel: '关闭'
                }
              }).then((v) => {
                let value = ''
                if ($jQuery('.swal-content textarea').length > 0) {
                  value = $jQuery('.swal-content textarea').val()
                }
                GM_setValue('history', [$jQuery('.swal-content').html(), value])
                if (v) {
                  GM_setClipboard(getKeysByRE($jQuery('#unusedKeys').text()).join(','))
                  swal({ title: '复制成功!', icon: 'success' })
                }
              })
              redeemKeys(key)
            } else {
              swal({
                closeOnClickOutside: false,
                className: 'swal-user',
                title: '获取sessionID失败!',
                icon: 'error',
                buttons: {
                  confirm: '关闭'
                }
              })
            }
          }
        }
      })
    }
  }

  function redeemSub (e) {
    const subText = e || document.getElementById('gameSub').value
    if (subText) {
      const ownedPackages = {}
      $jQuery('.account_table a').each(function (i, el) {
        const match = el.href.match(/javascript:RemoveFreeLicense\( ([0-9]+), '/)
        if (match !== null) {
          ownedPackages[+match[1]] = true
        }
      })
      const freePackages = subText.match(/[\d]{2,}/g)
      let i = 0
      let loaded = 0
      let packae = 0
      const total = freePackages.length
      swal('正在执行…', '请等待所有请求完成。 忽略所有错误,让它完成。')
      for (; i < total; i++) {
        packae = freePackages[i]
        if (ownedPackages[packae]) {
          loaded++
          continue
        }
        $jQuery.post('//store.steampowered.com/checkout/addfreelicense', {
          action: 'add_to_cart',
          sessionid: g_sessionID,
          subid: packae
        }).always(function () {
          loaded++
          if (loaded >= total) {
            if (url.includes('licenses')) {
              window.open('https://store.steampowered.com/account/licenses/', '_self')
            } else {
              swal('全部激活完成,是否前往账户页面查看结果?', {
                buttons: {
                  cancel: '取消',
                  确定: true
                }
              })
                .then((value) => {
                  if (value) window.open('https://store.steampowered.com/account/licenses/', '_blank')
                })
            }
          } else {
            swal('正在激活…', '进度:' + loaded + '/' + total + '.')
          }
        })
      }
    }
  }
  function cc () {
    swal({
      closeOnClickOutside: false,
      icon: 'info',
      title: '正在获取当前国家/地区...'
    })
    $jQuery.ajax({
      url: '//store.steampowered.com/cart/',
      type: 'get',
      success: function (data) {
        if (data.match(/id="usercountrycurrency_trigger"[\w\W]*?>[w\W]*?<\/a/gim)) {
          const c = data.match(/id="usercountrycurrency_trigger"[\w\W]*?>[w\W]*?<\/a/gim)[0].replace(/id="usercountrycurrency_trigger"[\w\W]*?>|<\/a/g, '')
          // const thisC = data.match(/id="usercountrycurrency"[\w\W]*?value=".*?"/gim)[0].match(/value=".*?"/gim)[0].replace(/value="|"/g, '')
          const div = data.match(/<div class="currency_change_options">[\w\W]*?<p/gim)[0].replace(/[\s]*?<p/gim, '') + '</div>'
          // $jQuery("body").append(`<div id="nowCountry" class="ellipsis" data-country="${thisC}" style="font-size:20px;">转换商店和钱包&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当前国家/地区:${c}</div><div style="padding:20px">${div}</div></div>`);
          swal({
            closeOnClickOutside: false,
            title: `当前国家/地区:${c}`,
            content: $jQuery(`<div>${div}</div>`)[0]
          })
          $jQuery('.currency_change_option').click(function () {
            changeCountry($jQuery(this).attr('data-country'))
          })
        } else {
          swal('需要挂相应地区的梯子!', '', 'warning')
        }
      },
      error: () => {
        swal('获取当前国家/地区失败!', '', 'error')
      }
    })
  }
  function changeCountry (country) {
    swal({
      closeOnClickOutside: false,
      icon: 'info',
      title: '正在更换国家/地区...'
    })
    $jQuery.ajax({
      url: '//store.steampowered.com/account/setcountry',
      type: 'post',
      data: {
        sessionid: g_sessionID,
        cc: country
      },
      complete: function () {
        $jQuery.ajax({
          url: '//store.steampowered.com/cart/',
          type: 'get',
          success: function (data) {
            const c = data.match(/id="usercountrycurrency_trigger"[\w\W]*?>[w\W]*?<\/a/gim)[0].replace(/id="usercountrycurrency_trigger"[\w\W]*?>|<\/a/g, '')
            const thisC = data.match(/id="usercountrycurrency"[\w\W]*?value=".*?"/gim)[0].match(/value=".*?"/gim)[0].replace(/value="|"/g, '')
            const div = data.match(/<div class="currency_change_options">[\w\W]*?<p/gim)[0].replace(/[\s]*?<p/gim, '') + '</div>'

            if (thisC === country) {
              swal('更换成功!', '', 'success').then(() => {
                swal({
                  closeOnClickOutside: false,
                  title: `当前国家/地区:${c}`,
                  content: $jQuery(`<div>${div}</div>`)[0]
                })
                $jQuery('.currency_change_option').click(function () {
                  changeCountry($jQuery(this).attr('data-country'))
                })
              })
            } else {
              swal('更换失败!', '', 'error')
            }
          },
          error: () => {
            swal('获取当前国家/地区失败!', '', 'error')
          }
        })
      }
    })
  }

  function redeemSubs () {
    redeemSub($jQuery('#inputKey').val().trim())
  }

  function mouseClick ($, e) {
    const $i = $('<span/>').text('Steam Key')
    const x = e.pageX
    const y = e.pageY
    $i.css({ 'z-index': 9999999999999999999, top: y - 20, left: x, position: 'absolute', 'font-weight': 'bold', color: '#ff6651' })
    $('body').append($i)
    $i.animate({ top: y - 180, opacity: 0 }, 1500, () => { $i.remove() })
  }
  function addBtn () {
    const div = document.createElement('div')
    div.setAttribute('id', 'keyDiv')
    div.setAttribute('style', 'position:fixed;left:5px;bottom:5px')
    const btn = document.createElement('button')
    btn.setAttribute('id', 'allKey')
    btn.setAttribute('key', '')
    btn.setAttribute('style', 'display:none;z-index:9999')
    btn.setAttribute('class', 'btn btn-default')
    btn.innerText = '激活本页面所有key(共0个)'
    btn.onclick = function () {
      const setting = GM_getValue('setting')
      const keys = getKeysByRE($jQuery(this).attr('key'))
      if (setting.asf) asfRedeem('!redeem ' + setting.asfBot + ' ' + keys.join(','))
      else if (setting.newTab) window.open('https://store.steampowered.com/account/registerkey?key=' + keys.join(','), '_blank')
      else webRedeem(keys)
    }
    $jQuery('body').append(div)
    div.appendChild(btn)
    return btn
  }
  function redeemAllKey () {
    let len = 0
    let keyList = ''
    let hasKey = []
    const btn = addBtn()
    setInterval(function () {
      const allSteamKey = arr(getKeysByRE($jQuery('body').text())) || []
      len = allSteamKey.length
      if (len > 0) {
        hasKey.push(...allSteamKey)
        hasKey = arr(hasKey)
        keyList = hasKey.join(',')
        if ($jQuery(btn).attr('key') !== keyList) {
          $jQuery(btn).attr('key', keyList)
          $jQuery(btn).text('激活本页面所有key(共' + hasKey.length + '个)')
          $jQuery(btn).show()
        }
      } else if (document.getElementById('allKey') && (document.getElementById('allKey').style.display === 'block')) {
        $jQuery(btn).hide()
        $jQuery(btn).text('激活本页面所有key(共0个)')
      }
    }, 1000)
  }
  function arr (arr) {
    return [...new Set(arr)]
  }
}($))