Greasy Fork

来自缓存

Humble Choice Get Key

try to take over the world!

目前为 2020-02-09 提交的版本。查看 最新版本

// ==UserScript==
// @name         Humble Choice Get Key
// @namespace    http://tampermonkey.net/
// @version      0.05
// @description  try to take over the world!
// @author       ku mi
// @match        https://www.humblebundle.com/subscription/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// ==/UserScript==
 const countryMap = {
            AD: '安道尔',
            AE: '阿拉伯联合酋长国',
            AF: '阿富汗',
            AG: '安提瓜和巴布达',
            AI: '安圭拉',
            AL: '阿尔巴尼亚',
            AM: '亚美尼亚',
            AO: '安哥拉',
            AQ: '南极洲',
            AR: '阿根廷',
            AS: '美属萨摩亚',
            AT: '奥地利',
            AU: '澳大利亚',
            AW: '阿鲁巴',
            AX: '奥兰群岛',
            AZ: '阿塞拜疆',
            BA: '波斯尼亚和黑塞哥维那',
            BB: '巴巴多斯',
            BD: '孟加拉',
            BE: '比利时',
            BF: '布基纳法索',
            BG: '保加利亚',
            BH: '巴林',
            BI: '布隆迪',
            BJ: '贝宁',
            BL: '圣巴托洛缪岛',
            BM: '百慕大',
            BN: '文莱',
            BO: '玻利维亚',
            BQ: '博奈尔',
            BR: '巴西',
            BS: '巴哈马',
            BT: '不丹',
            BU: '缅甸',
            BV: '布韦岛',
            BW: '博兹瓦纳',
            BY: '白俄罗斯',
            BZ: '伯利兹',
            CA: '加拿大',
            CC: '科科斯(基林)群岛',
            CD: '刚果(金)',
            CF: '中非共和国',
            CG: '刚果(布)',
            CH: '瑞士',
            CI: '科特迪瓦',
            CK: '库克群岛',
            CL: '智利',
            CM: '喀麦隆',
            CN: '中国',
            CO: '哥伦比亚',
            CR: '哥斯达黎加',
            CS: '塞尔维亚和黑山',
            CU: '古巴',
            CV: '佛得角',
            CW: '库拉索',
            CX: '圣诞岛',
            CY: '塞浦路斯',
            CZ: '捷克',
            DE: '德国',
            DJ: '吉布提',
            DK: '丹麦',
            DM: '多米尼克',
            DO: '多米尼加',
            DZ: '阿尔及利亚',
            EC: '厄瓜多尔',
            EE: '爱沙尼亚',
            EG: '埃及',
            EH: '西撒哈拉',
            ER: '厄立特里亚',
            ES: '西班牙',
            ET: '埃塞俄比亚',
            FI: '芬兰',
            FJ: '斐济',
            FK: '福克兰群岛',
            FM: '密克罗尼西亚',
            FO: '法罗群岛',
            FR: '法国',
            GA: '加蓬',
            GB: '英国',
            GD: '格林纳达',
            GE: '格鲁吉亚',
            GF: '法属圭亚那',
            GG: '根西',
            GH: '加纳',
            GI: '直布罗陀',
            GL: '格陵兰',
            GM: '冈比亚',
            GN: '几内亚',
            GP: '瓜德鲁普',
            GQ: '赤道几内亚',
            GR: '希腊',
            GS: '南乔治亚岛和南桑威奇群岛',
            GT: '危地马拉',
            GU: '关岛',
            GW: '几内亚比绍',
            GY: '圭亚那',
            HK: '香港',
            HM: '赫德岛和麦克唐纳群岛',
            HN: '洪都拉斯',
            HR: '克罗地亚',
            HT: '海地',
            HU: '匈牙利',
            ID: '印尼',
            IE: '爱尔兰',
            IL: '以色列',
            IM: '马恩岛',
            IN: '印度',
            IO: '英属印度洋领地',
            IQ: '伊拉克',
            IR: '伊朗',
            IS: '冰岛',
            IT: '意大利',
            JE: '泽西岛',
            JM: '牙买加',
            JO: '约旦',
            JP: '日本',
            KE: '肯尼亚',
            KG: '吉尔吉斯',
            KH: '柬埔寨',
            KI: '基里巴斯',
            KM: '科摩罗',
            KN: '圣基茨和尼维斯',
            KP: '朝鲜',
            KR: '韩国',
            KW: '科威特',
            KY: '开曼群岛',
            KZ: '哈萨克斯坦',
            LA: '老挝',
            LB: '黎巴嫩',
            LC: '圣卢西亚',
            LI: '列支敦士登',
            LK: '斯里兰卡',
            LR: '利比里亚',
            LS: '莱索托',
            LT: '立陶宛',
            LU: '卢森堡',
            LV: '拉脱维亚',
            LY: '利比亚',
            MA: '摩洛哥',
            MC: '摩纳哥',
            MD: '摩尔多瓦',
            ME: '黑山',
            MF: '法属圣马丁',
            MG: '马达加斯加',
            MH: '马绍尔群岛',
            MK: '马其顿',
            ML: '马里',
            MM: '缅甸',
            MN: '蒙古',
            MO: '澳门',
            MP: '北马里亚纳群岛',
            MQ: '马提尼克',
            MR: '毛里塔尼亚',
            MS: '蒙塞拉特',
            MT: '马耳他',
            MU: '毛里求斯',
            MV: '马尔代夫',
            MW: '马拉维',
            MX: '墨西哥',
            MY: '马来西亚',
            MZ: '莫桑比克',
            NA: '纳米比亚',
            NC: '新喀里多尼亚',
            NE: '尼日尔',
            NF: '诺福克岛',
            NG: '尼日利',
            NI: '尼加拉瓜',
            NL: '荷兰',
            NO: '挪威',
            NP: '尼泊尔',
            NR: '瑙鲁',
            NU: '纽埃',
            NZ: '新西兰',
            OM: '阿曼',
            PA: '巴拿马',
            PE: '秘鲁',
            PF: '法属波利尼西亚a',
            PG: '巴布亚新几内亚',
            PH: '菲律宾',
            PK: '巴基斯坦',
            PL: '波兰',
            PM: '圣皮埃尔和密克隆',
            PN: '皮特凯恩群岛',
            PR: '波多黎各',
            PS: '巴勒斯坦',
            PT: '葡萄牙',
            PW: '帕劳',
            PY: '巴拉圭',
            QA: '卡塔尔',
            RE: '留尼旺島',
            RO: '罗马尼亚',
            RS: '塞尔维亚',
            RU: '俄罗斯',
            RW: '卢旺达',
            SA: '沙特阿拉伯',
            SB: '所罗门群岛',
            SC: '塞舌尔',
            SD: '苏丹',
            SE: '瑞典',
            SG: '新加坡',
            SH: '圣赫勒拿、阿森松与特斯坦达库尼亚',
            SI: '斯洛文尼',
            SJ: '斯瓦尔巴群岛和扬马延岛',
            SK: '斯洛伐克',
            SL: '塞拉利昂',
            SM: '圣马力诺',
            SN: '塞内加尔',
            SO: '索马里',
            SR: '苏里南',
            SS: '南苏丹',
            ST: '圣多美和普林西比',
            SV: '萨尔瓦多',
            SX: '荷属圣马丁',
            SY: '叙利亚',
            SZ: '斯威士兰',
            TC: '特克斯和凯科斯群岛',
            TD: '乍得',
            TF: '法属南部领土',
            TG: '多哥',
            TH: '泰国',
            TJ: '塔吉克斯坦',
            TK: '托克劳',
            TL: '东帝汶',
            TM: '土库曼斯坦',
            TN: '突尼斯',
            TO: '汤加',
            TR: '土耳其',
            TT: '特立尼达和多巴哥',
            TV: '图瓦卢',
            TW: '台湾',
            TZ: '坦桑尼亚',
            UA: '乌克兰',
            UG: '乌干达',
            UM: '美国本土外小岛屿',
            US: '美国',
            UY: '乌拉圭',
            UZ: '乌兹别克斯坦',
            VA: '圣座',
            VC: '圣文森特和格林纳丁斯',
            VE: '委内瑞拉',
            VG: '英属维尔京群岛',
            VI: '美属维尔京群岛',
            VN: '越南',
            VU: '瓦努阿图',
            WF: '瓦利斯和富图纳群岛',
            WS: '萨摩亚',
            XK: '科索沃',
            YE: '也门',
            YT: '马约特',
            ZA: '南非',
            ZM: '赞比亚',
            ZW: '津巴布韦',
        };
(function() {
   function http (setData) {
    return new Promise((resolve, reject) => {
     GM_xmlhttpRequest({
                method: setData.method | 'GET',
                url: setData.url,
                onerror: reject,
                ontimeout: reject,
                onload: (res) => {
                     resolve(res.responseText)
                }
            })
    })
   }
    http({url: window.location}).then(res => {
      getInitData(new DOMParser().parseFromString(res, 'text/html'))

    }).catch(()=>{})
    function getInitData (el) {
       const script = el.querySelector('#webpack-monthly-product-data') || el.querySelector('#webpack-subscriber-hub-data')
       if(!script) return
       const {contentChoiceData, gamekey, contentChoicesMade, downloadPageUrl} = JSON.parse(script.innerText.trim()).contentChoiceOptions
       const {content_choices, display_order} = contentChoiceData.initial
       const selecedGame = contentChoicesMade.initial.choices_made
       const allGame = display_order.map(item => {
           let i = content_choices[item]
           return {
               machine_name: i.tpkds[0].machine_name,
               title: i.title,
               exclusive: i.tpkds[0].exclusive_countries,
               disallowed: i.tpkds[0].disallowed_countries,
               appid: i.tpkds[0].steam_app_id,
               name: item,
               key: i.tpkds[0].redeemed_key_val
           }

       })
       function getLock (game) {
           let lockDetil
           function getZhName (arr) {
              return arr.map(item => {
               if (/(\u53f0\u6e7e|\u4e2d\u56fd|\u9999\u6e2f)/.test(countryMap[item])) return '<span style="color: #c93756; font-size: 20px;">' + countryMap[item] + '</span>'
                 return countryMap[item]
             }).join('、')
           }
           if(game.exclusive.length) {
             lockDetil = `<span style="color: #cc6699"><span style="color: #c93756;">只能在</span>以下激活:  + ${getZhName(game.exclusive)}</span>`
           }
           if(game.disallowed.length){
             lockDetil = `<span style="color: #B0E2FF"><span style="color: #c93756;">不能在</span>以下地区激活: ${getZhName(game.disallowed)}<span>: `
           }
           return lockDetil || `<span style="color: #279b61">无限制激活</span>`
       }
       const gameBox = document.createElement('div')
       gameBox.innerHTML = `<button class="_sh_hd_">隐藏锁区信息</button><a class="_down_page_" target="_blank" href=${downloadPageUrl}>Download页面</a/><ul class="_self_view_"></ul>`
       const gamelist = gameBox.querySelector('._self_view_')
       const sButton = gameBox.querySelector('._sh_hd_')
       const optionBox = document.createElement('div')
       optionBox.innerHTML = '<ul class="_option_ul_"></ul><ul class="_select_ul_"></ul><textarea class="_key_value_"></textarea>'
       const optionUl = optionBox.querySelector('._option_ul_')
       const selectUl = optionBox.querySelector('._select_ul_')
       const keyValue = optionBox.querySelector('._key_value_')
       const textArr = ['选择游戏(只选游戏不刮)','刮开游戏(已选择的游戏才能刮)', '全选高亮', '取消高亮', '清理文本框', '显示数字']
       const [selectKey, getKey, allLight, noLight, clearKey, setNumber] = textArr.map((item, index) => {
        item = document.createElement('li')
        item.innerText = textArr[index]
        optionUl.appendChild(item)
        return item
       })
       const liChild = allGame.map((item, index) => {
         const li = document.createElement('li')
         li.innerText = index + 1
         Object.assign(li.dataset, {
            title: item.title,
            name: item.name,
            machine_name: item.machine_name,
            key: item.key || ''
           })
         selectUl.appendChild(li)
         return li
       })
       setNum()
       optionUl.onselectstart = () => false
       selectUl.onselectstart = () => false
       selectUl.addEventListener('click',(e) => {
          if (e.target.nodeName === 'LI') e.target.classList.toggle('current')
       })
        allLight.addEventListener('click', () => {
            liChild.forEach(item => item.classList.add('current'))
        })
        noLight.addEventListener('click', () => {
            liChild.forEach(item => item.classList.remove('current'))

        })
        clearKey.addEventListener('click',() => (keyValue.value = ''))
        selectKey.addEventListener('click', () => {
           if(selecedGame.length >= 10) return noLight.click()
           keyValue.value = ''
           let num = 0
           let filter = liChild.filter(item => item.classList.contains('current'))
           filter.forEach((item, index) => {
              if(selecedGame.includes(item.dataset.name)) return num++
              let time = setTimeout(() => {
               clearTimeout(time)
                fetchHttp({url: `https://www.humblebundle.com/humbler/choosecontent?gamekey=${gamekey}&parent_identifier=initial&chosen_identifier=${item.dataset.name}`})
               .then(res => res.json())
               .then(res => {
                  keyValue.value += `${item.dataset.title}: ${res.success ? '选择成功' : '选择失败'}\n`
                  if(res.success){
                     noSelectList.forEach((it) => {
                     if(it.title === item.dataset.name){
                      it.classList.add('current')
                      it.innerText = '已选择'
                     }
                 })
                  }
              })
              }, (index - num) * 1500)
          })
            noLight.click()
        })
        getKey.addEventListener('click', () => {
            keyValue.value = ''
            let num = 0
            let filter = liChild.filter(item => item.classList.contains('current'))
            filter.forEach((item, index) => {
               if(item.dataset.key) {
                 (keyValue.value += `${item.dataset.title}: ${item.dataset.key}\n`)
                   return num++
               }
               let time = setTimeout(() => {
                  clearTimeout(time)
                 fetchHttp({url: 'https://www.humblebundle.com/humbler/redeemkey', body: `keytype=${item.dataset.machine_name}&key=${gamekey}&keyindex=0`, method: 'POST'})
                  .then(res => res.json())
                 .then(res => {
                if(res.success){
                  keyValue.value += `${item.dataset.title}: ${res.key}\n`
                  item.dataset.key = res.key
                  noGetList.forEach((it) => {
                     if(it.dataset.name === item.dataset.name){
                      it.classList.add('current')
                      it.innerText = '已刮开'
                     }
                 })
                }
              })
              }, index * 1500)

           })
           noLight.click()

        })
        setNumber.addEventListener('click', () => {
           if(!document.querySelectorAll('._game_num_').length)setNum()
        })
    function setNum() {
        const els = document.querySelectorAll('.js-content-choices .choice-image-container')
        els.forEach((item, index) => {
        let div = document.createElement('div')
        div.setAttribute('class','_game_num_')
        div.innerText = index + 1
          item.appendChild(div)
      })
    }
       gameBox.insertBefore(optionBox, sButton)
       allGame.forEach(item => {
           const li = document.createElement('li')
           li.innerHTML = `<div style="width: 100%;"><a style="text-decoration: none; color: #169fe3" href="https://store.steampowered.com/app/${item.appid}" target="_blank">${item.title}</a>${item.key ? '<button class="current">已刮开</button>': '<button data-name="'+ item.name + '" data-machine_name="'+ item.machine_name + '" class="no-get" title="'+ item.name + '">未刮开</button>'}${selecedGame.includes(item.name) ? '<button class="current">已选择</button>' : '<button class="no-select" title="'+ item.name + '">未选择</button>'}<p style="margin: 15px 15px 15px 0; ">${getLock(item)}</p></div>`
           gamelist.appendChild(li)
       })
       const view = document.querySelector('.content-choices-view')
       const list = document.querySelector(".content-choice-tiles.js-content-choice-tiles")
       view.insertBefore(gameBox, list)
       sButton.addEventListener('click', () => {
            if(sButton.classList.contains('current')){
              gamelist.style.display = 'block'
              sButton.innerHTML = '隐藏锁区信息'
            }else {
              gamelist.style.display = 'none'
              sButton.innerHTML = '显示锁区信息'
            }
            sButton.classList.toggle('current')
        } )
       const noGetList = document.querySelectorAll('.no-get')
       const noSelectList = document.querySelectorAll('.no-select')
       noSelectList.forEach(item => {
            item.addEventListener('click', clickEvent(true, {url: `https://www.humblebundle.com/humbler/choosecontent?gamekey=${gamekey}&parent_identifier=initial&chosen_identifier=${item.title}`}))
          })
        noGetList.forEach(item => {
              item.addEventListener('click', clickEvent(false, {url: 'https://www.humblebundle.com/humbler/redeemkey', body: `keytype=${item.dataset.machine_name}&key=${gamekey}&keyindex=0`, method: 'POST'}))
        })
       function fetchHttp(data) {
         return fetch(data.url, {
            method: data.method || 'GET',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                Origin: 'https://www.humblebundle.com',
                Referer: location.href
            },
            body: data.body,
            credentials: 'same-origin'
        })
       }
       function clickEvent (flag, data) {
         return function request () {
           if((this.innerText === '已选择') || (this.innerText === '已刮开') || (selecedGame.length >= 10)) return
           this.innerText = '请求中...'
           fetchHttp(data)
            .then(res => res.json())
            .then(res => {
             if(!res.success){
               return (this.innerText = flag ? '未选择' : '未刮开')
             }
             this.removeEventListener('click', request)
             this.innerText = flag ? '已选择' : '已刮开'
             this.className = 'current'
             keyValue.value = ''
             if(!flag) keyValue.value += `${this.title}: ${res.key}\n`
             else keyValue.value += `${this.title}: 选择成功\n`
         })
       }

       }
    GM_addStyle(`
._sh_hd_ {
    border: none;
    outline: none;
    background-color: #c93756;
    margin: 20px 0 0 20px;
    border-radius: 5px;
    line-height: 50px;
    padding: 0 20px;
}
._down_page_{
   float: right;
   padding: 0 20px;
   border-radius: 5px;
   height: 50px;
   margin: 20px 20px 0 0;
   line-height: 50px;
   background-color: rgb(22, 159, 227);
    color: #fff;
     text-decoration: none;

}
._key_value_ {
margin: 20px 0 0 20px;
            width: 800px;
            height: 200px;
            resize: none;
            font-size: 18px;
            color: #fff;
            margin-top: 20px;
            outline: none;
            background-color: #454c5e;
            border: none;

}
._option_ul_, ._select_ul_ {
            margin: 20px 0 0 20px;
            height: 50px;
            line-height: 50px;
            display: flex;
            list-style: none;
            padding: 0;
}
._option_ul_ > li, ._select_ul_ > li {
            height: 50px;
            line-height: 50px;
            background-color: rgb(22, 159, 227);
            margin-right: 20px;
            border-radius: 5px;
            text-align: center;
            padding: 0 20px;
            color: #fff;
            font-size: 16px;
            cursor: pointer;
}
._select_ul_ > li {
      background-color: #454c5e;
}
._select_ul_ > li.current {
     background-color: #cc6699;
}
._game_num_ {
          width: 100%;
          height: 100%;
          position: absolute;
          left: 0;
          top: 0;
          z-index: 1;
           background-color: rgba(0, 0, 0, .3);
           text-align: center;
          font-size: 100px;
}
._sh_hd_.current {
   background-color: #169fe3;
}
._self_view_ {
     list-style: none;
     margin: 20px 0 0 0;
     padding: 0;
}
._self_view_ > li {
     font-size: 16px;
     padding: 20px 0 0px 20px;
     border-bottom: 10px solid #454c5e;
     display: flex;
    justify-content: space-between;
}
._self_view_ > li button {
    border: none;
    outline: none;
    background-color: #169fe3;
    margin: 0 10px;
    font-size: 16px;
    border-radius: 0.8em;
    padding: 5px 15px;
    width: 100px;
    float: right;
}
._self_view_ > li .current{
  background-color: #c93756;
}
._self_view_ > li:last-child {
    border: none;
}
`)
}

})();