自动任务

自动完成赠key站任务

スクリプトをインストール?
作者が勧める他のスクリプト

AuTo Redeem Steamkeyも気に入るかもしれません。

スクリプトをインストール
作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name           自动任务
// @name:en        Auto Task
// @namespace      auto-task
// @version        2.2.13
// @description    自动完成赠key站任务
// @description:en Automatically complete giveaway tasks
// @author         HCLonely
// @license        MIT
// @iconURL        https://cdn.jsdelivr.net/gh/HCLonely/[email protected]/favicon.ico
// @homepage       https://blog.hclonely.com/posts/777c60d5/
// @supportURL     https://github.com/HCLonely/auto-task/issues/new/choose
// @include        *://giveaway.su/giveaway/view/*
// @include        *://marvelousga.com/*
// @include        *://dupedornot.com/*
// @include        *://www.grabfreegame.com/giveaway/*
// @include        *://www.bananagiveaway.com/giveaway/*
// @include        /https?:\/\/gamehag.com/.*?giveaway\/.*/
// @include        *://prys.revadike.com/giveaway/?id=*
// @include        *://www.indiedb.com/giveaways*
// @include        *://www.opiumpulses.com/giveaways
// @include        *://gkey.fun/distribution/*
// @include        *://givekey.ru/distribution/*
// @include        *://takekey.ru/distribution/*
// @include        *://chubkeys.com/giveaway/*
// @include        *://giveawayhopper.com/giveaway/*
// @include        *://*freegamelottery.com*
// @include        *://gleam.io/*
// @exclude        *googleads*
// @include        https://userjs.hclonely.com/setting.html
// @include        https://userjs.hclonely.com/setting_en.html
// @include        https://userjs.hclonely.com/announcement.html
// @require        https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js
// @require        https://cdn.jsdelivr.net/npm/[email protected]/lib/index.min.js
// @require        https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @resource       css https://cdn.jsdelivr.net/gh/HCLonely/[email protected]/auto-task.min.css
// @grant          GM_setValue
// @grant          GM_getValue
// @grant          GM_listValues
// @grant          GM_deleteValue
// @grant          GM_addStyle
// @grant          GM_xmlhttpRequest
// @grant          GM_getResourceText
// @grant          GM_registerMenuCommand
// @grant          GM_info
// @grant          GM_openInTab
// @connect        userjs.hclonely.com
// @connect        cdn.jsdelivr.net
// @connect        store.steampowered.com
// @connect        steamcommunity.com
// @connect        twitter.com
// @connect        youtube.com
// @connect        facebook.com
// @connect        instagram.com
// @connect        vk.com
// @connect        discordapp.com
// @connect        github.com
// @connect        twitch.tv
// @connect        *
// @run-at         document-end
// @compatible     chrome >= 58, 没有测试其他浏览器的兼容性
// ==/UserScript==

/* global $,Vue,checkClick,getURLParameter,showAlert,urlPath,checkUser,Centrifuge,DashboardApp,captchaCheck */

(function () {
  'use strict'

  const i18n = {
    'zh-cn': {
      language: '语言',
      auto: '自动',
      needBanana: '此key需要收集 s% 个香蕉, 是否继续?',
      needPoints: '此key需要收集 s% , 是否继续?',
      notice: '提示',
      confirm: '确定',
      cancel: '取消',
      canceled: '已取消',
      processTasksInfo: '正在处理任务信息...',
      processTasksUrl: '正在处理任务链接(用时取决于Steam任务数量,请耐心等待)...',
      getTasksInfo: '正在获取任务信息...',
      allTasksComplete: '所有任务已完成!',
      prysAllTasksComplete: '所有任务验证完成,请手动完成人机验证获取key!',
      verifyTasksComplete: '所有任务验证完成!',
      verifyingTask: '正在验证任务',
      noKeysLeft: '此页面已经没有剩余key了, 是否关闭?',
      logining: '正在登录...',
      needLogin: '请先登录!',
      fglTimeout: '正在 s% (如果长时间没反应,请打开控制台查看错误日志)...',
      fglComplete: '任务完成,正在刷新页面(如果页面没有自动刷新,请手动刷新查看结果)...',
      checkingUpdate: '正在检测更新...',
      checkUpdate: '检查更新',
      thisIsNew: '当前脚本为最新版本!',
      updateNow: '立即更新至 ',
      newVer: '检测到新版本: ',
      getAnnouncement: '正在获取更新公告...',
      visitHistory: '查看历史更新内容',
      close: '关闭',
      websiteSetting: '网站设置',
      updateCommunityId: '正在更新Steam社区SessionID(用于加组退组)...',
      updateStoreId: '正在更新Steam商店SessionID(用于添加愿望单、关注游戏、关注鉴赏家等)...',
      loginSteamCommunity: '请先登录<a href="https://steamcommunity.com/login/home" target="_blank">Steam社区</a>',
      loginSteamStore: '请先登录<a href="https://store.steampowered.com/login" target="_blank">Steam商店</a>',
      joinGroup: '正在加入Steam组',
      getGroupId: '正在获取Steam组ID',
      leaveGroup: '正在退出Steam组',
      followCurator: '正在关注鉴赏家',
      unfollowCurator: '正在取关鉴赏家',
      getDeveloperId: '正在获取开发商ID',
      followDeveloper: '正在关注开发商',
      unfollowDeveloper: '正在取关开发商',
      getPublisherId: '正在获取发行商ID',
      followPublisher: '正在关注发行商',
      unfollowPublisher: '正在取关发行商',
      addWishlist: '正在添加愿望单',
      removeWishlist: '正在移除愿望单',
      followGame: '正在关注游戏',
      unfollowGame: '正在取关游戏',
      likeAnnouncements: '正在点赞通知',
      visitLink: '正在访问页面',
      unknown: '未知操作',
      joinGiveaway: '正在加入赠key...',
      needJoinGiveaway: '请检查是否已加入此赠key!',
      doing: '正在做任务',
      unknowntype: '未知任务类型',
      getIdFailed: '获取任务id失败!',
      loadAnnouncementFailed: '加载公告失败',
      checkConsole: ',详情请查看控制台',
      setting: '设置',
      visitUpdateText: '查看更新内容',
      cleanCache: '清理缓存',
      feedback: '提交建议/BUG',
      cleaning: '正在清理缓存...',
      readme: '脚本说明',
      updateSteamInfo: '更新Steam信息',
      updateSteamInfoComplete: 'Steam信息更新完成',
      cannotRemove: '没有可以移除的任务!',
      joinLotteryComplete: '所有抽奖参加完成!',
      noPoints: '点数不足,任务中止!',
      getNeedPointsFailed: '获取抽奖需要点数失败,任务中止!',
      joinLottery: '正在参加抽奖',
      pointsLeft: '剩余点数: ',
      getPointsFailed: '获取当前拥有点数失败!',
      joinFreeLottery: '参加免费抽奖',
      joinPointLottery: '参加点数抽奖',
      getTaskIdFailed: '获取 s% 任务id失败!',
      noAutoFinish: '没有检测到可以自动完成的任务!',
      finishSelf: '没完成的请手动完成!',
      getUrlFailed: '获取任务链接失败( s% )',
      closeExtensions: '建议关闭脚本管理器和广告屏蔽插件再获取key!',
      changeLanguage: '需要将页面语言设置为"English"或"Русский"(将页面右下角的自动翻译关闭)!如果已设置,请忽视本条信息',
      gkrobot: '请在弹出的页面完成验证(如果有的话),然后关闭页面',
      connectWss: '正在连接WSS...',
      connectWssWait: '正在连接WSS, 请稍候!',
      beforeFuck: '每次点击"Fuck"按钮前请手动完成人机验证!!!',
      getTaskStatus: '正在获取任务完成状态(时间稍长,请耐心等待)...',
      wssConnected: 'WSS已连接!',
      wssConnectSuccess: 'WSS连接成功',
      wssDisconnected: 'WSS连接断开!',
      wssReconnect: 'WSS连接断开,正在重连...',
      noLogin: '您尚未登录!',
      accessDenied: '访问被拒绝!',
      notFound: '错误,找不到页面!',
      serverError: '服务器错误!',
      errorRefresh: '错误,请刷新页面!',
      initFirst: '请先Init再做任务!',
      initPlease: '请先点击Init按钮再点此按钮!',
      getGroupFailed: '获取Steam组信息失败!',
      openPage: '已打开任务页面',
      getTaskUrlFailed: '获取任务链接失败',
      notRobot: '触发人机验证,请完成验证后再点击"Verify"按钮验证任务!',
      getVisitTimeFailed: '获取浏览时间失败',
      doYourself: '请手动完成',
      googleVerify: '谷歌验证',
      getKey: '获取key',
      fuckBtnTitle: '一键做任务+验证',
      verifyBtnTitle: '一键验证任务',
      joinBtnTitle: '一键加组、关注鉴赏家、关注游戏、添加愿望单...',
      removeBtnTitle: '一键退组、取关鉴赏家、取关游戏、移除愿望单...',
      showLog: '显示执行日志',
      hideLog: '隐藏执行日志',
      show: '展开',
      hide: '收起',
      taskLog: '任务执行日志',
      saveSetting: '保存设置',
      saveSuccess: '保存成功',
      resetSetting: '重置所有设置',
      resetSettingNotice: '是否重置所有设置?',
      resetSettingSuccess: '重置成功',
      resetSettingFailed: '重置失败',
      resetSettingCancel: '已取消重置',
      downloadSetting: '下载设置文件',
      processSetting: '正在处理设置...',
      creatUrlFailed: '创建下载链接失败!',
      loadSetting: '加载设置文件',
      readSetting: '正在读取设置文件...',
      readSettingComplete: '设置文件读取完成!',
      readSettingFailed: '读取设置文件失败!',
      loadSettingComplete: '设置加载完成!',
      loadSettingFailed: '设置加载失败',
      notSupport: '当前浏览器不支持直接读取文件,已触发备用方案!',
      copySetting: '请将设置文件里的内容复制到下面!',
      loadSettingText: '正在加载设置...',
      jsError: '脚本执行出错,详细信息请查看控制台(红色背景部分)!',
      ajaxError: 'Ajax请求出错',
      group: '加组',
      curator: '关注鉴赏家',
      developer: '关注开发商',
      publisher: '关注发行商',
      announcement: '点赞通知',
      wishlist: '加愿望单',
      fGame: '关注游戏',
      visit: '访问链接',
      verify: '验证任务',
      autoLogin: '自动登录',
      doTask: '做任务',
      autoLoginDes: '自动登录,第一次需要手动登录(仅适用于freegamelottery网站)',
      doTaskDes: '依次做"MAIN DRAW","SURVEY DRAW","VIDEO DRAW","STACKPOT"等任务',
      ungroup: '退组',
      uncurator: '取关鉴赏家',
      undeveloper: '取关开发商',
      unpublisher: '取关发行商',
      unwishlist: '移除愿望单',
      unfGame: '取关游戏',
      ungroupDes: '退出steam组(Group)',
      uncuratorDes: '取关steam鉴赏家(Curator)',
      undeveloperDes: '取关steam开发商(Developer)',
      unpublisherDes: '取关steam发行商(Publisher)',
      unwishlistDes: '将游戏移除愿望单(Wishlist)',
      unfGameDes: '取关游戏(Followed game)',
      showLogs: '默认显示日志',
      showDetails: '输出详细日志',
      checkLogin: '登录检测',
      checkLeft: '剩余key检测',
      autoOpen: '自动打开任务页面',
      autoCheckUpdate: '自动检测更新',
      reCaptcha: '人机验证修复',
      showLogsDes: '默认显示右下角任务日志',
      showDetailsDes: '控制台输出详细日志',
      checkLoginDes: '检测是否已登录,没登录则跳转到登录页面',
      checkLeftDes: '检测是否有剩余key,没有剩余key则提醒',
      autoOpenDes: '未完成的任务自动打开任务页面手动完成(需要关闭浏览器弹窗拦截)',
      reCaptchaDes: '如果Gamehag网站人机验证出错,请尝试打开/关闭此选项',
      globalSettings: '全局设置'
    },
    en: {
      language: 'Language',
      auto: 'Auto',
      needBanana: 'This key needs to collect s% banana, do you want to continue?',
      needPoints: 'This key needs to collect s%, do you want to continue?',
      notice: 'Notice',
      confirm: 'OK',
      cancel: 'Cancel',
      cancelled: 'Cancelled',
      processTasksInfo: 'Processing task information...',
      processTasksUrl: 'Processing task link (time depends on the number of Steam tasks, please be patient)...',
      getTasksInfo: 'Getting task information...',
      allTasksComplete: 'All tasks completed!',
      prysAllTasksComplete: 'All tasks are verified, please complete the man-machine verification to get the key!',
      verifyTasksComplete: 'All tasks verified!',
      verifyingTask: 'Verifying task',
      noKeysLeft: 'This page has no remaining keys, do you want to close?',
      logining: 'Logining...',
      needLogin: 'Login please!',
      fglTimeout: 'Doing "s%" (If there is no response for a long time, please open the console to view the error log)...',
      fglComplete: 'The task is completed and the page is being refreshed (if the page does not refresh automatically, please refresh it manually to view the results)...',
      checkingUpdate: 'Checking for updates...',
      checkUpdate: 'Check for updates',
      thisIsNew: 'The current script is the latest version!',
      updateNow: 'Update to ',
      newVer: 'New version available: ',
      getAnnouncement: 'Getting update announcement...',
      visitHistory: 'History',
      close: 'Close',
      websiteSetting: ' website settings',
      updateCommunityId: 'Updating Steam Community SessionID (for joining and leaving groups)...',
      updateStoreId: 'Updating Steam Store SessionID (for adding to wishlist, following game, following curator, etc.)...',
      loginSteamCommunity: 'Please log in to the <a href="https://steamcommunity.com/login/home" target="_blank">Steam Community</a>.',
      loginSteamStore: 'Please log in to the <a href="https://store.steampowered.com/login" target="_blank">Steam Store</a>.',
      joinGroup: 'Joining the Steam group',
      getGroupId: 'Getting Steam group ID',
      leaveGroup: 'Leaving Steam group',
      followCurator: 'Following curator',
      unfollowCurator: 'Unfollowing curator',
      getDeveloperId: 'Getting developer ID',
      followDeveloper: 'Following developer',
      unfollowDeveloper: 'Unfollowing developer',
      getPublisherId: 'Getting publisher ID',
      followPublisher: 'Following publisher',
      unfollowPublisher: 'Unfollowing publisher',
      addWishlist: 'Adding to wishlist',
      removeWishlist: 'Removing from wishlist',
      followGame: 'Following game',
      unfollowGame: 'Unfollowing gema',
      likeAnnouncements: 'Liking announcement',
      visitLink: 'Visiting page',
      unknown: 'Unknown operation',
      joinGiveaway: 'Joining giveaway...',
      needJoinGiveaway: 'Please check if this giveaway has been joined!',
      doing: 'Doing task',
      unknowntype: 'Unknown task type',
      getIdFailed: 'Failed to get task id!',
      loadAnnouncementFailed: 'Loading announcement failed',
      checkConsole: ', see console for details',
      setting: 'Setting',
      visitUpdateText: 'View updates',
      cleanCache: 'Clear cache',
      feedback: 'Feedback',
      cleaning: 'Clearing cache...',
      readme: 'Script description',
      updateSteamInfo: 'Update Steam Information',
      updateSteamInfoComplete: 'Steam information update completed',
      cannotRemove: 'No tasks can be removed!',
      joinLotteryComplete: 'All giveaways have been joined!',
      noPoints: 'Not enough points, task aborted!',
      getNeedPointsFailed: 'Failed to get points for joining giveaway, task aborted!',
      joinLottery: 'Joining giveaway',
      pointsLeft: 'Points remaining: ',
      getPointsFailed: 'Failed to get points currently owned!',
      joinFreeLottery: 'Join free giveaway',
      joinPointLottery: 'Join points giveaway',
      getTaskIdFailed: 'Failed to get s% task id!',
      noAutoFinish: 'No tasks detected that could be done automatically!',
      finishSelf: 'Unfinished tasks please do it yourself!',
      getUrlFailed: 'Failed to get task link( s% )',
      closeExtensions: 'It is recommended to close the script manager and the ad blocking plugin before obtaining the key!',
      changeLanguage: 'Need to set the page language to "English" or "Русский" (Turn off automatic translation in the bottom right corner of the page)! If it is set to "English" or "Русский", please ignore this message.',
      gkrobot: 'Please complete the verification on the pop-up page (if any), and then close the page.',
      connectWss: 'Connecting to WSS...',
      connectWssWait: 'Connecting to WSS, please wait!',
      beforeFuck: 'Please complete the verification before clicking the "Fuck" button!!!',
      getTaskStatus: 'Getting task completion status (a little longer, please be patient)...',
      wssConnected: 'WSS is connected!',
      wssConnectSuccess: 'WSS connection succeeded',
      wssDisconnected: 'WSS is disconnected!',
      wssReconnect: 'WSS is disconnected, reconnecting...',
      noLogin: 'You have not logged in!',
      accessDenied: 'Access denied!',
      notFound: 'Error, page not found!',
      serverError: 'Server error!',
      errorRefresh: 'Error, please refresh the page!',
      initFirst: 'Please Init before doing the task!',
      initPlease: 'Please click the Init button before clicking this button!',
      getGroupFailed: 'Failed to get Steam group information!',
      openPage: 'Task page opened',
      getTaskUrlFailed: 'Failed to get task link',
      notRobot: 'Trigger human-machine verification, please complete the verification and then click the "Verify" button to verify the task',
      getVisitTimeFailed: 'Failed to get visit time',
      doYourself: 'Please complete ',
      googleVerify: 'Google verification',
      getKey: ' to get key',
      fuckBtnTitle: 'Complete and verify tasks',
      verifyBtnTitle: 'Verify tasks',
      joinBtnTitle: 'Join group, follow curator, follow game, add to wishlist...',
      removeBtnTitle: 'Leave group, unfollow curator, unfollow game, remove from wishlist...',
      showLog: 'Show execution log',
      hideLog: 'Hide execution log',
      show: 'Show',
      hide: 'Hide',
      taskLog: 'Task execution log',
      saveSetting: 'Save settings',
      saveSuccess: 'Saved successfully',
      resetSetting: 'Reset all settings',
      resetSettingNotice: 'Do you want to reset all settings?',
      resetSettingSuccess: 'Reset succeeded',
      resetSettingFailed: 'Reset failed',
      resetSettingCancel: 'Canceled reset',
      downloadSetting: 'Download the settings file',
      processSetting: 'Processing settings...',
      creatUrlFailed: 'Failed to create download link!',
      loadSetting: 'Load settings file',
      readSetting: 'Reading settings file...',
      readSettingComplete: 'Setting file read completed!',
      readSettingFailed: 'Failed to read the settings file!',
      loadSettingComplete: 'Settings are loaded!',
      loadSettingFailed: 'Failed to load settings',
      notSupport: 'The current browser does not support reading files directly, an alternative has been triggered!',
      copySetting: 'Please copy the contents of the settings file to the following',
      loadSettingText: 'Loading settings...',
      jsError: 'Script execution error, please see the console for details (red background part)!',
      ajaxError: 'Ajax request error',
      group: 'Join group',
      curator: 'Follow curator',
      developer: 'Follow developer',
      publisher: 'Follow publisher',
      announcement: 'Like announcement',
      wishlist: 'Add to wishlist',
      fGame: 'Follow game',
      visit: 'Visit link',
      verify: 'Verify',
      autoLogin: 'Auto login',
      doTask: 'Do the task',
      autoLoginDes: 'Automatic login, manual login required for the first time (only for freegamelottery website)',
      doTaskDes: 'Do "MAIN DRAW", "SURVEY DRAW", "VIDEO DRAW", and "STACKPOT" tasks in that order',
      ungroup: 'Leave group',
      uncurator: 'Unfollow curator',
      undeveloper: 'Unfollow developer',
      unpublisher: 'Unfollow publisher',
      unwishlist: 'Remove from wishlist',
      unfGame: 'Unfollow game',
      ungroupDes: 'Leave the steam group',
      uncuratorDes: 'Unfollow the steam curator',
      undeveloperDes: 'Unfollow the steam developer',
      unpublisherDes: 'Unfollow the steam publisher',
      unwishlistDes: 'Remove game from wishlist',
      unfGameDes: 'Unfollow game',
      showLogs: 'Show logs',
      showDetails: 'Output verbose logs',
      checkLogin: 'Login check',
      checkLeft: 'Remaining key check',
      autoOpen: 'Open task page automatically',
      autoCheckUpdate: 'Check for updates automatically',
      reCaptcha: 'Repair reCaptcha',
      showLogsDes: 'Show task log in bottom right corner by default',
      showDetailsDes: 'Output verbose logs to the console',
      checkLoginDes: 'Check if you are logged in, jump to login page if not logged in',
      checkLeftDes: 'Check if there are remaining keys, and remind if there are no remaining keys',
      autoOpenDes: 'Unfinished tasks automatically open the task page for manual completion (requires closing the browser pop-up block)',
      reCaptchaDes: 'If the Gamehag website has an ergonomic error, try turning this option on / off',
      globalSettings: 'Global Settings'
    }
  }
  let language = getLanguage()
  function getLanguage () {
    let lan = GM_getValue('language') || 'auto'
    if (lan === 'auto') {
      const browserLanguage = (navigator.browserLanguage || navigator.language).toLowerCase()
      lan = browserLanguage.includes('en') ? 'en' : 'zh-cn'
    }
    return lan
  }
  function getI18n (name, str = null) {
    let value = 'null'
    if (str) value = i18n[language][name] ? i18n[language][name].replace('s%', str) : 'null'
    else value = i18n[language][name] || 'null'
    return value
  }

  GM_addStyle(GM_getResourceText('css'))
  $('body').append('<div v-cloak id="vue-ui"></div>')
  const vueUi = new Vue({ el: '#vue-ui' })
  Vue.config.errorHandler = function (err, vm, info) {
    setTimeout(() => {
      vueUi.$message({ type: 'error', duration: 0, message: getI18n('jsError'), showClose: true })
    }, 500)
    console.log('%c%s', 'color:white;background:red', 'Info:' + info + '\nError:' + err.stack)
  }
  $(document).ajaxError(function (event, xhr, options, exc) {
    vueUi.$message({ type: 'error', duration: 0, message: getI18n('jsError'), showClose: true })
    console.log('%c%s', 'color:white;background:red', getI18n('ajaxError') + ':')
    console.log('Event:', event)
    console.log('XMLHttpRequest :', xhr)
    console.log('Options:', options)
    console.log('JavaScript exception:', exc)
  })

  try {
    const steamInfo = GM_getValue('steamInfo') || {
      userName: '',
      steam64Id: '',
      communitySessionID: '',
      storeSessionID: '',
      updateTime: 0
    }
    const defaultConf = {
      fuck: {
        group: 1,
        curator: 1,
        developer: 1,
        publisher: 1,
        announcement: 1,
        wishlist: 1,
        followGame: 1,
        visit: 1,
        verify: 1
      },
      verify: {
        verify: 1
      },
      join: {
        group: 1,
        curator: 1,
        developer: 1,
        publisher: 1,
        announcement: 1,
        wishlist: 1,
        followGame: 1,
        visit: 1
      },
      remove: {
        group: 1,
        curator: 1,
        developer: 1,
        publisher: 1,
        wishlist: 1,
        followGame: 1
      },
      other: {
        showLogs: 1,
        showDetails: 0,
        checkLogin: 1,
        checkLeft: 1,
        autoOpen: 0,
        reCaptcha: 0
      },
      announcement: ''
    }
    const globalConf = (GM_getValue('conf') && GM_getValue('conf').global) ? GM_getValue('conf').global : defaultConf
    const debug = !!globalConf.other.showDetails
    const fuc = {
      httpRequest: function (e) {
        const requestObj = {}
        requestObj.url = e.url
        requestObj.method = e.method.toUpperCase()
        requestObj.timeout = e.timeout || 30000
        if (e.dataType) requestObj.responseType = e.dataType
        if (e.headers) requestObj.headers = e.headers
        if (e.data) requestObj.data = e.data
        if (e.onload) requestObj.onload = e.onload
        requestObj.ontimeout = e.ontimeout || function (data) {
          if (debug) console.log(data)
          if (e.status) e.status.error('Error:Timeout(0)')
          if (e.r) e.r({ result: 'error', statusText: 'Timeout', status: 0, option: e })
        }
        requestObj.onabort = e.onabort || function (data) {
          if (debug) console.log(data)
          if (e.status) e.status.error('Error:Aborted(0)')
          if (e.r) e.r({ result: 'error', statusText: 'Aborted', status: 0, option: e })
        }
        requestObj.onerror = e.onerror || function (data) {
          if (debug) console.log(data)
          if (e.status) e.status.error('Error:Error(0)')
          if (e.r) e.r({ result: 'error', statusText: 'Error', status: 0, option: e })
        }
        if (debug) console.log('发送请求:', requestObj)
        GM_xmlhttpRequest(requestObj)
      },
      updateSteamInfo: function (r, type = 'all', update = false) {
        if (new Date().getTime() - steamInfo.updateTime > 10 * 60 * 1000 || update) {
          const pro = []
          if (type === 'community' || type === 'all') {
            pro.push(new Promise((resolve, reject) => {
              const status = this.echoLog({ type: 'updateSteamCommunity' })
              this.httpRequest({
                url: 'https://steamcommunity.com/my',
                method: 'GET',
                onload: (response) => {
                  if (debug) console.log(response)
                  if (response.status === 200) {
                    if ($(response.responseText).find('a[href*="/login/home"]').length > 0) {
                      status.error('Error:' + getI18n('loginSteamCommunity'), true)
                      reject(Error('Not Login'))
                    } else {
                      const steam64Id = response.responseText.match(/g_steamID = "(.+?)";/)
                      const communitySessionID = response.responseText.match(/g_sessionID = "(.+?)";/)
                      const userName = response.responseText.match(/steamcommunity.com\/id\/(.+?)\/friends\//)
                      if (steam64Id) steamInfo.steam64Id = steam64Id[1]
                      if (communitySessionID) steamInfo.communitySessionID = communitySessionID[1]
                      if (userName) steamInfo.userName = userName[1]
                      status.success()
                      resolve()
                    }
                  } else {
                    status.error('Error:' + response.statusText + '(' + response.status + ')')
                    reject(Error('Request Failed'))
                  }
                },
                r: resolve,
                status
              })
            }))
          }
          if (type === 'store' || type === 'all') {
            pro.push(new Promise((resolve, reject) => {
              const status = this.echoLog({ type: 'updateSteamStore' })

              this.httpRequest({
                url: 'https://store.steampowered.com/stats/',
                method: 'GET',
                onload: (response) => {
                  if (debug) console.log(response)
                  if (response.status === 200) {
                    if ($(response.responseText).find('a[href*="/login/"]').length > 0) {
                      status.error('Error:' + getI18n('loginSteamStore'), true)
                      reject(Error('Not Login'))
                    } else {
                      const storeSessionID = response.responseText.match(/g_sessionID = "(.+?)";/)
                      if (storeSessionID) steamInfo.storeSessionID = storeSessionID[1]
                      status.success()
                      resolve()
                    }
                  } else {
                    status.error('Error:' + response.statusText + '(' + response.status + ')')
                    reject(Error('Request Failed'))
                  }
                },
                r: resolve,
                status
              })
            }))
          }
          Promise.all(pro).then(() => {
            steamInfo.updateTime = new Date().getTime()
            GM_setValue('steamInfo', steamInfo)
            r(1)
          }).catch(err => {
            console.error(err)
          })
        } else {
          r(1)
        }
      },
      joinSteamGroup: function (r, group) {
        const status = this.echoLog({ type: 'joinSteamGroup', text: group })

        this.httpRequest({
          url: 'https://steamcommunity.com/groups/' + group,
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
          data: $.param({ action: 'join', sessionID: steamInfo.communitySessionID }),
          onload: (response) => {
            if (debug) console.log(response)
            if (response.status === 200 && !response.responseText.includes('grouppage_join_area')) {
              status.success()
              r({ result: 'success', statusText: response.statusText, status: response.status })
            } else {
              status.error('Error:' + response.statusText + '(' + response.status + ')')
              r({ result: 'error', statusText: response.statusText, status: response.status })
            }
          },
          r,
          status
        })
      },
      getGroupID: function (groupName, callback) {
        const status = this.echoLog({ type: 'getGroupId', text: groupName })
        const groupNameToId = GM_getValue('groupNameToId') || {}
        if (groupNameToId[groupName]) {
          status.success()
          callback(groupName, groupNameToId[groupName])
        } else {
          new Promise(resolve => {
            this.httpRequest({
              url: 'https://steamcommunity.com/groups/' + groupName,
              method: 'GET',
              headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
              onload: function (response) {
                if (debug) console.log(response)
                if (response.status === 200) {
                  const groupId = response.responseText.match(/OpenGroupChat\( '([0-9]+)'/)
                  if (groupId === null) {
                    status.error('Error:' + response.statusText + '(' + response.status + ')')
                    resolve(false)
                  } else {
                    status.success()
                    groupNameToId[groupName] = groupId[1]
                    GM_setValue('groupNameToId', groupNameToId)
                    resolve(groupId[1])
                  }
                } else {
                  status.error('Error:' + response.statusText + '(' + response.status + ')')
                  resolve(false)
                }
              },
              status,
              r: () => {
                resolve(false)
              }
            })
          }).then(groupId => {
            if (groupId !== false && callback) callback(groupName, groupId)
          }).catch(err => {
            console.error(err)
          })
        }
      },
      leaveSteamGroup: function (r, groupName) {
        this.getGroupID(groupName, (groupName, groupId) => {
          const status = this.echoLog({ type: 'leaveSteamGroup', text: groupName })

          this.httpRequest({
            url: 'https://steamcommunity.com/id/' + steamInfo.userName + '/home_process',
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
            data: $.param({ sessionID: steamInfo.communitySessionID, action: 'leaveGroup', groupId: groupId }),
            onload: (response) => {
              if (debug) console.log(response)
              if (response.status === 200 && response.finalUrl.includes('groups') && $(response.responseText.toLowerCase()).find(`a[href='https://steamcommunity.com/groups/${groupName.toLowerCase()}']`).length === 0) {
                status.success()
                r({ result: 'success', statusText: response.statusText, status: response.status })
              } else {
                status.error('Error:' + response.statusText + '(' + response.status + ')')
                r({ result: 'error', statusText: response.statusText, status: response.status })
              }
            },
            r,
            status
          })
        })
      },
      followCurator: function (r, curatorId, follow = '1', status = '') {
        status = status || this.echoLog({ type: follow === '1' ? 'followCurator' : 'unfollowCurator', text: curatorId })

        this.httpRequest({
          url: 'https://store.steampowered.com/curators/ajaxfollow',
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
          data: $.param({ clanid: curatorId, sessionid: steamInfo.storeSessionID, follow: follow }),
          dataType: 'json',
          onload: (response) => {
            if (debug) console.log(response)
            if (response.status === 200 && response.response && response.response.success && response.response.success.success === 1) {
              status.success()
              r({ result: 'success', statusText: response.statusText, status: response.status })
            } else {
              status.error(`Error:${response.response.msg || response.statusText}(${response.response.success || response.status})`)
              r({ result: 'error', statusText: response.statusText, status: response.status })
            }
          },
          r,
          status
        })
      },
      unfollowCurator: function (r, curatorId) {
        this.followCurator(r, curatorId, '0')
      },
      getCuratorID: function (developerName, callback, isPublisher = 0) {
        const status = this.echoLog({ type: isPublisher ? 'getPublisherId' : 'getDeveloperId', text: developerName })
        const developerNameToId = GM_getValue('developerNameToId') || {}
        if (developerNameToId[developerName]) {
          status.success()
          callback(developerName, developerNameToId[developerName])
        } else {
          new Promise(resolve => {
            this.httpRequest({
              url: `https://store.steampowered.com/${isPublisher ? 'publisher' : 'developer'}/${developerName}`,
              method: 'GET',
              headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
              onload: function (response) {
                if (debug) console.log(response)
                if (response.status === 200) {
                  const developerId = response.responseText.match(/g_pagingData.*?"clanid":([\d]+)/)
                  if (developerId === null) {
                    status.error('Error:' + response.statusText + '(' + response.status + ')')
                    resolve(false)
                  } else {
                    status.success()
                    developerNameToId[developerName] = developerId[1]
                    GM_setValue('developerNameToId', developerNameToId)
                    resolve(developerId[1])
                  }
                } else {
                  status.error('Error:' + response.statusText + '(' + response.status + ')')
                  resolve(false)
                }
              },
              status,
              r: () => { resolve(false) }
            })
          }).then(curatorId => {
            if (curatorId !== false && callback) callback(developerName, curatorId)
          }).catch(err => {
            console.error(err)
          })
        }
      },
      followDeveloper: function (r, developerName, isPublisher = 0) {
        this.getCuratorID(developerName, (developerName, curatorId) => {
          const status = this.echoLog({ type: isPublisher ? 'followPublisher' : 'followDeveloper', text: developerName })
          this.followCurator(r, curatorId, '1', status)
        }, isPublisher)
      },
      unfollowDeveloper: function (r, developerName, isPublisher = 0) {
        this.getCuratorID(developerName, (developerName, curatorId) => {
          const status = this.echoLog({ type: isPublisher ? 'unfollowPublisher' : 'unfollowDeveloper', text: developerName })
          this.followCurator(r, curatorId, '0', status)
        }, isPublisher)
      },
      followPublisher: function (r, publisherName) {
        this.followDeveloper(r, publisherName, 1)
      },
      unfollowPublisher: function (r, publisherName) {
        this.unfollowDeveloper(r, publisherName, 1)
      },
      addWishlist: function (r, gameId) {
        const status = this.echoLog({ type: 'addWishlist', text: gameId })
        new Promise(resolve => {
          this.httpRequest({
            url: 'https://store.steampowered.com/api/addtowishlist',
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
            data: $.param({ sessionid: steamInfo.storeSessionID, appid: gameId }),
            dataType: 'json',
            onload: function (response) {
              if (debug) console.log(response)
              if (response.status === 200 && response.response && response.response.success === true) {
                status.success()
                resolve({ result: 'success', statusText: response.statusText, status: response.status })
              } else {
                resolve({ result: 'error', statusText: response.statusText, status: response.status })
              }
            },
            onabort: response => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            onerror: response => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            ontimeout: response => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            r: resolve,
            status
          })
        }).then(result => {
          if (result.result === 'success') {
            r(result)
          } else {
            this.httpRequest({
              url: 'https://store.steampowered.com/app/' + gameId,
              method: 'GET',
              onload: function (response) {
                if (debug) console.log(response)
                if (response.status === 200) {
                  if (response.responseText.includes('class="queue_actions_ctn"') && response.responseText.includes('已在库中')) {
                    status.success()
                    r({ result: 'success', statusText: response.statusText, status: response.status, own: true })
                  } else if ((response.responseText.includes('class="queue_actions_ctn"') && response.responseText.includes('添加至您的愿望单')) || !response.responseText.includes('class="queue_actions_ctn"')) {
                    status.error('Error:' + result.statusText + '(' + result.status + ')')
                    r({ result: 'error', statusText: response.statusText, status: response.status })
                  } else {
                    status.success()
                    r({ result: 'success', statusText: response.statusText, status: response.status })
                  }
                } else {
                  status.error('Error:' + result.statusText + '(' + result.status + ')')
                  r({ result: 'error', statusText: response.statusText, status: response.status })
                }
              },
              r,
              status
            })
          }
        }).catch(err => {
          console.error(err)
        })
      },
      removeWishlist: function (r, gameId) {
        const status = this.echoLog({ type: 'removeWishlist', text: gameId })
        new Promise(resolve => {
          this.httpRequest({
            url: 'https://store.steampowered.com/api/removefromwishlist',
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
            data: $.param({ sessionid: steamInfo.storeSessionID, appid: gameId }),
            dataType: 'json',
            onload: function (response) {
              if (debug) console.log(response)
              if (response.status === 200 && response.response && response.response.success === true) {
                status.success()
                resolve({ result: 'success', statusText: response.statusText, status: response.status })
              } else {
                resolve({ result: 'error', statusText: response.statusText, status: response.status })
              }
            },
            onabort: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            onerror: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            ontimeout: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            r: resolve,
            status
          })
        }).then(result => {
          if (result.result === 'success') {
            r(result)
          } else {
            this.httpRequest({
              url: 'https://store.steampowered.com/app/' + gameId,
              method: 'GET',
              onload: function (response) {
                if (debug) console.log(response)
                if (response.status === 200) {
                  if (response.responseText.includes('class="queue_actions_ctn"') && (response.responseText.includes('已在库中') || response.responseText.includes('添加至您的愿望单'))) {
                    status.success()
                    r({ result: 'success', statusText: response.statusText, status: response.status })
                  } else {
                    status.error('Error:' + result.statusText + '(' + result.status + ')')
                    r({ result: 'error', statusText: response.statusText, status: response.status })
                  }
                } else {
                  status.error('Error:' + result.statusText + '(' + result.status + ')')
                  r({ result: 'error', statusText: response.statusText, status: response.status })
                }
              },
              r,
              status
            })
          }
        }).catch(err => {
          console.error(err)
        })
      },
      followGame: function (r, gameId) {
        const status = this.echoLog({ type: 'followGame', text: gameId })
        new Promise(resolve => {
          this.httpRequest({
            url: 'https://store.steampowered.com/explore/followgame/',
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
            data: $.param({ sessionid: steamInfo.storeSessionID, appid: gameId }),
            onload: function (response) {
              if (debug) console.log(response)
              if (response.status === 200 && response.responseText === 'true') {
                status.success()
                resolve({ result: 'success', statusText: response.statusText, status: response.status })
              } else {
                resolve({ result: 'error', statusText: response.statusText, status: response.status })
              }
            },
            onabort: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            onerror: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            ontimeout: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            r: resolve,
            status
          })
        }).then(result => {
          if (result.result === 'success') {
            r(result)
          } else {
            this.httpRequest({
              url: 'https://store.steampowered.com/app/' + gameId,
              method: 'GET',
              onload: function (response) {
                if (debug) console.log(response)
                if (response.status === 200) {
                  if (response.responseText.includes('class="queue_actions_ctn"') && response.responseText.includes('class="btnv6_blue_hoverfade btn_medium queue_btn_active" style="">')) {
                    status.success()
                    r({ result: 'success', statusText: response.statusText, status: response.status })
                  } else {
                    status.error('Error:' + result.statusText + '(' + result.status + ')')
                    r({ result: 'error', statusText: response.statusText, status: response.status })
                  }
                } else {
                  status.error('Error:' + result.statusText + '(' + result.status + ')')
                  r({ result: 'error', statusText: response.statusText, status: response.status })
                }
              },
              r,
              status
            })
          }
        }).catch(err => {
          console.error(err)
        })
      },
      unfollowGame: function (r, gameId) {
        const status = this.echoLog({ type: 'unfollowGame', text: gameId })
        new Promise(resolve => {
          this.httpRequest({
            url: 'https://store.steampowered.com/explore/followgame/',
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
            data: $.param({ sessionid: steamInfo.storeSessionID, appid: gameId, unfollow: '1' }),
            onload: function (response) {
              if (debug) console.log(response)
              if (response.status === 200 && response.responseText === 'true') {
                status.success()
                resolve({ result: 'success', statusText: response.statusText, status: response.status })
              } else {
                resolve({ result: 'error', statusText: response.statusText, status: response.status })
              }
            },
            onabort: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            onerror: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            ontimeout: (response) => { resolve({ result: 'error', statusText: response.statusText, status: response.status }) },
            r: resolve,
            status
          })
        }).then(result => {
          if (result.result === 'success') {
            r(result)
          } else {
            this.httpRequest({
              url: 'https://store.steampowered.com/app/' + gameId,
              method: 'GET',
              onload: function (response) {
                if (debug) console.log(response)
                if (response.status === 200) {
                  if (response.responseText.includes('class="queue_actions_ctn"') && response.responseText.includes('class="btnv6_blue_hoverfade btn_medium queue_btn_active" style="">')) {
                    status.error('Error:' + result.statusText + '(' + result.status + ')')
                    r({ result: 'error', statusText: response.statusText, status: response.status })
                  } else {
                    status.success()
                    r({ result: 'success', statusText: response.statusText, status: response.status })
                  }
                } else {
                  status.error('Error:' + result.statusText + '(' + result.status + ')')
                  r({ result: 'error', statusText: response.statusText, status: response.status })
                }
              },
              r,
              status
            })
          }
        }).catch(err => {
          console.error(err)
        })
      },
      likeAnnouncements: function (r, url, id) {
        const status = this.echoLog({ type: 'likeAnnouncements', url, id })

        this.httpRequest({
          url: url.replace('/detail/', '/rate/'),
          method: 'POST',
          headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
          data: $.param({ sessionid: steamInfo.communitySessionID, voteup: true }),
          dataType: 'json',
          onload: (response) => {
            if (debug) console.log(response)
            if (response.status === 200 && response.response && response.response.success === 1) {
              status.success()
              r({ result: 'success', statusText: response.statusText, status: response.status })
            } else {
              status.error(`Error:${response.response.msg || response.statusText}(${response.response.success || response.status})`)
              r({ result: 'error', statusText: response.statusText, status: response.status })
            }
          },
          r,
          status
        })
      },
      getFinalUrl: function (r, url, options = {}) {
        const conf = {
          url: options.url || url,
          method: options.method || 'GET',
          onload: (response) => {
            r({ result: 'success', finalUrl: response.finalUrl, url })
          },
          r
        }
        if (options.headers) conf.headers = options.headers
        if (options.data) conf.data = options.data
        this.httpRequest(conf)
      },
      visitLink: function (r, url, options = {}) {
        if (!options.method) options.method = 'HEAD'
        const status = this.echoLog({ type: 'visitLink', text: url })
        new Promise(resolve => {
          this.getFinalUrl(resolve, url, options)
        }).then(() => {
          status.warning('Complete')
          r(1)
        }).catch(err => {
          console.error(err)
        })
      },
      checkUpdate: function (v, s = false) {
        v.icon = 'el-icon-loading'
        let status = false
        if (s) status = this.echoLog({ type: 'custom', text: `<li>${getI18n('checkingUpdate')}<font></font></li>` })
        this.httpRequest({
          url: 'https://userjs.hclonely.com/version?t=' + new Date().getTime(),
          method: 'get',
          dataType: 'json',
          onload: (response) => {
            if (debug) console.log(response)
            if (response.response && response.response.version === GM_info.script.version) {
              v.icon = 'el-icon-refresh'
              v.title = getI18n('checkUpdate')
              if (s) status.success(getI18n('thisIsNew'))
              v.hidden = true
            } else if (response.response) {
              v.icon = 'el-icon-download'
              v.title = getI18n('updateNow') + response.response.version
              v.checkUpdate = function () { window.open('https://userjs.hclonely.com/auto-task.user.js', '_blank') }
              if (s) status.success(getI18n('newVer') + response.response.version)
              v.hidden = false
            } else {
              v.icon = 'el-icon-refresh'
              v.title = getI18n('checkUpdate')
              if (s) status.error('Error:' + (response.statusText || response.status))
            }
            const conf = GM_getValue('conf') || defaultConf
            if (response.response && response.response.time !== conf.announcement) {
              v.announcementHidden = false
              conf.announcement = response.response.time
              GM_setValue('conf', conf)
            }
          },
          ontimeout: (response) => {
            if (debug) console.log(response)
            v.icon = 'el-icon-refresh'
            v.title = getI18n('checkUpdate')
            if (s) status.error('Error:Timeout(0)')
          },
          onabort: (response) => {
            if (debug) console.log(response)
            v.icon = 'el-icon-refresh'
            v.title = getI18n('checkUpdate')
            if (s) status.error('Error:Abort(0)')
          },
          onerror: (response) => {
            if (debug) console.log(response)
            v.icon = 'el-icon-refresh'
            v.title = getI18n('checkUpdate')
            if (s) status.error('Error:Error(0)')
          },
          status
        })
      },
      getAnnouncement: function (v) {
        v.announcementIcon = 'el-icon-loading'
        const status = this.echoLog({ type: 'custom', text: `<li>${getI18n('getAnnouncement')}<font></font></li>` })
        this.httpRequest({
          url: 'https://userjs.hclonely.com/new.json?t=' + new Date().getTime(),
          method: 'get',
          dataType: 'json',
          onload: (response) => {
            if (debug) console.log(response)
            if (response.responseText && response.response) {
              status.success()
              const data = response.response
              const conf = GM_getValue('conf') || defaultConf
              conf.announcement = data.time
              GM_setValue('conf', conf)
              v.announcementHidden = true
              const h = vueUi.$createElement
              const hArr = []
              for (const index in data.text) {
                if (/^[\d]+$/.test(index)) hArr.push(h('p', null, `${parseInt(index) + 1}.${data.text[index]}`))
              }
              vueUi.$msgbox({
                title: `V${data.version}(${fuc.dateFormat('YYYY-mm-dd HH:MM', new Date(data.time))})`,
                message: h('div', null, hArr),
                showCancelButton: true,
                confirmButtonText: getI18n('visitHistory'),
                cancelButtonText: getI18n('close')
              }).then(() => {
                window.open('https://userjs.hclonely.com/announcement.html', '_blank')
              }).catch(() => { })
            } else {
              status.error('Error:' + (response.statusText || response.status))
            }
            v.announcementIcon = 'el-icon-document'
          },
          ontimeout: (response) => {
            if (debug) console.log(response)
            v.announcementIcon = 'el-icon-document'
            status.error('Error:Timeout(0)')
          },
          onabort: (response) => {
            if (debug) console.log(response)
            v.announcementIcon = 'el-icon-document'
            status.error('Error:Abort(0)')
          },
          onerror: (response) => {
            if (debug) console.log(response)
            v.announcementIcon = 'el-icon-document'
            status.error('Error:Error(0)')
          },
          status
        })
      },
      newTabBlock: function () {
        const d = new Date()
        const cookiename = 'haveVisited1'
        document.cookie = cookiename + '=1; path=/'
        document.cookie = cookiename + '=' + (d.getUTCMonth() + 1) + '/' + d.getUTCDate() + '/' + d.getUTCFullYear() + '; path=/'
      },
      creatSetting: function (settingName, header, fuckOptions, checkedFucks, removeOptions, checkedRemoves) {
        new Vue({ // eslint-disable-line no-new
          el: `#${settingName}`,
          data: {
            header: `${header} ${getI18n('websiteSetting')}`,
            checked: GM_getValue('conf') ? GM_getValue('conf')[settingName] ? (!!GM_getValue('conf')[settingName].load) : false : false,
            fuck: {
              checkAll: fuckOptions.length === checkedFucks.length,
              checkedFucks: checkedFucks,
              fucks: fuckOptions,
              isIndeterminate: fuckOptions.length !== checkedFucks.length
            },
            remove: {
              checkAll: removeOptions.length === checkedRemoves.length,
              checkedRemoves: checkedRemoves,
              removes: removeOptions,
              isIndeterminate: removeOptions.length !== checkedRemoves.length
            },
            openDelay: 100,
            rowType: 'flex',
            rowAlign: 'middle',
            verify: '1'
          },
          methods: {
            fuckHandleCheckAllChange (val) {
              this.fuck.checkedFucks = val ? fuckOptions.map(e => e.name) : []
              this.fuck.isIndeterminate = false
            },
            handleCheckedFucksChange (value) {
              const checkedCount = value.length
              this.fuck.checkAll = checkedCount === this.fuck.fucks.length
              this.fuck.isIndeterminate = checkedCount > 0 && checkedCount < this.fuck.fucks.length
            },
            removeHandleCheckAllChange (val) {
              this.remove.checkedRemoves = val ? removeOptions.map(e => e.name) : []
              this.remove.isIndeterminate = false
            },
            handleCheckedRemovesChange (value) {
              const checkedCount = value.length
              this.remove.checkAll = checkedCount === this.remove.removes.length
              this.remove.isIndeterminate = checkedCount > 0 && checkedCount < this.remove.removes.length
            }
          }
        })
      },
      creatConf: function () {
        const confs = {}
        for (const div of $('div.setting')) {
          const id = $(div).attr('id')
          const conf = {}
          for (const form of $(div).find('form')) {
            const name = $(form).attr('name')
            if (name === 'max-point') {
              const value = $(form).find('input').val()
              conf[name] = /^[\d]+$/.test(value) ? value : 0
            } else {
              const setting = {}
              for (const data of $(form).serializeArray()) {
                setting[data.name] = 1
              }
              conf[name] = setting
            }
          }
          confs[id] = conf
        }
        for (const checkbox of $('.non-global input')) {
          if ($(checkbox).is(':checked')) confs[$(checkbox).attr('name')].load = 1
        }
        const lotteryUserInfo = GM_getValue('conf') ? GM_getValue('conf').lotteryUserInfo : false
        if (lotteryUserInfo) confs.lotteryUserInfo = lotteryUserInfo
        const announcement = GM_getValue('conf') ? GM_getValue('conf').announcement : false
        if (announcement) confs.announcement = announcement
        return confs
      },
      echoLog: function (e) {
        let ele = ''
        switch (e.type) {
          case 'updateSteamCommunity':
            ele = $(`<li>${getI18n('updateCommunityId')}<font></font></li>`)
            break
          case 'updateSteamStore':
            ele = $(`<li>${getI18n('updateStoreId')}<font></font></li>`)
            break
          case 'joinSteamGroup':
            ele = $(`<li>${getI18n('joinGroup')}<a href="https://steamcommunity.com/groups/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'getGroupId':
            ele = $(`<li>${getI18n('getGroupId')}<a href="https://steamcommunity.com/groups/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'leaveSteamGroup':
            ele = $(`<li>${getI18n('leaveGroup')}<a href="https://steamcommunity.com/groups/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'followCurator':
            ele = $(`<li>${getI18n('followCurator')}<a href="https://store.steampowered.com/curator/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'unfollowCurator':
            ele = $(`<li>${getI18n('unfollowCurator')}<a href="https://store.steampowered.com/curator/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'getDeveloperId':
            ele = $(`<li>${getI18n('getDeveloperId')}<a href="https://store.steampowered.com/developer/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'followDeveloper':
            ele = $(`<li>${getI18n('followDeveloper')}<a href="https://store.steampowered.com/developer/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'unfollowDeveloper':
            ele = $(`<li>${getI18n('unfollowDeveloper')}<a href="https://store.steampowered.com/developer/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'getPublisherId':
            ele = $(`<li>${getI18n('getPublisherId')}<a href="https://store.steampowered.com/publisher/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'followPublisher':
            ele = $(`<li>${getI18n('followPublisher')}<a href="https://store.steampowered.com/publisher/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'unfollowPublisher':
            ele = $(`<li>${getI18n('unfollowPublisher')}<a href="https://store.steampowered.com/publisher/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'addWishlist':
            ele = $(`<li>${getI18n('addWishlist')}<a href="https://store.steampowered.com/app/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'removeWishlist':
            ele = $(`<li>${getI18n('removeWishlist')}<a href="https://store.steampowered.com/app/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'followGame':
            ele = $(`<li>${getI18n('followGame')}<a href="https://store.steampowered.com/app/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'unfollowGame':
            ele = $(`<li>${getI18n('unfollowGame')}<a href="https://store.steampowered.com/app/${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'likeAnnouncements':
            ele = $(`<li>${getI18n('likeAnnouncements')}<a href="${e.url}" target="_blank">${e.id}</a>...<font></font></li>`)
            break
          case 'visitLink':
            ele = $(`<li>${getI18n('visitLink')}...<a href="${e.text}" target="_blank">${e.text}</a>...<font></font></li>`)
            break
          case 'custom':
            ele = $(e.text)
            break
          default:
            ele = $(`<li>${getI18n('unknown')}<font></font></li>`)
            break
        }
        $('.fuck-task-logs .el-notification__content').append(ele)
        ele[0].scrollIntoView()
        const font = ele.find('font')
        const status = {
          font,
          success: function (text = 'Success', html = false) {
            this.font.attr('class', '').addClass('success')
            html ? this.font.html(text) : this.font.text(text)
          },
          error: function (text = 'Error', html = false) {
            this.font.attr('class', '').addClass('error')
            html ? this.font.html(text) : this.font.text(text)
          },
          warning: function (text = 'Warning', html = false) {
            this.font.attr('class', '').addClass('warning')
            html ? this.font.html(text) : this.font.text(text)
          },
          info: function (text = 'Info', html = false) {
            this.font.attr('class', '').addClass('info')
            html ? this.font.html(text) : this.font.text(text)
          }
        }
        return status
      },
      unique: e => [...new Set(e)],
      getUrlQuery: function (url) {
        const q = {}
        if (url) {
          if (url.includes('?')) url.split('?')[1].replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => { q[k] = v })
        } else {
          window.location.search.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => { q[k] = v })
        }
        return q
      },
      dateFormat: function (fmt, date) {
        let ret = null
        const opt = {
          'Y+': date.getFullYear().toString(),
          'm+': (date.getMonth() + 1).toString(),
          'd+': date.getDate().toString(),
          'H+': date.getHours().toString(),
          'M+': date.getMinutes().toString(),
          'S+': date.getSeconds().toString()
        }
        for (const k in opt) {
          ret = new RegExp('(' + k + ')').exec(fmt)
          if (ret) {
            fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, '0')))
          }
        }
        return fmt
      },
      addBackground: function () {
        GM_addStyle('body {background-image:url(//img.hclonely.com/www/006brDXlly1ft9lm7ns5zj31hc0u0qh3.jpg);background-position:center bottom;background-size:cover;background-attachment:fixed;background-repeat:no-repeat;}')
      },
      isEmptyObjArr: function (object) {
        for (const value of Object.values(object)) {
          if (Object.prototype.toString.call(value) === '[object Array]') {
            if (value.length !== 0) return false
          } else if (Object.prototype.toString.call(value) === '[object Object]') {
            if (Object.keys(value).length !== 0) return false
          } else if (Object.prototype.toString.call(value) === '[object String]') {
            if (value !== '') return false
          }
        }
        return true
      }
    }

    const banana = {
      test: () => { return (window.location.host.includes('grabfreegame') || window.location.host.includes('bananagiveaway')) },
      fuck: function (vue) {
        const needBanana = $("p:contains('Collect'):contains('banana')")
        const needPoints = $("p:contains('Collect'):contains('point')")
        let msg = ''
        if (needBanana.length > 0) msg = getI18n('needBanana', needBanana.text().match(/[\d]+/gim)[0])
        if (needPoints.length > 0) msg = getI18n('needPoints', needPoints.text().replace(/Collect/gi, ''))
        if (needPoints.length > 0 || needBanana.length > 0) {
          vue.$confirm(msg, getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning'
          }).then(() => {
            this.get_tasks('do_task')
          }).catch(err => {
            console.error(err)
          })
        } else {
          this.get_tasks('do_task')
        }
      },
      get_tasks: function (callback = 'do_task') {
        const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) this.taskInfo = taskInfoHistory
        if (callback === 'remove' && taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) {
          this.remove(true)
        } else {
          this.tasks = []
          this.links = []
          this.groups = []
          this.curators = []
          this.wishlists = []
          this.fGames = []
          this.taskIds = []

          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('processTasksInfo')}<font></font></li>` })

          const tasksUl = $('ul.tasks li:not(:contains(Completed))')
          const pro = []
          for (const task of tasksUl) { // 遍历任务信息
            const taskDes = $(task).find('p')
            const verifyBtn = $(task).find('button:contains(Verify)')
            const taskId = verifyBtn.length > 0 ? verifyBtn.attr('onclick').match(/\?verify=([\d]+)/) : ''
            if (taskId) {
              this.tasks.push({ taskId: taskId[1], taskDes: taskDes.text() })
              if (/join.*?steam.*?group/gim.test(taskDes.text())) {
            pro.push(new Promise(res => { // eslint-disable-line
                  new Promise(resolve => {
                    fuc.getFinalUrl(resolve, window.location.origin + window.location.pathname + '?q=' + taskId[1])
                  }).then(r => {
                    if (r.result === 'success') {
                      const groupName = r.finalUrl.match(/groups\/(.+)\/?/)
                      if (groupName) {
                        this.groups.push(groupName[1])
                        this.taskInfo.groups.push(groupName[1])
                      } else {
                        this.taskIds.push(taskId[1])
                      }
                    } else {
                      this.taskIds.push(taskId[1])
                    }
                    res(1)
                  })
                }))
              } else if (/follow.*?curator/gim.test(taskDes.text())) {
            pro.push(new Promise(res => { // eslint-disable-line
                  new Promise(resolve => {
                    fuc.getFinalUrl(resolve, window.location.origin + window.location.pathname + '?q=' + taskId[1])
                  }).then(r => {
                    if (r.result === 'success') {
                      const curatorId = r.finalUrl.match(/curator\/([\d]+)/)
                      if (curatorId) {
                        this.curators.push(curatorId[1])
                        this.taskInfo.curators.push(curatorId[1])
                      } else {
                        this.taskIds.push(taskId[1])
                      }
                    } else {
                      this.taskIds.push(taskId[1])
                    }
                    res(1)
                  })
                }))
              } else if (/wishlist/gim.test(taskDes.text())) {
            pro.push(new Promise(res => { // eslint-disable-line
                  new Promise(resolve => {
                    fuc.getFinalUrl(resolve, window.location.origin + window.location.pathname + '?q=' + taskId[1])
                  }).then(r => {
                    if (r.result === 'success') {
                      const appId = r.finalUrl.match(/store.steampowered.com\/app\/([\d]+)/)
                      if (appId) {
                        this.wishlists.push(appId[1])
                        this.taskInfo.wishlists.push(appId[1])
                      } else {
                        this.taskIds.push(taskId[1])
                      }
                    } else {
                      this.taskIds.push(taskId[1])
                    }
                    res(1)
                  })
                }))
              } else {
                if (/(Subscribe.*channel)|(Retweet)|(Twitter)/gim.test(taskDes.text())) {
                  if (!this.verifyBtn) this.verifyBtn = taskDes.parent().find('button:contains(Verify)')
                  if (callback === 'do_task' && globalConf.other.autoOpen) {
                    taskDes.parent().find('button')[0].click()
                  }
                }
                pro.push(new Promise(resolve => {
                  this.links.push(window.location.origin + window.location.pathname + '?q=' + taskId[1])
                  this.taskIds.push(taskId[1])
                  resolve(1)
                }))
              }
            }
          }
          Promise.all(pro).finally(() => {
            this.links = fuc.unique(this.links)
            this.groups = fuc.unique(this.groups)
            this.curators = fuc.unique(this.curators)
            this.wishlists = fuc.unique(this.wishlists)
            this.fGames = fuc.unique(this.fGames)
            this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
            this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
            this.taskInfo.wishlists = fuc.unique(this.taskInfo.wishlists)
            this.taskInfo.fGames = fuc.unique(this.taskInfo.fGames)
            this.taskIds = fuc.unique(this.taskIds)
            this.tasks = fuc.unique(this.tasks)
            GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
            status.success()
            if (debug) console.log(this)
            if (callback === 'do_task') {
              this.do_task()
            } else if (callback === 'verify') {
              this.tasks.length > 0 ? this.verify(true) : fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            } else {
              !fuc.isEmptyObjArr(this.taskInfo) ? this.remove(true) : fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('cannotRemove')}</font></li>` })
            }
          })
        }
      },
      do_task: function () {
        this.updateSteamInfo(() => {
          const pro = []
          const groups = fuc.unique(this.groups)
          const curators = fuc.unique(this.curators)
          const wishlists = fuc.unique(this.wishlists)
          const fGames = fuc.unique(this.fGames)
          const links = fuc.unique(this.links)
          if (this.conf.fuck.group) {
            for (const group of groups) {
              pro.push(new Promise(resolve => {
                fuc.joinSteamGroup(resolve, group)
              }))
            }
          }
          if (this.conf.fuck.curator) {
            for (const curator of curators) {
              pro.push(new Promise(resolve => {
                fuc.followCurator(resolve, curator)
              }))
            }
          }
          if (this.conf.fuck.wishlist) {
            for (const gameId of wishlists) {
              pro.push(new Promise(resolve => {
                fuc.addWishlist(resolve, gameId)
              }))
            }
          }
          if (this.conf.fuck.followGame) {
            for (const gameId of fGames) {
              pro.push(new Promise(resolve => {
                fuc.followGame(resolve, gameId)
              }))
            }
          }
          if (this.conf.fuck.visit) {
            for (const link of links) {
              pro.push(new Promise(resolve => {
                fuc.visitLink(resolve, link)
              }))
            }
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            if (this.conf.fuck.verify) this.verify()
          })
        })
      },
      verify: function (verify = false) {
        if (verify) {
          const pro = []
          for (const task of fuc.unique(this.tasks)) {
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('verifyingTask')}${task.taskDes}...<font></font></li>` })
            pro.push(new Promise(resolve => {
              fuc.httpRequest({
                url: window.location.origin + window.location.pathname + '?verify=' + task.taskId,
                method: 'GET',
                onload: function (response) {
                  if (debug) console.log(response)
                  status.warning('Complete')
                  resolve({ result: 'success', statusText: response.statusText, status: response.status })
                },
                r: resolve,
                status
              })
            }))
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('verifyTasksComplete')}</font></li>` })
            this.verifyBtn.length > 0 ? this.verifyBtn.removeAttr('disabled')[0].click() : window.location.reload(true)
          })
        } else {
          this.get_tasks('verify')
        }
      },
      remove: function (remove = false) {
        const pro = []
        if (remove) {
          this.updateSteamInfo(() => {
            if (this.conf.remove.group) {
              for (const group of fuc.unique(this.taskInfo.groups)) {
                pro.push(new Promise(resolve => {
                  fuc.leaveSteamGroup(resolve, group)
                }))
              }
            }
            if (this.conf.remove.curator) {
              for (const curator of fuc.unique(this.taskInfo.curators)) {
                pro.push(new Promise(resolve => {
                  fuc.unfollowCurator(resolve, curator)
                }))
              }
            }
            if (this.conf.remove.wishlist) {
              for (const gameId of fuc.unique(this.taskInfo.wishlists)) {
                pro.push(new Promise(resolve => {
                  fuc.removeWishlist(resolve, gameId)
                }))
              }
            }
            if (this.conf.remove.unfollowGame) {
              for (const gameId of fuc.unique(this.taskInfo.fGames)) {
                pro.push(new Promise(resolve => {
                  fuc.unfollowGame(resolve, gameId)
                }))
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            })
          })
        } else {
          this.get_tasks('remove')
        }
      },
      get_giveawayId: function () {
        const id = window.location.href.match(/\/giveaway\/([\w\d-]+)/)
        return id ? id[1] : window.location.href
      },
      updateSteamInfo: function (callback) {
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0) {
            if (this.taskInfo.curators.length > 0 || this.taskInfo.fGames.length > 0 || this.taskInfo.wishlists.length > 0) {
              fuc.updateSteamInfo(resolve, 'all')
            } else {
              fuc.updateSteamInfo(resolve, 'community')
            }
          } else if (this.taskInfo.curators.length > 0 || this.taskInfo.fGames.length > 0 || this.taskInfo.wishlists.length > 0) {
            fuc.updateSteamInfo(resolve, 'store')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) callback()
        }).catch(err => {
          console.error(err)
        })
      },
      checkLogin: function () {
        if ($('a.steam[title*=team]').length > 0) window.open('/giveaway/steam/', '_self')
      },
      checkLeft: function (ui) {
        if ($('.left b').text() === '0') {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      verifyBtn: 0,
      links: [], // 需要浏览的页面链接
      groups: [], // 所有任务需要加的组
      curators: [], // 所有任务需要关注的鉴赏家
      wishlists: [], // 所有务需要添加愿望单的游戏
      fGames: [], // 所有任务需要关注的的游戏
      taskIds: [], // 处理失败的任务
      taskInfo: {
        groups: [], // 任务需要加的组
        curators: [], // 任务需要关注的鉴赏家
        wishlists: [], // 任务需要添加愿望单的游戏
        fGames: []// 任务需要关注的的游戏
      },
      tasks: [], // 所有任务ID
      setting: {
        fuck: true,
        verify: true,
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').banana && GM_getValue('conf').banana.load) ? GM_getValue('conf').banana : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const freegamelottery = {
      test: () => { return window.location.host.includes('freegamelottery') },
      after: website => {
        if (window.location.host === 'd.freegamelottery.com' && GM_getValue('lottery') === 1) website.draw()
      },
      fuck: function (vue) {
        GM_setValue('lottery', 1)
        if ($('a.registration-button').length > 0) {
          if (this.conf.fuck.autoLogin) {
            const userInfo = GM_getValue('conf').lotteryUserInfo
            if (userInfo) {
              const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('logining')}<font></font></li>` })
              fuc.httpRequest({
                url: 'https://freegamelottery.com/user/login',
                method: 'POST',
                data: `username=${userInfo.username}&password=${userInfo.password}&rememberMe=1`,
                headers: {
                  'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                },
                onload: function (data) {
                  if (data.status === 200) {
                    status.success()
                    window.location.reload(true)
                  } else {
                    status.error('Error:' + (data.statusText || data.status))
                  }
                },
                status
              })
            } else {
              vue.$message({ type: 'warning', message: getI18n('needLogin') })
              $('a.registration-button')[0].click()
              $('button[value=Login]').click(() => {
                const conf = GM_getValue('conf')
                conf.lotteryUserInfo = { username: $('#modal_login').val(), password: $('#modal_password').val() }
                GM_setValue('conf', conf)
              })
            }
          } else {
            vue.$message({ type: 'warning', message: getI18n('needLogin') })
            $('a.registration-button')[0].click()
          }
        } else {
          this.draw()
        }
      },
      draw: function () {
        GM_setValue('lottery', 0)
        if (this.conf.fuck.doTask) {
          const main = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('fglTimeout', 'Visit MAIN DRAW')}<font></font></li>` })
          $.post('/draw/register-visit', { drawId: DashboardApp.draws.main.actual.id })
            .done(function () {
              DashboardApp.draws.main.actual.haveVisited = true
              main.success()
              const survey = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('fglTimeout', 'Visit SURVEY DRAW')}<font></font></li>` })
              $.post('/draw/register-visit', { type: 'survey', drawId: DashboardApp.draws.survey.actual.id })
                .done(function () {
                  DashboardApp.draws.survey.actual.haveVisited = 1
                  survey.success()
                  const video = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('fglTimeout', 'Visit VIDEO DRAW')}<font></font></li>` })
                  $.post('/draw/register-visit', { drawId: DashboardApp.draws.video.actual.id })
                    .done(function () {
                      DashboardApp.draws.video.actual.haveVisited = true
                      video.success()
                      const stackpot = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('fglTimeout', 'Visit STACKPOT')}<font></font></li>` })
                      $.post('/draw/register-visit', { type: 'stackpot', drawId: DashboardApp.draws.stackpot.actual.id })
                        .done(function () {
                          DashboardApp.draws.stackpot.actual.haveVisited = 1
                          stackpot.success()
                          fuc.echoLog({ type: 'custom', text: `<li>${getI18n('fglComplete')}<font></font></li>` })
                          window.location.href = '/#/draw/stackpot'
                          window.location.reload(true)
                        })
                    })
                })
            })
        }
      },
      setting: {
        fuck: true,
        verify: false,
        join: false,
        remove: false
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').freegamelottery && GM_getValue('conf').freegamelottery.load) ? GM_getValue('conf').freegamelottery : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const gamehag = {
      test: () => { return window.location.host.includes('gamehag') },
      before: () => {
        $('#getkey').removeAttr('disabled')
        if (globalConf.other.reCaptcha) $('body').append('<script>window.bannedCountries = ["en"];window.geo ="en";window.respCaptch="";</script>')
      },
      fuck: function () { this.get_tasks('do_task') },
      get_tasks: function (callback = 'do_task') {
        const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })
        const verifyBtns = $('button[data-id]')
        if (callback === 'do_task') {
          const taskInfo = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
          if (taskInfo && !fuc.isEmptyObjArr(taskInfo)) this.taskInfo = taskInfo
          this.groups = []
          this.tasks = []
          for (const btn of verifyBtns) {
            const taskId = $(btn).attr('data-id')
            const taskDes = $(btn).parent().prev().text()
            if ($(btn).parents('.task-content').next().text().includes('+1')) this.tasks.push({ taskId, taskDes })
          }
          if ($('a.giveaway-survey').length > 0) {
            const taskId = $('a.giveaway-survey').attr('data-task_id')
            const taskDes = 'Complete the survey'
            this.tasks.push({ taskId, taskDes })
          }
          this.groups = fuc.unique(this.groups)
          this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
          this.tasks = fuc.unique(this.tasks)
          GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
          if (this.tasks.length > 0) {
            this.do_task()
          } else {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            if (this.conf.fuck.verify) this.verify()
          }
        } else if (callback === 'verify') {
          this.tasks = []
          for (const btn of verifyBtns) {
            const taskId = $(btn).attr('data-id')
            const taskDes = $(btn).parent().prev().text()
            if ($(btn).parents('.task-content').next().text().includes('+1')) this.tasks.push({ taskId, taskDes })
          }
          this.tasks = fuc.unique(this.tasks)
          if (this.tasks.length > 0) {
            this.verify(true)
          } else {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('verifyTasksComplete')}</font></li>` })
          }
        } else if (callback === 'remove') {
          fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('cannotRemove')}</font></li>` })
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('unknown')}!</font></li>` })
        }
        status.success()
        if (debug) console.log(this)
      },
      do_task: async function () {
        const pro = []
        const tasks = fuc.unique(this.tasks)
        for (let i = 0; i < tasks.length; i++) {
          const task = tasks[i]
          pro.push(new Promise((resolve) => {
            fuc.visitLink(resolve, '/giveaway/click/' + task.taskId, { headers: { 'x-csrf-token': $('meta[name="csrf-token"]').attr('content') } })
          }))
          if (/play.*?games/gim.test(task.taskDes)) {
            pro.push(new Promise((resolve) => {
              fuc.visitLink(resolve, '/games', { headers: { 'x-csrf-token': $('meta[name="csrf-token"]').attr('content') } })
            }))
            pro.push(new Promise((resolve) => {
              fuc.visitLink(resolve, '/games/war-thunder/play', { headers: { 'x-csrf-token': $('meta[name="csrf-token"]').attr('content') } })
            }))
          }
          await new Promise(resolve => {
            setTimeout(() => { resolve() }, 1000)
          })
        }
        Promise.all(pro).finally(() => {
          fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
          if (this.conf.fuck.verify) this.verify()
        })
      },
      verify: async function (verify = false) {
        if (verify) {
          const pro = []
          const tasks = fuc.unique(this.tasks)
          for (let i = 0; i < tasks.length; i++) {
            const task = tasks[i]
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('verifyingTask')}<a href="/giveaway/click/${task.taskId}" target="_blank">${task.taskDes.trim()}</a>...<font></font></li>` })
            pro.push(new Promise((resolve) => {
              fuc.httpRequest({
                url: '/api/v1/giveaway/sendtask',
                method: 'POST',
                dataType: 'json',
                headers: {
                  'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
                  'x-csrf-token': $('meta[name="csrf-token"]').attr('content')
                },
                data: 'task_id=' + task.taskId,
                onload: function (response) {
                  if (debug) console.log(response)
                  if (response.response) {
                    if (response.response.status === 'success') {
                      status.success()
                      $(`div.task-reward[href="#task-${task.taskId}-collapse"]`).html('<svg class="nc-icon nc-align-to-text grid-24 glyph"><use xlink:href="/icons/nci-fill.svg#nc-icon-check-simple" /></svg>')
                      resolve({ result: 'success', statusText: response.statusText, status: response.status })
                    } else {
                      status.error('Error:' + (response.response.message || response.statusText || response.status || 'error'))
                      if (globalConf.other.autoOpen) window.open(`/giveaway/click/${task.taskId}`, '_blank')
                      resolve({ result: 'error', statusText: response.statusText, status: response.status })
                    }
                  } else {
                    status.error('Error:' + response.statusText)
                    resolve({ result: 'error', statusText: response.statusText, status: response.status })
                  }
                },
                r: resolve,
                status
              })
            }))
            await new Promise(resolve => {
              setTimeout(() => { resolve() }, 1000)
            })
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('verifyTasksComplete')}</font></li>` })
          })
        } else {
          this.get_tasks('verify')
        }
      },
      remove: function (remove = false) {
        fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('cannotRemove')}</font></li>` })
      },
      get_giveawayId: function () {
        const id = window.location.href.match(/\/giveaway\/([\d]+)/)
        return id ? id[1] : window.location.href
      },
      checkLeft: function (ui) {
        if ($('.giveaway-counter:first .strong').text() === '0') {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      groups: [], // 任务需要加的组
      taskInfo: {
        groups: []// 所有任务需要加的组
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        verify: true,
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').gamehag && GM_getValue('conf').gamehag.load) ? GM_getValue('conf').gamehag : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const giveawaysu = {
      test: () => { return window.location.host.includes('giveaway.su') },
      get_tasks: function (e) {
        // 获取任务信息
        const taskInfo = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfo && !fuc.isEmptyObjArr(taskInfo) && e === 'remove') {
          this.taskInfo = taskInfo
          this.do_task('remove')
        } else {
          if (taskInfo && !fuc.isEmptyObjArr(taskInfo)) this.taskInfo = taskInfo
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })
          const tasks = $('#actions tr')
          for (const task of tasks) {
            const taskDes = $(task).find('td').eq(1).find('a:not([data-trigger="link"])')
            const taskInfo = this.which_task(taskDes)
            for (const info of taskInfo) {
              if (info.name !== 'nonSteam' && this.taskInfo[info.name + 's']) {
                this.taskInfo[info.name + 's'].push(info.link)
                this.taskInfo.links.push(info.link)
              }
            }
          }
          status.success()
          this.getFinalUrl(e)
        }
      },
      which_task: function (taskDes) {
        const taskInfo = []
        const taskName = taskDes.text().trim()
        const link = taskDes.attr('href')
        if (/disable adblock/gim.test(taskName)) {
          return [{ name: 'nonSteam' }]
        } else if (/join.*group/gim.test(taskName)) {
          taskInfo.push({ name: 'group', link })
          this.community = 1
        } else if (/like.*announcement/gim.test(taskName)) {
          taskInfo.push({ name: 'announcement', link })
          this.community = 1
        } else if (/follow.*publisher/gim.test(taskName)) {
          taskInfo.push({ name: 'publisher', link })
          this.store = 1
        } else if (/follow.*developer/gim.test(taskName)) {
          taskInfo.push({ name: 'developer', link })
          this.store = 1
        } else if (/follow.*curator|subscribe.*curator/gim.test(taskName)) {
          taskInfo.push({ name: 'curator', link })
          this.store = 1
        } else {
          if (/(Subscribe.*YouTube)|(Like.*YouTube)|(Follow.*Instagram)|(on twitter)|(Join.*Discord.*server)|(Follow.*on.*Facebook)/gim.test(taskName)) {
            this.links.push(link)
          } else {
            if (/wishlist.*game|add.*wishlist/gim.test(taskName)) {
              taskInfo.push({ name: 'wGame', link })
              this.store = 1
            }
            if (/follow.*button/gim.test(taskName)) {
              taskInfo.push({ name: 'fGame', link })
              this.store = 1
            }
          }
          if (taskInfo.length === 0) return [{ name: 'nonSteam' }]
        }
        return taskInfo
      },
      getFinalUrl: function (e) {
        // 处理任务链接
        const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('processTasksUrl')}<font></font></li>` })
        const pro = []
        for (const link of this.taskInfo.links) {
          pro.push(new Promise(resolve => {
            if (this.taskInfo.toFinalUrl[link]) {
              resolve({ result: 'success' })
            } else {
              fuc.getFinalUrl(resolve, link)
            }
          }))
        }
        Promise.all(pro).then(data => {
          for (const r of data) {
            if (r.finalUrl) {
              this.taskInfo.toFinalUrl[r.url] = r.finalUrl
            }
          }

          this.links = fuc.unique(this.links)
          this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
          this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
          this.taskInfo.publishers = fuc.unique(this.taskInfo.publishers)
          this.taskInfo.developers = fuc.unique(this.taskInfo.developers)
          this.taskInfo.fGames = fuc.unique(this.taskInfo.fGames)
          this.taskInfo.wGames = fuc.unique(this.taskInfo.wGames)
          this.taskInfo.announcements = fuc.unique(this.taskInfo.announcements)
          this.taskInfo.links = fuc.unique(this.taskInfo.links)
          // 任务链接处理完成
          GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
          status.success()
          if (debug) console.log(this)
          e === 'doTask' ? this.do_task('join') : this.do_task('remove')
        }).catch(error => {
          status.error()
          if (debug) console.log(error)
        })
      },
      do_task: function (act) {
        if (globalConf.other.autoOpen && act === 'join' && this.links.length > 0) {
          for (const link of fuc.unique(this.links)) {
            window.open(link, '_blank')
          }
        }
        if ($('div.bind-discord').is(':visible')) $('div.bind-discord a')[0].click()
        if ($('div.bind-twitch').is(':visible')) $('div.bind-twitch a')[0].click()
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0 || this.taskInfo.announcements.length > 0) {
            if (this.taskInfo.curators.length > 0 || this.taskInfo.publishers.length > 0 || this.taskInfo.developers.length > 0 || this.taskInfo.fGames.length > 0 || this.taskInfo.wGames.length > 0) {
              fuc.updateSteamInfo(resolve, 'all')
            } else {
              fuc.updateSteamInfo(resolve, 'community')
            }
          } else if (this.taskInfo.curators.length > 0 || this.taskInfo.publishers.length > 0 || this.taskInfo.developers.length > 0 || this.taskInfo.fGames.length > 0 || this.taskInfo.wGames.length > 0) {
            fuc.updateSteamInfo(resolve, 'store')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) {
            const pro = []
            for (const group of fuc.unique(this.taskInfo.groups)) {
              if (this.taskInfo.toFinalUrl[group]) {
                const groupName = this.taskInfo.toFinalUrl[group].match(/groups\/(.+)\/?/)
                if (groupName) {
                  pro.push(new Promise(resolve => {
                    if (act === 'join' && this.conf.join.group) {
                      fuc.joinSteamGroup(resolve, groupName[1])
                    } else if (act === 'remove' && this.conf.remove.group) {
                      fuc.leaveSteamGroup(resolve, groupName[1])
                    } else {
                      resolve(1)
                    }
                  }))
                }
              }
            }
            for (const curator of fuc.unique(this.taskInfo.curators)) {
              if (this.taskInfo.toFinalUrl[curator]) {
                const curatorId = this.taskInfo.toFinalUrl[curator].match(/curator\/([\d]+)/)
                if (curatorId) {
                  pro.push(new Promise(resolve => {
                    if (act === 'join' && this.conf.join.curator) {
                      fuc.followCurator(resolve, curatorId[1])
                    } else if (act === 'remove' && this.conf.remove.curator) {
                      fuc.unfollowCurator(resolve, curatorId[1])
                    } else {
                      resolve(1)
                    }
                  }))
                }
              }
            }
            for (const publisher of fuc.unique(this.taskInfo.publishers)) {
              if (this.taskInfo.toFinalUrl[publisher]) {
                const publisherName = this.taskInfo.toFinalUrl[publisher].includes('publisher') ? this.taskInfo.toFinalUrl[publisher].match(/publisher\/(.+)\/?/) : this.taskInfo.toFinalUrl[publisher].match(/pub\/(.+)\/?/)
                if (publisherName) {
                  pro.push(new Promise(resolve => {
                    if (act === 'join' && this.conf.join.publisher) {
                      fuc.followPublisher(resolve, publisherName[1])
                    } else if (act === 'remove' && this.conf.remove.publisher) {
                      fuc.unfollowPublisher(resolve, publisherName[1])
                    } else {
                      resolve(1)
                    }
                  }))
                }
              }
            }
            for (const developer of fuc.unique(this.taskInfo.developers)) {
              if (this.taskInfo.toFinalUrl[developer]) {
                const developerName = this.taskInfo.toFinalUrl[developer].includes('developer') ? this.taskInfo.toFinalUrl[developer].match(/developer\/(.+)\/?/) : this.taskInfo.toFinalUrl[developer].match(/dev\/(.+)\/?/)
                if (developerName) {
                  pro.push(new Promise(resolve => {
                    if (act === 'join' && this.conf.join.developer) {
                      fuc.followDeveloper(resolve, developerName[1])
                    } else if (act === 'remove' && this.conf.remove.developer) {
                      fuc.unfollowDeveloper(resolve, developerName[1])
                    } else {
                      resolve(1)
                    }
                  }))
                }
              }
            }
            for (const game of fuc.unique(this.taskInfo.fGames)) {
              if (this.taskInfo.toFinalUrl[game]) {
                const gameId = this.taskInfo.toFinalUrl[game].match(/app\/([\d]+)/)
                if (gameId) {
                  pro.push(new Promise(resolve => {
                    if (act === 'join' && this.conf.join.followGame) {
                      fuc.followGame(resolve, gameId[1])
                    } else if (act === 'remove' && this.conf.remove.unfollowGame) {
                      fuc.unfollowGame(resolve, gameId[1])
                    } else {
                      resolve(1)
                    }
                  }))
                }
              }
            }
            for (const game of fuc.unique(this.taskInfo.wGames)) {
              if (this.taskInfo.toFinalUrl[game]) {
                const gameId = this.taskInfo.toFinalUrl[game].match(/app\/([\d]+)/)
                if (gameId) {
                  pro.push(new Promise(resolve => {
                    if (act === 'join' && this.conf.join.wishlist) {
                      fuc.addWishlist(resolve, gameId[1])
                    } else if (act === 'remove' && this.conf.remove.wishlist) {
                      fuc.removeWishlist(resolve, gameId[1])
                    } else {
                      resolve(1)
                    }
                  }))
                }
              }
            }
            for (const announcement of fuc.unique(this.taskInfo.announcements)) {
              if (this.taskInfo.toFinalUrl[announcement]) {
                const announcementUrl = this.taskInfo.toFinalUrl[announcement]
                const announcementId = announcementUrl.match(/announcements\/detail\/([\d]+)/)
                if (announcementId) {
                  if (act === 'join' && this.conf.join.announcement) {
                    pro.push(new Promise(resolve => {
                      fuc.likeAnnouncements(resolve, announcementUrl, announcementId[1])
                    }))
                  }
                }
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
              if (act === 'join') fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('closeExtensions')}</font></li>` })
            })
          }
        })
      },
      fuck: function () { },
      verify: function () { },
      join: function () { this.get_tasks('doTask') },
      remove: function () { this.get_tasks('remove') },
      get_giveawayId: function () {
        const id = window.location.href.match(/view\/([\d]+)/)
        return id ? id[1] : window.location.href
      },
      checkLogin: function () {
        if ($('a.steam-login').length > 0) window.open('/steam/redirect', '_self')
      },
      checkLeft: function (ui) {
        if ($('.giveaway-ended').length > 0) {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      community: 0,
      store: 0,
      links: [], // 非steam任务
      taskInfo: {
        groups: [], // 任务需要加的组
        curators: [], // 任务需要关注的鉴赏家
        publishers: [], // 任务需要关注的发行商
        developers: [], // 任务需要关注的开发商
        fGames: [], // 任务需要关注的游戏
        wGames: [], // 任务需要加愿望单的游戏
        announcements: [], // 任务需要点赞的通知
        links: [], // 原始链接
        toFinalUrl: {}// 链接转换
      },
      setting: {
        fuck: false,
        verify: false,
        join: true,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').giveawaysu && GM_getValue('conf').giveawaysu.load) ? GM_getValue('conf').giveawaysu : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const givekey = {
      test: () => { return (window.location.host.includes('gkey') || window.location.host.includes('givekey')) },
      before: website => {
        const init = setInterval(() => {
          try {
            if (typeof Centrifuge !== 'undefined') {
              clearInterval(init)
              website.creat_app()
            }
          } catch (e) { }
        }, 500)
      },
      after: () => { $('#verify-task').addClass('is-disabled').attr('disabled', 'disabled') },
      fuck: function (btnArea) {
        const transBtn = $('.yt-button__icon.yt-button__icon_type_right')
        if (transBtn.css('background-position') === '-68px 0px') transBtn[0].click()
        fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('changeLanguage')}</font></li>` })
        givekey.wssApp.message = btnArea.$message({ message: getI18n('connectWss'), duration: 0 })
        $(() => givekey.wssApp.init(btnArea))
        fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('connectWssWait')}</font></li>` })
        fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('beforeFuck')}</font></li>` })
        fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('gkrobot')}</font></li>` })
        window.open($('a[id^="task_"').attr('href'), '_blank')
      },
      analyze_tasks: function (tasks) {
        const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('processTasksUrl')}<font></font></li>` })
        const pro = []
        this.groups = []
        this.wGames = []
        this.fGames = []
        this.links = []
        const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) this.taskInfo = taskInfoHistory
        for (const id of tasks) {
          const task = $('#task_' + id)
          const href = task.attr('href')
          if (href.includes('vk.com')) {
          } else if (href.includes('steamcommunity.com/groups')) {
            this.groups.push(href.match(/groups\/(.+)/)[1])
            this.taskInfo.groups.push(href.match(/groups\/(.+)/)[1])
          } else if (/Add to wishlist|加入愿望单/i.test(task.text())) {
        pro.push(new Promise(r => { // eslint-disable-line
              new Promise(resolve => {
                fuc.getFinalUrl(resolve, href)
              }).then(data => {
                if (data.result === 'success') {
                  const appId = data.finalUrl.match(/app\/([\d]+)/)
                  if (appId) {
                    this.wGames.push(appId[1])
                    this.taskInfo.wGames.push(appId[1])
                    r(1)
                  } else {
                    r(0)
                  }
                } else {
                  r(0)
                }
              })
            }))
          } else if (href.includes('store.steampowered.com/app')) {
            this.fGames.push(href.match(/app\/([\d]+)/)[1])
            this.taskInfo.fGames.push(href.match(/app\/([\d]+)/)[1])
          } else {
            this.links.push(href)
          }
        }
        Promise.all(pro).finally(() => {
          this.groups = fuc.unique(this.groups)
          this.wGames = fuc.unique(this.wGames)
          this.fGames = fuc.unique(this.fGames)
          this.links = fuc.unique(this.links)
          this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
          this.taskInfo.fGames = fuc.unique(this.taskInfo.fGames)
          this.taskInfo.wGames = fuc.unique(this.taskInfo.wGames)
          if (this.groups.length > 0 || this.fGames.length > 0 || this.links.length > 0 || this.wGames.length > 0) {
            this.do_task()
          } else {
            fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('noAutoFinish')}</font></li>` })
          }
          GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
          status.success()
          if (debug) console.log(this)
        })
      },
      get_tasks: function () {
        const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) {
          this.taskInfo = taskInfoHistory
          this.remove(true)
        } else {
          const pro = []
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })

          const tasksContainer = $('a[id^=task_]')
          for (const task of tasksContainer) { // 遍历任务信息
            const href = task.attr('href')
            if (href.includes('vk.com')) {
            } else if (href.includes('steamcommunity.com/groups/')) {
              this.taskInfo.groups.push(href.match(/groups\/(.+)/)[1])
            } else if (/Add to wishlist|加入愿望单/i.test(task.text())) {
          pro.push(new Promise(r => { // eslint-disable-line
                new Promise(resolve => {
                  fuc.getFinalUrl(resolve, href)
                }).then(data => {
                  if (data.result === 'success') {
                    const appId = data.finalUrl.match(/app\/([\d]+)/)
                    if (appId) {
                      this.wGames.push(appId[1])
                      this.taskInfo.wGames.push(appId[1])
                      r(1)
                    } else {
                      r(0)
                    }
                  } else {
                    r(0)
                  }
                })
              }))
            } else if (href.includes('store.steampowered.com/app/')) {
              this.taskInfo.fGames.push(href.match(/app\/([\d]+)/)[1])
            }
          }
          Promise.all(pro).finally(() => {
            this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
            this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
            this.taskInfo.wGames = fuc.unique(this.taskInfo.wGames)
            GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
            status.success()
            if (debug) console.log(this)
            if (this.taskInfo.groups.length > 0 || this.taskInfo.curators.length > 0 || this.taskInfo.wGames.length > 0) {
              this.remove(true)
            } else {
              fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('cannotRemove')}</font></li>` })
            }
          })
        }
      },
      do_task: function () {
        this.updateSteamInfo(() => {
          const pro = []
          const groups = fuc.unique(this.groups)
          const fGames = fuc.unique(this.fGames)
          const wGames = fuc.unique(this.wGames)
          const curators = fuc.unique(this.curators)
          const links = fuc.unique(this.links)
          if (this.conf.fuck.group) {
            for (const group of groups) {
              pro.push(new Promise((resolve) => {
                fuc.joinSteamGroup(resolve, group)
              }))
            }
          }
          if (this.conf.fuck.wishlist) {
            for (const game of wGames) {
              pro.push(new Promise(resolve => {
                fuc.addWishlist(resolve, game)
              }))
            }
          }
          if (this.conf.fuck.followGame) {
            for (const game of fGames) {
              pro.push(new Promise((resolve) => {
                fuc.followGame(resolve, game)
              }))
            }
          }
          if (this.conf.fuck.curator) {
            for (const curator of curators) {
              pro.push(new Promise((resolve) => {
                fuc.followCurator(resolve, curator)
              }))
            }
          }
          if (this.conf.fuck.visit) {
            for (const link of links) {
              pro.push(new Promise((resolve) => {
                fuc.visitLink(resolve, link)
              }))
            }
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
          })
        })
      },
      verify: function () {
        givekey.wssApp.status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTaskStatus')}<font></font></li>` })
        givekey.wssApp.request('/distribution/check', 'post', { id: window.location.href.match(/[\d]+/)[0], g_captcha: $('[name="g-recaptcha-response"]').val() })
      },
      remove: function (remove = false) {
        const pro = []
        if (remove) {
          this.updateSteamInfo(() => {
            if (this.conf.remove.group) {
              for (const group of fuc.unique(this.taskInfo.groups)) {
                pro.push(new Promise((resolve) => {
                  fuc.leaveSteamGroup(resolve, group)
                }))
              }
            }
            if (this.conf.remove.unfollowGame) {
              for (const game of fuc.unique(this.taskInfo.fGames)) {
                pro.push(new Promise((resolve) => {
                  fuc.unfollowCurator(resolve, game)
                }))
              }
            }
            if (this.conf.remove.wishlist) {
              for (const game of fuc.unique(this.taskInfo.wGames)) {
                pro.push(new Promise((resolve) => {
                  fuc.removeWishlist(resolve, game)
                }))
              }
            }
            if (this.conf.remove.curator) {
              for (const curator of fuc.unique(this.taskInfo.curators)) {
                pro.push(new Promise((resolve) => {
                  fuc.unfollowCurator(resolve, curator)
                }))
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            })
          })
        } else {
          this.get_tasks('remove')
        }
      },
      creat_app: function () {
        this.wssApp = {
          status: {},
          message: {},
          loading: false,
          centrifuge: new Centrifuge(/givekey.ru/.test(window.location.href) ? 'wss://app.givekey.ru/connection/websocket' : 'wss://app.gkey.fun/connection/websocket'),
          uid: $('meta[name="uid"]').attr('content'),
          init: function (m) {
            this.centrifuge.setToken($('meta[name="cent_token"]').attr('content'))
            this.centrifuge.connect()
            this.centrifuge.on('connect', function (e) {
              if (debug) console.log(getI18n('wssConnected'))
              $('#verify-task').removeClass('is-disabled').removeAttr('disabled')
              givekey.wssApp.message.close()
              m.$message({ message: getI18n('wssConnectSuccess'), type: 'success' })
              for (const a of $('a[id^=task_]')) {
                $(a).html($(a).html().replace('Посмотреть обзор на игру', '查看游戏评论')
                  .replace('Подписаться на разработчика', '订阅开发商')
                  .replace('Подписаться на куратора', '订阅鉴赏家')
                  .replace('Поставить лайк', '点赞')
                  .replace('Подписаться на игру', '关注游戏')
                  .replace(/Subscribe|Подписаться/, '订阅/加组')
                  .replace('Сделать репост', '转发')
                  .replace('Добавить в список желаемого', '加入愿望单')
                  .replace('Сделать обзор на игру', '评论')
                  .replace('Посетить web-сайт', '访问页面')
                )
              }
            })
            this.centrifuge.on('disconnect', function (e) {
              if (debug) console.log(`${getI18n('wssDisconnected')}\n${e.reason}`)
              $('#verify-task').addClass('is-disabled').attr('disabled', 'disabled')
              givekey.wssApp.message = m.$message({ message: getI18n('wssReconnect'), type: 'warning', duration: 0 })
            })
            if (this.uid) {
              this.centrifuge.subscribe(`usr#${this.uid}`, (data) => {
                if (debug) console.log(data)
                givekey.wssApp.status.success()
                if (data.data.js) {
                  const taskA = data.data.js.split(';')
                  if (taskA) {
                    const tasks = []
                    taskA.map((e) => {
                      if (e.includes('btn-danger')) tasks.push(e.match(/[\d]+/)[0])
                    })
                    givekey.analyze_tasks(tasks)
                  }
                }
              })
            }
          },
          request: (url, type, data, page) => {
            if (url) {
              data = data || {}
              type = type || 'post'
              if (type.toLowerCase() === 'get') {
                if (givekey.wssApp.loading) { return }
                givekey.wssApp.loading = !0
              }
              $.ajax({
                url: url,
                type: type,
                data: data,
                headers: {
                  'x-csrf-token': $('meta[name="csrf-token"]').attr('content')
                },
                success: function (data) {
                  if (debug) console.log(data)
                  if (data.msg && !data.msg.data.includes('Проверяем! Пожалуйста подождите')) givekey.wssApp.status.error(data.msg.data.replace('Вы уже участвовали в этой раздаче!', '你已经参与了此赠key!'))
                },
                error: function (e) {
                  if (debug) console.log(e)
                  switch (e.status) {
                    case 401:
                      givekey.wssApp.status.error(getI18n('noLogin'))
                      break
                    case 403:
                      givekey.wssApp.status.error(getI18n('accessDenied'))
                      break
                    case 404:
                      givekey.wssApp.status.error(getI18n('notFound'))
                      break
                    case 500:
                      givekey.wssApp.status.error(getI18n('serverError'))
                      break
                    case 503:
                      givekey.wssApp.status.error(getI18n('errorRefresh'))
                      break
                    default:
                      givekey.wssApp.status.error('Error:' + e.status)
                      break
                  }
                  givekey.wssApp.loading = !1
                }
              })
            }
          }
        }
      },
      get_giveawayId: function () {
        const id = window.location.href.match(/distribution\/([\d]+)/)
        return id ? id[1] : window.location.href
      },
      updateSteamInfo: function (callback) {
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0) {
            if (this.taskInfo.curators.length > 0 || this.taskInfo.fGames.length > 0 || this.taskInfo.wGames.length > 0) {
              fuc.updateSteamInfo(resolve, 'all')
            } else {
              fuc.updateSteamInfo(resolve, 'community')
            }
          } else if (this.taskInfo.curators.length > 0 || this.taskInfo.fGames.length > 0 || this.taskInfo.wGames.length > 0) {
            fuc.updateSteamInfo(resolve, 'store')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) callback()
        }).catch(err => {
          console.error(err)
        })
      },
      checkLogin: function () {
        if ($("a[href='/auth']").length > 0) window.open('/auth/steam', '_self')
      },
      checkLeft: function (ui) {
        if ($('#keys_count').text() === '0') {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      groups: [], // 任务需要加的组
      curators: [], // 任务需要关注的鉴赏家
      fGames: [], // 任务需要关注的游戏
      wGames: [], // 任务需要加愿望单的游戏
      developers: [], // 任务需要关注的开发商
      links: [], // 需要浏览的页面链接
      taskInfo: {
        groups: [], // 所有任务需要加的组
        curators: [], // 所有任务需要关注的鉴赏家
        developers: [], // 任务需要关注的开发商
        fGames: [], // 所有任务需要关注的游戏
        wGames: []// 所有任务需要加愿望单的游戏
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        fuckText: 'Init',
        fuckTitle: getI18n('initFirst'),
        verify: true,
        verifyText: 'Fuck',
        verifyTitle: getI18n('initPlease'),
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').givekey && GM_getValue('conf').givekey.load) ? GM_getValue('conf').givekey : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const gleam = {
      test: () => { return window.location.host.includes('gleam.io') },
      fuck: function () { this.get_tasks('do_task') },
      get_tasks: function (callback = 'do_task') {
        const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) this.taskInfo = taskInfoHistory
        if (callback === 'remove' && taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) {
          this.remove(true)
        } else {
          this.twitters = []
          this.facebooks = []
          this.youtubes = []
          this.discords = []
          this.others = []
          this.groups = []
          this.links = []
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })

          const tasksContainer = $('div.entry-content .entry-method')
          for (const task of tasksContainer) { // 遍历任务信息
            if ($(task).find('i.fa-question').length > 0) {
              if ($(task).hasClass('visit') || $(task).find('span:contains(Visit):contains(seconds)').length > 0) {
                this.links.push(task)
              } else {
                const icon = $(task).find('.icon-wrapper i')
                if (icon.hasClass('fa-twitter')) {
                  this.twitters.push(task)
                } else if (icon.hasClass('fa-facebook')) {
                  this.facebooks.push(task)
                } else if (icon.hasClass('fa-youtube')) {
                  this.youtubes.push(task)
                } else if (icon.hasClass('fa-discord')) {
                  this.discords.push(task)
                } else if (icon.hasClass('fa-steam') || icon.hasClass('fa-steam-symbol')) {
                  const title = $(task).find('.entry-method-title')
                  if (/join.*group/gim.test(title.text())) {
                    const groupA = $(task).find("a[href*='steamcommunity.com/groups']:first").attr('href')
                    if (groupA) {
                      const groupName = groupA.match(/steamcommunity.com\/groups\/([\w\d\-_]*)/)[1]
                      this.groups.push(groupName)
                      this.taskInfo.groups.push(groupName)
                    } else {
                      fuc.echoLog({
                        type: 'custom',
                        text: `<li><font class="error">${getI18n('getGroupFailed')}</font></li>`
                      })
                    }
                  } else {
                    this.others.push(task)
                  }
                } else {
                  this.others.push(task)
                }
              }
            } else if (callback === 'remove') {
              const icon = $(task).find('.icon-wrapper i')
              if (icon.hasClass('fa-steam')) {
                const title = $(task).find('.entry-method-title')
                if (/join.*group/gim.test(title.text())) {
                  const groupA = $(task).find("a[href*='steamcommunity.com/groups']:first").attr('href')
                  if (groupA) {
                    const groupName = groupA.match(/steamcommunity.com\/groups\/([\w\d\-_]*)/)[1]
                    this.taskInfo.groups.push(groupName)
                  } else {
                    fuc.echoLog({
                      type: 'custom',
                      text: `<li><font class="error">${getI18n('getGroupFailed')}</font></li>`
                    })
                  }
                }
              }
            }
          }
          this.groups = fuc.unique(this.groups)
          this.twitters = fuc.unique(this.twitters)
          this.facebooks = fuc.unique(this.facebooks)
          this.youtubes = fuc.unique(this.youtubes)
          this.discords = fuc.unique(this.discords)
          this.groups = fuc.unique(this.groups)
          this.others = fuc.unique(this.others)
          this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
          GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
          status.success()
          if (debug) console.log(this)
          if (callback === 'do_task') {
            this.do_task()
          } else if (callback === 'verify') {
            this.verify(true)
          } else {
            !fuc.isEmptyObjArr(this.taskInfo) ? this.remove(true) : fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('cannotRemove')}</font></li>` })
          }
        }
      },
      do_task: function () {
        this.updateSteamInfo(() => {
          const pro = []
          const groups = fuc.unique(this.groups)
          const twitters = fuc.unique(this.twitters)
          const discords = fuc.unique(this.discords)
          const facebooks = fuc.unique(this.facebooks)
          const youtubes = fuc.unique(this.youtubes)
          const others = fuc.unique(this.others)
          const links = fuc.unique(this.links)
          const socals = [...discords, ...facebooks, ...youtubes]
          if (this.conf.fuck.group && groups.length > 0) {
            for (const group of groups) {
              pro.push(new Promise((resolve) => {
                fuc.joinSteamGroup(resolve, group)
              }))
            }
          }
          if (globalConf.other.autoOpen) {
            if (twitters.length > 0) {
              for (const twitter of twitters) {
                const title = $(twitter).find('.entry-method-title').text().trim()
                const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('doing')}:${title}...<font></font></li>` })
                const followButton = $(twitter).find('a.twitter-button:contains(Follow)').attr('href')
                const retweetButton = $(twitter).find('a.twitter-button:contains(Retweet)').attr('href')
                const button = followButton || retweetButton
                if (button) {
                  window.open(button, '_blank')
                  status.warning(getI18n('openPage'))
                } else {
                  status.error(getI18n('getTaskUrlFailed'))
                }
              }
            }
            if (socals.length > 0) {
              for (const task of socals) {
                const title = $(task).find('.entry-method-title').text().trim()
                const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('doing')}:${title}...<font></font></li>` })
                const button = $(task).find('a.btn-info:first').attr('href')
                if (button) {
                  window.open(button, '_blank')
                  status.warning(getI18n('openPage'))
                } else {
                  status.error(getI18n('getTaskUrlFailed'))
                }
              }
            }
          }
          if ((globalConf.other.autoOpen || this.conf.fuck.visit) && links.length > 0) {
            pro.push(new Promise((resolve) => {
              this.visit_link(links, 0, resolve)
            }))
          }
          for (const other of others) {
            const icon = $(other).find('.icon-wrapper i')
            if (icon.hasClass('fa-steam')) {
              const title = $(other).find('.entry-method-title').text().trim()
              fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('unknowntype')}:${title}</font></li>` })
            } else {
              const taskType = icon.attr('class').match(/fa-([\w]+)/) ? icon.attr('class').match(/fa-([\w]+)/)[1] : icon.attr('class')
              fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('unknowntype')}:${taskType}</font></li>` })
            }
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            if (this.conf.fuck.verify) this.verify(0)
          })
        })
      },
      verify: function (i = 0) {
        if ($('.ng-scope[ng-include*=challenge]').is(':visible')) {
          fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('notRobot')}</font></li>` })
          return
        }
        const tasks = $('div.entry-content .entry-method')
        if (i < tasks.length) {
          if (tasks.eq(i).find('i.fa-question').length > 0) {
            const title = tasks.eq(i).find('.entry-method-title').text().trim()
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('verifyingTask')}:${title}...<font></font></li>` })
            tasks.eq(i).find('a.enter-link')[0].click()
            const enterBtn = tasks.eq(i).find('.form-actions.center .btn-primary:contains(Continue)').removeAttr('disabled')
            if (enterBtn.length > 0) {
              setTimeout(() => {
                enterBtn[0].click()
                status.warning('Complete')
                setTimeout(() => { gleam.verify(++i) }, 1000)
              }, 1000)
            } else {
              setTimeout(() => { gleam.verify(++i) }, 1000)
            }
          } else {
            this.verify(++i)
          }
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font><font class="warning">${getI18n('finishSelf')}</font></li>` })
        }
      },
      remove: function (remove = false) {
        const pro = []
        if (remove) {
          this.updateSteamInfo(() => {
            if (this.conf.remove.group) {
              for (const group of fuc.unique(this.taskInfo.groups)) {
                pro.push(new Promise((resolve) => {
                  fuc.leaveSteamGroup(resolve, group)
                }))
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            })
          })
        } else {
          this.get_tasks('remove')
        }
      },
      visit_link: function (links, i, r) {
        if (i < links.length) {
          const title = $(links[i]).find('.entry-method-title').text().trim()
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('doing')}:${title}...<font></font></li>` })
          const taskTime = $(links[i]).find('.form-actions.center span:contains(Visit):contains(seconds)').text()
          if (taskTime) {
            const taskBtn = $(links[i]).find('a.btn-info')
            const href = taskBtn.attr('href')
            taskBtn.removeAttr('href')[0].click()
            const time = taskTime.match(/[\d]+/)
            if (time) {
              const url = language === 'en' ? 'https://userjs.hclonely.com/time_en.html?time=' : 'https://userjs.hclonely.com/time.html?time='
              GM_openInTab(url + time[0], { active: 1, setParent: 1 }).onclose = () => {
                status.warning('Complete')
                taskBtn.attr('target', '_blank').attr('href', href)
                gleam.visit_link(links, ++i, r)
              }
            } else {
              GM_openInTab('javascript:setTimeout(()=>{window.close()},1000)', { active: 1, setParent: 1 }).onclose = () => {
                status.warning('Complete')
                taskBtn.attr('target', '_blank').attr('href', href)
                gleam.visit_link(links, ++i, r)
              }
            }
          } else {
            status.error(getI18n('getVisitTimeFailed'))
          }
        } else {
          r(1)
        }
      },
      get_giveawayId: function () {
        return window.location.pathname.replace(/\?.*/, '') || window.location.href
      },
      updateSteamInfo: function (callback) {
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0) {
            fuc.updateSteamInfo(resolve, 'community')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) callback()
        }).catch(err => {
          console.error(err)
        })
      },
      checkLeft: function (ui) {
        if ($('.massive-message:contains(ended)').is(':visible')) {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      groups: [], // 任务需要加的组
      links: [], // 需要浏览的页面链接
      twitters: [], // twitter任务
      discords: [], // discord任务
      facebooks: [], // facebook任务
      youtubes: [], // youtube任务
      others: [], // 位置类型任务
      taskInfo: {
        groups: []// 所有任务需要加的组
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        verify: true,
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').gleam && GM_getValue('conf').gleam.load) ? GM_getValue('conf').gleam : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const indiedb = {
      test: () => { return window.location.host.includes('indiedb') },
      fuck: function () {
        if ($('a.buttonenter:contains(Register to join)').length > 0) fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('needLogin')}</font></li>` })
        const currentoption = $('a.buttonenter.buttongiveaway')
        if (/join giveaway/gim.test(currentoption.text())) {
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('joinGiveaway')}<font></font></li>` })
          const doTask = this.do_task
          fuc.httpRequest({
            url: currentoption.attr('href'),
            method: 'POST',
            data: 'ajax=t',
            dataType: 'json',
            headers: {
              'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
              accept: 'application/json, text/javascript, */*; q=0.01'
            },
            onload: function (response) {
              if (debug) console.log(response)
              if (response.status === 200 && response.response) {
                if (response.response.success) {
                  currentoption.addClass('buttonentered').text('Success - Giveaway joined')
                  $('#giveawaysjoined').slideDown()
                  $('#giveawaysrecommend').slideDown()
                  status.success('Success' + (response.response.text ? (':' + response.response.text) : ''))
                  doTask()
                } else {
                  status.error('Error' + (response.response.text ? (':' + response.response.text) : ''))
                }
              } else {
                status.error('Error:' + (response.statusText || response.status))
              }
            }
          })
        } else if (/success/gim.test($('a.buttonenter.buttongiveaway').text())) {
          this.do_task()
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('needJoinGiveaway')}</font></li>` })
        }
      },
      do_task: function () {
        const id = $('script').map(function (i, e) {
          if (/\$\(document\)/gim.test(e.innerHTML)) {
            const optionId = e.innerHTML.match(/"\/newsletter\/ajax\/subscribeprofile\/optin\/[\d]+"/gim)[0].match(/[\d]+/)[0]
            const taskId = e.innerHTML.match(/"\/[\d]+"/gim)[0].match(/[\d]+/)[0]
            return [taskId, optionId]
          }
        })
        if (id.length === 2) {
          const tasks = $('#giveawaysjoined a[class*=promo]')
          const pro = []
          for (const task of tasks) {
            const promo = $(task)
            if (!promo.hasClass('buttonentered')) {
              const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('doing')}:${promo.parents('p').text()}...<font></font></li>` })
              if (/facebookpromo|twitterpromo|visitpromo/gim.test(task.className)) {
                pro.push(new Promise(resolve => {
                  $.ajax({
                    type: 'POST',
                    url: urlPath('/giveaways/ajax/' + (promo.hasClass('facebookpromo') ? 'facebookpromo' : (promo.hasClass('twitterpromo') ? 'twitterpromo' : 'visitpromo')) + '/' + id[0]),
                    timeout: 60000,
                    dataType: 'json',
                    data: { ajax: 't' },
                    error: function (response, error, exception) {
                      if (debug) console.log({ response, error, exception })
                      status.error('Error:An error has occurred performing the action requested. Please try again shortly.')
                      resolve(0)
                    },
                    success: function (response) {
                      if (debug) console.log(response)
                      if (response.success) {
                        status.success('Success:' + response.text)
                        promo.addClass('buttonentered').closest('p').html(promo.closest('p').find('span').html())
                        resolve(1)
                      } else {
                        status.error('Error:' + response.text)
                        resolve(0)
                      }
                    }
                  })
                }))
              } else if (promo.hasClass('emailoptinpromo')) {
                pro.push(new Promise(resolve => {
                  $.ajax({
                    type: 'POST',
                    url: urlPath('/newsletter/ajax/subscribeprofile/optin/' + id[1]),
                    timeout: 60000,
                    dataType: 'json',
                    data: { ajax: 't', emailsystoggle: 4 },
                    error: function (response, error, exception) {
                      if (debug) console.log({ response, error, exception })
                      status.error('Error:An error has occurred performing the action requested. Please try again shortly.')
                      resolve(0)
                    },
                    success: function (response) {
                      if (debug) console.log(response)
                      if (response.success) {
                        status.success('Success:' + response.text)
                        promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html())
                        resolve(1)
                      } else {
                        status.error('Error:' + response.text)
                        resolve(0)
                      }
                    }
                  })
                }))
              } else if (promo.hasClass('watchingpromo')) {
                pro.push(new Promise(resolve => {
                  const data = fuc.getUrlQuery(promo.attr('href'))
                  data.ajax = 't'
                  $.ajax({
                    type: 'POST',
                    url: urlPath(promo.attr('href').split(/[?#]/)[0]),
                    timeout: 60000,
                    dataType: 'json',
                    data: data,
                    error: function (response, error, exception) {
                      if (debug) console.log({ response, error, exception })
                      status.error('Error:An error has occurred performing the action requested. Please try again shortly.')
                      resolve(0)
                    },
                    success: function (response) {
                      if (debug) console.log(response)
                      if (response.success) {
                        status.success('Success:' + response.text)
                        promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html())
                        resolve(1)
                      } else {
                        status.error('Error:' + response.text)
                        resolve(0)
                      }
                    }
                  })
                }))
              } else if (!/the-challenge-of-adblock/gim.test(promo.attr('href'))) {
                pro.push(new Promise(resolve => {
                  $.ajax({
                    type: 'POST',
                    url: urlPath(promo.attr('href')),
                    timeout: 60000,
                    dataType: 'json',
                    data: { ajax: 't' },
                    error: function (response, error, exception) {
                      if (debug) console.log({ response, error, exception })
                      status.error('Error:An error has occurred performing the action requested. Please try again shortly.')
                      resolve(0)
                    },
                    success: function (response) {
                      if (debug) console.log(response)
                      if (response.success) {
                        status.success('Success:' + response.text)
                        promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html())
                        resolve(1)
                      } else {
                        status.error('Error:' + response.text)
                        resolve(0)
                      }
                    }
                  })
                }))
              } else {
                status.error('Error:' + getI18n('unknowntype'))
              }
            }
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('allTasksComplete')}</font></li>` })
          })
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('getIdFailed')}</font></li>` })
        }
      },
      checkLogin: function () {
        if ($('a.buttonenter:contains(Register to join)').length > 0) window.open('/members/login', '_self')
      },
      setting: {
        fuck: true,
        verify: false,
        join: false,
        remove: false
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').indiedb && GM_getValue('conf').indiedb.load) ? GM_getValue('conf').indiedb : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const marvelousga = {
      test: () => { return (window.location.host.includes('marvelousga') || window.location.host.includes('dupedornot')) },
      before: () => { fuc.newTabBlock() },
      fuck: function () { this.get_tasks('do_task') },
      get_tasks: function (callback = 'do_task') {
        const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) this.taskInfo = taskInfoHistory
        if (callback === 'remove' && taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) {
          this.remove(true)
        } else {
          this.tasks = []
          this.groups = []
          this.curators = []
          this.links = []
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })

          const tasksContainer = $('.container_task')
          for (const task of tasksContainer) { // 遍历任务信息
            const taskDes = $(task).find('.card-body p.card-text.monospace')
            const verifyBtn = $(task).find('button[id^=task_]:not(:contains(VERIFIED))')
            if (/join[\w\W]*?steamcommunity.com\/groups/gim.test(taskDes.html())) { // 加组任务
              const groupName = taskDes.find('a[href*="steamcommunity.com/groups"]').attr('href').match(/steamcommunity.com\/groups\/([\w\d\-_]*)/)[1]
              if (verifyBtn.length > 0) {
                this.groups.push(groupName)
              }
              this.taskInfo.groups.push(groupName)
            }
            if (/follow[\w\W]*?store.steampowered.com\/curator/gim.test(taskDes.html())) { // 关注鉴赏家任务
              const curatorName = taskDes.find('a[href*="store.steampowered.com/curator"]').attr('href').match(/store.steampowered.com\/curator\/([\d]*)/)[1]
              if (verifyBtn.length > 0) {
                this.curators.push(curatorName)
              }
              this.taskInfo.curators.push(curatorName)
            }
            if (/visit.*?this.*?page/gim.test(taskDes.text()) && verifyBtn.length > 0) { // 浏览页面任务
              const pageUrl = taskDes.find('a[id^="task_webpage_clickedLink"]').attr('href')
              this.links.push({ pageUrl: pageUrl, taskId: verifyBtn.attr('id').split('_')[3] })
            }
            if (verifyBtn.length > 0) { // 任务验证信息
              const provider = verifyBtn.attr('id').split('_')[1]
              const taskRoute = verifyBtn.attr('id').split('_')[2]
              const taskId = verifyBtn.attr('id').split('_')[3]
              this.tasks.push({ provider, taskRoute, taskId, taskDes: taskDes.html() })
            }
          }
          this.groups = fuc.unique(this.groups)
          this.curators = fuc.unique(this.curators)
          this.links = fuc.unique(this.links)
          this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
          this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
          this.tasks = fuc.unique(this.tasks)
          GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
          status.success()
          if (debug) console.log(this)
          if (callback === 'do_task') {
            if (this.tasks.length === 0) {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
              if (this.conf.fuck.verify) this.verify()
            } else {
              this.do_task()
            }
          } else if (callback === 'verify') {
            this.tasks.length > 0 ? this.verify(true) : fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('verifyTasksComplete')}</font></li>` })
          } else {
            !fuc.isEmptyObjArr(this.taskInfo) ? this.remove(true) : fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('cannotRemove')}</font></li>` })
          }
        }
      },
      do_task: function () {
        this.updateSteamInfo(() => {
          const pro = []
          const groups = fuc.unique(this.groups)
          const curators = fuc.unique(this.curators)
          const links = fuc.unique(this.links)
          if (this.conf.fuck.group) {
            for (const group of groups) {
              pro.push(new Promise(resolve => {
                fuc.joinSteamGroup(resolve, group)
              }))
            }
          }
          if (this.conf.fuck.curator) {
            for (const curator of curators) {
              pro.push(new Promise(resolve => {
                fuc.followCurator(resolve, curator)
              }))
            }
          }
          if (this.conf.fuck.visit) {
            for (const link of links) {
              pro.push(new Promise(resolve => {
                fuc.visitLink(resolve, link.pageUrl, {
                  url: '/ajax/verifyTasks/webpage/clickedLink',
                  method: 'POST',
                  headers: {
                    'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
                    'x-csrf-token': $('meta[name="csrf-token"]').attr('content')
                  },
                  data: $.param({
                    giveaway_slug: this.get_giveawayId(),
                    giveaway_task_id: link.taskId
                  })
                })
              }))
            }
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            if (this.conf.fuck.verify) this.verify()
          })
        })
      },
      verify: function (verify = false) {
        if (verify) {
          const pro = []
          for (const task of fuc.unique(this.tasks)) {
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('verifyingTask')}${task.taskDes}...<font></font></li>` })
            pro.push(new Promise(resolve => {
              fuc.httpRequest({
                url: '/ajax/verifyTasks/' + task.provider + '/' + task.taskRoute,
                method: 'POST',
                dataType: 'json',
                headers: {
                  'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
                  'x-csrf-token': $('meta[name="csrf-token"]').attr('content')
                },
                data: $.param({
                  giveaway_slug: this.get_giveawayId(),
                  giveaway_task_id: task.taskId
                }),
                onload: function (response) {
                  if (debug) console.log(response)
                  if (response.status === 200) {
                    if (response.response.status === 1) {
                      $(`#task_${task.provider}_${task.taskRoute}_${task.taskId}`).text('VERIFIED')
                      status.success(response.response.percentageNanoBar.toFixed(2) + '%')
                      resolve({ result: 'success', statusText: response.statusText, status: response.status })
                    } else {
                      status.error('Error:' + (response.response.message || 'error'))
                      if (globalConf.other.autoOpen) window.open($(`<div>${task.taskDes}</div>`).find('a').attr('href'), '_blank')
                      resolve({ result: 'error', statusText: response.statusText, status: response.status })
                    }
                  } else {
                    status.error('Error:' + (response.response.message || response.statusText || response.status))
                    if (globalConf.other.autoOpen) window.open($(`<div>${task.taskDes}</div>`).find('a').attr('href'), '_blank')
                    resolve({ result: 'error', statusText: response.statusText, status: response.status })
                  }
                },
                r: resolve,
                status
              })
            }))
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('verifyTasksComplete')}</font><font class="warning">${getI18n('doYourself')}<a class="hclonely-google" href="javascript:void(0)" target="_self">${getI18n('googleVerify')}</a>${getI18n('getKey')}!</font></li>` })
            $('#get_key_container').show()
            $('.hclonely-google').unbind()
            $('.hclonely-google').click(() => { $('#get_key_container')[0].scrollIntoView() })
          })
        } else {
          this.get_tasks('verify')
        }
      },
      remove: function (remove = false) {
        const pro = []
        if (remove) {
          this.updateSteamInfo(() => {
            if (this.conf.remove.group) {
              for (const group of fuc.unique(this.taskInfo.groups)) {
                pro.push(new Promise(resolve => {
                  fuc.leaveSteamGroup(resolve, group)
                }))
              }
            }
            if (this.conf.remove.curator) {
              for (const curator of fuc.unique(this.taskInfo.curators)) {
                pro.push(new Promise(resolve => {
                  fuc.unfollowCurator(resolve, curator)
                }))
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            })
          })
        } else {
          this.get_tasks('remove')
        }
      },
      get_giveawayId: function () {
        return $('#giveawaySlug').val() || window.location.href
      },
      updateSteamInfo: function (callback) {
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0) {
            if (this.taskInfo.curators.length > 0) {
              fuc.updateSteamInfo(resolve, 'all')
            } else {
              fuc.updateSteamInfo(resolve, 'community')
            }
          } else if (this.taskInfo.curators.length > 0) {
            fuc.updateSteamInfo(resolve, 'store')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) callback()
        }).catch(err => {
          console.error(err)
        })
      },
      checkLogin: function () {
        if ($('a[href*=login]').length > 0) window.open('/login', '_self')
      },
      checkLeft: function (ui) {
        if ($('h3.text-danger:contains(this giveaway is closed)').length > 0) {
          $('#link_to_click').remove()
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      groups: [], // 任务需要加的组
      curators: [], // 任务需要关注的鉴赏家
      links: [], // 需要浏览的页面链接
      taskInfo: {
        groups: [], // 所有任务需要加的组
        curators: []// 所有任务需要关注的鉴赏家
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        verify: true,
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').marvelousga && GM_getValue('conf').marvelousga.load) ? GM_getValue('conf').marvelousga : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const opiumpulses = {
      test: () => { return window.location.host.includes('opiumpulses') },
      fuck: function () { this.get_tasks('FREE') },
      get_tasks: async function (type = 'FREE') {
        const items = $(`.giveaways-page-item:contains('${type}'):not(:contains('ENTERED'))`)
        const myPoint = this.myPoints
        const maxPoint = this.maxPoint()
        for (let i = 0; i < items.length; i++) {
          const item = items[i]
          const needPoints = $(item).find('.giveaways-page-item-header-points').text().match(/[\d]+/gim)
          if (type === 'points' && needPoints && parseInt(needPoints[0]) > myPoint) {
            fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('noPoints')}</font></li>` })
          } else if (type === 'points' && !needPoints) {
            fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('getNeedPointsFailed')}</font></li>` })
          } else if (!(type === 'points' && parseInt(needPoints[0]) > maxPoint)) {
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('joinLottery')}<a href="${$(item).find('a.giveaways-page-item-img-btn-more').attr('href')}" target="_blank">${$(item).find('.giveaways-page-item-footer-name').text().trim()}</a>...<font></font></li>` })
            const a = $(item).find("a.giveaways-page-item-img-btn-enter:contains('enter')")
            if (a.attr('onclick') && a.attr('onclick').includes('checkUser')) {
              const giveawayId = a.attr('onclick').match(/[\d]+/)
              if (giveawayId) checkUser(giveawayId[0])
            }
            await new Promise(resolve => {
              fuc.httpRequest({
                url: a.attr('href'),
                method: 'GET',
                onload: response => {
                  if (debug) console.log(response)
                  if (response.responseText && /You've entered this giveaway/gim.test(response.responseText)) {
                    status.success()
                    const points = response.responseText.match(/Points:[\s]*?([\d]+)/)
                    if (type === 'points' && points) {
                      if (debug) console.log(getI18n('pointsLeft') + points[1])
                      opiumpulses.myPoints = parseInt(points[1])
                    }
                  } else {
                    status.error('Error:' + (response.status || response.statusText))
                  }
                  resolve(1)
                },
                status,
                r: resolve
              })
            }).then(data => {
              return true
            }).catch(() => {
              return false
            })
          }
        }
        fuc.echoLog({ type: 'custom', text: '<li>-----END-----</li>' })
      },
      verify: function () {
        const myPoints = $('.page-header__nav-func-user-nav-items.points-items').text().match(/[\d]+/gim)
        if (myPoints) {
          this.myPoints = myPoints
          this.get_tasks('points')
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('getPointsFailed')}</font></li>` })
        }
      },
      myPoints: 0,
      setting: {
        fuck: true,
        fuckText: 'Free',
        fuckTitle: getI18n('joinFreeLottery'),
        verify: true,
        verifyText: 'Point',
        verifyTitle: getI18n('joinPointLottery'),
        join: false,
        remove: false
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').opiumpulses && GM_getValue('conf').opiumpulses.load) ? GM_getValue('conf').opiumpulses : (GM_getValue('conf').global || defaultConf)) : defaultConf,
      maxPoint: function () {
        return this.conf['max-point'] || Infinity
      }
    }

    const prys = {
      test: () => { return window.location.host.includes('prys.revadike') },
      fuck: function () { this.get_tasks('do_task') },
      get_tasks: function (callback = 'do_task') {
        const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })
        const steps = $('#steps tbody tr')
        for (let i = 0; i < steps.length; i++) {
          if (steps.eq(i).find('span:contains(Success)').length === 0) checkClick(i)
        }
        if (callback === 'do_task') {
          const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
          if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) this.taskInfo = taskInfoHistory
          this.groups = []
          this.curators = []
          const pro = []
          for (const step of steps) {
            if ($(step).find('span:contains(Success)').length === 0) {
              if ($(step).find("a[href*='store.steampowered.com/curator/']").length > 0) {
                const link = $(step).find("a[href*='store.steampowered.com/curator/']").attr('href')
                const curatorId = link.match(/curator\/([\d]+)/)
                if (curatorId) {
                  this.curators.push(curatorId[1])
                  this.taskInfo.curators.push(curatorId[1])
                }
              } else if ($(step).find("a[href*='steampowered.com/groups/']").length > 0) {
                const link = $(step).find("a[href*='steampowered.com/groups/']").attr('href')
                const groupName = link.match(/groups\/(.+)\/?/)
                if (groupName) {
                  this.groups.push(groupName[1])
                  this.taskInfo.groups.push(groupName[1])
                }
              } else if ($(step).find("a[href*='steamcommunity.com/gid']").length > 0) {
                const link = $(step).find("a[href*='steamcommunity.com/gid']").attr('href')
            pro.push(new Promise(r => { // eslint-disable-line
                  new Promise(resolve => {
                    fuc.getFinalUrl(resolve, link)
                  }).then(data => {
                    if (data.result === 'success') {
                      const groupName = data.finalUrl.match(/groups\/(.+)\/?/)
                      if (groupName) {
                        this.groups.push(groupName[1])
                        this.taskInfo.groups.push(groupName[1])
                      }
                    }
                    r(1)
                  })
                }))
              }
            }
          }
          if (pro.length > 0) {
            Promise.all(pro).finally(() => {
              this.groups = fuc.unique(this.groups)
              this.curators = fuc.unique(this.curators)
              this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
              this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
              GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
              if (this.groups.length > 0 || this.curators.length > 0) {
                this.do_task()
              } else {
                fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
                if (this.conf.fuck.verify) this.verify()
              }
            })
          } else {
            this.groups = fuc.unique(this.groups)
            this.curators = fuc.unique(this.curators)
            this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
            this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
            GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
            if (this.groups.length > 0 || this.curators.length > 0) {
              this.do_task()
            } else {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
              if (this.conf.fuck.verify) this.verify()
            }
          }
        } else if (callback === 'verify') {
          this.tasks = []
          const checks = $('#steps tbody a[id^=check]')
          if (checks.length > 0) {
            for (const check of checks) {
              const id = $(check).attr('id').match(/[\d]+/)
              if (id) this.tasks.push({ id: id[0], taskDes: $(check).parent().prev().html().trim() })
            }
            this.verify(true)
          } else {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('prysAllTasksComplete')}</font></li>` })
          }
        } else if (callback === 'remove') {
          const taskInfo = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
          if (taskInfo && !fuc.isEmptyObjArr(taskInfo)) {
            this.taskInfo = taskInfo
            this.remove(true)
          } else {
            const pro = []
            for (const step of steps) {
              if ($(step).find("a[href*='store.steampowered.com/curator/']").length > 0) {
                const link = $(step).find("a[href*='store.steampowered.com/curator/']").attr('href')
                const curatorId = link.match(/curator\/([\d]+)/)
                if (curatorId) this.taskInfo.curators.push(curatorId[1])
              } else if ($(step).find("a[href*='steampowered.com/groups/']").length > 0) {
                const link = $(step).find("a[href*='steampowered.com/groups/']").attr('href')
                const groupName = link.match(/groups\/(.+)\/?/)
                if (groupName) this.taskInfo.groups.push(groupName[1])
              } else if ($(step).find("a[href*='steamcommunity.com/gid']").length > 0) {
                const link = $(step).find("a[href*='steamcommunity.com/gid']").attr('href')
            pro.push(new Promise(r => { // eslint-disable-line
                  new Promise(resolve => {
                    fuc.getFinalUrl(resolve, link)
                  }).then(data => {
                    if (data.result === 'success') {
                      const groupName = data.finalUrl.match(/groups\/(.+)\/?/)
                      if (groupName) {
                        this.taskInfo.groups.push(groupName[1])
                      }
                    }
                    r(1)
                  })
                }))
              }
            }
            if (pro.length > 0) {
              Promise.all(pro).finally(() => {
                this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
                this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
                GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
                if (this.taskInfo.groups.length > 0 || this.taskInfo.curators.length > 0) {
                  this.remove(true)
                } else {
                  fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('cannotRemove')}</font></li>` })
                }
              })
            } else {
              this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
              this.taskInfo.curators = fuc.unique(this.taskInfo.curators)
              GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
              if (this.taskInfo.groups.length > 0 || this.taskInfo.curators.length > 0) {
                this.remove(true)
              } else {
                fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('cannotRemove')}</font></li>` })
              }
            }
          }
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('unknown')}!</font></li>` })
        }
        status.success()
        if (debug) console.log(this)
      },
      do_task: function () {
        this.updateSteamInfo(() => {
          const pro = []
          const groups = fuc.unique(this.groups)
          const curators = fuc.unique(this.curators)
          if (this.conf.fuck.group) {
            for (const group of groups) {
              pro.push(new Promise(resolve => {
                fuc.joinSteamGroup(resolve, group)
              }))
            }
          }
          if (this.conf.fuck.curator) {
            for (const curator of curators) {
              pro.push(new Promise(resolve => {
                fuc.followCurator(resolve, curator)
              }))
            }
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            if (this.conf.fuck.verify) this.verify()
          })
        })
      },
      verify: function (verify = false) {
        if (verify) {
          const pro = []
          for (const task of fuc.unique(this.tasks)) {
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('verifyingTask')}${task.taskDes}...<font></font></li>` })
            pro.push(new Promise(resolve => {
              this.checkStep(task.id, resolve, status)
            }))
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('prysAllTasksComplete')}</font></li>` })
          })
        } else {
          this.get_tasks('verify')
        }
      },
      checkStep: function (step, r, status, captcha) {
        if (!captcha) captcha = null
        if (step !== 'captcha') {
          $('#check' + step).replaceWith('<span id="check' + step + '"><i class="fa fa-refresh fa-spin fa-fw"></i> Checking...</span>')
        }
        $.post('/api/check_step', {
          step: step,
          id: getURLParameter('id'),
          'g-recaptcha-response': captcha
        }, function (json) {
          r(1)
          if (json.success && step !== 'captcha') {
            $('#check' + step).replaceWith('<span class="text-success" id="check' + step + '"><i class="fa fa-check"></i> Success</span>')
            status.success()
          } else if (step !== 'captcha') {
            $('#check' + step).replaceWith('<a id="check' + step + '" href="javascript:checkStep(' + step + ')"><i class="fa fa-question"></i> Check</a>')
            status.error((json.response ? json.response.error ? json.response.error : 'Error' : 'Error'))
          }
          if (json.response) {
            if (json.response.captcha && json.success) {
              showAlert('info', json.response.captcha)
              captchaCheck()
            } else if (json.response.captcha) {
              showAlert('warning', json.response.captcha)
              captchaCheck()
            }
            if (json.response.prize) {
              showAlert('success', 'Here is your prize:<h1 role="button" align="middle" style="word-wrap: break-word;">' + json.response.prize + '</h2>')
            }
          }
        }).fail(function () {
          r(1)
          $('#check' + step).replaceWith('<a id="check' + step + '" href="javascript:checkStep(' + step + ')"><i class="fa fa-question"></i> Check</a>')
          status.error('Error:0')
        })
      },
      remove: function (remove = false) {
        const pro = []
        if (remove) {
          this.updateSteamInfo(() => {
            if (this.conf.remove.group) {
              for (const group of fuc.unique(this.taskInfo.groups)) {
                pro.push(new Promise(resolve => {
                  fuc.leaveSteamGroup(resolve, group)
                }))
              }
            }
            if (this.conf.remove.curator) {
              for (const curator of fuc.unique(this.taskInfo.curators)) {
                pro.push(new Promise(resolve => {
                  fuc.unfollowCurator(resolve, curator)
                }))
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            })
          })
        } else {
          this.get_tasks('remove')
        }
      },
      get_giveawayId: function () {
        const id = window.location.search.match(/id=([\d]+)/)
        return id ? id[1] : window.location.href
      },
      updateSteamInfo: function (callback) {
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0) {
            if (this.taskInfo.curators.length > 0) {
              fuc.updateSteamInfo(resolve, 'all')
            } else {
              fuc.updateSteamInfo(resolve, 'community')
            }
          } else if (this.taskInfo.curators.length > 0) {
            fuc.updateSteamInfo(resolve, 'store')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) callback()
        }).catch(err => {
          console.error(err)
        })
      },
      checkLeft: function (ui) {
        const left = $('#header').text().match(/([\d]+).*?prize.*?left/)
        if (!(left.length > 0 && left[1] !== '0')) {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      groups: [], // 任务需要加的组
      curators: [], // 任务需要关注的鉴赏家
      taskInfo: {
        groups: [], // 所有任务需要加的组
        curators: []// 所有任务需要关注的鉴赏家
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        verify: true,
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').prys && GM_getValue('conf').prys.load) ? GM_getValue('conf').prys : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const spoune = {
      test: () => { return window.location.host.includes('spoune') },
      fuck: function () { this.get_tasks() },
      get_tasks: function () {
        const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })
        const giveawayTasks = $('#GiveawayTasks button')
        for (const task of giveawayTasks) {
          const taskClick = $(task).attr('onclick')
          if (taskClick) {
            const taskId = taskClick.match(/loadTask\(([\d]+)/)
            if (taskId) {
              this.tasks.push({ id: taskId[1], text: $(task).text() })
            } else {
              fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('getTaskIdFailed', $(task).text())}</font></li>` })
            }
          } else {
            fuc.echoLog({ type: 'custom', text: `<li><font class="error">${getI18n('getTaskIdFailed', $(task).text())}</font></li>` })
          }
        }
        status.warning('Complete')
        if (this.tasks.length > 0) {
          this.verify()
        } else {
          fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('noAutoFinish')}</font></li>` })
        }
      },
      verify: async function ({ arr, i, end }) {
        const tasks = fuc.unique(this.tasks)
        for (let i = 0; i < tasks.length; i++) {
          const task = tasks[i]
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('doing')}${task.text}...<font></font></li>` })
          await new Promise(resolve => {
            fuc.httpRequest({
              url: `/controller.php?taskDetail=${task.id}&show`,
              method: 'get',
              onload: response => {
                if (debug) console.log(response)
                if (response.status === 200) {
                  const src = response.responseText.match(/src="\.([\w\W]*?)">/)
                  if (src) {
                    fuc.httpRequest({
                      url: src[1],
                      method: 'get',
                      onload: response => {
                        if (debug) console.log(response)
                        if (response.status === 200) {
                          const href = response.responseText.match(/href="\.(\/verify[\w\W]*?)"/) || response.responseText.match(/href="\.(\/steamgroup[\w\W]*?)"/)
                          if (href) {
                            fuc.httpRequest({
                              url: '/werbung' + href[1],
                              method: 'get',
                              onload: response => {
                                if (debug) console.log(response)
                                if (response.status === 200 && /Task.*completed/gim.test(response.responseText)) {
                                  status.success()
                                  resolve()
                                } else {
                                  const href = response.responseText.match(/href="\.(\/verify[\w\W]*?)"/) || response.responseText.match(/href="\.(\/steamgroup[\w\W]*?)"/)
                                  if (href) {
                                    fuc.httpRequest({
                                      url: '/werbung' + href[1],
                                      method: 'get',
                                      onload: response => {
                                        if (debug) console.log(response)
                                        if (response.status === 200 && /Task.*completed/gim.test(response.responseText)) {
                                          status.success()
                                        } else {
                                          status.error('Error:' + (response.statusText || response.status))
                                        }
                                        resolve()
                                      },
                                      r: resolve,
                                      status
                                    })
                                  } else {
                                    status.error('Error:' + (response.statusText || response.status))
                                    resolve()
                                  }
                                }
                              },
                              r: resolve,
                              status
                            })
                          } else {
                            status.error('Error:' + getI18n('getUrlFailed', '2'))
                            resolve()
                          }
                        } else {
                          status.error('Error:' + (response.statusText || response.status))
                          resolve()
                        }
                      },
                      r: resolve,
                      status
                    })
                  } else {
                    status.error('Error:' + getI18n('getUrlFailed', '1'))
                    resolve()
                  }
                } else {
                  status.error('Error:' + (response.statusText || response.status))
                  resolve()
                }
              },
              r: resolve,
              status
            })
          }).then(() => {
            return true
          }).catch(() => {
            return false
          })
        }
        fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font>,<font class="warning">${getI18n('finishSelf')}</font></li>` })
      },
      checkLeft: function (ui) {
        const checkLeft = setInterval(() => {
          if ($('#keysAvailable').length > 0) {
            clearInterval(checkLeft)
            if ($('#keysAvailable').text() === '0') {
              ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
                confirmButtonText: getI18n('confirm'),
                cancelButtonText: getI18n('cancel'),
                type: 'warning',
                center: true
              }).then(() => {
                window.close()
              })
            }
          }
        }, 500)
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        verify: false,
        join: false,
        remove: false
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').spoune && GM_getValue('conf').spoune.load) ? GM_getValue('conf').spoune : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const takekey = {
      test: () => { return window.location.host.includes('takekey') },
      fuck: function () { this.get_tasks('do_task') },
      get_tasks: function (callback = 'do_task') {
        const taskInfoHistory = GM_getValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']')
        if (taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) this.taskInfo = taskInfoHistory
        if (callback === 'remove' && taskInfoHistory && !fuc.isEmptyObjArr(taskInfoHistory)) {
          this.remove(true)
        } else {
          this.tasks = []
          this.groups = []
          // this.curators=[];
          this.links = []
          const pro = []
          const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('getTasksInfo')}<font></font></li>` })

          const tasksContainer = $('#usl>div')
          for (const task of tasksContainer) { // 遍历任务信息
            this.tasks.push(task)
            const icon = $(task).find('i')
            const link = $(task).children('a[id]').attr('href')
            const id = $(task).children('a[id]').attr('id')
            if (icon.hasClass('fa-steam')) {
              if (link && /gid\/[\d]+/.test(link)) {
            pro.push(new Promise(r => { // eslint-disable-line
                  new Promise(resolve => {
                    fuc.getFinalUrl(resolve, link)
                  }).then(data => {
                    if (data.result === 'success') {
                      const groupName = data.finalUrl.match(/steamcommunity.com\/groups\/([\w\d\-_]*)/)[1]
                      if (groupName) {
                        this.groups.push(groupName)
                        this.taskInfo.groups.push(groupName)
                        r(1)
                      } else {
                        r(0)
                      }
                    } else {
                      r(0)
                    }
                  }).catch(() => {
                    r(0)
                  })
                }))
              }
            } else if (icon.hasClass('fa-link')) {
              this.links.push(id)
            } else if (icon.hasClass('fa-vk')) {
              this.vks.push(link)
            } else {
              this.others.push(icon)
            }
          }
          Promise.all(pro).finally(() => {
            this.groups = fuc.unique(this.groups)
            // this.curators=fuc.unique(this.curators);
            this.links = fuc.unique(this.links)
            this.others = fuc.unique(this.others)
            this.taskInfo.groups = fuc.unique(this.taskInfo.groups)
            // this.taskInfo.curators=fuc.unique(this.taskInfo.curators);
            this.tasks = fuc.unique(this.tasks)
            GM_setValue('taskInfo[' + window.location.host + this.get_giveawayId() + ']', this.taskInfo)
            status.success()
            if (debug) console.log(this)
            if (callback === 'do_task') {
              if (this.tasks.length === 0) {
                fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
                if (this.conf.fuck.verify) this.verify()
              } else {
                this.do_task()
              }
            } else {
              !fuc.isEmptyObjArr(this.taskInfo) ? this.remove(true) : fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('cannotRemove')}</font></li>` })
            }
          })
        }
      },
      do_task: function () {
        this.updateSteamInfo(() => {
          const pro = []
          const groups = fuc.unique(this.groups)
          // let curators = fuc.unique(this.curators);
          const links = fuc.unique(this.links)
          const others = fuc.unique(this.others)
          const vks = fuc.unique(this.vks)
          if (this.conf.fuck.group) {
            for (const group of groups) {
              pro.push(new Promise(resolve => {
                fuc.joinSteamGroup(resolve, group)
              }))
            }
          }
          if (this.conf.fuck.visit) {
            for (const link of links) {
              const a = $(`a[id='${link}']`).attr('onclick', 'return false;')
              a[0].click()
              a.removeAttr('onclick')
              pro.push(new Promise(resolve => {
                fuc.visitLink(resolve, $(`a[id='${link}']`).attr('href'))
              }))
            }
          }
          if (globalConf.other.autoOpen) {
            for (const vk of vks) {
              window.open(vk, '_blank')
            }
          }
          for (const other of others) {
            fuc.echoLog({ type: 'custom', text: `<li><font class="warning">${getI18n('unknowntype')}:${$(other).attr('class')}</font></li>` })
          }
          Promise.all(pro).finally(() => {
            fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            if (this.conf.fuck.verify) this.verify()
          })
        })
      },
      verify: function () {
        setTimeout(() => { $('.fa-check').click() }, 1000)
      },
      remove: function (remove = false) {
        const pro = []
        if (remove) {
          this.updateSteamInfo(() => {
            if (this.conf.remove.group) {
              for (const group of fuc.unique(this.taskInfo.groups)) {
                pro.push(new Promise(resolve => {
                  fuc.leaveSteamGroup(resolve, group)
                }))
              }
            }
            Promise.all(pro).finally(() => {
              fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('allTasksComplete')}</font></li>` })
            })
          })
        } else {
          this.get_tasks('remove')
        }
      },
      get_giveawayId: function () {
        const id = window.location.href.match(/distribution\/([\d]+)/)
        return id ? id[1] : window.location.href
      },
      updateSteamInfo: function (callback) {
        new Promise(resolve => {
          if (this.taskInfo.groups.length > 0) {
            if (this.taskInfo.curators.length > 0) {
              fuc.updateSteamInfo(resolve, 'all')
            } else {
              fuc.updateSteamInfo(resolve, 'community')
            }
          } else if (this.taskInfo.curators.length > 0) {
            fuc.updateSteamInfo(resolve, 'store')
          } else {
            resolve(1)
          }
        }).then(s => {
          if (s === 1) callback()
        }).catch(err => {
          console.error(err)
        })
      },
      checkLogin: function () {
        if ($('i.fa-sign-in').length > 0) window.open('/auth/steam', '_self')
      },
      checkLeft: function (ui) {
        const leftKey = $('span:contains(Осталось ключей),span:contains(Keys Left)').text().match(/[\d]+/)
        if (!(leftKey && parseInt(leftKey[0]) > 0)) {
          ui.$confirm(getI18n('noKeysLeft'), getI18n('notice'), {
            confirmButtonText: getI18n('confirm'),
            cancelButtonText: getI18n('cancel'),
            type: 'warning',
            center: true
          }).then(() => {
            window.close()
          })
        }
      },
      groups: [], // 任务需要加的组
      curators: [], // 任务需要关注的鉴赏家
      links: [], // 需要浏览的页面链接
      others: [],
      vks: [],
      taskInfo: {
        groups: [], // 所有任务需要加的组
        curators: []// 所有任务需要关注的鉴赏家
      },
      tasks: [], // 任务信息
      setting: {
        fuck: true,
        verify: true,
        join: false,
        remove: true
      },
      conf: GM_getValue('conf') ? ((GM_getValue('conf').takekey && GM_getValue('conf').takekey.load) ? GM_getValue('conf').takekey : (GM_getValue('conf').global || defaultConf)) : defaultConf
    }

    const loadSetting = function () {
      const eNameToNameJoin = {
        group: getI18n('group'),
        curator: getI18n('curator'),
        developer: getI18n('developer'),
        publisher: getI18n('publisher'),
        announcement: getI18n('announcement'),
        wishlist: getI18n('wishlist'),
        followGame: getI18n('fGame'),
        visit: getI18n('visit'),
        verify: getI18n('verify'),
        autoLogin: getI18n('autoLogin'),
        doTask: getI18n('doTask')
      }
      const eNameToNameRemove = {
        group: getI18n('ungroup'),
        curator: getI18n('uncurator'),
        developer: getI18n('undeveloper'),
        publisher: getI18n('unpublisher'),
        wishlist: getI18n('unwishlist'),
        unfollowGame: getI18n('unfGame')
      }
      const eNameToNameOther = {
        showLogs: getI18n('showLogs'),
        showDetails: getI18n('showDetails'),
        checkLogin: getI18n('checkLogin'),
        checkLeft: getI18n('checkLeft'),
        autoOpen: getI18n('autoOpen'),
        autoCheckUpdate: getI18n('checkUpdate'),
        reCaptcha: getI18n('reCaptcha')
      }
      const Options = {
        fuckOptions: [
          { name: getI18n('group'), eName: 'group', des: 'Join XXX steam group' },
          { name: getI18n('curator'), eName: 'curator', des: 'Follow XXX curator' },
          { name: getI18n('developer'), eName: 'developer', des: 'Follow XXX developer' },
          { name: getI18n('publisher'), eName: 'publisher', des: 'Follow XXX publisher' },
          { name: getI18n('announcement'), eName: 'announcement', des: 'Like Steam announcement' },
          { name: getI18n('wishlist'), eName: 'wishlist', des: 'Add XXX to your wishlist' },
          { name: getI18n('fGame'), eName: 'followGame', des: 'Click "Follow" button' },
          { name: getI18n('visit'), eName: 'visit', des: 'Visit XXX page' },
          { name: getI18n('verify'), eName: 'verify', des: getI18n('verify') },
          { name: getI18n('autoLogin'), eName: 'autoLogin', des: getI18n('autoLoginDes') },
          { name: getI18n('doTask'), eName: 'doTask', des: getI18n('doTaskDes') }
        ],
        joinOptions: [
          { name: getI18n('group'), eName: 'group', des: 'Join XXX steam group' },
          { name: getI18n('curator'), eName: 'curator', des: 'Follow XXX curator' },
          { name: getI18n('developer'), eName: 'developer', des: 'Follow XXX developer' },
          { name: getI18n('publisher'), eName: 'publisher', des: 'Follow XXX publisher' },
          { name: getI18n('announcement'), eName: 'announcement', des: 'Like Steam announcement' },
          { name: getI18n('wishlist'), eName: 'wishlist', des: 'Add XXX to your wishlist' },
          { name: getI18n('fGame'), eName: 'followGame', des: 'Click "Follow" button' },
          { name: getI18n('visit'), eName: 'visit', des: 'Visit XXX page' }
        ],
        removeOptions: [
          { name: getI18n('ungroup'), eName: 'group', des: getI18n('ungroupDes') },
          { name: getI18n('uncurator'), eName: 'curator', des: getI18n('uncuratorDes') },
          { name: getI18n('undeveloper'), eName: 'developer', des: getI18n('undeveloperDes') },
          { name: getI18n('unpublisher'), eName: 'publisher', des: getI18n('unpublisherDes') },
          { name: getI18n('unwishlist'), eName: 'wishlist', des: getI18n('unwishlistDes') },
          { name: getI18n('unfGame'), eName: 'unfollowGame', des: getI18n('unfGameDes') }
        ],
        otherOptions: [
          { name: getI18n('checkLogin'), eName: 'checkLogin', des: getI18n('checkLoginDes') },
          { name: getI18n('checkLeft'), eName: 'checkLeft', des: getI18n('checkLeftDes') },
          { name: getI18n('autoOpen'), eName: 'autoOpen', des: getI18n('autoOpenDes') },
          { name: getI18n('showLogs'), eName: 'showLogs', des: getI18n('showLogsDes') },
          { name: getI18n('showDetails'), eName: 'showDetails', des: getI18n('showDetailsDes') },
          { name: getI18n('autoCheckUpdate'), eName: 'checkUpdate', des: getI18n('autoCheckUpdate') },
          { name: getI18n('reCaptcha'), eName: 'reCaptcha', des: getI18n('reCaptchaDes') }
        ],
        checkedFucks: [getI18n('group'), getI18n('curator'), getI18n('developer'), getI18n('publisher'), getI18n('announcement'), getI18n('wishlist'), getI18n('fGame'), getI18n('visit'), getI18n('verify'), getI18n('autoLogin'), getI18n('doTask')],
        checkedJoins: [getI18n('group'), getI18n('curator'), getI18n('developer'), getI18n('publisher'), getI18n('announcement'), getI18n('wishlist'), getI18n('fGame'), getI18n('visit')],
        checkedRemoves: [getI18n('ungroup'), getI18n('uncurator'), getI18n('undeveloper'), getI18n('unpublisher'), getI18n('unwishlist'), getI18n('unfGame')],
        checkedOthers: [getI18n('checkLogin'), getI18n('checkLeft'), getI18n('autoOpen'), getI18n('showLogs'), getI18n('showDetails'), getI18n('autoCheckUpdate'), getI18n('reCaptcha')]
      }
      function getOptions (type, options) {
        const opt = []
        const defaultOpt = Options[type]
        options.map(function (e, i) {
          opt.push(defaultOpt[e])
        })
        return opt
      }

      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').global) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').global.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 1, 2, 3, 4, 5, 6, 7, 8, 10])

        const joinOptions = getOptions('joinOptions', [0, 1, 2, 3, 4, 5, 6, 7])
        const checkedJoins = (GM_getValue('conf') && GM_getValue('conf').global) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').global.join)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedJoins', [0, 1, 2, 3, 4, 5, 6, 7])

        const removeOptions = getOptions('removeOptions', [0, 1, 2, 3, 4, 5])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').global) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').global.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0, 1, 2, 3, 4, 5])

        const otherOptions = getOptions('otherOptions', [0, 1, 2, 3, 4, 5, 6])
        const checkedOthers = (GM_getValue('conf') && GM_getValue('conf').global) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').global.other)) {
            conf.push(eNameToNameOther[eName])
          }
          return conf
        })() : getOptions('checkedOthers', [0, 1, 3])

        new Vue({ // eslint-disable-line no-new
          el: '#global',
          data: {
            header: getI18n('globalSettings'),
            fuck: {
              checkAll: fuckOptions.length === checkedFucks.length,
              checkedFucks: checkedFucks,
              fucks: fuckOptions,
              isIndeterminate: fuckOptions.length !== checkedFucks.length
            },
            join: {
              checkAll: joinOptions.length === checkedJoins.length,
              checkedJoins: checkedJoins,
              joins: joinOptions,
              isIndeterminate: joinOptions.length !== checkedJoins.length
            },
            remove: {
              checkAll: removeOptions.length === checkedRemoves.length,
              checkedRemoves: checkedRemoves,
              removes: removeOptions,
              isIndeterminate: removeOptions.length !== checkedRemoves.length
            },
            other: {
              checkAll: otherOptions.length === checkedOthers.length,
              checkedOthers: checkedOthers,
              others: otherOptions,
              isIndeterminate: otherOptions.length !== checkedOthers.length
            },
            openDelay: 100,
            rowType: 'flex',
            rowAlign: 'middle',
            verify: '1'
          },
          methods: {
            fuckHandleCheckAllChange (val) {
              this.fuck.checkedFucks = val ? fuckOptions.map(e => e.name) : []
              this.fuck.isIndeterminate = false
            },
            handleCheckedFucksChange (value) {
              const checkedCount = value.length
              this.fuck.checkAll = checkedCount === this.fuck.fucks.length
              this.fuck.isIndeterminate = checkedCount > 0 && checkedCount < this.fuck.fucks.length
            },
            joinHandleCheckAllChange (val) {
              this.join.checkedJoins = val ? joinOptions.map(e => e.name) : []
              this.join.isIndeterminate = false
            },
            handleCheckedJoinsChange (value) {
              const checkedCount = value.length
              this.join.checkAll = checkedCount === this.join.joins.length
              this.join.isIndeterminate = checkedCount > 0 && checkedCount < this.join.joins.length
            },
            removeHandleCheckAllChange (val) {
              this.remove.checkedRemoves = val ? removeOptions.map(e => e.name) : []
              this.remove.isIndeterminate = false
            },
            handleCheckedRemovesChange (value) {
              const checkedCount = value.length
              this.remove.checkAll = checkedCount === this.remove.removes.length
              this.remove.isIndeterminate = checkedCount > 0 && checkedCount < this.remove.removes.length
            },
            otherHandleCheckAllChange (val) {
              this.other.checkedOthers = val ? otherOptions.map(e => e.name) : []
              this.other.isIndeterminate = false
            },
            handleCheckedOthersChange (value) {
              const checkedCount = value.length
              this.other.checkAll = checkedCount === this.other.others.length
              this.other.isIndeterminate = checkedCount > 0 && checkedCount < this.other.others.length
            }
          }
        })
      })();
      (function () {
        const joinOptions = getOptions('joinOptions', [0, 1, 2, 3, 4, 5, 6])
        const checkedJoins = (GM_getValue('conf') && GM_getValue('conf').giveawaysu) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').giveawaysu.join)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedJoins', [0, 1, 2, 3, 4, 5, 6])

        const removeOptions = getOptions('removeOptions', [0, 1, 2, 3, 4, 5])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').giveawaysu) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').giveawaysu.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0, 1, 2, 3, 4, 5])

        new Vue({ // eslint-disable-line no-new
          el: '#giveawaysu',
          data: {
            header: 'giveaway.su' + getI18n('websiteSetting'),
            checked: GM_getValue('conf') ? GM_getValue('conf').giveawaysu ? !!GM_getValue('conf').giveawaysu.load : false : false,
            remove: {
              checkAll: removeOptions.length === checkedRemoves.length,
              checkedRemoves: checkedRemoves,
              removes: removeOptions,
              isIndeterminate: removeOptions.length !== checkedRemoves.length
            },
            join: {
              checkAll: joinOptions.length === checkedJoins.length,
              checkedJoins: checkedJoins,
              joins: joinOptions,
              isIndeterminate: joinOptions.length !== checkedJoins.length
            },
            openDelay: 100,
            rowType: 'flex',
            rowAlign: 'middle',
            verify: '1'
          },
          methods: {
            removeHandleCheckAllChange (val) {
              this.remove.checkedRemoves = val ? removeOptions.map(e => e.name) : []
              this.remove.isIndeterminate = false
            },
            handleCheckedRemovesChange (value) {
              const checkedCount = value.length
              this.remove.checkAll = checkedCount === this.remove.removes.length
              this.remove.isIndeterminate = checkedCount > 0 && checkedCount < this.remove.removes.length
            },
            joinHandleCheckAllChange (val) {
              this.join.checkedJoins = val ? joinOptions.map(e => e.name) : []
              this.join.isIndeterminate = false
            },
            handleCheckedJoinsChange (value) {
              const checkedCount = value.length
              this.join.checkAll = checkedCount === this.join.joins.length
              this.join.isIndeterminate = checkedCount > 0 && checkedCount < this.join.joins.length
            }
          }
        })
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 1, 2, 3, 5, 6, 7, 8])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').marvelousga) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').marvelousga.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 1, 2, 3, 5, 6, 7, 8])

        const removeOptions = getOptions('removeOptions', [0, 1, 2, 3, 4, 5])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').marvelousga) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').marvelousga.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0, 1, 2, 3, 4, 5])

        fuc.creatSetting('marvelousga', 'marvelousGA & dupedornot', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 1, 2, 3, 5, 6, 7, 8])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').banana) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').banana.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 1, 2, 3, 5, 6, 7, 8])

        const removeOptions = getOptions('removeOptions', [0, 1, 2, 3, 4, 5])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').banana) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').banana.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0, 1, 2, 3, 4, 5])

        fuc.creatSetting('banana', 'grabfreegame & bananagiveaway', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();

      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 7, 8])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').gamehag) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').gamehag.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 7, 8])

        const removeOptions = getOptions('removeOptions', [0])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').gamehag) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').gamehag.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0])

        fuc.creatSetting('gamehag', 'gamehag', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 1, 8])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').prys) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').prys.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 1, 8])

        const removeOptions = getOptions('removeOptions', [0, 1])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').prys) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').prys.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0, 1])

        fuc.creatSetting('prys', 'prys', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 1, 5, 6, 7])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').givekey) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').givekey.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 1, 5, 6, 7])

        const removeOptions = getOptions('removeOptions', [0, 1, 4, 5])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').givekey) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').givekey.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0, 1, 4, 5])

        fuc.creatSetting('givekey', 'givekey.ru', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 7])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').takekey) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').takekey.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 7])

        const removeOptions = getOptions('removeOptions', [0])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').takekey) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').takekey.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0])

        fuc.creatSetting('takekey', 'takekey.ru', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [0, 7, 8])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').gleam) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').gleam.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [0, 7, 8])

        const removeOptions = getOptions('removeOptions', [0])
        const checkedRemoves = (GM_getValue('conf') && GM_getValue('conf').gleam) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').gleam.remove)) {
            conf.push(eNameToNameRemove[eName])
          }
          return conf
        })() : getOptions('checkedRemoves', [0])

        fuc.creatSetting('gleam', 'gleam.io', fuckOptions, checkedFucks, removeOptions, checkedRemoves)
      })();
      (function () {
        const fuckOptions = getOptions('fuckOptions', [9, 10])
        const checkedFucks = (GM_getValue('conf') && GM_getValue('conf').freegamelottery) ? (() => {
          const conf = []
          for (const eName of Object.keys(GM_getValue('conf').freegamelottery.fuck)) {
            conf.push(eNameToNameJoin[eName])
          }
          return conf
        })() : getOptions('checkedFucks', [10])

        new Vue({ // eslint-disable-line no-new
          el: '#freegamelottery',
          data: {
            header: 'freegamelottery' + getI18n('websiteSetting'),
            checked: GM_getValue('conf') ? GM_getValue('conf').freegamelottery ? !!GM_getValue('conf').freegamelottery.load : false : false,
            fuck: {
              checkAll: fuckOptions.length === checkedFucks.length,
              checkedFucks: checkedFucks,
              fucks: fuckOptions,
              isIndeterminate: fuckOptions.length !== checkedFucks.length
            },
            openDelay: 100,
            rowType: 'flex',
            rowAlign: 'middle',
            verify: '1'
          },
          methods: {
            fuckHandleCheckAllChange (val) {
              this.fuck.checkedFucks = val ? fuckOptions.map(e => e.name) : []
              this.fuck.isIndeterminate = false
            },
            handleCheckedFucksChange (value) {
              const checkedCount = value.length
              this.fuck.checkAll = checkedCount === this.fuck.fucks.length
              this.fuck.isIndeterminate = checkedCount > 0 && checkedCount < this.fuck.fucks.length
            }
          }
        })
      })();

      (function () {
        new Vue({ // eslint-disable-line no-new
          el: '#save',
          data: {
            title: getI18n('saveSetting')
          },
          methods: {
            save () {
              const conf = fuc.creatConf()
              GM_setValue('conf', conf)
              this.$notify({
                title: getI18n('saveSuccess'),
                type: 'success'
              })
            }
          }
        })
        new Vue({ // eslint-disable-line no-new
          el: '#reset',
          data: {
            title: getI18n('resetSetting')
          },
          methods: {
            reset () {
              this.$confirm(getI18n('resetSettingNotice'), getI18n('notice'), {
                confirmButtonText: getI18n('confirm'),
                cancelButtonText: getI18n('cancel'),
                type: 'warning'
              }).then(() => {
                GM_deleteValue('conf')
                if (!GM_getValue('conf')) {
                  vueUi.$message({
                    type: 'success',
                    message: getI18n('resetSettingSuccess')
                  })
                } else {
                  vueUi.$message({
                    type: 'error',
                    message: getI18n('resetSettingFailed')
                  })
                }
              }).catch(() => {
                vueUi.$message({
                  type: 'info',
                  message: getI18n('resetSettingCancel')
                })
              })
            }
          }
        })
        new Vue({ // eslint-disable-line no-new
          el: '#download',
          data: {
            title: getI18n('downloadSetting')
          },
          methods: {
            download () {
              const msg = vueUi.$message({
                type: 'info',
                message: getI18n('processSetting')
              })
              const conf = fuc.creatConf()
              const creatFile = new FileReader()
              creatFile.onload = () => {
                $(`<a href="${creatFile.result}" download="auto-task.conf.json" target="_self"></a>`)[0].click()
              }
              creatFile.onerror = (e) => {
                if (debug) console.log(e)
                msg.close()
                vueUi.$message({
                  type: 'error',
                  message: getI18n('creatUrlFailed')
                })
              }
              creatFile.readAsDataURL(new File([JSON.stringify(conf, null, 4)], 'setting.conf.txt'))
            }
          }
        })
        new Vue({ // eslint-disable-line no-new
          el: '#upload2',
          data: {
            title: getI18n('loadSetting'),
            multiple: false,
            sfl: false,
            accept: 'json',
            httpRequest: () => { }
          },
          methods: {
            upload (file) {
              const msg = vueUi.$message({
                type: 'info',
                message: getI18n('readSetting')
              })
              if (window.FileReader) {
                const reader = new FileReader()
                reader.onload = () => {
                  if (debug) console.log(reader.result)
                  msg.close()
                  const cMsg = vueUi.$message({
                    type: 'success',
                    message: getI18n('readSettingComplete')
                  })
                  try {
                    GM_setValue('conf', JSON.parse(reader.result))
                    cMsg.close()
                    vueUi.$message({
                      type: 'success',
                      message: getI18n('loadSettingComplete')
                    })
                    window.location.reload()
                  } catch (e) {
                    cMsg.close()
                    vueUi.$message({
                      type: 'error',
                      message: `${getI18n('loadSettingFailed')}!`
                    })
                    if (debug) console.log(`${getI18n('loadSettingFailed')}: `, e)
                  }
                }
                reader.onerror = (e) => {
                  if (debug) console.log(e)
                  msg.close()
                  vueUi.$message({
                    type: 'error',
                    message: getI18n('readSettingFailed')
                  })
                }
                reader.readAsText(file)
              } else {
                msg.close()
                vueUi.$message({
                  type: 'warning',
                  duration: 5000,
                  message: getI18n('notSupport')
                })
                this.$msgbox({
                  title: getI18n('copySetting'),
                  type: 'info',
                  showClose: false,
                  showCancelButton: true,
                  confirmButtonText: getI18n('confirm'),
                  cancelButtonText: getI18n('cancel'),
                  closeOnClickModal: false,
                  closeOnPressEscape: false,
                  closeOnHashChange: false,
                  center: true,
                  showInput: true,
                  inputType: 'textarea'
                })
                  .then(({ value }) => {
                    if (debug) console.log(value)
                    const cMsg = vueUi.$message({
                      type: 'info',
                      message: getI18n('loadSettingText')
                    })
                    try {
                      GM_setValue('conf', JSON.parse(value))
                      cMsg.close()
                      vueUi.$message({
                        type: 'success',
                        message: getI18n('loadSettingComplete')
                      })
                      window.location.reload()
                    } catch (e) {
                      cMsg.close()
                      vueUi.$message({
                        type: 'error',
                        message: `${getI18n('loadSettingFailed')}!`
                      })
                      if (debug) console.log(`${getI18n('loadSettingFailed')}: `, e)
                    }
                  })
                  .catch(action => {
                    vueUi.$message({
                      type: 'info',
                      message: getI18n('cancelled')
                    })
                  })
              }
              this.$refs.upload.abort(file.name)
            }
          }
        })
      })();
      (function () {
        const maxPoint = GM_getValue('conf') ? GM_getValue('conf').opiumpulses ? (GM_getValue('conf').opiumpulses['max-point'] || 0) : 0 : 0

        new Vue({ // eslint-disable-line no-new
          el: '#opiumpulses',
          data: {
            header: 'opiumpulses' + getI18n('websiteSetting'),
            checked: GM_getValue('conf') ? GM_getValue('conf').opiumpulses ? !!GM_getValue('conf').opiumpulses.load : false : false,
            maxPoint: maxPoint,
            openDelay: 100,
            rowType: 'flex',
            rowAlign: 'middle',
            verify: '1'
          }
        })
      })()
    }

    const loadAnnouncement = function () {
      new Promise(resolve => {
        fuc.httpRequest({
          url: 'https://userjs.hclonely.com/announcement.json',
          method: 'get',
          dataType: 'json',
          onload: response => {
            if (debug) console.log(response)
            if (response.status === 200 && response.response) {
              resolve({ result: 'success', data: response.response })
            } else {
              resolve({ result: 'error', data: response })
            }
          },
          r: resolve
        })
      }).then(data => {
        if (data.result === 'success') {
          const announcements = data.data
          announcements.map(e => {
            e.time = fuc.dateFormat('YYYY-mm-dd HH:MM', new Date(e.time))
            return e
          })
          new Vue({ // eslint-disable-line no-new
            el: '#app',
            data: { announcements }
          })
        } else {
          vueUi.$message({ type: 'error', duration: 0, message: `${getI18n('loadAnnouncementFailed')}${data.statusText || getI18n('checkConsole')}!`, showClose: true })
          console.error(data)
        }
      }).catch(error => {
        vueUi.$message({ type: 'error', duration: 0, message: `${getI18n('loadAnnouncementFailed') + getI18n('checkConsole')}`, showClose: true })
        console.error(error)
      })
    }

    const plugins = [banana, freegamelottery, gamehag, giveawaysu, givekey, gleam, indiedb, marvelousga, opiumpulses, prys, spoune, takekey]

    if (window.location.host.includes('hclonely')) {
      if (window.location.pathname.includes('setting')) {
        fuc.addBackground()
        loadSetting()
      } else if (window.location.pathname.includes('announcement')) {
        fuc.addBackground()
        loadAnnouncement()
      }
    } else if ((window.location.host.includes('marvelousga') || window.location.host.includes('dupedornot') || window.location.host.includes('gamecode.win')) && (!window.location.pathname.includes('giveaway'))) {
      fuc.newTabBlock()
    } else {
      let website = {}
      plugins.map((e, i) => {
        if (e.test()) {
          website = e
          if (website.before) website.before(website)
        }
      })

      if (globalConf.other.checkLogin && website.checkLogin) website.checkLogin()
      if (globalConf.other.checkLeft && website.checkLeft) website.checkLeft(vueUi)

      $('body').append(`
<div id="fuck-task-app">
  <div v-cloak id="fuck-task-btn">
  <el-button :style="style" @click="toggleThisDiv" :icon="icon" :title="title" :show="show"></el-button>
    <el-button type="primary" v-for="item in buttons" v-if="item.show" @click="item.click" :id="item.id" :title="item.title">{{item.text}}</el-button>
    <el-button type="primary" @click="toggle" :id="drawerBtn.id" :title="drawerBtn.title">{{drawerBtn.text}}</el-button>
  </div>
  <div id="fuck-task-info"></div>
</div>
`)
      const showLogs = globalConf.other ? globalConf.other.showLogs : defaultConf.other.showLogs

      let btnNum = 1
      for (const boolean of Object.values(website.setting)) {
        if (boolean === true) btnNum++
      }

      const btnArea = new Vue({
        el: '#fuck-task-btn',
        data: {
          icon: 'el-icon-arrow-right',
          title: getI18n('hide'),
          show: true,
          style: `position:absolute;left:-20px;width:20px;border:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;padding:0;height:${btnNum * 40}px;opacity:80%;`,
          buttons: [
            {
              id: 'fuck-task',
              text: website.setting.fuckText || 'FuckTask',
              title: website.setting.fuckTitle || getI18n('fuckBtnTitle'),
              show: website.setting.fuck,
              click: () => { website.fuck(btnArea) }
            },
            {
              id: 'verify-task',
              text: website.setting.verifyText || 'Verify',
              title: website.setting.verifyTitle || getI18n('verifyBtnTitle'),
              show: website.setting.verify,
              click: () => { website.verify() }
            },
            {
              id: 'join-task',
              text: website.setting.joinText || 'Join',
              title: website.setting.joinDes || getI18n('joinBtnTitle'),
              show: website.setting.join,
              click: () => { website.join() }
            },
            {
              id: 'remove-task',
              text: website.setting.removeText || 'Remove',
              title: website.setting.removeTitle || getI18n('removeBtnTitle'),
              show: website.setting.remove,
              click: () => { website.remove() }
            }
          ],
          drawerBtn: {
            id: 'show-logs',
            text: !showLogs ? 'ShowLogs' : 'HideLogs',
            title: !showLogs ? getI18n('showLog') : getI18n('hideLog'),
            show: !!showLogs
          }
        },
        methods: {
          toggleThisDiv () {
            if (this.show) {
              this.icon = 'el-icon-arrow-left'
              this.title = getI18n('show')
              $('#fuck-task-btn').animate({ width: '0' })
            } else {
              this.icon = 'el-icon-arrow-right'
              this.title = getI18n('hide')
              $('#fuck-task-btn').animate({ width: '110' })
            }
            this.show = !this.show
          },
          toggle () {
            if (this.drawerBtn.show) {
              this.drawerBtn.text = 'ShowLogs'
              this.drawerBtn.title = getI18n('showLog')
              $('.fuck-task-logs').animate({ right: '-100%' }, 'fast')
            } else {
              this.drawerBtn.text = 'HideLogs'
              this.drawerBtn.title = getI18n('hideLog')
              $('.fuck-task-logs').animate({ right: '16px' }, 'fast')
            }
            this.drawerBtn.show = !this.drawerBtn.show
          }
        }
      })
      new Vue({
        el: '#fuck-task-info'
      }).$notify({
        title: getI18n('taskLog'),
        iconClass: '',
        duration: 0,
        position: 'bottom-right',
        showClose: false,
        customClass: 'fuck-task-logs',
        dangerouslyUseHTMLString: true,
        message: ''
      })
      $('.fuck-task-logs .el-notification__title').before(`
<h2 v-cloak id="extraBtn" class="el-notification__title">
<el-badge is-dot class="item" :hidden="hidden">
  <el-button :icon="icon" :title="title" @click="checkUpdate" circle></el-button>
</el-badge>
<el-badge is-dot class="item" :hidden="settingHidden">
  <el-button icon="el-icon-setting" title="${getI18n('setting')}" @click="setting" circle></el-button>
</el-badge>
<el-badge is-dot class="item" :hidden="announcementHidden">
  <el-button :icon="announcementIcon" title="${getI18n('visitUpdateText')}" @click="updateText" circle></el-button>
</el-badge>
<el-badge is-dot class="item" :hidden="otherHidden">
  <el-button icon="el-icon-brush" title="${getI18n('cleanCache')}" @click="clearTemp" circle></el-button>
</el-badge>
<el-badge is-dot class="item" :hidden="otherHidden">
  <el-button icon="el-icon-s-promotion" title="${getI18n('feedback')}" @click="updateBug" circle></el-button>
</el-badge>
</h2>
`)
      const extraBtn = new Vue({
        el: '#extraBtn',
        data: {
          title: getI18n('checkUpdate'),
          icon: 'el-icon-refresh',
          hidden: true,
          settingHidden: !!GM_getValue('conf'),
          otherHidden: true,
          announcementHidden: true,
          announcementIcon: 'el-icon-document'
        },
        methods: {
          setting () {
            language === 'en' ? window.open('https://userjs.hclonely.com/setting_en.html', '_blank') : window.open('https://userjs.hclonely.com/setting.html', '_blank')
          },
          updateText () {
            fuc.getAnnouncement(this)
          },
          updateBug () {
            window.open('https://github.com/HCLonely/auto-task/issues/new/choose', '_blank')
          },
          checkUpdate () {
            fuc.checkUpdate(this, true)
          },
          clearTemp () {
            const status = fuc.echoLog({ type: 'custom', text: `<li>${getI18n('cleaning')}<font></font></li>` })
            const listValues = GM_listValues()
            for (const value of listValues) {
              if (value !== 'conf' && value !== 'language') GM_deleteValue(value)
            }
            status.success()
          }
        }
      })

      if (globalConf.other.checkUpdate) fuc.checkUpdate(extraBtn)

      $('.fuck-task-logs .el-notification__content').show()
      if (!showLogs) {
        $('.fuck-task-logs').animate({
          right: '-100%',
          display: '-webkit-box',
          display: '-ms-flexbox', // eslint-disable-line no-dupe-keys
          display: 'flex' // eslint-disable-line no-dupe-keys
        }, 0)
      }
      if (website.after) website.after(website)
    }

    GM_registerMenuCommand(getI18n('readme'), () => { window.open('https://blog.hclonely.com/posts/777c60d5/', '_blank') })
    GM_registerMenuCommand(getI18n('updateSteamInfo'), () => {
      new Promise(resolve => {
        fuc.updateSteamInfo(resolve, 'all', true)
      }).then(r => {
        fuc.echoLog({ type: 'custom', text: `<li><font class="success">${getI18n('updateSteamInfoComplete')}</font></li>` })
      })
    })
    GM_registerMenuCommand('Language', () => {
      vueUi.$msgbox({
        title: getI18n('language') + ' : ' + language,
        message: `<select id="auto-task-language"><option value="auto">${getI18n('auto')}</option><option value="zh-cn">简体中文</option><option value="en">English</option></select>`,
        dangerouslyUseHTMLString: true,
        confirmButtonText: getI18n('confirm'),
        cancelButtonText: getI18n('cancel'),
        type: 'info'
      }).then(value => {
        if (value) GM_setValue('language', $('#auto-task-language option:selected').val())
        language = getLanguage()
      })
    })
  } catch (e) {
    setTimeout(() => {
      vueUi.$message({ type: 'error', duration: 0, message: getI18n('jsError'), showClose: true })
    }, 500)
    console.log('%c%s', 'color:white;background:red', e.stack)
  }
})()