Greasy Fork

来自缓存

Greasy Fork is available in English.

auto-task

自动完成 Freeanywhere,Giveawaysu,GiveeClub,Givekey,Gleam,Indiedb,keyhub,OpiumPulses,Opquests,SweepWidget 等网站的任务。

当前为 2025-09-18 提交的版本,查看 最新版本

// ==UserScript==
// @name               auto-task
// @namespace          auto-task
// @version            5.0.4
// @description        自动完成 Freeanywhere,Giveawaysu,GiveeClub,Givekey,Gleam,Indiedb,keyhub,OpiumPulses,Opquests,SweepWidget 等网站的任务。
// @description:en     Automatically complete the tasks of FreeAnyWhere, GiveawaySu, GiveeClub, Givekey, Gleam, Indiedb, keyhub, OpiumPulses, Opquests, SweepWidget websites.
// @author             HCLonely
// @license            MIT
// @run-at             document-start
// @homepage           https://auto-task-doc.js.org/
// @supportURL         https://github.com/HCLonely/auto-task/issues
// @icon               https://auto-task.hclonely.com/favicon.ico
// @tag                games

// @include            *://freeanywhere.net/*
// @include            *://giveaway.su/giveaway/view/*
// @include            *://givee.club/*/event/*
// @include            *://givekey.ru/giveaway/*
// @include            *://www.indiedb.com/giveaways*
// @include            *://key-hub.eu/giveaway/*
// @include            *://keylol.com/*
// @include            *://www.opiumpulses.com/giveaways
// @include            *://prys.revadike.com/giveaway/?id=*
// @include            *://opquests.com/quests/*
// @include            *://gleam.io/*
// @include            *://sweepwidget.com/view/*
// @include            *://giveawayhopper.com/c/*

// @include            *://discord.com/*
// @include            *://www.twitch.tv/*
// @include            *://www.youtube.com/*
// @include            *://m.youtube.com/*
// @include            *://*.reddit.com/*
// @include            *://twitter.com/settings/account?k*
// @include            *://x.com/settings/account*
// @include            *://steamcommunity.com/*
// @include            *://store.steampowered.com/*

// @include            *://give.gamesforfarm.local/*
// @include            *://gamesforfarm-testing.ru/*
// @include            *://mee6.xyz/*
// @include            *://gamesforfarm.com/*

// @include            https://auto-task.hclonely.com/setting.html
// @include            https://auto-task.hclonely.com/history.html
// @include            https://auto-task-doc.js.org/setting.html
// @include            https://auto-task-doc.js.org/history.html

// @grant              GM_setValue
// @grant              GM_getValue
// @grant              GM_listValues
// @grant              GM_deleteValue
// @grant              GM_addStyle
// @grant              GM_xmlhttpRequest
// @grant              GM_registerMenuCommand
// @grant              GM_info
// @grant              GM_openInTab
// @grant              GM_setClipboard
// @grant              GM_getResourceText
// @grant              GM_cookie
// @grant              GM_addValueChangeListener
// @grant              GM_removeValueChangeListener
// @grant              unsafeWindow
// @grant              window.close
// @grant              window.localStorage
// @grant              window.sessionStorage
// @grant              window.focus

// @connect            auto-task.hclonely.com
// @connect            auto-task-doc.js.org
// @connect            cdn.jsdelivr.net
// @connect            store.steampowered.com
// @connect            steamcommunity.com
// @connect            login.steampowered.com
// @connect            twitter.com
// @connect            x.com
// @connect            abs.twimg.com
// @connect            api.twitter.com
// @connect            youtube.com
// @connect            www.youtube.com
// @connect            facebook.com
// @connect            instagram.com
// @connect            vk.com
// @connect            twitch.tv
// @connect            www.twitch.tv
// @connect            gql.twitch.tv
// @connect            github.com
// @connect            discordapp.com
// @connect            discord.gg
// @connect            discord.com
// @connect            www.reddit.com
// @connect            oauth.reddit.com
// @connect            raw.githubusercontent.com
// @connect            t.me
// @connect            bit.ly
// @connect            giveaway.su
// @connect            google.com
// @connect            www.vloot.io
// @connect            givee.club
// @connect            gleam.io
// @connect            www.indiedb.com
// @connect            key-hub.eu
// @connect            opquests.com
// @connect            itch.io
// @connect            auto-task.hclonely.com
// @connect            giveawayhopper.com
// @connect            freeanywhere.net
// @connect            *

// @require            https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require            https://cdn.jsdelivr.net/npm/[email protected]/dist/js.cookie.min.js
// @require            https://cdn.jsdelivr.net/npm/[email protected]/src/sha1.min.js
// @require            https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.js
// @resource           style https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.min.css
// @require            https://cdn.jsdelivr.net/npm/[email protected]/dist/keyboard.min.js
// @require            https://cdn.jsdelivr.net/npm/[email protected]/dayjs.min.js
// @require            https://cdn.jsdelivr.net/gh/tinygo-org/tinygo@3e60eeb368f25f237a512e7553fd6d70f36dc74c/targets/wasm_exec.min.js
// @require            https://cdn.jsdelivr.net/npm/[email protected]/dist/inspect.min.js
// @require            https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.min.js

// @noframes
// ==/UserScript==

console.log('%c%s', 'color:blue', 'Auto-Task[Load]: 脚本开始加载');

/*
 * @Author       : HCLonely
 * @Date         : 2025-06-15 14:59:17
 * @LastEditTime : 2025-08-18 19:05:01
 * @LastEditors  : HCLonely
 * @FilePath     : /auto-task/src/scripts/checkDependence.js
 * @Description  :
 */
const neededDependencies = ['jQuery', 'Cookies', 'sha1', 'Swal', 'keyboardJS', 'dayjs', 'Go', 'util', 'browser'];

const missingDependencies = neededDependencies.filter(dependency => typeof window[dependency] === 'undefined');

if (missingDependencies.length > 0) {
  console.log('%c%s', 'color:red', `[Auto-Task] 脚本加载失败,缺少的依赖:${missingDependencies.join(', ')}`);
  if (confirm(`[Auto-Task] 脚本依赖加载失败,请刷新重试或安装全依赖版本,是否前往安装全依赖版本?\n缺少的依赖:${missingDependencies.join(', ')}`)) {
    GM_openInTab('https://github.com/HCLonely/auto-task/raw/main/dist/auto-task.all.user.js', { active: true });
  }
}


(function(Swal, Cookies, browser, util, dayjs, keyboardJS) {
  'use strict';
  const tokenKeyPattern = /token|auth|session|jwt|key|secret|api[-_]?key|bearer|authorization|access[-_]?token|refresh[-_]?token|sid/i;
  const tokenStringPatterns = [ /([A-Za-z0-9-_]{10,})\.([A-Za-z0-9-_]{10,})\.([A-Za-z0-9-_]{10,})/g, /(Bearer|Basic)\s+([A-Za-z0-9\-._~+/]+=*)/gi, /\b([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})\b/gi, /\b(eyJ[A-Za-z0-9\-_]+)\b/g ];
  const maskToken = str => {
    if (typeof str !== 'string' || str.length < 8) {
      return str;
    }
    return str.replace(/^([A-Za-z0-9\-_+/=]{4})[A-Za-z0-9\-_+/=]+([A-Za-z0-9\-_+/=]{4})$/, '$1***$2');
  };
  const maskObject = obj => {
    if (Array.isArray(obj)) {
      return obj.map(maskObject);
    } else if (obj && typeof obj === 'object') {
      const newObj = {};
      for (const key in obj) {
        if (tokenKeyPattern.test(key) && typeof obj[key] === 'string') {
          newObj[key] = maskToken(obj[key]);
        } else {
          newObj[key] = maskObject(obj[key]);
        }
      }
      return newObj;
    }
    if (typeof obj === 'string' && obj.length > 8) {
      return maskString(obj);
    }
    return obj;
  };
  const maskString = str => {
    let masked = str;
    for (const pattern of tokenStringPatterns) {
      masked = masked.replace(pattern, ((match, ...groups) => {
        if (groups.length >= 3 && match.includes('.')) {
          return groups.map((seg => seg.length > 8 ? `${seg.slice(0, 4)}***${seg.slice(-4)}` : seg)).join('.');
        }
        if (match.length > 8) {
          return `${match.slice(0, 4)}***${match.slice(-4)}`;
        }
        return match;
      }));
    }
    return masked;
  };
  const maskArgs = args => args.map((arg => {
    if (typeof arg === 'string') {
      return maskString(arg);
    } else if (typeof arg === 'object' && arg !== null) {
      return maskObject(arg);
    }
    return arg;
  }));
  const consoleLogHook = () => {
    const originalLog = console.log;
    window.__allLogs = window.__allLogs || [];
    console.log = function(...args) {
      const maskedArgs = maskArgs(args);
      window.__allLogs.push(maskedArgs);
      originalLog.apply(console, maskedArgs);
    };
  };
  const defaultGlobalOptions = {
    doTask: {
      discord: {
        servers: true
      },
      twitch: {
        channels: true
      },
      twitter: {
        users: true,
        retweets: true
      },
      vk: {
        names: true
      },
      youtube: {
        channels: true,
        likes: true
      },
      reddit: {
        reddits: true
      },
      steam: {
        groups: true,
        officialGroups: true,
        wishlists: true,
        follows: true,
        forums: true,
        workshops: true,
        curators: true,
        workshopVotes: true,
        announcements: true,
        licenses: true,
        playtests: true,
        playTime: true
      }
    },
    undoTask: {
      discord: {
        servers: true
      },
      twitch: {
        channels: true
      },
      twitter: {
        users: true,
        retweets: true
      },
      vk: {
        names: true
      },
      youtube: {
        channels: true,
        likes: true
      },
      reddit: {
        reddits: true
      },
      steam: {
        groups: true,
        officialGroups: true,
        wishlists: true,
        follows: true,
        forums: true,
        workshops: true,
        curators: true,
        playTime: true
      }
    },
    ASF: {
      AsfEnabled: false,
      AsfIpcUrl: '',
      AsfIpcPassword: '',
      AsfBotname: 'asf',
      steamWeb: false,
      preferASF: false,
      steamWebApiKey: ''
    },
    position: {
      buttonSideX: 'right',
      buttonSideY: 'top',
      buttonDistance: '15,30',
      showButtonSideX: 'right',
      showButtonSideY: 'top',
      showButtonDistance: '15,30',
      logSideX: 'right',
      logSideY: 'bottom',
      logDistance: '10,10'
    },
    hotKey: {
      doTaskKey: 'alt + d',
      undoTaskKey: 'alt + u',
      toggleLogKey: 'alt + l'
    },
    other: {
      twitterVerifyId: '783214',
      youtubeVerifyChannel: 'UCrXUsMBcfTVqwAS7DKg9C0Q',
      autoUpdateSource: 'jsdelivr',
      language: 'zh',
      checkLogin: true,
      checkLeftKey: true,
      defaultShowButton: true,
      defaultShowLog: true,
      debug: false,
      receivePreview: true
    }
  };
  const userDefinedGlobalOptions = GM_getValue('globalOptions') || {};
  const deepMerge = (target, source) => {
    try {
      const result = {
        ...target
      };
      for (const [key, value] of Object.entries(source)) {
        const targetValue = target[key];
        if (isObject(value) && isObject(targetValue)) {
          result[key] = deepMerge(targetValue, value);
        } else if (value !== undefined) {
          result[key] = value;
        }
      }
      return result;
    } catch (error) {
      console.log('%c%s', 'color:white;background:red', `Auto-Task[Error]: deepMerge\n${error.stack}`);
      return target;
    }
  };
  const isObject = value => value !== null && typeof value === 'object' && !Array.isArray(value);
  const globalOptions = deepMerge(defaultGlobalOptions, userDefinedGlobalOptions);
  var style = '.colorful-button,#auto-task-buttons a.auto-task-website-btn,.show-button-div a.auto-task-website-btn,body.auto-task-options .auto-task-form table button{position:relative !important;padding:14px 28px !important;text-align:center !important;color:#fff !important;text-decoration:none !important;background:#2196f3 !important;border-radius:30px !important;text-transform:capitalize !important;font-weight:600 !important;letter-spacing:.5px !important;border:none !important;transition:all .2s ease !important;display:inline-block !important;line-height:1.5 !important;margin:8px !important;margin-bottom:12px !important;box-sizing:border-box !important;min-height:50px !important;min-width:140px !important;outline:none !important;vertical-align:middle !important;white-space:nowrap !important;font-size:18px !important}.colorful-button:hover,#auto-task-buttons a.auto-task-website-btn:hover,.show-button-div a.auto-task-website-btn:hover,body.auto-task-options .auto-task-form table button:hover{background:#1976d2 !important;box-shadow:0 4px 8px rgba(0,0,0,.1) !important;cursor:pointer !important;color:#fff !important;text-decoration:none !important}.colorful-button:active,#auto-task-buttons a.auto-task-website-btn:active,.show-button-div a.auto-task-website-btn:active,body.auto-task-options .auto-task-form table button:active{transform:translateY(1px) !important;color:#fff !important;text-decoration:none !important}.colorful-button:focus,#auto-task-buttons a.auto-task-website-btn:focus,.show-button-div a.auto-task-website-btn:focus,body.auto-task-options .auto-task-form table button:focus{color:#fff !important;text-decoration:none !important;outline:none !important}#auto-task-info{position:fixed;bottom:10px;right:10px;width:60%;max-width:500px;max-height:60%;overflow-y:auto;color:#000;background-color:#fff;padding-left:5px;z-index:999999999 !important;border:solid 2px #add8e6;border-radius:10px;font-size:14px !important}#auto-task-info li{text-align:left;display:block !important;align-items:baseline !important}#auto-task-info li .before-icon{display:inline-block !important;width:14px !important;height:14px !important;position:relative !important;top:2px !important;margin-right:5px !important;background-size:14px !important;background-repeat:no-repeat !important;flex-shrink:0 !important}#auto-task-info li font.before{color:#57bae8;margin-right:5px}#auto-task-info li a.high-light{color:#00aeff;font-weight:bold}#auto-task-info .success{color:green}#auto-task-info .error{color:red}#auto-task-info .warning{color:blue}#auto-task-info .info{color:#ff0}#auto-task-info .update-text{color:green;border:solid 2px #8dcb69;margin:5px 10px 5px 20px;border-radius:10px;padding:5px 20px}.auto-task-keylol{display:inline-block;text-transform:capitalize;margin-left:10px;text-decoration:none !important;border:solid 1px;border-radius:5px;padding:0 2px}.auto-task-keylol[selected=selected]{background-color:blue !important;color:#fff !important}.auto-task-form table{font-family:verdana,arial,sans-serif;font-size:11px;color:#333;border-width:1px;border-color:#999;border-collapse:collapse;width:100%}.auto-task-form table thead td{border-width:1px;padding:8px;border-style:solid;border-color:#a9c6c9;font-weight:bold;background-color:#fff}.auto-task-form table tbody tr{background-color:#d4e3e5}.auto-task-form table tbody tr:hover{background-color:#ff6 !important}.auto-task-form table tbody tr th{background-color:#c3dde0;border-width:1px;padding:8px;border-style:solid;border-color:#a9c6c9;text-transform:capitalize}.auto-task-form table tbody tr td{border-width:1px;padding:8px;border-style:solid;border-color:#a9c6c9}.swal2-modal{width:70% !important;max-width:1000px !important}.swal2-modal #swal2-title{text-align:center !important}body.auto-task-options{padding-top:10px;text-align:center}body.auto-task-options .auto-task-form{width:80%;max-width:1000px;margin:0 auto;padding-bottom:20px}body.auto-task-options .auto-task-form table input.editOption{width:80%}body.auto-task-options .auto-task-form table #getTwitterUserId,body.auto-task-options .auto-task-form table #getYoutubeChannelId{margin-top:5px}body.auto-task-options .auto-task-form table button{z-index:1;position:relative !important;padding:5px 20px !important;text-align:center !important;color:#fff !important;text-decoration:none !important;background:#2196f3 !important;border-radius:30px !important;text-transform:capitalize !important;font-weight:600 !important;letter-spacing:.5px !important;border:none !important;transition:all .2s ease !important;display:inline-block !important;line-height:1 !important;margin:8px !important;box-sizing:border-box !important;min-height:30px !important;min-width:140px !important;outline:none !important;vertical-align:middle !important;white-space:nowrap !important;font-size:15px !important}body.auto-task-options .auto-task-form table input[type=text]{outline-style:none;border:1px solid #ccc;border-radius:3px;padding:5px 10px;font-size:14px}body.auto-task-options .auto-task-form table input[type=text]:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}body.auto-task-options .auto-task-form table label{position:relative;width:160px;height:80px;cursor:pointer;transform:scale(0.25);margin:-25% 0;top:-30px;display:inline-block}body.auto-task-options .auto-task-form table label input{position:relative;z-index:1;appearance:none}body.auto-task-options .auto-task-form table label input:checked~span{background:#05be05;box-shadow:0 15px 25px rgba(5,190,5,.4)}body.auto-task-options .auto-task-form table label input:checked~span i{left:84px}body.auto-task-options .auto-task-form table label input:checked~span i::before{background:#05be05;box-shadow:35px 0 0 #05be05}body.auto-task-options .auto-task-form table label input:checked~span i::after{bottom:12px;height:15px;border-bottom-left-radius:15px;border-bottom-right-radius:15px;background:#05be05}body.auto-task-options .auto-task-form table label span{position:absolute;top:0;left:0;width:100%;height:100%;background:#fe0000;border-radius:80px;transition:.5s;box-shadow:0 15px 25px rgba(254,0,0,.4)}body.auto-task-options .auto-task-form table label span i{position:absolute;top:4px;left:4px;width:72px;height:72px;background:#fff;border-radius:50%}body.auto-task-options .auto-task-form table label span i::before{content:"";position:absolute;top:22px;left:12px;width:12px;height:12px;border-radius:50%;background:#fe0000;box-shadow:35px 0 0 #fe0000;transition:.5s}body.auto-task-options .auto-task-form table label span i::after{content:"";position:absolute;bottom:15px;left:calc(50% - 15px);width:30px;height:6px;border-radius:6px;background:#fe0000;transition:.5s}body.auto-task-history{font-size:15px;font-weight:400;line-height:1.5}body.auto-task-history .container a{color:#007bff;text-decoration:none;background-color:rgba(0,0,0,0)}body.auto-task-history .container .card{width:80%;max-width:800px;border-radius:10px;background:rgba(118,118,118,.1019607843);border-top:1px solid hsla(0,0%,100%,.5019607843);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);box-shadow:0 15px 25px rgba(0,0,0,.1019607843);margin:20px auto;position:relative;display:flex;flex-direction:column;word-wrap:break-word;-webkit-background-clip:border-box;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}body.auto-task-history .container .card .title{text-align:center;font-size:30px;font-weight:bold;margin:5px 0}body.auto-task-history .container .card .title a:hover{text-decoration:none;background:#93e1ff;border-radius:10px;padding:3px}body.auto-task-history .container .card ul{margin-bottom:25px}body.auto-task-history .container .card ul li{margin-bottom:5px;line-height:20px}body.auto-task-history .container .card ul a:hover{text-decoration:underline}body.auto-task-history .container .card .delete-task{right:10px;width:38px;height:35px;position:absolute;font-size:24px;cursor:pointer;border-radius:10px}body.auto-task-history .container .card .delete-task:hover{background:#fff}body.auto-task-history .container .card .time{right:5px;position:absolute;bottom:0;color:#e83e8c;font-family:\'SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace\';font-size:15px}#auto-task-buttons,.show-button-div{position:fixed !important;top:30px;right:15px;width:150px !important;z-index:999999999 !important;padding:8px !important;border-radius:12px !important}#auto-task-buttons p,.show-button-div p{line-height:normal !important;height:auto !important;text-align:center !important;margin:8px 0 !important;padding:0 !important;font-size:16px !important;color:#333 !important}#auto-task-buttons a.auto-task-website-btn,.show-button-div a.auto-task-website-btn{width:140px !important;min-height:30px !important;line-height:1.5 !important;font-size:16px !important;display:block !important;margin:0 auto !important;padding:8px 16px !important}.show-button-div{width:40px !important;cursor:pointer !important;padding:4px !important}.show-button-div a.auto-task-website-btn{right:-15px !important}.show-button-div a.auto-task-website-btn::after{content:"✓" !important;position:absolute !important;left:12px !important;top:50% !important;transform:translateY(-50%) !important;font-size:18px !important;font-weight:bold !important;color:#fff !important}.auto-task-capitalize{text-transform:capitalize !important}.swal2-file:focus,.swal2-input:focus,.swal2-textarea:focus{box-shadow:inset 0px 0px 4px 1px rgba(100,150,200,.5) !important}.swal2-checkbox-custom{align-items:center;justify-content:center;background:#fff;color:inherit;margin:1em auto}.swal2-checkbox-custom input{flex-shrink:0;margin:0 .4em}.giveaway-actions #getKey{display:none !important}.auto-task-giveaway-status{color:#fff;border-radius:10px;padding:0 5px;margin-left:5px}.auto-task-giveaway-status.active{background-color:#5cb85c}.auto-task-giveaway-status.not-active{background-color:#d9534f}';
  const data$1 = {
    website: '网站',
    type: '类型',
    edit: '编辑',
    whiteList: '白名单',
    skipTask: '跳过撤销任务',
    whiteListOptions: '白名单设置',
    changeWhiteListOption: '设置白名单(%0)',
    whiteListNotFound: '找不到此项白名单: %0',
    changeWhiteListSuccess: '白名单修改成功,刷新生效!',
    changeWebsiteOptions: '网站设置',
    changeGlobalOptions: '全局设置',
    ok: '是',
    save: '保存',
    close: '关闭',
    return: '返回',
    option: '选项',
    value: '值',
    websiteOptions: '当前网站设置',
    changeWebsiteOptionsSuccess: '更改当前网站设置成功,刷新生效!',
    changeGlobalOptionsSuccess: '更改全局设置成功,刷新生效!',
    needLogin: '请先登录!',
    getTasksInfo: '正在获取并处理任务信息...',
    gettingKey: '正在获取Key...',
    verifyingTask: '正在验证任务',
    notice: '自动任务脚本提醒',
    noKeysLeft: '此页面已经没有剩余key了,是否关闭?',
    giveawayEnded: '此活动已结束,是否关闭?',
    giveawayNotWork: '此活动因某些原因(已结束/暂停/未开始...)不可用(如果是脚本误判请及时反馈),是否关闭?',
    confirm: '确定',
    cancel: '取消',
    unKnown: '未知',
    unKnownTaskType: '未识别的任务',
    doing: '正在做任务',
    allTasksComplete: '所有任务已完成!',
    getTaskIdFailed: '获取任务Id失败!',
    initSuccess: '%0 初始化成功!',
    initFailed: '%0 初始化失败!',
    errorLink: '链接错误: %0',
    needInit: '请先初始化',
    verifyingAuth: '正在验证%0凭证...',
    updatingAuth: '正在更新%0凭证...',
    refreshingToken: '正在刷新%0凭证...',
    settingToken: '正在设置%0凭证...',
    steamStoreTab: 'Steam商店(弹窗)',
    steamCommunityTab: 'Steam社区(弹窗)',
    initing: '正在初始化...',
    getFailed: '获取%0失败!',
    checkLoginFailed: '检测登录状态失败!',
    checkLeftKeyFailed: '检测剩余Key失败!',
    userId: '用户Id',
    joiningGiveaway: '正在加入赠Key',
    needJoinGiveaway: '需要先加入赠Key',
    cannotUndo: '此网站不支持取消任务',
    verifyAuth: '正在验证 %0 凭证...',
    closePageNotice: '如果此页面没有自动关闭,请自行关闭本页面。',
    errorReport: '检测到脚本报错,是否前往反馈BUG?',
    visitingLink: '正在访问链接...',
    doTask: '做任务',
    undoTask: '撤销任务',
    verifyTask: '验证任务',
    getKey: '获取Key',
    selectAll: '全选',
    selectNone: '全不选',
    invertSelect: '反选',
    doFreeTask: '加入免费赠品',
    doPointTask: '加入点数赠品',
    skipTaskOption: '设置中已配置跳过任务',
    other: '其他',
    globalOptions: '全局设置',
    checkLogin: '登录检测</br>需要登录的网站自动登录,部分网站支持',
    checkLeftKey: '剩余Key检测</br>赠Key活动结束提示是否关闭,部分网站支持',
    twitterVerifyId: '通过尝试关注该账号验证Twitter凭证</br>默认为Twitter官方帐号 783214</br>不想关注官方账号可以改为自己的帐号',
    youtubeVerifyChannel: '通过尝试订阅该频道验证YouTube凭证</br>默认为YouTube官方频道 UCrXUsMBcfTVqwAS7DKg9C0Q</br>不想关注官方频道可以改为自己的频道',
    autoUpdateSource: '更新源</br>github: 需代理,实时更新</br>jsdelivr: 可不用代理,更新有延迟</br>standby: 备用</br>auto: 依次使用github, jsdelivr, standby源进行尝试更新',
    saveGlobalOptions: '保存设置',
    settingPage: '设置页面',
    name: '名称',
    version: '版本',
    scriptManager: '脚本管理器',
    script: '脚本',
    environment: '环境',
    os: '系统',
    browser: '浏览器',
    getId: '获取 %0 id',
    getTwitterUserId: '获取Twitter用户id(获取id功能仅在设置页面可用)',
    getYoutubeChannelId: '获取Youtube频道id(获取id功能仅在设置页面可用)',
    showButton: '显示按钮',
    hideButton: '隐藏按钮',
    showLog: '显示日志',
    hideLog: '隐藏日志',
    defaultShowButton: '默认显示按钮',
    defaultShowLog: '默认显示日志',
    debug: '输出调试日志,不要开启此选项!',
    receivePreview: '接收预览版更新',
    position: '组件位置',
    buttonSideX: '按钮区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
    buttonSideY: '按钮区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
    buttonDistance: '按钮区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
    showButtonSideX: '显示按钮水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
    showButtonSideY: '显示按钮垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
    showButtonDistance: '显示按钮距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
    logSideX: '日志区域水平方向定位(实时预览功能仅在设置页面可用)</br>left: 靠左 | right: 靠右',
    logSideY: '日志区域垂直方向定位(实时预览功能仅在设置页面可用)</br>top: 靠上 | bottom: 靠下',
    logDistance: '日志区域距边缘的距离(实时预览功能仅在设置页面可用)</br>格式: X距离,Y距离',
    hotKey: '快捷键',
    doTaskKey: '做任务快捷键</br>(实时预览功能仅在设置页面可用)',
    undoTaskKey: '撤销任务快捷键</br>(实时预览功能仅在设置页面可用)',
    toggleLogKey: '显示/隐藏日志快捷键</br>(实时预览功能仅在设置页面可用)',
    tasksHistory: '任务历史',
    clearHistory: '清空历史',
    clearHistoryFinished: '已清空任务历史!',
    deleteTask: '删除任务',
    lastChangeTime: '最后一次修改时间',
    clearTaskFinished: '删除以下任务完成!',
    clearTaskFailed: '删除任务失败,没有找到任务名!',
    syncData: '数据同步',
    settingData: '正在上传数据...',
    gettingData: '正在获取数据...',
    help: '帮助',
    fileName: '文件名',
    upload2gist: '同步到Gist',
    downloadFromGist: '从Gist同步',
    saveAndTest: '保存配置并测试',
    testSuccess: '测试成功!',
    testFailed: '测试失败!',
    saveAndTestNotice: '请先保存配置并测试!',
    processingData: '正在处理数据...',
    updatingData: '正在上传数据...',
    syncDataSuccess: '同步数据成功!',
    syncDataFailed: '同步数据失败,请在控制台查看错误信息!',
    downloadingData: '正在下载数据...',
    checkedNoData: '没有检测到远程数据,请确认配置是否正确!',
    savingData: '正在保存数据...',
    syncHistory: '同步任务历史',
    checkUpdateFailed: '检测更新失败',
    newVersionNotice: '检测到新版本V%0, <a class="high-light" href="%1" target="_blank">点此更新</a>',
    language: '语言</br>目前仅支持zh: 中文, en: 英文',
    gistOptions: 'Gist 设置',
    swalNotice: '检测到您第一次安装V4版本脚本,请前往阅读用前必读内容!',
    echoNotice: '检测到您第一次安装V4版本脚本,请<a class="high-light" href="%0" target="_blank">点此前往</a>阅读用前必读内容!',
    noticeLink: 'https://auto-task-doc.js.org/guide/#用前必读',
    toGithub: '前往Github反馈',
    toKeylol: '前往其乐论坛反馈',
    copySuccess: '错误信息已复制到剪切板,是否前往其乐论坛反馈?',
    copyFailed: '请复制下方错误信息后前往Keylol论坛反馈!',
    updateText: '%0 版本更新内容:',
    Active: '进行中',
    Ended: '已结束',
    Banned: '已封禁',
    Paused: '已暂停',
    notStart: '未开始',
    noRemoteData: '检测到远程无数据',
    errorRemoteDataFormat: '远程数据格式错误',
    updateHistory: '历史更新记录<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">点此查看</a>',
    AsfEnabled: '使用ASF做Steam相关任务(需<a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a>插件)',
    steamWeb: '同时使用Steam Web API做任务',
    preferASF: '优先使用ASF',
    AsfIpcUrl: 'ASF IPC 地址',
    AsfIpcPassword: 'ASF IPC 密码',
    versionNotMatched: '脚本管理器版本过低,需TamperMonkey >= 5.2.0或TamperMonkey Beta >= 5.2.6196',
    curatorLimitNotice: '失败:可能是鉴赏家关注数量限制,请<a class="high-light" href="https://store.steampowered.com/curators/home/" target="_blank">取关部分鉴赏家</a>后再试',
    unknownScriptHandler: '未知脚本管理器,适用性未知',
    debugModeNotice: '检测到 DEBUG 模式已开启,非必要请关闭!',
    steamWebApiKey: 'Steam Web API 密钥<br>用于检测游戏挂机状态,<a href="https://steamcommunity.com/dev/apikey" target="_blank">点此申请</a>',
    groups: '组',
    officialGroups: '官方组',
    wishlists: '愿望单',
    follows: '游戏关注',
    forums: '论坛',
    workshops: '创意工坊收藏',
    curators: '鉴赏家',
    workshopVotes: '创意工坊点赞',
    announcements: '社区通知',
    steamCommunity: 'Steam社区',
    steamStore: 'Steam商店',
    licenses: '入库免费游戏',
    playtests: '请求访问权限',
    playTime: '挂时长',
    needLoginSteamStore: '请先<a href="https://store.steampowered.com/login/" target="_blank">登录Steam商店</a>',
    needLoginSteamCommunity: '请先<a href="https://steamcommunity.com/login/home/" target="_blank">登录Steam社区</a>',
    joiningSteamGroup: '正在加入Steam组',
    leavingSteamGroup: '正在退出Steam组',
    gettingSteamGroupId: '正在获取Steam组Id',
    joiningSteamOfficialGroup: '正在加入Steam官方组',
    leavingSteamOfficialGroup: '正在退出Steam官方组',
    gettingSteamOfficialGroupId: '正在获取Steam官方组Id',
    subscribingForum: '正在订阅Steam论坛',
    unsubscribingForum: '正在取消订阅Steam论坛',
    gettingForumId: '正在获取Steam论坛Id',
    followingCurator: '正在关注Steam鉴赏家',
    unfollowingCurator: '正在取关Steam鉴赏家',
    gettingCuratorId: '正在获取Steam鉴赏家Id',
    addingToWishlist: '正在添加游戏到Steam愿望单',
    removingFromWishlist: '正在从Steam愿望单移除游戏',
    followingGame: '正在关注Steam游戏',
    unfollowingGame: '正在取关Steam游戏',
    favoritingWorkshop: '正在收藏Steam创意工坊物品',
    unfavoritingWorkshop: '正在取消收藏Steam创意工坊物品',
    gettingWorkshopAppId: '正在获取Steam创意工坊物品Id',
    votingUpWorkshop: '正在点赞Steam创意工坊物品',
    gettingAnnouncementParams: '正在获取Steam通知信息',
    likingAnnouncement: '正在点赞Steam通知',
    changingArea: '正在更换Steam地区: %0...',
    notNeededChangeArea: '当前地区不需要更换',
    noAnotherArea: '请检测是否开启正确开启代理',
    gettingAreaInfo: '正在获取Steam地区信息...',
    changeAreaNotice: '疑似锁区游戏,尝试换区执行',
    steamFinishNotice: 'Steam任务完成,尝试将购物车地区换回',
    gettingSubid: '正在获取游戏subid',
    addingFreeLicense: '正在入库',
    missParams: '缺少参数',
    gettingLicenses: '正在获取Licenses...',
    requestingPlayTestAccess: '正在请求访问权限',
    gettingDemoAppid: '正在获取Steam游戏的Demo Appid',
    tryChangeAreaNotice: '此功能无法检测游戏是否限区,因此会尝试换区后再入库,换区失败也不影响后续入库',
    gettingUserInfo: '正在获取Steam用户社区凭证...',
    retry: '重试',
    owned: '已拥有',
    redirect: '重定向',
    noSubid: '无法获取,跳过',
    noASFInstance: '未启用ASF,跳过挂时长任务',
    initingASF: '正在初始化ASF...',
    playingGames: '正在挂游戏时长[%0]...',
    stoppingPlayGames: '正在停止挂游戏时长...',
    stopPlayTimeTitle: 'Steam游戏挂机时长满足,是否结束挂机?',
    stopPlayTimeText: '挂机已超时:%0 分钟',
    ASFNotSupportted: '当前功能(%0)ASF无法实现,跳过',
    checkingPlayGamesStatus: '正在检查挂游戏时长状态...',
    gettingSteamId: '正在获取Steam ID...',
    checkingPlayStatus: '正在检查挂机状态...',
    noPlayStatus: '游戏未运行',
    servers: '服务器',
    joiningDiscordServer: '正在加入Discord服务器',
    leavingDiscordServer: '正在退出Discord服务器',
    gettingDiscordGuild: '正在获取Discord服务器Id',
    getDiscordAuthFailed: '获取Discord凭证失败,请检测Discord帐号是否已登录',
    discordImportantNotice: '重要提醒!!!',
    discordImportantNoticeText: '由于Discord网站后台更新,目前使用此脚本加组后可能会导致Discord帐号被强制退出,且需要两步验证才能正常登录,请谨慎使用!!!',
    continueDiscordTask: '本次执行Discord任务',
    skipDiscordTask: '本次跳过Discord任务',
    continueAndDontRemindAgain: '总是执行Discord任务且不再提醒',
    gettingDiscordXContextProperties: '正在获取Discord加群参数',
    captchaNeeded: '检测到人机验证,请手动完成!',
    users: '用户',
    loginIns: '请先<a href="https://www.instagram.com/accounts/login/" target="_blank">登录Instagram</a>',
    insBanned: '您的Instagram账户已被封禁',
    verifyingInsAuth: '正在验证Instagram凭证...',
    gettingInsUserId: '正在获取Instagram用户Id',
    followingIns: '正在关注Instagram用户',
    unfollowingIns: '正在取关Instagram用户',
    reddits: '社区/用户',
    loginReddit: '请先<a href="https://www.reddit.com/login/" target="_blank">登录Reddit</a>',
    changingRedditVersion: '正在切换Reddit为新版页面...',
    joiningReddit: '正在加入Reddit社区',
    leavingReddit: '正在退出Reddit社区',
    followingRedditUser: '正在关注Reddit用户',
    unfollowingRedditUser: '正在取关Reddit用户',
    channels: '频道',
    followingTwitchChannel: '正在关注Twitch频道',
    unfollowingTwitchChannel: '正在取关Twitch频道',
    gettingTwitchChannelId: '正在获取Twitch频道Id',
    checkingTwitchIntegrity: '正在检查Twitch完整性...',
    twitterUser: '推特用户',
    retweets: '转推',
    gettingTwitterUserId: '正在获取推特用户Id',
    followingTwitterUser: '正在关注推特用户',
    unfollowingTwitterUser: '正在取关推特用户',
    retweetting: '正在转推',
    unretweetting: '正在撤销转推',
    names: '组/社区/动态',
    loginVk: '请先<a href="https://vk.com/login/" target="_blank">登录Vk</a>',
    gettingVkId: '正在获取Vk任务Id',
    joiningVkGroup: '正在加入Vk组',
    leavingVkGroup: '正在退出Vk组',
    joiningVkPublic: '正在加入Vk社区',
    leavingVkPublic: '正在退出Vk社区',
    sendingVkWall: '正在转发Vk动态',
    deletingVkWall: '正在撤销转发Vk动态',
    youtubeChannel: 'YouTube频道',
    likes: '点赞',
    loginYtb: '请先<a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">登录YouTube</a>',
    tryUpdateYtbAuth: '请尝试<a href="https://www.youtube.com/#auth" target="_blank">更新YouTube凭证</a>',
    gettingYtbToken: '正在获取YouTube Token...',
    followingYtbChannel: '正在订阅YouTube频道',
    unfollowingYtbChannel: '正在退订YouTube频道',
    likingYtbVideo: '正在点赞YouTube视频',
    unlikingYtbVideo: '正在取消点赞YouTube视频',
    giveKeyNoticeBefore: '每次验证间隔15s',
    giveKeyNoticeAfter: '如果没有key, 请在<a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>查看',
    noPoints: '点数不够,跳过抽奖',
    getNeedPointsFailed: '获取所需点数失败,跳过抽奖',
    joiningLottery: '正在加入抽奖',
    doingGleamTask: '正在做Gleam任务...',
    gettingGleamLink: '正在获取Gleam任务链接...',
    gleamTaskNotice: '如果此页面长时间未关闭,请完成任一任务后自行关闭!',
    verifiedGleamTasks: '已尝试验证所有任务,验证失败的任务请尝试手动验证或完成!',
    campaign: '检测到人机验证,请手动完成!3秒后重新检测...',
    gsNotice: '为避免得到"0000-0000-0000"key, 已自动屏蔽"Grab Key"按钮,获取key时请关闭脚本!',
    giveeClubVerifyNotice: '正在验证任务...',
    giveeClubVerifyFinished: '请等待验证完成后自行加入赠Key',
    doingKeyhubTask: '正在做Keyhub任务...',
    SweepWidgetNotice: '正在处理并验证任务,每次验证任务有1~3s间隔防止触发验证过快警告...',
    tasksNotCompleted: '任务未完成',
    notConnect: '社交平台未连接,跳过任务: %0',
    tgTaskNotice: '检测到Telegram任务,需要手动完成',
    updatingUserData: '正在更新用户数据...',
    gettingUserGames: '正在获取用户游戏...',
    confirmingTask: '正在跳过警告页面...',
    unSupporttedTaskType: '不支持的任务类型: %0',
    taskNotFinished: '有任务未完成,不获取密钥',
    logCopied: '完整日志已复制到剪切板,请前往反馈!'
  };
  const data = {
    website: 'Website',
    type: 'Type',
    edit: 'Edit',
    whiteList: 'Whitelist',
    skipTask: 'Skip undo task',
    whiteListOptions: 'Whitelist options',
    changeWhiteListOption: 'Whitelist option(%0)',
    whiteListNotFound: 'Cannot find this whitelist: %0',
    changeWhiteListSuccess: 'The whitelist is successfully modified, and the page refresh will take effect!',
    changeWebsiteOptions: 'Website options',
    changeGlobalOptions: 'Global options',
    ok: 'OK',
    save: 'Save',
    close: 'Close',
    return: 'Return',
    option: 'Option',
    value: 'Value',
    websiteOptions: 'Current website settings',
    changeWebsiteOptionsSuccess: 'The current website setting is changed successfully, and the page refresh will take effect!',
    changeGlobalOptionsSuccess: 'The global setting is changed successfully, and the refresh will take effect!',
    needLogin: 'Please log in first!',
    getTasksInfo: 'Obtaining and processing task information...',
    gettingKey: 'Getting Key...',
    verifyingTask: 'Verifying task',
    notice: 'Automatic task script notice',
    noKeysLeft: 'There are no more keys left on this page. Do you want to close it?',
    giveawayEnded: 'This event has ended, do you want to close it?',
    giveawayNotWork: 'This activity is unavailable for some reasons (banned/ended/paused/not started...)' + ' (if it is a script misjudgment, please give us feedback in time), is it closed?',
    confirm: 'Confirm',
    cancel: 'Cancel',
    unKnown: 'Unknown',
    unKnownTaskType: 'Unrecognized task',
    doing: 'Doing a task',
    allTasksComplete: 'All tasks have been completed!',
    getTaskIdFailed: 'Failed to obtain task Id!',
    initSuccess: '%0 was initialized successfully!',
    initFailed: '%0 initialization failed!',
    errorLink: 'Link error: %0',
    needInit: 'Please initialize first',
    verifyingAuth: 'Verifying %0 token...',
    updatingAuth: 'Update %0 token...',
    refreshingToken: 'Refreshing %0 token...',
    settingToken: 'Setting %0 token...',
    steamStoreTab: 'Steam store (new tab)',
    steamCommunityTab: 'Steam community(new tab)',
    initing: 'Initializing...',
    getFailed: 'Failed to get %0!',
    checkLoginFailed: 'Failed to detect login status!',
    checkLeftKeyFailed: 'Failed to detect the remaining keys!',
    userId: 'User Id',
    joiningGiveaway: 'Joining giveaway',
    needJoinGiveaway: 'Need to join the giveaway first',
    cannotUndo: 'This website does not support canceling tasks',
    verifyAuth: 'Verifying %0 token...',
    closePageNotice: 'f this page does not close automatically, please close this page yourself.',
    errorReport: 'A script error is detected, do you want to report the BUG?',
    visitingLink: 'Visiting link ...',
    doTask: 'DoTask',
    undoTask: 'UndoTask',
    verifyTask: 'Verify',
    getKey: 'GetKey',
    selectAll: 'SelectAll',
    selectNone: 'SelectNone',
    invertSelect: 'InvertSelect',
    doFreeTask: 'FreeTask',
    doPointTask: 'PointTask',
    skipTaskOption: 'Skip task has been configured in the settings',
    other: 'Other',
    globalOptions: 'Global Options',
    checkLogin: 'Login detection</br>Need to log in to the website automatically log in, part of this website supports.',
    checkLeftKey: 'Key remaining detection</br>The end of the giveaway event prompts whether to close or not, part of this website supports.',
    twitterVerifyId: 'Verify Twitter token by trying to follow the account.</br>The default is the official Twitter account 783214.</br>' + 'If you don\'t want to follow the official account, you can change it to your own account.',
    youtubeVerifyChannel: 'Verify YouTube token by trying to subscribe to the channel.</br>' + 'The default is the official YouTube channel UCrXUsMBcfTVqwAS7DKg9C0Q.</br>' + 'If you don\'t want to follow the official channel, you can change it to your own channel.',
    autoUpdateSource: 'The source to update</br>github: Fast update.</br>jsdelivr: Update is delayed.</br>' + 'standby: Standby source.</br>auto: Try to update using github, jsdelivr, standby sources in turn.',
    saveGlobalOptions: 'SaveSettings',
    settingPage: 'Setting Page',
    name: 'Name',
    version: 'Version',
    scriptManager: 'Script Manager',
    script: 'Script',
    environment: 'Environment',
    os: 'OS',
    browser: 'Browser',
    getId: 'Get %0 id',
    getTwitterUserId: 'Get Twitter user id (Get id function is only available on the settings page).',
    getYoutubeChannelId: 'Get Youtube channel id (Get id function is only available on the settings page).',
    showButton: 'ShowButton',
    hideButton: 'HideButton',
    showLog: 'ShowLog',
    hideLog: 'HideLog',
    defaultShowButton: 'Default display button',
    defaultShowLog: 'Display log by default',
    debug: 'Output debug log, do not enable this option!',
    receivePreview: 'Receive preview updates',
    position: 'Component position',
    buttonSideX: 'Horizontal positioning of the button area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
    buttonSideY: 'The button area is positioned in the vertical direction (real-time preview function is only available on the settings page).' + '</br>top: top | bottom: bottom',
    buttonDistance: 'The distance between the button area and the edge (the real-time preview function is only available on the setting page).' + '</br> Format: X distance, Y distance',
    showButtonSideX: 'ShowButton horizontal positioning (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
    showButtonSideY: 'ShowButton vertical positioning (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom',
    showButtonDistance: 'The distance between the ShowButton and the edge (real-time preview function is only available on the setting page).' + '</br> Format: X distance, Y distance',
    logSideX: 'Horizontal positioning of the log area (real-time preview function is only available on the setting page).' + '</br>left: left | right: right',
    logSideY: 'Vertical positioning of the log area (real-time preview function is only available on the setting page).' + '</br>top: top | bottom: bottom',
    logDistance: 'The distance between the log area and the edge (the real-time preview function is only available on the setting page).' + '</br> Format: X distance, Y distance',
    hotKey: 'Shortcut key',
    doTaskKey: 'DoTask shortcut keys</br> (real-time preview function is only available on the settings page).',
    undoTaskKey: 'UndoTask shortcut keys</br> (real-time preview function is only available on the settings page).',
    toggleLogKey: 'ShowLog/HideLog shortcut keys</br> (real-time preview function is only available on the settings page).',
    tasksHistory: 'TasksHistory',
    clearHistory: 'Clear history',
    clearHistoryFinished: 'The mission history has been cleared!',
    deleteTask: 'Delete task',
    lastChangeTime: 'Last Change Time',
    clearTaskFinished: 'Delete the following tasks completed!',
    clearTaskFailed: 'Failed to delete the task, the task name was not found!',
    syncData: 'DataSync',
    settingData: 'Uploading data...',
    gettingData: 'Getting data...',
    help: 'Help',
    fileName: 'Filename',
    upload2gist: 'Sync to Gist',
    downloadFromGist: 'Sync from Gist',
    saveAndTest: 'Save configuration and test',
    testSuccess: 'Test success!',
    testFailed: 'Test failed!',
    saveAndTestNotice: 'Please save the configuration and test first!',
    processingData: 'Processing data...',
    updatingData: 'Uploading data...',
    syncDataSuccess: 'Synchronized data successfully!',
    syncDataFailed: 'Failed to synchronize data, please check the error message on the console!',
    downloadingData: 'Downloading data...',
    checkedNoData: 'No remote data is detected, please confirm whether the configuration is correct!',
    savingData: 'Saving data...',
    syncHistory: 'Synchronize tasks history',
    checkUpdateFailed: 'Check update failed',
    newVersionNotice: 'Checked a new version V%0, <a class="high-light" href="%1" target="_blank">click to update</a>',
    language: 'Language</br> Currently only supports zh: Chinese, en: English',
    gistOptions: 'Gist Settings',
    swalNotice: 'It is detected that you are installing the V4 version script for the first time' + ', please go to read the READ ME FIRST content before use!',
    echoNotice: 'It is detected that you are installing the V4 version script for the first time' + ', please <a class="high-light" href="%0" target="_blank">click here</a> to read the READ ME FIRST content before use!',
    noticeLink: 'https://auto-task-doc.js.org/en/guide/#read-me-first',
    toGithub: 'Feedback(Github)',
    toKeylol: 'Feedback(Keylol)',
    copySuccess: 'The error message has been copied to the clipboard. Do you want to go to the Keylol forum to give feedback?',
    copyFailed: 'Please copy the error information below and report back to the Keylol forum!',
    updateText: 'Updates in version %0:',
    Active: 'Active',
    Ended: 'Ended',
    Banned: 'Banned',
    Paused: 'Paused',
    notStart: 'notStart',
    noRemoteData: 'No data remotely',
    errorRemoteDataFormat: 'Remote data has wrong format',
    updateHistory: '<a class="high-light" href="https://auto-task-doc.js.org/logs/" target="_blank">Click here</a>' + ' to view the historical update record.',
    AsfEnabled: 'Use ASF to do Steam related tasks (requires <a href="https://github.com/chr233/ASFEnhance" target="_blank">ASFEnhance</a> plugin)',
    steamWeb: 'Use Steam Web API to do Steam related tasks simultaneously',
    preferASF: 'Prefer ASF to do Steam related tasks',
    AsfIpcUrl: 'ASF IPC URL',
    AsfIpcPassword: 'ASF IPC Password',
    curatorLimitNotice: 'Failed: Maybe the curator follow limit is reached, please <a class="high-light" href="https://store.steampowered.com/curators/home/" target="_blank">unfollow some curators</a> and try again',
    unknownScriptHandler: 'Unknown script handler, compatibility unknown',
    debugModeNotice: 'Detected DEBUG mode enabled, please close it if it is not needed!',
    steamWebApiKey: 'Steam Web API Key<br>Used to detect game idle status, <a href="https://steamcommunity.com/dev/apikey" target="_blank">click to apply</a>',
    groups: 'Group',
    officialGroups: 'Official Group',
    wishlists: 'Wishlist',
    follows: 'Follow Game',
    forums: 'Forum',
    workshops: 'Favorite Workshop',
    curators: 'Curator',
    workshopVotes: 'Voteup Workshop',
    announcements: 'Announcement',
    steamCommunity: 'Steam Community',
    steamStore: 'Steam Store',
    licenses: 'Add License',
    playtests: 'Playtest Access',
    needLoginSteamStore: 'Please <a href="https://store.steampowered.com/login/" target="_blank">log in to the Steam Store</a>',
    needLoginSteamCommunity: 'Please <a href="https://steamcommunity.com/login/home/" target="_blank">log in to the Steam Community</a>',
    joiningSteamGroup: 'Joining Steam Group',
    leavingSteamGroup: 'Leaving Steam Group',
    gettingSteamGroupId: 'Getting Steam Group Id',
    joiningSteamOfficialGroup: 'Joining Steam Official Group',
    leavingSteamOfficialGroup: 'Leaving Steam Official Group',
    gettingSteamOfficialGroupId: 'Getting Steam Official Group Id',
    subscribingForum: 'Subscribing the Steam Forum',
    unsubscribingForum: 'Unsubscribing the Steam Forum',
    gettingForumId: 'Getting Steam Forum Id',
    followingCurator: 'Following Steam Curator',
    unfollowingCurator: 'Unfollowing Steam Curator',
    gettingCuratorId: 'Getting Steam Curator Id',
    addingToWishlist: 'Adding the game to the Steam wishlist',
    removingFromWishlist: 'Removing the game from the Steam wishlist',
    followingGame: 'Following Steam games',
    unfollowingGame: 'Unfollowing Steam games',
    favoritingWorkshop: 'Favouring Steam Workshop Items',
    unfavoritingWorkshop: 'Unfavoriting Steam Workshop Items',
    gettingWorkshopAppId: 'Getting Steam Workshop Item Id',
    votingUpWorkshop: 'Liking Steam workshop items',
    gettingAnnouncementParams: 'Getting Steam announcement information',
    likingAnnouncement: 'Liking Steam announcement',
    changingArea: 'Changing Steam area: %0...',
    notNeededChangeArea: 'The current area does not need to be changed',
    noAnotherArea: 'Please check whether the proxy is turned on correctly',
    gettingAreaInfo: 'Getting Steam area information...',
    changeAreaNotice: 'Suspected of a locked zone game, try to change the zone to execute',
    steamFinishNotice: 'Steam task completed, try to change the shopping cart area back to ',
    gettingSubid: 'Getting subid',
    addingFreeLicense: 'Adding free license',
    missParams: 'Missing parameters',
    gettingLicenses: 'Getting licenses...',
    requestingPlayTestAccess: 'Requesting play test access',
    gettingDemoAppid: 'Getting demo appid for steam game',
    tryChangeAreaNotice: 'This function cannot detect whether the game is limited, so it will try to change the area before entering the library' + '. Failure to change the area will not affect the subsequent storage.',
    versionNotMatched: 'The script manager version is too low, requiring TamperMonkey >= 5.2.0 or TamperMonkey Beta >= 5.2.6196',
    gettingUserInfo: 'Getting steam user community credentials...',
    retry: 'Retry',
    owned: 'Owned',
    redirect: 'Redirect',
    noSubid: 'skip due to unrecognized',
    noASFInstance: 'ASF is not enabled, skip idle time task',
    initingASF: 'Initing ASF...',
    playingGames: 'Playing games [%0]...',
    stoppingPlayGames: 'Stopping play games...',
    stopPlayTimeTitle: 'The Steam game idle time has finished. Do you want to end it?',
    stopPlayTimeText: 'Time out: %0 minutes',
    ASFNotSupportted: 'The current function (%0) cannot be implemented by ASF, skipping',
    checkingPlayGamesStatus: 'Checking play games status...',
    gettingSteamId: 'Getting Steam ID...',
    checkingPlayStatus: 'Checking play status...',
    noPlayStatus: 'Game not running',
    servers: 'Server',
    joiningDiscordServer: 'Joining Discord Server',
    leavingDiscordServer: 'Leaving Discord Server',
    gettingDiscordGuild: 'Getting Discord server Id',
    getDiscordAuthFailed: 'Failed to get Discord token, please check whether the Discord account is logged in',
    discordImportantNotice: 'Important Reminder! ! !',
    discordImportantNoticeText: 'Due to the background update of the Discord website, currently using this script to join a group may cause the Discord account to be forcibly logged out, and two-step verification is required to log in normally, please use it with caution! ! !',
    continueDiscordTask: 'Do Discord tasks this time.',
    skipDiscordTask: 'Skip Discord tasks this time.',
    continueAndDontRemindAgain: 'Always do Discord tasks and do not remind again.',
    gettingDiscordXContextProperties: 'Getting Discord X context properties...',
    captchaNeeded: 'Captcha detected, please complete it manually!',
    users: 'User',
    loginIns: 'Please <a href="https://www.instagram.com/accounts/login/" target="_blank">log in to Instagram</a>',
    insBanned: 'Your Instagram account has been banned',
    verifyingInsAuth: 'Verifying Instagram token...',
    gettingInsUserId: 'Getting Instagram user Id',
    followingIns: 'Following Instagram user',
    unfollowingIns: 'Unfollowing Instagram user',
    reddits: 'Reddit/User',
    loginReddit: 'Please <a href="https://www.reddit.com/login/" target="_blank">log in to Reddit</a>',
    changingRedditVersion: 'Switching Reddit to a new version page...',
    joiningReddit: 'Joining the Reddit',
    leavingReddit: 'Leaving the Reddit',
    followingRedditUser: 'Following Reddit User',
    unfollowingRedditUser: 'Unfollowing Reddit User',
    channels: 'Channel',
    followingTwitchChannel: 'Following Twitch Channel',
    unfollowingTwitchChannel: 'Unfollowing Twitch Channel',
    gettingTwitchChannelId: 'Getting Twitch Channel Id',
    checkingTwitchIntegrity: 'Checking Twitch integrity...',
    twitterUser: 'Twitter User',
    retweets: 'Retweet',
    gettingTwitterUserId: 'Getting Twitter User Id',
    followingTwitterUser: 'Following Twitter User',
    unfollowingTwitterUser: 'Unfollowing Twitter User',
    retweetting: 'Retweetting',
    unretweetting: 'Unretweetting',
    names: 'Group/Public/Wall',
    loginVk: 'Please <a href="https://vk.com/login/" target="_blank">log in to Vk</a>',
    gettingVkId: 'Getting Vk task Id',
    joiningVkGroup: 'Joining Vk Group',
    leavingVkGroup: 'Leaving Vk Group',
    joiningVkPublic: 'Joining Vk Public',
    leavingVkPublic: 'Leaving Vk Public',
    sendingVkWall: 'Sending Vk Wall',
    deletingVkWall: 'Deleting Vk Wall',
    youtubeChannel: 'YouTube Channel',
    likes: 'Like',
    loginYtb: 'Please <a href="https://accounts.google.com/ServiceLogin?service=youtube" target="_blank">log in to YouTube</a>',
    tryUpdateYtbAuth: 'Please try to <a href="https://www.youtube.com/#auth" target="_blank">update YouTube token</a>',
    gettingYtbToken: 'Getting YouTube Token...',
    followingYtbChannel: 'Subscribing to YouTube channel',
    unfollowingYtbChannel: 'Unsubscribing to YouTube channel',
    likingYtbVideo: 'Liking YouTube video',
    unlikingYtbVideo: 'Unliking YouTube video',
    giveKeyNoticeBefore: 'Each verification interval is 15s',
    giveKeyNoticeAfter: 'If there is no key, please check at <a href="https://givekey.ru/profile" target="_blank">https://givekey.ru/profile</a>',
    noPoints: 'Not enough points, skip the lottery',
    getNeedPointsFailed: 'ailed to obtain the required points, skip the lottery',
    joiningLottery: 'Joining the lottery',
    doingGleamTask: 'Doing Gleam Task...',
    gettingGleamLink: 'Getting Gleam task link...',
    gleamTaskNotice: 'If this page has not been closed for a long time, please close it yourself after completing any task!',
    verifiedGleamTasks: 'Attempted to verify all tasks. If the verification fails, please try to verify manually or complete it!',
    campaign: 'ReCAPTCHA detected, please complete it manually! 3 seconds later, re-verify...',
    gsNotice: 'In order to avoid getting the "0000-0000-0000" key, the "Grab Key" button has been hidden,' + ' please close the script when obtaining the key!',
    giveeClubVerifyNotice: 'Verifying task...',
    giveeClubVerifyFinished: 'Wait for the verification to complete and join it by yourself',
    doingKeyhubTask: 'Doing Keyhub Task...',
    SweepWidgetNotice: 'The task is being processed and verified. ' + 'There is an interval of 1~3s for each verification task to prevent the triggering of too fast verification warning...',
    tasksNotCompleted: 'Tasks Not Completed',
    notConnect: 'Social platform is not connectted, skip task: %0',
    tgTaskNotice: 'The telegram task is checked, need to do it yourself!',
    updatingUserData: 'Updating user data...',
    gettingUserGames: 'Getting user games...',
    confirmingTask: 'Confirming task...',
    unSupporttedTaskType: 'Unsupportted task type: %0',
    taskNotFinished: 'There are tasks not completed, do not get the key',
    logCopied: 'Full log has been copied to the clipboard, please go to feedback!'
  };
  const languages = {
    zh: data$1,
    en: data
  };
  const SUPPORTED_LANGUAGES = [ 'zh', 'en' ];
  const getCurrentLanguage = () => {
    const userLanguage = globalOptions.other.language;
    return SUPPORTED_LANGUAGES.includes(userLanguage) ? userLanguage : 'en';
  };
  const replacePlaceholders = (text, args) => text.replace(/%([\d]+)/g, ((_, index) => args[parseInt(index, 10)] || ''));
  const I18n = (key, ...args) => {
    const currentLanguage = getCurrentLanguage();
    const translation = languages[currentLanguage]?.[key];
    if (!translation) {
      console.warn(`Missing translation for key: ${key} in language: ${currentLanguage}`);
      return key;
    }
    return replacePlaceholders(translation, args);
  };
  var DebugLevel;
  (function(DebugLevel) {
    DebugLevel['ERROR'] = 'error';
    DebugLevel['WARN'] = 'warn';
    DebugLevel['INFO'] = 'info';
    DebugLevel['DEBUG'] = 'debug';
    DebugLevel['TRACE'] = 'trace';
  })(DebugLevel || (DebugLevel = {}));
  const defaultConfig = {
    enabled: false,
    level: DebugLevel.INFO,
    prefix: 'Auto-Task',
    styles: {
      error: 'color:#ff0000;font-weight:bold',
      warn: 'color:#ffa500',
      info: 'color:#a7a7a7',
      debug: 'color:#808080',
      trace: 'color:#87ceeb'
    },
    showTimestamp: true
  };
  class Debugger {
    config;
    levelPriority;
    constructor(config = {}) {
      this.config = {
        ...defaultConfig,
        ...config
      };
      this.levelPriority = {
        error: 0,
        warn: 1,
        info: 2,
        debug: 3,
        trace: 4
      };
    }
    getTimestamp() {
      return (new Date).toLocaleString();
    }
    shouldLog(level) {
      return this.config.enabled && this.levelPriority[level] <= this.levelPriority[this.config.level];
    }
    formatMessage(level, message) {
      const parts = [ this.config.prefix ];
      if (this.config.showTimestamp) {
        parts.push(`[${this.getTimestamp()}]`);
      }
      parts.push(`[${level.toUpperCase()}]:`);
      parts.push(message);
      return parts.join(' ');
    }
    log(level, message, ...args) {
      if (!this.shouldLog(level)) {
        return;
      }
      const formattedMessage = this.formatMessage(level, message);
      const style = this.config.styles[level];
      if (args.length > 0) {
        console.groupCollapsed('%c%s', style, formattedMessage);
        args.forEach((arg => {
          console.log(util.inspect(arg, {
            showHidden: true,
            depth: null,
            colors: false
          }));
        }));
        console.groupEnd();
      } else {
        console.log('%c%s', style, formattedMessage);
      }
    }
    error(message, ...args) {
      this.log(DebugLevel.ERROR, message, ...args);
    }
    warn(message, ...args) {
      this.log(DebugLevel.WARN, message, ...args);
    }
    info(message, ...args) {
      this.log(DebugLevel.INFO, message, ...args);
    }
    debug(message, ...args) {
      this.log(DebugLevel.DEBUG, message, ...args);
    }
    trace(message, ...args) {
      this.log(DebugLevel.TRACE, message, ...args);
      if (this.shouldLog(DebugLevel.TRACE)) {
        console.trace();
      }
    }
    updateConfig(config) {
      this.config = {
        ...this.config,
        ...config
      };
    }
    enable() {
      this.config.enabled = true;
    }
    disable() {
      this.config.enabled = false;
    }
    setLevel(level) {
      this.config.level = level;
    }
  }
  let debugInstance;
  const initDebug = () => {
    if (!debugInstance) {
      debugInstance = new Debugger({
        enabled: window.DEBUG || false
      });
      if (window.DEBUG) {
        debugInstance.setLevel(DebugLevel.DEBUG);
      }
    }
    return debugInstance;
  };
  const debug = (...args) => {
    const instance = initDebug();
    return instance.debug(...args);
  };
  const getRunLogs = () => {
    debug('开始获取运行日志');
    const logElements = $('#auto-task-info>li');
    const logs = logElements.length > 0 ? $.makeArray(logElements).map((element => element.innerText)).join('\n') : '';
    debug('运行日志获取完成', {
      logsLength: logs.length
    });
    return logs;
  };
  const getEnvironmentInfo = async () => {
    debug('开始获取环境信息');
    const envInfo = {
      website: window.location.href,
      browser: JSON.stringify(await browser.getInfo(), null, 2),
      manager: `${GM_info.scriptHandler} ${GM_info.version}`,
      userScript: GM_info.script.version,
      logs: '',
      runLogs: getRunLogs()
    };
    debug('环境信息获取完成', envInfo);
    return envInfo;
  };
  const buildGithubIssueParams = async (name, errorStack, envInfo) => {
    debug('开始构建GitHub Issue参数', {
      name: name,
      errorStackLength: errorStack.length
    });
    const params = {
      title: `[BUG] 脚本报错: ${name}`,
      labels: 'bug',
      template: 'bug_report.yml',
      website: envInfo.website,
      browser: envInfo.browser,
      manager: envInfo.manager,
      'user-script': envInfo.userScript,
      logs: errorStack || '',
      'run-logs': ''
    };
    const runLogs = window.__allLogs.join('\n');
    await GM_setClipboard(runLogs);
    debug('GitHub Issue参数构建完成', params);
    return params;
  };
  const generateGithubLink = async (name, errorStack, envInfo) => {
    debug('开始生成GitHub Issue链接');
    const params = new URLSearchParams(await buildGithubIssueParams(name, errorStack, envInfo));
    const link = `https://github.com/HCLonely/auto-task/issues/new?${params.toString()}`;
    debug('GitHub Issue链接生成完成', {
      link: link
    });
    return link;
  };
  const logError = (name, errorStack) => {
    debug('记录错误日志', {
      name: name
    });
    console.log('%c%s', 'color:white;background:red', `Auto-Task[Error]: ${name}\n${errorStack}`);
  };
  const handleErrorReport = async (platform, name, errorStack, envInfo) => {
    debug('开始处理错误报告', {
      platform: platform,
      name: name
    });
    {
      const githubLink = await generateGithubLink(name, errorStack, envInfo);
      debug('打开GitHub Issue链接', {
        githubLink: githubLink
      });
      GM_openInTab(githubLink, {
        active: true
      });
    }
  };
  async function throwError(error, name) {
    debug('开始处理错误', {
      name: name,
      error: error
    });
    if (window.TRACE) {
      debug('启用跟踪模式');
      console.trace('%cAuto-Task[Trace]:', 'color:blue');
    }
    const errorStack = error.stack || '';
    logError(name, errorStack);
    debug('获取环境信息');
    const envInfo = await getEnvironmentInfo();
    envInfo.logs = errorStack;
    debug('显示错误报告对话框');
    const {isConfirmed: isConfirmed} = await Swal.fire({
      title: I18n('errorReport'),
      icon: 'error',
      showCancelButton: true,
      confirmButtonText: I18n('toGithub'),
      cancelButtonText: I18n('close')
    });
    if (isConfirmed) {
      debug('用户确认提交错误报告');
      await handleErrorReport('github', name, errorStack, envInfo);
      Swal.fire({
        title: I18n('logCopied'),
        icon: 'success',
        showConfirmButton: false,
        showCancelButton: true,
        cancelButtonText: I18n('close')
      });
    } else {
      debug('用户取消提交错误报告');
    }
  }
  const parseHeaders = headerString => {
    debug('开始解析HTTP头', {
      headerString: headerString
    });
    const headers = {};
    if (!headerString) {
      debug('HTTP头为空,返回空对象');
      return headers;
    }
    headerString.split('\n').forEach((header => {
      const [name, ...values] = header.trim().split(':');
      const value = values.join(':').trim();
      if (!name || !value) {
        return;
      }
      if (headers[name]) {
        headers[name] = Array.isArray(headers[name]) ? [ ...headers[name], value ] : [ headers[name], value ];
      } else {
        headers[name] = value;
      }
    }));
    if (headers['set-cookie'] && !Array.isArray(headers['set-cookie'])) {
      headers['set-cookie'] = [ headers['set-cookie'] ];
    }
    debug('HTTP头解析完成', {
      headers: headers
    });
    return headers;
  };
  const processResponse = (data, options) => {
    debug('开始处理响应数据', {
      responseType: options.responseType
    });
    const headers = parseHeaders(data.responseHeaders);
    data.responseHeadersText = data.responseHeaders;
    data.responseHeaders = headers;
    data.finalUrl = headers.location || data.finalUrl;
    debug('响应头处理完成', {
      finalUrl: data.finalUrl
    });
    if (options.responseType === 'json' && data?.response && typeof data.response !== 'object') {
      debug('尝试解析JSON响应');
      try {
        data.response = JSON.parse(data.responseText);
        debug('JSON解析成功');
      } catch {
        debug('JSON解析失败,保持原始响应');
      }
    }
  };
  const httpRequest = async (options, times = 0) => {
    debug('开始HTTP请求', {
      url: options.url,
      method: options.method,
      retryTimes: times
    });
    if (window.TRACE) {
      console.trace('%cAuto-Task[Trace]:', 'color:blue');
    }
    try {
      const result = await new Promise((resolve => {
        const requestObj = {
          fetch: true,
          timeout: 3e4,
          ontimeout: data => {
            debug('请求超时', {
              url: options.url
            });
            resolve({
              result: 'Error',
              statusText: 'Timeout',
              status: 601,
              data: data,
              options: options
            });
          },
          onabort: () => {
            debug('请求被中止', {
              url: options.url
            });
            resolve({
              result: 'Error',
              statusText: 'Aborted',
              status: 602,
              data: undefined,
              options: options
            });
          },
          onerror: data => {
            debug('请求发生错误', {
              url: options.url,
              error: data
            });
            resolve({
              result: 'Error',
              statusText: 'Error',
              status: 603,
              data: data,
              options: options
            });
          },
          onload: data => {
            debug('请求加载完成', {
              url: options.url,
              status: data.status
            });
            processResponse(data, options);
            resolve({
              result: 'Success',
              statusText: 'Load',
              status: 600,
              data: data,
              options: options
            });
          },
          ...options,
          responseType: options.dataType || options.responseType
        };
        debug('发送请求', {
          requestObj: requestObj
        });
        GM_xmlhttpRequest(requestObj);
      }));
      if (window.DEBUG) {
        console.log('%cAuto-Task[httpRequest]:', 'color:blue', result);
      }
      if (result.status !== 600 && times < 2) {
        debug('请求失败,准备重试', {
          status: result.status,
          retryTimes: times + 1
        });
        return await httpRequest(options, times + 1);
      }
      debug('请求完成', {
        status: result.status,
        result: result.result
      });
      return result;
    } catch (error) {
      debug('请求发生JavaScript错误', {
        error: error
      });
      console.log('%cAuto-Task[httpRequest]:', 'color:red', JSON.stringify({
        errorMsg: error,
        options: options
      }));
      throwError(error, 'httpRequest');
      return {
        result: 'JsError',
        statusText: 'Error',
        status: 604,
        error: error,
        options: options
      };
    }
  };
  var ASF = '<?xml version="1.0" encoding="UTF-8"?>\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" version="1.1">\n<g id="surface1">\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,17.254902%,26.274511%);fill-opacity:1;" d="M 7.652344 0.175781 C 8.046875 0.351562 8.210938 0.59375 8.441406 0.953125 C 9.007812 1.746094 9.644531 2.539062 10.640625 2.761719 C 12.011719 2.949219 13.429688 2.882812 14.808594 2.796875 C 14.90625 2.792969 15.003906 2.785156 15.101562 2.78125 C 15.1875 2.773438 15.273438 2.769531 15.363281 2.761719 C 15.429688 2.769531 15.496094 2.777344 15.566406 2.78125 C 15.761719 3.082031 15.757812 3.191406 15.75 3.539062 C 15.75 3.625 15.746094 3.710938 15.746094 3.800781 C 15.742188 3.867188 15.742188 3.933594 15.738281 4 C 15.824219 4.027344 15.910156 4.058594 16 4.085938 C 15.988281 4.34375 15.976562 4.597656 15.960938 4.851562 C 15.957031 4.925781 15.957031 5 15.953125 5.074219 C 15.945312 5.175781 15.945312 5.175781 15.941406 5.285156 C 15.9375 5.378906 15.9375 5.378906 15.929688 5.480469 C 15.914062 5.652344 15.914062 5.652344 15.824219 5.914062 C 15.816406 6.058594 15.8125 6.203125 15.8125 6.34375 C 15.8125 6.433594 15.8125 6.519531 15.808594 6.613281 C 15.808594 6.707031 15.808594 6.800781 15.808594 6.898438 C 15.804688 7.097656 15.804688 7.300781 15.800781 7.5 C 15.796875 7.816406 15.792969 8.132812 15.792969 8.449219 C 15.789062 8.753906 15.785156 9.058594 15.78125 9.363281 C 15.78125 9.457031 15.78125 9.550781 15.78125 9.648438 C 15.777344 9.738281 15.777344 9.824219 15.773438 9.914062 C 15.773438 10.03125 15.773438 10.03125 15.773438 10.148438 C 15.738281 10.347656 15.738281 10.347656 15.625 10.503906 C 15.386719 10.671875 15.152344 10.625 14.871094 10.609375 C 14.867188 10.675781 14.859375 10.742188 14.855469 10.808594 C 14.816406 11.367188 14.746094 11.890625 14.609375 12.433594 C 14.3125 12.535156 14.105469 12.507812 13.804688 12.441406 C 13.6875 12.414062 13.6875 12.414062 13.570312 12.390625 C 13.480469 12.367188 13.480469 12.367188 13.390625 12.347656 C 13.359375 12.515625 13.359375 12.515625 13.324219 12.683594 C 13.226562 13.144531 13.054688 13.566406 12.871094 14 C 12.75 13.988281 12.628906 13.980469 12.511719 13.96875 C 12.410156 13.957031 12.410156 13.957031 12.308594 13.949219 C 12.050781 13.90625 11.8125 13.828125 11.566406 13.738281 C 11.492188 13.867188 11.492188 13.867188 11.417969 14 C 11.355469 14.113281 11.292969 14.222656 11.226562 14.335938 C 11.195312 14.394531 11.164062 14.449219 11.132812 14.507812 C 11 14.738281 10.882812 14.941406 10.695312 15.128906 C 10.257812 15.097656 9.957031 14.863281 9.601562 14.625 C 9.402344 14.503906 9.402344 14.503906 9.222656 14.542969 C 9.015625 14.617188 8.925781 14.703125 8.777344 14.863281 C 8.730469 14.914062 8.683594 14.964844 8.632812 15.019531 C 8.535156 15.125 8.433594 15.234375 8.335938 15.339844 C 7.972656 15.726562 7.972656 15.726562 7.675781 15.792969 C 7.4375 15.726562 7.367188 15.660156 7.21875 15.460938 C 7 15.1875 6.773438 14.941406 6.523438 14.695312 C 6.375 14.550781 6.230469 14.40625 6.085938 14.261719 C 6.023438 14.195312 5.957031 14.128906 5.890625 14.0625 C 2.175781 10.347656 2.175781 10.347656 1.945312 10.117188 C 1.738281 9.910156 1.527344 9.707031 1.316406 9.503906 C 1.160156 9.351562 1 9.199219 0.84375 9.042969 C 0.722656 8.925781 0.722656 8.925781 0.597656 8.808594 C 0.519531 8.734375 0.445312 8.660156 0.363281 8.582031 C 0.296875 8.515625 0.226562 8.445312 0.152344 8.375 C -0.03125 8.132812 -0.0351562 8.039062 0 7.738281 C 0.117188 7.570312 0.117188 7.570312 0.28125 7.402344 C 0.34375 7.339844 0.40625 7.277344 0.472656 7.210938 C 0.542969 7.144531 0.613281 7.074219 0.683594 7.003906 C 0.757812 6.933594 0.828125 6.859375 0.902344 6.785156 C 1.101562 6.585938 1.304688 6.386719 1.503906 6.1875 C 1.714844 5.980469 1.921875 5.773438 2.132812 5.5625 C 2.480469 5.214844 2.832031 4.863281 3.183594 4.515625 C 3.683594 4.023438 4.175781 3.53125 4.671875 3.039062 C 5.015625 2.695312 5.359375 2.355469 5.699219 2.015625 C 5.785156 1.929688 5.867188 1.847656 5.949219 1.765625 C 6.222656 1.492188 6.496094 1.222656 6.773438 0.949219 C 6.839844 0.882812 6.910156 0.8125 6.980469 0.742188 C 7.078125 0.648438 7.078125 0.648438 7.171875 0.550781 C 7.226562 0.496094 7.285156 0.441406 7.339844 0.386719 C 7.476562 0.261719 7.476562 0.261719 7.652344 0.175781 Z M 7.652344 0.175781 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(5.490196%,7.843138%,14.901961%);fill-opacity:1;" d="M 10.433594 2.78125 C 11.101562 2.777344 11.765625 2.773438 12.433594 2.769531 C 12.742188 2.769531 13.050781 2.765625 13.359375 2.761719 C 13.714844 2.757812 14.070312 2.757812 14.425781 2.757812 C 14.539062 2.753906 14.648438 2.753906 14.761719 2.753906 C 14.867188 2.753906 14.96875 2.753906 15.074219 2.753906 C 15.210938 2.753906 15.210938 2.753906 15.347656 2.75 C 15.421875 2.761719 15.492188 2.773438 15.566406 2.78125 C 15.761719 3.082031 15.757812 3.191406 15.75 3.539062 C 15.75 3.625 15.746094 3.710938 15.746094 3.800781 C 15.742188 3.867188 15.742188 3.933594 15.738281 4 C 15.824219 4.027344 15.910156 4.058594 16 4.085938 C 15.988281 4.332031 15.980469 4.578125 15.96875 4.824219 C 15.964844 4.929688 15.964844 4.929688 15.960938 5.035156 C 15.9375 5.492188 15.863281 5.90625 15.738281 6.347656 C 15.675781 6.3125 15.613281 6.273438 15.546875 6.234375 C 15.011719 5.921875 14.472656 5.609375 13.9375 5.296875 C 13.761719 5.195312 13.582031 5.089844 13.40625 4.988281 C 12.996094 4.746094 12.585938 4.507812 12.167969 4.273438 C 10.847656 3.527344 10.847656 3.527344 10.433594 2.957031 C 10.433594 2.898438 10.433594 2.839844 10.433594 2.78125 Z M 10.433594 2.78125 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(95.686275%,96.078432%,96.470588%);fill-opacity:1;" d="M 7.566406 5.304688 C 7.878906 5.410156 7.90625 5.480469 8.058594 5.761719 C 8.117188 5.859375 8.117188 5.859375 8.175781 5.964844 C 8.269531 6.195312 8.277344 6.363281 8.261719 6.609375 C 8.355469 6.550781 8.449219 6.492188 8.550781 6.433594 C 8.777344 6.296875 8.855469 6.261719 9.128906 6.261719 C 9.136719 6.425781 9.140625 6.589844 9.148438 6.753906 C 9.152344 6.894531 9.152344 6.894531 9.15625 7.035156 C 9.125 7.34375 9.058594 7.492188 8.871094 7.738281 C 8.703125 7.871094 8.703125 7.871094 8.527344 7.972656 C 8.46875 8.007812 8.410156 8.042969 8.351562 8.078125 C 8.292969 8.109375 8.234375 8.140625 8.175781 8.175781 C 8.113281 8.207031 8.054688 8.238281 7.996094 8.273438 C 7.710938 8.398438 7.511719 8.335938 7.21875 8.261719 C 6.832031 8.070312 6.476562 7.859375 6.261719 7.476562 C 6.167969 7.203125 6.164062 7.007812 6.167969 6.722656 C 6.167969 6.636719 6.171875 6.550781 6.171875 6.460938 C 6.171875 6.394531 6.171875 6.328125 6.175781 6.261719 C 6.492188 6.332031 6.753906 6.457031 7.042969 6.609375 C 7.050781 6.480469 7.050781 6.480469 7.058594 6.347656 C 7.113281 5.9375 7.332031 5.636719 7.566406 5.304688 Z M 7.566406 5.304688 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(5.882353%,8.235294%,15.294118%);fill-opacity:1;" d="M 15.652344 6.433594 C 15.679688 6.433594 15.710938 6.433594 15.738281 6.433594 C 15.746094 6.988281 15.75 7.539062 15.753906 8.09375 C 15.753906 8.28125 15.757812 8.46875 15.757812 8.65625 C 15.761719 8.925781 15.761719 9.195312 15.765625 9.464844 C 15.765625 9.550781 15.765625 9.636719 15.769531 9.722656 C 15.769531 9.800781 15.769531 9.878906 15.769531 9.960938 C 15.769531 10.027344 15.769531 10.097656 15.769531 10.167969 C 15.730469 10.398438 15.664062 10.472656 15.476562 10.609375 C 15.15625 10.625 15.15625 10.625 14.871094 10.609375 C 14.867188 10.675781 14.859375 10.742188 14.855469 10.808594 C 14.816406 11.367188 14.746094 11.890625 14.609375 12.433594 C 14.3125 12.535156 14.105469 12.507812 13.804688 12.441406 C 13.726562 12.421875 13.648438 12.40625 13.570312 12.390625 C 13.480469 12.367188 13.480469 12.367188 13.390625 12.347656 C 13.449219 12.027344 13.535156 11.730469 13.644531 11.425781 C 13.679688 11.332031 13.710938 11.238281 13.746094 11.144531 C 13.78125 11.046875 13.816406 10.953125 13.851562 10.851562 C 13.902344 10.710938 13.902344 10.710938 13.957031 10.566406 C 14.054688 10.289062 14.160156 10.015625 14.261719 9.738281 C 14.292969 9.65625 14.320312 9.574219 14.351562 9.488281 C 14.613281 8.792969 14.613281 8.792969 14.929688 8.523438 C 15.359375 8.140625 15.347656 7.753906 15.40625 7.203125 C 15.441406 6.886719 15.472656 6.707031 15.652344 6.433594 Z M 15.652344 6.433594 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(13.725491%,18.431373%,37.254903%);fill-opacity:1;" d="M 13.566406 9.824219 C 13.609375 9.914062 13.609375 9.914062 13.652344 10 C 13.539062 10.21875 13.417969 10.425781 13.289062 10.636719 C 13.207031 10.769531 13.125 10.90625 13.046875 11.039062 C 13.003906 11.109375 12.960938 11.183594 12.914062 11.253906 C 12.691406 11.632812 12.46875 12.015625 12.25 12.398438 C 12.207031 12.472656 12.160156 12.550781 12.117188 12.628906 C 11.8125 13.160156 11.53125 13.703125 11.269531 14.253906 C 11.113281 14.582031 10.933594 14.855469 10.695312 15.128906 C 10.3125 15.078125 10.042969 14.933594 9.710938 14.734375 C 9.574219 14.648438 9.574219 14.648438 9.429688 14.566406 C 9.359375 14.523438 9.289062 14.480469 9.21875 14.433594 C 9.253906 14.046875 9.523438 13.835938 9.789062 13.582031 C 9.832031 13.539062 9.875 13.496094 9.921875 13.449219 C 10.15625 13.21875 10.402344 12.996094 10.65625 12.78125 C 11.15625 12.34375 11.621094 11.871094 12.089844 11.398438 C 12.25 11.238281 12.414062 11.078125 12.574219 10.914062 C 12.679688 10.8125 12.78125 10.707031 12.886719 10.605469 C 12.933594 10.554688 12.980469 10.507812 13.03125 10.457031 C 13.234375 10.253906 13.40625 10.066406 13.566406 9.824219 Z M 13.566406 9.824219 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(95.294118%,95.686275%,96.078432%);fill-opacity:1;" d="M 6.175781 10.347656 C 6.503906 10.464844 6.769531 10.617188 7.054688 10.820312 C 7.128906 10.871094 7.203125 10.925781 7.277344 10.976562 C 7.445312 11.105469 7.59375 11.234375 7.738281 11.390625 C 7.769531 11.316406 7.769531 11.316406 7.800781 11.238281 C 7.941406 10.992188 8.105469 10.882812 8.335938 10.722656 C 8.410156 10.671875 8.488281 10.617188 8.566406 10.5625 C 8.761719 10.449219 8.90625 10.386719 9.128906 10.347656 C 9.21875 11.453125 9.21875 11.453125 8.914062 11.832031 C 8.617188 12.113281 8.285156 12.273438 7.914062 12.433594 C 7.882812 12.921875 7.855469 13.410156 7.824219 13.914062 C 7.683594 13.914062 7.539062 13.914062 7.390625 13.914062 C 7.390625 13.398438 7.390625 12.878906 7.390625 12.347656 C 7.246094 12.320312 7.105469 12.289062 6.957031 12.261719 C 6.5625 12.078125 6.359375 11.875 6.175781 11.476562 C 6.144531 11.097656 6.152344 10.726562 6.175781 10.347656 Z M 6.175781 10.347656 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(8.235294%,11.764706%,23.137255%);fill-opacity:1;" d="M 14.433594 9.042969 C 14.523438 9.21875 14.523438 9.21875 14.484375 9.378906 C 14.460938 9.445312 14.4375 9.507812 14.414062 9.574219 C 14.386719 9.648438 14.359375 9.71875 14.335938 9.792969 C 14.308594 9.871094 14.277344 9.949219 14.25 10.027344 C 14.222656 10.105469 14.195312 10.183594 14.164062 10.265625 C 14.007812 10.703125 13.84375 11.132812 13.675781 11.566406 C 13.503906 11.996094 13.386719 12.429688 13.285156 12.878906 C 13.179688 13.269531 13.03125 13.632812 12.871094 14 C 12.378906 13.96875 12 13.910156 11.566406 13.652344 C 11.703125 13.144531 11.960938 12.71875 12.222656 12.265625 C 12.269531 12.1875 12.316406 12.105469 12.363281 12.023438 C 12.460938 11.859375 12.554688 11.695312 12.648438 11.53125 C 12.765625 11.332031 12.882812 11.128906 12.996094 10.925781 C 13.402344 10.222656 13.859375 9.621094 14.433594 9.042969 Z M 14.433594 9.042969 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 10.433594 2.78125 C 11.101562 2.777344 11.765625 2.773438 12.433594 2.769531 C 12.742188 2.769531 13.050781 2.765625 13.359375 2.761719 C 13.714844 2.757812 14.070312 2.757812 14.425781 2.757812 C 14.539062 2.753906 14.648438 2.753906 14.761719 2.753906 C 14.867188 2.753906 14.96875 2.753906 15.074219 2.753906 C 15.210938 2.753906 15.210938 2.753906 15.347656 2.75 C 15.421875 2.761719 15.492188 2.773438 15.566406 2.78125 C 15.761719 3.082031 15.757812 3.191406 15.75 3.539062 C 15.75 3.625 15.746094 3.710938 15.746094 3.800781 C 15.742188 3.867188 15.742188 3.933594 15.738281 4 C 14.917969 3.957031 14.128906 3.839844 13.324219 3.6875 C 13.066406 3.640625 12.808594 3.59375 12.546875 3.550781 C 12.363281 3.515625 12.175781 3.484375 11.992188 3.449219 C 11.78125 3.414062 11.566406 3.378906 11.355469 3.34375 C 11.226562 3.324219 11.226562 3.324219 11.097656 3.304688 C 11.027344 3.292969 10.953125 3.28125 10.878906 3.273438 C 10.664062 3.207031 10.570312 3.132812 10.433594 2.957031 C 10.433594 2.898438 10.433594 2.839844 10.433594 2.78125 Z M 10.433594 2.78125 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(95.686275%,96.078432%,96.470588%);fill-opacity:1;" d="M 9.128906 8.261719 C 9.183594 9.257812 9.183594 9.257812 9.011719 9.695312 C 8.605469 10.082031 8.152344 10.3125 7.597656 10.398438 C 7.09375 10.3125 6.6875 10.128906 6.347656 9.738281 C 6.074219 9.320312 6.136719 8.828125 6.175781 8.347656 C 6.539062 8.394531 6.765625 8.519531 7.066406 8.734375 C 7.140625 8.789062 7.214844 8.839844 7.292969 8.894531 C 7.476562 9.042969 7.476562 9.042969 7.566406 9.21875 C 7.621094 9.21875 7.679688 9.21875 7.738281 9.21875 C 7.835938 9.117188 7.933594 9.015625 8.03125 8.914062 C 8.738281 8.261719 8.738281 8.261719 9.128906 8.261719 Z M 9.128906 8.261719 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(7.843138%,11.372549%,22.745098%);fill-opacity:1;" d="M 11.042969 3.476562 C 11.648438 3.675781 12.246094 3.886719 12.84375 4.101562 C 12.984375 4.152344 12.984375 4.152344 13.125 4.207031 C 14.054688 4.542969 14.984375 4.878906 15.914062 5.21875 C 15.867188 5.597656 15.816406 5.972656 15.738281 6.347656 C 15.675781 6.3125 15.613281 6.273438 15.546875 6.234375 C 15.011719 5.921875 14.472656 5.609375 13.9375 5.296875 C 13.667969 5.140625 13.402344 4.984375 13.132812 4.828125 C 12.804688 4.636719 12.476562 4.445312 12.148438 4.253906 C 12.011719 4.179688 11.878906 4.101562 11.746094 4.023438 C 11.683594 3.988281 11.621094 3.949219 11.558594 3.914062 C 11.140625 3.671875 11.140625 3.671875 11.042969 3.476562 Z M 11.042969 3.476562 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0.392157%);fill-opacity:1;" d="M 15.652344 6.433594 C 15.679688 6.433594 15.710938 6.433594 15.738281 6.433594 C 15.746094 6.988281 15.75 7.539062 15.753906 8.09375 C 15.753906 8.28125 15.757812 8.46875 15.757812 8.65625 C 15.761719 8.925781 15.761719 9.195312 15.765625 9.464844 C 15.765625 9.550781 15.765625 9.636719 15.769531 9.722656 C 15.769531 9.839844 15.769531 9.839844 15.769531 9.960938 C 15.769531 10.027344 15.769531 10.097656 15.769531 10.167969 C 15.730469 10.394531 15.664062 10.472656 15.476562 10.609375 C 15.199219 10.625 15.199219 10.625 14.957031 10.609375 C 14.875 10.285156 14.871094 10.046875 14.933594 9.71875 C 14.949219 9.636719 14.964844 9.550781 14.980469 9.464844 C 15 9.378906 15.015625 9.289062 15.03125 9.199219 C 15.050781 9.113281 15.066406 9.027344 15.082031 8.933594 C 15.203125 8.289062 15.203125 8.289062 15.304688 8.085938 C 15.34375 7.792969 15.375 7.5 15.40625 7.203125 C 15.441406 6.886719 15.472656 6.707031 15.652344 6.433594 Z M 15.652344 6.433594 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(86.274511%,87.450981%,89.019608%);fill-opacity:1;" d="M 8.609375 3.390625 C 8.78125 3.390625 8.953125 3.390625 9.128906 3.390625 C 9.128906 4.109375 9.128906 4.824219 9.128906 5.566406 C 8.988281 5.59375 8.84375 5.621094 8.695312 5.652344 C 8.609375 5.566406 8.609375 5.566406 8.597656 5.355469 C 8.597656 5.265625 8.601562 5.175781 8.601562 5.082031 C 8.601562 4.984375 8.601562 4.886719 8.601562 4.785156 C 8.601562 4.683594 8.601562 4.578125 8.601562 4.472656 C 8.605469 4.371094 8.605469 4.265625 8.605469 4.160156 C 8.605469 3.902344 8.605469 3.648438 8.609375 3.390625 Z M 8.609375 3.390625 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(93.725491%,94.117647%,94.509804%);fill-opacity:1;" d="M 6.175781 3.390625 C 6.316406 3.390625 6.460938 3.390625 6.609375 3.390625 C 6.609375 4.136719 6.609375 4.882812 6.609375 5.652344 C 6.464844 5.625 6.320312 5.59375 6.175781 5.566406 C 6.175781 4.847656 6.175781 4.128906 6.175781 3.390625 Z M 6.175781 3.390625 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(93.333334%,93.725491%,94.117647%);fill-opacity:1;" d="M 7.476562 2.433594 C 7.59375 2.433594 7.707031 2.433594 7.824219 2.433594 C 7.824219 3.179688 7.824219 3.925781 7.824219 4.695312 C 7.683594 4.695312 7.539062 4.695312 7.390625 4.695312 C 7.390625 4.335938 7.386719 3.976562 7.386719 3.613281 C 7.386719 3.511719 7.382812 3.410156 7.382812 3.300781 C 7.382812 3.203125 7.382812 3.105469 7.382812 3.003906 C 7.382812 2.914062 7.382812 2.824219 7.382812 2.730469 C 7.390625 2.523438 7.390625 2.523438 7.476562 2.433594 Z M 7.476562 2.433594 "/>\n<path style=" stroke:none;fill-rule:nonzero;fill:rgb(5.490196%,7.843138%,14.901961%);fill-opacity:1;" d="M 15.390625 6.871094 C 15.511719 7.203125 15.449219 7.484375 15.390625 7.824219 C 15.304688 7.769531 15.21875 7.710938 15.128906 7.652344 C 15.171875 7.328125 15.207031 7.148438 15.390625 6.871094 Z M 15.390625 6.871094 "/>\n</g>\n</svg>\n';
  var Web = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="16" height="16">\n\t<title>favicon</title>\n\t<defs>\n\t\t<image  width="256" height="256" id="img1" href="data:image/png;base64,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"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>\n';
  var Discord$1 = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="16" height="16">\n\t<title>favicon</title>\n\t<defs>\n\t\t<image  width="256" height="256" id="img1" href="data:image/png;base64,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"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>\n';
  var Twitch$1 = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="16" height="16">\n\t<title>favicon-32-e29e246c157142c94346</title>\n\t<defs>\n\t\t<image  width="28" height="32" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgBAMAAADzmwVxAAAAAXNSR0IB2cksfwAAACdQTFRFAAAAk0b/kUb/////wZf/yKP/j0b/j0X/j0b/kUb/j0D/kUb/j0j/8nvBLQAAAA10Uk5TAH//////gJCgzxDfIMV/78EAAACZSURBVHicY2RgYFRkgANGBgYhAWQuUFIQxnvPCJJE4oJ0InFBOpG4Sgxg7ntBMKI9F81ebFzGdyhc+SvIXKa3dshc+as3kbhMb+MawFygANNbBga2GwwwrvwFBoaKNBhXGCjJXp4A4xoAJWe4McC4QMA51QGZO8sFEuwMDEoQKQS3KoUBiQsyFIkb18CAxFW/yYDMTVgA4wIAtrc0x9ZZthYAAAAASUVORK5CYII="/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="2" y="0"/>\n</svg>\n';
  var Instagram = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76" width="16" height="16">\n\t<title>lam-fZmwmvn</title>\n\t<defs>\n\t\t<image  width="76" height="76" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAMAAADwSaEZAAAAAXNSR0IB2cksfwAAAvdQTFRFR3BM1TeUehf6exj7gBn8bxf9bxX9eA32hAnukgXlngTjqATisAPguQLewAThxAHdygLd0AHazwDU3gDA3gDB7ROe1gDY3wDI2gDHYBlFeBf9cxn8gRf9ihf9kQvx3ADW6AC/kRf9oQzxrw3v4wDX5gDO7AC0uAnomRf86wDV8ADG8QPR8wC69AqfoBf8qBf74BTc6xTW8wCr9xOVvzT24WHu3oP39qzy9sr5+N78/ej6/t31+Xrj+lbX9xvS9wnJ//7+//////n69QCesRn7/gLD/gG+/gGy/8vq/ivO/gG5//X7/QKq9wea6k3l+zrS+yq8/gCj+ACPuhr6/gq3/gCc7xbO/A/BxRr4/RO4/gCW/VDD/2nM/gCQ0hzz/7Pe/gGJ/gmw/UG4+h2r/gGC3Bru6Bvd/QJ79BrD/hOt/pDO5Rro/hKk9xu2/gJ08Brf+x6g/hKY/S+j/QJt/SCW/hOQ/SKQ/m+3/haH/SKI/lul/+vw/QBn/EOT/h2B/hV8/iF6/iR0/idu/uHk/i1//QFi/its/oar/T94/ixm/Spd/mON/lZw/snV/i5V/omZ/hNw/kNZ//r2/jNO/jtT/jNi/gBf/l1c/jpJ/nh//tfS/jlc/jFH/jND/khR/jk//T9D/hFn/ipM/kM6/js1/kZB/sS1/R1k/lA9/Us1/kEq/oN1/qmz/g5c/nNI/lEv/hZb/lg2/kgf/h5Z/lgq/lQX/l8m/mI4/iJS/mMY/oxO/mch/mcv/FEP/FwG/pdo/m0b/WUB/rd//mwC/nQY/nQn/m4s/nMC/qOJ/ndk/vHc/noV/noC/oQd/p0//oIS/nsi/unI/tuq/oIC/rA9/ooB/owT/vbn/pAE/pUP/pYB/pwI/p0A/qkf/tBr/GMY/XQD+3QI/qQC/qoC/td8+4QW/q8A/rsW/rQA/rgA/rsA/r4A/YUD/SGH/sEA/JUF/sUA/JIG/skA/DJm/JgH/asD/s0A/EFI+68J/bcE+1E0+0w6/L0Fi9deiwAAAP10Uk5TAA5AcL3X////////////////5a9+QP//zwL/nP////////////////7/////xP//////df/////////////////////////////////l/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+XBcP///z/////////V1f+M/6v/oavV/9VwwMFw5VUJIaQAAAukSURBVHicbZhbbBxXGYD/f2Zn9uZL7NiNL4nTFLnUqZpKlaqKRCBIgApIWhKE1PahPKAiRFNaCdSqL4U+0odKlUorQXkAoSCQQLRqSwlKpIKaFAJNlFtDTdzarr221/a63uvc+S9nZ9eB8Xr27Myc7/zXc/4zCOmBcph2wg35kZ7wxg9Kl9WkQ0gbltVp/y8q/Qik3XZYhHAt2QIbhWU7RQ3B2va1/y8QYEpUko4aZUqjAKVRReBYOSUBrA3D6nD5JmqVsSMJWLAFBJCHJuZa3IrWktHSaAm7WEOCoz4oJFjtkCzoVk1AdLQURe3qetIeilkpiS9lIshwawlTUofDnZ2A/tQUm/lmHty19ZES/x61ykpKx7cjRi2PLI8vqs9Svdq81EtAVDq7sO4wbHR5pBtFmCz4plViEDJhC4cFo3MozYawACplcgBmhg1pC4qaJbrKpDZIEe0jJILERKOnxrDsZRLV3mGlQZIhlAtYS1G7u+JHjpaVNhPU+Gr08PA9gP9CtEduQEENBiQXcAumjY0gcRDXYGhVaAz3XRYtuIzWmLGkaMgsx7Jy3CvR0w2sBKwYIWllNGHWYqH10GngItpjDApZKkENb9pZxhOqm4byW12olwK0XSiNLQKMc5QOAGxgZpfcMihwMjkjqbELSHc0jS2XchixQtGCoa3gbfKEq0oMbzg5MELxx8rfYLNmDGmEJej3IcyNQ3kMFkkwKOC+jj2GYcPJ8qMJeLEzKNb3b6BxeCZBxtEe/rAfcdws7t6k3/14pz7DsQb9C2L5wuqOOUAOgiEjcjsK0qOwNNRg+bI9VY5BBzYHiYpfTB/oh/kCs7wggFpv644rjBpc7zJgt1ebkcteCosO0zYH1/vp8jfaDzjBLBksQW9ojh/2KV/dwQpIzGjmqKGMHzJOOUtm9SeqDj/iAE0g+ABnqibKTJHGLq5Q4mLr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"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>';
  var Twitter$1 = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="16" height="16">\n\t<title>icon-ios</title>\n\t<defs>\n\t\t<image  width="1024" height="1024" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAMAAABIw9uxAAAAAXNSR0IB2cksfwAAAwBQTFRFAAAABAQEFxcXGBgYDAwMERERCgoKfn5+wMDAv7+/k5OTFhYWKioqp6enq6urJycnPDw83Nzc////+/v7f39/BwcHKSkpu7u78vLyc3NzXl5e7+/v6+vrU1NTExMTra2t9/f3e3t7BgYGCQkJiIiI+fn50tLSLy8vDw8Pjo6O/f39mJiYrq6ur6+vGRkZCAgIh4eH/v7+Gxsb1NTUhISEAQEBZGRk8PDwvLy8ICAgVVVV6enp7OzsVlZWAwMDWFhY4+Pj0NDQODg4AgIC1tbWNTU1QkJC4eHh2NjYPz8/pKSktLS0Li4uxcXFy8vL+vr6wsLC7u7ubW1tBQUFSEhI5eXl8/PzfHx89vb2Nzc3EhISkpKS/Pz8nZ2dEBAQDQ0NuLi4hYWFIyMjwcHBi4uLYmJi7e3tvr6+Q0ND3d3dXFxczMzMZ2dn8fHx29vbOzs72traQEBAj4+Pvb29Hh4eMjIyx8fHHR0dt7e3JiYmaGhoNjY2oaGh39/fmZmZpqamFRUVrKysl5eXZmZmw8PDJCQkMDAwz8/Pa2tr6urqycnJMzMzUFBQ4uLifX19+Pj4xMTE5+fnFBQUo6OjnJycISEhb29vR0dH5OTkRUVFmpqalJSUcHBw9fX1xsbGJSUleHh4Dg4ObGxsKCgodHR0QUFB5ubmPj4+1dXV4ODgGhoaubm5eXl5hoaGOTk56Ojom5ubkZGRXV1dd3d3qKioUVFRysrKRkZGqqqqtra29PT0aWlpg4ODHBwcCwsLlpaWenp6sbGxcXFxT09Pzs7O19fXSkpK3t7e2dnZIiIijIyMgICAYGBgbm5u0dHRUlJScnJylZWVsLCwurq6Tk5OVFRU09PTNDQ0Ojo6KysrPT09Y2NjZWVlW1tbjY2NtbW1yMjIYWFhn5+fWlpadnZ2TU1Nzc3NpaWlLS0tgYGBV1dXoqKiWVlZS0tLdXV1s7OzHx8fgoKCoKCgkJCQREREX19fTExMSUlJqampMTExLCwsiYmJsrKyampqioqKnp6enA0qUQAAUvtJREFUeJzt3X1gjmX/P/DrZFt5aNTQ4reNzTC5Lasrj9tks7Kk1iwNbR5KMVHa8rDGPM00NzeNodCEydMippIVlqhMSTGR4ksSIk+F7HfXfd9luGzXcb2P6zyv83i//vne9/fb8TnOb+y96zrO4/gcmoWIlKXp/QBEpB8GAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwB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ABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHCGABECmMAECmMAUCkMAYAkcIYAEQKYwAQKYwBQKQwBgCRwhgARApjABApjAFApDAGAJHC/j9GYmsPmw8LugAAAABJRU5ErkJggg=="/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>\n';
  var Reddit$1 = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 192" width="16" height="16">\n\t<title>192x192</title>\n\t<defs>\n\t\t<image  width="192" height="192" id="img1" href="data:image/png;base64,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"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>';
  var Youtube$1 = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="16" height="16">\n\t<title>favicon_48x48</title>\n\t<defs>\n\t\t<image  width="48" height="48" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAAXNSR0IB2cksfwAAARRQTFRF////AAAA/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/xBA/wAz/56x/5uv/xZF/wAz/wAz/6Cz/////+/y/26L/wQ2/wAz/wAz/9Pc/0Bm/6m6/x1K/wAz//X3/3uV/wg5/wAz/93k/01x/7fF/yVR/yZR/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAz/wAzgb8Y2wAAAFx0Uk5TAAAJNFp0i52ptMDQ3ODl8Pj/99uoWS+z+zD6uxL+DEhAcm2Vkav/v////7zU///////T6P/////0////8///////8ufSlEEUDVe1/bkyOF13jKC2wd3mqp92XDdJ2BKpAAABRElEQVR4nO2VwUtCQRDG53vV0/DwEhNDXoREdCjC0CK6Rlj9vYHdg04SiSAUEUFE8gwJi0roNb0tHwS7Gzu3iOawh5nvt+zOzs6AhIZ/wAXA1/rdxl7ERMz+K3PukXlmwJwCRWDksHeGvd4nMDv14nic6ShOAK/kqk+Itz5QfnbWE/kRQjwJgIyPhaFATxSg8iAC8lgciIAClu41Z7FvByawHGnOEnBnA8pYvdWcoaqPazNQQe3KACQJx6URiBF4RoAoiwsD8I6tcwtAOaCrxVaQ13cJ008SoKMFfwTUO7WFgHcmAYxHEl56XZ7WnVMjYH84YWnU5MUnLu/dlj1qsIL8iwqbwAYaXVGbqcobGeYgbJW015Y14yTvdZw4yLeBw3SgzFdVNXTW0Dw42myNvWqANJrM+zyJURY4vlHS3zgU/wDwAXpXWYPo2LOhAAAAAElFTkSuQmCC"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>';
  var Vk$1 = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="16" height="16">\n\t<title>fav_logo</title>\n\t<defs>\n\t\t<image  width="256" height="256" id="img1" href="data:image/png;base64,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"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>';
  var AutoTask = '<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="16" height="16">\n\t<title>favicon</title>\n\t<defs>\n\t\t<image  width="32" height="32" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IB2cksfwAAAgdQTFRFPHjYPnnYUIXbR3/ZUofbaJbgZpTfSIDaPXjYUYfbapfhbJnhZ5XgRn7ZP3rYU4jca5jhbZriaZfgR3/aVIncapjhZZTgRn/aVIjcbpvicp3iZ5bgQXvZVYncjrHorsfutMvvvtLyj7HoVorcdqDj0+H26/H7/v7+////1eH2apfgYpLfm7nq8fX87fP71uL2vNDxnLrq7fL7/v7/7PL7faXkWIvdRH3ZfqXk7vP7/f3+1+P2k7TpkbPpnLrrY5PfRn/ZPXnYXo/eu9DweqPkeKHjtMvwdaDjRX7ZQXvYWYzd1OL2dJ/jaJfgeKHk1eL2bpriWozdkLLoaZfhbZrhdZ/i7PH7WozeeKLk8/b8nbvrr8fvQHrYb5vitszwuM7wapjgfKTkz971/P3+9/n9mrnqtczwuM3wZpXgcp7jwdTyl7fqeaLkvtLxxtfzc53i1OH2+vz+t83wkrPoxNbzdJ7jZpTgjbDo6fD62uX39Pf8rsfvkbPoT4TaYZLfr8fuc57jcJviQnzYja/n+vv+rcbucZziYJHfXpDeqsTtkrPpQnzZd6Dj0+D21uP2UYbcYZHfdqHj8vb8q8Xussnv7/T7YpPfSoLaQHvYX5Dfnbrr0+D1h6vmYJHegajln7zrSYHZw9XzTIPaUIbbT4XbXY7ea5nhUofcW43dV4rdXI7dXI7eX5DeWOgbkgAAAmNJREFUeJx10l1IFFEUB/DzT/c6uTpb9CCIbYFBZVIhpuXLYD6oYCTSt9LXkgj7lL1kPVVbSSGbD5ZhUqD0AUKxrNqTK5KhRoo+WFgbZUHuw6Ls+jEz7jbdGbVYZ3deZuacH/ece+4FxTwAousisX9JXCiJgcDTfJFwIiDqeb1MMD4Q0hDR36oVgXgAGTJ4EdJkdRN+mYFokyPpeg1NS5pNmTGD7JANKz1wgUkz2AMss9UVdInhdeCgHvTLerM7QlY5Dej/D4oHpOHdbCM+ruJ8zIczx/LeroFyvEeRP2Ur+pixzdQc2xdtJz5EAisAlT4UT/+xjpYNzemiBD1sc/5X66gxD5BY7iUmCrtGZHXbjMLUI+P70SsUfM7vUVUhTKiZmgJVYKTQw9sr9Sgn9Ga76PiAtOilk08VFPA8nUJfyXOq5qmOs2ERniBd7K7AE1KdTZAmaA3U4g0qX1fhIY84uwygXkVhaRNbK3FGeUdVFjRzYBOkzAeEOQl089V3RitNWq782A7cW2YkaXqTqUHJxxsQG1wsd2GD3Td/q7Ha3kiaZZGlC0LN3fkok41B3Y+4mF0pyxr0phmDslDZgbbagcFr9drqqOG+fgcvTzf/NiZJatHRsbyhQ7gs/zusVtS7W4UCz5IekiYahiYd/Z0xp5l1o97dNrtXsX2jnMAnONNdftOVEyqWfy4YF8YaXVi6fd4E+NK59ox9NB6Y3tLdXiubQUcdn1g2+b2U7K4xXzn+2Qmn8XH42AU5HqDycw59ny1Jl0IUFxBe1IFakh/5KAEgZAXxzBGihIDEx5b23pjIX32q0uJJAW9GAAAAAElFTkSuQmCC"/>\n\t</defs>\n\t<style>\n\t</style>\n\t<use id="Background" href="#img1" x="0" y="0"/>\n</svg>';
  const ICONS = {
    '[ASF]': ASF,
    '[Web]': Web,
    '[Discord]': Discord$1,
    '[Twitch]': Twitch$1,
    '[Instagram]': Instagram,
    '[Twitter]': Twitter$1,
    '[Reddit]': Reddit$1,
    '[Youtube]': Youtube$1,
    '[Vk]': Vk$1,
    '[AutoTask]': AutoTask
  };
  const generateLink = (url, text) => `<a href="${url}" target="_blank">${text}</a>`;
  const createBaseElement = content => $(`<li>${content}<font class="log-status"></font></li>`).addClass('card-text');
  const createPlatformElement = (type, text, id) => {
    const urlGenerators = {
      group: text => `https://steamcommunity.com/groups/${text}`,
      officialGroup: text => `https://steamcommunity.com/games/${text}`,
      forum: text => `https://steamcommunity.com/app/${text}/discussions/`,
      curator: text => `https://store.steampowered.com/${text?.includes('/') ? text : `curator/${text}`}`,
      app: text => `https://store.steampowered.com/app/${text}`,
      sub: text => `https://steamdb.info/sub/${text}/`,
      workshop: text => `https://steamcommunity.com/sharedfiles/filedetails/?id=${text}`,
      announcement: (text, id) => `https://store.steampowered.com/news/app/${text}/view/${id}`,
      discord: {
        invite: text => `https://discord.com/invite/${text}`,
        server: text => `https://discord.com/channels/@me/${text}`
      },
      twitch: text => `https://www.twitch.tv/${text}`,
      instagram: text => `https://www.instagram.com/${text}/`,
      twitter: text => `https://x.com/${text}`,
      reddit: {
        subreddit: text => `https://www.reddit.com/r/${text}/`,
        user: text => `https://www.reddit.com/user/${text?.replace('u_', '')}`
      },
      youtube: {
        channel: text => `https://www.youtube.com/channel/${text}`,
        video: text => `https://www.youtube.com/watch?v=${text}`
      },
      vk: text => `https://vk.com/${text}/`
    };
    const typeMap = {
      joiningSteamGroup: [ 'group' ],
      leavingSteamGroup: [ 'group' ],
      gettingSteamGroupId: [ 'group' ],
      joiningSteamOfficialGroup: [ 'officialGroup' ],
      leavingSteamOfficialGroup: [ 'officialGroup' ],
      gettingSteamOfficialGroupId: [ 'officialGroup' ],
      subscribingForum: [ 'forum' ],
      unsubscribingForum: [ 'forum' ],
      gettingForumId: [ 'forum' ],
      followingCurator: [ 'curator' ],
      unfollowingCurator: [ 'curator' ],
      gettingCuratorId: [ 'curator' ],
      addingToWishlist: [ 'app' ],
      removingFromWishlist: [ 'app' ],
      followingGame: [ 'app' ],
      unfollowingGame: [ 'app' ],
      gettingSubid: [ 'app' ],
      addingFreeLicense: [ 'app', 'sub' ],
      requestingPlayTestAccess: [ 'app' ],
      gettingDemoAppid: [ 'app' ],
      favoritingWorkshop: [ 'workshop' ],
      unfavoritingWorkshop: [ 'workshop' ],
      gettingWorkshopAppId: [ 'workshop' ],
      votingUpWorkshop: [ 'workshop' ],
      gettingAnnouncementParams: [ 'announcement' ],
      likingAnnouncement: [ 'announcement' ],
      joiningDiscordServer: [ 'discord', 'invite' ],
      gettingDiscordGuild: [ 'discord', 'invite' ],
      gettingDiscordXContextProperties: [ 'discord', 'invite' ],
      leavingDiscordServer: [ 'discord', 'server' ],
      followingTwitchChannel: [ 'twitch' ],
      unfollowingTwitchChannel: [ 'twitch' ],
      gettingTwitchChannelId: [ 'twitch' ],
      gettingInsUserId: [ 'instagram' ],
      followingIns: [ 'instagram' ],
      unfollowingIns: [ 'instagram' ],
      gettingTwitterUserId: [ 'twitter' ],
      followingTwitterUser: [ 'twitter' ],
      unfollowingTwitterUser: [ 'twitter' ],
      joiningReddit: [ 'reddit', 'subreddit' ],
      leavingReddit: [ 'reddit', 'subreddit' ],
      followingRedditUser: [ 'reddit', 'user' ],
      unfollowingRedditUser: [ 'reddit', 'user' ],
      followingYtbChannel: [ 'youtube', 'channel' ],
      unfollowingYtbChannel: [ 'youtube', 'channel' ],
      likingYtbVideo: [ 'youtube', 'video' ],
      unlikingYtbVideo: [ 'youtube', 'video' ],
      gettingVkId: [ 'vk' ],
      joiningVkGroup: [ 'vk' ],
      leavingVkGroup: [ 'vk' ],
      joiningVkPublic: [ 'vk' ],
      leavingVkPublic: [ 'vk' ],
      sendingVkWall: [ 'vk' ],
      deletingVkWall: [ 'vk' ]
    };
    const urlConfig = typeMap[type];
    if (!urlConfig || !text) {
      return null;
    }
    const [platform, subType] = urlConfig;
    const urlGenerator = urlGenerators[platform];
    if (typeof urlGenerator === 'function') {
      const url = urlGenerator(text, id);
      const displayText = platform === 'announcement' ? id || '' : text;
      return createBaseElement(`${I18n(type)}[${generateLink(url, displayText)}]...`);
    }
    if (subType && typeof urlGenerator === 'object') {
      const subGenerator = urlGenerator[subType];
      if (typeof subGenerator === 'function') {
        const displayText = type.includes('RedditUser') ? text.replace('u_', '') : text;
        return createBaseElement(`${I18n(type)}[${generateLink(subGenerator(text), displayText)}]...`);
      }
    }
    return null;
  };
  const createSpecialElement = (type, text, html, id) => {
    switch (type) {
     case 'retweetting':
     case 'unretweetting':
      return createBaseElement(`${I18n(type)}${text}...`);

     case 'visitingLink':
      return createBaseElement(`${I18n('visitingLink')}[${generateLink(text || '', text || '')}]...`);

     case 'verifyingInsAuth':
     case 'text':
      return createBaseElement(I18n(text || ''));

     case 'html':
      return $(text || html || '');

     case 'whiteList':
      return $(`<li><font class="warning">${I18n('skipTask')}[${text}(${id})](${I18n('whiteList')})</font></li>`);

     case 'globalOptionsSkip':
      return $(`<li>${I18n('skipTaskOption')}<font class="warning">${text}</font></li>`);

     default:
      return createBaseElement(`${I18n('unKnown')}:${type}(${text})...`);
    }
  };
  const echoLog = ({type: type, text: text, html: html, id: id, before: before}) => {
    const emptyStatus = {
      success: () => emptyStatus,
      error: () => emptyStatus,
      warning: () => emptyStatus,
      info: () => emptyStatus,
      view: () => emptyStatus,
      remove: () => emptyStatus
    };
    try {
      let ele;
      if (!type && !text && !html) {
        ele = createBaseElement('');
      } else if (text && !type) {
        ele = createBaseElement(text);
      } else if (html && !type) {
        ele = $(html);
      } else if (type) {
        const platformElement = createPlatformElement(type, text, id);
        ele = platformElement || createSpecialElement(type, text, html, id);
      } else {
        ele = createBaseElement('');
      }
      if (before) {
        if (before in ICONS) {
          const iconKey = before;
          const svgContent = ICONS[iconKey];
          const base64Svg = btoa(svgContent);
          ele.prepend(`<font class="before-icon" style="background-image: url('data:image/svg+xml;base64,${base64Svg}')"></font>`);
        } else {
          ele.prepend(`<font class="before">${before}</font>`);
        }
      } else {
        const base64Svg = btoa(ICONS['[AutoTask]']);
        ele.prepend(`<font class="before-icon" style="background-image: url('data:image/svg+xml;base64,${base64Svg}')"></font>`);
      }
      ele.addClass('card-text');
      $('#auto-task-info').append(ele);
      ele[0]?.scrollIntoView();
      const font = ele.find('font.log-status');
      const status = {
        font: font,
        success(text = 'Success', html = false) {
          this.font?.attr('class', '').addClass('success');
          html ? this.font?.html(text) : this.font?.text(text);
          return this;
        },
        error(text = 'Error', html = false) {
          this.font?.attr('class', '').addClass('error');
          html ? this.font?.html(text) : this.font?.text(text);
          return this;
        },
        warning(text = 'Warning', html = false) {
          this.font?.attr('class', '').addClass('warning');
          html ? this.font?.html(text) : this.font?.text(text);
          return this;
        },
        info(text = 'Info', html = false) {
          this.font?.attr('class', '').addClass('info');
          html ? this.font?.html(text) : this.font?.text(text);
          return this;
        },
        view() {
          this.font?.[0].scrollIntoView();
          return this;
        },
        remove() {
          this.font?.parent().remove();
          return this;
        }
      };
      return status;
    } catch (error) {
      throwError(error, 'echoLog');
      return emptyStatus;
    }
  };
  const unique = array => {
    try {
      return Array.from(new Set(array));
    } catch (error) {
      throwError(error, 'unique');
      return [];
    }
  };
  const delay = (time = 1e3) => new Promise((resolve => setTimeout((() => resolve(true)), time)));
  const getRedirectLink = async (link, redirectOnce = false) => {
    try {
      if (!link) {
        return null;
      }
      const redirectLinksCache = GM_getValue('redirectLinks') || {};
      const cachedLink = redirectLinksCache[link];
      if (cachedLink) {
        debug('使用缓存的重定向链接', {
          original: link,
          cached: cachedLink
        });
        return cachedLink;
      }
      const {data: data} = await httpRequest({
        url: link,
        method: 'GET',
        redirect: redirectOnce ? 'manual' : 'follow'
      });
      if (data?.finalUrl) {
        redirectLinksCache[link] = data.finalUrl;
        GM_setValue('redirectLinks', redirectLinksCache);
        debug('获取新的重定向链接', {
          original: link,
          final: data.finalUrl
        });
        return data.finalUrl;
      }
      debug('未找到重定向链接', {
        link: link
      });
      return null;
    } catch (error) {
      throwError(error, 'getRedirectLink');
      return null;
    }
  };
  const visitLink = async (link, options) => {
    try {
      debug('开始访问链接', {
        link: link,
        options: options
      });
      const logStatus = echoLog({
        type: 'visitLink',
        text: link
      });
      const {result: result, statusText: statusText, status: status} = await httpRequest({
        url: link,
        method: 'GET',
        ...options
      });
      if (result === 'Success') {
        debug('链接访问成功', {
          link: link
        });
        logStatus.success();
        return true;
      }
      debug('链接访问失败', {
        link: link,
        result: result,
        statusText: statusText,
        status: status
      });
      logStatus.error(`${result}:${statusText}(${status})`);
      return false;
    } catch (error) {
      throwError(error, 'visitLink');
      return false;
    }
  };
  const getUrlQuery = url => {
    try {
      debug('开始解析URL查询参数', {
        url: url || window.location.href
      });
      const searchParams = url ? new URL(url, window.location.origin).searchParams : new URLSearchParams(window.location.search);
      const query = {};
      for (const [key, value] of searchParams.entries()) {
        query[key] = value;
      }
      debug('URL查询参数解析结果', query);
      return query;
    } catch (error) {
      throwError(error, 'getUrlQuery');
      return {};
    }
  };
  const stringToColour = str => {
    try {
      let hash = 0;
      for (let i = 0; i < str.length; i++) {
        hash = str.charCodeAt(i) + ((hash << 5) - hash);
      }
      const rgb = Array.from({
        length: 3
      }, ((_, i) => {
        const value = hash >> i * 8 & 255;
        return value.toString(16).padStart(2, '0');
      }));
      const color = `#${rgb.join('')}`;
      return color;
    } catch (error) {
      throwError(error, 'stringToColour');
      return '#ffffff';
    }
  };
  const getAllLocalStorageAsObjects = localStorage => {
    try {
      debug('开始将所有LocalStorage转换为对象');
      const result = {};
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (!key) {
          continue;
        }
        const value = localStorage.getItem(key);
        try {
          result[key] = JSON.parse(value);
        } catch (error) {
          result[key] = value;
          console.error(error);
        }
      }
      debug('所有LocalStorage转换为对象完成', result);
      return result;
    } catch (error) {
      debug('将所有LocalStorage转换为对象失败', {
        error: error
      });
      throwError(error, 'getAllLocalStorageAsObjects');
      return {};
    }
  };
  class Social {
    tasks;
    getRealParams(name, links, doTask, link2param) {
      try {
        debug('开始获取实际参数', {
          name: name,
          linksCount: links.length,
          doTask: doTask
        });
        let realParams = [];
        if (links.length > 0) {
          debug('处理链接参数');
          const convertedLinks = links.map((link => link2param(link))).filter((link => link !== undefined));
          debug('链接参数处理结果', {
            convertedLinksCount: convertedLinks.length
          });
          realParams = [ ...realParams, ...convertedLinks ];
        }
        if (!doTask && this.tasks[name]?.length) {
          debug('处理任务参数', {
            taskCount: this.tasks[name].length
          });
          realParams = [ ...realParams, ...this.tasks[name] ];
        }
        const uniqueParams = unique(realParams);
        debug('参数处理完成', {
          originalCount: realParams.length,
          uniqueCount: uniqueParams.length
        });
        return uniqueParams;
      } catch (error) {
        debug('获取实际参数时发生错误', {
          error: error
        });
        throwError(error, 'Social.getRealParams');
        return [];
      }
    }
  }
  class Discord extends Social {
    tasks;
    whiteList;
    #auth=GM_getValue('discordAuth') || {};
    #cache=GM_getValue('discordCache') || {};
    #xContextPropertiesCache=GM_getValue('discordXContextPropertiesCache') || {};
    #initialized=false;
    constructor() {
      super();
      const defaultTasksTemplate = {
        servers: []
      };
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.discord || {}
      };
    }
    async init(action) {
      try {
        debug('开始初始化Discord模块', {
          action: action
        });
        if (!GM_getValue('dontRemindDiscordAgain')) {
          debug('显示Discord重要提示对话框');
          const result = await Swal.fire({
            title: I18n('discordImportantNotice'),
            text: I18n('discordImportantNoticeText'),
            showCancelButton: true,
            showDenyButton: true,
            confirmButtonText: I18n('continueDiscordTask'),
            cancelButtonText: I18n('skipDiscordTask'),
            denyButtonText: I18n('continueAndDontRemindAgain')
          }).then((({isConfirmed: isConfirmed, isDenied: isDenied}) => {
            if (isConfirmed) {
              return true;
            }
            if (isDenied) {
              GM_setValue('dontRemindDiscordAgain', true);
              return true;
            }
            return false;
          }));
          if (!result) {
            this.#initialized = false;
            return 'skip';
          }
        }
        if (action === 'do' && !globalOptions.doTask.discord.servers || action === 'undo' && !globalOptions.undoTask.discord.servers) {
          this.#initialized = false;
          debug('检测到用户已禁用Discord任务,跳过初始化');
          return 'skip';
        }
        if (this.#initialized) {
          debug('Discord模块已初始化');
          return true;
        }
        if (!this.#auth.auth || !this.#auth.xSuperProperties) {
          debug('未找到Discord授权信息,尝试更新授权');
          if (await this.#updateAuth()) {
            this.#initialized = true;
            return true;
          }
          return false;
        }
        const isVerified = await this.#verifyAuth();
        if (isVerified) {
          debug('Discord授权验证成功');
          echoLog({
            before: '[Discord]'
          }).success(I18n('initSuccess', 'Discord'));
          this.#initialized = true;
          return true;
        }
        GM_setValue('discordAuth', {
          auth: null
        });
        debug('Discord授权验证失败,尝试重新获取授权');
        if (await this.#updateAuth()) {
          echoLog({
            before: '[Discord]'
          }).success(I18n('initSuccess', 'Discord'));
          this.#initialized = true;
          return true;
        }
        echoLog({
          before: '[Discord]'
        }).error(I18n('initFailed', 'Discord'));
        return false;
      } catch (error) {
        throwError(error, 'Discord.init');
        return false;
      }
    }
    async #verifyAuth() {
      try {
        debug('开始验证Discord授权');
        const logStatus = echoLog({
          text: I18n('verifyingAuth', 'Discord'),
          before: '[Discord]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://discord.com/api/v6/users/@me',
          method: 'HEAD',
          headers: {
            authorization: this.#auth.auth
          }
        });
        if (result !== 'Success') {
          debug('Discord授权验证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('Discord授权验证状态码错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('Discord授权验证成功');
        logStatus.success();
        return true;
      } catch (error) {
        throwError(error, 'Discord.verifyAuth');
        return false;
      }
    }
    async #updateAuth() {
      try {
        debug('开始更新Discord授权');
        const logStatus = echoLog({
          text: I18n('updatingAuth', 'Discord'),
          before: '[Discord]'
        });
        return await new Promise((resolve => {
          const newTab = GM_openInTab('https://discord.com/channels/@me', {
            active: true,
            insert: true,
            setParent: true
          });
          newTab.name = 'ATv4_discordAuth';
          newTab.onclose = async () => {
            const {auth: auth, xSuperProperties: xSuperProperties} = GM_getValue('discordAuth');
            if (auth && xSuperProperties) {
              debug('成功获取新的Discord授权');
              this.#auth = {
                auth: auth,
                xSuperProperties: xSuperProperties
              };
              logStatus.success();
              resolve(await this.#verifyAuth());
            } else {
              debug('获取Discord授权失败');
              logStatus.error('Error: Update discord auth failed!');
              resolve(false);
            }
          };
        }));
      } catch (error) {
        throwError(error, 'Discord.updateAuth');
        return false;
      }
    }
    async #joinServer(inviteId) {
      try {
        debug('开始加入Discord服务器', {
          inviteId: inviteId
        });
        const logStatus = echoLog({
          type: 'joiningDiscordServer',
          text: inviteId,
          before: '[Discord]'
        });
        const xContextProperties = await this.#getXContextProperties(inviteId);
        if (!xContextProperties) {
          debug('获取加群参数失败,无法加入服务器', {
            inviteId: inviteId
          });
          logStatus.error('Error: Failed to get xContextProperties');
          return false;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://discord.com/api/v9/invites/${inviteId}`,
          method: 'POST',
          dataType: 'json',
          headers: {
            'content-type': 'application/json',
            authorization: this.#auth.auth,
            origin: 'https://discord.com',
            referer: `https://discord.com/invite/${inviteId}`,
            'x-super-properties': this.#auth.xSuperProperties,
            'x-context-properties': xContextProperties
          },
          data: '{"session_id":null}'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('加入Discord服务器失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          if (status === 400) {
            debug('加入Discord服务器失败,状态码为400,需完成人机验证');
            logStatus.error(I18n('captchaNeeded'));
            return false;
          }
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        const guild = data.response?.guild?.id;
        if (!guild) {
          debug('获取服务器ID失败');
          logStatus.error('Error: Failed to get guild ID');
          return false;
        }
        debug('成功加入Discord服务器', {
          guild: guild
        });
        logStatus.success();
        this.#setCache(inviteId, guild);
        this.tasks.servers = unique([ ...this.tasks.servers, inviteId ]);
        return true;
      } catch (error) {
        throwError(error, 'Discord.joinServer');
        return false;
      }
    }
    async #leaveServer(inviteId) {
      try {
        debug('开始退出Discord服务器', {
          inviteId: inviteId
        });
        if (this.whiteList.servers.includes(inviteId)) {
          debug('服务器在白名单中,跳过退出操作', {
            inviteId: inviteId
          });
          echoLog({
            type: 'whiteList',
            text: 'Discord.leaveServer',
            id: inviteId,
            before: '[Discord]'
          });
          return true;
        }
        const guild = await this.#getGuild(inviteId);
        if (!guild) {
          debug('获取服务器ID失败,无法退出服务器', {
            inviteId: inviteId
          });
          return false;
        }
        const logStatus = echoLog({
          type: 'leavingDiscordServer',
          text: guild,
          before: '[Discord]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://discord.com/api/v9/users/@me/guilds/${guild}`,
          method: 'DELETE',
          headers: {
            authorization: this.#auth.auth,
            'x-super-properties': this.#auth.xSuperProperties
          }
        });
        if (result !== 'Success' || data?.status !== 204) {
          debug('退出Discord服务器失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        debug('成功退出Discord服务器', {
          guild: guild
        });
        logStatus.success();
        return true;
      } catch (error) {
        throwError(error, 'Discord.leaveServer');
        return false;
      }
    }
    async #getXContextProperties(inviteId) {
      try {
        debug('开始获取Discord加群参数', {
          inviteId: inviteId
        });
        const logStatus = echoLog({
          type: 'gettingDiscordXContextProperties',
          text: inviteId,
          before: '[Discord]'
        });
        const cachedXContextProperties = this.#xContextPropertiesCache[inviteId];
        if (cachedXContextProperties) {
          debug('从缓存中获取到加群参数', {
            inviteId: inviteId,
            cachedXContextProperties: cachedXContextProperties
          });
          logStatus.success();
          return cachedXContextProperties;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://discord.com/api/v9/invites/${inviteId}?with_counts=true&with_expiration=true&with_permissions=true`,
          responseType: 'json',
          method: 'GET',
          headers: {
            authorization: this.#auth.auth,
            'x-super-properties': this.#auth.xSuperProperties
          }
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('获取加群参数失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        const guild = data.response?.guild?.id;
        if (!guild) {
          debug('加群参数中未找到ID', {
            inviteId: inviteId
          });
          logStatus.error('Error: Failed to get guild ID');
          return false;
        }
        const xContextProperties = {
          location: 'Accept Invite Page',
          location_guild_id: data.response?.guild?.id,
          location_channel_id: data.response?.channel?.id,
          location_channel_type: data.response?.channel?.type
        };
        debug('成功获取加群参数', xContextProperties);
        logStatus.success();
        this.#setXContextPropertiesCache(inviteId, window.btoa(JSON.stringify(xContextProperties)));
        this.#setCache(inviteId, guild);
        return window.btoa(JSON.stringify(xContextProperties));
      } catch (error) {
        throwError(error, 'Discord.getXContextProperties');
        return false;
      }
    }
    async #getGuild(inviteId) {
      try {
        debug('开始获取Discord服务器ID', {
          inviteId: inviteId
        });
        const logStatus = echoLog({
          type: 'gettingDiscordGuild',
          text: inviteId,
          before: '[Discord]'
        });
        const cachedGuild = this.#cache[inviteId];
        if (cachedGuild) {
          debug('从缓存中获取到服务器ID', {
            inviteId: inviteId,
            cachedGuild: cachedGuild
          });
          logStatus.success();
          return cachedGuild;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://discord.com/api/v9/invites/${inviteId}`,
          responseType: 'json',
          method: 'GET',
          headers: {
            authorization: this.#auth.auth,
            'x-super-properties': this.#auth.xSuperProperties
          }
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('获取服务器信息失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        const guild = data.response?.guild?.id;
        if (!guild) {
          debug('服务器信息中未找到ID', {
            inviteId: inviteId
          });
          logStatus.error('Error: Failed to get guild ID');
          return false;
        }
        debug('成功获取服务器ID', {
          inviteId: inviteId,
          guild: guild
        });
        logStatus.success();
        this.#setCache(inviteId, guild);
        return guild;
      } catch (error) {
        throwError(error, 'Discord.getGuild');
        return false;
      }
    }
    async toggle({doTask: doTask = true, serverLinks: serverLinks = []}) {
      try {
        debug('开始处理Discord服务器任务', {
          doTask: doTask,
          serverLinksCount: serverLinks.length
        });
        if (!this.#initialized) {
          debug('Discord模块未初始化');
          echoLog({
            text: I18n('needInit'),
            before: '[Discord]'
          });
          return false;
        }
        if (doTask && !globalOptions.doTask.discord.servers || !doTask && !globalOptions.undoTask.discord.servers) {
          debug('根据全局选项跳过Discord服务器任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'discord.servers',
            before: '[Discord]'
          });
          return true;
        }
        const realServers = this.getRealParams('servers', serverLinks, doTask, (link => link.match(/invite\/(.+)/)?.[1]));
        debug('处理后的服务器列表', {
          count: realServers.length,
          servers: realServers
        });
        if (realServers.length === 0) {
          debug('没有需要处理的服务器');
          return true;
        }
        const results = [];
        for (const server of realServers) {
          results.push(doTask ? this.#joinServer(server) : this.#leaveServer(server));
          await delay(1e3);
        }
        return await Promise.allSettled(results).then((() => true));
      } catch (error) {
        throwError(error, 'Discord.toggleServers');
        return false;
      }
    }
    #setCache(inviteId, guild) {
      try {
        debug('设置Discord服务器缓存', {
          inviteId: inviteId,
          guild: guild
        });
        this.#cache[inviteId] = guild;
        GM_setValue('discordCache', this.#cache);
        debug('Discord服务器缓存设置成功');
      } catch (error) {
        debug('设置Discord服务器缓存失败', {
          error: error
        });
        throwError(error, 'Discord.setCache');
      }
    }
    #setXContextPropertiesCache(inviteId, xContextProperties) {
      try {
        debug('设置Discord加群参数缓存', {
          inviteId: inviteId,
          xContextProperties: xContextProperties
        });
        this.#xContextPropertiesCache[inviteId] = xContextProperties;
        GM_setValue('discordXContextPropertiesCache', this.#xContextPropertiesCache);
      } catch (error) {
        debug('设置Discord加群参数缓存失败', {
          error: error
        });
        throwError(error, 'Discord.setXContextPropertiesCache');
      }
    }
  }
  class Reddit extends Social {
    tasks;
    whiteList;
    #auth;
    #initialized=false;
    constructor() {
      super();
      const defaultTasksTemplate = {
        reddits: []
      };
      debug('初始化Reddit实例');
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.reddit || {}
      };
    }
    async init() {
      try {
        debug('开始初始化Reddit模块');
        if (this.#initialized) {
          debug('Reddit模块已初始化');
          return true;
        }
        const isVerified = await this.#updateAuth();
        if (isVerified) {
          debug('Reddit授权验证成功');
          echoLog({
            before: '[Reddit]'
          }).success(I18n('initSuccess', 'Reddit'));
          this.#initialized = true;
          return true;
        }
        debug('Reddit初始化失败');
        echoLog({
          before: '[Reddit]'
        }).error(I18n('initFailed', 'Reddit'));
        return false;
      } catch (error) {
        debug('Reddit初始化发生错误', {
          error: error
        });
        throwError(error, 'Reddit.init');
        return false;
      }
    }
    async #useBeta() {
      try {
        debug('开始切换Reddit为新版');
        const logStatus = echoLog({
          text: I18n('changingRedditVersion'),
          before: '[Reddit]'
        });
        return await new Promise((resolve => {
          const newTab = GM_openInTab('https://www.reddit.com/', {
            active: true,
            insert: true,
            setParent: true
          });
          newTab.name = 'ATv4_redditAuth';
          newTab.onclose = async () => {
            debug('新版Reddit标签页已关闭');
            logStatus.success();
            resolve(await this.#updateAuth(true));
          };
        }));
      } catch (error) {
        debug('切换Reddit版本时发生错误', {
          error: error
        });
        throwError(error, 'Reddit.useBeta');
        return false;
      }
    }
    async #updateAuth(beta = false) {
      try {
        debug('开始更新Reddit授权', {
          beta: beta
        });
        const logStatus = echoLog({
          text: I18n('updatingAuth', 'Reddit'),
          before: '[Reddit]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://www.reddit.com/',
          method: 'GET',
          nochche: true,
          headers: {
            'Cache-Control': 'no-cache'
          }
        });
        if (result !== 'Success') {
          debug('获取Reddit页面失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.responseText.includes('www.reddit.com/login/')) {
          debug('需要登录Reddit');
          logStatus.error(`Error:${I18n('loginReddit')}`, true);
          return false;
        }
        if (data?.status !== 200) {
          debug('Reddit页面状态码错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        if (data.responseText.includes('redesign-beta-optin-btn') && !beta) {
          debug('检测到旧版Reddit,需要切换到新版');
          return await this.#useBeta();
        }
        const accessToken = data.responseText.match(/"accessToken":"(.*?)","expires":"(.*?)"/)?.[1];
        if (!accessToken) {
          debug('未找到Reddit访问令牌');
          logStatus.error('Error: Parameter "accessToken" not found!');
          return false;
        }
        debug('成功获取Reddit访问令牌');
        this.#auth = {
          token: accessToken
        };
        logStatus.success();
        return true;
      } catch (error) {
        debug('更新Reddit授权时发生错误', {
          error: error
        });
        throwError(error, 'Reddit.updateAuth');
        return false;
      }
    }
    async #toggleTask({name: name, doTask: doTask = true}) {
      try {
        debug('开始处理Reddit任务', {
          name: name,
          doTask: doTask
        });
        if (!doTask && this.whiteList.reddits.includes(name)) {
          debug('Reddit在白名单中,跳过取消订阅', {
            name: name
          });
          echoLog({
            type: 'whiteList',
            text: 'Reddit.undoTask',
            id: name,
            before: '[Reddit]'
          });
          return true;
        }
        let type = doTask ? 'joiningReddit' : 'leavingReddit';
        if (/^u_/.test(name)) {
          type = doTask ? 'followingRedditUser' : 'unfollowingRedditUser';
        }
        debug('任务类型', {
          type: type,
          name: name
        });
        const logStatus = echoLog({
          type: type,
          text: name,
          before: '[Reddit]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://oauth.reddit.com/api/subscribe?redditWebClient=desktop2x&app=desktop2x-client-production&raw_json=1&gilding_detail=1',
          method: 'POST',
          headers: {
            authorization: `Bearer ${this.#auth.token}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param({
            action: doTask ? 'sub' : 'unsub',
            sr_name: name,
            api_type: 'json'
          })
        });
        if (result !== 'Success') {
          debug('Reddit任务请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('Reddit任务状态码错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('Reddit任务处理成功', {
          name: name,
          doTask: doTask
        });
        logStatus.success();
        if (doTask) {
          this.tasks.reddits = unique([ ...this.tasks.reddits, name ]);
        }
        return true;
      } catch (error) {
        debug('处理Reddit任务时发生错误', {
          error: error
        });
        throwError(error, 'Reddit.toggleTask');
        return false;
      }
    }
    async toggle({doTask: doTask = true, redditLinks: redditLinks = []}) {
      try {
        debug('开始处理Reddit链接任务', {
          doTask: doTask,
          redditLinksCount: redditLinks.length
        });
        if (!this.#initialized) {
          debug('Reddit模块未初始化');
          echoLog({
            text: I18n('needInit'),
            before: '[Reddit]'
          });
          return false;
        }
        if (doTask && !globalOptions.doTask.reddit.reddits || !doTask && !globalOptions.undoTask.reddit.reddits) {
          debug('根据全局选项跳过Reddit任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'reddit.reddits',
            before: '[Reddit]'
          });
          return true;
        }
        const realReddits = this.getRealParams('reddits', redditLinks, doTask, (link => {
          const name = link.match(/https?:\/\/www\.reddit\.com\/r\/([^/]*)/)?.[1];
          const userName = link.match(/https?:\/\/www\.reddit\.com\/user\/([^/]*)/)?.[1];
          if (userName) {
            return name || userName;
          }
          return name;
        }));
        debug('处理后的Reddit列表', {
          count: realReddits.length,
          reddits: realReddits
        });
        if (realReddits.length === 0) {
          debug('没有需要处理的Reddit链接');
          return true;
        }
        const prom = [];
        for (const name of realReddits) {
          prom.push(this.#toggleTask({
            name: name,
            doTask: doTask
          }));
          await delay(1e3);
        }
        return await Promise.all(prom).then((() => true));
      } catch (error) {
        debug('处理Reddit链接任务时发生错误', {
          error: error
        });
        throwError(error, 'Reddit.toggle');
        return false;
      }
    }
  }
  class Twitch extends Social {
    tasks;
    whiteList;
    #auth=GM_getValue('twitchAuth') || {};
    #cache=GM_getValue('twitchCache') || {};
    #initialized=false;
    #integrityToken;
    constructor() {
      super();
      const defaultTasksTemplate = {
        channels: []
      };
      debug('初始化Twitch实例');
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.twitch || {}
      };
    }
    async init() {
      try {
        debug('开始初始化Twitch模块');
        if (this.#initialized) {
          debug('Twitch模块已初始化');
          return true;
        }
        if (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId) {
          if (await this.#updateAuth()) {
            this.#initialized = true;
            return true;
          }
          return false;
        }
        const isVerified = await this.#verifyAuth(true);
        if (isVerified) {
          debug('Twitch授权验证成功');
          echoLog({
            before: '[Twitch]'
          }).success(I18n('initSuccess', 'Twitch'));
          this.#initialized = true;
          return true;
        }
        GM_setValue('twitchAuth', null);
        if (await this.#updateAuth()) {
          debug('Twitch重新授权成功');
          echoLog({
            before: '[Twitch]'
          }).success(I18n('initSuccess', 'Twitch'));
          this.#initialized = true;
          return true;
        }
        debug('Twitch初始化失败');
        echoLog({
          before: '[Twitch]'
        }).error(I18n('initFailed', 'Twitch'));
        return false;
      } catch (error) {
        debug('Twitch初始化发生错误', {
          error: error
        });
        throwError(error, 'Twitch.init');
        return false;
      }
    }
    async #verifyAuth(isFirst) {
      try {
        debug('开始验证Twitch授权');
        const logStatus = echoLog({
          text: I18n('verifyingAuth', 'Twitch'),
          before: '[Twitch]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://gql.twitch.tv/gql',
          method: 'POST',
          dataType: 'json',
          headers: {
            Authorization: `OAuth ${this.#auth.authToken}`,
            'Client-Id': this.#auth.clientId
          },
          data: '[{"operationName":"FrontPageNew_User","variables":{"limit":1},"extensions":{"persistedQuery":{"version":1,' + '"sha256Hash":"64bd07a2cbaca80699d62636d966cf6395a5d14a1f0a14282067dcb28b13eb11"}}}]'
        });
        if (result !== 'Success') {
          debug('Twitch授权验证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || !data.response?.[0]?.data?.currentUser) {
          debug('Twitch授权验证状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        await this.#integrity(isFirst);
        debug('Twitch授权验证成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('Twitch授权验证发生错误', {
          error: error
        });
        throwError(error, 'Twitch.verifyAuth');
        return false;
      }
    }
    async #integrity(isFirst = true, ct = '') {
      try {
        debug('开始检查Twitch完整性', {
          isFirst: isFirst,
          ct: ct
        });
        const logStatus = echoLog({
          text: I18n('checkingTwitchIntegrity'),
          before: '[Twitch]'
        });
        if (isFirst && (!this.#auth.authToken || !this.#auth.clientId || !this.#auth.clientVersion || !this.#auth.deviceId || !this.#auth.clientSessionId)) {
          return await this.#updateAuth(false);
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://gql.twitch.tv/integrity',
          method: 'POST',
          dataType: 'json',
          anonymous: true,
          headers: {
            Origin: 'https://www.twitch.tv',
            Referer: 'https://www.twitch.tv/',
            Authorization: `OAuth ${this.#auth.authToken}`,
            'Client-Id': this.#auth.clientId,
            'Client-Version': this.#auth.clientVersion,
            'X-Device-Id': this.#auth.deviceId,
            'Client-Session-Id': this.#auth.clientSessionId,
            'x-kpsdk-ct': ct
          }
        });
        if (result !== 'Success') {
          debug('Twitch完整性检查请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (!ct && data?.responseHeaders?.['x-kpsdk-ct']) {
          debug('需要重新检查Twitch完整性');
          return await this.#integrity(isFirst, data.responseHeaders['x-kpsdk-ct']);
        }
        if (data?.status !== 200 || !data.response?.token) {
          debug('Twitch完整性检查状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        this.#integrityToken = data.response.token;
        debug('Twitch完整性检查成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('Twitch完整性检查发生错误', {
          error: error
        });
        throwError(error, 'Twitch.integrity');
        return false;
      }
    }
    async #updateAuth(isFirst = true) {
      try {
        debug('开始更新Twitch授权', {
          isFirst: isFirst
        });
        const logStatus = echoLog({
          text: I18n('updatingAuth', 'Twitch'),
          before: '[Twitch]'
        });
        return await new Promise((resolve => {
          const newTab = GM_openInTab('https://www.twitch.tv/', {
            active: true,
            insert: true,
            setParent: true
          });
          newTab.name = 'ATv4_twitchAuth';
          newTab.onclose = async () => {
            const auth = GM_getValue('twitchAuth');
            if (auth) {
              debug('成功获取新的Twitch授权');
              this.#auth = auth;
              logStatus.success();
              resolve(await this.#verifyAuth(isFirst));
            } else {
              debug('获取Twitch授权失败');
              logStatus.error('Error: Update twitch auth failed!');
              resolve(false);
            }
          };
        }));
      } catch (error) {
        debug('更新Twitch授权时发生错误', {
          error: error
        });
        throwError(error, 'Twitch.updateAuth');
        return false;
      }
    }
    async #toggleChannel({name: name, doTask: doTask = true}) {
      try {
        debug('开始处理Twitch频道任务', {
          name: name,
          doTask: doTask
        });
        if (!doTask && this.whiteList.channels.includes(name)) {
          debug('Twitch频道在白名单中,跳过取消关注', {
            name: name
          });
          echoLog({
            type: 'whiteList',
            text: 'Twitch.unfollowChannel',
            id: name,
            before: '[Twitch]'
          });
          return true;
        }
        const channelId = await this.#getChannelId(name);
        if (!channelId) {
          return false;
        }
        const logStatus = echoLog({
          type: `${doTask ? '' : 'un'}followingTwitchChannel`,
          text: name,
          before: '[Twitch]'
        });
        const followData = `[{"operationName":"FollowButton_FollowUser","variables":{"input":{"disableNotifications":false,"targetID":"${channelId}` + '"}},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"800e7346bdf7e5278a3c1d3f21b2b56e2639928f86815677a7126b093b2fdd08"}}}]';
        const unfollowData = `[{"operationName":"FollowButton_UnfollowUser","variables":{"input":{"targetID":"${channelId}"}},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"f7dae976ebf41c755ae2d758546bfd176b4eeb856656098bb40e0a672ca0d880"}}}]';
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://gql.twitch.tv/gql',
          method: 'POST',
          dataType: 'json',
          anonymous: true,
          headers: {
            Origin: 'https://www.twitch.tv',
            Referer: 'https://www.twitch.tv/',
            Authorization: `OAuth ${this.#auth.authToken}`,
            'Client-Id': this.#auth.clientId,
            'Client-Version': this.#auth.clientVersion,
            'X-Device-Id': this.#auth.deviceId,
            'Client-Session-Id': this.#auth.clientSessionId,
            'Client-Integrity': this.#integrityToken
          },
          data: doTask ? followData : unfollowData
        });
        if (result !== 'Success') {
          debug('Twitch频道操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || data.response?.[0] && data.response[0].errors) {
          debug('Twitch频道操作状态错误', {
            status: data?.status,
            statusText: data?.statusText,
            errors: data?.response?.[0].errors
          });
          logStatus.error(`Error:${data?.response?.[0].errors?.[0]?.message || `${data?.statusText}(${data?.status})`}`);
          return false;
        }
        debug('Twitch频道操作成功', {
          name: name,
          doTask: doTask
        });
        logStatus.success();
        if (doTask) {
          this.tasks.channels = unique([ ...this.tasks.channels, name ]);
        }
        return true;
      } catch (error) {
        debug('处理Twitch频道任务时发生错误', {
          error: error
        });
        throwError(error, 'Twitch.toggleChannel');
        return false;
      }
    }
    async #getChannelId(name) {
      try {
        debug('开始获取Twitch频道ID', {
          name: name
        });
        const logStatus = echoLog({
          type: 'gettingTwitchChannelId',
          text: name,
          before: '[Twitch]'
        });
        const cachedChannelId = this.#cache[name];
        if (cachedChannelId) {
          debug('从缓存获取到Twitch频道ID', {
            name: name,
            id: cachedChannelId
          });
          logStatus.success();
          return cachedChannelId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://gql.twitch.tv/gql',
          method: 'POST',
          headers: {
            Authorization: `OAuth ${this.#auth.authToken}`,
            'Client-Id': this.#auth.clientId
          },
          responseType: 'json',
          data: `[{"operationName":"ActiveWatchParty","variables":{"channelLogin":"${name}"},` + '"extensions":{"persistedQuery":{"version":1,"sha256Hash":"4a8156c97b19e3a36e081cf6d6ddb5dbf9f9b02ae60e4d2ff26ed70aebc80a30"}}}]'
        });
        if (result !== 'Success') {
          debug('获取Twitch频道ID请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取Twitch频道ID状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const newChannelId = data.response?.[0]?.data?.user?.id;
        if (!newChannelId) {
          debug('未找到Twitch频道ID', {
            name: name
          });
          logStatus.error(`Error:${data?.statusText || 'Unknown'}(${data?.status || 'Unknown'})`);
          return false;
        }
        debug('成功获取Twitch频道ID', {
          name: name,
          id: newChannelId
        });
        this.#setCache(name, newChannelId);
        logStatus.success();
        return newChannelId;
      } catch (error) {
        debug('获取Twitch频道ID时发生错误', {
          error: error
        });
        throwError(error, 'Twitch.getChannelId');
        return false;
      }
    }
    async toggle({doTask: doTask = true, channelLinks: channelLinks = []}) {
      try {
        debug('开始处理Twitch链接任务', {
          doTask: doTask,
          channelLinksCount: channelLinks.length
        });
        if (!this.#initialized) {
          debug('Twitch模块未初始化');
          echoLog({
            text: I18n('needInit'),
            before: '[Twitch]'
          });
          return false;
        }
        const prom = [];
        if (doTask && !globalOptions.doTask.twitch.channels || !doTask && !globalOptions.undoTask.twitch.channels) {
          debug('根据全局选项跳过Twitch任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'twitch.channels',
            before: '[Twitch]'
          });
        } else {
          const realChannels = this.getRealParams('channels', channelLinks, doTask, (link => link.match(/https:\/\/(www\.)?twitch\.tv\/(.+)/)?.[2]));
          debug('处理后的Twitch频道列表', {
            count: realChannels.length,
            channels: realChannels
          });
          if (realChannels.length > 0) {
            for (const channel of realChannels) {
              prom.push(this.#toggleChannel({
                name: channel,
                doTask: doTask
              }));
              await delay(1e3);
            }
          }
        }
        return Promise.all(prom).then((() => true));
      } catch (error) {
        debug('处理Twitch链接任务时发生错误', {
          error: error
        });
        throwError(error, 'Twitch.toggle');
        return false;
      }
    }
    #setCache(name, id) {
      try {
        debug('设置Twitch频道ID缓存', {
          name: name,
          id: id
        });
        this.#cache[name] = id;
        GM_setValue('twitchCache', this.#cache);
      } catch (error) {
        debug('设置Twitch频道ID缓存时发生错误', {
          error: error
        });
        throwError(error, 'Twitch.setCache');
      }
    }
  }
  const encodeSha256 = async data => {
    const encoder = new TextEncoder;
    const dataBuffer = encoder.encode(data);
    const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
    return Array.from(new Uint8Array(hashBuffer));
  };
  const encodeBase64 = data => {
    let binary = '';
    const bytes = new Uint8Array(data);
    const len = bytes.byteLength;
    for (let i = 0; i < len; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary).replace(/=/g, '');
  };
  const decodeBase64 = data => {
    const binaryString = atob(data);
    const len = binaryString.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    return Array.from(bytes);
  };
  const generateTransactionId = async (method, path, key, animationKey) => {
    const DEFAULT_KEYWORD = 'obfiowerehiring';
    const ADDITIONAL_RANDOM_NUMBER = 3;
    const timeNow = Math.floor((Date.now() - 1682924400 * 1e3) / 1e3);
    const timeNowBytes = [ timeNow & 255, timeNow >> 8 & 255, timeNow >> 16 & 255, timeNow >> 24 & 255 ];
    const data = `${method}!${path}!${timeNow}${DEFAULT_KEYWORD}${animationKey}`;
    const hashBytes = await encodeSha256(data);
    const keyBytes = decodeBase64(key);
    const randomNum = Math.floor(Math.random() * 256);
    const bytesArr = [ ...keyBytes, ...timeNowBytes, ...hashBytes.slice(0, 16), ADDITIONAL_RANDOM_NUMBER ];
    const out = new Uint8Array(bytesArr.length + 1);
    out[0] = randomNum;
    bytesArr.forEach(((item, index) => {
      out[index + 1] = item ^ randomNum;
    }));
    return encodeBase64(out);
  };
  const url = 'https://raw.githubusercontent.com/fa0311/x-client-transaction-id-pair-dict/refs/heads/main/pair.json';
  const getTID = async () => {
    const res = await fetch(url);
    const json = await res.json();
    return async (method, path) => {
      const randomPair = json[Math.floor(Math.random() * json.length)];
      const {animationKey: animationKey, verification: verification} = randomPair;
      const tid = await generateTransactionId(method, path, verification, animationKey);
      return tid;
    };
  };
  const parseResponseHeaders = headerStr => {
    const headers = {};
    if (!headerStr) {
      return headers;
    }
    headerStr.split('\r\n').forEach((line => {
      if (line) {
        const parts = line.split(':');
        const key = parts.shift()?.trim();
        const value = parts.join(':').trim();
        if (key) {
          if (key.toLowerCase() === 'set-cookie') {
            if (headers[key]) {
              if (Array.isArray(headers[key])) {
                headers[key].push(value);
              } else {
                headers[key] = [ headers[key], value ];
              }
            } else {
              headers[key] = value;
            }
          } else {
            headers[key] = value;
          }
        }
      }
    }));
    return headers;
  };
  const axiosGM = function(config) {
    const finalConfig = {
      ...axiosGM.defaults,
      ...config
    };
    const retries = finalConfig.retry ?? 0;
    const retryDelay = finalConfig.retryDelay ?? 0;
    const requestAttempt = attempt => new Promise(((resolve, reject) => {
      GM_xmlhttpRequest({
        method: finalConfig.method ? finalConfig.method.toUpperCase() : 'GET',
        url: finalConfig.url,
        headers: finalConfig.headers,
        data: finalConfig.data,
        responseType: finalConfig.responseType || 'json',
        timeout: finalConfig.timeout,
        fetch: finalConfig.fetch ?? true,
        onload(response) {
          const axiosResponse = {
            data: response.response || response.responseText,
            status: response.status,
            statusText: response.statusText,
            headers: parseResponseHeaders(response.responseHeaders),
            config: finalConfig,
            request: response
          };
          resolve(axiosResponse);
        },
        onerror(error) {
          if (attempt < retries) {
            setTimeout((() => {
              requestAttempt(attempt + 1).then(resolve).catch(reject);
            }), retryDelay);
          } else {
            reject(error);
          }
        },
        ontimeout() {
          if (attempt < retries) {
            setTimeout((() => {
              requestAttempt(attempt + 1).then(resolve).catch(reject);
            }), retryDelay);
          } else {
            reject('Error: timeout');
          }
        }
      });
    }));
    return requestAttempt(0);
  };
  axiosGM.defaults = {};
  axiosGM.get = function(url, config = {}) {
    return axiosGM({
      ...config,
      url: url,
      method: 'GET'
    });
  };
  axiosGM.post = function(url, data, config = {}) {
    return axiosGM({
      ...config,
      url: url,
      data: data,
      method: 'POST'
    });
  };
  axiosGM.head = function(url, config = {}) {
    return axiosGM({
      ...config,
      url: url,
      method: 'HEAD'
    });
  };
  axiosGM.create = function(instanceDefaults = {}) {
    const instance = config => {
      const mergedConfig = {
        ...axiosGM.defaults,
        ...instanceDefaults,
        ...config
      };
      return axiosGM(mergedConfig);
    };
    instance.defaults = {
      ...axiosGM.defaults,
      ...instanceDefaults
    };
    instance.get = function(url, config = {}) {
      return instance({
        ...config,
        url: url,
        method: 'GET'
      });
    };
    instance.post = function(url, data, config = {}) {
      return instance({
        ...config,
        url: url,
        data: data,
        method: 'POST'
      });
    };
    instance.head = function(url, config = {}) {
      return instance({
        ...config,
        url: url,
        method: 'HEAD'
      });
    };
    instance.create = axiosGM.create;
    return instance;
  };
  const getFwdForSdkUrl = async () => {
    const rawHtml = await axiosGM({
      url: 'https://x.com',
      method: 'GET'
    });
    return [ ...rawHtml.data.matchAll(/"(loader\.FwdForSdk)":"([^"]+?)"/g) ];
  };
  const fwdForSdkExpoter = async url => {
    const {data: data} = await axiosGM.get(url);
    const regex = /Uint8Array\(\w\)\.set\(\[(.*?)\]\)/;
    if (!regex.test(data)) {
      return false;
    }
    const json = `[${data.match(regex)?.[1]}]`;
    const obj = JSON.parse(json);
    return new Uint8Array(obj);
  };
  const getWasmData = async () => {
    const fwdForSdkUrl = await getFwdForSdkUrl();
    for (const url of fwdForSdkUrl) {
      const sdkData = await fwdForSdkExpoter(`https://abs.twimg.com/responsive-web/client-web/${url[1]}.${url[2]}a.js`);
      if (sdkData) {
        return sdkData;
      }
    }
    return false;
  };
  const getFwdForSdk = async () => {
    debug('开始获取 XFwdForSdk');
    const wasmData = await getWasmData();
    debug('获取 wasmData 成功', {
      wasmData: wasmData
    });
    const go = new Go;
    const wasmModule = await WebAssembly.instantiate(wasmData, {
      ...go.importObject,
      env: {
        ...go.importObject.env,
        memory: new WebAssembly.Memory({
          initial: 10
        }),
        table: new WebAssembly.Table({
          initial: 0,
          element: 'anyfunc'
        })
      }
    });
    debug('初始化 wasmModule 成功');
    go.run(wasmModule.instance);
    debug('运行 wasmModule 成功');
    const {str: str, expiryTimeMillis: expiryTimeMillis} = await globalThis.getForwardedForStr();
    debug('获取 XFwdForSdk 成功', {
      str: str,
      expiryTimeMillis: expiryTimeMillis
    });
    return {
      str: str,
      expiryTimeMillis: parseInt(expiryTimeMillis, 10)
    };
  };
  const generateSecCHUA = () => {
    if (navigator.userAgentData && navigator.userAgentData.brands) {
      return navigator.userAgentData.brands.map((brand => `"${brand.brand}";v="${brand.version}"`)).join(', ');
    }
    return '"Google Chrome";v="125", "Chromium";v="125", "Not-A.Brand";v="99"';
  };
  class Twitter extends Social {
    tasks;
    whiteList;
    #verifyId=globalOptions.other.twitterVerifyId;
    #auth=GM_getValue('twitterAuth') || {};
    #cache=GM_getValue('twitterCache') || {};
    #initialized=false;
    #getTID;
    #FwdForSdk;
    #headers={};
    constructor() {
      super();
      const defaultTasksTemplate = {
        users: [],
        retweets: [],
        likes: []
      };
      debug('初始化Twitter实例');
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.twitter || {}
      };
      this.#headers = {
        authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
        'X-Twitter-Auth-Type': 'OAuth2Session',
        'X-Twitter-Active-User': 'yes',
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-origin',
        'sec-ch-ua-platform': '"Windows"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua': generateSecCHUA()
      };
    }
    async init() {
      try {
        debug('开始初始化Twitter模块');
        if (this.#initialized) {
          debug('Twitter模块已初始化');
          return true;
        }
        debug('获取Twitter授权信息');
        if (!await this.#updateAuth()) {
          return false;
        }
        debug('创建Twitter会话和SDK');
        this.#getTID = await getTID();
        this.#FwdForSdk = await getFwdForSdk();
        const isVerified = await this.#verifyAuth();
        if (isVerified) {
          debug('Twitter授权验证成功');
          echoLog({
            before: '[Twitter]'
          }).success(I18n('initSuccess', 'Twitter'));
          this.#initialized = true;
          return true;
        }
        debug('Twitter授权失效,尝试重新获取');
        GM_setValue('twitterAuth', null);
        if (await this.#updateAuth()) {
          debug('Twitter重新授权成功');
          echoLog({
            before: '[Twitter]'
          }).success(I18n('initSuccess', 'Twitter'));
          this.#initialized = true;
          return true;
        }
        debug('Twitter初始化失败');
        echoLog({
          before: '[Twitter]'
        }).error(I18n('initFailed', 'Twitter'));
        return false;
      } catch (error) {
        debug('Twitter初始化发生错误', {
          error: error
        });
        throwError(error, 'Twitter.init');
        return false;
      }
    }
    async #verifyAuth() {
      try {
        debug('开始验证Twitter授权');
        return await this.#toggleUser({
          name: 'verify',
          doTask: true,
          verify: true
        });
      } catch (error) {
        debug('Twitter授权验证发生错误', {
          error: error
        });
        throwError(error, 'Twitter.verifyAuth');
        return false;
      }
    }
    async #updateAuth() {
      try {
        debug('开始更新Twitter授权');
        const logStatus = echoLog({
          text: I18n('updatingAuth', 'Twitter'),
          before: '[Twitter]'
        });
        return await new Promise((resolve => {
          GM_cookie.list({
            url: 'https://x.com/settings/account'
          }, (async (cookies, error) => {
            if (!error) {
              const ct0 = cookies.find((cookie => cookie.name === 'ct0'))?.value;
              const isLogin = cookies.find((cookie => cookie.name === 'twid'))?.value;
              if (isLogin && ct0) {
                debug('成功获取Twitter授权信息');
                GM_setValue('twitterAuth', {
                  ct0: ct0
                });
                this.#auth = {
                  ct0: ct0
                };
                this.#headers['x-csrf-token'] = ct0;
                this.#headers['x-twitter-client-language'] = cookies.find((cookie => cookie.name === 'lang'))?.value || 'en';
                logStatus.success();
                resolve(true);
              } else {
                debug('获取Twitter授权失败:未登录');
                logStatus.error(I18n('needLogin'));
                resolve(false);
              }
            } else {
              debug('获取Twitter授权失败', {
                error: error
              });
              logStatus.error('Error: Update twitter auth failed!');
              resolve(false);
            }
          }));
        }));
      } catch (error) {
        debug('更新Twitter授权时发生错误', {
          error: error
        });
        throwError(error, 'Twitter.updateToken');
        return false;
      }
    }
    async #toggleUser({name: name, doTask: doTask = true, verify: verify = false, retry: retry = false}) {
      try {
        debug('开始处理Twitter用户任务', {
          name: name,
          doTask: doTask,
          verify: verify,
          retry: retry
        });
        if (!doTask && !verify && this.whiteList.users.includes(name)) {
          debug('Twitter用户在白名单中,跳过取消关注', {
            name: name
          });
          echoLog({
            type: 'whiteList',
            text: 'Twitter.unfollowUser',
            id: name,
            before: '[Twitter]'
          });
          return true;
        }
        const userId = verify ? this.#verifyId : await this.userName2id(name);
        if (!userId) {
          return false;
        }
        const logStatus = verify ? echoLog({
          text: I18n('verifyingAuth', 'Twitter'),
          before: '[Twitter]'
        }) : echoLog({
          type: `${doTask ? '' : 'un'}followingTwitterUser`,
          text: name,
          before: '[Twitter]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://x.com/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`,
          method: 'POST',
          headers: {
            ...this.#headers,
            'Content-Type': 'application/x-www-form-urlencoded',
            'x-client-transaction-id': await this.#getTID('POST', `/i/api/1.1/friendships/${doTask ? 'create' : 'destroy'}.json`),
            'x-xp-forwarded-for': this.#FwdForSdk.str
          },
          responseType: 'json',
          data: $.param({
            include_profile_interstitial_type: 1,
            include_blocking: 1,
            include_blocked_by: 1,
            include_followed_by: 1,
            include_want_retweets: 1,
            include_mute_edge: 1,
            include_can_dm: 1,
            include_can_media_tag: 1,
            skip_status: 1,
            id: userId
          })
        });
        if (result !== 'Success') {
          debug('Twitter用户操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200) {
          debug('Twitter用户操作成功', {
            name: name,
            doTask: doTask
          });
          logStatus.success();
          if (doTask && !verify) {
            this.tasks.users = unique([ ...this.tasks.users, name ]);
          }
          return true;
        }
        if (verify && data?.status === 403) {
          if (data.response?.errors?.[0]?.code === 158) {
            debug('Twitter授权验证成功(已关注)');
            logStatus.success();
            return true;
          }
          if (data.response?.errors?.[0]?.code === 353 && !retry && data.responseHeaders?.['set-cookie']) {
            const newCt0 = data.responseHeaders['set-cookie']?.find((cookie => cookie.includes('ct0=')))?.split(';')?.at(0)?.split('=')?.at(-1);
            if (newCt0) {
              debug('获取到新的Twitter授权Token,重试操作');
              this.#auth.ct0 = newCt0;
              GM_setValue('twitterAuth', this.#auth);
              logStatus.warning(I18n('retry'));
              return this.#toggleUser({
                name: name,
                doTask: doTask,
                verify: verify,
                retry: true
              });
            }
          }
        }
        debug('Twitter用户操作失败', {
          status: data?.status,
          statusText: data?.statusText
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('处理Twitter用户任务时发生错误', {
          error: error
        });
        throwError(error, 'Twitter.toggleUser');
        return false;
      }
    }
    async userName2id(name) {
      try {
        debug('开始获取Twitter用户ID', {
          name: name
        });
        const logStatus = echoLog({
          type: 'gettingTwitterUserId',
          text: name,
          before: '[Twitter]'
        });
        const cachedUserId = this.#cache[name];
        if (cachedUserId) {
          debug('从缓存获取到Twitter用户ID', {
            name: name,
            id: cachedUserId
          });
          logStatus.success();
          return cachedUserId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://x.com/i/api/graphql/jUKA--0QkqGIFhmfRZdWrQ/UserByScreenName' + `?variables=%7B%22screen_name%22%3A%22${name}%22%7D&features=%7B%22responsive_web_grok_bio_auto_translation_is_enabled%22%3Afalse%2C%22hidden_profile_subscriptions_enabled%22%3Atrue%2C%22payments_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22subscriptions_verification_info_is_identity_verified_enabled%22%3Atrue%2C%22subscriptions_verification_info_verified_since_enabled%22%3Atrue%2C%22highlights_tweets_tab_ui_enabled%22%3Atrue%2C%22responsive_web_twitter_article_notes_tab_enabled%22%3Atrue%2C%22subscriptions_feature_can_gift_premium%22%3Atrue%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D&fieldToggles=%7B%22withAuxiliaryUserLabels%22%3Atrue%7D`,
          method: 'GET',
          headers: {
            ...this.#headers,
            'content-type': 'application/json',
            referer: `https://x.com/${name}`,
            'x-client-transaction-id': await this.#getTID('GET', '/i/api/graphql/jUKA--0QkqGIFhmfRZdWrQ/UserByScreenName' + `?variables=%7B%22screen_name%22%3A%22${name}%22%7D&features=%7B%22responsive_web_grok_bio_auto_translation_is_enabled%22%3Afalse%2C%22hidden_profile_subscriptions_enabled%22%3Atrue%2C%22payments_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22subscriptions_verification_info_is_identity_verified_enabled%22%3Atrue%2C%22subscriptions_verification_info_verified_since_enabled%22%3Atrue%2C%22highlights_tweets_tab_ui_enabled%22%3Atrue%2C%22responsive_web_twitter_article_notes_tab_enabled%22%3Atrue%2C%22subscriptions_feature_can_gift_premium%22%3Atrue%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D&fieldToggles=%7B%22withAuxiliaryUserLabels%22%3Atrue%7D`),
            'x-xp-forwarded-for': this.#FwdForSdk.str
          },
          responseType: 'json'
        });
        if (result !== 'Success') {
          debug('获取Twitter用户ID请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取Twitter用户ID状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        let response = data.response || (typeof data.responseText === 'object' ? data.responseText : null);
        if (!response) {
          try {
            response = JSON.parse(data.responseText);
          } catch (error) {
            response = null;
          }
        }
        const fetchedUserId = response?.data?.user?.result?.rest_id;
        if (!fetchedUserId) {
          debug('未找到Twitter用户ID', {
            name: name
          });
          logStatus.error(`Error:${data.statusText}(${data.status})`);
          return false;
        }
        debug('成功获取Twitter用户ID', {
          name: name,
          id: fetchedUserId
        });
        this.#setCache(name, fetchedUserId);
        logStatus.success();
        return fetchedUserId;
      } catch (error) {
        debug('获取Twitter用户ID时发生错误', {
          error: error
        });
        throwError(error, 'Twitter.getUserId');
        return false;
      }
    }
    async #toggleRetweet({retweetId: retweetId, doTask: doTask = true, retry: retry = false}) {
      try {
        debug('开始处理Twitter转推任务', {
          retweetId: retweetId,
          doTask: doTask,
          retry: retry
        });
        if (!doTask && this.whiteList.retweets.includes(retweetId)) {
          debug('Twitter转推在白名单中,跳过取消', {
            retweetId: retweetId
          });
          echoLog({
            type: 'whiteList',
            text: 'Twitter.unretweet',
            id: retweetId,
            before: '[Twitter]'
          });
          return true;
        }
        const logStatus = echoLog({
          type: `${doTask ? '' : 'un'}retweetting`,
          text: retweetId,
          before: '[Twitter]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://x.com/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`,
          method: 'POST',
          headers: {
            ...this.#headers,
            'Content-Type': 'application/json',
            origin: 'https://x.com',
            referer: 'https://x.com/home',
            'x-client-transaction-id': await this.#getTID('POST', `/i/api/graphql/${doTask ? 'ojPdsZsimiJrUGLR1sjUtA/CreateRetweet' : 'iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet'}`),
            'x-xp-forwarded-for': this.#FwdForSdk.str
          },
          data: `{"variables":{"${doTask ? '' : 'source_'}tweet_id":"${retweetId}","dark_request":false},"queryId":"${doTask ? 'ojPdsZsimiJrUGLR1sjUtA' : 'iQtK4dl5hBmXewYZuEOKVw'}"}`,
          responseType: 'json'
        });
        if (result !== 'Success') {
          debug('Twitter转推操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 403 && data.response?.errors?.[0]?.code === 353 && !retry && data.responseHeaders?.['set-cookie']) {
          const newCt0 = data.responseHeaders['set-cookie']?.find((cookie => cookie.includes('ct0=')))?.split(';')?.at(0)?.split('=')?.at(-1);
          if (newCt0) {
            debug('获取到新的Twitter授权Token,重试操作');
            this.#auth.ct0 = newCt0;
            GM_setValue('twitterAuth', this.#auth);
            logStatus.warning(I18n('retry'));
            return this.#toggleRetweet({
              retweetId: retweetId,
              doTask: doTask,
              retry: true
            });
          }
        }
        if (data?.status !== 200 && !(data?.status === 403 && data.response?.errors?.[0]?.code === 327)) {
          debug('Twitter转推操作状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        if (data.response?.errors && data.response?.errors?.[0]?.code !== 327) {
          debug('Twitter转推操作出错', {
            error: data.response?.errors?.[0]?.message
          });
          logStatus.error(`Error:${data.response?.errors?.[0]?.message}`);
          return false;
        }
        debug('Twitter转推操作成功', {
          retweetId: retweetId,
          doTask: doTask
        });
        logStatus.success();
        if (doTask) {
          this.tasks.retweets = unique([ ...this.tasks.retweets, retweetId ]);
        }
        return true;
      } catch (error) {
        debug('处理Twitter转推任务时发生错误', {
          error: error
        });
        throwError(error, 'Twitter.toggleRetweet');
        return false;
      }
    }
    async toggle({doTask: doTask = true, userLinks: userLinks = [], retweetLinks: retweetLinks = []}) {
      try {
        debug('开始处理Twitter链接任务', {
          doTask: doTask,
          userLinksCount: userLinks.length,
          retweetLinksCount: retweetLinks.length
        });
        if (!this.#initialized) {
          debug('Twitter模块未初始化');
          echoLog({
            text: I18n('needInit'),
            before: '[Twitter]'
          });
          return false;
        }
        if (doTask && !globalOptions.doTask.twitter.users || !doTask && !globalOptions.undoTask.twitter.users) {
          debug('根据全局选项跳过Twitter用户任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'twitter.users',
            before: '[Twitter]'
          });
        } else {
          const realUsers = this.getRealParams('users', userLinks, doTask, (link => link.match(/https:\/\/x\.com\/([^/]+)/)?.[1] || link.match(/https:\/\/twitter\.com\/([^/]+)/)?.[1]));
          debug('处理后的Twitter用户列表', {
            count: realUsers.length,
            users: realUsers
          });
          if (realUsers.length > 0) {
            for (const user of realUsers) {
              if (Date.now() > this.#FwdForSdk.expiryTimeMillis) {
                debug('Twitter SDK过期,重新获取', {
                  expiryTimeMillis: this.#FwdForSdk.expiryTimeMillis
                });
                this.#FwdForSdk = await getFwdForSdk();
              }
              await this.#toggleUser({
                name: user,
                doTask: doTask
              });
              await delay(1e3);
            }
          }
        }
        if (doTask && !globalOptions.doTask.twitter.retweets || !doTask && !globalOptions.undoTask.twitter.retweets) {
          debug('根据全局选项跳过Twitter转推任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'twitter.retweets',
            before: '[Twitter]'
          });
        } else {
          const realRetweets = this.getRealParams('retweets', retweetLinks, doTask, (link => link.match(/https:\/\/x\.com\/.*?\/status\/([\d]+)/)?.[1] || link.match(/https:\/\/twitter\.com\/.*?\/status\/([\d]+)/)?.[1]));
          debug('处理后的Twitter转推列表', {
            count: realRetweets.length,
            retweets: realRetweets
          });
          if (realRetweets.length > 0) {
            for (const retweet of realRetweets) {
              if (Date.now() > this.#FwdForSdk.expiryTimeMillis) {
                debug('Twitter SDK过期,重新获取');
                this.#FwdForSdk = await getFwdForSdk();
              }
              await this.#toggleRetweet({
                retweetId: retweet,
                doTask: doTask
              });
              await delay(1e3);
            }
          }
        }
        return true;
      } catch (error) {
        debug('处理Twitter链接任务时发生错误', {
          error: error
        });
        throwError(error, 'Twitter.toggle');
        return false;
      }
    }
    #setCache(name, id) {
      try {
        debug('设置Twitter用户ID缓存', {
          name: name,
          id: id
        });
        this.#cache[name] = id;
        GM_setValue('twitterCache', this.#cache);
      } catch (error) {
        debug('设置Twitter用户ID缓存时发生错误', {
          error: error
        });
        throwError(error, 'Twitter.setCache');
      }
    }
  }
  class Vk extends Social {
    tasks;
    whiteList;
    #username='';
    #cache=GM_getValue('vkCache') || {};
    #initialized=false;
    constructor() {
      super();
      const defaultTasksTemplate = {
        names: []
      };
      debug('初始化Vk实例');
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.vk || {}
      };
    }
    async init() {
      try {
        debug('开始初始化Vk模块');
        if (this.#initialized) {
          debug('Vk模块已初始化');
          return true;
        }
        const isVerified = await this.#verifyAuth();
        if (isVerified) {
          debug('Vk授权验证成功');
          echoLog({
            before: '[Vk]'
          }).success(I18n('initSuccess', 'Vk'));
          this.#initialized = true;
          return true;
        }
        debug('Vk初始化失败');
        echoLog({
          before: '[Vk]'
        }).error(I18n('initFailed', 'Vk'));
        return false;
      } catch (error) {
        debug('Vk初始化发生错误', {
          error: error
        });
        throwError(error, 'Vk.init');
        return false;
      }
    }
    async #verifyAuth() {
      try {
        debug('开始验证Vk授权');
        const logStatus = echoLog({
          text: I18n('verifyAuth', 'Vk'),
          before: '[Vk]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://vk.com/im',
          method: 'GET'
        });
        if (result !== 'Success') {
          debug('Vk授权验证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.finalUrl.includes('vk.com/login')) {
          debug('Vk授权验证失败:需要登录');
          logStatus.error(`Error:${I18n('loginVk')}`, true);
          return false;
        }
        if (data?.status !== 200) {
          debug('Vk授权验证状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        this.#username = data.responseText.match(/TopNavBtn__profileLink" href="\/(.*?)"/)?.[1] || '';
        debug('Vk授权验证成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('Vk授权验证发生错误', {
          error: error
        });
        throwError(error, 'Vk.verifyAuth');
        return false;
      }
    }
    async #toggleGroup(name, dataParam, doTask = true) {
      try {
        debug('开始处理Vk群组任务', {
          name: name,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: doTask ? 'joiningVkGroup' : 'leavingVkGroup',
          text: name,
          before: '[Vk]'
        });
        if (dataParam.groupAct === 'enter' && !doTask || dataParam.groupAct === 'leave' && doTask) {
          debug('Vk群组操作已完成,跳过', {
            name: name,
            doTask: doTask
          });
          logStatus.success();
          return true;
        }
        const reqData = {
          act: doTask ? 'enter' : 'leave',
          al: 1,
          gid: dataParam.groupId,
          hash: dataParam.groupHash
        };
        if (doTask) {
          reqData.context = '_';
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://vk.com/al_groups.php',
          method: 'POST',
          headers: {
            origin: 'https://vk.com',
            referer: `https://vk.com/${name}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param(reqData)
        });
        if (result !== 'Success') {
          debug('Vk群组操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('Vk群组操作状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('Vk群组操作成功', {
          name: name,
          doTask: doTask
        });
        logStatus.success();
        if (doTask) {
          this.tasks.names = unique([ ...this.tasks.names, name ]);
        }
        return true;
      } catch (error) {
        debug('处理Vk群组任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.toggleGroup');
        return false;
      }
    }
    async #togglePublic(name, dataParam, doTask = true) {
      try {
        debug('开始处理Vk公共页面任务', {
          name: name,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: doTask ? 'joiningVkPublic' : 'leavingVkPublic',
          text: name,
          before: '[Vk]'
        });
        if (dataParam.publicJoined && doTask || !dataParam.publicJoined && !doTask) {
          debug('Vk公共页面操作已完成,跳过', {
            name: name,
            doTask: doTask
          });
          logStatus.success();
          return true;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://vk.com/al_public.php',
          method: 'POST',
          headers: {
            origin: 'https://vk.com',
            referer: `https://vk.com/${name}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param({
            act: doTask ? 'a_enter' : 'a_leave',
            al: 1,
            pid: dataParam.publicPid,
            hash: dataParam.publicHash
          })
        });
        if (result !== 'Success') {
          debug('Vk公共页面操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('Vk公共页面操作状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('Vk公共页面操作成功', {
          name: name,
          doTask: doTask
        });
        logStatus.success();
        if (doTask) {
          this.tasks.names = unique([ ...this.tasks.names, name ]);
        }
        return true;
      } catch (error) {
        debug('处理Vk公共页面任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.togglePublic');
        return false;
      }
    }
    async #toggleLikeWall(name, dataParam, doTask = true) {
      try {
        debug('开始处理Vk点赞任务', {
          name: name,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: doTask ? 'likingVkPublic' : 'unlikingVkPublic',
          text: name,
          before: '[Vk]'
        });
        const postData = {
          act: 'a_set_reaction',
          al: 1,
          event_subtype: 'post_modal',
          from: 'wall_page',
          hash: dataParam.hash,
          object: dataParam.object,
          track_code: dataParam.trackCode,
          wall: 2
        };
        if (doTask) {
          postData.reaction_id = 0;
        }
        const {result: resultR, statusText: statusTextR, status: statusR, data: dataR} = await httpRequest({
          url: 'https://vk.com/like.php?act=a_set_reaction',
          method: 'POST',
          headers: {
            origin: 'https://vk.com',
            referer: `https://vk.com/${name}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param(postData)
        });
        if (resultR !== 'Success') {
          debug('Vk点赞操作请求失败', {
            result: resultR,
            statusText: statusTextR,
            status: statusR
          });
          logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
          return false;
        }
        if (dataR?.status !== 200) {
          debug('Vk点赞操作状态错误', {
            status: dataR?.status,
            statusText: dataR?.statusText
          });
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        if (dataR.response?.payload?.[1]?.[1]?.like_my !== true) {
          debug('Vk点赞操作验证失败');
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        debug('Vk点赞操作成功', {
          name: name,
          doTask: doTask
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('处理Vk点赞任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.sendWall');
        return false;
      }
    }
    async #sendWall(name) {
      try {
        debug('开始处理Vk转发任务', {
          name: name
        });
        const logStatus = echoLog({
          type: 'sendingVkWall',
          text: name,
          before: '[Vk]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://vk.com/like.php',
          method: 'POST',
          headers: {
            origin: 'https://vk.com',
            referer: `https://vk.com/${name}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param({
            act: 'publish_box',
            al: 1,
            object: name
          })
        });
        if (result !== 'Success') {
          debug('Vk转发操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('Vk转发操作状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const hash = data.responseText.match(/shHash:[\s]*'(.*?)'/)?.[1];
        if (!hash) {
          debug('获取Vk转发hash失败');
          logStatus.error('Error: Get "hash" failed');
          return false;
        }
        const {result: resultR, statusText: statusTextR, status: statusR, data: dataR} = await httpRequest({
          url: 'https://vk.com/like.php',
          method: 'POST',
          headers: {
            origin: 'https://vk.com',
            referer: `https://vk.com/${name}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param({
            Message: '',
            act: 'a_do_publish',
            al: 1,
            close_comments: 0,
            friends_only: 0,
            from: 'box',
            hash: hash,
            list: '',
            mark_as_ads: 0,
            mute_notifications: 0,
            object: name,
            ret_data: 1,
            to: 0
          })
        });
        if (resultR !== 'Success') {
          debug('Vk转发确认请求失败', {
            result: resultR,
            statusText: statusTextR,
            status: statusR
          });
          logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
          return false;
        }
        if (dataR?.status !== 200) {
          debug('Vk转发确认状态错误', {
            status: dataR?.status,
            statusText: dataR?.statusText
          });
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        const jsonData = JSON.parse(dataR.responseText?.replace('\x3c!--', '') || '{}');
        if (jsonData?.payload?.[1]?.[1]?.share_my !== true) {
          debug('Vk转发确认验证失败');
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        debug('Vk转发操作成功', {
          name: name
        });
        logStatus.success();
        const postId = jsonData?.payload?.[1]?.[1]?.post_id;
        const ownerId = jsonData?.payload?.[1]?.[1]?.owner_id;
        if (postId && ownerId) {
          this.#setCache(name, `${ownerId}_${postId}`);
        }
        this.tasks.names = unique([ ...this.tasks.names, name ]);
        return true;
      } catch (error) {
        debug('处理Vk转发任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.sendWall');
        return false;
      }
    }
    async #deleteWall(name, dataParams) {
      try {
        debug('开始处理Vk删除墙任务', {
          name: name
        });
        const logStatus = echoLog({
          type: 'deletingVkWall',
          text: name,
          before: '[Vk]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://vk.com/al_wall.php?act=delete',
          method: 'POST',
          headers: {
            origin: 'https://vk.com',
            referer: `https://vk.com/${this.#username}?w=wall${this.#cache[name]}%2Fall`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          data: $.param({
            act: 'delete',
            al: 1,
            confirm: 0,
            from: 'wkview',
            hash: dataParams.wallHash,
            post: this.#cache[name]
          })
        });
        if (result !== 'Success') {
          debug('Vk删除墙请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('Vk删除墙状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const jsonData = JSON.parse(data.responseText?.replace('\x3c!--', '') || '{}');
        if (!jsonData?.payload?.[1]?.[1]) {
          debug('Vk删除墙验证失败');
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('Vk删除墙操作成功', {
          name: name
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('处理Vk删除墙任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.deleteWall');
        return false;
      }
    }
    async #getId(name, doTask) {
      try {
        debug('开始获取Vk ID', {
          name: name,
          doTask: doTask
        });
        let url = `https://vk.com/${name}`;
        if (/^wall-/.test(name)) {
          if (doTask) {
            return {
              type: 'sendWall'
            };
          }
          if (!this.#cache[name]) {
            return {
              type: 'unSupport'
            };
          }
          url = `https://vk.com/${this.#username}?w=wall${this.#cache[name]}`;
        }
        const logStatus = echoLog({
          type: 'gettingVkId',
          text: name,
          before: '[Vk]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: url,
          method: 'GET'
        });
        if (result !== 'Success') {
          debug('获取Vk ID请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取Vk ID状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const [, groupAct, groupId, , groupHash] = data.responseText.match(/Groups.(enter|leave)\(.*?,.*?([\d]+?), (&#39;|')(.*?)(&#39;|')/) || [];
        const publicHash = data.responseText.match(/"enterHash":"(.*?)"/)?.[1];
        const publicPid = data.responseText.match(/"public_id":([\d]+?),/)?.[1];
        const publicJoined = !data.responseText.includes('Public.subscribe');
        if (groupAct && groupId && groupHash) {
          debug('获取到Vk群组ID', {
            groupAct: groupAct,
            groupId: groupId,
            groupHash: groupHash
          });
          logStatus.success();
          return {
            groupAct: groupAct,
            groupId: groupId,
            groupHash: groupHash,
            type: 'group'
          };
        }
        if (publicHash && publicPid) {
          debug('获取到Vk公共页面ID', {
            publicHash: publicHash,
            publicPid: publicPid,
            publicJoined: publicJoined
          });
          logStatus.success();
          return {
            publicHash: publicHash,
            publicPid: publicPid,
            publicJoined: publicJoined,
            type: 'public'
          };
        }
        if (name.includes('action=like')) {
          const hash = data.responseText.match(/data-reaction-hash="(.*?)"/)?.[1];
          const trackCode = data.responseText.match(/data-post-track-code="(.*?)"/)?.[1];
          const object = name.match(/wall-[\w_]+/)?.[0];
          if (hash && trackCode && object) {
            debug('获取到Vk点赞ID', {
              hash: hash,
              trackCode: trackCode,
              object: object
            });
            logStatus.success();
            return {
              type: 'likeWall',
              hash: hash,
              trackCode: trackCode,
              object: object
            };
          }
        }
        if (data.responseText.includes('wall.deletePost') && !doTask) {
          const wallHash = data.responseText.match(/wall\.deletePost\(this, '.*?', '(.*?)'\)/)?.[1];
          if (wallHash) {
            debug('获取到Vk删除墙ID', {
              wallHash: wallHash
            });
            logStatus.success();
            return {
              type: 'deleteWall',
              wallHash: wallHash
            };
          }
        }
        if (name.includes('wall') && doTask) {
          debug('获取到Vk墙ID');
          logStatus.success();
          return {
            type: 'sendWall'
          };
        }
        debug('未找到Vk ID参数');
        logStatus.error('Error: Parameters not found!');
        return false;
      } catch (error) {
        debug('获取Vk ID时发生错误', {
          error: error
        });
        throwError(error, 'Vk.getId');
        return false;
      }
    }
    async #toggleVk({name: name, doTask: doTask = true}) {
      try {
        debug('开始处理Vk任务', {
          name: name,
          doTask: doTask
        });
        if (!doTask && this.whiteList.names.includes(name)) {
          debug('Vk任务在白名单中,跳过', {
            name: name
          });
          echoLog({
            type: 'whiteList',
            text: 'Vk.undoTask',
            id: name,
            before: '[Vk]'
          });
          return true;
        }
        const formatName = name.replace(/\/$/, '');
        const data = await this.#getId(formatName, doTask);
        if (!data) {
          return false;
        }
        switch (data.type) {
         case 'group':
          return await this.#toggleGroup(formatName, data, doTask);

         case 'public':
          return await this.#togglePublic(formatName, data, doTask);

         case 'likeWall':
          return await this.#toggleLikeWall(formatName, data, doTask);

         case 'sendWall':
          return doTask ? await this.#sendWall(formatName) : true;

         case 'deleteWall':
          return doTask ? true : await this.#deleteWall(formatName, data);

         default:
          debug('未知的Vk任务类型', {
            type: data.type
          });
          return false;
        }
      } catch (error) {
        debug('处理Vk任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.toggleVk');
        return false;
      }
    }
    async toggle({doTask: doTask = true, nameLinks: nameLinks = []}) {
      try {
        debug('开始处理Vk链接任务', {
          doTask: doTask,
          nameLinksCount: nameLinks.length
        });
        if (!this.#initialized) {
          debug('Vk模块未初始化');
          echoLog({
            text: I18n('needInit'),
            before: '[Vk]'
          });
          return false;
        }
        const prom = [];
        if (doTask && !globalOptions.doTask.vk.names || !doTask && !globalOptions.undoTask.vk.names) {
          debug('根据全局选项跳过Vk任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'vk.names',
            before: '[Vk]'
          });
        } else {
          const realNames = this.getRealParams('names', nameLinks, doTask, (link => link.match(/https:\/\/vk\.com\/([^/]+)/)?.[1]));
          debug('处理后的Vk链接列表', {
            count: realNames.length,
            names: realNames
          });
          if (realNames.length > 0) {
            for (const name of realNames) {
              prom.push(this.#toggleVk({
                name: name,
                doTask: doTask
              }));
              await delay(1e3);
            }
          }
        }
        return Promise.all(prom).then((() => true));
      } catch (error) {
        debug('处理Vk链接任务时发生错误', {
          error: error
        });
        throwError(error, 'Vk.toggle');
        return false;
      }
    }
    #setCache(name, postId) {
      try {
        debug('设置Vk缓存', {
          name: name,
          postId: postId
        });
        this.#cache[name] = postId;
        GM_setValue('vkCache', this.#cache);
      } catch (error) {
        debug('设置Vk缓存时发生错误', {
          error: error
        });
        throwError(error, 'Vk.setCache');
      }
    }
  }
  const getInfo = async function(link, type) {
    try {
      debug('开始获取YouTube信息', {
        link: link,
        type: type
      });
      const logStatus = echoLog({
        text: I18n('gettingYtbToken'),
        before: '[Youtube]'
      });
      const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
        url: link,
        method: 'GET'
      });
      if (result !== 'Success') {
        debug('获取YouTube信息请求失败', {
          result: result,
          statusText: statusText,
          status: status
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return {};
      }
      if (data?.status !== 200) {
        debug('获取YouTube信息状态错误', {
          status: data?.status,
          statusText: data?.statusText
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return {};
      }
      if (data.responseText.includes('accounts.google.com/ServiceLogin?service=youtube')) {
        debug('获取YouTube信息失败:需要登录');
        logStatus.error(`Error:${I18n('loginYtb')}`, true);
        return {
          needLogin: true
        };
      }
      const apiKey = data.responseText.match(/"INNERTUBE_API_KEY":"(.*?)"/)?.[1];
      const context = (data.responseText.match(/\(\{"INNERTUBE_CONTEXT":([\w\W]*?)\}\)/) || data.responseText.match(/"INNERTUBE_CONTEXT":([\w\W]*?\}),"INNERTUBE/))?.[1] || '{}';
      const {client: client, request: request} = JSON.parse(context);
      if (!apiKey || !client || !request) {
        debug('获取YouTube信息失败:缺少必要参数');
        logStatus.error('Error: Parameter "apiKey" not found!');
        return {};
      }
      client.hl = 'en';
      if (type === 'channel') {
        const channelId = data.responseText.match(/"channelId":"(.+?)"/)?.[1];
        if (!channelId) {
          debug('获取YouTube频道ID失败');
          logStatus.error('Error: Get "channelId" failed!');
          return {};
        }
        debug('成功获取YouTube频道信息', {
          channelId: channelId
        });
        logStatus.success();
        return {
          params: {
            apiKey: apiKey,
            client: client,
            request: request,
            channelId: channelId
          }
        };
      }
      if (type === 'likeVideo') {
        const videoId = data.responseText.match(/<link rel="shortlinkUrl" href="https:\/\/youtu\.be\/(.*?)">/)?.[1];
        const likeParams = data.responseText.match(/"likeParams":"(.*?)"/)?.[1];
        if (!videoId) {
          debug('获取YouTube视频ID失败');
          logStatus.error('Error: Get "videoId" failed!');
          return {};
        }
        debug('成功获取YouTube视频信息', {
          videoId: videoId
        });
        logStatus.success();
        return {
          params: {
            apiKey: apiKey,
            client: client,
            request: request,
            videoId: videoId,
            likeParams: likeParams
          }
        };
      }
      debug('未知的YouTube信息类型', {
        type: type
      });
      logStatus.error('Error: Unknown type');
      return {};
    } catch (error) {
      debug('获取YouTube信息时发生错误', {
        error: error
      });
      throwError(error, 'Youtube.getInfo');
      return {};
    }
  };
  class Youtube extends Social {
    tasks;
    whiteList;
    #auth=GM_getValue('youtubeAuth') || {};
    #initialized=false;
    #verifyChannel=`https://www.youtube.com/channel/${globalOptions.other.youtubeVerifyChannel}`;
    constructor() {
      super();
      const defaultTasksTemplate = {
        channels: [],
        likes: []
      };
      debug('初始化YouTube实例');
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.youtube || {}
      };
    }
    async init() {
      try {
        debug('开始初始化YouTube模块');
        if (this.#initialized) {
          debug('YouTube模块已初始化');
          return true;
        }
        if (!this.#auth.PAPISID) {
          debug('YouTube授权信息不完整,需要更新授权');
          if (await this.#updateAuth()) {
            this.#initialized = true;
            return true;
          }
          return false;
        }
        const isVerified = await this.#verifyAuth();
        if (isVerified) {
          debug('YouTube授权验证成功');
          echoLog({
            before: '[Youtube]'
          }).success(I18n('initSuccess', 'Youtube'));
          this.#initialized = true;
          return true;
        }
        debug('YouTube授权失效,尝试重新获取');
        GM_setValue('youtubeAuth', null);
        if (await this.#updateAuth()) {
          debug('YouTube重新授权成功');
          echoLog({
            before: '[Youtube]'
          }).success(I18n('initSuccess', 'Youtube'));
          this.#initialized = true;
          return true;
        }
        debug('YouTube初始化失败');
        echoLog({
          before: '[Youtube]'
        }).error(I18n('initFailed', 'Youtube'));
        return false;
      } catch (error) {
        debug('YouTube初始化发生错误', {
          error: error
        });
        throwError(error, 'Youtube.init');
        return false;
      }
    }
    async #verifyAuth() {
      try {
        debug('开始验证YouTube授权');
        return await this.#toggleChannel({
          link: this.#verifyChannel,
          doTask: true,
          verify: true
        });
      } catch (error) {
        debug('YouTube授权验证发生错误', {
          error: error
        });
        throwError(error, 'Youtube.verifyAuth');
        return false;
      }
    }
    async #updateAuth() {
      try {
        debug('开始更新YouTube授权');
        const logStatus = echoLog({
          text: I18n('updatingAuth', 'Youtube'),
          before: '[Youtube]'
        });
        return await new Promise((resolve => {
          GM_cookie.list({
            url: 'https://www.youtube.com/@YouTube'
          }, (async (cookies, error) => {
            if (!error) {
              const PAPISID = cookies.find((cookie => cookie.name === '__Secure-3PAPISID'))?.value;
              if (PAPISID) {
                debug('成功获取YouTube新授权信息');
                GM_setValue('youtubeAuth', {
                  PAPISID: PAPISID
                });
                this.#auth = {
                  PAPISID: PAPISID
                };
                logStatus.success();
                resolve(await this.#verifyAuth());
              } else {
                debug('获取YouTube授权失败:未登录');
                logStatus.error(I18n('needLogin'));
                resolve(false);
              }
            } else {
              debug('获取YouTube授权失败', {
                error: error
              });
              logStatus.error('Error: Update youtube auth failed!');
              resolve(false);
            }
          }));
        }));
      } catch (error) {
        debug('更新YouTube授权时发生错误', {
          error: error
        });
        throwError(error, 'Youtube.updateAuth');
        return false;
      }
    }
    #getInfo(link, type) {
      debug('调用获取YouTube信息方法', {
        link: link,
        type: type
      });
      return getInfo(link, type);
    }
    async #toggleChannel({link: link, doTask: doTask = true, verify: verify = false}) {
      try {
        debug('开始处理YouTube频道任务', {
          link: link,
          doTask: doTask,
          verify: verify
        });
        const {params: params, needLogin: needLogin} = await this.#getInfo(link, 'channel');
        const {apiKey: apiKey, client: client, request: request, channelId: channelId} = params || {};
        if (needLogin) {
          debug('YouTube频道操作失败:需要登录');
          echoLog({
            html: I18n('loginYtb'),
            before: '[Youtube]'
          });
          return false;
        }
        if (!(apiKey && client && request && channelId)) {
          debug('YouTube频道操作失败:获取参数失败');
          echoLog({
            text: '"getYtbToken" failed',
            before: '[Youtube]'
          });
          return false;
        }
        if (!doTask && !verify && this.whiteList.channels.includes(channelId)) {
          debug('YouTube频道在白名单中,跳过取消订阅', {
            channelId: channelId
          });
          echoLog({
            type: 'whiteList',
            text: 'Youtube.unfollowChannel',
            id: channelId,
            before: '[Youtube]'
          });
          return true;
        }
        const logStatus = verify ? echoLog({
          text: I18n('verifyingAuth', 'Youtube'),
          before: '[Youtube]'
        }) : echoLog({
          type: doTask ? 'followingYtbChannel' : 'unfollowingYtbChannel',
          text: channelId,
          before: '[Youtube]'
        });
        const nowTime = parseInt(String((new Date).getTime() / 1e3), 10);
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://www.youtube.com/youtubei/v1/subscription/${doTask ? '' : 'un'}subscribe?key=${apiKey}&prettyPrint=false`,
          method: 'POST',
          headers: {
            origin: 'https://www.youtube.com',
            referer: `https://www.youtube.com/channel/${channelId}`,
            'content-type': 'application/json',
            'x-goog-authuser': '0',
            'x-goog-visitor-id': client?.visitorData,
            'x-origin': 'https://www.youtube.com',
            authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}`
          },
          data: JSON.stringify({
            context: {
              client: client,
              request: {
                sessionId: request?.sessionId,
                internalExperimentFlags: [],
                consistencyTokenJars: []
              },
              user: {}
            },
            channelIds: [ channelId ],
            params: doTask ? 'EgIIAhgA' : 'CgIIAhgA'
          })
        });
        if (result !== 'Success') {
          debug('YouTube频道操作请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('YouTube频道操作状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const isSubscribed = doTask && (/"subscribed":true/.test(data.responseText) || data.responseText.includes('The subscription already exists'));
        const isUnsubscribed = !doTask && /"subscribed":false/.test(data.responseText);
        const isVerified = verify && data.responseText.includes('You may not subscribe to yourself');
        if (isSubscribed || isUnsubscribed || isVerified) {
          debug('YouTube频道操作成功', {
            doTask: doTask,
            verify: verify
          });
          logStatus.success();
          if (doTask && !verify) {
            this.tasks.channels = unique([ ...this.tasks.channels, link ]);
          }
          return true;
        }
        debug('YouTube频道操作失败,需要更新授权');
        logStatus.error(I18n('tryUpdateYtbAuth'), true);
        return false;
      } catch (error) {
        debug('处理YouTube频道任务时发生错误', {
          error: error
        });
        throwError(error, 'Youtube.toggleChannel');
        return false;
      }
    }
    async #toggleLikeVideo({link: link, doTask: doTask = true}) {
      try {
        debug('开始处理YouTube视频点赞任务', {
          link: link,
          doTask: doTask
        });
        const {params: params, needLogin: needLogin} = await this.#getInfo(link, 'likeVideo');
        const {apiKey: apiKey, client: client, request: request, videoId: videoId, likeParams: likeParams} = params || {};
        if (needLogin) {
          debug('YouTube视频点赞失败:需要登录');
          echoLog({
            html: `${I18n('loginYtb')}`,
            before: '[Youtube]'
          });
          return false;
        }
        if (!(apiKey && client && request && videoId && likeParams)) {
          debug('YouTube视频点赞失败:获取参数失败');
          echoLog({
            text: '"getYtbToken" failed',
            before: '[Youtube]'
          });
          return false;
        }
        if (!doTask && this.whiteList.likes.includes(videoId)) {
          debug('YouTube视频在白名单中,跳过取消点赞', {
            videoId: videoId
          });
          echoLog({
            type: 'whiteList',
            text: 'Youtube.unlikeVideo',
            id: videoId,
            before: '[Youtube]'
          });
          return true;
        }
        const logStatus = echoLog({
          type: doTask ? 'likingYtbVideo' : 'unlikingYtbVideo',
          text: videoId,
          before: '[Youtube]'
        });
        const nowTime = parseInt(String((new Date).getTime() / 1e3), 10);
        const likeVideoData = {
          context: {
            client: client,
            request: {
              sessionId: request.sessionId,
              internalExperimentFlags: [],
              consistencyTokenJars: []
            },
            user: {}
          },
          target: {
            videoId: videoId
          }
        };
        if (doTask && !likeParams) {
          debug('YouTube视频点赞失败:缺少likeParams参数');
          logStatus.error('Empty likeParams');
          return false;
        }
        if (doTask) {
          likeVideoData.params = likeParams;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://www.youtube.com/youtubei/v1/like/${doTask ? '' : 'remove'}like?key=${apiKey}`,
          method: 'POST',
          headers: {
            origin: 'https://www.youtube.com',
            referer: `https://www.youtube.com/watch?v=${videoId}`,
            'content-type': 'application/json',
            'x-goog-authuser': '0',
            'x-goog-visitor-id': client.visitorData,
            'x-origin': 'https://www.youtube.com',
            authorization: `SAPISIDHASH ${nowTime}_${sha1(`${nowTime} ${this.#auth.PAPISID} https://www.youtube.com`)}`
          },
          data: JSON.stringify(likeVideoData)
        });
        if (result !== 'Success') {
          debug('YouTube视频点赞请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('YouTube视频点赞状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const isLiked = doTask && data.responseText.includes('Added to Liked videos');
        const isUnliked = !doTask && (data.responseText.includes('Removed from Liked videos') || data.responseText.includes('Dislike removed'));
        if (isLiked || isUnliked) {
          debug('YouTube视频点赞操作成功', {
            doTask: doTask
          });
          logStatus.success();
          if (doTask) {
            this.tasks.likes = unique([ ...this.tasks.likes, link ]);
          }
          return true;
        }
        debug('YouTube视频点赞失败,需要更新授权');
        logStatus.error(I18n('tryUpdateYtbAuth'), true);
        return false;
      } catch (error) {
        debug('处理YouTube视频点赞任务时发生错误', {
          error: error
        });
        throwError(error, 'Youtube.toggleLikeVideo');
        return false;
      }
    }
    async toggle({doTask: doTask = true, channelLinks: channelLinks = [], videoLinks: videoLinks = []}) {
      try {
        debug('开始处理YouTube链接任务', {
          doTask: doTask,
          channelLinksCount: channelLinks.length,
          videoLinksCount: videoLinks.length
        });
        if (!this.#initialized) {
          debug('YouTube模块未初始化');
          echoLog({
            text: I18n('needInit'),
            before: '[Youtube]'
          });
          return false;
        }
        const prom = [];
        const shouldProcessChannels = doTask && globalOptions.doTask.youtube.channels || !doTask && globalOptions.undoTask.youtube.channels;
        const shouldProcessVideos = doTask && globalOptions.doTask.youtube.likes || !doTask && globalOptions.undoTask.youtube.likes;
        if (!shouldProcessChannels) {
          debug('根据全局选项跳过YouTube频道任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'youtube.channels',
            before: '[Youtube]'
          });
        } else {
          const realChannels = this.getRealParams('channels', channelLinks, doTask, (link => {
            if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) {
              return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1];
            }
            return link;
          }));
          debug('处理后的YouTube频道链接列表', {
            count: realChannels.length,
            channels: realChannels
          });
          if (realChannels.length > 0) {
            for (const channel of realChannels) {
              prom.push(this.#toggleChannel({
                link: channel,
                doTask: doTask
              }));
              await delay(1e3);
            }
          }
        }
        if (!shouldProcessVideos) {
          debug('根据全局选项跳过YouTube视频任务', {
            doTask: doTask
          });
          echoLog({
            type: 'globalOptionsSkip',
            text: 'youtube.likes',
            before: '[Youtube]'
          });
        } else {
          const realLikes = this.getRealParams('likes', videoLinks, doTask, (link => {
            if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www\.youtube\.com\/.*/.test(link)) {
              return link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1];
            }
            return link;
          }));
          debug('处理后的YouTube视频链接列表', {
            count: realLikes.length,
            videos: realLikes
          });
          if (realLikes.length > 0) {
            for (const video of realLikes) {
              prom.push(this.#toggleLikeVideo({
                link: video,
                doTask: doTask
              }));
              await delay(1e3);
            }
          }
        }
        return Promise.all(prom).then((() => true));
      } catch (error) {
        debug('处理YouTube链接任务时发生错误', {
          error: error
        });
        throwError(error, 'Youtube.toggle');
        return false;
      }
    }
  }
  class SteamASF {
    #asfOptions;
    #botName='asf';
    #groupInfo;
    #steamWebApiKey;
    #steamId;
    constructor({AsfIpcUrl: AsfIpcUrl, AsfIpcPassword: AsfIpcPassword, AsfBotname: AsfBotname, steamWebApiKey: steamWebApiKey}) {
      debug('初始化SteamASF实例', {
        AsfIpcUrl: AsfIpcUrl,
        AsfBotname: AsfBotname
      });
      const asfCommandsUrl = new URL('/Api/Command/', AsfIpcUrl);
      this.#asfOptions = {
        url: asfCommandsUrl.href,
        method: 'POST',
        responseType: 'json',
        headers: {
          accept: 'application/json',
          'Content-Type': 'application/json',
          Host: asfCommandsUrl.host,
          Origin: asfCommandsUrl.origin,
          Referer: asfCommandsUrl.href,
          Authentication: AsfIpcPassword
        }
      };
      if (AsfBotname) {
        this.#botName = AsfBotname;
      }
      if (steamWebApiKey) {
        this.#steamWebApiKey = steamWebApiKey;
      }
      debug('SteamASF实例初始化完成', {
        botName: this.#botName
      });
    }
    async init() {
      try {
        debug('开始初始化ASF');
        const logStatus = echoLog({
          text: I18n('initingASF'),
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: '{"Command":"!stats"}'
        });
        if (result !== 'Success') {
          debug('ASF初始化请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.response?.Success === true && data.response.Message === 'OK' && data.response.Result) {
          debug('ASF初始化成功');
          logStatus.success();
          return true;
        }
        if (data?.response?.Result || data?.response?.Message) {
          debug('ASF初始化失败', {
            result: data?.response?.Result,
            message: data?.response?.Message
          });
          logStatus.error(data?.response?.Result || data.response.Message);
          return false;
        }
        debug('ASF初始化失败', {
          statusText: data?.statusText,
          status: data?.status
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('ASF初始化发生错误', {
          error: error
        });
        throwError(error, 'SteamASF.init');
        return false;
      }
    }
    async joinGroup(groupName) {
      try {
        debug('开始加入Steam组', {
          groupName: groupName
        });
        const logStatus = echoLog({
          type: 'joiningSteamGroup',
          text: groupName,
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!JOINGROUP ${this.#botName} ${groupName}`
          })
        });
        if (result !== 'Success') {
          debug('加入Steam组请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '已加入', '已申请', 'Joined', 'Applied', 'Присоединился', 'costs' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功加入Steam组', {
            groupName: groupName
          });
          logStatus.success();
          return true;
        }
        debug('加入Steam组失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('加入Steam组时发生错误', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'SteamASF.joinGroup');
        return false;
      }
    }
    joinOfficialGroup=this.joinGroup;
    leaveOfficialGroup=this.leaveGroup;
    async leaveGroup(groupName) {
      try {
        debug('开始退出Steam组', {
          groupName: groupName
        });
        if (!this.#groupInfo) {
          debug('未找到组信息,尝试获取组ID');
          if (!await this.#getGroupId()) {
            return false;
          }
        }
        const groupId = await this.#groupInfo[groupName];
        if (!groupId) {
          debug('未找到组ID', {
            groupName: groupName
          });
          return false;
        }
        const logStatus = echoLog({
          type: 'leavingSteamGroup',
          text: groupName,
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!LEAVEGROUP ${this.#botName} ${groupId}`
          })
        });
        if (result !== 'Success') {
          debug('退出Steam组请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功退出Steam组', {
            groupName: groupName
          });
          logStatus.success();
          return true;
        }
        debug('退出Steam组失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('退出Steam组时发生错误', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'SteamASF.leaveGroup');
        return false;
      }
    }
    async #getGroupId() {
      try {
        debug('开始获取Steam组ID列表');
        const logStatus = echoLog({
          type: 'gettingSteamGroupId',
          text: 'All',
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!GROUPLIST ${this.#botName}`
          })
        });
        if (result !== 'Success') {
          debug('获取Steam组ID列表请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && data.response?.Result?.includes('|')) {
          this.#groupInfo = Object.fromEntries(data.response.Result.split('\n').map((line => {
            const [, name, id] = line.trim().split('|');
            if (name && id) {
              return [ name, id ];
            }
            return null;
          })).filter((ele => ele)));
          debug('成功获取Steam组ID列表', {
            groupCount: Object.keys(this.#groupInfo).length
          });
          logStatus.success();
          return true;
        }
        debug('获取Steam组ID列表失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('获取Steam组ID列表时发生错误', {
          error: error
        });
        throwError(error, 'SteamASF.getGroupID');
        return false;
      }
    }
    async addToWishlist(gameId) {
      try {
        debug('开始添加游戏到愿望单', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'addingToWishlist',
          text: gameId,
          before: '[ASF]'
        });
        const gameStatus = await this.#checkGame(gameId);
        if (gameStatus.wishlist === true) {
          debug('游戏已在愿望单中', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!ADDWISHLIST ${this.#botName} ${gameId}`
          })
        });
        if (result !== 'Success') {
          debug('添加游戏到愿望单请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功添加游戏到愿望单', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        debug('添加游戏到愿望单失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('添加游戏到愿望单时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamASF.addToWishlist');
        return false;
      }
    }
    async removeFromWishlist(gameId) {
      try {
        debug('开始从愿望单移除游戏', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'removingFromWishlist',
          text: gameId,
          before: '[ASF]'
        });
        const gameStatus = await this.#checkGame(gameId);
        if (gameStatus.wishlist === false) {
          debug('游戏已不在愿望单中', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!REMOVEWISHLIST ${this.#botName} ${gameId}`
          })
        });
        if (result !== 'Success') {
          debug('从愿望单移除游戏请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功从愿望单移除游戏', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        debug('从愿望单移除游戏失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('从愿望单移除游戏时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamASF.removeFromWishlist');
        return false;
      }
    }
    async toggleFollowGame(gameId, doTask) {
      try {
        debug('开始处理游戏关注状态', {
          gameId: gameId,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: `${doTask ? '' : 'un'}followingGame`,
          text: gameId,
          before: '[ASF]'
        });
        const gameStatus = await this.#checkGame(gameId);
        if (doTask && gameStatus.followed === true || !doTask && gameStatus.followed === false) {
          debug('游戏关注状态已符合要求', {
            gameId: gameId,
            doTask: doTask,
            currentStatus: gameStatus.followed
          });
          logStatus.success();
          return true;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!${doTask ? '' : 'UN'}FOLLOWGAME ${this.#botName} ${gameId}`
          })
        });
        if (result !== 'Success') {
          debug('处理游戏关注状态请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功处理游戏关注状态', {
            gameId: gameId,
            doTask: doTask
          });
          logStatus.success();
          return true;
        }
        debug('处理游戏关注状态失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('处理游戏关注状态时发生错误', {
          error: error,
          gameId: gameId,
          doTask: doTask
        });
        throwError(error, 'SteamASF.toggleFollowGame');
        return false;
      }
    }
    async #checkGame(gameId) {
      try {
        debug('开始检查游戏状态', {
          gameId: gameId
        });
        const {result: result, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!CHECK ${this.#botName} ${gameId}`
          })
        });
        if (result !== 'Success') {
          debug('检查游戏状态请求失败', {
            result: result
          });
          return {};
        }
        if (data?.status !== 200 || !data.response?.Result?.includes(gameId)) {
          debug('检查游戏状态响应无效', {
            status: data?.status
          });
          return {};
        }
        const matchedResult = data.response.Result.split('\n').find((result => result.includes(gameId)))?.split('|');
        if (!matchedResult || matchedResult.length <= 3) {
          debug('未找到游戏状态信息', {
            gameId: gameId
          });
          return {};
        }
        const status = {
          wishlist: matchedResult.at(-3).trim() === '√' || matchedResult.at(-2).trim() === '√',
          followed: matchedResult.at(-1).trim() === '√'
        };
        debug('成功获取游戏状态', {
          gameId: gameId,
          status: status
        });
        return status;
      } catch (error) {
        debug('检查游戏状态时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamASF.checkGame');
        return {};
      }
    }
    async toggleCurator(curatorId, doTask = true) {
      try {
        debug('开始处理鉴赏家关注状态', {
          curatorId: curatorId,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: doTask ? 'followingCurator' : 'unfollowingCurator',
          text: curatorId,
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!${doTask ? '' : 'UN'}FOLLOWCURATOR ${this.#botName} ${curatorId}`
          })
        });
        if (result !== 'Success') {
          debug('处理鉴赏家关注状态请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功处理鉴赏家关注状态', {
            curatorId: curatorId,
            doTask: doTask
          });
          logStatus.success();
          return true;
        }
        if (data?.status === 200) {
          debug('处理鉴赏家关注状态失败', {
            result: data?.response?.Result,
            message: data?.response?.Message
          });
          logStatus.error(I18n('curatorLimitNotice'));
          return false;
        }
        debug('处理鉴赏家关注状态失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('处理鉴赏家关注状态时发生错误', {
          error: error,
          curatorId: curatorId,
          doTask: doTask
        });
        throwError(error, 'Steam.toggleCurator');
        return false;
      }
    }
    async addLicense(id) {
      try {
        debug('开始添加许可证', {
          id: id
        });
        const [type, ids] = id.split('-');
        const idsArr = ids.split(',');
        if (type === 'appid') {
          const logStatus = echoLog({
            type: 'addingFreeLicense',
            text: ids,
            before: '[ASF]'
          });
          const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
            ...this.#asfOptions,
            data: JSON.stringify({
              Command: `!addlicense ${this.#botName} ${idsArr.map((id => `app/${id}`)).join(',')}`
            })
          });
          if (result !== 'Success') {
            debug('添加应用许可证请求失败', {
              result: result,
              statusText: statusText,
              status: status
            });
            logStatus.error(`${result}:${statusText}(${status})`);
            return false;
          }
          if (data?.status === 200 && [ 'AlreadyPurchased', 'OK' ].find((text => data.response?.Result?.includes(text)))) {
            debug('成功添加应用许可证', {
              ids: ids
            });
            logStatus.success();
            return true;
          }
          debug('添加应用许可证失败', {
            result: data?.response?.Result,
            message: data?.response?.Message
          });
          logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
          return false;
        }
        if (type === 'subid') {
          const logStatus = echoLog({
            type: 'addingFreeLicenseSubid',
            text: ids,
            before: '[ASF]'
          });
          const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
            ...this.#asfOptions,
            data: JSON.stringify({
              Command: `!addlicense ${this.#botName} ${idsArr.map((id => `sub/${id}`)).join(',')}`
            })
          });
          if (result !== 'Success') {
            debug('添加订阅许可证请求失败', {
              result: result,
              statusText: statusText,
              status: status
            });
            logStatus.error(`${result}:${statusText}(${status})`);
            return false;
          }
          if (data?.status === 200 && data.response?.Result) {
            const resultLines = data.response.Result.split('\n');
            debug('处理订阅许可证结果', {
              resultLines: resultLines
            });
            idsArr.forEach((subid => {
              const targetLine = resultLines.find((text => text.includes(subid)));
              if (targetLine && [ '成功', 'Success', 'Успех' ].find((text => targetLine.includes(text)))) {
                debug('成功添加订阅许可证', {
                  subid: subid
                });
                echoLog({
                  before: '[ASF]'
                }).success(targetLine);
              } else {
                debug('添加订阅许可证失败', {
                  subid: subid,
                  targetLine: targetLine
                });
                echoLog({
                  before: '[ASF]'
                }).error(targetLine);
              }
            }));
            return true;
          }
          debug('添加订阅许可证失败', {
            result: data?.response?.Result,
            message: data?.response?.Message
          });
          logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
          return false;
        }
        debug('无效的许可证类型', {
          type: type
        });
        return false;
      } catch (error) {
        debug('添加许可证时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'SteamASF.addLicense');
        return false;
      }
    }
    async requestPlayTestAccess(id) {
      try {
        debug('开始请求游戏试玩权限', {
          id: id
        });
        const logStatus = echoLog({
          type: 'requestingPlayTestAccess',
          text: id,
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!REQUESTACCESS ${this.#botName} ${id}`
          })
        });
        if (result !== 'Success') {
          debug('请求游戏试玩权限请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '成功', 'Success', 'Успех' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功请求游戏试玩权限', {
            id: id
          });
          logStatus.success();
          return true;
        }
        debug('请求游戏试玩权限失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('请求游戏试玩权限时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'SteamASF.requestPlayTestAccess');
        return false;
      }
    }
    async playGames(ids) {
      try {
        debug('开始挂游戏时长', {
          ids: ids
        });
        const logStatus = echoLog({
          text: I18n('playingGames', ids),
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!play ${this.#botName} ${ids}`
          })
        });
        if (result !== 'Success') {
          debug('挂游戏时长请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '正在运行', '正在掛', 'Playing', 'Играет' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功开始挂游戏时长', {
            ids: ids
          });
          logStatus.success();
          return true;
        }
        debug('开始挂游戏时长失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('挂游戏时长时发生错误', {
          error: error,
          ids: ids
        });
        throwError(error, 'SteamASF.playGames');
        return false;
      }
    }
    async getSteamIdASF() {
      try {
        debug('开始获取Steam ID');
        const logStatus = echoLog({
          text: I18n('gettingSteamId'),
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!steamid ${this.#botName}`
          })
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('获取Steam ID请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return '';
        }
        if (data.response?.Result) {
          const steamId = data.response.Result.trim()?.split(/\s+/)?.at(-1);
          if (steamId) {
            debug('成功获取Steam ID', steamId);
            logStatus.success();
            return steamId;
          }
        }
        debug('获取Steam ID失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return '';
      } catch (error) {
        debug('获取Steam ID时发生错误', {
          error: error
        });
        throwError(error, 'SteamASF.getSteamIdASF');
        return '';
      }
    }
    async getSteamIdWeb() {
      try {
        debug('开始获取Steam ID');
        const logStatus = echoLog({
          text: I18n('gettingSteamId'),
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://store.steampowered.com',
          method: 'GET',
          headers: {
            host: 'store.steampowered.com'
          }
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('获取Steam ID请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return '';
        }
        const steamId = data.responseText.match(/steamid&quot;:&quot;(\d+)/)?.[1];
        if (steamId) {
          debug('成功获取Steam ID', steamId);
          logStatus.success();
          return steamId;
        }
        debug('获取Steam ID失败', {
          data: data
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return '';
      } catch (error) {
        debug('获取Steam ID时发生错误', {
          error: error
        });
        throwError(error, 'SteamASF.getSteamIdWeb');
        return '';
      }
    }
    async getSteamId() {
      const steamId = await this.getSteamIdWeb();
      if (steamId) {
        return steamId;
      }
      return this.getSteamIdASF();
    }
    async checkPlayStatus(ids) {
      try {
        debug('开始检查挂游戏时长状态');
        if (!this.#steamWebApiKey) {
          debug('未设置Steam Web API Key');
          return 'skip';
        }
        if (!this.#steamId) {
          const steamId = await this.getSteamId();
          if (!steamId) {
            debug('未获取到Steam ID');
            return 'skip';
          }
          this.#steamId = steamId;
        }
        const logStatus = echoLog({
          text: I18n('checkingPlayStatus'),
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${this.#steamWebApiKey}&steamids=${this.#steamId}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/json'
          }
        });
        if (result !== 'Success') {
          debug('检查挂游戏时长状态请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200) {
          debug('挂游戏时长状态正常', {
            data: data
          });
          const playedIds = new Set(data.responseText?.match(/\d+/g));
          const neededIds = new Set(ids.match(/\d+/g));
          if (neededIds.intersection(playedIds).size > 0) {
            logStatus.success();
            return true;
          }
          logStatus.warning(I18n('noPlayStatus'));
          return false;
        }
        debug('挂游戏时长状态异常', {
          data: data
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('检查挂游戏时长状态时发生错误', {
          error: error
        });
        throwError(error, 'SteamASF.checkPlayStatus');
        return false;
      }
    }
    async stopPlayGames() {
      try {
        debug('开始停止挂游戏时长');
        const logStatus = echoLog({
          text: I18n('stoppingPlayGames'),
          before: '[ASF]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          ...this.#asfOptions,
          data: JSON.stringify({
            Command: `!resume ${this.#botName}`
          })
        });
        if (result !== 'Success') {
          debug('停止挂游戏时长请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status === 200 && [ '已经恢复', '已恢复', '已經繼續', '已繼續', 'resumed', 'возобновлён' ].find((text => data.response?.Result?.includes(text)))) {
          debug('成功停止挂游戏时长');
          logStatus.success();
          return true;
        }
        debug('停止挂游戏时长失败', {
          result: data?.response?.Result,
          message: data?.response?.Message
        });
        logStatus.error(`Error:${data?.response?.Result || data?.response?.Message || data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('停止挂游戏时长时发生错误', {
          error: error
        });
        throwError(error, 'SteamASF.stopPlayGames');
        return false;
      }
    }
    async #unsupportted(name) {
      try {
        debug('尝试使用不支持的功能', {
          name: name
        });
        echoLog({
          before: '[ASF]'
        }).warning(I18n('ASFNotSupportted', name));
        return false;
      } catch (error) {
        debug('处理不支持的功能时发生错误', {
          error: error,
          name: name
        });
        throwError(error, 'SteamASF.unsupportted');
        return false;
      }
    }
    async toggleForum() {
      return this.#unsupportted('toggleForum');
    }
    async toggleFavoriteWorkshop() {
      return this.#unsupportted('toggleFavoriteWorkshop');
    }
    async voteUpWorkshop() {
      return this.#unsupportted('voteUpWorkshop');
    }
    async likeAnnouncement() {
      return this.#unsupportted('likeAnnouncement');
    }
  }
  class SteamWeb {
    #cache={
      ...{
        group: {},
        officialGroup: {},
        forum: {},
        workshop: {},
        curator: {}
      },
      ...GM_getValue('steamCache')
    };
    #auth={};
    #storeInitialized=false;
    #communityInitialized=false;
    #area='CN';
    #oldArea;
    #areaStatus='end';
    constructor() {
      debug('初始化SteamWeb实例');
    }
    async init(type = 'all') {
      try {
        debug('开始初始化SteamWeb', {
          type: type
        });
        const initStoreResult = await this.initStore();
        debug('Steam商店初始化完成', {
          initStoreResult: initStoreResult
        });
        if (type === 'store') {
          return initStoreResult;
        }
        const initCommunityResult = await this.initCommunity(initStoreResult);
        debug('Steam社区初始化完成', {
          initCommunityResult: initCommunityResult
        });
        return initCommunityResult;
      } catch (error) {
        debug('SteamWeb初始化发生错误', {
          error: error,
          type: type
        });
        throwError(error, 'SteamWeb.init');
        return false;
      }
    }
    async initStore() {
      try {
        debug('开始初始化Steam商店');
        if (this.#storeInitialized) {
          return true;
        }
        let storeInitialized = await this.#updateStoreAuth();
        if (!storeInitialized) {
          storeInitialized = await this.#updateStoreAuthTab();
        }
        this.#storeInitialized = storeInitialized;
        if (!this.#storeInitialized) {
          echoLog({
            before: '[Web]'
          }).error(I18n('initFailed', 'Steam'));
          return false;
        }
        echoLog({
          before: '[Web]'
        }).success(I18n('initSuccess', 'SteamStore'));
        debug('Steam商店初始化完成');
        return true;
      } catch (error) {
        debug('Steam商店初始化发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.initStore');
        return false;
      }
    }
    async initCommunity(initStoreResult) {
      try {
        debug('开始初始化Steam社区');
        if (this.#communityInitialized) {
          return true;
        }
        let communityInitialized = await this.#updateCommunityAuth(initStoreResult);
        if (!communityInitialized) {
          communityInitialized = await this.#updateCommunityAuthTab();
          GM_setValue('steamCommunityAuth', null);
        }
        this.#communityInitialized = communityInitialized;
        if (!this.#communityInitialized) {
          echoLog({
            before: '[Web]'
          }).error(I18n('initFailed', 'Steam'));
          return false;
        }
        echoLog({
          before: '[Web]'
        }).success(I18n('initSuccess', 'SteamCommunity'));
        debug('Steam社区初始化完成');
        return true;
      } catch (error) {
        debug('Steam社区初始化发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.initCommunity');
        return false;
      }
    }
    async #refreshToken(type = 'steamStore') {
      try {
        debug('开始刷新令牌', {
          type: type
        });
        const host = {
          steamStore: 'store.steampowered.com',
          steamCommunity: 'steamcommunity.com'
        };
        const logStatus = echoLog({
          text: I18n('refreshingToken', I18n(type)),
          before: '[Web]'
        });
        debug('准备刷新令牌请求数据');
        const formData = new FormData;
        formData.append('redir', `https://${host[type]}/`);
        debug('发送刷新令牌请求');
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://login.steampowered.com/jwt/ajaxrefresh',
          method: 'POST',
          responseType: 'json',
          headers: {
            Host: 'login.steampowered.com',
            Origin: `https://${host[type]}`,
            Referer: `https://${host[type]}/`
          },
          data: formData
        });
        debug('收到刷新令牌响应', {
          result: result,
          status: status,
          statusText: statusText
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (!data?.response?.success) {
          debug('响应不成功', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('开始设置新令牌');
        if (!await this.#setToken(data.response, type)) {
          debug('设置新令牌失败');
          logStatus.error('Error');
          return false;
        }
        debug('成功刷新令牌');
        logStatus.success();
        return true;
      } catch (error) {
        debug('刷新令牌时发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.refreshToken');
        return false;
      }
    }
    async #setToken(param, type) {
      try {
        const host = {
          steamStore: 'store.steampowered.com',
          steamCommunity: 'steamcommunity.com'
        };
        debug('开始设置Steam令牌', {
          type: type
        });
        const logStatus = echoLog({
          text: I18n('settingToken', I18n(type)),
          before: '[Web]'
        });
        debug('准备表单数据');
        const formData = new FormData;
        formData.append('steamID', param.steamID);
        formData.append('nonce', param.nonce);
        formData.append('redir', param.redir);
        formData.append('auth', param.auth);
        debug('表单数据准备完成', {
          steamID: param.steamID,
          nonce: param.nonce,
          redir: param.redir
        });
        debug('发送设置令牌请求');
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://${host[type]}/login/settoken`,
          method: 'POST',
          headers: {
            Accept: 'application/json, text/plain, */*',
            Host: host[type],
            Origin: `https://${host[type]}`
          },
          data: formData
        });
        debug('收到设置令牌响应', {
          result: result,
          status: status,
          statusText: statusText
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('成功设置令牌');
        logStatus.success();
        return true;
      } catch (error) {
        debug('设置令牌时发生错误', {
          error: error,
          type: type
        });
        throwError(error, 'SteamWeb.setToken');
        return false;
      }
    }
    async #updateStoreAuth(retry = false) {
      try {
        debug('开始更新Steam商店身份验证');
        const logStatus = echoLog({
          text: I18n('updatingAuth', I18n('steamStore')),
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://store.steampowered.com/',
          method: 'GET',
          headers: {
            Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
            'Sec-Fetch-Dest': 'document',
            'Sec-Fetch-Mode': 'navigate',
            'Upgrade-Insecure-Requests': '1'
          },
          redirect: 'manual'
        });
        debug('收到Steam商店身份验证响应', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (data?.status !== 200) {
          if (![ 301, 302 ].includes(data?.status)) {
            debug('Steam商店身份验证状态错误', {
              status: data?.status
            });
            logStatus.error(`${result}:${statusText}(${status})`);
            return false;
          }
          if (!await this.#refreshToken('steamStore')) {
            debug('Steam商店身份验证刷新失败');
            logStatus.error(`Error:${I18n('needLoginSteamStore')}`, true);
            return false;
          }
          if (retry) {
            debug('Steam商店身份验证重试失败');
            logStatus.error(`Error:${I18n('needLoginSteamStore')}`, true);
            return false;
          }
          debug('Steam商店身份验证重试中');
          logStatus.warning(I18n('retry'));
          return this.#updateStoreAuth(true);
        }
        if (!data.responseText.includes('data-miniprofile=')) {
          if (await this.#refreshToken('steamStore')) {
            debug('Steam商店身份验证需要重试');
            logStatus.warning(I18n('retry'));
            if (retry) {
              debug('Steam商店身份验证重试次数超限');
              logStatus.error(`Error:${I18n('needLoginSteamStore')}`, true);
              return false;
            }
            return this.#updateStoreAuth(true);
          }
          debug('Steam商店身份验证失败:需要登录');
          logStatus.error(`Error:${I18n('needLoginSteamStore')}`, true);
          return false;
        }
        const storeSessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1];
        if (!storeSessionID) {
          debug('Steam商店身份验证失败:获取sessionID失败');
          logStatus.error('Error: Get "sessionID" failed');
          return false;
        }
        this.#auth.storeSessionID = storeSessionID;
        debug('Steam商店身份验证更新成功', {
          storeSessionID: storeSessionID
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('更新Steam商店身份验证时发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.updateStoreAuth');
        return false;
      }
    }
    async #updateStoreAuthTab() {
      try {
        debug('开始通过新标签页更新Steam商店身份验证');
        const logStatus = echoLog({
          text: I18n('updatingAuth', I18n('steamStoreTab')),
          before: '[Web]'
        });
        return await new Promise((resolve => {
          GM_deleteValue('steamStoreAuth');
          GM_setValue('ATv4_updateStoreAuth', true);
          const newTab = GM_openInTab('https://store.steampowered.com/', {
            active: true,
            setParent: true
          });
          debug('打开Steam商店新标签页');
          newTab.name = 'ATv4_updateStoreAuth';
          const listenerId = GM_addValueChangeListener('steamStoreAuth', ((key, oldValue, newValue) => {
            debug('监听到Steam商店身份验证值变化', {
              oldValue: oldValue,
              newValue: newValue
            });
            GM_removeValueChangeListener(listenerId);
            GM_deleteValue('ATv4_updateStoreAuth');
            newTab?.close();
            window.focus();
            if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
              this.#auth.storeSessionID = newValue.storeSessionID;
              debug('Steam商店身份验证更新成功', {
                storeSessionID: newValue.storeSessionID
              });
              logStatus.success();
              resolve(true);
              return;
            }
            debug('Steam商店身份验证更新失败');
            logStatus.error('Failed');
            resolve(false);
          }));
          newTab.onclose = () => {
            debug('Steam商店新标签页已关闭');
            GM_deleteValue('ATv4_updateStoreAuth');
          };
        }));
      } catch (error) {
        debug('通过新标签页更新Steam商店身份验证时发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.updateStoreAuthTab');
        return false;
      }
    }
    async #updateCommunityAuthTab() {
      try {
        debug('开始通过新标签页更新Steam社区身份验证');
        const logStatus = echoLog({
          text: I18n('updatingAuth', I18n('steamCommunityTab')),
          before: '[Web]'
        });
        return await new Promise((resolve => {
          GM_deleteValue('steamCommunityAuth');
          GM_setValue('ATv4_updateCommunityAuth', true);
          const newTab = GM_openInTab('https://steamcommunity.com/my', {
            active: true,
            setParent: true
          });
          debug('打开Steam社区新标签页');
          newTab.name = 'ATv4_updateCommunityAuth';
          const listenerId = GM_addValueChangeListener('steamCommunityAuth', ((key, oldValue, newValue) => {
            debug('监听到Steam社区身份验证值变化', {
              oldValue: oldValue,
              newValue: newValue
            });
            GM_removeValueChangeListener(listenerId);
            GM_deleteValue('ATv4_updateCommunityAuth');
            newTab?.close();
            window.focus();
            if (newValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
              this.#auth.steam64Id = newValue.steam64Id;
              this.#auth.communitySessionID = newValue.communitySessionID;
              debug('Steam社区身份验证更新成功', {
                steam64Id: newValue.steam64Id,
                communitySessionID: newValue.communitySessionID
              });
              logStatus.success();
              resolve(true);
              return;
            }
            debug('Steam社区身份验证更新失败');
            logStatus.error('Failed');
            resolve(false);
          }));
          newTab.onclose = () => {
            debug('Steam社区新标签页已关闭');
            GM_deleteValue('ATv4_updateCommunityAuth');
          };
        }));
      } catch (error) {
        debug('通过新标签页更新Steam社区身份验证时发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.updateCommunityAuthTab');
        return false;
      }
    }
    async #updateCommunityAuth(initStoreResult, retry = false) {
      try {
        debug('开始更新Steam社区身份验证');
        const logStatus = echoLog({
          text: I18n('gettingUserInfo'),
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://steamcommunity.com/my',
          method: 'GET',
          headers: {
            Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
            Host: 'steamcommunity.com',
            'Sec-Fetch-Dest': 'document',
            'Sec-Fetch-Mode': 'navigate'
          },
          redirect: 'follow'
        });
        debug('收到Steam社区身份验证响应', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (data?.status !== 200) {
          debug('Steam社区身份验证状态错误', {
            status: data?.status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data.finalUrl.includes('https://steamcommunity.com/login/home')) {
          if (initStoreResult) {
            if (await this.#refreshToken('steamCommunity')) {
              debug('Steam社区身份验证需要重试');
              logStatus.warning(I18n('retry'));
              if (retry) {
                debug('Steam社区身份验证重试次数超限');
                logStatus.error(`Error:${I18n('needLoginSteamCommunity')}`, true);
                return false;
              }
              return this.#updateCommunityAuth(initStoreResult, retry);
            }
          }
          debug('Steam社区身份验证失败:需要登录');
          logStatus.error(`Error:${I18n('needLoginSteamCommunity')}`, true);
          return false;
        }
        const steam64Id = data.responseText.match(/g_steamID = "(.+?)";/)?.[1];
        const communitySessionID = data.responseText.match(/g_sessionID = "(.+?)";/)?.[1];
        if (!steam64Id || !communitySessionID) {
          debug('Steam社区身份验证失败:获取身份信息失败');
          logStatus.error('Error: Get "sessionID" failed');
          return false;
        }
        this.#auth.steam64Id = steam64Id;
        this.#auth.communitySessionID = communitySessionID;
        debug('Steam社区身份验证更新成功', {
          steam64Id: steam64Id,
          communitySessionID: communitySessionID
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('更新Steam社区身份验证时发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.updateCommunityAuth');
        return false;
      }
    }
    async #getAreaInfo() {
      try {
        debug('开始获取Steam地区信息');
        const logStatus = echoLog({
          text: I18n('gettingAreaInfo'),
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://store.steampowered.com/cart/',
          method: 'GET'
        });
        debug('获取地区信息请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('获取地区信息失败', {
            result: result,
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(result === 'Success' ? `Error:${data?.statusText}(${data?.status})` : `${result}:${statusText}(${status})`);
          return {};
        }
        const cartConfigRaw = data.responseText.match(/data-cart_config="(.*?)"/)?.[1];
        debug('cartConfigRaw提取结果', {
          cartConfigRaw: cartConfigRaw
        });
        const temp = document.createElement('div');
        temp.innerHTML = cartConfigRaw || '{}';
        const cartConfigStr = temp.textContent || temp.innerText;
        let cartConfig;
        try {
          cartConfig = JSON.parse(cartConfigStr);
          debug('cartConfig解析成功', {
            cartConfig: cartConfig
          });
        } catch (error) {
          debug('cartConfig解析失败', {
            error: error
          });
          logStatus.error('Error: get country info filed');
          console.error(error);
          return {};
        }
        if (!cartConfig.rgUserCountryOptions) {
          debug('未找到可更换地区');
          logStatus.warning('Warning: Area cannot be changed');
          return {};
        }
        const userInfoRaw = data.responseText.match(/data-userinfo="(.*?)"/)?.[1];
        debug('userInfoRaw提取结果', {
          userInfoRaw: userInfoRaw
        });
        const temp1 = document.createElement('div');
        temp1.innerHTML = userInfoRaw || '{}';
        const userInfoStr = temp1.textContent || temp1.innerText;
        let userInfo;
        try {
          userInfo = JSON.parse(userInfoStr);
          debug('userInfo解析成功', {
            userInfo: userInfo
          });
        } catch (error) {
          debug('userInfo解析失败', {
            error: error
          });
          logStatus.error('Error: get country info filed');
          console.error(error);
          return {};
        }
        const currentArea = userInfo.country_code;
        const areas = Object.keys(cartConfig.rgUserCountryOptions).filter((area => area !== 'help'));
        debug('地区信息提取', {
          currentArea: currentArea,
          areas: areas
        });
        if (!currentArea || areas.length === 0) {
          debug('未获取到当前地区或可更换地区为空', {
            currentArea: currentArea,
            areas: areas
          });
          logStatus.error('Error: get country info filed');
          return {};
        }
        this.#area = currentArea;
        debug('获取地区信息成功', {
          currentArea: currentArea,
          areas: areas
        });
        logStatus.success();
        return {
          currentArea: currentArea,
          areas: areas
        };
      } catch (error) {
        debug('获取地区信息时发生异常', {
          error: error
        });
        throwError(error, 'SteamWeb.getAreaInfo');
        return {};
      }
    }
    async #changeArea(area) {
      try {
        debug('开始更换Steam地区', {
          area: area
        });
        if (this.#areaStatus === 'waiting') {
          debug('当前地区状态为waiting,等待状态改变');
          await new Promise((resolve => {
            const checker = setInterval((() => {
              if (this.#areaStatus !== 'waiting') {
                clearInterval(checker);
                resolve(true);
              }
            }));
          }));
        }
        if (this.#area === area || !area && this.#area !== 'CN') {
          debug('无需更换地区', {
            currentArea: this.#area,
            targetArea: area
          });
          return true;
        }
        this.#areaStatus = 'waiting';
        let aimedArea = area;
        if (!aimedArea) {
          debug('未指定目标地区,自动获取可用地区');
          const {currentArea: currentArea, areas: areas} = await this.#getAreaInfo();
          debug('获取到地区信息', {
            currentArea: currentArea,
            areas: areas
          });
          if (!currentArea || !areas) {
            debug('获取地区信息失败', {
              currentArea: currentArea,
              areas: areas
            });
            this.#areaStatus = 'error';
            return false;
          }
          if (currentArea !== 'CN') {
            debug('当前地区不是CN,无需更换', {
              currentArea: currentArea
            });
            this.#areaStatus = 'skip';
            echoLog({
              text: I18n('notNeededChangeArea'),
              before: '[Web]'
            });
            return 'skip';
          }
          const anotherArea = areas.filter((area => area && area !== 'CN'));
          debug('可更换的其他地区', {
            anotherArea: anotherArea
          });
          if (!anotherArea || anotherArea.length === 0) {
            debug('没有可用的其他地区');
            this.#areaStatus = 'noAnotherArea';
            echoLog({
              text: I18n('noAnotherArea'),
              before: '[Web]'
            });
            return false;
          }
          [aimedArea] = anotherArea;
          debug('选定目标地区', {
            aimedArea: aimedArea
          });
        }
        const logStatus = echoLog({
          text: I18n('changingArea', aimedArea),
          before: '[Web]'
        });
        debug('发送更换地区请求', {
          aimedArea: aimedArea
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://store.steampowered.com/country/setcountry',
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            cc: aimedArea,
            sessionid: this.#auth.storeSessionID
          })
        });
        debug('更换地区请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success' || data?.status !== 200 || data.responseText !== 'true') {
          debug('更换地区失败', {
            result: result,
            status: data?.status,
            statusText: data?.statusText,
            responseText: data?.responseText
          });
          this.#areaStatus = 'error';
          logStatus.error(result === 'Success' ? `Error:${data?.statusText}(${data?.status})` : `${result}:${statusText}(${status})`);
          return 'CN';
        }
        const {currentArea: currentArea} = await this.#getAreaInfo();
        debug('更换后获取到的当前地区', {
          currentArea: currentArea
        });
        if (currentArea) {
          this.#area = currentArea;
          if (!this.#oldArea) {
            this.#oldArea = currentArea;
          }
        }
        if (currentArea !== aimedArea) {
          debug('更换后当前地区与目标地区不符', {
            currentArea: currentArea,
            aimedArea: aimedArea
          });
          this.#areaStatus = 'error';
          logStatus.error('Error: change country filed');
          return 'CN';
        }
        this.#areaStatus = 'success';
        debug('更换地区成功', {
          currentArea: currentArea
        });
        logStatus.success();
        return currentArea;
      } catch (error) {
        debug('更换地区时发生异常', {
          error: error
        });
        this.#areaStatus = 'error';
        throwError(error, 'SteamWeb.changeArea');
        return false;
      }
    }
    async joinGroup(groupName) {
      try {
        debug('开始加入Steam组', {
          groupName: groupName
        });
        const logStatus = echoLog({
          type: 'joiningSteamGroup',
          text: groupName,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/groups/${groupName}`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            action: 'join',
            sessionID: this.#auth.communitySessionID
          })
        });
        if (result !== 'Success') {
          debug('加入Steam组请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || data.responseText.includes('grouppage_join_area')) {
          debug('加入Steam组失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('成功加入Steam组', {
          groupName: groupName
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('加入Steam组时发生错误', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'SteamWeb.joinGroup');
        return false;
      }
    }
    async leaveGroup(groupName) {
      try {
        debug('开始退出Steam组', {
          groupName: groupName
        });
        const groupId = await this.#getGroupId(groupName);
        if (!groupId) {
          return false;
        }
        const logStatus = echoLog({
          type: 'leavingSteamGroup',
          text: groupName,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            sessionID: this.#auth.communitySessionID,
            action: 'leaveGroup',
            groupId: groupId
          })
        });
        if (result !== 'Success') {
          debug('退出Steam组请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || !data.finalUrl.includes('groups')) {
          debug('退出Steam组失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const hasGroupLink = $(data.responseText.replace(/<img.*?>/g, '').toLowerCase()).find(`a[href='https://steamcommunity.com/groups/${groupName.toLowerCase()}']`).length > 0;
        if (hasGroupLink) {
          debug('Error: Group link still exists');
          return false;
        }
        debug('成功退出Steam组', {
          groupName: groupName
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('退出Steam组时发生错误', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'SteamWeb.leaveGroup');
        return false;
      }
    }
    async #getGroupId(groupName) {
      try {
        debug('开始获取Steam组ID', {
          groupName: groupName
        });
        const logStatus = echoLog({
          type: 'gettingSteamGroupId',
          text: groupName,
          before: '[Web]'
        });
        const cachedGroupId = this.#cache.group[groupName];
        if (cachedGroupId) {
          debug('从缓存中获取到组ID', {
            groupName: groupName,
            cachedGroupId: cachedGroupId
          });
          logStatus.success();
          return cachedGroupId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/groups/${groupName}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
        });
        debug('获取组ID请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取组ID请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取组ID响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const matchedGroupId = data.responseText.match(/OpenGroupChat\( '([0-9]+)'/)?.[1];
        debug('正则提取组ID结果', {
          matchedGroupId: matchedGroupId
        });
        if (!matchedGroupId) {
          debug('未能提取到组ID', {
            groupName: groupName
          });
          logStatus.error(`Error:${data.statusText}(${data.status})`);
          return false;
        }
        this.#setCache('group', groupName, matchedGroupId);
        debug('组ID已缓存', {
          groupName: groupName,
          matchedGroupId: matchedGroupId
        });
        logStatus.success();
        return matchedGroupId;
      } catch (error) {
        debug('获取组ID时发生异常', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'SteamWeb.getGroupID');
        return false;
      }
    }
    async joinOfficialGroup(gameId) {
      try {
        debug('开始加入Steam官方组', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'joiningSteamOfficialGroup',
          text: gameId,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/games/${gameId}?action=join&sessionID=${this.#auth.communitySessionID}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
        });
        if (result !== 'Success') {
          debug('加入Steam官方组请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || data.responseText.includes('id="publicGroupJoin"')) {
          debug('加入Steam官方组失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const groupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1];
        if (groupId) {
          this.#setCache('officialGroup', gameId, groupId);
        }
        debug('成功加入Steam官方组', {
          gameId: gameId
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('加入Steam官方组时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.joinOfficialGroup');
        return false;
      }
    }
    async leaveOfficialGroup(gameId) {
      try {
        debug('开始退出Steam官方组', {
          gameId: gameId
        });
        const groupId = await this.#getOfficialGroupId(gameId);
        if (!groupId) {
          return false;
        }
        const logStatus = echoLog({
          type: 'leavingSteamOfficialGroup',
          text: gameId,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/profiles/${this.#auth.steam64Id}/home_process`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            sessionID: this.#auth.communitySessionID,
            action: 'leaveGroup',
            groupId: groupId
          })
        });
        if (result !== 'Success') {
          debug('退出Steam官方组请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('退出Steam官方组失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const {result: resultR, statusText: statusTextR, status: statusR, data: dataR} = await httpRequest({
          url: `https://steamcommunity.com/games/${gameId}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
        });
        if (resultR !== 'Success') {
          debug('退出Steam官方组时发生错误', {
            error: resultR,
            status: statusR,
            statusText: statusTextR
          });
          logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
          return false;
        }
        if (dataR?.status !== 200 || !dataR.responseText.includes('id="publicGroupJoin"')) {
          debug('退出Steam官方组失败', {
            status: dataR?.status
          });
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        debug('成功退出Steam官方组', {
          gameId: gameId
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('退出Steam官方组时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.leaveOfficialGroup');
        return false;
      }
    }
    async #getOfficialGroupId(gameId) {
      try {
        debug('开始获取Steam官方群组ID', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'gettingSteamOfficialGroupId',
          text: gameId,
          before: '[Web]'
        });
        const cachedGroupId = this.#cache.officialGroup[gameId];
        if (cachedGroupId) {
          debug('从缓存中获取到官方群组ID', {
            gameId: gameId,
            cachedGroupId: cachedGroupId
          });
          logStatus.success();
          return cachedGroupId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/games/${gameId}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
        });
        debug('获取官方群组ID请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取官方群组ID请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取官方群组ID响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const matchedGroupId = data.responseText.match(/steam:\/\/friends\/joinchat\/([0-9]+)/)?.[1];
        debug('正则提取官方群组ID结果', {
          matchedGroupId: matchedGroupId
        });
        if (!matchedGroupId) {
          debug('未能提取到官方群组ID', {
            gameId: gameId
          });
          logStatus.error(`Error:${data.statusText}(${data.status})`);
          return false;
        }
        this.#setCache('officialGroup', gameId, matchedGroupId);
        debug('官方群组ID已缓存', {
          gameId: gameId,
          matchedGroupId: matchedGroupId
        });
        logStatus.success();
        return matchedGroupId;
      } catch (error) {
        debug('获取官方群组ID时发生异常', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.getGroupID');
        return false;
      }
    }
    async addToWishlist(gameId) {
      try {
        debug('开始添加游戏到愿望单', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'addingToWishlist',
          text: gameId,
          before: '[Web]'
        });
        const {result: result, data: data} = await httpRequest({
          url: 'https://store.steampowered.com/api/addtowishlist',
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            sessionid: this.#auth.storeSessionID,
            appid: gameId
          }),
          dataType: 'json'
        });
        if (result === 'Success' && data?.status === 200 && data.response?.success === true) {
          debug('成功添加游戏到愿望单', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        const {result: resultR, statusText: statusTextR, status: statusR, data: dataR} = await httpRequest({
          url: `https://store.steampowered.com/app/${gameId}`,
          method: 'GET'
        });
        if (resultR !== 'Success') {
          debug('添加游戏到愿望单请求失败', {
            result: resultR,
            status: statusR,
            statusText: statusTextR
          });
          logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
          return false;
        }
        if (dataR?.status !== 200) {
          debug('添加游戏到愿望单失败', {
            status: dataR?.status
          });
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) {
          debug('changeAreaNotice');
          if (!await this.#changeArea()) {
            return false;
          }
          return await this.addToWishlist(gameId);
        }
        if (dataR.responseText.includes('class="queue_actions_ctn"') && dataR.responseText.includes('class="already_in_library"')) {
          debug('成功添加游戏到愿望单', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        if (dataR.responseText.includes('class="queue_actions_ctn"') && dataR.responseText.includes('id="add_to_wishlist_area_success" style="display: none;') || !dataR.responseText.includes('class="queue_actions_ctn"')) {
          debug('添加游戏到愿望单失败', {
            status: dataR.statusText
          });
          logStatus.error(`Error:${dataR.statusText}(${dataR.status})`);
          return false;
        }
        debug('成功添加游戏到愿望单', {
          gameId: gameId
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('添加游戏到愿望单时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.addToWishlist');
        return false;
      }
    }
    async removeFromWishlist(gameId) {
      try {
        debug('开始从愿望单移除游戏', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'removingFromWishlist',
          text: gameId,
          before: '[Web]'
        });
        const {result: result, data: data} = await httpRequest({
          url: 'https://store.steampowered.com/api/removefromwishlist',
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            sessionid: this.#auth.storeSessionID,
            appid: gameId
          }),
          dataType: 'json'
        });
        if (result === 'Success' && data?.status === 200 && data.response?.success === true) {
          debug('成功从愿望单移除游戏', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        const {result: resultR, statusText: statusTextR, status: statusR, data: dataR} = await httpRequest({
          url: `https://store.steampowered.com/app/${gameId}`,
          method: 'GET'
        });
        if (resultR !== 'Success') {
          debug('从愿望单移除游戏请求失败', {
            result: resultR,
            status: statusR,
            statusText: statusTextR
          });
          logStatus.error(`${resultR}:${statusTextR}(${statusR})`);
          return false;
        }
        if (dataR?.status !== 200) {
          debug('从愿望单移除游戏失败', {
            status: dataR?.status
          });
          logStatus.error(`Error:${dataR?.statusText}(${dataR?.status})`);
          return false;
        }
        if (this.#area === 'CN' && dataR.responseText.includes('id="error_box"')) {
          debug('changeAreaNotice');
          const result = await this.#changeArea();
          if (!result || result === 'CN' || result === 'skip') {
            return false;
          }
          return await this.removeFromWishlist(gameId);
        }
        if (dataR.responseText.includes('class="queue_actions_ctn"') && (dataR.responseText.includes('ds_owned_flag ds_flag') || dataR.responseText.includes('add_to_wishlist_area'))) {
          debug('成功从愿望单移除游戏', {
            gameId: gameId
          });
          logStatus.success();
          return true;
        }
        debug('从愿望单移除游戏请求失败', {
          result: resultR,
          status: statusR,
          statusText: statusTextR
        });
        logStatus.error(`Error:${dataR.statusText}(${dataR.status})`);
        return false;
      } catch (error) {
        debug('从愿望单移除游戏时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.removeFromWishlist');
        return false;
      }
    }
    async toggleFollowGame(gameId, doTask) {
      try {
        debug('开始处理游戏关注状态', {
          gameId: gameId,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: `${doTask ? '' : 'un'}followingGame`,
          text: gameId,
          before: '[Web]'
        });
        const requestData = {
          sessionid: this.#auth.storeSessionID,
          appid: gameId
        };
        if (!doTask) {
          requestData.unfollow = '1';
        }
        const {result: result, data: data} = await httpRequest({
          url: 'https://store.steampowered.com/explore/followgame/',
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param(requestData)
        });
        if (result === 'Success' && data?.status === 200 && data.responseText === 'true') {
          debug('成功处理游戏关注状态', {
            gameId: gameId,
            doTask: doTask
          });
          logStatus.success();
          return true;
        }
        const followed = await this.#isFollowedGame(gameId);
        if (this.#area === 'CN' && followed === 'areaLocked') {
          debug('changeAreaNotice');
          if (!await this.#changeArea()) {
            return false;
          }
          return await this.toggleFollowGame(gameId, doTask);
        }
        if (doTask === followed) {
          debug('成功处理游戏关注状态', {
            gameId: gameId,
            doTask: doTask
          });
          logStatus.success();
          return true;
        }
        debug('处理游戏关注状态请求失败', {
          result: result
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      } catch (error) {
        debug('处理游戏关注状态时发生错误', {
          error: error,
          gameId: gameId,
          doTask: doTask
        });
        throwError(error, 'SteamWeb.toggleFollowGame');
        return false;
      }
    }
    async #isFollowedGame(gameId) {
      try {
        debug('开始判断Steam游戏是否已关注', {
          gameId: gameId
        });
        const {result: result, data: data} = await httpRequest({
          url: `https://store.steampowered.com/app/${gameId}`,
          method: 'GET'
        });
        debug('获取游戏页面请求结果', {
          result: result,
          status: data?.status
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result
          });
          return false;
        }
        if (data?.status !== 200) {
          debug('响应状态错误', {
            status: data?.status
          });
          return false;
        }
        if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
          debug('地区锁定,返回areaLocked', {
            area: this.#area
          });
          return 'areaLocked';
        }
        const isFollowed = $(data.responseText.replace(/<img.*?>/g, '')).find('.queue_control_button.queue_btn_follow>.btnv6_blue_hoverfade.btn_medium.queue_btn_active').css('display') !== 'none';
        debug('关注状态判断结果', {
          isFollowed: isFollowed
        });
        return isFollowed;
      } catch (error) {
        debug('判断游戏关注状态时发生异常', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.isFollowedGame');
        return false;
      }
    }
    async toggleForum(gameId, doTask = true) {
      try {
        debug('开始处理论坛订阅状态', {
          gameId: gameId,
          doTask: doTask
        });
        const forumId = await this.#getForumId(gameId);
        if (!forumId) {
          return false;
        }
        const logStatus = echoLog({
          type: `${doTask ? '' : 'un'}subscribingForum`,
          text: gameId,
          before: '[Web]'
        });
        const [id, feature] = forumId.split('_');
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/forum/${id}/General/${doTask ? '' : 'un'}subscribe/${feature || '0'}/`,
          method: 'POST',
          responseType: 'json',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            sessionid: this.#auth.communitySessionID
          })
        });
        if (result !== 'Success') {
          debug('处理论坛订阅状态请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return true;
        }
        if (data?.status !== 200 || data.response?.success !== 1 && data.response?.success !== 29) {
          debug('处理论坛订阅状态失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return true;
        }
        debug('成功处理论坛订阅状态', {
          gameId: gameId,
          doTask: doTask
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('处理论坛订阅状态时发生错误', {
          error: error,
          gameId: gameId,
          doTask: doTask
        });
        throwError(error, 'SteamWeb.toggleForum');
        return false;
      }
    }
    async #getForumId(gameId) {
      try {
        debug('开始获取Steam论坛ID', {
          gameId: gameId
        });
        const logStatus = echoLog({
          type: 'gettingForumId',
          text: gameId,
          before: '[Web]'
        });
        const cachedForumId = this.#cache.forum[gameId];
        if (cachedForumId) {
          debug('从缓存中获取到论坛ID', {
            gameId: gameId,
            cachedForumId: cachedForumId
          });
          logStatus.success();
          return cachedForumId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/app/${gameId}/discussions/`,
          method: 'GET'
        });
        debug('获取论坛ID请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取论坛ID请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取论坛ID响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const matchedForumId = data.responseText?.match(/General_([\d]+(_[\d]+)?)/)?.[1];
        debug('正则提取论坛ID结果', {
          matchedForumId: matchedForumId
        });
        if (!matchedForumId) {
          debug('未能提取到论坛ID', {
            gameId: gameId
          });
          logStatus.error(`Error:${data.statusText}(${data.status})`);
          return false;
        }
        this.#setCache('forum', gameId, matchedForumId);
        debug('论坛ID已缓存', {
          gameId: gameId,
          matchedForumId: matchedForumId
        });
        logStatus.success();
        return matchedForumId;
      } catch (error) {
        debug('获取论坛ID时发生异常', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'SteamWeb.getForumId');
        return false;
      }
    }
    async toggleFavoriteWorkshop(id, doTask = true) {
      try {
        debug('开始处理创意工坊收藏状态', {
          id: id,
          doTask: doTask
        });
        const appid = await this.#getWorkshopAppId(id);
        if (!appid) {
          return false;
        }
        const logStatus = echoLog({
          type: doTask ? 'favoritingWorkshop' : 'unfavoritingWorkshop',
          text: id,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/sharedfiles/${doTask ? '' : 'un'}favorite`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            id: id,
            appid: appid,
            sessionid: this.#auth.communitySessionID
          })
        });
        if (result !== 'Success') {
          debug('处理创意工坊收藏状态请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || data.responseText) {
          debug('处理创意工坊收藏状态失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('成功处理创意工坊收藏状态', {
          id: id,
          doTask: doTask
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('处理创意工坊收藏状态时发生错误', {
          error: error,
          id: id,
          doTask: doTask
        });
        throwError(error, 'SteamWeb.toggleFavoriteWorkshop');
        return false;
      }
    }
    async #getWorkshopAppId(id) {
      try {
        debug('开始获取Steam创意工坊AppId', {
          id: id
        });
        const logStatus = echoLog({
          type: 'gettingWorkshopAppId',
          text: id,
          before: '[Web]'
        });
        const cachedAppId = this.#cache.workshop[id];
        if (cachedAppId) {
          debug('从缓存中获取到AppId', {
            id: id,
            cachedAppId: cachedAppId
          });
          logStatus.success();
          return cachedAppId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${id}`,
          method: 'GET'
        });
        debug('获取创意工坊AppId请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取创意工坊AppId请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取创意工坊AppId响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const matchedAppId = data.responseText.match(/<input type="hidden" name="appid" value="([\d]+?)" \/>/)?.[1];
        debug('正则提取AppId结果', {
          matchedAppId: matchedAppId
        });
        if (!matchedAppId) {
          debug('未能提取到AppId', {
            id: id
          });
          logStatus.error('Error: getWorkshopAppId failed');
          return false;
        }
        debug('AppId已缓存', {
          id: id,
          matchedAppId: matchedAppId
        });
        return matchedAppId;
      } catch (error) {
        debug('获取创意工坊AppId时发生异常', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.getWorkshopAppId');
        return false;
      }
    }
    async voteUpWorkshop(id) {
      try {
        debug('开始点赞创意工坊物品', {
          id: id
        });
        const logStatus = echoLog({
          type: 'votingUpWorkshop',
          text: id,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://steamcommunity.com/sharedfiles/voteup',
          method: 'POST',
          responseType: 'json',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: $.param({
            id: id,
            sessionid: this.#auth.communitySessionID
          })
        });
        if (result !== 'Success') {
          debug('点赞创意工坊物品请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return true;
        }
        if (data?.status !== 200 || data.response?.success !== 1) {
          debug('点赞创意工坊物品失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return true;
        }
        debug('成功点赞创意工坊物品', {
          id: id
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('点赞创意工坊物品时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.voteUpWorkshop');
        return false;
      }
    }
    async toggleCurator(curatorId, doTask = true) {
      try {
        debug('开始处理鉴赏家关注状态', {
          curatorId: curatorId,
          doTask: doTask
        });
        const logStatus = echoLog({
          type: doTask ? 'followingCurator' : 'unfollowingCurator',
          text: curatorId,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await 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: this.#auth.storeSessionID,
            follow: doTask
          }),
          dataType: 'json'
        });
        if (result !== 'Success') {
          debug('处理鉴赏家关注状态请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.response?.success?.success === 25) {
          debug('处理鉴赏家关注状态失败', {
            status: data?.status,
            success: data?.response?.success,
            message: data?.response?.msg
          });
          logStatus.error(I18n('curatorLimitNotice'));
          return false;
        }
        if (data?.status !== 200 || data.response?.success?.success !== 1) {
          debug('处理鉴赏家关注状态失败', {
            status: data?.status,
            success: data?.response?.success
          });
          logStatus.error(`Error:${data?.statusText}(${data?.response?.success}` || `${data?.status})`);
          return false;
        }
        debug('成功处理鉴赏家关注状态', {
          curatorId: curatorId,
          doTask: doTask
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('处理鉴赏家关注状态时发生错误', {
          error: error,
          curatorId: curatorId,
          doTask: doTask
        });
        throwError(error, 'SteamWeb.toggleCurator');
        return false;
      }
    }
    async #getAnnouncementParams(appId, viewId) {
      try {
        debug('开始获取Steam公告参数', {
          appId: appId,
          viewId: viewId
        });
        const logStatus = echoLog({
          type: 'gettingAnnouncementParams',
          text: appId,
          id: viewId,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/events/ajaxgetpartnerevent?appid=${appId}&announcement_gid=${viewId}&lang_list=6_0&last_modified_time=0&origin=https:%2F%2Fstore.steampowered.com&for_edit=false`,
          method: 'GET',
          responseType: 'json',
          headers: {
            Host: 'store.steampowered.com',
            Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}`
          }
        });
        debug('获取公告参数请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取公告参数请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return {};
        }
        if (data?.status !== 200 || data?.response?.success !== 1) {
          debug('获取公告参数响应状态错误', {
            status: data?.status,
            statusText: data?.statusText,
            response: data?.response
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return {};
        }
        const {clanid: clanid, gid: gid} = data.response.event?.announcement_body || {};
        debug('公告参数提取', {
          clanid: clanid,
          gid: gid
        });
        if (!clanid) {
          debug('未能提取到clanid', {
            appId: appId,
            viewId: viewId
          });
          logStatus.error(`Error:${data.statusText}(${data.status})`);
          return {};
        }
        logStatus.success();
        debug('获取公告参数成功', {
          clanId: clanid,
          gid: gid
        });
        return {
          clanId: clanid,
          gid: gid
        };
      } catch (error) {
        debug('获取公告参数时发生异常', {
          error: error,
          appId: appId,
          viewId: viewId
        });
        throwError(error, 'SteamWeb.likeAnnouncement');
        return {};
      }
    }
    async likeAnnouncement(id) {
      try {
        debug('开始点赞公告', {
          id: id
        });
        const [appId, viewId] = id.split('/');
        if (!(appId && viewId)) {
          echoLog({
            before: '[Web]'
          }).error(`${I18n('missParams')}(id)`);
          return false;
        }
        const {clanId: clanId, gid: gid} = await this.#getAnnouncementParams(appId, viewId);
        if (!clanId) {
          return false;
        }
        const logStatus = echoLog({
          type: 'likingAnnouncement',
          text: appId,
          id: viewId,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/updated/ajaxrateupdate/${gid || viewId}`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            Host: 'store.steampowered.com',
            Origin: 'https://store.steampowered.com',
            Referer: `https://store.steampowered.com/news/app/${appId}/view/${viewId}`
          },
          data: $.param({
            sessionid: this.#auth.storeSessionID,
            voteup: 1,
            clanid: clanId,
            ajax: 1
          }),
          dataType: 'json'
        });
        if (result !== 'Success') {
          debug('点赞公告请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || data.response.success !== 1) {
          debug('点赞公告失败', {
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('成功点赞公告', {
          id: id
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('点赞公告时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.likeAnnouncement');
        return false;
      }
    }
    async #appid2subid(id) {
      try {
        debug('开始将AppId转换为SubId', {
          id: id
        });
        const logStatus = echoLog({
          type: 'gettingSubid',
          text: id,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/app/${id}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
        });
        debug('获取App页面请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取App页面请求失败', {
            result: result
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取App页面响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        if (data.responseText.includes('ds_owned_flag ds_flag') || data.responseText.includes('class="already_in_library"')) {
          debug('App已拥有', {
            id: id
          });
          logStatus.success(I18n('owned'));
          return true;
        }
        if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
          debug('地区锁定,尝试更换地区', {
            area: this.#area
          });
          logStatus.warning(I18n('changeAreaNotice'));
          const result = await this.#changeArea();
          if (!result || result === 'CN' || result === 'skip') {
            debug('更换地区失败或未更换', {
              result: result
            });
            return false;
          }
          return await this.#appid2subid(id);
        }
        let subid = data.responseText.match(/name="subid" value="([\d]+?)"/)?.[1];
        debug('正则提取subid结果1', {
          subid: subid
        });
        if (subid) {
          logStatus.success();
          return subid;
        }
        subid = data.responseText.match(/AddFreeLicense\(\s*(\d+)/)?.[1];
        debug('正则提取subid结果2', {
          subid: subid
        });
        if (subid) {
          logStatus.success();
          return subid;
        }
        debug('未能提取到subid', {
          id: id
        });
        logStatus.error(`Error:${I18n('noSubid')}`);
        return false;
      } catch (error) {
        debug('AppId转SubId时发生异常', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.appid2subid');
        return false;
      }
    }
    async #getLicenses() {
      try {
        debug('开始获取Steam用户许可证信息');
        const logStatus = echoLog({
          text: I18n('gettingLicenses'),
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/dynamicstore/userdata/?t=${(new Date).getTime()}`,
          method: 'GET',
          responseType: 'json'
        });
        debug('获取许可证请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('获取许可证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('获取许可证响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('获取到的许可证列表', {
          licenses: data.response?.rgOwnedPackages
        });
        logStatus.remove();
        return data.response?.rgOwnedPackages;
      } catch (error) {
        debug('获取许可证时发生异常', {
          error: error
        });
        throwError(error, 'SteamWeb.getLicenses');
        return false;
      }
    }
    async addLicense(id) {
      try {
        debug('开始添加许可证', {
          id: id
        });
        const [type, ids] = id.split('-');
        debug('解析许可证ID', {
          type: type,
          ids: ids
        });
        if (type !== 'appid' && type !== 'subid') {
          debug('无效的许可证类型', {
            type: type
          });
          return false;
        }
        if (type === 'appid') {
          debug('处理appid类型许可证', {
            ids: ids
          });
          const subid = await this.#appid2subid(ids);
          debug('appid转换为subid结果', {
            appid: ids,
            subid: subid
          });
          if (!subid) {
            debug('appid转换失败', {
              appid: ids
            });
            return false;
          }
          if (subid === true) {
            debug('appid已拥有', {
              appid: ids
            });
            return true;
          }
          const logStatus = echoLog({
            type: 'addingFreeLicense',
            text: ids,
            before: '[Web]'
          });
          debug('开始添加免费许可证', {
            subid: subid
          });
          if (!await this.#addFreeLicense(subid, logStatus)) {
            debug('添加免费许可证失败', {
              subid: subid
            });
            return false;
          }
          const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
            url: `https://store.steampowered.com/app/${ids}`,
            method: 'GET'
          });
          debug('验证许可证添加状态', {
            result: result,
            status: status,
            statusText: statusText
          });
          if (result !== 'Success') {
            debug('验证请求失败', {
              result: result,
              status: status,
              statusText: statusText
            });
            logStatus.error(`${result}:${statusText}(${status})`);
            return false;
          }
          if (data?.status !== 200) {
            debug('验证响应状态错误', {
              status: data?.status,
              statusText: data?.statusText
            });
            logStatus.error(`Error:${data?.statusText}(${data?.status})`);
            return false;
          }
          if (!data.responseText.includes('ds_owned_flag ds_flag') && !data.responseText.includes('class="already_in_library"')) {
            debug('未找到游戏拥有标记', {
              status: data.status,
              statusText: data.statusText
            });
            logStatus.error(`Error:${data.statusText}(${data.status})`);
            return false;
          }
          debug('appid许可证添加成功', {
            appid: ids
          });
          logStatus.success();
          return true;
        }
        if (this.#area === 'CN') {
          debug('当前区域为CN,尝试更改区域', {
            currentArea: this.#area
          });
          echoLog({
            before: '[Web]'
          }).success(I18n('tryChangeAreaNotice'));
          await this.#changeArea();
        }
        const logStatusArr = {};
        const idsArr = ids.split(',');
        debug('处理subid类型许可证', {
          idsArr: idsArr
        });
        for (const subid of idsArr) {
          debug('开始处理单个subid', {
            subid: subid
          });
          const logStatus = echoLog({
            type: 'addingFreeLicense',
            text: subid,
            before: '[Web]'
          });
          if (!await this.#addFreeLicense(subid, logStatus)) {
            debug('添加subid许可证失败', {
              subid: subid
            });
            return false;
          }
          logStatusArr[subid] = logStatus;
        }
        const licenses = await this.#getLicenses();
        debug('获取许可证列表', {
          licenses: licenses
        });
        if (!licenses) {
          debug('获取许可证列表失败');
          return false;
        }
        for (const subid of idsArr) {
          const hasLicense = licenses.includes(parseInt(subid, 10));
          debug('验证许可证添加状态', {
            subid: subid,
            hasLicense: hasLicense
          });
          if (hasLicense) {
            logStatusArr[subid].success();
          } else {
            logStatusArr[subid].error();
          }
        }
        debug('所有subid许可证处理完成', {
          idsArr: idsArr
        });
        return true;
      } catch (error) {
        debug('添加许可证过程发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.addLicense');
        return false;
      }
    }
    async #addFreeLicense(id, logStatusPre) {
      try {
        debug('开始添加免费Steam游戏许可证', {
          id: id
        });
        const logStatus = logStatusPre || echoLog({
          type: 'addingFreeLicenseSubid',
          text: id,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/freelicense/addfreelicense/${id}`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            Host: 'store.steampowered.com',
            Origin: 'https://store.steampowered.com',
            Referer: 'https://store.steampowered.com/account/licenses/'
          },
          data: $.param({
            ajax: true,
            sessionid: this.#auth.storeSessionID
          }),
          dataType: 'json'
        });
        debug('添加免费许可证请求结果', {
          result: result,
          statusText: statusText,
          status: status
        });
        if (result !== 'Success') {
          debug('添加免费许可证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('添加免费许可证响应状态错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        if (this.#area === 'CN' && data.responseText.includes('id="error_box"')) {
          debug('地区锁定,尝试更换地区', {
            area: this.#area
          });
          logStatus.warning(I18n('changeAreaNotice'));
          const result = await this.#changeArea();
          if (!result || [ 'CN', 'skip' ].includes(result)) {
            debug('更换地区失败或未更换', {
              result: result
            });
            return false;
          }
          return await this.#addFreeLicense(id);
        }
        debug('成功添加免费许可证', {
          id: id
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('添加免费许可证时发生异常', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.addFreeLicense');
        return false;
      }
    }
    async requestPlayTestAccess(id) {
      debug('开始请求游戏试玩权限', {
        id: id
      });
      try {
        debug('开始请求游戏试玩权限', {
          id: id
        });
        const logStatus = echoLog({
          type: 'requestingPlayTestAccess',
          text: id,
          before: '[Web]'
        });
        debug('准备发送试玩权限请求', {
          id: id
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/ajaxrequestplaytestaccess/${id}`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            Host: 'store.steampowered.com',
            Origin: 'https://store.steampowered.com',
            Referer: `https://store.steampowered.com/app/${id}`
          },
          data: $.param({
            sessionid: this.#auth.storeSessionID
          }),
          dataType: 'json'
        });
        debug('收到试玩权限请求响应', {
          result: result,
          status: status,
          statusText: statusText,
          responseData: data
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            status: status,
            statusText: statusText
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || data?.response?.success !== 1) {
          debug('响应状态错误', {
            status: data?.status,
            statusText: data?.statusText,
            success: data?.response?.success
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('成功请求游戏试玩权限', {
          id: id
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('请求游戏试玩权限时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'SteamWeb.requestPlayTestAccess');
        return false;
      }
    }
    async resetArea() {
      try {
        debug('检查区域设置状态', {
          currentArea: this.#area,
          oldArea: this.#oldArea,
          needReset: Boolean(this.#oldArea && this.#area !== this.#oldArea)
        });
        if (this.#oldArea && this.#area !== this.#oldArea) {
          debug('需要重置区域', {
            fromArea: this.#area,
            toArea: this.#oldArea
          });
          echoLog({
            before: '[Web]'
          }).warning(I18n('steamFinishNotice') + this.#oldArea);
          const changeResult = await this.#changeArea(this.#oldArea);
          debug('区域重置结果', {
            success: changeResult,
            targetArea: this.#oldArea
          });
        } else {
          debug('无需重置区域', {
            currentArea: this.#area,
            oldArea: this.#oldArea
          });
        }
        debug('区域重置流程完成');
        return true;
      } catch (error) {
        debug('重置区域时发生错误', {
          error: error
        });
        throwError(error, 'SteamWeb.resetArea');
        return false;
      }
    }
    #setCache(type, name, id) {
      try {
        debug('开始设置缓存', {
          type: type,
          name: name,
          id: id
        });
        this.#cache[type][name] = id;
        GM_setValue('steamCache', this.#cache);
        debug('设置缓存成功', {
          type: type,
          name: name,
          id: id
        });
      } catch (error) {
        debug('设置缓存时发生异常', {
          error: error,
          type: type,
          name: name,
          id: id
        });
        throwError(error, 'SteamWeb.setCache');
      }
    }
  }
  class Steam extends Social {
    tasks;
    whiteList;
    #cache={
      ...{
        group: {},
        officialGroup: {},
        forum: {},
        workshop: {},
        curator: {}
      },
      ...GM_getValue('steamCache')
    };
    #TaskExecutor=[];
    constructor() {
      super();
      debug('初始化Steam实例');
      const defaultTasksTemplate = {
        groups: [],
        officialGroups: [],
        wishlists: [],
        follows: [],
        forums: [],
        workshops: [],
        workshopVotes: [],
        curators: [],
        curatorLikes: [],
        announcements: [],
        licenses: [],
        playtests: [],
        playTime: []
      };
      this.tasks = defaultTasksTemplate;
      this.whiteList = {
        ...defaultTasksTemplate,
        ...GM_getValue('whiteList')?.steam || {}
      };
      this.#TaskExecutor = this.#getTaskExecutionOrder(globalOptions.ASF.AsfEnabled, globalOptions.ASF.steamWeb, globalOptions.ASF.preferASF);
      debug('Steam实例初始化完成', {
        taskExecutorCount: this.#TaskExecutor.length
      });
    }
    async init(type = 'all') {
      try {
        debug('开始初始化Steam模块', {
          type: type
        });
        for (let i = 0; i < this.#TaskExecutor.length; i++) {
          debug(`初始化执行器 ${i + 1}/${this.#TaskExecutor.length}`);
          if (!await this.#TaskExecutor[i].init(type)) {
            debug(`执行器 ${i + 1} 初始化失败,移除该执行器`);
            this.#TaskExecutor.splice(i, 1);
          }
        }
        debug('Steam模块初始化完成', {
          remainingExecutors: this.#TaskExecutor.length
        });
        return this.#TaskExecutor.length > 0;
      } catch (error) {
        debug('Steam初始化发生错误', {
          error: error
        });
        throwError(error, 'Steam.init');
        return false;
      }
    }
    async #joinGroup(groupName) {
      try {
        debug('开始加入Steam组', {
          groupName: groupName
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.joinGroup(groupName)) {
            debug('成功加入Steam组', {
              groupName: groupName
            });
            this.tasks.groups = unique([ ...this.tasks.groups, groupName ]);
            return true;
          }
        }
        debug('加入Steam组失败', {
          groupName: groupName
        });
        return false;
      } catch (error) {
        debug('加入Steam组时发生错误', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'Steam.joinGroup');
        return false;
      }
    }
    async #leaveGroup(groupName) {
      try {
        debug('开始退出Steam组', {
          groupName: groupName
        });
        if (this.whiteList.groups.includes(groupName)) {
          debug('Steam组在白名单中,跳过退出', {
            groupName: groupName
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.leaveGroup',
            id: groupName
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.leaveGroup(groupName)) {
            debug('成功退出Steam组', {
              groupName: groupName
            });
            return true;
          }
        }
        debug('退出Steam组失败', {
          groupName: groupName
        });
        return false;
      } catch (error) {
        debug('退出Steam组时发生错误', {
          error: error,
          groupName: groupName
        });
        throwError(error, 'Steam.leaveGroup');
        return false;
      }
    }
    async #joinOfficialGroup(gameId) {
      try {
        debug('开始加入Steam官方组', {
          gameId: gameId
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.joinOfficialGroup(gameId)) {
            debug('成功加入Steam官方组', {
              gameId: gameId
            });
            return true;
          }
        }
        debug('加入Steam官方组失败', {
          gameId: gameId
        });
        return false;
      } catch (error) {
        debug('加入Steam官方组时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'Steam.joinOfficialGroup');
        return false;
      }
    }
    async #leaveOfficialGroup(gameId) {
      try {
        debug('开始退出Steam官方组', {
          gameId: gameId
        });
        if (this.whiteList.officialGroups.includes(gameId)) {
          debug('Steam官方组在白名单中,跳过退出', {
            gameId: gameId
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.leaveOfficialGroup',
            id: gameId
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.leaveOfficialGroup(gameId)) {
            debug('成功退出Steam官方组', {
              gameId: gameId
            });
            this.tasks.officialGroups = unique([ ...this.tasks.officialGroups, gameId ]);
            return true;
          }
        }
        debug('退出Steam官方组失败', {
          gameId: gameId
        });
        return false;
      } catch (error) {
        debug('退出Steam官方组时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'Steam.leaveOfficialGroup');
        return false;
      }
    }
    async #addToWishlist(gameId) {
      try {
        debug('开始添加游戏到愿望单', {
          gameId: gameId
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.addToWishlist(gameId)) {
            debug('成功添加游戏到愿望单', {
              gameId: gameId
            });
            this.tasks.wishlists = unique([ ...this.tasks.wishlists, gameId ]);
            return true;
          }
        }
        debug('添加游戏到愿望单失败', {
          gameId: gameId
        });
        return false;
      } catch (error) {
        debug('添加游戏到愿望单时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'Steam.addToWishlist');
        return false;
      }
    }
    async #removeFromWishlist(gameId) {
      try {
        debug('开始从愿望单移除游戏', {
          gameId: gameId
        });
        if (this.whiteList.wishlists.includes(gameId)) {
          debug('游戏在愿望单白名单中,跳过移除', {
            gameId: gameId
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.removeFromWishlist',
            id: gameId
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.removeFromWishlist(gameId)) {
            debug('成功从愿望单移除游戏', {
              gameId: gameId
            });
            return true;
          }
        }
        debug('从愿望单移除游戏失败', {
          gameId: gameId
        });
        return false;
      } catch (error) {
        debug('从愿望单移除游戏时发生错误', {
          error: error,
          gameId: gameId
        });
        throwError(error, 'Steam.removeFromWishlist');
        return false;
      }
    }
    async #toggleFollowGame(gameId, doTask) {
      try {
        debug('开始处理游戏关注状态', {
          gameId: gameId,
          doTask: doTask
        });
        if (!doTask && this.whiteList.follows.includes(gameId)) {
          debug('游戏在关注白名单中,跳过取关', {
            gameId: gameId
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.unfollowGame',
            id: gameId
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.toggleFollowGame(gameId, doTask)) {
            if (doTask) {
              debug('成功关注游戏', {
                gameId: gameId
              });
              this.tasks.follows = unique([ ...this.tasks.follows, gameId ]);
            } else {
              debug('成功取关游戏', {
                gameId: gameId
              });
            }
            return true;
          }
        }
        debug('处理游戏关注状态失败', {
          gameId: gameId,
          doTask: doTask
        });
        return false;
      } catch (error) {
        debug('处理游戏关注状态时发生错误', {
          error: error,
          gameId: gameId,
          doTask: doTask
        });
        throwError(error, 'Steam.toggleFollowGame');
        return false;
      }
    }
    async #toggleForum(gameId, doTask = true) {
      try {
        debug('开始处理论坛订阅状态', {
          gameId: gameId,
          doTask: doTask
        });
        if (!doTask && this.whiteList.forums.includes(gameId)) {
          debug('论坛在白名单中,跳过取消订阅', {
            gameId: gameId
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.unsubscribeForum',
            id: gameId
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.toggleForum(gameId, doTask)) {
            if (doTask) {
              debug('成功订阅论坛', {
                gameId: gameId
              });
              this.tasks.forums = unique([ ...this.tasks.forums, gameId ]);
            } else {
              debug('成功取消订阅论坛', {
                gameId: gameId
              });
            }
            return true;
          }
        }
        debug('处理论坛订阅状态失败', {
          gameId: gameId,
          doTask: doTask
        });
        return false;
      } catch (error) {
        debug('处理论坛订阅状态时发生错误', {
          error: error,
          gameId: gameId,
          doTask: doTask
        });
        throwError(error, 'Steam.toggleForum');
        return true;
      }
    }
    async #toggleFavoriteWorkshop(id, doTask = true) {
      try {
        debug('开始处理创意工坊收藏状态', {
          id: id,
          doTask: doTask
        });
        if (!doTask && this.whiteList.workshops.includes(id)) {
          debug('创意工坊物品在白名单中,跳过取消收藏', {
            id: id
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.unfavoriteWorkshop',
            id: id
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.toggleFavoriteWorkshop(id)) {
            if (doTask) {
              debug('成功收藏创意工坊物品', {
                id: id
              });
              this.tasks.workshops = unique([ ...this.tasks.workshops, id ]);
            } else {
              debug('成功取消收藏创意工坊物品', {
                id: id
              });
            }
            return true;
          }
        }
        debug('处理创意工坊收藏状态失败', {
          id: id,
          doTask: doTask
        });
        return false;
      } catch (error) {
        debug('处理创意工坊收藏状态时发生错误', {
          error: error,
          id: id,
          doTask: doTask
        });
        throwError(error, 'Steam.toggleFavoriteWorkshop');
        return false;
      }
    }
    async #voteUpWorkshop(id) {
      try {
        debug('开始点赞创意工坊物品', {
          id: id
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.voteUpWorkshop(id)) {
            debug('成功点赞创意工坊物品', {
              id: id
            });
            return true;
          }
        }
        debug('点赞创意工坊物品失败', {
          id: id
        });
        return false;
      } catch (error) {
        debug('点赞创意工坊物品时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'Steam.voteupWorkshop');
        return true;
      }
    }
    async #toggleCurator(curatorId, doTask = true) {
      try {
        debug('开始处理鉴赏家关注状态', {
          curatorId: curatorId,
          doTask: doTask
        });
        if (!doTask && this.whiteList.curators.includes(curatorId)) {
          debug('鉴赏家在白名单中,跳过取关', {
            curatorId: curatorId
          });
          echoLog({
            type: 'whiteList',
            text: 'Steam.unfollowCurator',
            id: curatorId
          });
          return true;
        }
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.toggleCurator(curatorId, doTask)) {
            if (doTask) {
              debug('成功关注鉴赏家', {
                curatorId: curatorId
              });
              this.tasks.curators = unique([ ...this.tasks.curators, curatorId ]);
            } else {
              debug('成功取关鉴赏家', {
                curatorId: curatorId
              });
            }
            return true;
          }
        }
        debug('处理鉴赏家关注状态失败', {
          curatorId: curatorId,
          doTask: doTask
        });
        return false;
      } catch (error) {
        debug('处理鉴赏家关注状态时发生错误', {
          error: error,
          curatorId: curatorId,
          doTask: doTask
        });
        throwError(error, 'Steam.toggleCurator');
        return false;
      }
    }
    async getCuratorId(path, name) {
      try {
        debug('开始获取鉴赏家ID', {
          path: path,
          name: name
        });
        const logStatus = echoLog({
          type: 'gettingCuratorId',
          text: `${path}/${name}`,
          before: '[Web]'
        });
        const curatorId = this.#cache.curator[`${path}/${name}`];
        if (curatorId) {
          debug('从缓存获取到鉴赏家ID', {
            path: path,
            name: name,
            curatorId: curatorId
          });
          logStatus.success();
          return curatorId;
        }
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/${path}/${name}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
          }
        });
        if (result === 'Success') {
          if (data?.status === 200) {
            const curatorId = data.responseText.match(/g_pagingData.*?"clanid":([\d]+)/)?.[1];
            if (curatorId) {
              debug('成功获取鉴赏家ID', {
                path: path,
                name: name,
                curatorId: curatorId
              });
              this.#setCache('curator', `${path}/${name}`, curatorId);
              logStatus.success();
              return curatorId;
            }
            debug('未找到鉴赏家ID', {
              path: path,
              name: name,
              status: data.status
            });
            logStatus.error(`Error:${data.statusText}(${data.status})`);
            return false;
          }
          debug('获取鉴赏家页面失败', {
            path: path,
            name: name,
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('请求鉴赏家页面失败', {
          path: path,
          name: name,
          result: result,
          status: status
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return false;
      } catch (error) {
        debug('获取鉴赏家ID时发生错误', {
          error: error,
          path: path,
          name: name
        });
        throwError(error, 'SteamWeb.getCuratorID');
        return false;
      }
    }
    async #toggleCuratorLike(link, doTask = true) {
      try {
        debug('开始处理鉴赏家点赞状态', {
          link: link,
          doTask: doTask
        });
        const [path, name] = link.split('/');
        if (!(path && name)) {
          debug('无效的鉴赏家链接', {
            link: link
          });
          echoLog({
            text: I18n('errorLink', link),
            before: '[Web]'
          });
          return false;
        }
        const curatorId = await this.getCuratorId(path, name);
        if (curatorId) {
          debug('获取到鉴赏家ID,开始处理点赞', {
            curatorId: curatorId,
            doTask: doTask
          });
          return await this.#toggleCurator(curatorId, doTask);
        }
        debug('未获取到鉴赏家ID', {
          link: link
        });
        return false;
      } catch (error) {
        debug('处理鉴赏家点赞状态时发生错误', {
          error: error,
          link: link,
          doTask: doTask
        });
        throwError(error, 'Steam.toggleCuratorLike');
        return false;
      }
    }
    async #likeAnnouncement(id) {
      try {
        debug('开始点赞公告', {
          id: id
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.likeAnnouncement(id)) {
            debug('成功点赞公告', {
              id: id
            });
            return true;
          }
        }
        debug('点赞公告失败', {
          id: id
        });
        return false;
      } catch (error) {
        debug('点赞公告时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'Steam.likeAnnouncement');
        return false;
      }
    }
    async #addLicense(id) {
      try {
        debug('开始添加许可证', {
          id: id
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.addLicense(id)) {
            debug('成功添加许可证', {
              id: id
            });
            return true;
          }
        }
        debug('添加许可证失败', {
          id: id
        });
        return false;
      } catch (error) {
        debug('添加许可证时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'Steam.addLicense');
        return false;
      }
    }
    async #requestPlayTestAccess(id) {
      try {
        debug('开始请求游戏试玩权限', {
          id: id
        });
        for (const taskExecutor of this.#TaskExecutor) {
          if (await taskExecutor.requestPlayTestAccess(id)) {
            debug('成功请求游戏试玩权限', {
              id: id
            });
            return true;
          }
        }
        debug('请求游戏试玩权限失败', {
          id: id
        });
        return false;
      } catch (error) {
        debug('请求游戏试玩权限时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'Steam.requestPlayTestAccess');
        return false;
      }
    }
    async #getDemoAppid(id) {
      try {
        debug('开始获取游戏试玩ID', {
          id: id
        });
        const logStatus = echoLog({
          type: 'gettingDemoAppid',
          text: id,
          before: '[Web]'
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://store.steampowered.com/app/${id}`,
          method: 'GET',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            Host: 'store.steampowered.com',
            Origin: 'https://store.steampowered.com',
            Referer: `https://store.steampowered.com/app/${id}`
          }
        });
        if (result === 'Success') {
          if (data?.status === 200) {
            const demoAppid = data.responseText.match(/steam:\/\/(install|run)\/(\d+)/)?.[2];
            debug('成功获取游戏试玩ID', {
              id: id,
              demoAppid: demoAppid
            });
            logStatus.success();
            return demoAppid || false;
          }
          debug('获取游戏页面失败', {
            id: id,
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('请求游戏页面失败', {
          id: id,
          result: result,
          status: status
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return false;
      } catch (error) {
        debug('获取游戏试玩ID时发生错误', {
          error: error,
          id: id
        });
        throwError(error, 'Steam.getDemoAppid');
        return false;
      }
    }
    async #playGames(ids, playTime, doTask = true) {
      try {
        debug('开始处理游戏挂时长', {
          ids: ids,
          playTime: playTime,
          doTask: doTask
        });
        if (playTime <= 0) {
          debug('游戏时长小于等于0,跳过挂时长');
          return true;
        }
        const asf = this.#TaskExecutor.find((e => e instanceof SteamASF));
        if (!asf) {
          debug('未找到ASF实例');
          echoLog({}).warning(I18n('noASFInstance'));
          return false;
        }
        if (!doTask) {
          debug('停止挂时长');
          return await asf.stopPlayGames();
        }
        const idsArr = await Promise.all(ids.split(',').map((async id => {
          try {
            const demoAppid = await this.#getDemoAppid(id);
            return demoAppid ? `${id},${demoAppid}` : id;
          } catch (error) {
            debug('获取游戏试玩ID失败', {
              error: error,
              id: id
            });
            return id;
          }
        })));
        const uniqueIds = unique(idsArr.join(',').split(','));
        debug('处理后的游戏ID列表', {
          uniqueIds: uniqueIds
        });
        debug('开始尝试入库游戏', {
          uniqueIds: uniqueIds
        });
        await Promise.all(uniqueIds.map((async id => {
          for (const taskExecutor of this.#TaskExecutor) {
            if (await taskExecutor.addLicense(`appid-${id}`)) {
              debug('成功入库游戏', {
                id: id
              });
              return true;
            }
          }
          return false;
        })));
        await asf.playGames(uniqueIds.join(','));
        const status = await asf.checkPlayStatus(uniqueIds.join(','));
        if (status !== true) {
          await delay(3e3);
          await asf.playGames(uniqueIds.join(','));
          const status = await asf.checkPlayStatus(uniqueIds.join(','));
          if (!status) {
            debug('启动游戏失败');
            return false;
          }
        }
        const stopPlayTime = Date.now() + (playTime + 10) * 60 * 1e3;
        const stopPlayTimeOld = GM_getValue('stopPlayTime', 0) || 0;
        GM_setValue('stopPlayTime', Math.max(stopPlayTime, stopPlayTimeOld));
        const playedGames = GM_getValue('playedGames', []) || [];
        GM_setValue('playedGames', unique([ ...playedGames, ...uniqueIds ]));
        const taskLink = GM_getValue('taskLink', []) || [];
        GM_setValue('taskLink', unique([ ...taskLink, window.location.href ]));
        debug('游戏挂时长状态更新完成');
        return true;
      } catch (error) {
        debug('处理游戏挂时长时发生错误', {
          error: error,
          ids: ids,
          playTime: playTime
        });
        throwError(error, 'Steam.playGames');
        return false;
      }
    }
    async toggle({doTask: doTask = true, groupLinks: groupLinks = [], officialGroupLinks: officialGroupLinks = [], wishlistLinks: wishlistLinks = [], followLinks: followLinks = [], forumLinks: forumLinks = [], workshopLinks: workshopLinks = [], workshopVoteLinks: workshopVoteLinks = [], curatorLinks: curatorLinks = [], curatorLikeLinks: curatorLikeLinks = [], announcementLinks: announcementLinks = [], licenseLinks: licenseLinks = [], playtestLinks: playtestLinks = [], playTimeLinks: playTimeLinks = []}) {
      try {
        debug('开始处理Steam任务', {
          doTask: doTask,
          linksCount: {
            groups: groupLinks.length,
            officialGroups: officialGroupLinks.length,
            wishlists: wishlistLinks.length,
            follows: followLinks.length,
            forums: forumLinks.length,
            workshops: workshopLinks.length,
            workshopVotes: workshopVoteLinks.length,
            curators: curatorLinks.length,
            curatorLikes: curatorLikeLinks.length,
            announcements: announcementLinks.length,
            licenses: licenseLinks.length,
            playtests: playtestLinks.length,
            playTime: playTimeLinks.length
          }
        });
        const allLinks = [ ...groupLinks, ...officialGroupLinks, ...forumLinks, ...workshopLinks, ...workshopVoteLinks, ...wishlistLinks, ...followLinks, ...curatorLinks, ...curatorLikeLinks, ...announcementLinks, ...licenseLinks, ...playtestLinks, ...playTimeLinks ];
        if (allLinks.length > 0 && this.#TaskExecutor.length === 0) {
          debug('Steam模块未初始化');
          echoLog({
            text: I18n('needInit')
          });
          return false;
        }
        const tasks = [];
        if (this.shouldProcessTask('groups', doTask)) {
          debug('开始处理群组任务');
          const realGroups = this.getRealParams('groups', groupLinks, doTask, (link => link.match(/groups\/(.+)\/?/)?.[1]?.split('/')?.[0]));
          debug('处理后的群组列表', {
            count: realGroups.length,
            groups: realGroups
          });
          for (const group of realGroups) {
            tasks.push(doTask ? this.#joinGroup(group) : this.#leaveGroup(group));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('officialGroups', doTask)) {
          const realOfficialGroups = this.getRealParams('officialGroups', officialGroupLinks, doTask, (link => link.match(/games\/(.+)\/?/)?.[1]));
          for (const officialGroup of realOfficialGroups) {
            tasks.push(doTask ? this.#joinOfficialGroup(officialGroup) : this.#leaveOfficialGroup(officialGroup));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('wishlists', doTask)) {
          const realWishlists = this.getRealParams('wishlists', wishlistLinks, doTask, (link => link.match(/app\/([\d]+)/)?.[1]));
          for (const game of realWishlists) {
            tasks.push(doTask ? this.#addToWishlist(game) : this.#removeFromWishlist(game));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('follows', doTask)) {
          const realFollows = this.getRealParams('follows', followLinks, doTask, (link => link.match(/app\/([\d]+)/)?.[1]));
          for (const game of realFollows) {
            tasks.push(this.#toggleFollowGame(game, doTask));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('playTime', doTask)) {
          const realGames = this.getRealParams('playTime', playTimeLinks, doTask, (link => `${link.split('-')[0]}-${link.match(/app\/([\d]+)/)?.[1] || ''}`));
          if (realGames.length > 0) {
            const maxTime = Math.max(...realGames.map((info => parseInt(info.split('-')[0], 10) || 0)));
            const games = realGames.filter((info => {
              const [time, game] = info.split('-');
              return (parseInt(time, 10) || 0) > 0 && game;
            })).map((info => info.split('-')[1]));
            tasks.push(this.#playGames(games.join(','), maxTime, doTask));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('forums', doTask)) {
          const realForums = this.getRealParams('forums', forumLinks, doTask, (link => link.match(/app\/([\d]+)/)?.[1]));
          for (const forum of realForums) {
            tasks.push(this.#toggleForum(forum, doTask));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('workshops', doTask)) {
          const realWorkshops = this.getRealParams('workshops', workshopLinks, doTask, (link => link.match(/\?id=([\d]+)/)?.[1]));
          for (const workshop of realWorkshops) {
            tasks.push(this.#toggleFavoriteWorkshop(workshop, doTask));
            await delay(1e3);
          }
        }
        if (doTask && globalOptions.doTask.steam.workshopVotes) {
          const realworkshopVotes = this.getRealParams('workshopVotes', workshopVoteLinks, doTask, (link => link.match(/\?id=([\d]+)/)?.[1]));
          for (const workshop of realworkshopVotes) {
            tasks.push(this.#voteUpWorkshop(workshop));
            await delay(1e3);
          }
        }
        if (this.shouldProcessTask('curators', doTask)) {
          const realCurators = this.getRealParams('curators', curatorLinks, doTask, (link => link.match(/curator\/([\d]+)/)?.[1]));
          const realCuratorLikes = this.getRealParams('curatorLikes', curatorLikeLinks, doTask, (link => link.match(/https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/)?.slice(1, 3).join('/')));
          for (const curator of realCurators) {
            tasks.push(this.#toggleCurator(curator, doTask));
            await delay(1e3);
          }
          for (const curatorLike of realCuratorLikes) {
            tasks.push(this.#toggleCuratorLike(curatorLike, doTask));
            await delay(1e3);
          }
        }
        if (doTask && globalOptions.doTask.steam.announcements) {
          const realAnnouncements = this.getRealParams('announcements', announcementLinks, doTask, (link => {
            if (link.includes('store.steampowered.com')) {
              return link.match(/store\.steampowered\.com\/news\/app\/([\d]+)\/view\/([\d]+)/)?.slice(1, 3).join('/');
            }
            return link.match(/steamcommunity\.com\/games\/([\d]+)\/announcements\/detail\/([\d]+)/)?.slice(1, 3).join('/');
          }));
          for (const id of realAnnouncements) {
            tasks.push(this.#likeAnnouncement(id));
            await delay(1e3);
          }
        }
        if (doTask && globalOptions.doTask.steam.licenses && licenseLinks.length > 0) {
          for (const ids of licenseLinks) {
            const [type, idsStr] = ids.split('-');
            const idsArr = idsStr.split(',');
            for (const id of idsArr) {
              tasks.push(this.#addLicense(`${type}-${id}`));
              await delay(1e3);
            }
          }
        }
        if (doTask && globalOptions.doTask.steam.playtests) {
          const realPlaytests = this.getRealParams('playtests', playtestLinks, doTask, (link => link.match(/app\/([\d]+)/)?.[1]));
          for (const id of realPlaytests) {
            tasks.push(this.#requestPlayTestAccess(id));
            await delay(1e3);
          }
        }
        debug('开始执行所有任务');
        const results = await Promise.all(tasks);
        this.#TaskExecutor.find((e => e instanceof SteamWeb))?.resetArea();
        debug('所有任务执行完成', {
          success: results.every((result => result))
        });
        return results.every((result => result));
      } catch (error) {
        debug('处理Steam任务时发生错误', {
          error: error
        });
        throwError(error, 'Steam.toggle');
        return false;
      }
    }
    shouldProcessTask(taskType, doTask) {
      debug('检查是否处理任务', {
        taskType: taskType,
        doTask: doTask
      });
      if (doTask) {
        const result = globalOptions.doTask.steam[taskType];
        debug('检查doTask配置', {
          taskType: taskType,
          result: result
        });
        return globalOptions.doTask.steam[taskType];
      }
      const undoTaskType = taskType;
      return undoTaskType in globalOptions.undoTask.steam && globalOptions.undoTask.steam[undoTaskType];
    }
    #setCache(type, name, id) {
      try {
        this.#cache[type][name] = id;
        GM_setValue('steamCache', this.#cache);
      } catch (error) {
        throwError(error, 'SteamWeb.setCache');
      }
    }
    #getTaskExecutionOrder(asfEnabled, steamWebEnabled, preferASF) {
      if (!asfEnabled) {
        return [ new SteamWeb ];
      }
      if (!steamWebEnabled) {
        return [ new SteamASF(globalOptions.ASF) ];
      }
      return preferASF ? [ new SteamASF(globalOptions.ASF), new SteamWeb ] : [ new SteamWeb, new SteamASF(globalOptions.ASF) ];
    }
  }
  class Website {
    undoneTasks;
    socialTasks;
    giveawayId;
    socialInitialized={
      discord: false,
      instagram: false,
      reddit: false,
      twitch: false,
      twitter: false,
      vk: false,
      youtube: false,
      steamStore: false,
      steamCommunity: false
    };
    initialized=false;
    steamTaskType={
      steamStore: false,
      steamCommunity: false
    };
    social={};
    async #bind(name, init) {
      try {
        debug('开始绑定社交媒体', {
          name: name
        });
        const result = await init;
        debug('绑定结果', {
          name: name,
          result: result
        });
        return {
          name: name,
          result: result
        };
      } catch (error) {
        debug('绑定失败', {
          name: name,
          error: error
        });
        throwError(error, 'Website.bind');
        return {
          name: name,
          result: false
        };
      }
    }
    async initSocial(action) {
      try {
        debug('开始初始化社交媒体', {
          action: action
        });
        const pro = [];
        const tasks = action === 'do' ? this.undoneTasks : this.socialTasks;
        if (tasks.discord) {
          const hasDiscord = Object.values(tasks.discord).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          debug('检查 Discord 任务', {
            hasDiscord: hasDiscord
          });
          if (hasDiscord && (!this.socialInitialized.discord || !this.social.discord)) {
            debug('初始化 Discord');
            this.social.discord = new Discord;
            pro.push(this.#bind('discord', this.social.discord.init(action)));
          }
        }
        if (tasks.reddit) {
          const hasReddit = Object.values(tasks.reddit).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          debug('检查 Reddit 任务', {
            hasReddit: hasReddit
          });
          if (hasReddit && (!this.socialInitialized.reddit || !this.social.reddit)) {
            debug('初始化 Reddit');
            this.social.reddit = new Reddit;
            pro.push(this.#bind('reddit', this.social.reddit.init()));
          }
        }
        if (tasks.twitch) {
          const hasTwitch = Object.values(tasks.twitch).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          debug('检查 Twitch 任务', {
            hasTwitch: hasTwitch
          });
          if (hasTwitch && (!this.socialInitialized.twitch || !this.social.twitch)) {
            debug('初始化 Twitch');
            this.social.twitch = new Twitch;
            pro.push(this.#bind('twitch', this.social.twitch.init()));
          }
        }
        if (tasks.twitter) {
          const hasTwitter = Object.values(tasks.twitter).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          debug('检查 Twitter 任务', {
            hasTwitter: hasTwitter
          });
          if (hasTwitter && (!this.socialInitialized.twitter || !this.social.twitter)) {
            debug('初始化 Twitter');
            this.social.twitter = new Twitter;
            pro.push(this.#bind('twitter', this.social.twitter.init()));
          }
        }
        if (tasks.vk) {
          const hasVk = Object.values(tasks.vk).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          debug('检查 VK 任务', {
            hasVk: hasVk
          });
          if (hasVk && (!this.socialInitialized.vk || !this.social.vk)) {
            debug('初始化 VK');
            this.social.vk = new Vk;
            pro.push(this.#bind('vk', this.social.vk.init()));
          }
        }
        if (tasks.youtube) {
          const hasYoutube = Object.values(tasks.youtube).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          debug('检查 YouTube 任务', {
            hasYoutube: hasYoutube
          });
          if (hasYoutube && (!this.socialInitialized.youtube || !this.social.youtube)) {
            debug('初始化 YouTube');
            this.social.youtube = new Youtube;
            pro.push(this.#bind('youtube', this.social.youtube.init()));
          }
        }
        if (tasks.steam) {
          const steamLength = Object.values(tasks.steam).reduce(((total, arr) => [ ...total, ...arr ])).length;
          debug('检查 Steam 任务', {
            steamLength: steamLength
          });
          if (steamLength > 0) {
            if (!this.social.steam) {
              debug('创建 Steam 实例');
              this.social.steam = new Steam;
            }
            const steamCommunityLength = Object.keys(tasks.steam).map((type => [ 'groupLinks', 'officialGroupLinks', 'forumLinks', 'workshopLinks', 'workshopVoteLinks' ].includes(type) ? tasks.steam?.[type]?.length || 0 : 0)).reduce(((total, number) => total + number), 0);
            debug('Steam 社区任务数量', {
              steamCommunityLength: steamCommunityLength
            });
            if (steamLength - steamCommunityLength > 0) {
              this.steamTaskType.steamStore = true;
              if (!this.socialInitialized.steamStore) {
                debug('初始化 Steam 商店');
                pro.push(this.#bind('steamStore', this.social.steam.init('store')));
              }
            }
            if (steamCommunityLength > 0) {
              if (!this.socialInitialized.steamCommunity) {
                this.steamTaskType.steamCommunity = true;
                debug('初始化 Steam 社区');
                pro.push(this.#bind('steamCommunity', this.social.steam.init('community')));
              }
            }
          }
        }
        if (tasks.links && tasks.links.length > 0) {
          debug('初始化链接访问', {
            linksCount: tasks.links.length
          });
          this.social.visitLink = visitLink;
        }
        debug('等待所有社交媒体初始化完成');
        return await Promise.all(pro).then((result => {
          let checked = true;
          for (const data of result) {
            if (data.result) {
              debug('社交媒体初始化成功', {
                name: data.name
              });
              this.socialInitialized[data.name] = data.result;
            } else {
              debug('社交媒体初始化失败', {
                name: data.name
              });
              checked = false;
            }
          }
          debug('社交媒体初始化完成', {
            allSuccess: checked
          });
          return checked;
        }));
      } catch (error) {
        debug('初始化社交媒体失败', {
          error: error
        });
        throwError(error, 'Website.initSocial');
        return false;
      }
    }
    uniqueTasks(allTasks) {
      try {
        debug('开始去重任务');
        const result = {};
        for (const [social, types] of Object.entries(allTasks)) {
          debug('处理社交媒体任务', {
            social: social
          });
          result[social] = {};
          for (const [type, tasks] of Object.entries(types)) {
            debug('处理任务类型', {
              social: social,
              type: type
            });
            result[social][type] = unique(tasks);
          }
        }
        debug('任务去重完成');
        return result;
      } catch (error) {
        debug('任务去重失败', {
          error: error
        });
        throwError(error, 'Website.uniqueTasks');
        return allTasks;
      }
    }
    async toggleTask(action) {
      try {
        debug('开始切换任务状态', {
          action: action
        });
        if (!this.initialized && !this.init()) {
          debug('初始化失败');
          return false;
        }
        if (!await this.classifyTask(action)) {
          debug('任务分类失败');
          return false;
        }
        debug('初始化社交媒体');
        await this.initSocial(action);
        const pro = [];
        const doTask = action === 'do';
        const tasks = doTask ? this.undoneTasks : this.socialTasks;
        if (this.socialInitialized.discord === true && this.social.discord) {
          debug('处理 Discord 任务');
          pro.push(this.social.discord.toggle({
            doTask: doTask,
            ...tasks.discord
          }));
        }
        if (this.socialInitialized.reddit === true && this.social.reddit) {
          debug('处理 Reddit 任务');
          pro.push(this.social.reddit.toggle({
            doTask: doTask,
            ...tasks.reddit
          }));
        }
        if (this.socialInitialized.twitch === true && this.social.twitch) {
          debug('处理 Twitch 任务');
          pro.push(this.social.twitch.toggle({
            doTask: doTask,
            ...tasks.twitch
          }));
        }
        if (this.socialInitialized.twitter === true && this.social.twitter) {
          debug('处理 Twitter 任务');
          pro.push(this.social.twitter.toggle({
            doTask: doTask,
            ...tasks.twitter
          }));
        }
        if (this.socialInitialized.vk === true && this.social.vk) {
          debug('处理 VK 任务');
          pro.push(this.social.vk.toggle({
            doTask: doTask,
            ...tasks.vk
          }));
        }
        if (this.socialInitialized.youtube === true && this.social.youtube) {
          debug('处理 YouTube 任务');
          pro.push(this.social.youtube.toggle({
            doTask: doTask,
            ...tasks.youtube
          }));
        }
        if ((this.steamTaskType.steamCommunity ? this.socialInitialized.steamCommunity === true : true) && (this.steamTaskType.steamStore ? this.socialInitialized.steamStore === true : true) && this.social.steam) {
          debug('处理 Steam 任务');
          pro.push(this.social.steam.toggle({
            doTask: doTask,
            ...tasks.steam
          }));
        }
        if (this.social.visitLink && tasks.links && doTask) {
          debug('处理链接任务', {
            linksCount: tasks.links.length
          });
          for (const link of tasks.links) {
            pro.push(this.social.visitLink(link));
          }
        }
        if (doTask && tasks.extra && this.extraDoTask) {
          const hasExtra = Object.values(tasks.extra).reduce(((total, arr) => [ ...total, ...arr ])).length > 0;
          if (hasExtra) {
            debug('处理额外任务');
            pro.push(this.extraDoTask(tasks.extra));
          }
        }
        debug('等待所有任务完成');
        await Promise.all(pro);
        debug('所有任务完成');
        echoLog({}).success(I18n('allTasksComplete'));
        return true;
      } catch (error) {
        debug('切换任务失败', {
          error: error
        });
        throwError(error, 'Website.toggleTask');
        return false;
      }
    }
    async doTask() {
      try {
        debug('开始执行任务');
        const result = await this.toggleTask('do');
        debug('任务执行完成', {
          success: result
        });
        return result;
      } catch (error) {
        debug('执行任务失败', {
          error: error
        });
        throwError(error, 'Website.doTask');
        return false;
      }
    }
    async undoTask() {
      try {
        debug('开始撤销任务');
        const result = await this.toggleTask('undo');
        debug('任务撤销完成', {
          success: result
        });
        return result;
      } catch (error) {
        debug('撤销任务失败', {
          error: error
        });
        throwError(error, 'Website.undoTask');
        return false;
      }
    }
  }
  const defaultTasksTemplate$6 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      curatorLinks: [],
      followLinks: [],
      playTimeLinks: []
    },
    discord: {
      serverLinks: []
    },
    vk: {
      nameLinks: []
    },
    youtube: {
      channelLinks: []
    },
    extra: {
      website: []
    }
  };
  const defaultTasks$8 = JSON.stringify(defaultTasksTemplate$6);
  class FreeAnyWhere extends Website {
    name='FreeAnyWhere';
    tasks=[];
    socialTasks=JSON.parse(defaultTasks$8);
    undoneTasks=JSON.parse(defaultTasks$8);
    games;
    buttons=[ 'doTask', 'undoTask', 'verifyTask', 'getKey' ];
    static test() {
      const isMatch = window.location.host === 'freeanywhere.net';
      debug('检查网站匹配', {
        host: window.location.host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async init() {
      try {
        debug('初始化 FreeAnyWhere', {
          url: window.location.href
        });
        const logStatus = echoLog({
          text: I18n('initing')
        });
        debug('检测登录状态');
        if ($('div.header__login a[href*=logout]').length === 0) {
          debug('未登录,准备跳转到登录页面');
          window.open('https://freeanywhere.net/game.php?steam_login', '_self');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        debug('检测是否为登录页面');
        if (window.location.href.includes('/login')) {
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
        const giveawayIdSuccess = this.#getGiveawayId();
        debug('获取抽奖ID结果', {
          success: giveawayIdSuccess,
          id: this.giveawayId
        });
        this.initialized = true;
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('获取已保存的任务信息');
          this.socialTasks = GM_getValue(`fawTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks$8);
        }
        const tasks = $('div.game__content-tasks__task').map(((index, element) => ({
          id: $(element).attr('data-id'),
          social: $(element).find('div.task-img img').attr('alt'),
          link: $(element).find('div.task-link a').attr('href'),
          title: $(element).find('div.task-link').text().trim(),
          type: $(element).attr('data-type'),
          data: $(element).attr('data-data'),
          isSuccess: $(element).hasClass('done')
        }))).toArray();
        debug('获取到的任务列表', {
          tasksCount: tasks.length,
          tasks: tasks
        });
        if (tasks.length === 0) {
          logStatus.success();
          return false;
        }
        if (action === 'verify') {
          this.tasks = [];
        }
        for (const task of tasks) {
          await this.#processTask(task, action);
        }
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        debug('任务分类结果', {
          undoneTasks: this.undoneTasks,
          socialTasks: this.socialTasks
        });
        GM_setValue(`fawTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.classifyTask');
        return false;
      }
    }
    async #processTask(task, action) {
      try {
        debug('处理任务', {
          task: task,
          action: action
        });
        const {id: id, social: social, title: title, type: type, link: link, data: data, isSuccess: isSuccess} = task;
        const taskInfo = {
          id: id,
          title: title,
          social: social,
          type: type,
          data: data
        };
        if (action === 'verify' && !isSuccess) {
          debug('添加到验证任务列表', taskInfo);
          this.tasks.push(taskInfo);
          return;
        }
        debug('处理特定类型任务', {
          type: type,
          action: action,
          isSuccess: isSuccess
        });
        switch (type) {
         case 'steam_account_verify':
         case 'site_email_verify':
          debug('跳过任务', {
            type: type
          });
          break;

         case 'steam_game_sub':
          if (action === 'undo' && link) {
            this.socialTasks.steam.followLinks.push(link);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.steam.followLinks.push(link);
          }
          break;

         case 'steam_game_wishlist':
          if (action === 'undo' && link) {
            this.socialTasks.steam.wishlistLinks.push(link);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.steam.wishlistLinks.push(link);
          }
          break;

         case 'steam_group_sub':
          if (action === 'undo' && link) {
            this.socialTasks.steam.groupLinks.push(link);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.steam.groupLinks.push(link);
          }
          break;

         case 'site_visit':
          if (action === 'do' && !isSuccess) {
            this.undoneTasks.extra.website.push(`id=${id}&type=${type}&task=true`);
          }
          break;

         case 'vk_community_sub':
          if (action === 'undo' && link) {
            this.socialTasks.vk.nameLinks.push(link);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.vk.nameLinks.push(link);
          }
          break;

         case 'vk_post_like':
          if (action === 'undo' && link) {
            this.socialTasks.vk.nameLinks.push(`${link}&action=like`);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.vk.nameLinks.push(`${link}&action=like`);
          }
          break;

         case 'discord_server_sub':
          if (action === 'undo' && link) {
            this.socialTasks.discord.serverLinks.push(link);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.discord.serverLinks.push(link);
          }
          break;

         case 'youtube_channel_sub':
          if (action === 'undo' && link) {
            this.socialTasks.youtube.channelLinks.push(link);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.youtube.channelLinks.push(link);
          }
          break;

         case 'steam_game_playtime':
          if (action === 'undo' && link) {
            this.socialTasks.steam.playTimeLinks.push(`${title.match(/(\d+)\s*min/)?.[1] || '0'}-${link}`);
          }
          if (action === 'do' && !isSuccess && link) {
            this.undoneTasks.steam.playTimeLinks.push(`${title.match(/(\d+)\s*min/)?.[1] || '0'}-${link}`);
          }
          break;

         case 'telegram_channel_sub':
          debug('跳过 Telegram 任务');
          echoLog({}).warning(`${I18n('tgTaskNotice')}`);
          break;

         case 'none':
          debug('跳过未连接的任务', {
            type: type
          });
          echoLog({}).warning(`${I18n('notConnect', type)}`);
          break;

         default:
          debug('未知任务类型', {
            type: type
          });
          echoLog({}).warning(`${I18n('unKnownTaskType', type)}`);
          break;
        }
      } catch (error) {
        debug('处理任务失败', {
          error: error
        });
        throwError(error, 'FreeAnyWhere.processTask');
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        if (!this.initialized && !await this.init()) {
          debug('未初始化');
          return false;
        }
        if (this.tasks.length === 0 && !await this.classifyTask('verify')) {
          debug('任务列表为空', this.tasks);
          return false;
        }
        debug('开始验证任务列表', {
          tasks: this.tasks
        });
        const pro = [];
        for (const task of this.tasks) {
          pro.push(this.#verify(task));
          await delay(1e3);
        }
        const result = await Promise.allSettled(pro);
        debug('任务验证结果', {
          result: result
        });
        echoLog({}).success(I18n('allTasksComplete'));
        if (result.every((item => item.status === 'fulfilled' && item.value === true))) {
          return !!await this.getKey(true);
        }
        return false;
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.verifyTask');
        return false;
      }
    }
    async extraDoTask({website: website}) {
      try {
        debug('执行额外任务', {
          website: website
        });
        const promises = website.map((link => this.#doVisitWebsite(link)));
        const results = await Promise.allSettled(promises);
        debug('额外任务执行结果', {
          results: results
        });
        return true;
      } catch (error) {
        debug('执行额外任务失败', {
          error: error
        });
        throwError(error, 'FreeAnyWhere.extraDoTask');
        return false;
      }
    }
    async #doVisitWebsite(link) {
      try {
        debug('访问网站', {
          link: link
        });
        const logStatus = echoLog({
          text: I18n('visitingLink')
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://freeanywhere.net/php/task_site_visit_done.php',
          method: 'POST',
          headers: {
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: link
        });
        if (result !== 'Success') {
          debug('访问失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.responseText.indexOf('bad') !== -1 || data?.responseText.length > 50) {
          debug('访问响应异常', {
            responseText: data?.responseText
          });
          logStatus.error(data?.responseText);
          return false;
        }
        debug('访问成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('访问网站失败', {
          error: error
        });
        throwError(error, 'FreeAnyWhere.doVisitWebsite');
        return false;
      }
    }
    async getKey(initialized) {
      try {
        debug('开始获取密钥', {
          initialized: initialized
        });
        if (!initialized && !this.initialized && !await this.init()) {
          debug('未初始化');
          return false;
        }
        const logStatus = echoLog({
          text: I18n('gettingKey')
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://freeanywhere.net/php/user_get_key.php',
          method: 'POST'
        });
        if (result !== 'Success') {
          debug('获取密钥失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.responseText.indexOf('bad') !== -1 || data?.responseText.length > 50) {
          debug('密钥响应异常', {
            responseText: data?.responseText
          });
          logStatus.error(data?.responseText);
          return false;
        }
        debug('获取密钥成功', {
          key: data.responseText
        });
        logStatus.success();
        echoLog({}).success(data.responseText);
        return data.responseText;
      } catch (error) {
        debug('获取密钥失败', {
          error: error
        });
        throwError(error, 'FreeAnyWhere.getKey');
        return false;
      }
    }
    async #verify(task) {
      try {
        if ($('.task-check-extension').length > 0) {
          return this.#verifyWithExtension(task);
        }
        return this.#verifyWithoutExtension(task);
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.verify');
        return false;
      }
    }
    async #verifyWithExtension(task) {
      try {
        await this.#updateUserData();
        debug('验证任务', {
          task: task
        });
        const logStatus = echoLog({
          text: `${I18n('verifyingTask')}${task.title.trim()}...`
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://freeanywhere.net/php/extension/user_task_update.php',
          method: 'POST',
          headers: {
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: `id=${task.id}&type=${task.type}${task.data && task.data !== 'none' ? `&data=${task.data}` : ''}`
        });
        if (result !== 'Success' || !data?.responseText) {
          debug('验证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        const response = data.responseText.trim();
        if (response !== 'good') {
          debug('验证响应异常', {
            response: response,
            statusText: data?.statusText,
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('验证成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.verifyWithExtension');
        return false;
      }
    }
    async #verifyWithoutExtension(task) {
      try {
        debug('验证任务', {
          task: task
        });
        const logStatus = echoLog({
          text: `${I18n('verifyingTask')}${task.title.trim()}...`
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://freeanywhere.net/php/user_task_update.php',
          method: 'POST',
          headers: {
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: `id=${task.id}&type=${task.type}${task.data && task.data !== 'none' ? `&data=${task.data}` : ''}`
        });
        if (result !== 'Success' || !data?.responseText) {
          debug('验证请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        const response = data.responseText.trim();
        if (response !== 'good') {
          debug('验证响应异常', {
            response: response,
            statusText: data?.statusText,
            status: data?.status
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('验证成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.verifyWithoutExtension');
        return false;
      }
    }
    async #updateUserData() {
      try {
        let postData = '';
        const userData = GM_getValue('FAW_STORAGE') || {};
        if (Object.keys(userData).length === 0 || !userData.tasks || !userData.user || !userData.games || !userData.settings) {
          if (!this.games) {
            await this.#userGamesGet();
          }
          if (!this.games) {
            debug('获取用户游戏失败');
            return false;
          }
          postData = `extension=${encodeURIComponent(JSON.stringify({
            games: this.games,
            settings: {
              game_update: Math.floor(Date.now() / 1e3)
            },
            tasks: {},
            user: {
              avatar: $('header.games_for_farm_site').attr('data-avatar'),
              lang: $('header.games_for_farm_site').attr('data-lang'),
              name: $('header.games_for_farm_site').attr('data-name'),
              steam: $('header.games_for_farm_site').attr('data-steam')
            }
          }))}`;
        } else {
          postData = `extension=${encodeURIComponent(JSON.stringify(userData))}`;
        }
        debug('更新用户数据');
        const logStatus = echoLog({
          text: `${I18n('updatingUserData')}`
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://freeanywhere.net/php/extension/user_data_update.php',
          method: 'POST',
          headers: {
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: postData
        });
        if (data?.status !== 200) {
          debug('验证请求失败', {
            result: result,
            statusText: statusText,
            status: status,
            data: data
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        debug('验证成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.updateUserData');
        return false;
      }
    }
    async #userGamesGet() {
      try {
        debug('获取用户游戏');
        const logStatus = echoLog({
          text: `${I18n('gettingUserGames')}`
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://freeanywhere.net/php/extension/user_games_get.php',
          method: 'POST',
          headers: {
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
          },
          data: `steam=${$('header.games_for_farm_site').attr('data-steam')}`,
          dataType: 'json'
        });
        if (result !== 'Success' || data?.status !== 200 || !data?.responseText) {
          debug('验证请求失败', {
            result: result,
            statusText: statusText,
            status: status,
            data: data
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        debug('验证成功');
        this.games = data.response;
        logStatus.success();
        return true;
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Freeanywhere.userGamesGet');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const giveawayStatus = $('div.card-info__lable-info').text()?.includes('Giveaway ended');
        debug('Giveaway状态', {
          giveawayStatus: giveawayStatus
        });
        if (!giveawayStatus) {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('giveawayEnded'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'FreeAnyWhere.checkLeftKey');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('开始获取抽奖ID');
        const giveawayId = $('link[rel="canonical"]').attr('href')?.match(/n=([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({}).error(I18n('getFailed', 'GiveawayId'));
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'FreeAnyWhere.getGiveawayId');
        return false;
      }
    }
  }
  const defaultTasks$7 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      curatorLinks: [],
      curatorLikeLinks: [],
      followLinks: [],
      forumLinks: [],
      announcementLinks: [],
      workshopVoteLinks: [],
      playtestLinks: [],
      playTimeLinks: []
    },
    discord: {
      serverLinks: []
    },
    vk: {
      nameLinks: []
    },
    twitch: {
      channelLinks: []
    },
    reddit: {
      redditLinks: []
    },
    youtube: {
      channelLinks: [],
      likeLinks: []
    },
    twitter: {
      userLinks: [],
      retweetLinks: []
    }
  };
  class GiveawaySu extends Website {
    name='GiveawaySu';
    socialTasks=defaultTasks$7;
    undoneTasks=defaultTasks$7;
    buttons=[ 'doTask', 'undoTask' ];
    static test() {
      const url = window.location.href;
      const isMatch = /^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(url);
      debug('检查网站匹配', {
        url: url,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('登录检查失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
        debug('显示网站通知');
        echoLog({}).warning(I18n('gsNotice'));
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Giveawaysu.after');
      }
    }
    init() {
      try {
        debug('初始化 GiveawaySu');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if ($('a.steam-login').length > 0) {
          debug('发现未登录状态,重定向到 Steam 登录');
          window.open('/steam/redirect', '_self');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        const giveawayIdResult = this.#getGiveawayId();
        if (!giveawayIdResult) {
          debug('获取抽奖ID失败');
          return false;
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Giveawaysu.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`gasTasks-${this.giveawayId}`)?.tasks || defaultTasks$7;
          return true;
        }
        const tasks = $('#actions tr');
        if (!tasks.length) {
          debug('未找到任务');
          logStatus.warning(I18n('noTasks'));
          return true;
        }
        debug('检查并处理 Discord 和 Twitch 绑定');
        if ($('div.bind-discord').is(':visible')) {
          debug('点击 Discord 绑定按钮');
          $('div.bind-discord a')[0]?.click();
        }
        if ($('div.bind-twitch').is(':visible')) {
          debug('点击 Twitch 绑定按钮');
          $('div.bind-twitch a')[0]?.click();
        }
        const processTask = async task => {
          const td = $(task).find('td:not(".hidden")');
          const colorfulTask = td.eq(1).find('a:not([data-trigger="link"])');
          const colorlessTask = td.eq(2).find('a:not([data-trigger="link"])');
          const taskDes = colorfulTask.length > 0 ? colorfulTask : colorlessTask;
          if (!taskDes.length) {
            debug('跳过无效任务');
            return true;
          }
          const taskIcon = td.eq(0).find('i').attr('class') || '';
          const taskName = taskDes.text().trim();
          const taskHref = taskDes.attr('href');
          debug('处理任务', {
            taskIcon: taskIcon,
            taskName: taskName,
            taskHref: taskHref
          });
          if (taskIcon.includes('ban') || /disable adblock/gi.test(taskName)) {
            debug('跳过禁用任务');
            return true;
          }
          if (!taskHref) {
            debug('任务链接为空');
            return false;
          }
          try {
            debug('获取重定向链接');
            const taskLink = await getRedirectLink(taskHref);
            if (!taskLink) {
              debug('获取重定向链接失败');
              return false;
            }
            debug('分类任务', {
              taskLink: taskLink,
              taskIcon: taskIcon,
              taskName: taskName
            });
            this.#classifyTaskByType(taskLink, taskIcon, taskName);
            return true;
          } catch (error) {
            debug('获取重定向链接失败', {
              error: error
            });
            throwError(error, 'Giveawaysu.classifyTask->getRedirectLink');
            return false;
          }
        };
        debug('开始处理所有任务');
        const results = await Promise.all(Array.from(tasks).map(processTask));
        const success = results.some((result => result));
        if (!success) {
          debug('所有任务处理失败');
          logStatus.error(I18n('allTasksFailed'));
          return false;
        }
        debug('任务处理完成');
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.undoneTasks;
        debug('保存任务信息');
        GM_setValue(`gasTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Giveawaysu.classifyTask');
        return false;
      }
    }
    static TASK_PATTERNS={
      wishlist: /wishlist.*game|add.*wishlist/gim,
      follow: /follow.*button/gim,
      twitter: /(on twitter)|(Follow.*on.*Facebook)/gim,
      vkGroup: /join.*vk.*group/gim,
      youtubeVideo: /(watch|like).*video/gim,
      youtubeChannel: /subscribe.*youtube.*channel/gim,
      watchArt: /watch.*art/gim,
      reddit: /subscribe.*subreddit|follow.*reddit/gim,
      twitchChannel: /follow.*twitch.*channel/gim,
      instagram: /follow.*instagram/gim,
      discord: /join.*discord/gim,
      playtest: /request.*playtest/gim,
      steamForum: /subscribe.*steam.*forum/gim,
      curator: /(follow|subscribe).*curator/gim,
      curatorLink: /^https?:\/\/store\.steampowered\.com\/curator\//,
      announcement: /like.*announcement/gim,
      steamGroup: /join/gi
    };
    #classifyTaskByType(taskLink, taskIcon, taskName) {
      try {
        debug('开始分类任务', {
          taskLink: taskLink,
          taskIcon: taskIcon,
          taskName: taskName
        });
        const {TASK_PATTERNS: TASK_PATTERNS} = GiveawaySu;
        if (taskIcon.includes('steam') && TASK_PATTERNS.steamGroup.test(taskName)) {
          debug('添加 Steam 组任务');
          this.undoneTasks.steam.groupLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.announcement.test(taskName)) {
          debug('添加 Steam 公告任务');
          this.undoneTasks.steam.announcementLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.curator.test(taskName) && TASK_PATTERNS.curatorLink.test(taskLink)) {
          debug('添加 Steam 鉴赏家关注任务');
          this.undoneTasks.steam.curatorLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) {
          debug('添加 Steam 鉴赏家点赞任务');
          this.undoneTasks.steam.curatorLikeLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.steamForum.test(taskName)) {
          debug('添加 Steam 论坛任务');
          this.undoneTasks.steam.forumLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('thumbs-up') && /^https?:\/\/steamcommunity\.com\/sharedfiles\/filedetails\/\?id=[\d]+/.test(taskLink)) {
          debug('添加 Steam 创意工坊投票任务');
          this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('plus') && TASK_PATTERNS.playtest.test(taskName)) {
          debug('添加 Steam 游戏测试任务');
          this.undoneTasks.steam.playtestLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('discord') || TASK_PATTERNS.discord.test(taskName)) {
          debug('添加 Discord 服务器任务');
          this.undoneTasks.discord.serverLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('instagram') || TASK_PATTERNS.instagram.test(taskName)) {
          debug('跳过 Instagram 任务');
          return;
        }
        if (taskIcon.includes('twitch') || TASK_PATTERNS.twitchChannel.test(taskName)) {
          debug('添加 Twitch 频道任务');
          this.undoneTasks.twitch.channelLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('reddit') || TASK_PATTERNS.reddit.test(taskName)) {
          debug('添加 Reddit 任务');
          this.undoneTasks.reddit.redditLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.watchArt.test(taskName)) {
          debug('添加创意工坊物品任务');
          this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.youtubeChannel.test(taskName)) {
          debug('添加 YouTube 频道任务');
          this.undoneTasks.youtube.channelLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.youtubeVideo.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && TASK_PATTERNS.youtubeVideo.test(taskName)) {
          debug('添加 YouTube 视频任务');
          this.undoneTasks.youtube.likeLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('vk') || TASK_PATTERNS.vkGroup.test(taskName)) {
          debug('添加 VK 任务');
          this.undoneTasks.vk.nameLinks.push(taskLink);
          return;
        }
        if (TASK_PATTERNS.twitter.test(taskName)) {
          debug('跳过 Twitter 任务');
          return;
        }
        if (TASK_PATTERNS.wishlist.test(taskName)) {
          debug('添加 Steam 愿望单任务');
          this.undoneTasks.steam.wishlistLinks.push(taskLink);
        }
        if (TASK_PATTERNS.follow.test(taskName)) {
          debug('添加 Steam 关注任务');
          this.undoneTasks.steam.followLinks.push(taskLink);
          return;
        }
        debug('未识别的任务类型', {
          taskLink: taskLink,
          taskIcon: taskIcon,
          taskName: taskName
        });
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Giveawaysu.classifyTaskByType');
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        const needLogin = $('a.steam-login').length > 0;
        if (needLogin) {
          debug('未登录,重定向到 Steam 登录');
          window.open('/steam/redirect', '_self');
        }
        debug('登录检查完成', {
          needLogin: needLogin
        });
        return true;
      } catch (error) {
        debug('登录检查失败', {
          error: error
        });
        throwError(error, 'Giveawaysu.checkLogin');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const isEnded = $('.giveaway-ended').length > 0;
        const hasNoKeys = $('.giveaway-key').length === 0;
        debug('检查抽奖状态', {
          isEnded: isEnded,
          hasNoKeys: hasNoKeys
        });
        if (!(isEnded && hasNoKeys)) {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('noKeysLeft'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'Giveawaysu.checkLeftKey');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('从URL获取抽奖ID');
        const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({
          text: I18n('getFailed', 'GiveawayId')
        });
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'Giveawaysu.getGiveawayId');
        return false;
      }
    }
  }
  class Indiedb {
    name='Indiedb';
    buttons=[ 'doTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'www.indiedb.com';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('检查登录失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Indiedb.after');
      }
    }
    async doTask() {
      try {
        debug('开始执行任务');
        if (!await this.#join()) {
          debug('加入抽奖失败');
          return false;
        }
        return await this.#do();
      } catch (error) {
        debug('执行任务失败', {
          error: error
        });
        throwError(error, 'Indiedb.doTask');
        return false;
      }
    }
    async #join() {
      try {
        debug('开始加入抽奖');
        if ($('a.buttonenter:contains(Register to join)').length > 0) {
          debug('需要登录');
          echoLog({}).error(I18n('needLogin'));
          return false;
        }
        const currentoption = $('a.buttonenter.buttongiveaway');
        const buttonText = currentoption.text();
        debug('检查按钮状态', {
          buttonText: buttonText
        });
        if (/success/gim.test($('a.buttonenter.buttongiveaway').text())) {
          debug('已成功加入抽奖');
          return true;
        }
        if (!/join giveaway/gim.test(buttonText)) {
          debug('需要加入抽奖');
          echoLog({}).warning(I18n('needJoinGiveaway'));
          return false;
        }
        const logStatus = echoLog({
          text: `${I18n('joiningGiveaway')}...`
        });
        debug('发送加入请求');
        const {result: result, statusText: statusText, status: status, data: data} = await 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',
            Origin: window.location.origin,
            referer: window.location.href
          }
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('尝试备用加入方法');
          if (await this.#join2()) {
            debug('备用加入方法成功');
            logStatus.success('Success');
            return true;
          }
          debug('加入失败', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        if (!data.response?.success) {
          debug('响应失败', {
            text: data.response?.text
          });
          logStatus.error(`Error${data.response?.text ? `:${data.response?.text}` : ''}`);
          return false;
        }
        debug('加入成功');
        currentoption.addClass('buttonentered').text('Success - Giveaway joined');
        $('#giveawaysjoined').slideDown();
        $('#giveawaysrecommend').slideDown();
        logStatus.success(`Success${data.response?.text ? `:${data.response?.text}` : ''}`);
        return true;
      } catch (error) {
        debug('加入抽奖失败', {
          error: error
        });
        throwError(error, 'Indiedb.join');
        return false;
      }
    }
    async #join2() {
      try {
        debug('开始备用加入方法');
        return await new Promise((resolve => {
          const targetNode = document.getElementById('giveawaysjoined');
          const config = {
            attributes: true
          };
          const observer = new MutationObserver((() => {
            if ($('#giveawaysjoined').is(':visible')) {
              debug('检测到加入成功');
              resolve(true);
              observer.disconnect();
            }
          }));
          observer.observe(targetNode, config);
          debug('点击加入按钮');
          $('a.buttonenter.buttongiveaway')[0]?.click();
          setTimeout((() => {
            debug('加入超时');
            resolve(false);
            observer.disconnect();
          }), 3e4);
        }));
      } catch (error) {
        debug('备用加入方法失败', {
          error: error
        });
        throwError(error, 'Indiedb.join2');
        return false;
      }
    }
    async #do() {
      try {
        debug('开始执行任务');
        const id = $('script').map(((index, script) => {
          if (!/\$\(document\)/gim.test(script.innerHTML)) {
            return null;
          }
          return [ script.innerHTML.match(/"\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0], script.innerHTML.match(/"\/newsletter\/ajax\/subscribeprofile\/optin\/[\d]+"/gim)?.[0]?.match(/[\d]+/)?.[0] ];
        }));
        if (id.length < 2) {
          debug('获取任务ID失败');
          echoLog({}).error(I18n('getFailed', 'TaskId'));
          return false;
        }
        const pro = [];
        const tasks = $('#giveawaysjoined a[class*=promo]');
        debug('找到任务', {
          count: tasks.length
        });
        for (const task of tasks) {
          const promo = $(task);
          if (promo.hasClass('buttonentered')) {
            debug('跳过已完成任务');
            continue;
          }
          const taskText = promo.parents('p').text();
          debug('处理任务', {
            taskText: taskText
          });
          const status = echoLog({
            text: `${I18n('doing')}:${taskText}...`
          });
          if (/the-challenge-of-adblock/gim.test(promo.attr('href'))) {
            debug('跳过未知任务类型');
            status.error(`Error:${I18n('unKnownTaskType')}`);
            continue;
          }
          if (/facebookpromo|twitterpromo|visitpromo/gim.test(task.className)) {
            let text = '';
            if (promo.hasClass('facebookpromo')) {
              text = 'facebookpromo';
            } else if (promo.hasClass('twitterpromo')) {
              text = 'twitterpromo';
            } else {
              text = 'visitpromo';
            }
            debug('处理社交媒体任务', {
              type: text
            });
            pro.push(this.#handleSocialPromo(text, id[0], status, promo));
          } else if (promo.hasClass('emailoptinpromo')) {
            debug('处理邮件订阅任务');
            pro.push(this.#handleEmailPromo(id[1], status, promo));
          } else if (promo.hasClass('watchingpromo')) {
            debug('处理关注任务');
            pro.push(this.#handleWatchingPromo(promo, status));
          } else {
            debug('处理默认任务');
            pro.push(this.#handleDefaultPromo(promo, status));
          }
        }
        await Promise.all(pro);
        debug('所有任务完成');
        echoLog({}).success(I18n('allTasksComplete'));
        return true;
      } catch (error) {
        debug('执行任务失败', {
          error: error
        });
        throwError(error, 'Indiedb.do');
        return false;
      }
    }
    async #handleSocialPromo(text, id, status, promo) {
      try {
        debug('处理社交媒体任务', {
          text: text,
          id: id
        });
        return await new Promise((resolve => {
          $.ajax({
            type: 'POST',
            url: urlPath(`/giveaways/ajax/${text}/${id}`),
            timeout: 6e4,
            dataType: 'json',
            data: {
              ajax: 't'
            },
            error(response, error, exception) {
              debug('请求失败', {
                response: response,
                error: error,
                exception: exception
              });
              if (window.DEBUG) {
                console.log('%cAuto-Task[Debug]:', 'color:red', {
                  response: response,
                  error: error,
                  exception: exception
                });
              }
              status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
              resolve(true);
            },
            success(response) {
              if (response.success) {
                debug('任务完成', {
                  response: response
                });
                status.success(`Success:${response.text}`);
                promo.addClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
              } else {
                debug('任务失败', {
                  response: response
                });
                status.error(`Error:${response.text}`);
              }
              resolve(true);
            }
          });
        }));
      } catch (error) {
        debug('处理社交媒体任务失败', {
          error: error
        });
        throwError(error, 'Indiedb.handleSocialPromo');
        return false;
      }
    }
    async #handleEmailPromo(id, status, promo) {
      try {
        debug('处理邮件订阅任务', {
          id: id
        });
        return await new Promise((resolve => {
          $.ajax({
            type: 'POST',
            url: urlPath(`/newsletter/ajax/subscribeprofile/optin/${id}`),
            timeout: 6e4,
            dataType: 'json',
            data: {
              ajax: 't',
              emailsystoggle: 4
            },
            error(response, error, exception) {
              debug('请求失败', {
                response: response,
                error: error,
                exception: exception
              });
              if (window.DEBUG) {
                console.log('%cAuto-Task[Debug]:', 'color:red', {
                  response: response,
                  error: error,
                  exception: exception
                });
              }
              status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
              resolve(true);
            },
            success(response) {
              if (response.success) {
                debug('任务完成', {
                  response: response
                });
                status.success(`Success:${response.text}`);
                promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
              } else {
                debug('任务失败', {
                  response: response
                });
                status.error(`Error:${response.text}`);
              }
              resolve(true);
            }
          });
        }));
      } catch (error) {
        debug('处理邮件订阅任务失败', {
          error: error
        });
        throwError(error, 'Indiedb.handleEmailPromo');
        return false;
      }
    }
    async #handleWatchingPromo(promo, status) {
      try {
        debug('处理关注任务');
        return await new Promise((resolve => {
          const href = promo.attr('href');
          if (!href) {
            debug('无效的链接');
            status.error('Error: Invalid href');
            resolve(true);
            return;
          }
          const data = getUrlQuery(href);
          data.ajax = 't';
          const [baseUrl] = href.split(/[?#]/);
          if (!baseUrl) {
            debug('无效的URL');
            status.error('Error: Invalid URL');
            resolve(true);
            return;
          }
          debug('发送请求', {
            url: baseUrl,
            data: data
          });
          $.ajax({
            type: 'POST',
            url: urlPath(baseUrl),
            timeout: 6e4,
            dataType: 'json',
            data: data,
            error(response, error, exception) {
              debug('请求失败', {
                response: response,
                error: error,
                exception: exception
              });
              if (window.DEBUG) {
                console.log('%cAuto-Task[Debug]:', 'color:red', {
                  response: response,
                  error: error,
                  exception: exception
                });
              }
              status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
              resolve(true);
            },
            success(response) {
              if (response.success) {
                debug('任务完成', {
                  response: response
                });
                status.success(`Success:${response.text}`);
                promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
              } else {
                debug('任务失败', {
                  response: response
                });
                status.error(`Error:${response.text}`);
              }
              resolve(true);
            }
          });
        }));
      } catch (error) {
        debug('处理关注任务失败', {
          error: error
        });
        throwError(error, 'Indiedb.handleWatchingPromo');
        return false;
      }
    }
    async #handleDefaultPromo(promo, status) {
      try {
        debug('处理默认任务');
        return await new Promise((resolve => {
          const href = promo.attr('href');
          if (!href) {
            debug('无效的链接');
            status.error('Error: Invalid href');
            resolve(true);
            return;
          }
          debug('发送请求', {
            url: href
          });
          $.ajax({
            type: 'POST',
            url: urlPath(href),
            timeout: 6e4,
            dataType: 'json',
            data: {
              ajax: 't'
            },
            error(response, error, exception) {
              debug('请求失败', {
                response: response,
                error: error,
                exception: exception
              });
              if (window.DEBUG) {
                console.log('%cAuto-Task[Debug]:', 'color:red', {
                  response: response,
                  error: error,
                  exception: exception
                });
              }
              status.error('Error:An error has occurred performing the action requested. Please try again shortly.');
              resolve(true);
            },
            success(response) {
              if (response.success) {
                debug('任务完成', {
                  response: response
                });
                status.success(`Success:${response.text}`);
                promo.toggleClass('buttonentered').closest('p').html(promo.closest('p').find('span').html());
              } else {
                debug('任务失败', {
                  response: response
                });
                status.error(`Error:${response.text}`);
              }
              resolve(true);
            }
          });
        }));
      } catch (error) {
        debug('处理默认任务失败', {
          error: error
        });
        throwError(error, 'Indiedb.handleDefaultPromo');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        if ($('a.buttonenter:contains(Register to join)').length > 0) {
          debug('未登录,重定向到登录页面');
          window.open('/members/login', '_self');
        }
        debug('登录检查完成');
        return true;
      } catch (error) {
        debug('检查登录失败', {
          error: error
        });
        throwError(error, 'Indiedb.checkLogin');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const hasEndedButton = $('a.buttonenter:contains("next time"), a.buttonenter:contains("Giveaway is closed")').length > 0;
        debug('检查抽奖状态', {
          hasEndedButton: hasEndedButton
        });
        if (!hasEndedButton) {
          return true;
        }
        debug('抽奖已结束,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('giveawayEnded'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'Indiedb.checkLeftKey');
        return false;
      }
    }
  }
  const defaultTasksTemplate$5 = {
    steam: {
      groupLinks: [],
      officialGroupLinks: [],
      wishlistLinks: [],
      curatorLinks: []
    },
    discord: {
      serverLinks: []
    },
    extra: {
      videoTasks: []
    },
    links: []
  };
  const defaultTasks$6 = JSON.stringify(defaultTasksTemplate$5);
  class Keyhub extends Website {
    name='Keyhub';
    socialTasks=JSON.parse(defaultTasks$6);
    undoneTasks=JSON.parse(defaultTasks$6);
    buttons=[ 'doTask', 'undoTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'key-hub.eu';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('检查登录失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
        debug('隐藏 NSFW 内容');
        $('.NSFW').hide();
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Keyhub.after');
      }
    }
    init() {
      try {
        debug('开始初始化');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if ($('a[href*="/connect/steam"]').length > 0) {
          debug('需要登录 Steam');
          window.open('/connect/steam', '_self');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        if (!this.#getGiveawayId()) {
          debug('获取抽奖ID失败');
          return false;
        }
        debug('隐藏 VPN 覆盖层');
        $('#VPNoverlay').hide();
        $('#mainArticleSection').show();
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Keyhub.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`khTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks$6);
        }
        const tasks = $('.task:not(".googleads")').filter(((index, element) => action === 'do' ? $(element).find('i.fa-check-circle:visible').length === 0 : true)).find('a');
        debug('找到任务', {
          count: tasks.length
        });
        for (const task of tasks) {
          let link = $(task).attr('href');
          const taskDes = $(task).text().trim();
          debug('处理任务', {
            taskDes: taskDes,
            link: link
          });
          if (!link) {
            debug('跳过无链接任务');
            continue;
          }
          if (/\/away\?data=/.test(link) || /steamcommunity\.com\/gid\//.test(link)) {
            debug('获取重定向链接');
            link = await getRedirectLink(link) || link;
          }
          if (/https?:\/\/key-hub\.eu\/connect\/discord/.test(link)) {
            debug('处理 Discord 连接任务');
            GM_openInTab(link, {
              active: true
            });
            continue;
          }
          if (/steamcommunity\.com\/groups\//.test(link)) {
            debug('处理 Steam 组任务');
            if (action === 'undo') {
              this.socialTasks.steam.groupLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.steam.groupLinks.push(link);
            }
            continue;
          }
          if (/steamcommunity\.com\/games\/[\d]+/.test(link)) {
            debug('处理 Steam 官方组任务');
            if (action === 'undo') {
              this.socialTasks.steam.officialGroupLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.steam.officialGroupLinks.push(link);
            }
            continue;
          }
          if (/store\.steampowered\.com\/app\//.test(link) && /wishlist/gim.test(taskDes)) {
            debug('处理 Steam 愿望单任务');
            if (action === 'undo') {
              this.socialTasks.steam.wishlistLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.steam.wishlistLinks.push(link);
            }
            continue;
          }
          if (/store\.steampowered\.com\/curator\//.test(link)) {
            debug('处理 Steam 鉴赏家任务');
            if (action === 'undo') {
              this.socialTasks.steam.curatorLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.steam.curatorLinks.push(link);
            }
            continue;
          }
          if (/^https?:\/\/discord\.com\/invite\//.test(link)) {
            debug('处理 Discord 服务器任务');
            if (action === 'undo') {
              this.socialTasks.discord.serverLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.discord.serverLinks.push(link);
            }
            continue;
          }
          if (/^javascript:videoTask.+/.test(link)) {
            debug('处理视频任务');
            if (action === 'do') {
              const taskData = link.match(/javascript:videoTask\('.+?','(.+?)'/)?.[1];
              if (taskData) {
                debug('添加视频任务', {
                  taskData: taskData
                });
                this.undoneTasks.extra.videoTasks.push(taskData);
              }
            }
            continue;
          }
          if (this.#isSkippableLink(link)) {
            debug('跳过可忽略的链接', {
              link: link
            });
            continue;
          }
          debug('未知任务类型', {
            taskDes: taskDes,
            link: link
          });
          echoLog({}).warning(`${I18n('unKnownTaskType')}: ${taskDes}(${link})`);
        }
        debug('任务分类完成');
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        if (window.DEBUG) {
          console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
        }
        debug('保存任务信息');
        GM_setValue(`khTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Keyhub.classifyTask');
        return false;
      }
    }
    #isSkippableLink(link) {
      return /^https?:\/\/www\.instagram\.com\/.*/.test(link) || /^https?:\/\/twitter\.com\/.*/.test(link) || /^https?:\/\/www\.twitch\.tv\/.*/.test(link) || /^https?:\/\/www\.facebook\.com\/.*/.test(link) || /^https?:\/\/www\.youtube\.com\/.*/.test(link) || /^https?:\/\/store\.steampowered\.com\/developer\//.test(link) || /^https?:\/\/.*?\.itch\.io\/.*/.test(link) || /^https?:\/\/key-hub\.eu.*/.test(link) || /^https?:\/\/store\.steampowered\.com\/app\/.*/.test(link) || /^https?:\/\/qr\.streamelements\.com\/.*/.test(link) || /^https?:\/\/store\.steampowered\.com\/news\/app\/.*/.test(link);
    }
    async #doScriptTask(data) {
      try {
        debug('执行脚本任务', {
          data: data
        });
        const logStatus = echoLog({
          text: I18n('doingKeyhubTask')
        });
        const {result: result, statusText: statusText, status: status, data: response} = await httpRequest({
          url: `/away?data=${data}`,
          method: 'GET',
          headers: {
            origin: 'https://key-hub.eu',
            referer: 'https://key-hub.eu/'
          }
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (response?.status !== 200) {
          debug('响应错误', {
            status: response?.status,
            statusText: response?.statusText
          });
          logStatus.error(`Error:${response?.statusText}(${response?.status})`);
          return false;
        }
        debug('任务完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('执行脚本任务失败', {
          error: error
        });
        throwError(error, 'Keyhub.doScriptTask');
        return false;
      }
    }
    async extraDoTask({videoTasks: videoTasks}) {
      try {
        debug('开始执行额外任务', {
          count: videoTasks.length
        });
        const pro = [];
        for (const data of videoTasks) {
          pro.push(this.#doScriptTask(data));
        }
        return Promise.all(pro).then((() => {
          debug('所有额外任务完成');
          return true;
        }));
      } catch (error) {
        debug('执行额外任务失败', {
          error: error
        });
        throwError(error, 'Keyhub.extraDoTask');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('获取抽奖ID');
        const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({}).error(I18n('getFailed', 'GiveawayId'));
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'Keyhub.getGiveawayId');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const leftKey = $('#keysleft').text().trim();
        debug('检查剩余密钥数量', {
          leftKey: leftKey
        });
        if (leftKey !== '0') {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('noKeysLeft'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'Keyhub.checkLeftKey');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        if ($('a[href*="/connect/steam"]').length > 0) {
          debug('未登录,重定向到 Steam 登录页面');
          window.open('/connect/steam', '_self');
        }
        debug('登录检查完成');
        return true;
      } catch (error) {
        debug('检查登录失败', {
          error: error
        });
        throwError(error, 'Keyhub.checkLogin');
        return false;
      }
    }
  }
  const defaultTasksTemplate$4 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      curatorLinks: [],
      curatorLikeLinks: []
    },
    twitter: {
      userLinks: []
    },
    vk: {
      nameLinks: []
    },
    discord: {
      serverLinks: []
    }
  };
  const defaultTasks$5 = JSON.stringify(defaultTasksTemplate$4);
  class Givekey extends Website {
    name='Givekey';
    tasks=[];
    socialTasks=JSON.parse(defaultTasks$5);
    undoneTasks=JSON.parse(defaultTasks$5);
    userId;
    buttons=[ 'doTask', 'undoTask', 'verifyTask' ];
    static test() {
      const url = window.location.host;
      const isMatch = url === 'givekey.ru';
      debug('检查网站匹配', {
        url: url,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        await new Promise((resolve => {
          const checker = setInterval((() => {
            if ($('#navbarDropdown').length > 0) {
              debug('导航栏元素已加载');
              clearInterval(checker);
              resolve(true);
            }
          }), 500);
        }));
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Givekey.after');
      }
    }
    init() {
      try {
        debug('初始化 Givekey');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if ($('a[href*="/auth/steam"]').length > 0) {
          debug('未登录,重定向到 Steam 登录页面');
          window.open('/auth/steam', '_self');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        if (!this.#getGiveawayId()) {
          debug('获取抽奖ID失败');
          return false;
        }
        const userId = $('meta[name="user-id"]').attr('content');
        if (!userId) {
          debug('获取用户ID失败');
          logStatus.error(I18n('getFailed', I18n('userId')));
          return false;
        }
        this.userId = userId;
        this.initialized = true;
        debug('初始化完成', {
          userId: userId
        });
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Givekey.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`gkTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks$5);
        }
        const tasks = $('.card-body:has("button") .row');
        debug('找到任务元素', {
          count: tasks.length
        });
        for (const task of tasks) {
          const taskEle = $(task);
          const button = taskEle.find('button');
          const isSuccess = /Complete/i.test(button.text().trim());
          debug('处理任务', {
            isSuccess: isSuccess
          });
          if (isSuccess && action !== 'undo') {
            debug('跳过已完成的任务');
            continue;
          }
          const checkButton = taskEle.find('#task_check');
          const taskId = checkButton.attr('data-id');
          if (taskId) {
            debug('添加任务ID', {
              taskId: taskId
            });
            this.tasks.push(taskId);
          }
          if (action === 'verify') {
            continue;
          }
          const taskLink = taskEle.find('a');
          let href = taskLink.attr('href');
          if (!href) {
            debug('任务链接为空');
            continue;
          }
          const text = taskLink.text().trim();
          if (!text) {
            debug('任务描述为空');
            continue;
          }
          if (/^https?:\/\/givekey\.ru\/giveaway\/[\d]+\/execution_task/.test(href)) {
            debug('获取重定向链接', {
              href: href
            });
            href = await getRedirectLink(href);
          }
          if (!href) {
            debug('获取重定向链接失败');
            continue;
          }
          const icon = taskEle.find('i');
          await this.#classifyTaskByType(href, text, icon, isSuccess, action);
        }
        debug('任务分类完成');
        logStatus.success();
        this.tasks = unique(this.tasks);
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        debug('保存任务信息');
        GM_setValue(`gkTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Givekey.classifyTask');
        return false;
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        if (!this.initialized && !this.init()) {
          debug('初始化失败');
          return false;
        }
        if (this.tasks.length === 0 && !await this.classifyTask('verify')) {
          debug('任务分类失败');
          return false;
        }
        echoLog({}).warning(I18n('giveKeyNoticeBefore'));
        const taskLength = this.tasks.length;
        debug('开始验证任务', {
          taskCount: taskLength
        });
        for (let i = 0; i < taskLength; i++) {
          await this.#verify(this.tasks[i]);
          if (i < taskLength - 1) {
            debug('等待15秒');
            await delay(15e3);
          }
        }
        debug('所有任务验证完成');
        echoLog({}).success(I18n('allTasksComplete'));
        echoLog({
          html: `<li><font class="warning">${I18n('giveKeyNoticeAfter')}</font></li>`
        });
        return true;
      } catch (error) {
        debug('任务验证失败', {
          error: error
        });
        throwError(error, 'Givekey.verifyTask');
        return false;
      }
    }
    async #verify(task) {
      try {
        debug('验证任务', {
          taskId: task
        });
        const logStatus = echoLog({
          html: `<li>${I18n('verifyingTask')}${task}...<font></font></li>`
        });
        const csrfToken = $('meta[name="csrf-token"]').attr('content');
        if (!csrfToken) {
          debug('CSRF token 未找到');
          logStatus.error('CSRF token not found');
          return false;
        }
        debug('发送验证请求');
        const response = await $.ajax({
          url: 'https://givekey.ru/giveaway/task',
          method: 'POST',
          data: `id=${task}&user_id=${this.userId}`,
          dataType: 'json',
          headers: {
            'X-CSRF-TOKEN': csrfToken
          }
        });
        if (!response) {
          debug('未收到响应');
          logStatus.error('No response received');
          return false;
        }
        debug('处理响应', {
          response: response
        });
        if (response.btn) {
          $(`button[data-id=${this.userId}]`).html(response.btn);
        }
        if (response.status === 'ok') {
          $(`.task_check_${response.id}`).html(`<button class="btn btn-success mb-2 btn-block" disabled>${response.btn}</button>`);
          debug('任务验证成功');
          logStatus.success();
          return true;
        }
        if (response.status === 'end') {
          debug('获得密钥');
          logStatus.success();
          echoLog({}).success(response.key);
          return true;
        }
        debug('验证失败', {
          error: response.msg
        });
        logStatus.error(`Error:${response.msg}`);
        return false;
      } catch (error) {
        debug('验证过程出错', {
          error: error
        });
        throwError(error, 'Givekey.verify');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('从URL获取抽奖ID');
        const giveawayId = window.location.href.match(/giveaway\/([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({
          text: I18n('getFailed', 'GiveawayId')
        });
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'Givekey.getGiveawayId');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const keysCount = $('#keys_count').text();
        debug('检查密钥数量', {
          keysCount: keysCount
        });
        if (keysCount) {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('noKeysLeft'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'Givekey.checkLeftKey');
        return false;
      }
    }
    async #classifyTaskByType(href, text, icon, isSuccess, action) {
      try {
        debug('开始分类任务类型', {
          href: href,
          text: text,
          isSuccess: isSuccess,
          action: action
        });
        if (/^https?:\/\/vk\.com\//.test(href)) {
          debug('添加 VK 任务');
          this.socialTasks.vk.nameLinks.push(href);
          if (action === 'do' && !isSuccess) {
            this.undoneTasks.vk.nameLinks.push(href);
          }
          return;
        }
        if (/^https?:\/\/steamcommunity\.com\/groups/.test(href)) {
          debug('添加 Steam 组任务');
          this.socialTasks.steam.groupLinks.push(href);
          if (action === 'do' && !isSuccess) {
            this.undoneTasks.steam.groupLinks.push(href);
          }
          return;
        }
        if (/^https?:\/\/store\.steampowered\.com\/app\//.test(href)) {
          debug('添加 Steam 愿望单任务');
          this.socialTasks.steam.wishlistLinks.push(href);
          if (action === 'do' && !isSuccess) {
            this.undoneTasks.steam.wishlistLinks.push(href);
          }
          return;
        }
        if (/Subscribe/gi.test(text) && icon.hasClass('fa-steam-square')) {
          if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(href)) {
            debug('添加 Steam 鉴赏家关注任务');
            this.socialTasks.steam.curatorLinks.push(href);
            if (action === 'do' && !isSuccess) {
              this.undoneTasks.steam.curatorLinks.push(href);
            }
          } else {
            debug('添加 Steam 鉴赏家点赞任务');
            this.socialTasks.steam.curatorLikeLinks.push(href);
            if (action === 'do' && !isSuccess) {
              this.undoneTasks.steam.curatorLikeLinks.push(href);
            }
          }
          return;
        }
        if (/^https?:\/\/twitter\.com\//.test(href) && /Subscribe/gi.test(text)) {
          debug('添加 Twitter 关注任务');
          this.socialTasks.twitter.userLinks.push(href);
          if (action === 'do' && !isSuccess) {
            this.undoneTasks.twitter.userLinks.push(href);
          }
          return;
        }
        if (icon.hasClass('fa-discord') || /^https?:\/\/discord\.com\/invite\//.test(href)) {
          debug('添加 Discord 服务器任务');
          this.socialTasks.discord.serverLinks.push(href);
          if (action === 'do' && !isSuccess) {
            this.undoneTasks.discord.serverLinks.push(href);
          }
          return;
        }
        debug('未识别的任务类型', {
          href: href,
          text: text
        });
        echoLog({}).warning(`${I18n('unKnownTaskType')}: ${text}(${href})`);
      } catch (error) {
        debug('任务类型分类失败', {
          error: error
        });
        throwError(error, 'Givekey.classifyTaskByType');
      }
    }
  }
  class GiveeClub extends GiveawaySu {
    name='GiveeClub';
    buttons=[ 'doTask', 'undoTask', 'verifyTask' ];
    static test() {
      const url = window.location.href;
      const isMatch = /^https?:\/\/givee\.club\/.*?\/event\/[\d]+/.test(url);
      debug('检查网站匹配', {
        url: url,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('登录检查失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'GiveeClub.after');
      }
    }
    init() {
      try {
        debug('初始化 GiveeClub');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if (!this.#checkLogin()) {
          debug('登录检查失败');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        const giveawayIdResult = this.#getGiveawayId();
        if (!giveawayIdResult) {
          debug('获取抽奖ID失败');
          return false;
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'GiveeClub.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`gcTasks-${this.giveawayId}`)?.tasks || defaultTasks$7;
          return true;
        }
        debug('初始化未完成任务列表');
        this.undoneTasks = defaultTasks$7;
        const tasks = $('.event-actions tr');
        const processTask = async task => {
          const taskDes = $(task).find('.event-action-label a');
          const taskIcon = $(task).find('.event-action-icon i').attr('class') || '';
          const taskName = taskDes.text().trim();
          const taskType = $(task).find('button[data-type]')?.attr('data-type') || '';
          const taskFinished = $(task).find('.event-action-buttons .btn-success')?.length;
          const appId = taskDes.attr('data-steam-wishlist-appid');
          debug('处理任务', {
            taskName: taskName,
            taskType: taskType,
            taskIcon: taskIcon,
            taskFinished: taskFinished,
            appId: appId
          });
          if (taskIcon.includes('ban') || /AdBlock/i.test(taskName) || taskIcon.includes('envelope') || taskFinished) {
            debug('跳过无效或已完成任务');
            return true;
          }
          const taskHref = taskDes.attr('href');
          if (!taskHref) {
            debug('任务链接为空');
            return false;
          }
          try {
            debug('获取重定向链接', {
              taskHref: taskHref
            });
            const taskLink = await getRedirectLink(taskHref, taskType.includes('steam'));
            if (!taskLink) {
              debug('获取重定向链接失败');
              return false;
            }
            if (taskType === 'steam.game.wishlist' && appId) {
              debug('添加 Steam 愿望单任务', {
                appId: appId
              });
              this.undoneTasks.steam.wishlistLinks.push(`https://store.steampowered.com/app/${appId}`);
              return true;
            }
            debug('分类任务', {
              taskLink: taskLink,
              taskType: taskType
            });
            this.#classifyTaskByType(taskLink, taskType, taskIcon, taskName, taskDes);
            return true;
          } catch (error) {
            debug('获取重定向链接失败', {
              error: error
            });
            throwError(error, 'GiveeClub.classifyTask->getRedirectLink');
            return false;
          }
        };
        debug('开始处理所有任务');
        await Promise.all(Array.from(tasks).map(processTask));
        debug('任务处理完成');
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.undoneTasks;
        debug('保存任务信息');
        GM_setValue(`gcTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'GiveeClub.classifyTask');
        return false;
      }
    }
    #classifyTaskByType(taskLink, taskType, taskIcon, taskName, taskDes) {
      try {
        debug('开始分类任务', {
          taskLink: taskLink,
          taskType: taskType,
          taskIcon: taskIcon,
          taskName: taskName
        });
        if (taskType === 'steam.group.join' && /^https?:\/\/steamcommunity\.com\/groups/.test(taskLink)) {
          debug('添加 Steam 组任务');
          this.undoneTasks.steam.groupLinks.push(taskLink);
          return;
        }
        if (/like.*announcement/gi.test(taskName)) {
          debug('添加 Steam 公告任务');
          this.undoneTasks.steam.announcementLinks.push(taskLink);
          return;
        }
        if (taskType === 'steam.game.wishlist' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
          debug('添加 Steam 愿望单任务');
          this.undoneTasks.steam.wishlistLinks.push(taskLink);
          return;
        }
        if (taskType === 'steam.game.wishlist' && taskDes.attr('data-steam-wishlist-appid')) {
          debug('添加 Steam 愿望单任务(通过 appId)');
          this.undoneTasks.steam.wishlistLinks.push(`https://store.steampowered.com/app/${taskDes.attr('data-steam-wishlist-appid')}`);
          return;
        }
        if (taskType === 'steam.game.follow' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
          debug('添加 Steam 游戏关注任务');
          this.undoneTasks.steam.followLinks.push(taskLink);
          return;
        }
        if (/^https?:\/\/store\.steampowered\.com\/curator\//.test(taskLink)) {
          debug('添加 Steam 鉴赏家关注任务');
          this.undoneTasks.steam.curatorLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('steam') && /follow|subscribe/gim.test(taskName)) {
          debug('添加 Steam 鉴赏家点赞任务');
          this.undoneTasks.steam.curatorLikeLinks.push(taskLink);
          return;
        }
        if (/subscribe.*steam.*forum/gim.test(taskName)) {
          debug('添加 Steam 论坛任务');
          this.undoneTasks.steam.forumLinks.push(taskLink);
          return;
        }
        if (taskType === 'steam.game.playtime' && /^https?:\/\/store\.steampowered\.com\/app\//.test(taskLink)) {
          const time = taskDes.text().match(/(\d+)(?:\.\d+)?/gim)?.[0] || '0';
          debug('添加 Steam 游戏时长任务', {
            time: time
          });
          this.undoneTasks.steam.playTimeLinks.push(`${time}-${taskLink}`);
          return;
        }
        if (taskIcon.includes('discord')) {
          debug('添加 Discord 服务器任务');
          this.undoneTasks.discord.serverLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('instagram')) {
          debug('跳过 Instagram 任务');
          return;
        }
        if (taskIcon.includes('twitch')) {
          debug('添加 Twitch 频道任务');
          this.undoneTasks.twitch.channelLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('reddit')) {
          debug('添加 Reddit 任务');
          this.undoneTasks.reddit.redditLinks.push(taskLink);
          return;
        }
        if (/watch.*art/gim.test(taskName)) {
          debug('添加创意工坊物品任务');
          this.undoneTasks.steam.workshopVoteLinks.push(taskLink);
          return;
        }
        if (/subscribe.*youtube.*channel/gim.test(taskName)) {
          debug('添加 YouTube 频道任务');
          this.undoneTasks.youtube.channelLinks.push(taskLink);
          return;
        }
        if (/(watch|like).*youtube.*video/gim.test(taskName) || (taskIcon.includes('youtube') || taskIcon.includes('thumbs-up')) && /(watch|like).*video/gim.test(taskName)) {
          debug('添加 YouTube 视频任务');
          this.undoneTasks.youtube.likeLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('vk') || /join.*vk.*group/gim.test(taskName)) {
          debug('添加 VK 任务');
          this.undoneTasks.vk.nameLinks.push(taskLink);
          return;
        }
        if (taskIcon.includes('twitter')) {
          if (/https?:\/\/(twitter|x)\.com\/[^/]+\/?$/gim.test(taskLink)) {
            debug('添加 Twitter 用户关注任务');
            this.undoneTasks.twitter.userLinks.push(taskLink);
            return;
          }
          if (/https?:\/\/(twitter|x)\.com\/[^/]+?\/status\/[\d]+/gim.test(taskLink)) {
            debug('添加 Twitter 转发任务');
            this.undoneTasks.twitter.retweetLinks.push(taskLink);
            return;
          }
        }
        if (/(on twitter)|(Follow.*on.*Facebook)/gim.test(taskName)) {
          debug('跳过 Twitter/Facebook 任务');
          return;
        }
        if (/follow.*button/gim.test(taskName)) {
          debug('添加 Steam 关注任务');
          this.undoneTasks.steam.followLinks.push(taskLink);
          return;
        }
        debug('未识别的任务类型', {
          taskLink: taskLink,
          taskType: taskType,
          taskIcon: taskIcon,
          taskName: taskName
        });
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'GiveeClub.classifyTaskByType');
        return;
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        const logStatus = echoLog({
          text: I18n('giveeClubVerifyNotice')
        });
        const taskButtons = $('.event-actions tr button').has('i.glyphicon-refresh').not('[data-type="user.adblock"]');
        debug('找到需要验证的任务按钮', {
          count: taskButtons.length
        });
        for (const button of taskButtons) {
          debug('点击验证按钮', {
            type: $(button).attr('data-type')
          });
          button.click();
          if ($(button).attr('data-type') !== 'steam.game.wishlist') {
            debug('等待1秒');
            await delay(1e3);
          }
        }
        debug('任务验证完成');
        logStatus.warning(I18n('giveeClubVerifyFinished'));
        return true;
      } catch (error) {
        debug('任务验证失败', {
          error: error
        });
        throwError(error, 'Givekey.verifyTask');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        const needLogin = $('a[href*="/account/auth"]').length > 0;
        if (needLogin) {
          debug('未登录,重定向到登录页面');
          window.open($('a[href*="/account/auth"]').attr('href'), '_self');
        }
        debug('登录检查完成', {
          needLogin: needLogin
        });
        return true;
      } catch (error) {
        debug('登录检查失败', {
          error: error
        });
        throwError(error, 'GiveeClub.checkLogin');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('从URL获取抽奖ID');
        const giveawayId = window.location.href.match(/\/event\/([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({
          text: I18n('getFailed', 'GiveawayId')
        });
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'GiveeClub.getGiveawayId');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const isEnded = $('.event-ended').length > 0;
        const hasNoWinner = $('.event-winner').length === 0;
        debug('检查抽奖状态', {
          isEnded: isEnded,
          hasNoWinner: hasNoWinner
        });
        if (!(isEnded && hasNoWinner)) {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('giveawayEnded'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'GiveeClub.checkLeftKey');
        return false;
      }
    }
  }
  const defaultOptions$1 = {
    maxPoint: '99999999'
  };
  class OpiumPulses {
    name='OpiumPulses';
    options={
      ...defaultOptions$1,
      ...GM_getValue('OpiumPulsesOptions')
    };
    maxPoints=99999999;
    myPoints=0;
    buttons=[ 'doFreeTask', 'doPointTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'www.opiumpulses.com';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('检查登录失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        debug('解析最大积分', {
          maxPoint: this.options.maxPoint
        });
        this.maxPoints = parseInt(this.options.maxPoint, 10);
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'OpiumPulses.after');
      }
    }
    async doFreeTask() {
      try {
        debug('开始执行免费任务');
        this.#toggleTask('FREE');
      } catch (error) {
        debug('执行免费任务失败', {
          error: error
        });
        throwError(error, 'OpiumPulses.doFreeTask');
      }
    }
    async doPointTask() {
      try {
        debug('开始执行积分任务');
        const pointsText = $('.page-header__nav-func-user-nav-items.points-items').text();
        const pointsMatch = pointsText.match(/[\d]+/gim)?.[0] || '0';
        this.myPoints = parseInt(pointsMatch, 10);
        debug('获取当前积分', {
          pointsText: pointsText,
          pointsMatch: pointsMatch,
          myPoints: this.myPoints
        });
        this.#toggleTask('points');
      } catch (error) {
        debug('执行积分任务失败', {
          error: error
        });
        throwError(error, 'OpiumPulses.doPointTask');
      }
    }
    async #toggleTask(type) {
      try {
        debug('开始切换任务', {
          type: type
        });
        const items = $(`.giveaways-page-item:contains('${type}'):not(:contains('ENTERED'))`);
        debug('找到未参与的抽奖项目', {
          count: items.length
        });
        for (const item of items) {
          const pointsText = $(item).find('.giveaways-page-item-header-points').text();
          const needPoints = parseInt(pointsText.match(/[\d]+/gim)?.[0] || '999999', 10);
          const name = $(item).find('.giveaways-page-item-footer-name').text().trim();
          debug('处理抽奖项目', {
            name: name,
            needPoints: needPoints
          });
          if (type === 'points') {
            if (needPoints > this.myPoints) {
              debug('积分不足', {
                needPoints: needPoints,
                myPoints: this.myPoints
              });
              echoLog({}).warning(`${I18n('noPoints')}: ${name}`);
              continue;
            }
            if (!needPoints) {
              debug('获取所需积分失败');
              echoLog({}).warning(`${I18n('getNeedPointsFailed')}: ${name}`);
              continue;
            }
            if (needPoints > this.maxPoints) {
              debug('超过最大积分限制', {
                needPoints: needPoints,
                maxPoints: this.maxPoints
              });
              continue;
            }
          }
          const logStatus = echoLog({
            text: `${I18n('joiningLottery')}<a href="${$(item).find('a.giveaways-page-item-img-btn-more').attr('href')}" target="_blank">${name}</a>...`
          });
          const aElement = $(item).find('a.giveaways-page-item-img-btn-enter:contains(\'enter\')');
          if (aElement?.attr('onclick')?.includes('checkUser')) {
            const giveawayId = aElement.attr('onclick')?.match(/[\d]+/)?.[0];
            if (giveawayId) {
              debug('执行用户检查', {
                giveawayId: giveawayId
              });
              checkUser(giveawayId);
            }
          }
          if (!aElement.attr('href')) {
            debug('无效的链接');
            logStatus.error('Error: No "href".');
            continue;
          }
          debug('发送加入请求', {
            url: aElement.attr('href')
          });
          const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
            url: aElement.attr('href'),
            method: 'GET'
          });
          if (result !== 'Success') {
            debug('请求失败', {
              result: result,
              statusText: statusText,
              status: status
            });
            logStatus.error(`${result}:${statusText}(${status})`);
            continue;
          }
          debug('发送最终请求', {
            url: data?.finalUrl
          });
          const {result: result0, statusText: statusText0, status: status0, data: data0} = await httpRequest({
            url: data?.finalUrl,
            method: 'GET'
          });
          if (!data0?.responseText) {
            debug('响应无效', {
              result: result0,
              statusText: statusText0,
              status: status0
            });
            logStatus.error(`${result0}:${statusText0}(${status0})`);
            continue;
          }
          if (/You're not eligible to enter/gim.test(data0.responseText)) {
            debug('用户不符合参与条件');
            logStatus.error('You\'re not eligible to enter');
            continue;
          }
          if (!/You've entered this giveaway/gim.test(data0.responseText)) {
            debug('加入抽奖失败', {
              result: result0,
              statusText: statusText0,
              status: status0
            });
            logStatus.error(`${result0}:${statusText0}(${status0})`);
            continue;
          }
          debug('加入抽奖成功');
          logStatus.success();
          if (type === 'points') {
            const points = data0.responseText.match(/Points:[\s]*?([\d]+)/)?.[1];
            if (points) {
              debug('更新用户积分', {
                points: points
              });
              this.myPoints = parseInt(points, 10);
            }
          }
        }
        debug('任务处理完成');
        echoLog({
          text: '-----END-----'
        });
      } catch (error) {
        debug('切换任务失败', {
          error: error
        });
        throwError(error, 'OpiumPulses.toggleTask');
      }
    }
    init() {
      debug('初始化完成');
      return true;
    }
    classifyTask() {
      debug('任务分类完成');
      return true;
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        if ($('a[href*="/site/login"]').length > 1) {
          debug('未登录,重定向到登录页面');
          window.open('/site/login', '_self');
        }
        debug('登录检查完成');
        return true;
      } catch (error) {
        debug('检查登录失败', {
          error: error
        });
        throwError(error, 'OpiumPulses.checkLogin');
        return false;
      }
    }
  }
  const leftKeyChecker = {
    async classify(link) {
      try {
        debug('开始分类链接', {
          link: link
        });
        let result = false;
        if (/^https?:\/\/giveaway\.su\/giveaway\/view\/[\d]+/.test(link)) {
          debug('匹配到 giveaway.su 链接');
          result = await this.giveawaySu(link);
        } else if (/^https?:\/\/givee\.club\/[\w]+?\/event\/[\d]+/.test(link)) {
          debug('匹配到 givee.club 链接');
          result = await this.giveeClub(link);
        } else if (/^https?:\/\/gleam\.io\/.+?\/.+/.test(link)) {
          debug('匹配到 gleam.io 链接');
          result = await this.gleam(link);
        } else if (/^https?:\/\/www\.indiedb\.com\/giveaways\/.+/.test(link)) {
          debug('匹配到 indiedb.com 链接');
          result = await this.indieDb(link);
        } else if (/^https?:\/\/key-hub\.eu\/giveaway\/[\d]+/.test(link)) {
          debug('匹配到 key-hub.eu 链接');
          result = await this.keyhub(link);
        } else if (/^https?:\/\/opquests\.com\/quests\/[\d]+/.test(link)) {
          debug('匹配到 opquests.com 链接');
          result = await this.opquests(link);
        } else if (/^https?:\/\/itch\.io\/s\/[\d]+?\/.*/.test(link)) {
          debug('匹配到 itch.io 链接');
          result = await this.itch(link);
        } else if (/^https?:\/\/freeanywhere\.net\/game\?n=[\d]+/.test(link)) {
          debug('匹配到 freeanywhere.net 链接');
          result = await this.freeanywhere(link);
        } else {
          debug('未匹配到支持的链接格式');
        }
        debug('链接分类完成', {
          result: result
        });
        return result;
      } catch (error) {
        debug('链接分类出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.classify');
        return false;
      }
    },
    async giveawaySu(link) {
      try {
        debug('开始检查 giveaway.su 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        if (data.responseText.includes('class="steam-login"')) {
          debug('检测到未登录状态');
          return false;
        }
        if (data.responseText.includes('class="giveaway-ended"')) {
          debug('检测到抽奖已结束');
          return 'Ended';
        }
        debug('检测到抽奖进行中');
        return 'Active';
      } catch (error) {
        debug('检查 giveaway.su 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.giveawaySu');
        return false;
      }
    },
    async giveeClub(link) {
      try {
        debug('开始检查 givee.club 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        if (data.responseText.includes('class="event-winner"')) {
          debug('检测到已中奖');
          return 'Won';
        }
        if (data.responseText.includes('class="event-ended"')) {
          debug('检测到活动已结束');
          return 'Ended';
        }
        debug('检测到活动进行中');
        return 'Active';
      } catch (error) {
        debug('检查 givee.club 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.giveeClub');
        return false;
      }
    },
    async gleam(link) {
      try {
        debug('开始检查 gleam.io 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        if (/incentives&quot;:{&quot;[\d]+?&quot;:\[&quot;.+?&quot;\]/.test(data.responseText)) {
          debug('检测到已中奖');
          return 'Won';
        }
        const campaignDiv = data.responseText.match(/<div class='popup-blocks-container'[\w\W]+?'>/)?.[0];
        if (!campaignDiv) {
          debug('未找到活动信息');
          return false;
        }
        const campaignString = $(campaignDiv).attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1];
        if (!campaignString) {
          debug('未找到活动初始化数据');
          return false;
        }
        const {campaign: campaign} = JSON.parse(campaignString);
        debug('解析活动数据', {
          campaign: campaign
        });
        if (campaign.banned) {
          debug('检测到活动已被禁止');
          return 'Banned';
        }
        if (campaign.finished) {
          debug('检测到活动已结束');
          return 'Ended';
        }
        if (campaign.paused) {
          debug('检测到活动已暂停');
          return 'Paused';
        }
        if ((new Date).getTime() < campaign.starts_at * 1e3) {
          debug('检测到活动未开始');
          return 'NotStart';
        }
        debug('检测到活动进行中');
        return 'Active';
      } catch (error) {
        debug('检查 gleam.io 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.gleam');
        return false;
      }
    },
    async indieDb(link) {
      try {
        debug('开始检查 indiedb.com 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        if (data.responseText.includes('Congrats you WON')) {
          debug('检测到已中奖');
          return 'Won';
        }
        if (data.responseText.includes('Giveaway is closed') || data.responseText.includes('next time')) {
          debug('检测到抽奖已结束');
          return 'Ended';
        }
        debug('检测到抽奖进行中');
        return 'Active';
      } catch (error) {
        debug('检查 indiedb.com 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.indieDb');
        return false;
      }
    },
    async keyhub(link) {
      try {
        debug('开始检查 key-hub.eu 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        const keysleft = data.responseText.match(/<span id="keysleft">([\d]+?)<\/span>/)?.[1];
        if (!keysleft) {
          debug('未找到剩余密钥信息');
          return false;
        }
        debug('检测到剩余密钥数量', {
          keysleft: keysleft
        });
        if (keysleft === '0') {
          debug('检测到密钥已用完');
          return 'Ended';
        }
        debug('检测到活动进行中');
        return `Active(${keysleft})`;
      } catch (error) {
        debug('检查 key-hub.eu 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.keyhub');
        return false;
      }
    },
    async opquests(link) {
      try {
        debug('开始检查 opquests.com 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (data?.status === 404) {
          debug('检测到活动不存在');
          return 'Ended';
        }
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        const keysleft = data.responseText.match(/<div class="">[\s]*?([\d]+?)[\s]*?of/)?.[1];
        if (!keysleft) {
          debug('未找到剩余密钥信息');
          return false;
        }
        debug('检测到剩余密钥数量', {
          keysleft: keysleft
        });
        if (keysleft === '0') {
          debug('检测到密钥已用完');
          return 'Ended';
        }
        debug('检测到活动进行中');
        return `Active(${keysleft})`;
      } catch (error) {
        debug('检查 opquests.com 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.opquests');
        return false;
      }
    },
    async itch(link) {
      try {
        debug('开始检查 itch.io 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        const endDate = data.responseText.match(/{"start_date":"[0-9A-Z-:]+?".*?"end_date":"([0-9A-Z-:]+?)".*?}/)?.[1];
        if (!endDate) {
          debug('未找到结束日期信息');
          return false;
        }
        debug('检测到活动结束日期', {
          endDate: endDate
        });
        if ((new Date).getTime() > new Date(endDate).getTime()) {
          debug('检测到活动已结束');
          return 'Ended';
        }
        const formattedEndDate = dayjs(endDate).format('YYYY-MM-DD HH:mm:ss');
        debug('检测到活动进行中', {
          formattedEndDate: formattedEndDate
        });
        return `Active(${formattedEndDate})`;
      } catch (error) {
        debug('检查 itch.io 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.itch');
        return false;
      }
    },
    async freeanywhere(link) {
      try {
        debug('开始检查 freeanywhere.net 链接', {
          link: link
        });
        const {result: result, data: data} = await httpRequest({
          url: link,
          method: 'GET'
        });
        if (result !== 'Success' || data?.status !== 200) {
          debug('请求失败', {
            result: result,
            status: data?.status
          });
          return false;
        }
        const giveawayStatus = data.responseText.includes('Giveaway ended');
        if (giveawayStatus) {
          debug('检测到活动已结束');
          return 'Ended';
        }
        debug('检测到活动进行中');
        return 'Active';
      } catch (error) {
        debug('检查 freeanywhere.net 链接出错', {
          error: error
        });
        throwError(error, 'leftKeyChecker.freeanywhere');
        return false;
      }
    }
  };
  const defaultTasksTemplate$3 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      curatorLinks: [],
      curatorLikeLinks: [],
      followLinks: [],
      forumLinks: [],
      announcementLinks: [],
      workshopVoteLinks: [],
      licenseLinks: []
    },
    discord: {
      serverLinks: []
    },
    vk: {
      nameLinks: []
    },
    twitch: {
      channelLinks: []
    },
    reddit: {
      redditLinks: []
    },
    twitter: {
      userLinks: [],
      retweetLinks: []
    },
    youtube: {
      channelLinks: [],
      likeLinks: []
    }
  };
  const defaultTasks$4 = JSON.stringify(defaultTasksTemplate$3);
  class Keylol extends Website {
    name='Keylol';
    socialTasks=JSON.parse(defaultTasks$4);
    undoneTasks=JSON.parse(defaultTasks$4);
    buttons=[ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect' ];
    static CONFIG={
      LINK_PATTERNS: {
        DISCORD: /^https?:\/\/discord\.com\/invite\/.+/,
        REDDIT: /^https?:\/\/www\.reddit\.com\/(r|user)\/.+/,
        INSTAGRAM: /^https:\/\/www\.instagram\.com\/.+/,
        TWITTER: /^https:\/\/(twitter|x)\.com\/.+/,
        TWITTER_RETWEET: /https:\/\/(twitter|x)\.com\/.*?\/status\/[\d]+/,
        TWITCH: /^https:\/\/(www\.)?twitch\.tv\/.+/,
        VK: /^https:\/\/vk\.com\/.+/,
        STEAM_CURATOR: /curator\/[\d]+/,
        STEAM_PUBLISHER: /(publisher|developer|franchise)\/.+/,
        STEAM_NEWS: /news(hub)?\/app\/[\d]+\/view\/[\d]+/,
        STEAM_APP: /app\/[\d]+/,
        STEAM_GROUP: /groups\/.+/,
        STEAM_ANNOUNCEMENT: /announcements\/detail\/[\d]+/,
        YOUTUBE: /youtube\.com/
      },
      SELECTORS: {
        MAIN_POST: {
          KEYLOL: '#postlist>div[id^="post_"]:first',
          DEFAULT: 'div.container'
        }
      }
    };
    static test() {
      const {host: host} = window.location;
      const link = $('.subforum_left_title_left_up a').eq(3).attr('href');
      const isMatch = host === 'keylol.com' && (!!link?.includes('319') || !!link?.includes('234'));
      debug('检查网站匹配', {
        host: host,
        link: link,
        isMatch: isMatch
      });
      return isMatch;
    }
    init() {
      debug('初始化 Keylol');
      return true;
    }
    after() {
      try {
        debug('开始处理页面链接');
        const mainPost = $(this.name === 'Keylol' ? Keylol.CONFIG.SELECTORS.MAIN_POST.KEYLOL : Keylol.CONFIG.SELECTORS.MAIN_POST.DEFAULT);
        const allLinks = mainPost.find('a');
        debug('找到所有链接', {
          count: allLinks.length
        });
        allLinks.each(((_, link) => {
          const $link = $(link);
          const href = $link.attr('href');
          if (!href) {
            return;
          }
          this.#classifyAndProcessLink($link, href);
        }));
        debug('开始处理抽奖链接');
        this.#processGiveawayLinks(mainPost);
        if (this.name === 'Keylol') {
          debug('开始处理 Keylol 特定链接');
          this.#processKeylolSpecificLinks(mainPost);
        }
        debug('设置 MutationObserver');
        this.#setupMutationObserver();
      } catch (error) {
        debug('处理页面链接失败', {
          error: error
        });
        throwError(error, 'keylol.after');
      }
    }
    #classifyAndProcessLink($link, href) {
      debug('分类处理链接', {
        href: href
      });
      const {LINK_PATTERNS: LINK_PATTERNS} = Keylol.CONFIG;
      switch (true) {
       case LINK_PATTERNS.DISCORD.test(href):
        debug('发现 Discord 链接');
        this.#addBtn($link[0], 'discord', 'serverLinks', href);
        break;

       case LINK_PATTERNS.REDDIT.test(href):
        debug('发现 Reddit 链接');
        this.#addBtn($link[0], 'reddit', 'redditLinks', href);
        break;

       case LINK_PATTERNS.TWITTER.test(href):
        if (LINK_PATTERNS.TWITTER_RETWEET.test(href)) {
          debug('发现 Twitter 转发链接');
          this.#addBtn($link[0], 'twitter', 'retweetLinks', href);
        } else {
          debug('发现 Twitter 用户链接');
          this.#addBtn($link[0], 'twitter', 'userLinks', href);
        }
        break;

       case LINK_PATTERNS.TWITCH.test(href):
        debug('发现 Twitch 链接');
        this.#addBtn($link[0], 'twitch', 'channelLinks', href);
        break;

       case LINK_PATTERNS.VK.test(href):
        debug('发现 VK 链接');
        this.#addBtn($link[0], 'vk', 'nameLinks', href);
        break;

       case href.includes('store.steampowered.com'):
        debug('发现 Steam 商店链接');
        this.#processSteamStoreLink($link[0], href);
        break;

       case href.includes('steamcommunity.com'):
        debug('发现 Steam 社区链接');
        this.#processSteamCommunityLink($link[0], href);
        break;

       case LINK_PATTERNS.YOUTUBE.test(href):
        debug('发现 YouTube 链接');
        this.#addBtn($link[0], 'youtube', 'channelLinks', href);
        this.#addBtn($link[0], 'youtube', 'likeLinks', href);
        break;
      }
    }
    #processSteamStoreLink(element, href) {
      debug('处理 Steam 商店链接', {
        href: href
      });
      const {LINK_PATTERNS: LINK_PATTERNS} = Keylol.CONFIG;
      if (LINK_PATTERNS.STEAM_CURATOR.test(href)) {
        debug('发现 Steam 鉴赏家链接');
        this.#addBtn(element, 'steam', 'curatorLinks', href);
      } else if (LINK_PATTERNS.STEAM_PUBLISHER.test(href)) {
        debug('发现 Steam 发行商链接');
        this.#addBtn(element, 'steam', 'curatorLikeLinks', href);
      } else if (LINK_PATTERNS.STEAM_NEWS.test(href)) {
        debug('发现 Steam 新闻链接');
        this.#addBtn(element, 'steam', 'announcementLinks', href);
      } else if (LINK_PATTERNS.STEAM_APP.test(href)) {
        debug('发现 Steam 应用链接');
        this.#addBtn(element, 'steam', 'followLinks', href);
        this.#addBtn(element, 'steam', 'wishlistLinks', href);
      }
    }
    #processSteamCommunityLink(element, href) {
      debug('处理 Steam 社区链接', {
        href: href
      });
      const {LINK_PATTERNS: LINK_PATTERNS} = Keylol.CONFIG;
      if (LINK_PATTERNS.STEAM_GROUP.test(href)) {
        debug('发现 Steam 组链接');
        this.#addBtn(element, 'steam', 'groupLinks', href);
      } else if (LINK_PATTERNS.STEAM_ANNOUNCEMENT.test(href)) {
        debug('发现 Steam 公告链接');
        this.#addBtn(element, 'steam', 'announcementLinks', href);
      }
    }
    #processGiveawayLinks(mainPost) {
      debug('开始处理抽奖链接');
      const giveawayLinks = mainPost.find('a[href*="giveaway.su/giveaway/view/"],' + 'a[href*="givee.club/"],' + 'a[href*="gleam.io/"],' + 'a[href*="www.indiedb.com/giveaways/"],' + 'a[href*="key-hub.eu/giveaway/"],' + 'a[href*="opquests.com/quests/"],' + 'a[href*="freeanywhere.net/game?n="],' + 'a[href*="itch.io/s/"]:visible');
      debug('找到抽奖链接', {
        count: giveawayLinks.length
      });
      giveawayLinks.each(((_, link) => {
        const href = $(link).attr('href');
        if (!href) {
          return;
        }
        debug('检查抽奖链接状态', {
          href: href
        });
        leftKeyChecker.classify(href).then((status => {
          if (!status) {
            return;
          }
          const statusClass = /^Active/.test(status) ? 'active' : 'not-active';
          const statusTitle = /^Active/.test(status) ? I18n('Active') : I18n(status);
          debug('更新抽奖链接状态', {
            href: href,
            status: status,
            statusClass: statusClass
          });
          $(`a[href="${href}"]`).after(`<font class="auto-task-giveaway-status ${statusClass}" title="${statusTitle}">${status}</font>`);
        })).catch((error => {
          debug('检查抽奖链接状态失败', {
            href: href,
            error: error
          });
          throwError(error, 'keylol.after -> leftKeyChecker');
        }));
      }));
    }
    #processKeylolSpecificLinks(mainPost) {
      debug('开始处理 Keylol 特定链接');
      const asfLinks = mainPost.find('a[href^="#asf"]:visible');
      debug('找到 ASF 链接', {
        count: asfLinks.length
      });
      asfLinks.each(((_, link) => {
        const href = $(link).attr('href');
        if (!href) {
          return;
        }
        debug('处理 ASF 链接', {
          href: href
        });
        const $link = $(`a[href="${href}"]`);
        $link.after('<span style="color: #ccc; margin: 0 -5px 0 5px"> | </span>');
        this.#addBtn($link.next()[0], 'steam', 'licenseLinks', `appid-${href.replace('#asf', '')}`);
      }));
      const steamDbLinks = mainPost.find('a[href*="steamdb.info/sub/"]:visible');
      debug('找到 SteamDB 链接', {
        count: steamDbLinks.length
      });
      steamDbLinks.each(((_, link) => {
        const href = $(link).attr('href');
        if (!href) {
          return;
        }
        const subid = href.match(/^https:\/\/steamdb\.info\/sub\/([\d]+)/)?.[1];
        if (!subid) {
          return;
        }
        debug('处理 SteamDB 链接', {
          href: href,
          subid: subid
        });
        this.#addBtn(link, 'steam', 'licenseLinks', `subid-${subid}`);
      }));
      const asfBlocks = mainPost.find('.blockcode:contains("addlicense"):visible');
      debug('找到 ASF 代码块', {
        count: asfBlocks.length
      });
      asfBlocks.each(((_, block) => {
        const appid = [ ...block.innerText.matchAll(/a(pp)?\/([\d]+)/g) ].map((matched => matched?.[2])).filter((id => id));
        if (appid.length > 0) {
          debug('处理 ASF 代码块 appid', {
            appid: appid
          });
          this.#addBtn($(block).children('em')[0], 'steam', 'licenseLinks', `appid-${appid.join(',')}`);
        }
        const subid = block.innerText.match(/[\d]+/g)?.filter((matched => !appid.includes(matched)));
        if (subid?.length) {
          debug('处理 ASF 代码块 subid', {
            subid: subid
          });
          this.#addBtn($(block).children('em')[0], 'steam', 'licenseLinks', `subid-${subid.join(',')}`);
        }
      }));
    }
    #setupMutationObserver() {
      debug('设置 MutationObserver');
      if ($('#threadindex').length > 0) {
        const [elementTargetNode] = $('#postlist').children('div[id^="post_"]');
        const elementObserver = new MutationObserver((() => {
          debug('检测到 DOM 变化,重新处理页面');
          elementObserver.disconnect();
          this.after();
        }));
        elementObserver.observe(elementTargetNode, {
          childList: true
        });
        debug('MutationObserver 设置完成');
      }
    }
    classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        this.socialTasks = JSON.parse(defaultTasks$4);
        this.undoneTasks = JSON.parse(defaultTasks$4);
        const selectedBtns = $('.auto-task-keylol[selected="selected"]:visible').get();
        debug('找到选中的按钮', {
          count: selectedBtns.length
        });
        for (const btn of selectedBtns) {
          const social = btn.getAttribute('data-social');
          const type = btn.getAttribute('data-type');
          const link = btn.getAttribute('data-link');
          debug('处理任务按钮', {
            social: social,
            type: type,
            link: link
          });
          if (!(social && type && link)) {
            debug('跳过无效任务按钮');
            continue;
          }
          if (!(social in this.undoneTasks)) {
            debug('跳过未知社交平台', {
              social: social
            });
            continue;
          }
          if (action === 'do' && type in this.undoneTasks[social]) {
            debug('添加到未完成任务', {
              social: social,
              type: type,
              link: link
            });
            this.undoneTasks[social][type].push(link);
          }
          if (action === 'undo' && type in this.socialTasks[social]) {
            debug('添加到社交任务', {
              social: social,
              type: type,
              link: link
            });
            this.socialTasks[social][type].push(link);
          }
        }
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        debug('任务分类完成', {
          undoneTasks: this.undoneTasks,
          socialTasks: this.socialTasks
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Keylol.classifyTask');
        return false;
      }
    }
    selectAll() {
      try {
        debug('选择所有可见任务');
        const tasks = $('.auto-task-keylol:visible');
        tasks.attr('selected', 'selected');
        debug('选择完成', {
          count: tasks.length
        });
      } catch (error) {
        debug('选择所有任务失败', {
          error: error
        });
        throwError(error, 'Keylol.selectAll');
      }
    }
    selectNone() {
      try {
        debug('取消选择所有可见任务');
        const tasks = $('.auto-task-keylol:visible');
        tasks.removeAttr('selected');
        debug('取消选择完成', {
          count: tasks.length
        });
      } catch (error) {
        debug('取消选择所有任务失败', {
          error: error
        });
        throwError(error, 'Keylol.selectNone');
      }
    }
    invertSelect() {
      try {
        debug('反转选择所有可见任务');
        const tasks = $('.auto-task-keylol:visible');
        tasks.each(((_, element) => {
          const $element = $(element);
          if ($element.attr('selected')) {
            $element.removeAttr('selected');
          } else {
            $element.attr('selected', 'selected');
          }
        }));
        debug('反转选择完成', {
          count: tasks.length
        });
      } catch (error) {
        debug('反转选择任务失败', {
          error: error
        });
        throwError(error, 'Keylol.invertSelect');
      }
    }
    #addBtn(before, social, linkType, link) {
      try {
        debug('添加任务按钮', {
          social: social,
          linkType: linkType,
          link: link
        });
        if (!before || !social || !linkType || !link) {
          debug('跳过无效按钮参数');
          return;
        }
        const button = $('<a>', {
          href: 'javascript:void(0);',
          class: 'auto-task-keylol',
          target: '_self',
          'data-social': social,
          'data-type': linkType,
          'data-link': link,
          text: linkType.replace('Links', ''),
          onclick: 'this.getAttribute("selected") ? this.removeAttribute("selected") : this.setAttribute("selected", "selected")'
        });
        $(before).after(button);
        debug('按钮添加成功');
      } catch (error) {
        debug('添加按钮失败', {
          error: error,
          social: social,
          linkType: linkType
        });
        throwError(error, `keylol.addBtn: ${social}/${linkType}`);
      }
    }
  }
  const defaultTasks$3 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      followLinks: [],
      curatorLikeLinks: [],
      playTimeLinks: []
    },
    twitter: {
      userLinks: [],
      retweetLinks: []
    },
    discord: {
      serverLinks: []
    }
  };
  class Opquests extends Website {
    name='Opquests';
    undoneTasks={
      ...defaultTasks$3
    };
    buttons=[ 'doTask', 'verifyTask', 'getKey' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'opquests.com';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('检查登录失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        const opquestsVerifyTasks = GM_getValue('opquestsVerifyTasks') || [];
        debug('获取待验证任务', {
          count: opquestsVerifyTasks.length
        });
        if (opquestsVerifyTasks.length > 0) {
          const taskId = opquestsVerifyTasks.pop();
          debug('处理任务', {
            taskId: taskId
          });
          GM_setValue('opquestsVerifyTasks', opquestsVerifyTasks);
          const [verifyBtn] = $(`#task_id[value="${taskId}"]`).parent().find('button[type="button"],button[type="submit"]').has('i.fa-check');
          if (verifyBtn) {
            debug('点击验证按钮');
            verifyBtn.click();
            return;
          }
          debug('未找到验证按钮,继续处理下一个任务');
          this.after();
          return;
        }
        if (GM_getValue('opquestsVerifyTasks')) {
          debug('清除验证任务缓存');
          GM_deleteValue('opquestsVerifyTasks');
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Opquests.after');
      }
    }
    init() {
      try {
        debug('开始初始化');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if ($('a[href*="/auth/redirect"]').length > 0) {
          debug('需要登录');
          window.open('/auth/redirect', '_self');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        if (!this.#getGiveawayId()) {
          debug('获取抽奖ID失败');
          return false;
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Opquests.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        if (action === 'undo') {
          debug('不支持撤销操作');
          echoLog({
            text: I18n('cannotUndo')
          });
          return false;
        }
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        const tasks = $('.w-full:contains("Validate") .items-center');
        debug('找到任务', {
          count: tasks.length
        });
        for (const task of tasks) {
          const link = $(task).find('a:contains("Open")').attr('href');
          if (!link) {
            debug('跳过无链接任务');
            continue;
          }
          const taskDes = $(task).find('div').eq(1).text().trim();
          debug('处理任务', {
            taskDes: taskDes,
            link: link
          });
          if (/steamcommunity\.com\/groups\//.test(link)) {
            debug('添加 Steam 组任务');
            this.undoneTasks.steam.groupLinks.push(link);
            continue;
          }
          if (/store\.steampowered\.com\/app\//.test(link)) {
            if (/wishlist/gim.test(taskDes)) {
              debug('添加 Steam 愿望单任务');
              this.undoneTasks.steam.wishlistLinks.push(link);
            } else if (/follow/gim.test(taskDes)) {
              debug('添加 Steam 关注任务');
              this.undoneTasks.steam.followLinks.push(link);
            } else if (/play/gim.test(taskDes)) {
              const time = parseInt(taskDes.replace(/\s/gim, '').match(/(\d+)hours/im)?.[1] || '0', 10) * 60;
              debug('添加 Steam 游戏时长任务', {
                time: time
              });
              this.undoneTasks.steam.playTimeLinks.push(`${time}-${link}`);
            }
            continue;
          }
          if (/store\.steampowered\.com\/(publisher|developer|curator)\//.test(link) && /follow/gim.test(taskDes)) {
            debug('添加 Steam 鉴赏家关注任务');
            this.undoneTasks.steam.curatorLikeLinks.push(link);
            continue;
          }
          if (link.includes('//x.com/')) {
            if (/follow/gim.test(taskDes)) {
              debug('添加 Twitter 关注任务');
              this.undoneTasks.twitter.userLinks.push(link);
              continue;
            }
            if (link.includes('status') && /Repost/gim.test(taskDes)) {
              debug('添加 Twitter 转发任务');
              this.undoneTasks.twitter.retweetLinks.push(link);
              continue;
            }
          }
          if (link.includes('//discord.com/')) {
            if (/join/gim.test(taskDes)) {
              debug('添加 Discord 加入任务');
              this.undoneTasks.discord.serverLinks.push(link);
              continue;
            }
          }
          if (/clash\.gg/.test(link)) {
            debug('跳过不支持的 Clash.gg 任务');
            echoLog({}).warning(`${I18n('unSupporttedTaskType')}: ${taskDes}(${link})`);
            continue;
          }
          debug('未知任务类型');
          echoLog({}).warning(`${I18n('unKnownTaskType')}: ${taskDes}(${link})`);
        }
        debug('任务分类完成');
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        if (window.DEBUG) {
          console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
        }
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Opquests.classifyTask');
        return false;
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        if (!this.initialized) {
          debug('未初始化,执行初始化');
          this.init();
        }
        const tasks = $.makeArray($('.items-center').has('input[name="task_id"]')).map((ele => $(ele).find('input[name="task_id"]').val()));
        debug('获取待验证任务', {
          count: tasks.length
        });
        GM_setValue('opquestsVerifyTasks', tasks);
        await this.#confirm();
        debug('执行后续操作');
        this.after();
        return true;
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Opquests.verifyTask');
        return false;
      }
    }
    async #confirm() {
      try {
        debug('开始确认任务');
        const logStatus = echoLog({
          html: `<li>${I18n('confirmingTask')}...<font></font></li>`
        });
        debug('发送确认请求');
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://opquests.com/quests/${this.giveawayId}?confirm=1`,
          method: 'GET',
          nochche: true,
          headers: {
            origin: 'https://opquests.com',
            referer: `https://opquests.com/warning?id=${this.giveawayId}`
          }
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200) {
          debug('响应错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('确认成功');
        logStatus.success();
        return true;
      } catch (error) {
        debug('确认任务失败', {
          error: error
        });
        throwError(error, 'Opquests.confirm');
        return false;
      }
    }
    async getKey(isButton) {
      try {
        if ($('[name="task_id"]').length > 0) {
          debug('有任务未完成,不获取密钥');
          echoLog({}).warning(I18n('taskNotFinished'));
          return false;
        }
        debug('开始获取密钥', {
          isButton: isButton
        });
        const logStatus = echoLog({
          text: I18n('gettingKey')
        });
        debug('发送获取密钥请求');
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://opquests.com/keys',
          method: 'GET'
        });
        if (result !== 'Success') {
          debug('请求失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (!data?.responseText) {
          debug('响应无效', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        const questTitle = $('h1.font-bold').text().trim().replace(' Quest', '');
        const key = $(data.responseText).find(`div.items-center:contains("${questTitle}")`).find('div.font-bold').next().text();
        debug('查找密钥', {
          questTitle: questTitle,
          hasKey: !!key
        });
        if (!key) {
          debug('未找到密钥');
          logStatus.error('Error: Key was not found');
          if (isButton) {
            debug('重定向到密钥页面');
            window.open('https://opquests.com/keys', '_self');
          }
          return false;
        }
        debug('获取密钥成功');
        logStatus.success();
        echoLog({}).success(key);
        return true;
      } catch (error) {
        debug('获取密钥失败', {
          error: error
        });
        throwError(error, 'Opquests.getKey');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('开始获取抽奖ID');
        const giveawayId = window.location.href.match(/quests\/([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({}).error(I18n('getFailed', 'GiveawayId'));
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'Opquests.getGiveawayId');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        if ($('a[href*="/auth/redirect"]').length > 0) {
          debug('未登录,重定向到登录页面');
          window.open('/auth/redirect', '_self');
        }
        debug('登录检查完成');
        return true;
      } catch (error) {
        debug('检查登录失败', {
          error: error
        });
        throwError(error, 'Opquests.checkLogin');
        return false;
      }
    }
  }
  const defaultTasksTemplate$2 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      followLinks: [],
      curatorLinks: [],
      curatorLikeLinks: [],
      playTimeLinks: []
    },
    twitter: {
      userLinks: [],
      retweetLinks: []
    },
    twitch: {
      channelLinks: []
    },
    discord: {
      serverLinks: []
    },
    youtube: {
      channelLinks: []
    },
    extra: {
      gleam: []
    }
  };
  const defaultTasks$2 = JSON.stringify(defaultTasksTemplate$2);
  class Gleam extends Website {
    name='Gleam';
    undoneTasks=JSON.parse(defaultTasks$2);
    socialTasks=JSON.parse(defaultTasks$2);
    buttons=[ 'doTask', 'undoTask', 'verifyTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'gleam.io';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    before() {
      try {
        debug('重写全局对话框函数');
        unsafeWindow.confirm = () => {};
        unsafeWindow.alert = () => {};
        unsafeWindow.prompt = () => {};
      } catch (error) {
        debug('重写全局对话框函数失败', {
          error: error
        });
        throwError(error, 'Gleam.before');
      }
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (window.location.search.includes('8b07d23f4bfa65f9')) {
          debug('检测到特殊查询参数,开始处理任务');
          const checkComplete = setInterval((() => {
            if ($('.entry-content .entry-method i.fa-check').length > 0) {
              debug('任务已完成,关闭窗口');
              clearInterval(checkComplete);
              window.close();
            }
          }));
          await this.verifyTask();
          echoLog({}).warning(I18n('gleamTaskNotice'));
        } else if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Gleam.after');
      }
    }
    init() {
      try {
        debug('初始化 Gleam');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if (!this.#getGiveawayId()) {
          debug('获取抽奖ID失败');
          return false;
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Gleam.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`gleamTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks$2);
        }
        const tasks = $('.entry-content .entry-method');
        debug('找到任务元素', {
          count: tasks.length
        });
        for (const task of tasks) {
          const $task = $(task);
          if (action === 'do' && $task.find('i.fa-question').length === 0) {
            debug('跳过已完成的任务');
            continue;
          }
          const socialIcon = $task.find('.icon-wrapper i');
          const taskInfo = $task.find('.user-links');
          const taskText = taskInfo.text().trim();
          const expandInfo = $task.find('.expandable');
          const aElements = expandInfo.find('a.btn');
          debug('处理任务', {
            taskText: taskText
          });
          if (aElements.length > 0) {
            debug('处理可点击元素', {
              count: aElements.length
            });
            for (const element of aElements) {
              const $element = $(element);
              const href = $element.attr('href');
              $element.removeAttr('href')[0].click();
              $element.attr('href', href);
            }
          }
          if (socialIcon.hasClass('fa-twitter') || socialIcon.hasClass('fa-x-twitter')) {
            const link = $task.find('a[href^="https://twitter.com/"],a[href^="https://x.com/"]').attr('href');
            if (!link) {
              continue;
            }
            if (/follow/gi.test(taskText)) {
              if (action === 'undo') {
                this.socialTasks.twitter.userLinks.push(link);
              }
              if (action === 'do') {
                this.undoneTasks.twitter.userLinks.push(link);
              }
              continue;
            }
            if (/retweet/gim.test(taskText)) {
              if (action === 'undo') {
                this.socialTasks.twitter.retweetLinks.push(link);
              }
              if (action === 'do') {
                this.undoneTasks.twitter.retweetLinks.push(link);
              }
              continue;
            }
          }
          if (socialIcon.hasClass('fa-twitch') && /follow/gim.test(taskText)) {
            const link = $task.find('a[href^="https://twitch.tv/"]').attr('href');
            if (!link) {
              continue;
            }
            if (action === 'undo') {
              this.socialTasks.twitch.channelLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.twitch.channelLinks.push(link);
            }
            continue;
          }
          if (socialIcon.hasClass('fa-discord') && /join/gim.test(taskText)) {
            let link = $task.find('a[href^="https://discord.com/invite/"]').attr('href');
            if (!link) {
              const ggLink = $task.find('a[href^="https://discord.gg/"]').attr('href')?.match(/discord\.gg\/([^/]+)/)?.[1];
              if (!ggLink) {
                continue;
              }
              link = `https://discord.com/invite/${ggLink}`;
            }
            if (action === 'undo') {
              this.socialTasks.discord.serverLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.discord.serverLinks.push(link);
            }
            continue;
          }
          if (socialIcon.hasClass('fa-external-link-square-alt')) {
            continue;
          }
          if (socialIcon.hasClass('fa-youtube') && /subscribe/gim.test(taskText)) {
            const link = $task.find('a[href^="https://www.youtube.com/channel/"]').attr('href');
            if (!link) {
              continue;
            }
            if (action === 'undo') {
              this.socialTasks.youtube.channelLinks.push(link);
            }
            if (action === 'do') {
              this.undoneTasks.youtube.channelLinks.push(link);
            }
            continue;
          }
          if (socialIcon.attr('class')?.includes('steam')) {
            if (/join.*group/gi.test(taskText)) {
              const link = $task.find('a[href^="https://steamcommunity.com/groups/"]').attr('href');
              if (!link) {
                continue;
              }
              if (action === 'undo') {
                this.socialTasks.steam.groupLinks.push(link);
              }
              if (action === 'do') {
                this.undoneTasks.steam.groupLinks.push(link);
              }
              continue;
            }
            if (/follow.*curator/gi.test(taskText)) {
              const link = $task.find('a[href^="https://store.steampowered.com/curator/"]').attr('href');
              if (!link) {
                continue;
              }
              if (action === 'undo') {
                this.socialTasks.steam.curatorLinks.push(link);
              }
              if (action === 'do') {
                this.undoneTasks.steam.curatorLinks.push(link);
              }
              continue;
            }
            if (/play.*hours/gi.test(taskText)) {
              const link = $task.find('a[href^="https://steamcommunity.com/app/"],a[href^="https://store.steampowered.com/app/"]').attr('href');
              if (!link) {
                continue;
              }
              if (action === 'undo') {
                this.socialTasks.steam.playTimeLinks.push(link);
              }
              if (action === 'do') {
                this.undoneTasks.steam.playTimeLinks.push(link);
              }
              continue;
            }
            if (/Sign up/gi.test(taskText)) {
              continue;
            }
          }
          if (socialIcon.hasClass('fa-bullhorn') && /Complete|Increase/gi.test(taskText)) {
            if (action !== 'do') {
              continue;
            }
            const gleamLink = await this.#getGleamLink(taskText);
            if (!gleamLink) {
              continue;
            }
            this.undoneTasks.extra.gleam.push(gleamLink);
            continue;
          }
          if (socialIcon.hasClass('fa-question') || socialIcon.hasClass('fa-reddit') || socialIcon.hasClass('fa-instagram') || socialIcon.hasClass('fa-facebook-f') || socialIcon.hasClass('fa-telegram-plane') || socialIcon.hasClass('fa-telegram') || socialIcon.hasClass('fa-vk') || socialIcon.hasClass('fa-envelope') || socialIcon.hasClass('fa-gift') || socialIcon.hasClass('fa-square-up-right') || socialIcon.hasClass('fa-gamepad-modern') || socialIcon.hasClass('fa-dollar-sign') || socialIcon.hasClass('fa-tiktok') || socialIcon.hasClass('fa-gamepad-alt') || socialIcon.hasClass('fa-bag-shopping') || socialIcon.hasClass('fa-swords') || socialIcon.hasClass('fa-shield') && taskText.includes('one of our giveaways') || socialIcon.hasClass('fa-shield') && taskText.includes('Check out') || socialIcon.hasClass('fa-shield') && taskText.includes('vloot.io')) {
            continue;
          }
          echoLog({}).warning(`${I18n('unKnownTaskType')}: ${taskText}`);
        }
        debug('任务分类完成');
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        debug('保存任务信息');
        GM_setValue(`gleamTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Gleam.classifyTask');
        return false;
      }
    }
    async extraDoTask({gleam: gleam}) {
      try {
        debug('开始执行额外任务', {
          count: gleam.length
        });
        const pro = [];
        for (const link of gleam) {
          pro.push(this.#doGleamTask(link));
        }
        return Promise.all(pro).then((() => true));
      } catch (error) {
        debug('执行额外任务失败', {
          error: error
        });
        throwError(error, 'Gleam.extraDoTask');
        return false;
      }
    }
    async #checkCampaign() {
      try {
        debug('检测人机验证');
        let logStatus;
        if ($('[campaign-key="campaign.key"]').length > 0) {
          logStatus = echoLog({
            text: I18n('campaign')
          });
          debug('检测到人机验证');
          await delay(3e3);
          logStatus.warning(I18n('retry'));
          await this.#checkCampaign();
          return true;
        }
        logStatus?.success();
        return false;
      } catch (error) {
        debug('检测人机验证失败', {
          error: error
        });
        throwError(error, 'Gleam.checkCampaign');
        return false;
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        echoLog({
          text: `${I18n('verifyingTask')}...`
        });
        const tasks = $('.entry-content .entry-method');
        unsafeWindow._OxA = '_OxA';
        for (const task of tasks) {
          const campaign = await this.#checkCampaign();
          if (campaign) {
            return this.verifyTask();
          }
          const $task = $(task);
          if ($task.find('i.fa-check').length > 0) {
            debug('跳过已完成的任务');
            continue;
          }
          debug('处理任务验证');
          const taskInfo = $task.find('.user-links');
          taskInfo[0].click();
          const aElements = $task.find('.expandable').find('a.btn');
          if (aElements.length > 0) {
            debug('处理可点击元素', {
              count: aElements.length
            });
            for (const element of aElements) {
              const $element = $(element);
              const href = $element.attr('href');
              $element.removeAttr('href')[0].click();
              $element.attr('href', href);
            }
          }
          debug('处理计时器');
          unsafeWindow.$hookTimer?.setSpeed(1e3);
          const visitBtn = $task.find('.expandable').find('span:contains(more seconds),button:contains(more seconds)').filter(':visible');
          if (visitBtn.length > 0 && unsafeWindow.$hookTimer) {
            debug('处理访问按钮');
            const newTab = GM_openInTab('', {
              active: true
            });
            await delay(1e3);
            newTab?.close();
            window.focus();
          }
          await delay(3e3);
          unsafeWindow.$hookTimer?.setSpeed(1);
          const expandInfo = $task.find('.expandable');
          const [input] = expandInfo.find('input');
          if (input) {
            debug('处理输入框');
            const evt = new Event('input', {
              bubbles: true,
              cancelable: true,
              composed: true
            });
            const valuelimit = [ ...expandInfo.text().matchAll(/"(.+?)"/g) ].at(-1)?.[1];
            input.value = valuelimit || 'vloot';
            input.dispatchEvent(evt);
            await delay(1e3);
          }
          await this.#checkSync();
          const continueBtn = $task.find('.expandable').find('span:contains(Continue),button:contains(Continue),a:contains(Continue)');
          for (const button of continueBtn) {
            debug('点击继续按钮');
            button.click();
            await delay(500);
            await this.#checkSync();
          }
        }
        debug('任务验证完成');
        echoLog({
          text: I18n('verifiedGleamTasks')
        });
        return true;
      } catch (error) {
        debug('任务验证失败', {
          error: error
        });
        throwError(error, 'Gleam.verifyTask');
        return false;
      }
    }
    async #checkSync() {
      try {
        debug('开始检查同步状态');
        return await new Promise((resolve => {
          const checker = setInterval((() => {
            if ($('.entry-content .entry-method i.fa-sync').length === 0) {
              debug('同步完成');
              clearInterval(checker);
              resolve(true);
            }
          }), 500);
        }));
      } catch (error) {
        debug('检查同步状态失败', {
          error: error
        });
        throwError(error, 'Gleam.checkSync');
        return false;
      }
    }
    async #doGleamTask(link) {
      try {
        debug('执行 Gleam 任务', {
          link: link
        });
        const logStatus = echoLog({
          text: I18n('doingGleamTask')
        });
        return await new Promise((resolve => {
          GM_openInTab(`${link}?8b07d23f4bfa65f9`, {
            active: true,
            insert: true,
            setParent: true
          }).onclose = () => {
            debug('任务完成');
            logStatus.success();
            resolve(true);
          };
        }));
      } catch (error) {
        debug('执行 Gleam 任务失败', {
          error: error
        });
        throwError(error, 'Gleam.doGleamTask');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('获取抽奖ID');
        const giveawayId = window.location.pathname;
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({
          text: I18n('getFailed', 'GiveawayId')
        });
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'Gleam.getGiveawayId');
        return false;
      }
    }
    async #getGleamLink(title) {
      try {
        debug('获取 Gleam 链接', {
          title: title
        });
        const logStatus = echoLog({
          text: I18n('gettingGleamLink')
        });
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: 'https://www.vloot.io/api/v1/giveaways',
          method: 'GET',
          responseType: 'json'
        });
        if (result === 'Success') {
          if (data?.status === 200 && data?.response?.Success === true && data?.response?.Data) {
            const {link: link} = data.response.Data.find((giveaway => title.replace(/[\s]/g, '').toLowerCase().includes(giveaway.title.replace(/[\s]/g, '').toLowerCase()))) || {};
            if (link) {
              debug('获取链接成功', {
                link: link
              });
              logStatus.success();
              return link;
            }
            debug('获取链接失败');
            logStatus.error(`Error:${I18n('getLinkFailed')}`);
            return false;
          }
          debug('API响应错误', {
            status: data?.status,
            statusText: data?.statusText
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('请求失败', {
          result: result,
          status: status,
          statusText: statusText
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return false;
      } catch (error) {
        debug('获取 Gleam 链接失败', {
          error: error
        });
        throwError(error, 'Gleam.getGleamLink');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const campaignString = $('div.popup-blocks-container').attr('ng-init')?.match(/initCampaign\(([\w\W]+?)\)$/)?.[1];
        if (!campaignString) {
          debug('未找到活动配置信息');
          return false;
        }
        const {campaign: campaign, incentive: incentive} = JSON.parse(campaignString);
        const controllerString = $('div.campaign.reward').attr('ng-init')?.match(/initContestant\(([\w\W]+?)\);/)?.[1];
        let ownedKey = false;
        if (controllerString) {
          if (JSON.parse(controllerString).contestant?.claims?.incentives?.[incentive.id]?.length) {
            debug('用户已拥有密钥');
            ownedKey = true;
          }
        }
        const isGiveawayInvalid = campaign.banned || campaign.finished && !ownedKey || campaign.paused || (new Date).getTime() < campaign.starts_at * 1e3;
        debug('检查抽奖状态', {
          banned: campaign.banned,
          finished: campaign.finished,
          ownedKey: ownedKey,
          paused: campaign.paused,
          notStarted: (new Date).getTime() < campaign.starts_at * 1e3
        });
        if (!isGiveawayInvalid) {
          return true;
        }
        debug('抽奖无效,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('giveawayNotWork'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'Gleam.checkLeftKey');
        return false;
      }
    }
  }
  const defaultOptions = {
    username: '',
    email: ''
  };
  class SweepWidget extends Website {
    name='SweepWidget';
    options={
      ...defaultOptions,
      ...GM_getValue('SweepWidgetOptions')
    };
    buttons=[ 'doTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = /^sweepwidget\.com$/.test(host);
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return /^https?:\/\/sweepwidget\.com\/view\/[\d]+/.test(window.location.href);
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('检查登录失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'SweepWidget.after');
      }
    }
    init() {
      try {
        debug('开始初始化');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if (!this.#checkLogin()) {
          debug('需要登录');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        if (!this.#getGiveawayId()) {
          debug('获取抽奖ID失败');
          return false;
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'SweepWidget.init');
        return false;
      }
    }
    classifyTask() {
      debug('任务分类完成');
      return true;
    }
    async doTask() {
      try {
        debug('开始执行任务');
        if ($('#unlock_rewards_main_wrapper').length === 0) {
          debug('未显示奖励界面,尝试登录');
          if ($('input[name="sw__login_name"]:visible').length > 0) {
            debug('填写用户名', {
              username: this.options.username
            });
            $('input[name="sw__login_name"]').val(this.options.username);
          }
          if ($('input[name="sw__login_email"]:visible').length > 0) {
            debug('填写邮箱', {
              email: this.options.email
            });
            $('input[name="sw__login_email"]').val(this.options.email);
          }
          if ($('#sw_login_button:visible').length > 0) {
            debug('点击登录按钮');
            $('#sw_login_button')[0].click();
          }
          const isEntered = await this.#checkEnter();
          if (!isEntered) {
            debug('进入抽奖失败');
            return false;
          }
        }
        const logStatus = echoLog({
          text: I18n('SweepWidgetNotice')
        });
        const tasks = $('#sw_inner_entry_methods_l2_wrapper>div.sw_entry');
        debug('找到任务列表', {
          count: tasks.length
        });
        for (const task of tasks) {
          const $task = $(task);
          if ($task.find('i.fa-check:visible').length > 0) {
            debug('跳过已完成的任务');
            continue;
          }
          const title = $task.find('.sw_text_inner');
          const aElement = $task.find('a.sw_link');
          const link = aElement.attr('href');
          if (!link) {
            debug('跳过无效链接的任务');
            continue;
          }
          debug('处理任务', {
            title: title.text(),
            link: link
          });
          title[0].click();
          aElement.attr('href', '#a').attr('target', '_self');
          aElement[0]?.click();
          await delay(300);
          aElement.attr('href', link).attr('target', '_blank');
          debug('填写测试文本');
          $task.find('input[type="text"]').val('test');
          const verifyBtn = $task.find('input.sw_verify');
          if (verifyBtn.prop('disabled') === true) {
            debug('验证按钮被禁用,尝试重新激活');
            title[0].click();
            await delay(300);
            title[0].click();
            await delay(300);
          }
          debug('点击验证按钮');
          $task.find('input.sw_verify').removeAttr('disabled')[0]?.click();
          await this.#checkFinish($task);
          const randomDelay = parseInt(`${Math.random() * (3e3 - 1e3 + 1) + 1e3}`, 10);
          debug('等待随机延迟', {
            delay: randomDelay
          });
          await delay(randomDelay);
        }
        debug('所有任务执行完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('执行任务失败', {
          error: error
        });
        throwError(error, 'SweepWidget.doTask');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if ($('#twitter_login_button').length > 0) {
          debug('点击 Twitter 登录按钮');
          $('#twitter_login_button')[0].click();
        }
        debug('登录检查完成');
        return true;
      } catch (error) {
        debug('检查登录失败', {
          error: error
        });
        throwError(error, 'SweepWidget.checkLogin');
        return false;
      }
    }
    #getGiveawayId() {
      try {
        debug('开始获取抽奖ID');
        const giveawayId = window.location.href.match(/\/view\/([\d]+)/)?.[1];
        if (!giveawayId) {
          debug('获取抽奖ID失败');
          echoLog({
            text: I18n('getFailed', 'GiveawayId')
          });
          return false;
        }
        this.giveawayId = giveawayId;
        debug('获取抽奖ID成功', {
          giveawayId: giveawayId
        });
        return true;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'SweepWidget.getGiveawayId');
        return false;
      }
    }
    async #checkEnter() {
      try {
        debug('开始检查是否进入抽奖');
        return new Promise((resolve => {
          const checker = setInterval((() => {
            if ($('#unlock_rewards_main_wrapper').length === 0) {
              debug('等待进入抽奖...');
              return;
            }
            debug('成功进入抽奖');
            clearInterval(checker);
            resolve(true);
          }), 500);
        }));
      } catch (error) {
        debug('检查进入抽奖失败', {
          error: error
        });
        throwError(error, 'SweepWidget.checkEnter');
        return false;
      }
    }
    async #checkFinish($task) {
      try {
        debug('开始检查任务完成状态');
        return new Promise((resolve => {
          const checker = setInterval((() => {
            const isCompleted = $task.find('i.fa-check:visible').length > 0 || $task.find('.sw_entry_input:visible').length === 0;
            if (!isCompleted) {
              debug('等待任务完成...');
              return;
            }
            debug('任务完成');
            clearInterval(checker);
            resolve(true);
          }), 500);
        }));
      } catch (error) {
        debug('检查任务完成状态失败', {
          error: error
        });
        throwError(error, 'SweepWidget.checkFinish');
        return false;
      }
    }
  }
  const processFormData = formData => {
    debug('开始处理表单数据', {
      formDataLength: formData.length
    });
    const data = {};
    formData.forEach((value => {
      data[value.name] = value.value;
    }));
    debug('表单数据处理完成', {
      processedData: data
    });
    return data;
  };
  const updateGlobalOption = (element, data) => {
    const name = $(element).attr('name');
    if (!name) {
      debug('元素缺少name属性', {
        element: element
      });
      return;
    }
    debug('开始更新全局选项', {
      name: name
    });
    const keys = name.split('.');
    const value = data[name];
    const processedValue = value ? value === 'on' ? true : value : value ?? false;
    debug('处理选项值', {
      keys: keys,
      originalValue: value,
      processedValue: processedValue
    });
    if (keys.length === 3) {
      globalOptions[keys[0]][keys[1]][keys[2]] = processedValue;
      debug('更新三级选项', {
        path: keys.join('.'),
        value: processedValue
      });
    } else if (keys.length === 2) {
      globalOptions[keys[0]][keys[1]] = processedValue;
      debug('更新二级选项', {
        path: keys.join('.'),
        value: processedValue
      });
    }
  };
  const generateFormRow = (type, option, data, isFirstOption, totalOptions) => {
    debug('开始生成表单行', {
      type: type,
      option: option,
      isFirstOption: isFirstOption,
      totalOptions: totalOptions
    });
    const backgroundColor = `${stringToColour(type)}44`;
    const headerBackgroundColor = `${stringToColour(type)}66`;
    if ([ 'other', 'position', 'hotKey', 'ASF' ].includes(type)) {
      const header = isFirstOption ? `<th rowspan="${totalOptions}" style="background-color: ${headerBackgroundColor}">${I18n(type)}</th>` : '';
      if (typeof data === 'boolean') {
        debug('生成布尔类型选项行', {
          type: type,
          option: option,
          value: data
        });
        return `\n        <tr style="background-color: ${backgroundColor}">\n          ${header}\n          <td>${I18n(option)}</td>\n          <td>\n            <label>\n              <input type="checkbox" name="${type}.${option}"${data ? ' checked="checked"' : ''}/>\n              <span><i></i></span>\n            </label>\n          </td>\n        </tr>`;
      }
      debug('生成文本类型选项行', {
        type: type,
        option: option,
        value: data
      });
      return `\n      <tr style="background-color: ${backgroundColor}">\n        ${header}\n        <td>${I18n(option)}</td>\n        <td>\n          <input class="editOption" type="text" name="${type}.${option}" value="${data}"/>\n        </td>\n      </tr>`;
    }
    debug('生成社交媒体选项行', {
      type: type,
      option: option,
      dataKeys: Object.keys(data)
    });
    return Object.entries(data).map((([socialType, value]) => `\n    <tr style="background-color: ${stringToColour(option)}66">\n      ${isFirstOption ? `<th rowspan="${totalOptions}" style="background-color: ${headerBackgroundColor}">${I18n(type)}</th>` : ''}\n      <td>${option}.${I18n(socialType)}</td>\n      <td>\n        <label>\n          <input type="checkbox" name="${type}.${option}.${socialType}"${value ? ' checked="checked"' : ''}/>\n          <span><i></i></span>\n        </label>\n      </td>\n    </tr>`)).join('');
  };
  const generateGlobalOptionsForm = () => {
    debug('开始生成全局选项表单');
    const formRows = Object.entries(globalOptions).map((([type, data1]) => {
      debug('处理选项类型', {
        type: type,
        optionsCount: Object.keys(data1).length
      });
      return Object.entries(data1).map((([option, data2], index) => {
        const totalOptions = [ 'other', 'position', 'hotKey', 'ASF' ].includes(type) ? Object.keys(data1).length : Object.values(data1).reduce(((acc, cur) => acc + Object.keys(cur).length), 0);
        return generateFormRow(type, option, data2, index === 0, totalOptions);
      })).join('');
    })).join('');
    debug('表单生成完成');
    return `\n    <form id="globalOptionsForm" class="auto-task-form">\n      <table class="auto-task-table">\n        <thead>\n          <tr>\n            <td>${I18n('type')}</td>\n            <td>${I18n('option')}</td>\n            <td>${I18n('value')}</td>\n          </tr>\n        </thead>\n        <tbody>\n          ${formRows}\n        </tbody>\n      </table>\n    </form>`;
  };
  const saveData = () => {
    try {
      debug('开始保存全局选项数据');
      const formData = $('#globalOptionsForm').serializeArray();
      debug('获取表单数据', {
        formDataLength: formData.length
      });
      const data = processFormData(formData);
      debug('开始更新全局选项');
      $.makeArray($('#globalOptionsForm input')).forEach((element => {
        updateGlobalOption(element, data);
      }));
      GM_setValue('globalOptions', globalOptions);
      debug('全局选项保存完成');
      Swal.fire({
        title: I18n('changeGlobalOptionsSuccess'),
        icon: 'success'
      });
    } catch (error) {
      debug('保存全局选项时发生错误', {
        error: error
      });
      throwError(error, 'saveData');
    }
  };
  const changeGlobalOptions = showType => {
    try {
      debug('开始显示全局选项配置界面', {
        showType: showType
      });
      const formHtml = generateGlobalOptionsForm();
      if (showType === 'swal') {
        debug('使用弹窗显示选项');
        Swal.fire({
          title: I18n('globalOptions'),
          html: formHtml,
          showConfirmButton: true,
          confirmButtonText: I18n('save'),
          showCancelButton: true,
          cancelButtonText: I18n('close')
        }).then((({isConfirmed: isConfirmed}) => {
          if (isConfirmed) {
            debug('用户确认保存选项');
            saveData();
          } else {
            debug('用户取消保存选项');
          }
        }));
      } else {
        debug('使用页面内显示选项');
        $('body').append(`<h2>${I18n('globalOptions')}</h2>${formHtml}`);
      }
    } catch (error) {
      debug('显示全局选项配置界面时发生错误', {
        error: error
      });
      throwError(error, 'changeGlobalOptions');
    }
  };
  const defaultWhiteList = {
    discord: {
      servers: []
    },
    instagram: {
      users: []
    },
    twitch: {
      channels: []
    },
    twitter: {
      users: [],
      retweets: [],
      likes: []
    },
    vk: {
      names: []
    },
    youtube: {
      channels: [],
      likes: []
    },
    reddit: {
      reddits: []
    },
    steam: {
      groups: [],
      officialGroups: [],
      wishlists: [],
      follows: [],
      forums: [],
      workshops: [],
      curators: [],
      workshopVotes: [],
      curatorLikes: [],
      announcements: [],
      licenses: [],
      playtests: [],
      playTime: []
    }
  };
  const REGEX_PATTERNS = {
    DISCORD_INVITE: /invite\/(.+)/,
    INSTAGRAM_USER: /https:\/\/www\.instagram\.com\/(.+)?\//,
    TWITCH_CHANNEL: /https:\/\/(www\.)?twitch\.tv\/(.+)/,
    TWITTER_USER: /https:\/\/twitter\.com\/(.+)/,
    TWITTER_STATUS: /https:\/\/twitter\.com\/.*?\/status\/([\d]+)/,
    VK_NAME: /https:\/\/vk\.com\/([^/]+)/,
    REDDIT_USER: /https?:\/\/www\.reddit\.com\/user\/([^/]*)/,
    REDDIT_SUBREDDIT: /https?:\/\/www\.reddit\.com\/r\/([^/]*)/,
    STEAM_GROUP: /groups\/(.+)\/?/,
    STEAM_APP: /app\/([\d]+)/,
    STEAM_WORKSHOP: /\?id=([\d]+)/,
    STEAM_CURATOR: /curator\/([\d]+)/,
    STEAM_STORE: /https?:\/\/store\.steampowered\.com\/(.*?)\/([^/?]+)/
  };
  const link2id = async function(type) {
    try {
      debug('开始从链接获取ID', {
        type: type
      });
      const link = $('#socialLink').val();
      let id = '';
      switch (type) {
       case 'discord.servers':
        id = REGEX_PATTERNS.DISCORD_INVITE.exec(link)?.[1] || '';
        break;

       case 'instagram.users':
        id = REGEX_PATTERNS.INSTAGRAM_USER.exec(link)?.[1] || '';
        break;

       case 'twitch.channels':
        id = REGEX_PATTERNS.TWITCH_CHANNEL.exec(link)?.[2] || '';
        break;

       case 'twitter.users':
        id = REGEX_PATTERNS.TWITTER_USER.exec(link)?.[1] || '';
        break;

       case 'twitter.retweets':
        id = REGEX_PATTERNS.TWITTER_STATUS.exec(link)?.[1] || '';
        break;

       case 'vk.names':
        id = REGEX_PATTERNS.VK_NAME.exec(link)?.[1] || '';
        break;

       case 'youtube.channels':
        id = (await getInfo(link, 'channel'))?.params?.channelId || '';
        break;

       case 'youtube.likes':
        id = (await getInfo(link, 'likeVideo'))?.params?.videoId || '';
        break;

       case 'reddit.reddits':
        {
          const userMatch = REGEX_PATTERNS.REDDIT_USER.exec(link);
          const subredditMatch = REGEX_PATTERNS.REDDIT_SUBREDDIT.exec(link);
          id = userMatch?.[1] || subredditMatch?.[1] || '';
          break;
        }

       case 'steam.groups':
        id = REGEX_PATTERNS.STEAM_GROUP.exec(link)?.[1] || '';
        break;

       case 'steam.wishlists':
       case 'steam.follows':
       case 'steam.forums':
       case 'steam.playtests':
       case 'steam.playTime':
        id = REGEX_PATTERNS.STEAM_APP.exec(link)?.[1] || '';
        break;

       case 'steam.workshops':
        id = REGEX_PATTERNS.STEAM_WORKSHOP.exec(link)?.[1] || '';
        break;

       case 'steam.curators':
        {
          if (link.includes('curator')) {
            id = REGEX_PATTERNS.STEAM_CURATOR.exec(link)?.[1] || '';
          } else {
            const storeMatch = REGEX_PATTERNS.STEAM_STORE.exec(link);
            if (!storeMatch) {
              break;
            }
            const [, param1, param2] = storeMatch;
            const steam = new Steam;
            if (await steam.init()) {
              id = await steam.getCuratorId(param1, param2) || '';
            }
          }
          break;
        }
      }
      debug('从链接获取ID结果', {
        type: type,
        id: id
      });
      return id;
    } catch (error) {
      debug('从链接获取ID时发生错误', {
        error: error
      });
      throwError(error, 'link2id');
      return I18n('getFailed', 'id');
    }
  };
  const disabledType = {
    steam: [ 'workshopVotes', 'curatorLikes', 'announcements' ],
    twitter: [ 'likes' ]
  };
  const assignWhiteList = whiteList => {
    try {
      debug('开始合并白名单');
      const newWhiteList = {};
      for (const [key, value] of Object.entries(defaultWhiteList)) {
        newWhiteList[key] = {
          ...value,
          ...whiteList[key]
        };
      }
      debug('白名单合并完成');
      return newWhiteList;
    } catch (error) {
      debug('合并白名单时发生错误', {
        error: error
      });
      throwError(error, 'assignWhiteList');
      return defaultWhiteList;
    }
  };
  const whiteListOptions = function(showType) {
    try {
      debug('开始显示白名单选项', {
        showType: showType
      });
      const whiteList = assignWhiteList(GM_getValue('whiteList') || {});
      let whiteListOptionsForm = `<form id="whiteListForm" class="auto-task-form">\n      <table class="auto-task-table">\n        <thead>\n          <tr>\n            <td>${I18n('website')}</td>\n            <td>${I18n('type')}</td>\n            <td>${I18n('edit')}</td>\n          </tr>\n        </thead>\n        <tbody>`;
      for (const [social, types] of Object.entries(whiteList)) {
        const validTypes = Object.keys(types).filter((type => !disabledType[social]?.includes(type)));
        whiteListOptionsForm += validTypes.map(((type, index) => {
          const bgColor = `${stringToColour(social)}66`;
          return `\n          <tr style="background-color: ${bgColor}">\n            ${index === 0 ? `<th rowspan="${validTypes.length}" style="background-color: ${bgColor}">${social}</th>` : ''}\n            <td>${I18n(type)}</td>\n            <td><button type="button" class="editWhiteList" data-value="${social}.${type}">${I18n('edit')}</button></td>\n          </tr>`;
        })).join('');
      }
      whiteListOptionsForm += '</tbody></table></form>';
      if (showType === 'swal') {} else {
        debug('使用页面显示白名单选项');
        $('body').append(`<h2>${I18n('whiteList')}</h2>${whiteListOptionsForm}`);
      }
      $('.editWhiteList').on('click', (function() {
        const value = $(this).attr('data-value');
        if (!value) {
          return;
        }
        const [social, type] = value.split('.');
        const currentList = whiteList[social]?.[type];
        if (!currentList) {
          debug('未找到白名单配置', {
            social: social,
            type: type
          });
          echoLog({}).warning(I18n('whiteListNotFound', value));
          return;
        }
        debug('编辑白名单', {
          social: social,
          type: type
        });
        Swal.fire({
          title: I18n('changeWhiteListOption', value),
          input: 'textarea',
          html: `\n          <input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id">\n          <button id="link2id" data-type="${value}" class="swal2-confirm swal2-styled">获取id</button>\n          <p style="margin-bottom:0 !important;">在下方填写白名单,每行一个</p>\n        `,
          inputValue: currentList.join('\n'),
          showConfirmButton: true,
          confirmButtonText: I18n('save'),
          showCancelButton: true,
          cancelButtonText: I18n('close'),
          showDenyButton: true,
          denyButtonText: I18n('return')
        }).then((({isDenied: isDenied, isConfirmed: isConfirmed, value: value}) => {
          if (isDenied) {
            debug('返回白名单选项');
            if (showType === 'swal') {}
            return;
          }
          if (isConfirmed && value) {
            debug('保存白名单更改', {
              social: social,
              type: type,
              value: value
            });
            whiteList[social][type] = value.split('\n').filter(Boolean);
            GM_setValue('whiteList', whiteList);
            Swal.fire({
              title: I18n('changeWhiteListSuccess'),
              icon: 'success'
            });
          }
        }));
        $('#link2id').on('click', (async function() {
          const type = $(this).attr('data-type');
          if (!type) {
            return;
          }
          debug('从链接获取ID按钮点击', {
            type: type
          });
          const id = await link2id(type);
          $('#socialLink').val(id);
        }));
      }));
    } catch (error) {
      debug('显示白名单选项时发生错误', {
        error: error
      });
      throwError(error, 'whiteListOptions');
    }
  };
  const setGistData = async (token, gistId, fileName, content) => {
    try {
      debug('开始设置Gist数据', {
        gistId: gistId,
        fileName: fileName
      });
      const logStatus = echoLog({
        text: I18n('settingData')
      });
      const contentData = JSON.stringify({
        files: {
          [fileName]: {
            content: JSON.stringify(content)
          }
        }
      });
      debug('准备发送的数据', {
        contentData: contentData
      });
      const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
        url: `https://api.github.com/gists/${gistId}`,
        headers: {
          Accept: 'application/vnd.github.v3+json',
          Authorization: `token ${token}`
        },
        data: contentData,
        responseType: 'json',
        method: 'POST',
        timeout: 3e4
      });
      if (result !== 'Success') {
        debug('设置Gist数据失败', {
          result: result,
          statusText: statusText,
          status: status
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return false;
      }
      const expectedContent = JSON.stringify(content);
      if (data?.status !== 200 || data?.response?.files?.[fileName]?.content !== expectedContent) {
        debug('设置Gist数据验证失败', {
          status: data?.status,
          content: data?.response?.files?.[fileName]?.content
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      }
      debug('设置Gist数据成功');
      logStatus.success();
      return true;
    } catch (error) {
      debug('设置Gist数据发生错误', {
        error: error
      });
      throwError(error, 'setGistData');
      return false;
    }
  };
  const getGistData = async (token, gistId, fileName, test = false) => {
    try {
      debug('开始获取Gist数据', {
        gistId: gistId,
        fileName: fileName,
        test: test
      });
      const logStatus = echoLog({
        text: I18n('gettingData')
      });
      const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
        url: `https://api.github.com/gists/${gistId}`,
        headers: {
          Accept: 'application/vnd.github.v3+json',
          Authorization: `token ${token}`
        },
        responseType: 'json',
        method: 'GET',
        timeout: 3e4
      });
      if (result !== 'Success') {
        debug('获取Gist数据失败', {
          result: result,
          statusText: statusText,
          status: status
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return false;
      }
      if (data?.status !== 200) {
        debug('获取Gist数据状态码错误', {
          status: data?.status
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      }
      const content = data.response?.files?.[fileName]?.content;
      if (!content) {
        debug('获取的Gist数据为空');
        logStatus.error(`Error:${I18n('noRemoteData')}`);
        return false;
      }
      if (test) {
        debug('Gist数据测试成功');
        logStatus.success();
        return true;
      }
      try {
        const formatedContent = JSON.parse(content);
        debug('Gist数据解析成功', {
          contentLength: Object.keys(formatedContent).length
        });
        logStatus.success();
        return formatedContent;
      } catch (error) {
        debug('Gist数据解析失败', {
          error: error
        });
        logStatus.error(`Error:${I18n('errorRemoteDataFormat')}`);
        console.log('%c%s', 'color:white;background:red', `Auto-Task[Error]: getGistData\n${error.stack}`);
        return false;
      }
    } catch (error) {
      debug('获取Gist数据发生错误', {
        error: error
      });
      throwError(error, 'getGistData');
      return false;
    }
  };
  const syncOptions = async () => {
    try {
      debug('开始同步选项配置');
      const defaultOptions = {
        TOKEN: '',
        GIST_ID: '',
        FILE_NAME: '',
        SYNC_HISTORY: true
      };
      let syncOptions = GM_getValue('gistOptions') || defaultOptions;
      debug('获取已保存的同步选项', syncOptions);
      const createForm = options => `\n      <div class="gist-options-form">\n        <p>\n          <label for="github-token">Github Token</label>\n          <input\n            id="github-token"\n            class="swal2-input"\n            placeholder="Github Token"\n            value="${options.TOKEN}"\n            autocomplete="off"\n            spellcheck="false"\n          />\n        </p>\n        <p>\n          <label for="gist-id">Gist ID</label>\n          <input\n            id="gist-id"\n            class="swal2-input"\n            placeholder="Gist ID"\n            value="${options.GIST_ID}"\n            autocomplete="off"\n            spellcheck="false"\n          />\n        </p>\n        <p>\n          <label for="file-name">${I18n('fileName')}</label>\n          <input\n            id="file-name"\n            class="swal2-input"\n            placeholder="${I18n('fileName')}"\n            value="${options.FILE_NAME}"\n            autocomplete="off"\n            spellcheck="false"\n          />\n        </p>\n        <p class="sync-history-wrapper">\n          <label for="sync-history" class="swal2-checkbox-custom">\n            <input\n              id="sync-history"\n              type="checkbox"\n              ${options.SYNC_HISTORY ? 'checked="checked"' : ''}\n            />\n            <span class="swal2-label">${I18n('syncHistory')}</span>\n          </label>\n        </p>\n        <div class="button-group">\n          <button id="upload-data" type="button" class="swal2-confirm swal2-styled" onclick="handleUpload()">\n            ${I18n('upload2gist')}\n          </button>\n          <button id="download-data" type="button" class="swal2-confirm swal2-styled" onclick="handleDownload()">\n            ${I18n('downloadFromGist')}\n          </button>\n        </div>\n      </div>\n    `;
      const showConfigDialog = async () => {
        debug('显示配置对话框');
        const result = await Swal.fire({
          title: I18n('gistOptions'),
          html: createForm(syncOptions),
          focusConfirm: false,
          showLoaderOnConfirm: true,
          footer: `<a href="https://auto-task-doc.js.org/guide/#%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5" target="_blank">${I18n('help')}</a>`,
          preConfirm: async () => {
            const options = {
              TOKEN: $('#github-token').val().trim(),
              GIST_ID: $('#gist-id').val().trim(),
              FILE_NAME: $('#file-name').val().trim(),
              SYNC_HISTORY: $('#sync-history').prop('checked')
            };
            debug('保存新的同步选项', options);
            GM_setValue('gistOptions', options);
            syncOptions = options;
            return await getGistData(options.TOKEN, options.GIST_ID, options.FILE_NAME, true);
          },
          allowOutsideClick: () => !Swal.isLoading(),
          confirmButtonText: I18n('saveAndTest'),
          showCancelButton: true,
          cancelButtonText: I18n('close')
        });
        if (result.value) {
          debug('配置测试成功');
          await Swal.fire({
            icon: 'success',
            title: I18n('testSuccess'),
            timer: 2e3,
            timerProgressBar: true
          });
          await showConfigDialog();
        } else if (result.value !== undefined) {
          debug('配置测试失败');
          await Swal.fire({
            icon: 'error',
            title: I18n('testFailed'),
            timer: 2e3,
            timerProgressBar: true
          });
          await showConfigDialog();
        }
      };
      const handleUpload = async () => {
        debug('开始处理数据上传');
        const options = GM_getValue('gistOptions');
        if (!options?.TOKEN || !options?.GIST_ID || !options?.FILE_NAME) {
          debug('配置信息不完整');
          await Swal.fire({
            icon: 'error',
            title: I18n('saveAndTestNotice')
          });
          await showConfigDialog();
          return;
        }
        debug('显示数据处理提示');
        Swal.fire({
          icon: 'info',
          title: I18n('processingData'),
          allowOutsideClick: false
        });
        const data = {};
        const names = GM_listValues();
        const syncHistory = $('#sync-history').prop('checked');
        debug('开始收集数据', {
          namesCount: names.length,
          syncHistory: syncHistory
        });
        for (const name of names) {
          if (name === 'gistOptions' || /^[\w]+?Auth$/.test(name)) {
            continue;
          }
          if (!syncHistory && /^[\w]+?Tasks-/.test(name)) {
            continue;
          }
          data[name] = GM_getValue(name);
        }
        debug('数据收集完成', {
          dataKeysCount: Object.keys(data).length
        });
        Swal.update({
          icon: 'info',
          title: I18n('updatingData')
        });
        const success = await setGistData(options.TOKEN, options.GIST_ID, options.FILE_NAME, data);
        debug('数据上传完成', {
          success: success
        });
        await Swal.fire({
          icon: success ? 'success' : 'error',
          title: I18n(success ? 'syncDataSuccess' : 'syncDataFailed'),
          timer: 2e3,
          timerProgressBar: true
        });
      };
      const handleDownload = async () => {
        debug('开始处理数据下载');
        const options = GM_getValue('gistOptions');
        if (!options?.TOKEN || !options?.GIST_ID || !options?.FILE_NAME) {
          debug('配置信息不完整');
          await Swal.fire({
            icon: 'error',
            title: I18n('saveAndTestNotice')
          });
          await showConfigDialog();
          return;
        }
        debug('显示数据下载提示');
        Swal.fire({
          icon: 'info',
          title: I18n('downloadingData'),
          allowOutsideClick: false
        });
        const data = await getGistData(options.TOKEN, options.GIST_ID, options.FILE_NAME);
        if (!data || typeof data === 'boolean') {
          debug('未检测到远程数据');
          await Swal.fire({
            icon: 'error',
            title: I18n('checkedNoData')
          });
          await showConfigDialog();
          return;
        }
        debug('开始保存数据');
        Swal.update({
          icon: 'info',
          title: I18n('savingData')
        });
        const syncHistory = $('#sync-history').prop('checked');
        let savedCount = 0;
        for (const [name, value] of Object.entries(data)) {
          if (!syncHistory && /^[\w]+?Tasks-/.test(name)) {
            continue;
          }
          GM_setValue(name, value);
          savedCount += 1;
        }
        debug('数据保存完成', {
          savedCount: savedCount
        });
        await Swal.fire({
          icon: 'success',
          title: I18n('syncDataSuccess'),
          timer: 2e3,
          timerProgressBar: true
        });
      };
      unsafeWindow.handleUpload = handleUpload;
      unsafeWindow.handleDownload = handleDownload;
      await showConfigDialog();
    } catch (error) {
      debug('同步选项发生错误', {
        error: error
      });
      throwError(error, 'syncOptions');
      await Swal.fire({
        icon: 'error',
        title: I18n('error'),
        text: error instanceof Error ? error.message : 'Unknown error occurred',
        timer: 3e3,
        timerProgressBar: true
      });
    }
  };
  const VALID_SIDES_X = [ 'right', 'left' ];
  const VALID_SIDES_Y = [ 'top', 'bottom' ];
  class Setting {
    name='Setting';
    buttons=[ 'saveGlobalOptions', 'syncData', 'tasksHistory' ];
    syncData=syncOptions;
    selectors={
      body: 'body',
      autoTaskInfo: '#auto-task-info',
      autoTaskButtons: '#auto-task-buttons',
      showButtonDiv: 'div.show-button-div',
      positionInputs: 'input[name^="position"]',
      hotKeyInputs: 'input[name^="hotKey"]'
    };
    tasksHistory() {
      debug('打开任务历史记录页面');
      GM_openInTab('https://auto-task.hclonely.com/history.html', {
        active: true
      });
    }
    static test() {
      const {host: host, pathname: pathname} = window.location;
      const isMatch = [ 'auto-task.hclonely.com', 'auto-task-doc.js.org' ].includes(host) && pathname === '/setting.html';
      debug('检查设置页面匹配', {
        host: host,
        pathname: pathname,
        isMatch: isMatch
      });
      return isMatch;
    }
    before() {
      try {
        debug('开始清空页面内容');
        $(this.selectors.body).html('').addClass('auto-task-options');
        debug('页面内容已清空');
      } catch (error) {
        debug('清空页面内容失败', {
          error: error
        });
        throwError(error, 'Setting.before');
      }
    }
    async after() {
      try {
        debug('开始初始化设置页面');
        await this.#initializeEnvironment();
        this.#initializeGlobalSettings();
        this.#setupSocialButtons();
        this.#setupPositionHandlers();
        this.#setupHotKeyHandlers();
        debug('设置页面初始化完成');
      } catch (error) {
        debug('设置页面初始化失败', {
          error: error
        });
        throwError(error, 'Setting.after');
      }
    }
    saveGlobalOptions() {
      try {
        debug('开始保存全局选项');
        saveData();
        debug('全局选项保存完成');
      } catch (error) {
        debug('保存全局选项失败', {
          error: error
        });
        throwError(error, 'Setting.saveGlobalOptions');
      }
    }
    async #initializeEnvironment() {
      try {
        debug('开始初始化环境信息');
        const userAgent = await browser.getInfo();
        debug('获取用户代理信息', {
          userAgent: userAgent
        });
        const environmentHtml = this.#generateEnvironmentHtml(userAgent);
        $(this.selectors.body).append(`<h2>${I18n('environment')}</h2>${environmentHtml}`);
        debug('环境信息初始化完成');
      } catch (error) {
        debug('初始化环境信息失败', {
          error: error
        });
        throwError(error, 'Setting.initializeEnvironment');
      }
    }
    #generateEnvironmentHtml(userAgent) {
      return `\n      <form id="environmentForm" class="auto-task-form">\n        <table class="auto-task-table">\n          <thead>\n            <tr>\n              <td>${I18n('type')}</td>\n              <td>${I18n('name')}</td>\n              <td>${I18n('version')}</td>\n            </tr>\n          </thead>\n          <tbody>\n            <tr>\n              <td>${I18n('os')}</td>\n              <td>${userAgent.system}</td>\n              <td>${userAgent.systemVersion}</td>\n            </tr>\n            <tr>\n              <td>${I18n('browser')}</td>\n              <td>${userAgent.browser}</td>\n              <td>${userAgent.browserVersion}</td>\n            </tr>\n            <tr>\n              <td>${I18n('scriptManager')}</td>\n              <td>${GM_info.scriptHandler}</td>\n              <td>${GM_info.version}</td>\n            </tr>\n            <tr>\n              <td>${I18n('script')}</td>\n              <td>${GM_info.script.name}</td>\n              <td>${GM_info.script.version}</td>\n            </tr>\n          </tbody>\n        </table>\n      </form>\n    `;
    }
    #initializeGlobalSettings() {
      debug('开始初始化全局设置');
      changeGlobalOptions('page');
      whiteListOptions('page');
      debug('全局设置初始化完成');
    }
    #setupSocialButtons() {
      debug('开始设置社交媒体按钮');
      this.#addSocialButton('other.twitterVerifyId', 'getTwitterUserId', 'twitterUser');
      this.#addSocialButton('other.youtubeVerifyChannel', 'getYoutubeChannelId', 'youtubeChannel');
      debug('社交媒体按钮设置完成');
    }
    #addSocialButton(inputName, buttonId, socialType) {
      debug('添加社交媒体按钮', {
        inputName: inputName,
        buttonId: buttonId,
        socialType: socialType
      });
      $(`input[name="${inputName}"]`).after(`<button id="${buttonId}" type="button">${I18n(`get${buttonId}`)}</button>`);
      $(`#${buttonId}`).on('click', (() => this.#getId(socialType)));
      debug('社交媒体按钮添加完成');
    }
    #setupPositionHandlers() {
      debug('开始设置位置处理器');
      $(this.selectors.positionInputs).on('input', (event => {
        const input = $(event.target);
        const type = input.attr('name')?.replace('position.', '');
        if (!type) {
          debug('无效的位置类型');
          return;
        }
        debug('处理位置变化', {
          type: type
        });
        this.#handlePositionChange(type);
      }));
      debug('位置处理器设置完成');
    }
    #handlePositionChange(type) {
      debug('开始处理位置变化', {
        type: type
      });
      const config = this.#getPositionConfig(type);
      if (!config) {
        debug('获取位置配置失败');
        return;
      }
      const {distance: distance, sideX: sideX, sideY: sideY} = config;
      if (!this.#isValidPosition(distance, sideX, sideY)) {
        debug('无效的位置配置', {
          distance: distance,
          sideX: sideX,
          sideY: sideY
        });
        return;
      }
      const [x, y] = distance.split(',');
      const target = this.#getPositionTarget(type);
      if (!target) {
        debug('获取目标元素失败');
        return;
      }
      debug('更新元素位置', {
        target: target,
        sideX: sideX,
        sideY: sideY,
        x: x,
        y: y
      });
      this.#updateElementPosition(target, sideX, sideY, x, y);
    }
    #getPositionConfig(type) {
      debug('获取位置配置', {
        type: type
      });
      const baseType = type.replace(/(?:button|log|show)(?:SideX|SideY|Distance)$/, '');
      const distance = $(`input[name="position.${baseType}Distance"]`).val();
      const sideX = $(`input[name="position.${baseType}SideX"]`).val();
      const sideY = $(`input[name="position.${baseType}SideY"]`).val();
      const config = {
        distance: distance,
        sideX: sideX,
        sideY: sideY
      };
      debug('位置配置', config);
      return config;
    }
    #isValidPosition(distance, sideX, sideY) {
      const isValid = VALID_SIDES_X.includes(sideX) && VALID_SIDES_Y.includes(sideY) && /^[\d]+?,[\d]+$/.test(distance);
      debug('验证位置配置', {
        distance: distance,
        sideX: sideX,
        sideY: sideY,
        isValid: isValid
      });
      return isValid;
    }
    #getPositionTarget(type) {
      const targetMap = {
        button: this.selectors.autoTaskButtons,
        showButton: this.selectors.showButtonDiv,
        log: this.selectors.autoTaskInfo
      };
      const baseType = type.replace(/(?:SideX|SideY|Distance)$/, '');
      return targetMap[baseType];
    }
    #updateElementPosition(selector, sideX, sideY, x, y) {
      debug('更新元素位置', {
        selector: selector,
        sideX: sideX,
        sideY: sideY,
        x: x,
        y: y
      });
      const $element = $(selector);
      const oppositeX = sideX === 'right' ? 'left' : 'right';
      const oppositeY = sideY === 'top' ? 'bottom' : 'top';
      $element.css(sideX, `${x}px`).css(sideY, `${y}px`).css(oppositeX, '').css(oppositeY, '');
      debug('元素位置更新完成');
    }
    #setupHotKeyHandlers() {
      debug('开始设置热键处理器');
      $(this.selectors.hotKeyInputs).attr('readonly', 'readonly').off('keydown').on('keydown', this.#handleHotKeyPress);
      debug('热键处理器设置完成');
    }
    #handleHotKeyPress(event) {
      debug('处理热键按下事件', {
        key: event.key
      });
      const functionKeys = [];
      if (event.altKey) {
        functionKeys.push('alt');
      }
      if (event.ctrlKey) {
        functionKeys.push('ctrl');
      }
      if (event.shiftKey) {
        functionKeys.push('shift');
      }
      const key = event.key.length === 1 ? event.key.toLowerCase() : '';
      const value = functionKeys.length ? `${functionKeys.join(' + ')} + ${key}` : key;
      debug('设置热键值', {
        functionKeys: functionKeys,
        key: key,
        value: value
      });
      $(event.target).val(value);
    }
    async #getId(social) {
      try {
        debug('开始获取社交媒体ID', {
          social: social
        });
        const result = await Swal.fire({
          title: I18n('getId', I18n(social)),
          html: this.#generateIdInputHtml(social),
          showCancelButton: true,
          cancelButtonText: I18n('close'),
          showConfirmButton: false
        });
        if (!result.isDismissed) {
          debug('用户确认获取ID');
          await this.#handleIdRetrieval(social);
        } else {
          debug('用户取消获取ID');
        }
      } catch (error) {
        debug('获取社交媒体ID失败', {
          error: error
        });
        throwError(error, 'Setting.getId');
      }
    }
    #generateIdInputHtml(social) {
      return `\n      <input id="socialLink" class="swal2-input" placeholder="在此处输入链接获取id">\n      <button id="link2id" data-type="${social}" class="swal2-confirm swal2-styled">获取id</button>\n    `;
    }
    async #handleIdRetrieval(social) {
      const link = $('#socialLink').val();
      if (!link) {
        debug('链接为空');
        return;
      }
      debug('开始处理ID获取', {
        social: social,
        link: link
      });
      let id = '';
      if (social === 'twitterUser') {
        const name = link.match(/https:\/\/twitter\.com\/(.+)/)?.[1] || link;
        debug('获取Twitter用户ID', {
          name: name
        });
        id = await (new Twitter).userName2id(name) || '';
      } else if (social === 'youtubeChannel') {
        const name = this.#extractYoutubeUrl(link);
        debug('获取YouTube频道信息', {
          name: name
        });
        const info = await getInfo(name, 'channel');
        id = info?.params?.channelId || '';
      }
      debug('ID获取结果', {
        id: id
      });
      $('#socialLink').val(id);
    }
    #extractYoutubeUrl(link) {
      debug('提取YouTube URL', {
        link: link
      });
      if (/^https:\/\/(www\.)?google\.com.*?\/url\?.*?url=https:\/\/www.youtube.com\/.*/.test(link)) {
        const extractedUrl = link.match(/url=(https:\/\/www\.youtube\.com\/.*)/)?.[1] || link;
        debug('从Google搜索结果提取URL', {
          extractedUrl: extractedUrl
        });
        return extractedUrl;
      }
      return link;
    }
  }
  class History extends Keylol {
    name='History';
    buttons=[ 'doTask', 'undoTask', 'selectAll', 'selectNone', 'invertSelect', 'clearHistory' ];
    static test() {
      try {
        const {host: host, pathname: pathname} = window.location;
        const isMatch = [ 'auto-task.hclonely.com', 'auto-task-doc.js.org' ].includes(host) && pathname === '/history.html';
        debug('检查是否为历史记录页面', {
          host: host,
          pathname: pathname,
          isMatch: isMatch
        });
        return isMatch;
      } catch (error) {
        debug('检查历史记录页面时出错', {
          error: error
        });
        throwError(error, 'History.test');
        return false;
      }
    }
    before() {
      try {
        debug('开始初始化历史记录页面');
        $('body').html('<div class="container"></div>').addClass('auto-task-history');
        debug('页面基础结构已创建');
        const data = GM_listValues() || [];
        debug('获取存储的所有值', {
          count: data.length
        });
        const tasksHistory = data.map((value => /^[\w]+?Tasks-/.test(value) ? value : null)).filter((value => value));
        debug('筛选任务历史记录', {
          count: tasksHistory.length
        });
        tasksHistory.forEach((item => {
          debug('处理任务项', {
            item: item
          });
          this.#addItem(item);
        }));
        debug('历史记录页面初始化完成');
      } catch (error) {
        debug('初始化历史记录页面时出错', {
          error: error
        });
        throwError(error, 'History.before');
      }
    }
    clearHistory() {
      try {
        debug('开始清除历史记录');
        const data = GM_listValues() || [];
        debug('获取存储的所有值', {
          count: data.length
        });
        const tasksHistory = data.map((value => /^[\w]+?Tasks-/.test(value) ? value : null)).filter((value => value));
        debug('筛选要清除的任务历史记录', {
          count: tasksHistory.length
        });
        tasksHistory.forEach((item => {
          debug('删除任务项', {
            item: item
          });
          GM_deleteValue(item);
        }));
        debug('历史记录清除完成');
        Swal.fire({
          title: I18n('clearHistoryFinished'),
          icon: 'success'
        });
      } catch (error) {
        debug('清除历史记录时出错', {
          error: error
        });
        throwError(error, 'History.clearHistory');
      }
    }
    #addItem(item) {
      try {
        debug('开始添加任务项', {
          item: item
        });
        const tasksData = GM_getValue(item);
        if (!tasksData?.tasks) {
          debug('任务数据无效', {
            item: item
          });
          return;
        }
        const {title: title, link: link} = this.#getTaskInfo(item);
        if (!title || !link) {
          debug('获取任务信息失败', {
            item: item
          });
          return;
        }
        debug('生成任务HTML', {
          item: item,
          title: title,
          link: link
        });
        const html = this.#generateTaskHtml(tasksData.tasks);
        this.#appendTaskToContainer(item, title, link, html, tasksData.time);
        this.#bindDeleteEvent();
        debug('任务项添加完成', {
          item: item
        });
      } catch (error) {
        debug('添加任务项时出错', {
          error: error,
          item: item
        });
        throwError(error, 'History.addItem');
      }
    }
    #getTaskInfo(item) {
      try {
        debug('开始获取任务信息', {
          item: item
        });
        const [website, id] = item.split('-');
        debug('解析任务标识符', {
          website: website,
          id: id
        });
        const taskInfoMap = {
          fawTasks: {
            title: `Freeanywhere[${id}]`,
            link: `https://freeanywhere.net/#/giveaway/${id}`
          },
          gasTasks: {
            title: `Giveawaysu[${id}]`,
            link: `https://giveaway.su/giveaway/view/${id}`
          },
          gcTasks: {
            title: `GiveeClub[${id}]`,
            link: `https://givee.club/event/${id}`
          },
          gkTasks: {
            title: `Givekey[${id}]`,
            link: `https://givekey.ru/giveaway/${id}`
          },
          gleamTasks: {
            title: `Gleam[${id}]`,
            link: `https://gleam.io${id}`
          },
          khTasks: {
            title: `keyhub[${id}]`,
            link: `https://key-hub.eu/giveaway/${id}`
          },
          prysTasks: {
            title: `Prys[${id}]`,
            link: `https://prys.revadike.com/giveaway/?id=${id}`
          }
        };
        const result = taskInfoMap[website] || {
          title: '',
          link: ''
        };
        debug('获取任务信息结果', {
          result: result
        });
        return result;
      } catch (error) {
        debug('获取任务信息时出错', {
          error: error,
          item: item
        });
        throwError(error, 'History.getTaskInfo');
        return {
          title: '',
          link: ''
        };
      }
    }
    #generateTaskHtml(tasks) {
      try {
        debug('开始生成任务HTML');
        let html = '';
        for (const [social, types] of Object.entries(tasks)) {
          for (const [type, taskList] of Object.entries(types)) {
            for (const task of taskList) {
              debug('处理任务', {
                social: social,
                type: type,
                task: task
              });
              const displayTask = task.length > 55 ? `${task.slice(0, 55)}...` : task;
              html += `<li>\n              <font class="auto-task-capitalize">${social}.${I18n(type.replace('Link', ''))}: </font>\n              <a href="${task}" target="_blank">${displayTask}</a>\n            </li>`;
            }
          }
        }
        debug('任务HTML生成完成');
        return html;
      } catch (error) {
        debug('生成任务HTML时出错', {
          error: error
        });
        throwError(error, 'History.generateTaskHtml');
        return '';
      }
    }
    #appendTaskToContainer(item, title, link, html, time) {
      try {
        debug('开始添加任务到容器', {
          item: item,
          title: title,
          link: link
        });
        $('.container').append(`\n        <div class="card" data-name="${item}">\n          <div class="title">\n            <a href="${link}" target="_blank">${title}</a>\n            <span class="delete-task" data-name="${item}" title="${I18n('deleteTask')}">\n              <svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2734" width="32" height="32">\n                <path d="M607.897867 768.043004c-17.717453 0-31.994625-14.277171-31.994625-31.994625L575.903242 383.935495c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 351.94087C639.892491 753.593818 625.61532 768.043004 607.897867 768.043004z" p-id="2735" fill="#d81e06"></path>\n                <path d="M415.930119 768.043004c-17.717453 0-31.994625-14.277171-31.994625-31.994625L383.935495 383.935495c0-17.717453 14.277171-31.994625 31.994625-31.994625 17.717453 0 31.994625 14.277171 31.994625 31.994625l0 351.94087C447.924744 753.593818 433.647573 768.043004 415.930119 768.043004z" p-id="2736" fill="#d81e06"></path>\n                <path d="M928.016126 223.962372l-159.973123 0L768.043004 159.973123c0-52.980346-42.659499-95.983874-95.295817-95.983874L351.94087 63.989249c-52.980346 0-95.983874 43.003528-95.983874 95.983874l0 63.989249-159.973123 0c-17.717453 0-31.994625 14.277171-31.994625 31.994625s14.277171 31.994625 31.994625 31.994625l832.032253 0c17.717453 0 31.994625-14.277171 31.994625-31.994625S945.73358 223.962372 928.016126 223.962372zM319.946246 159.973123c0-17.545439 14.449185-31.994625 31.994625-31.994625l320.806316 0c17.545439 0 31.306568 14.105157 31.306568 31.994625l0 63.989249L319.946246 223.962372 319.946246 159.973123 319.946246 159.973123z" p-id="2737" fill="#d81e06"></path>\n                <path d="M736.048379 960.010751 288.123635 960.010751c-52.980346 0-95.983874-43.003528-95.983874-95.983874L192.139761 383.591466c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 480.435411c0 17.717453 14.449185 31.994625 31.994625 31.994625l448.096758 0c17.717453 0 31.994625-14.277171 31.994625-31.994625L768.215018 384.795565c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 479.231312C832.032253 916.835209 789.028725 960.010751 736.048379 960.010751z" p-id="2738" fill="#d81e06"></path>\n              </svg>\n            </span>\n          </div>\n          <ul>${html}</ul>\n          <span class="time">${I18n('lastChangeTime')}: ${dayjs(time).format('YYYY-MM-DD HH:mm:ss')}</span>\n        </div>\n      `);
        debug('任务已添加到容器', {
          item: item
        });
      } catch (error) {
        debug('添加任务到容器时出错', {
          error: error,
          item: item
        });
        throwError(error, 'History.appendTaskToContainer');
      }
    }
    #bindDeleteEvent() {
      try {
        debug('开始绑定删除事件');
        $('span.delete-task').on('click', (function() {
          const itemName = $(this).attr('data-name');
          debug('点击删除按钮', {
            itemName: itemName
          });
          if (!itemName) {
            debug('删除失败:未找到任务名称');
            Swal.fire({
              title: I18n('clearTaskFailed'),
              icon: 'error'
            });
            return;
          }
          GM_deleteValue(itemName);
          $(`div.card[data-name="${itemName}"]`).remove();
          debug('任务删除成功', {
            itemName: itemName
          });
          Swal.fire({
            title: I18n('clearTaskFinished'),
            text: itemName,
            icon: 'success'
          });
        }));
        debug('删除事件绑定完成');
      } catch (error) {
        debug('绑定删除事件时出错', {
          error: error
        });
        throwError(error, 'History.bindDeleteEvent');
      }
    }
  }
  const defaultTasksTemplate$1 = {
    steam: {
      groupLinks: [],
      wishlistLinks: [],
      followLinks: [],
      curatorLinks: [],
      curatorLikeLinks: []
    },
    twitter: {
      userLinks: [],
      retweetLinks: []
    },
    twitch: {
      channelLinks: []
    },
    discord: {
      serverLinks: []
    },
    youtube: {
      channelLinks: []
    },
    extra: {
      giveawayHopper: []
    }
  };
  const defaultTasks$1 = JSON.stringify(defaultTasksTemplate$1);
  class GiveawayHopper extends Website {
    name='GiveawayHopper';
    undoneTasks=JSON.parse(defaultTasks$1);
    socialTasks=JSON.parse(defaultTasks$1);
    tasks=[];
    buttons=[ 'doTask', 'undoTask', 'verifyTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'giveawayhopper.com';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('登录检查失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        const giveawayIdResult = this.#getGiveawayId();
        debug('获取抽奖ID', {
          success: giveawayIdResult,
          id: this.giveawayId
        });
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.after');
      }
    }
    async init() {
      try {
        debug('初始化 GiveawayHopper');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        const leftKeyResult = await this.#checkLeftKey();
        if (!leftKeyResult) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        if (!this.giveawayId) {
          debug('未找到抽奖ID,尝试获取');
          await this.#getGiveawayId();
        }
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`giveawayHopperTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks$1);
        }
        debug('请求任务列表');
        const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
          url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/with-auth`,
          method: 'GET',
          responseType: 'json',
          headers: {
            authorization: `Bearer ${window.sessionStorage.gw_auth}`,
            'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
          }
        });
        if (result !== 'Success') {
          debug('请求任务列表失败', {
            result: result,
            statusText: statusText,
            status: status
          });
          logStatus.error(`${result}:${statusText}(${status})`);
          return false;
        }
        if (data?.status !== 200 || !data?.response?.tasks) {
          debug('任务列表数据异常', {
            status: data?.status,
            response: data?.response
          });
          logStatus.error(`Error:${data?.statusText}(${data?.status})`);
          return false;
        }
        debug('获取到任务列表', {
          count: data.response.tasks.length
        });
        this.tasks = data.response.tasks;
        for (const task of data.response.tasks) {
          if (task.isDone) {
            debug('跳过已完成任务', {
              taskId: task.id,
              type: task.type
            });
            continue;
          }
          debug('处理任务', {
            taskId: task.id,
            category: task.category,
            type: task.type
          });
          await httpRequest({
            url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/visited`,
            method: 'GET',
            responseType: 'json',
            headers: {
              authorization: `Bearer ${window.sessionStorage.gw_auth}`,
              'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
            }
          });
          if (task.category === 'Steam' && task.type === 'JoinGroup') {
            debug('处理 Steam 组任务');
            const steamGroupLink = await getRedirectLink(`https://steamcommunity.com/gid/${task.group_id}`);
            if (!steamGroupLink) {
              debug('获取 Steam 组链接失败');
              continue;
            }
            debug('添加 Steam 组链接', {
              action: action,
              link: steamGroupLink
            });
            if (action === 'undo') {
              this.socialTasks.steam.groupLinks.push(steamGroupLink);
            }
            if (action === 'do') {
              this.undoneTasks.steam.groupLinks.push(steamGroupLink);
            }
            continue;
          }
          if (task.category === 'Discord' && task.type === 'JoinServer') {
            const discordLink = `https://discord.gg/${task.invite_code}`;
            debug('添加 Discord 服务器链接', {
              action: action,
              link: discordLink
            });
            if (action === 'undo') {
              this.socialTasks.discord.serverLinks.push(discordLink);
            }
            if (action === 'do') {
              this.undoneTasks.discord.serverLinks.push(discordLink);
            }
            continue;
          }
          if ([ 'TikTok', 'YouTube', 'General' ].includes(task.category)) {
            debug('跳过特殊任务类型', {
              category: task.category
            });
            continue;
          }
          debug('发现未知任务类型', {
            category: task.category,
            type: task.type
          });
          echoLog({}).warning(`${I18n('unKnownTaskType')}: ${task.category}-${task.type}`);
        }
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        debug('任务分类完成', {
          undoneTasks: this.undoneTasks,
          socialTasks: this.socialTasks
        });
        GM_setValue(`giveawayHopperTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.classifyTask');
        return false;
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        for (const task of this.tasks) {
          if (task.isDone) {
            debug('跳过已完成任务', {
              taskId: task.id
            });
            continue;
          }
          debug('验证任务', {
            taskId: task.id,
            name: task.displayName?.replace(':target', task.targetName) || task.name
          });
          const logStatus = echoLog({
            text: `${I18n('verifyingTask')}[${task.displayName?.replace(':target', task.targetName) || task.name}]...`
          });
          if (!task.link) {
            debug('获取任务链接');
            task.link = this.#getTaskLink(task);
          }
          if (task.link) {
            debug('访问任务链接', {
              link: task.link
            });
            await this.#visitTaskLink(task);
          }
          await delay(1e3);
          const verifyResult = await this.#verifyTask(task, logStatus);
          debug('任务验证结果', {
            taskId: task.id,
            success: verifyResult
          });
          if (!verifyResult) {
            continue;
          }
        }
        debug('所有任务验证完成');
        return true;
      } catch (error) {
        debug('任务验证失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.verifyTask');
        return false;
      }
    }
    #getTaskLink(task) {
      try {
        debug('生成任务链接', {
          category: task.category,
          type: task.type
        });
        let link = '';
        if (task.category === 'YouTube' && task.type === 'FollowAccount') {
          link = `https://www.youtube.com/@${task.targetName}`;
        } else if (task.category === 'TikTok' && task.type === 'FollowAccount') {
          link = `https://www.tiktok.com/@${task.targetName}`;
        } else if (task.category === 'Steam' && task.type === 'JoinGroup') {
          link = '';
        } else if (task.category === 'Discord' && task.type === 'JoinServer') {
          link = '';
        }
        debug('生成的任务链接', {
          link: link
        });
        return link;
      } catch (error) {
        debug('生成任务链接失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.getTaskLink');
        return '';
      }
    }
    async #visitTaskLink(task) {
      debug('访问任务链接', {
        taskId: task.id,
        link: task.link
      });
      await httpRequest({
        url: `https://giveawayhopper.com/fw?url=${encodeURIComponent(task.link)}&src=campaign&src_id=${this.giveawayId}&ref=task&ref_id=${task.id}&token=${window.sessionStorage.gw_auth}`,
        method: 'GET',
        headers: {
          authorization: `Bearer ${window.sessionStorage.gw_auth}`,
          'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1])
        }
      });
    }
    async #verifyTask(task, logStatus) {
      debug('验证任务', {
        taskId: task.id,
        category: task.category,
        type: task.type
      });
      const postData = {
        taskcategory: task.category,
        taskname: task.type
      };
      if ([ 'YouTube', 'TikTok' ].includes(task.category)) {
        postData.username = '1';
      }
      const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
        url: `https://giveawayhopper.com/api/v1/campaigns/${this.giveawayId}/tasks/${task.id}/complete`,
        method: 'POST',
        headers: {
          authorization: `Bearer ${window.sessionStorage.gw_auth}`,
          'x-xsrf-token': decodeURIComponent(document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1]),
          'content-type': 'application/json'
        },
        dataType: 'json',
        data: JSON.stringify(postData)
      });
      if (result !== 'Success') {
        debug('任务验证请求失败', {
          result: result,
          statusText: statusText,
          status: status
        });
        logStatus.error(`${result}:${statusText}(${status})`);
        return false;
      }
      if (data?.status !== 200 || !data?.response?.completed) {
        debug('任务验证响应异常', {
          status: data?.status,
          response: data?.response
        });
        logStatus.error(`Error:${data?.statusText}(${data?.status})`);
        return false;
      }
      debug('任务验证成功', {
        taskId: task.id
      });
      logStatus.success();
      return true;
    }
    #getGiveawayId() {
      try {
        debug('从URL获取抽奖ID');
        const giveawayId = window.location.pathname.split('/').at(-1);
        if (!giveawayId) {
          debug('获取抽奖ID失败');
          echoLog({
            text: I18n('getFailed', 'GiveawayId')
          });
          return false;
        }
        this.giveawayId = giveawayId;
        debug('获取抽奖ID成功', {
          giveawayId: giveawayId
        });
        return true;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'GiveawayHopper.getGiveawayId');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        const needLogin = $('div.widget-connections-edit:contains("Log in")').length > 0;
        if (needLogin) {
          debug('未登录,自动点击登录按钮');
          $('div.widget-connections-edit:contains("Log in") a')[0].click();
        }
        debug('登录检查完成', {
          needLogin: needLogin
        });
        return true;
      } catch (error) {
        debug('登录检查失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.checkLogin');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const keyCount = parseInt($('p.widget-single-prize span').text()?.match(/\d+/)?.[0] || '0', 10);
        debug('剩余密钥数量', {
          keyCount: keyCount
        });
        if (keyCount > 0) {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('noKeysLeft'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'GiveawayHopper.checkLeftKey');
        return false;
      }
    }
  }
  const defaultTasksTemplate = {
    steam: {
      groupLinks: [],
      curatorLinks: [],
      wishlistLinks: [],
      followLinks: []
    },
    youtube: {
      channelLinks: []
    }
  };
  const defaultTasks = JSON.stringify(defaultTasksTemplate);
  class Prys extends Website {
    name='Prys';
    socialTasks=JSON.parse(defaultTasks);
    undoneTasks=JSON.parse(defaultTasks);
    buttons=[ 'doTask', 'undoTask', 'verifyTask' ];
    static test() {
      const {host: host} = window.location;
      const isMatch = host === 'prys.revadike.com';
      debug('检查网站匹配', {
        host: host,
        isMatch: isMatch
      });
      return isMatch;
    }
    async after() {
      try {
        debug('开始执行后续操作');
        if (!this.#checkLogin()) {
          debug('检查登录失败');
          echoLog({}).warning(I18n('checkLoginFailed'));
        }
        if (!await this.#checkLeftKey()) {
          debug('检查剩余密钥失败');
          echoLog({}).warning(I18n('checkLeftKeyFailed'));
        }
      } catch (error) {
        debug('后续操作失败', {
          error: error
        });
        throwError(error, 'Prys.after');
      }
    }
    init() {
      try {
        debug('开始初始化');
        const logStatus = echoLog({
          text: I18n('initing')
        });
        if ($('button:contains("Sign")').length > 0) {
          debug('需要登录');
          logStatus.warning(I18n('needLogin'));
          return false;
        }
        if (!this.#getGiveawayId()) {
          debug('获取抽奖ID失败');
          return false;
        }
        this.initialized = true;
        debug('初始化完成');
        logStatus.success();
        return true;
      } catch (error) {
        debug('初始化失败', {
          error: error
        });
        throwError(error, 'Prys.init');
        return false;
      }
    }
    async classifyTask(action) {
      try {
        debug('开始分类任务', {
          action: action
        });
        const logStatus = echoLog({
          text: I18n('getTasksInfo')
        });
        if (action === 'undo') {
          debug('恢复已保存的任务信息');
          this.socialTasks = GM_getValue(`prysTasks-${this.giveawayId}`)?.tasks || JSON.parse(defaultTasks);
        }
        const steps = $('#steps tbody tr');
        debug('找到任务步骤', {
          count: steps.length
        });
        for (let eq = 0; eq < steps.length; eq += 1) {
          if (steps.eq(eq).find('span:contains(Success)').length === 0) {
            debug('点击检查按钮', {
              step: eq
            });
            checkClick(eq);
          }
        }
        const pro = [];
        for (const step of steps) {
          const isSuccess = $(step).find('span:contains(Success)').length > 0;
          if (isSuccess && action === 'do') {
            debug('跳过已完成的任务');
            continue;
          }
          const appLink = $(step).find('a[href*=\'store.steampowered.com/app/\']').attr('href');
          if (appLink) {
            const taskType = $(step).find('a[href*=\'store.steampowered.com/app/\']').text().includes('wishlist') ? 'wishlistLinks' : 'followLinks';
            debug('添加 Steam 应用任务', {
              type: taskType,
              link: appLink
            });
            if (action === 'undo') {
              this.socialTasks.steam[taskType].push(appLink);
            }
            if (action === 'do') {
              this.undoneTasks.steam[taskType].push(appLink);
            }
            continue;
          }
          const curatorLink = $(step).find('a[href*=\'store.steampowered.com/curator/\']').attr('href');
          if (curatorLink) {
            debug('添加 Steam 鉴赏家任务', {
              link: curatorLink
            });
            if (action === 'undo') {
              this.socialTasks.steam.curatorLinks.push(curatorLink);
            }
            if (action === 'do') {
              this.undoneTasks.steam.curatorLinks.push(curatorLink);
            }
            continue;
          }
          const groupLink = $(step).find('a[href*=\'steamcommunity.com/groups/\']').attr('href');
          if (groupLink) {
            debug('添加 Steam 组任务', {
              link: groupLink
            });
            if (action === 'undo') {
              this.socialTasks.steam.groupLinks.push(groupLink);
            }
            if (action === 'do') {
              this.undoneTasks.steam.groupLinks.push(groupLink);
            }
            continue;
          }
          const gidLink = $(step).find('a[href*=\'steamcommunity.com/gid\']').attr('href');
          if (gidLink) {
            debug('处理 Steam GID 链接', {
              link: gidLink
            });
            pro.push(getRedirectLink(gidLink).then((finalUrl => {
              if (!finalUrl || !/^https?:\/\/steamcommunity\.com\/groups\//.test(finalUrl)) {
                debug('无效的 Steam 组链接', {
                  finalUrl: finalUrl
                });
                return false;
              }
              debug('添加 Steam 组任务(从 GID)', {
                link: finalUrl
              });
              if (action === 'undo') {
                this.socialTasks.steam.groupLinks.push(finalUrl);
              }
              if (action === 'do') {
                this.undoneTasks.steam.groupLinks.push(finalUrl);
              }
            })));
          }
        }
        await Promise.allSettled(pro);
        debug('任务分类完成');
        logStatus.success();
        this.undoneTasks = this.uniqueTasks(this.undoneTasks);
        this.socialTasks = this.uniqueTasks(this.socialTasks);
        if (window.DEBUG) {
          console.log('%cAuto-Task[Debug]:', 'color:blue', JSON.stringify(this));
        }
        GM_setValue(`prysTasks-${this.giveawayId}`, {
          tasks: this.socialTasks,
          time: (new Date).getTime()
        });
        return true;
      } catch (error) {
        debug('任务分类失败', {
          error: error
        });
        throwError(error, 'Prys.classifyTask');
        return false;
      }
    }
    async verifyTask() {
      try {
        debug('开始验证任务');
        const checks = $('#steps tbody a[id^=check]');
        if (checks.length === 0) {
          debug('没有需要验证的任务');
          echoLog({}).success(I18n('allTasksComplete'));
          return;
        }
        const pro = [];
        for (const check of checks) {
          const id = $(check).attr('id')?.match(/[\d]+/)?.[0];
          if (!id) {
            debug('跳过无效任务ID');
            continue;
          }
          const taskDes = $(check).parent()?.prev()?.html()?.trim();
          debug('验证任务', {
            id: id,
            taskDes: taskDes
          });
          const status = echoLog({
            text: `${I18n('verifyingTask')}${taskDes}...`
          });
          pro.push(new Promise((resolve => {
            this.#checkStep(id, resolve, status);
          })));
        }
        await Promise.all(pro);
        debug('所有任务验证完成');
        echoLog({}).success(I18n('allTasksComplete'));
      } catch (error) {
        debug('验证任务失败', {
          error: error
        });
        throwError(error, 'Prys.verifyTask');
      }
    }
    #getGiveawayId() {
      try {
        debug('开始获取抽奖ID');
        const giveawayId = window.location.search.match(/id=([\d]+)/)?.[1];
        if (giveawayId) {
          this.giveawayId = giveawayId;
          debug('获取抽奖ID成功', {
            giveawayId: giveawayId
          });
          return true;
        }
        debug('获取抽奖ID失败');
        echoLog({}).error(I18n('getFailed', 'GiveawayId'));
        return false;
      } catch (error) {
        debug('获取抽奖ID出错', {
          error: error
        });
        throwError(error, 'Prys.getGiveawayId');
        return false;
      }
    }
    async #checkLeftKey() {
      try {
        debug('检查剩余密钥');
        if (!globalOptions.other.checkLeftKey) {
          debug('跳过密钥检查');
          return true;
        }
        const leftKey = $('#header').text().match(/([\d]+).*?prize.*?left/)?.[1];
        debug('检查剩余密钥数量', {
          leftKey: leftKey
        });
        if (leftKey !== '0') {
          return true;
        }
        debug('没有剩余密钥,显示确认对话框');
        const {value: value} = await Swal.fire({
          icon: 'warning',
          title: I18n('notice'),
          text: I18n('noKeysLeft'),
          confirmButtonText: I18n('confirm'),
          cancelButtonText: I18n('cancel'),
          showCancelButton: true
        });
        if (value) {
          debug('用户确认关闭窗口');
          window.close();
        }
        return true;
      } catch (error) {
        debug('检查剩余密钥失败', {
          error: error
        });
        throwError(error, 'Prys.checkLeftKey');
        return false;
      }
    }
    #checkLogin() {
      try {
        debug('检查登录状态');
        if (!globalOptions.other.checkLogin) {
          debug('跳过登录检查');
          return true;
        }
        if ($('button:contains("Sign")').length > 0) {
          debug('未登录');
          echoLog({}).warning(I18n('needLogin'));
        }
        debug('登录检查完成');
        return true;
      } catch (error) {
        debug('检查登录失败', {
          error: error
        });
        throwError(error, 'Prys.checkLogin');
        return false;
      }
    }
    #checkStep(step, resolve, status, captcha = null) {
      try {
        debug('开始检查步骤', {
          step: step,
          hasCaptcha: !!captcha
        });
        if (step !== 'captcha') {
          debug('更新步骤状态为检查中');
          $(`#check${step}`).replaceWith(`<span id="check${step}"><i class="fa fa-refresh fa-spin fa-fw"></i> Checking...</span>`);
        }
        debug('发送检查请求');
        $.post('/api/check_step', {
          step: step,
          id: getURLParameter('id'),
          'g-recaptcha-response': captcha
        }, (json => {
          resolve();
          debug('收到检查响应', {
            success: json.success
          });
          if (step !== 'captcha') {
            if (json.success) {
              debug('步骤检查成功');
              $(`#check${step}`).replaceWith(`<span class="text-success" id="check${step}"><i class="fa fa-check"></i> Success</span>`);
              status.success();
            } else {
              debug('步骤检查失败');
              $(`#check${step}`).replaceWith(`<a id="check${step}" href="javascript:checkStep(${step})"><i class="fa fa-question"></i> Check</a>`);
              status.error(json.response?.error || 'Error');
            }
          }
          if (!json.response) {
            return;
          }
          if (json.response.prize) {
            debug('获得奖品', {
              prize: json.response.prize
            });
            showAlert('success', `Here is your prize:<h1 role="button" align="middle" style="word-wrap: break-word;">${json.response.prize}</h2>`);
          }
          if (!json.response.captcha) {
            return;
          }
          debug('需要验证码');
          if (json.success) {
            showAlert('info', json.response.captcha);
          } else {
            showAlert('warning', json.response.captcha);
          }
          captchaCheck();
        })).fail((() => {
          resolve();
          debug('请求失败');
          $(`#check${step}`).replaceWith(`<a id="check${step}" href="javascript:checkStep(${step})"><i class="fa fa-question"></i> Check</a>`);
          status.error('Error:0');
        }));
      } catch (error) {
        debug('检查步骤失败', {
          error: error
        });
        throwError(error, 'prys.checkStep');
        resolve(false);
      }
    }
  }
  const Websites = [ FreeAnyWhere, GiveawaySu, Indiedb, Keyhub, Givekey, GiveeClub, OpiumPulses, Keylol, Opquests, Gleam, SweepWidget, Setting, History, GiveawayHopper, Prys ];
  const generateFormHtml = options => {
    debug('开始生成网站选项表单HTML', {
      options: options
    });
    const tableRows = Object.entries(options).map((([option, value]) => `\n      <tr>\n        <td>${option}</td>\n        <td>\n          <input\n            class="editOption"\n            type="text"\n            name="${option}"\n            value="${value}"\n          />\n        </td>\n      </tr>\n    `)).join('');
    const formHtml = `\n    <form id="websiteOptionsForm" class="auto-task-form">\n      <table class="auto-task-table">\n        <thead>\n          <tr>\n            <td>${I18n('option')}</td>\n            <td>${I18n('value')}</td>\n          </tr>\n        </thead>\n        <tbody>\n          ${tableRows}\n        </tbody>\n      </table>\n    </form>\n  `;
    debug('表单HTML生成完成');
    return formHtml;
  };
  const saveOptions = (website, options, formValues) => {
    debug('开始保存网站选项', {
      website: website,
      formValues: formValues
    });
    formValues.forEach((({name: name, value: value}) => {
      options[name] = value;
      debug('更新选项值', {
        name: name,
        value: value
      });
    }));
    GM_setValue(`${website}Options`, options);
    debug('选项已保存到存储', {
      website: website
    });
    Swal.fire({
      title: I18n('changeWebsiteOptionsSuccess'),
      icon: 'success'
    });
  };
  const websiteOptions = async (website, options) => {
    try {
      debug('开始设置网站选项', {
        website: website
      });
      if (!website || typeof website !== 'string') {
        debug('无效的网站参数', {
          website: website
        });
        throw new Error('Invalid website parameter');
      }
      if (!options || typeof options !== 'object') {
        debug('无效的选项参数', {
          options: options
        });
        throw new Error('Invalid options parameter');
      }
      debug('显示选项编辑对话框');
      const result = await Swal.fire({
        title: I18n('websiteOptions'),
        html: generateFormHtml(options),
        showConfirmButton: true,
        confirmButtonText: I18n('save'),
        showCancelButton: true,
        cancelButtonText: I18n('close')
      });
      if (result.isConfirmed) {
        debug('用户确认保存选项');
        const form = document.getElementById('websiteOptionsForm');
        if (!form) {
          debug('未找到表单元素');
          throw new Error('Form element not found');
        }
        const formData = $('#websiteOptionsForm').serializeArray();
        debug('获取表单数据', {
          formData: formData
        });
        saveOptions(website, options, formData);
      } else {
        debug('用户取消保存选项');
      }
    } catch (error) {
      debug('设置网站选项时发生错误', {
        error: error
      });
      throwError(error, 'websiteOptions');
    }
  };
  const UPDATE_LINKS = {
    github: 'https://github.com/HCLonely/auto-task/raw/main/',
    jsdelivr: 'https://cdn.jsdelivr.net/gh/HCLonely/auto-task@main/',
    standby: 'https://auto-task.hclonely.com/'
  };
  const checkUpdate = async (updateLink, auto) => {
    try {
      debug('开始检查更新', {
        updateLink: updateLink,
        auto: auto
      });
      const checkUrl = `${updateLink}package.json?time=${Date.now()}`;
      debug('构建检查URL', {
        checkUrl: checkUrl
      });
      const {result: result, statusText: statusText, status: status, data: data} = await httpRequest({
        url: checkUrl,
        responseType: 'json',
        method: 'GET',
        timeout: 3e4
      });
      if (result === 'Success' && data?.response?.version) {
        debug('成功获取更新信息', {
          version: data.response.version
        });
        return data.response;
      }
      if (!auto) {
        const errorMessage = data?.response?.version ? `${I18n('checkUpdateFailed')}[${data?.statusText}(${data?.status})]` : `${I18n('checkUpdateFailed')}[${result}:${statusText}(${status})]`;
        debug('检查更新失败', {
          errorMessage: errorMessage
        });
        echoLog({}).error(errorMessage);
      } else {
        debug('自动检查更新失败', {
          result: result,
          statusText: statusText,
          status: status
        });
      }
      return false;
    } catch (error) {
      debug('检查更新发生错误', {
        error: error
      });
      throwError(error, 'checkUpdate');
      return false;
    }
  };
  const hasNewVersion = (currentVersion, remoteVersion) => {
    try {
      debug('开始比较版本号', {
        currentVersion: currentVersion,
        remoteVersion: remoteVersion
      });
      const [currentRealVersion] = currentVersion.split('-');
      const [remoteRealVersion, isPreview] = remoteVersion.split('-');
      if (isPreview && !globalOptions.other.receivePreview) {
        debug('不接收预览版本', {
          isPreview: isPreview
        });
        return false;
      }
      const currentVersionParts = currentRealVersion.split('.').map(Number);
      const remoteVersionParts = remoteRealVersion.split('.').map(Number);
      debug('版本号解析', {
        currentVersionParts: currentVersionParts,
        remoteVersionParts: remoteVersionParts
      });
      for (let i = 0; i < 3; i++) {
        if (remoteVersionParts[i] > currentVersionParts[i]) {
          debug('发现新版本', {
            position: i,
            current: currentVersion,
            remote: remoteVersion
          });
          return true;
        }
        if (remoteVersionParts[i] < currentVersionParts[i]) {
          debug('远程版本较旧', {
            position: i,
            current: currentVersion,
            remote: remoteVersion
          });
          return false;
        }
      }
      debug('版本号相同');
      return false;
    } catch (error) {
      debug('比较版本号时发生错误', {
        error: error
      });
      throwError(error, 'compareVersion');
      return false;
    }
  };
  const getUpdateLink = updateSource => {
    debug('获取更新链接', {
      updateSource: updateSource
    });
    const source = updateSource.toLowerCase();
    const link = UPDATE_LINKS[source] || UPDATE_LINKS.github;
    debug('选择的更新链接', {
      source: source,
      link: link
    });
    return link;
  };
  const showUpdateInfo = (packageData, currentVersion, updateLink) => {
    debug('准备显示更新信息', {
      currentVersion: currentVersion,
      newVersion: packageData.version
    });
    if (hasNewVersion(currentVersion, packageData.version)) {
      const scriptUrl = `${updateLink}dist/${GM_info.script.name}.user.js`;
      debug('发现新版本,显示更新通知', {
        scriptUrl: scriptUrl
      });
      echoLog({
        html: `<li><font>${I18n('newVersionNotice', packageData.version, scriptUrl)}</font></li>`
      });
      const changeList = packageData.change?.map((change => `<li>${change}</li>`)).join('') || '';
      debug('显示更新日志', {
        changeListLength: packageData.change?.length
      });
      echoLog({
        html: `<li>${I18n('updateText', packageData.version)}</li><ol class="update-text">${changeList}<li>${I18n('updateHistory')}</li></ol>`
      });
    } else {
      debug('当前已是最新版本');
    }
  };
  const updateChecker = async () => {
    try {
      debug('开始检查更新流程');
      const currentVersion = GM_info.script.version;
      const updateSource = globalOptions.other.autoUpdateSource;
      debug('当前配置', {
        currentVersion: currentVersion,
        updateSource: updateSource
      });
      let packageData = false;
      if ([ 'github', 'jsdelivr', 'standby' ].includes(updateSource.toLowerCase())) {
        debug('使用指定的更新源', {
          updateSource: updateSource
        });
        const updateLink = getUpdateLink(updateSource);
        packageData = await checkUpdate(updateLink, false);
      } else {
        debug('按优先级尝试不同的更新源');
        for (const source of [ 'github', 'jsdelivr', 'standby' ]) {
          debug('尝试更新源', {
            source: source
          });
          packageData = await checkUpdate(UPDATE_LINKS[source], true);
          if (packageData) {
            debug('成功获取更新信息', {
              source: source
            });
            break;
          }
        }
      }
      if (!packageData) {
        debug('所有更新源检查失败');
        echoLog({}).error(I18n('checkUpdateFailed'));
        return;
      }
      showUpdateInfo(packageData, currentVersion, getUpdateLink(updateSource));
    } catch (error) {
      debug('更新检查过程发生错误', {
        error: error
      });
      throwError(error, 'updateChecker');
    }
  };
  const byteToHex = [];
  for (let i = 0; i < 256; ++i) {
    byteToHex.push((i + 256).toString(16).slice(1));
  }
  function unsafeStringify(arr, offset = 0) {
    return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
  }
  let getRandomValues;
  const rnds8 = new Uint8Array(16);
  function rng() {
    if (!getRandomValues) {
      if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
        throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
      }
      getRandomValues = crypto.getRandomValues.bind(crypto);
    }
    return getRandomValues(rnds8);
  }
  const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
  var native = {
    randomUUID: randomUUID
  };
  function v4(options, buf, offset) {
    if (native.randomUUID && true && !options) {
      return native.randomUUID();
    }
    options = options || {};
    const rnds = options.random ?? options.rng?.() ?? rng();
    if (rnds.length < 16) {
      throw new Error('Random bytes length must be >= 16');
    }
    rnds[6] = rnds[6] & 15 | 64;
    rnds[8] = rnds[8] & 63 | 128;
    return unsafeStringify(rnds);
  }
  function fawExtension() {
    const hostname = window.location.hostname;
    function IsJsonString(str) {
      try {
        JSON.parse(str);
      } catch (e) {
        return false;
      }
      return true;
    }
    $(window).on('load', (function() {
      console.log('👌 gamesforfarm extension');
      if (hostname == 'freeanywhere.net' || hostname == 'give.gamesforfarm.local' || hostname == 'gamesforfarm-testing.ru') {
        const steam = $('.games_for_farm_site').data('steam');
        const avatar = $('.games_for_farm_site').data('avatar');
        const name = $('.games_for_farm_site').data('name');
        const lang = $('.games_for_farm_site').data('lang');
        let need_update = true;
        GM_addValueChangeListener('FAW_STORAGE', (function(newValue, oldValue) {
          if (need_update == false) {
            return;
          }
          GM_getValue('FAW_STORAGE', (function(STORAGE) {
            $.ajax({
              type: 'POST',
              url: '/php/extension/user_data_update.php',
              data: {
                extension: JSON.stringify(STORAGE)
              },
              success: function(data) {}
            });
          }));
        }));
        const STORAGE = GM_getValue('FAW_STORAGE') || {};
        if (Object.keys(STORAGE).length === 0 || !STORAGE['tasks'] || !STORAGE['user'] || !STORAGE['games'] || !STORAGE['settings']) {
          GM_deleteValue('FAW_STORAGE');
          let new_storage = {};
          new_storage['tasks'] = {};
          new_storage['user'] = {};
          new_storage['games'] = {};
          new_storage['settings'] = {};
          if (steam) {
            new_storage['user']['steam'] = steam;
          }
          if (avatar) {
            new_storage['user']['avatar'] = avatar;
          }
          if (name) {
            new_storage['user']['name'] = name;
          }
          if (lang) {
            new_storage['user']['lang'] = lang;
          }
          if (steam) {
            $.ajax({
              type: 'POST',
              url: '/php/extension/user_games_get.php',
              data: {
                steam: steam
              },
              success: function(data) {
                if (data != '' && IsJsonString(data)) {
                  const user_games = JSON.parse(data);
                  new_storage['games'] = user_games;
                  new_storage['settings']['game_update'] = parseInt(Date.now() / 1e3);
                  GM_setValue('FAW_STORAGE', new_storage);
                }
              }
            });
          } else {
            GM_setValue('FAW_STORAGE', new_storage);
          }
        }
        if (STORAGE['user'] && STORAGE['settings'] && STORAGE['user']['steam']) {
          if (!STORAGE['settings']['game_update']) {
            STORAGE['settings']['game_update'] = 0;
          }
          let time_now = parseInt(Date.now() / 1e3);
          let time_update = parseInt(STORAGE['settings']['game_update']);
          if (time_now - time_update > 60 * 60 * 24) {
            $.ajax({
              type: 'POST',
              url: '/php/extension/user_games_get.php',
              data: {
                steam: STORAGE['user']['steam']
              },
              success: function(data) {
                if (data != '' && IsJsonString(data)) {
                  const games = JSON.parse(data);
                  STORAGE['games'] = games;
                  STORAGE['settings']['game_update'] = parseInt(Date.now() / 1e3);
                  GM_setValue('FAW_STORAGE', STORAGE);
                }
              }
            });
          }
        }
        if (steam && STORAGE['user']) {
          if (!STORAGE['user']['steam']) {
            STORAGE['user']['steam'] = steam;
          }
          if (STORAGE['user']['steam'] != steam) {
            $.ajax({
              type: 'POST',
              url: '/php/extension/user_data_get.php',
              data: {
                steam: steam
              },
              success: function(data) {
                if (!data) {
                  return;
                }
                const db_storage = JSON.parse(data);
                if (db_storage) {
                  GM_deleteValue('FAW_STORAGE');
                  need_update = false;
                  GM_setValue('FAW_STORAGE', db_storage);
                  setTimeout((function() {
                    need_update = true;
                  }), 100);
                }
              }
            });
          } else {
            if (avatar) {
              STORAGE['user']['avatar'] = avatar;
            }
            if (name) {
              STORAGE['user']['name'] = name;
            }
            if (lang) {
              STORAGE['user']['lang'] = lang;
            }
            GM_setValue('FAW_STORAGE', STORAGE);
          }
        }
        if (STORAGE['tasks']) {
          let update_tasks = [];
          let is_update = false;
          let time_now = parseInt(Date.now() / 1e3);
          $.each(STORAGE['tasks'], (function(index, val) {
            if (val['time'] && time_now - parseInt(val['time']) > 2 * 60 * 60) {
              is_update = true;
              return;
            }
            update_tasks.push(val);
          }));
          if (is_update == true) {
            STORAGE['tasks'] = update_tasks;
            GM_setValue('FAW_STORAGE', STORAGE);
          }
        }
        if (STORAGE['discord']) {
          if (STORAGE['discord'] && STORAGE['discord'].length > 0) {
            $.ajax({
              type: 'POST',
              url: '/php/extension/discord_levels_update.php',
              data: {
                discord: JSON.stringify(STORAGE['discord'])
              },
              success: function(data) {
                if (data.indexOf('success') != -1) {
                  alert('Данные discord уровней обновлены');
                  delete STORAGE['discord'];
                  GM_setValue('FAW_STORAGE', STORAGE);
                } else {
                  alert('Возникла ошибка при обновлении discord уровней');
                  delete STORAGE['discord'];
                  GM_setValue('FAW_STORAGE', STORAGE);
                }
              },
              error: function() {
                alert('Возникла ошибка при обновлении discord уровней');
                delete STORAGE['discord'];
                GM_setValue('FAW_STORAGE', STORAGE);
              }
            });
          }
        }
        function check_tasks_button() {
          let tasks_done = true;
          $('.game__content-tasks__task').each((function(index, el) {
            if ($(this).hasClass('done') == false) {
              tasks_done = false;
            }
          }));
          if (tasks_done == true) {
            $('.js-get-key').removeClass('inactive');
          } else {
            $('.js-get-key').addClass('inactive');
          }
        }
        if ($('.games_for_farm_extension.work').length > 0) {
          $('.games_for_farm_extension.not_work').remove();
          $('.games_for_farm_extension.work').slideDown(200);
        }
        if ($('.game__content-tasks__task .task-check-extension').length > 0) {
          $('.task-check-extension').removeClass('js-extentions-modal');
          $('.game__content-tasks__task[data-extension=\'1\'] .task-link a').removeClass('js-extentions-modal');
          $('.game__content-tasks__task .task-check-extension').on('click', (function(event) {
            event.preventDefault();
            let $button = $(this);
            if ($button.hasClass('loading')) {
              return;
            }
            let $parrent = $(this).parent('.game__content-tasks__task');
            const type = $parrent.data('type');
            const id = $parrent.data('id');
            const data = $parrent.data('data');
            const extension = $parrent.data('extension');
            if (extension == false) {
              return;
            }
            $button.addClass('loading');
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            $.ajax({
              type: 'POST',
              url: '/php/extension/user_data_update.php',
              data: {
                extension: JSON.stringify(STORAGE)
              },
              success: function(update) {
                const getTime_start = (new Date).getTime();
                $.ajax({
                  type: 'POST',
                  url: '/php/extension/user_task_update.php',
                  data: {
                    id: id,
                    type: type,
                    data: data
                  },
                  success: function(data) {
                    const getTime_end = (new Date).getTime();
                    console.log('👌 checking task in ' + (getTime_end - getTime_start) + ' ms');
                    if (data.indexOf('good') != -1) {
                      setTimeout((function() {
                        $parrent.addClass('done');
                        $parrent.removeClass('error');
                        $button.removeClass('loading');
                        check_tasks_button();
                      }), 1250);
                    } else if (data.indexOf('bad') != -1) {
                      setTimeout((function() {
                        $parrent.addClass('error');
                        $parrent.removeClass('done');
                        $button.removeClass('loading');
                        check_tasks_button();
                      }), 1250);
                    } else {
                      setTimeout((function() {
                        $parrent.removeClass('error');
                        $parrent.removeClass('done');
                        $button.removeClass('loading');
                        check_tasks_button();
                      }), 1250);
                    }
                  },
                  error: function() {
                    setTimeout((function() {
                      $parrent.removeClass('error');
                      $parrent.removeClass('done');
                      $button.removeClass('loading');
                      check_tasks_button();
                    }), 1250);
                  }
                });
              },
              error: function() {
                setTimeout((function() {
                  $parrent.removeClass('error');
                  $parrent.removeClass('done');
                  $button.removeClass('loading');
                  check_tasks_button();
                }), 1250);
              }
            });
          }));
        }
      }
      function storage_tasks_update(tasks, type, value, action) {
        let result = [];
        let is_find = false;
        $.each(tasks, (function(index, val) {
          if (!val['type'] || !val['data']) {
            return;
          }
          if (val['type'] == type && val['data'] == value) {
            is_find = true;
            return;
          }
          result.push(val);
        }));
        const obj = {};
        switch (action) {
         case 'add':
          if (is_find == true) {
            return;
          }
          const task = {};
          task['type'] = type;
          task['data'] = value;
          task['time'] = parseInt(Date.now() / 1e3);
          result.push(task);
          obj['tasks'] = result;
          GM_setValue('FAW_STORAGE', obj);
          break;

         case 'remove':
          if (is_find == false) {
            return;
          }
          obj['tasks'] = result;
          GM_setValue('FAW_STORAGE', obj);
        }
      }
      if (hostname == 'store.steampowered.com' || hostname == 'steamcommunity.com') {
        if (document.querySelector('span[id^=\'CuratorUnFollowBtn_\']')) {
          const curator_id = $('span[id^=\'CuratorUnFollowBtn_\']').attr('id').split('_')[1];
          const follow_btn = '#CuratorFollowBtn_' + curator_id;
          const unfollow_btn = '#CuratorUnFollowBtn_' + curator_id;
          const STORAGE = GM_getValue('FAW_STORAGE') || {};
          if (!STORAGE['tasks']) {
            return;
          }
          const follow = $(follow_btn).css('display');
          const unfollow = $(unfollow_btn).css('display');
          if (unfollow && unfollow == 'none') {
            storage_tasks_update(STORAGE['tasks'], 'steam_curator_sub', curator_id, 'remove');
          }
          if (follow && follow == 'none') {
            storage_tasks_update(STORAGE['tasks'], 'steam_curator_sub', curator_id, 'add');
          }
          $(follow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_curator_sub', curator_id, 'add');
          }));
          $(unfollow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_curator_sub', curator_id, 'remove');
          }));
        }
        if (document.querySelector('.followStatsBlock')) {
          const user_id = $('#HeaderUserInfoName a').attr('href').split('/').pop();
          const follow_btn = '#FollowUserOptionAdd';
          const unfollow_btn = '#FollowUserOptionFollowing, .followOption.remove';
          const STORAGE = GM_getValue('FAW_STORAGE') || {};
          if (!STORAGE['tasks']) {
            return;
          }
          const follow = $(follow_btn).css('visibility');
          const unfollow = $(unfollow_btn).css('visibility');
          if (unfollow && unfollow == 'hidden') {
            storage_tasks_update(STORAGE['tasks'], 'steam_guides_sub', user_id, 'remove');
          }
          if (follow && follow == 'hidden') {
            storage_tasks_update(STORAGE['tasks'], 'steam_guides_sub', user_id, 'add');
          }
          $(follow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_guides_sub', user_id, 'add');
          }));
          $(unfollow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_guides_sub', user_id, 'remove');
          }));
        }
        if (document.querySelector('#ScrollingItemControls')) {
          const manual_id = $('#PublishedFileFavorite input[name=\'id\']').val();
          const follow_btn = '#FavoriteItemOptionAdd';
          const unfollow_btn = '#FavoriteItemOptionFavorited, .favoriteOption.removefavorite';
          const STORAGE = GM_getValue('FAW_STORAGE') || {};
          if (!STORAGE['tasks']) {
            return;
          }
          const follow = $(follow_btn).css('visibility');
          const unfollow = $(unfollow_btn).css('visibility');
          if (unfollow && unfollow == 'hidden') {
            storage_tasks_update(STORAGE['tasks'], 'steam_manual_favourite', manual_id, 'remove');
          }
          if (follow && follow == 'hidden') {
            storage_tasks_update(STORAGE['tasks'], 'steam_manual_favourite', manual_id, 'add');
          }
          $(follow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_manual_favourite', manual_id, 'add');
          }));
          $(unfollow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_manual_favourite', manual_id, 'remove');
          }));
        }
        if (document.querySelector('#queueBtnFollow')) {
          const game_id = $('.game_page_background').data('miniprofile-appid');
          const follow_btn = '#queueBtnFollow .queue_btn_inactive';
          const unfollow_btn = '#queueBtnFollow .queue_btn_active';
          const STORAGE = GM_getValue('FAW_STORAGE') || {};
          if (!STORAGE['tasks']) {
            return;
          }
          const follow = $(follow_btn).css('display');
          const unfollow = $(unfollow_btn).css('display');
          if (unfollow && unfollow == 'none') {
            storage_tasks_update(STORAGE['tasks'], 'steam_game_sub', game_id, 'remove');
          }
          if (follow && follow == 'none') {
            storage_tasks_update(STORAGE['tasks'], 'steam_game_sub', game_id, 'add');
          }
          $(follow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_game_sub', game_id, 'add');
          }));
          $(unfollow_btn).on('click', (function(event) {
            const STORAGE = GM_getValue('FAW_STORAGE') || {};
            if (!STORAGE['tasks']) {
              return;
            }
            storage_tasks_update(STORAGE['tasks'], 'steam_game_sub', game_id, 'remove');
          }));
        }
      }
      if (hostname == 'www.youtube.com' || hostname == 'm.youtube.com') {
        setInterval((function() {
          if (document.querySelector('yt-subscribe-button-view-model')) {
            const channel_id = $('meta[itemprop="identifier"]').attr('content');
            const subscribe = [ 'Подписаться', 'Падпісацца', 'Підписатися', 'Abonnieren', 'Subscribe', 'Suscribirse', 'Mag-subscribe', 'S\'abonner', 'Iscriviti', 'Subskrybuj', 'Subscrever', 'Abonează-te', '订阅', 'チャンネル登録', '訂閱' ];
            const subscribed = [ 'Вы подписаны', 'Вы падпісаны', 'Ви підписалися', 'Abonniert', 'Subscribed', 'Suscrito', 'Naka-subscribe', 'Abonné', 'Iscritto', 'Subskrybujesz', 'Subscrito', 'Abonat(ă)', '已订阅', '登録済み', '已訂閱' ];
            const $parent = $('yt-subscribe-button-view-model');
            const text = $parent.text();
            if (subscribe.indexOf(text) != -1 || subscribed.indexOf(text) != -1) {
              if (subscribe.indexOf(text) != -1) {
                const STORAGE = GM_getValue('FAW_STORAGE') || {};
                if (!STORAGE['tasks']) {
                  return;
                }
                storage_tasks_update(STORAGE['tasks'], 'youtube_channel_sub', channel_id, 'remove');
              }
              if (subscribed.indexOf(text) != -1) {
                const STORAGE = GM_getValue('FAW_STORAGE') || {};
                if (!STORAGE['tasks']) {
                  return;
                }
                storage_tasks_update(STORAGE['tasks'], 'youtube_channel_sub', channel_id, 'add');
              }
            } else {
              if ($('.ytSubscribePlusButtonViewModelHost').length != 0) {
                const STORAGE = GM_getValue('FAW_STORAGE') || {};
                if (!STORAGE['tasks']) {
                  return;
                }
                storage_tasks_update(STORAGE['tasks'], 'youtube_channel_sub', channel_id, 'add');
              } else {
                const color = $parent.find('button').css('color');
                if (color == '#0f0f0f' || color == 'rgb(15, 15, 15)') {
                  const STORAGE = GM_getValue('FAW_STORAGE') || {};
                  if (!STORAGE['tasks']) {
                    return;
                  }
                  storage_tasks_update(STORAGE['tasks'], 'youtube_channel_sub', channel_id, 'remove');
                }
                if (color == '#f1f1f1' || color == 'rgb(241, 241, 241)') {
                  const STORAGE = GM_getValue('FAW_STORAGE') || {};
                  if (!STORAGE['tasks']) {
                    return;
                  }
                  storage_tasks_update(STORAGE['tasks'], 'youtube_channel_sub', channel_id, 'add');
                }
              }
            }
          }
          if (document.querySelector('.ytLikeButtonViewModelHost')) {
            let video_id;
            if (hostname == 'm.youtube.com') {
              video_id = $('link[rel="canonical"]').attr('href').split('v=').pop();
            } else {
              video_id = $('meta[itemprop="identifier"]').attr('content');
            }
            if ($('.ytLikeButtonViewModelHost button').attr('aria-pressed') == 'false') {
              const STORAGE = GM_getValue('FAW_STORAGE') || {};
              if (!STORAGE['tasks']) {
                return;
              }
              storage_tasks_update(STORAGE['tasks'], 'youtube_video_like', video_id, 'remove');
            }
            if ($('.ytLikeButtonViewModelHost button').attr('aria-pressed') == 'true') {
              const STORAGE = GM_getValue('FAW_STORAGE') || {};
              if (!STORAGE['tasks']) {
                return;
              }
              storage_tasks_update(STORAGE['tasks'], 'youtube_video_like', video_id, 'add');
            }
          }
        }), 600);
      }
    }));
    if (hostname == 'mee6.xyz') {
      var message = false;
      $(document).on('keydown', '', (function(event) {
        if (event.code == 'End') {
          let USERS = [];
          $('.md\\:block').each((function(index, el) {
            const user = {};
            user['name'] = $(this).find('.justify-start p').text();
            user['level'] = $(this).find('.leaderboardPlayerStat .items-center').text();
            USERS.push(user);
            if (user['level'] == 0) {
              const obj = {};
              obj['discord'] = USERS;
              GM_setValue('FAW_STORAGE', obj);
              if (message == false) {
                alert('Можно переходить на freeanywhere.net');
                message = true;
              }
              return false;
            }
          }));
        }
      }));
    }
    if (hostname == 'gamesforfarm.com') {
      const STORAGE = GM_getValue('FAW_STORAGE') || {};
      if (!STORAGE['settings']) {
        return;
      }
      if (!STORAGE['games']) {
        return;
      }
      if (STORAGE['settings']['hide_games'] && STORAGE['settings']['hide_games'] == true) {
        $('.product__item').each((function(index, el) {
          const image = $(this).find('.product__box-image img').data('src');
          const cart = $(this).find('.product__box-props a').attr('href');
          if (image && image.indexOf('/apps/') != -1) {
            const id = parseInt(image.split('/apps/')[1].split('/')[0]);
            if (id && isNaN(id) == false) {
              if (STORAGE['games'][id]) {
                $(this).css('opacity', '.2');
              }
            }
          } else if (cart && cart.indexOf('/app/') != -1) {
            const id = parseInt(cart.split('/app/')[1].split('/')[0]);
            if (id && isNaN(id) == false) {
              if (STORAGE['games'][id]) {
                $(this).css('opacity', '.2');
              }
            }
          }
        }));
      }
    }
  }
  try {
    consoleLogHook();
  } catch (error) {
    console.error('Auto-Task[Warning]: consoleLogHook 初始化失败', error);
  }
  window.STYLE = GM_addStyle(style + GM_getResourceText('style'));
  window.DEBUG = !!globalOptions.other?.debug;
  window.TRACE = !!globalOptions.other?.debug && typeof console.trace === 'function';
  const handleTwitchAuth = async () => {
    debug('开始处理Twitch认证');
    const authToken = Cookies.get('auth-token');
    const isLogin = !!Cookies.get('login');
    if (isLogin) {
      const authData = {
        authToken: authToken,
        clientVersion: window.__twilightBuildID,
        clientId: window.commonOptions?.headers?.['Client-ID'],
        deviceId: window.commonOptions?.headers?.['Device-ID'],
        clientSessionId: window.localStorage.local_storage_app_session_id.replace(/"/g, '')
      };
      GM_setValue('twitchAuth', authData);
      window.close();
      await Swal.fire('', I18n('closePageNotice'));
    } else {
      await Swal.fire('', I18n('needLogin'));
    }
  };
  const handleRedditAuth = async () => {
    debug('开始处理Reddit认证');
    const betaButton = $('#redesign-beta-optin-btn');
    if (betaButton.length > 0) {
      betaButton[0].click();
      return;
    }
    window.close();
    await Swal.fire('', I18n('closePageNotice'));
  };
  const handleDiscordAuth = async () => {
    debug('开始处理Discord认证');
    const LocalStorage = window.localStorage;
    const allLocalStorage = getAllLocalStorageAsObjects(LocalStorage);
    const discordAuth = allLocalStorage.token;
    if (discordAuth && discordAuth.length > 0) {
      const browserInfo = await browser.getInfo();
      GM_setValue('discordAuth', {
        auth: discordAuth,
        xSuperProperties: window.btoa(JSON.stringify({
          os: browserInfo.system,
          browser: browserInfo.browser,
          device: '',
          system_locale: browserInfo.language,
          ...allLocalStorage.deviceProperties || {},
          browser_user_agent: navigator.userAgent,
          browser_version: browserInfo.browserVersion,
          os_version: browserInfo.systemVersion,
          referrer: '',
          referring_domain: '',
          referrer_current: '',
          referring_domain_current: '',
          release_channel: 'stable',
          client_build_number: unsafeWindow.GLOBAL_ENV.BUILD_NUMBER,
          client_event_source: null,
          has_client_mods: false,
          client_launch_id: v4(),
          client_heartbeat_session_id: allLocalStorage.LAST_CLIENT_HEARTBEAT_SESSION?.uuid,
          client_app_state: 'focused'
        }))
      });
      window.close();
      Swal.fire('', I18n('closePageNotice'));
    } else {
      Swal.fire({
        text: I18n('getDiscordAuthFailed'),
        icon: 'error'
      });
    }
  };
  const handleSteamStoreAuth = async () => {
    debug('开始处理Steam商店认证');
    const storeSessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1];
    if (storeSessionID) {
      GM_deleteValue('ATv4_updateStoreAuth');
      GM_setValue('steamStoreAuth', {
        storeSessionID: storeSessionID
      });
      window.close();
      await Swal.fire('', I18n('closePageNotice'));
    } else {
      await Swal.fire({
        title: 'Error: Get "sessionID" failed',
        icon: 'error'
      });
    }
  };
  const handleSteamCommunityAuth = async () => {
    debug('开始处理Steam社区认证');
    const steam64Id = document.body.innerHTML.match(/g_steamID = "(.+?)";/)?.[1];
    const communitySessionID = document.body.innerHTML.match(/g_sessionID = "(.+?)";/)?.[1];
    if (steam64Id && communitySessionID) {
      GM_deleteValue('ATv4_updateCommunityAuth');
      GM_setValue('steamCommunityAuth', {
        steam64Id: steam64Id,
        communitySessionID: communitySessionID
      });
      window.close();
      await Swal.fire('', I18n('closePageNotice'));
    } else {
      setTimeout((async () => {
        await Swal.fire({
          title: 'Error: Get "sessionID" failed',
          icon: 'error'
        });
      }), 3e3);
    }
  };
  const initializeUI = website => {
    debug('初始化UI元素', {
      website: website.name
    });
    const $body = $('body');
    $body.append(`\n    <div id="auto-task-info"\n        style="display:${globalOptions.other.defaultShowLog ? 'block' : 'none'};\n                ${globalOptions.position.logSideX}:${globalOptions.position.logDistance.split(',')[0]}px;\n                ${globalOptions.position.logSideY}:${globalOptions.position.logDistance.split(',')[1]}px;">\n    </div>\n    <div id="auto-task-buttons"\n        style="display:${globalOptions.other.defaultShowButton ? 'block' : 'none'};\n                ${globalOptions.position.buttonSideX}:${globalOptions.position.buttonDistance.split(',')[0]}px;\n                ${globalOptions.position.buttonSideY}:${globalOptions.position.buttonDistance.split(',')[1]}px;">\n    </div>\n    <div class="show-button-div"\n        style="display:${globalOptions.other.defaultShowButton ? 'none' : 'block'};\n                ${globalOptions.position.showButtonSideX}:${globalOptions.position.showButtonDistance.split(',')[0]}px;\n                ${globalOptions.position.showButtonSideY}:${globalOptions.position.showButtonDistance.split(',')[1]}px;">\n      <a class="auto-task-website-btn"\n        href="javascript:void(0);"\n        target="_self"\n        title="${I18n('showButton')}"> </a>\n    </div>\n  `);
    const $autoTaskInfo = $('#auto-task-info');
    const $autoTaskButtons = $('#auto-task-buttons');
    const $showButtonDiv = $('div.show-button-div');
    $showButtonDiv.on('click', (() => {
      $autoTaskButtons.show();
      $showButtonDiv.hide();
    }));
    if (website.buttons && $autoTaskButtons.children().length === 0) {
      $autoTaskButtons.addClass(`${website.name}-buttons`);
      for (const button of website.buttons) {
        if (website[button]) {
          const btnElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">${I18n(button)}</a></p>`);
          btnElement.find('a.auto-task-website-btn').on('click', (() => {
            website[button]();
          }));
          $autoTaskButtons.append(btnElement);
        }
      }
    }
    const hideButtonElement = $(`<p><a class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self">${I18n('hideButton')}</a></p>`);
    hideButtonElement.find('a.auto-task-website-btn').on('click', (() => {
      $autoTaskButtons.hide();
      $showButtonDiv.show();
    }));
    const toggleLogElement = $(`<p><a id="toggle-log" class="auto-task-website-btn ${website.name}-button" href="javascript:void(0);" target="_self" data-status="${globalOptions.other.defaultShowLog ? 'show' : 'hide'}">${globalOptions.other.defaultShowLog ? I18n('hideLog') : I18n('showLog')}</a></p>`);
    const toggleLog = () => {
      const $toggleLog = $('#toggle-log');
      const status = $toggleLog.attr('data-status');
      if (status === 'show') {
        $autoTaskInfo.hide();
        $toggleLog.attr('data-status', 'hide').text(I18n('showLog'));
      } else {
        $autoTaskInfo.show();
        $toggleLog.attr('data-status', 'show').text(I18n('hideLog'));
      }
    };
    toggleLogElement.find('a.auto-task-website-btn').on('click', toggleLog);
    $autoTaskButtons.append(hideButtonElement).append(toggleLogElement);
    if (website.options) {
      GM_registerMenuCommand(I18n('changeWebsiteOptions'), (() => {
        websiteOptions(website.name, website.options);
      }));
    }
  };
  const initializeHotkeys = website => {
    debug('初始化热键', {
      website: website.name
    });
    keyboardJS.bind(globalOptions.hotKey.doTaskKey, (() => {
      if (website.doTask) {
        website.doTask();
      }
    }));
    keyboardJS.bind(globalOptions.hotKey.undoTaskKey, (() => {
      if (website.undoTask) {
        website.undoTask();
      }
    }));
    keyboardJS.bind(globalOptions.hotKey.toggleLogKey, (() => {
      const $toggleLog = $('#toggle-log');
      const status = $toggleLog.attr('data-status');
      const $autoTaskInfo = $('#auto-task-info');
      if (status === 'show') {
        $autoTaskInfo.hide();
        $toggleLog.attr('data-status', 'hide').text(I18n('showLog'));
      } else {
        $autoTaskInfo.show();
        $toggleLog.attr('data-status', 'show').text(I18n('hideLog'));
      }
    }));
  };
  const checkSteamASFStatus = async () => {
    debug('检查Steam ASF状态');
    if (!globalOptions.ASF.AsfEnabled || !globalOptions.ASF.AsfIpcUrl || !globalOptions.ASF.AsfIpcPassword) {
      return;
    }
    const stopPlayTime = GM_getValue('stopPlayTime', 0) || 0;
    if (stopPlayTime === 0 || stopPlayTime >= Date.now()) {
      return;
    }
    const stopPlayTimeMinutes = Math.floor((Date.now() - stopPlayTime) / 6e4);
    await Swal.fire({
      title: I18n('stopPlayTimeTitle'),
      text: I18n('stopPlayTimeText', stopPlayTimeMinutes.toString()),
      icon: 'warning',
      confirmButtonText: I18n('confirm')
    });
    let steamASF = new SteamASF(globalOptions.ASF);
    try {
      const isInitialized = await steamASF.init();
      if (!isInitialized) {
        return;
      }
      const isGamesStopped = await steamASF.stopPlayGames();
      if (!isGamesStopped) {
        return;
      }
      const taskLink = GM_getValue('taskLink', []) || [];
      for (const link of taskLink) {
        GM_openInTab(link, {
          active: true
        });
      }
      GM_setValue('stopPlayTime', 0);
      GM_setValue('playedGames', []);
      GM_setValue('taskLink', []);
    } catch (error) {
      console.error('SteamASF operation failed:', error);
    } finally {
      steamASF = null;
    }
  };
  const checkVersionAndNotice = () => {
    debug('检查版本和通知');
    const {scriptHandler: scriptHandler} = GM_info;
    if (scriptHandler !== 'Tampermonkey') {
      debug('未知脚本管理器', {
        scriptHandler: scriptHandler
      });
      echoLog({}).warning(I18n('unknownScriptHandler'));
      return;
    }
    const [v1, v2] = GM_info.version?.split('.') || [];
    if (!(parseInt(v1, 10) >= 5 && parseInt(v2, 10) >= 2)) {
      echoLog({}).error(I18n('versionNotMatched'));
    }
    if (!GM_getValue('notice')) {
      Swal.fire({
        title: I18n('swalNotice'),
        icon: 'warning'
      }).then((() => {
        GM_openInTab(I18n('noticeLink'), {
          active: true
        });
        GM_setValue('notice', (new Date).getTime());
      }));
      echoLog({
        html: `<li><font class="warning">${I18n('echoNotice', I18n('noticeLink'))}</font></li>`
      }).font?.find('a').on('click', (() => {
        GM_setValue('notice', (new Date).getTime());
      }));
    }
  };
  const loadScript = async () => {
    debug('主程序入口 loadScript 开始');
    if (window.name === 'ATv4_twitchAuth' && window.location.hostname === 'www.twitch.tv') {
      debug('检测到Twitch认证窗口');
      await handleTwitchAuth();
      return;
    }
    if (window.name === 'ATv4_redditAuth' && window.location.hostname === 'www.reddit.com') {
      debug('检测到Reddit认证窗口');
      await handleRedditAuth();
      return;
    }
    let website;
    for (const Website of Websites) {
      if (Website.test()) {
        debug('识别到支持的网站', {
          website: Website.name
        });
        website = new Website;
        break;
      }
    }
    if (!website) {
      debug('未识别到支持的网站,脚本停止加载');
      console.log('%c%s', 'color:#ff0000', 'Auto-Task[Warning]: 脚本停止加载,当前网站不支持!');
      return;
    }
    if (website.before) {
      debug('执行网站 before 钩子');
      await website.before();
    }
    initializeUI(website);
    initializeHotkeys(website);
    if (website.after) {
      debug('执行网站 after 钩子');
      await website.after();
    }
    if (website.name !== 'Setting') {
      debug('注册全局菜单命令');
      GM_registerMenuCommand(I18n('changeGlobalOptions'), (() => {
        changeGlobalOptions('swal');
      }));
      GM_registerMenuCommand(I18n('settingPage'), (() => {
        GM_openInTab('https://auto-task.hclonely.com/setting.html', {
          active: true
        });
      }));
    }
    debug('脚本加载完成');
    console.log('%c%s', 'color:#1bbe1a', 'Auto-Task[Load]: 脚本加载完成');
    if (window.DEBUG) {
      echoLog({}).warning(I18n('debugModeNotice'));
    }
    await checkSteamASFStatus();
    checkVersionAndNotice();
    updateChecker();
  };
  try {
    debug('主程序入口开始', {
      hostname: window.location.hostname,
      windowName: window.name
    });
    if ([ 'freeanywhere.net', 'give.gamesforfarm.local', 'gamesforfarm-testing.ru', 'store.steampowered.com', 'steamcommunity.com', 'www.youtube.com', 'm.youtube.com', 'mee6.xyz', 'gamesforfarm.com' ].includes(window.location.hostname) && $('.task-check-extension').length > 0) {
      debug('检测到freeanywhere.com,加载扩展');
      fawExtension();
    }
    if (window.location.hostname === 'discord.com') {
      if (window.name === 'ATv4_discordAuth') {
        debug('检测到Discord认证窗口');
        handleDiscordAuth();
      } else {
        debug('检测到Discord主站');
        const discordAuth = window.localStorage?.getItem('token')?.replace(/^"|"$/g, '');
        if (discordAuth && discordAuth.length > 0) {
          debug('获取到Discord认证token');
          GM_setValue('discordAuth', {
            auth: discordAuth
          });
        }
      }
    } else if (window.location.hostname === 'opquests.com') {
      debug('检测到opquests.com,加载主脚本');
      loadScript();
    } else if ((window.name === 'ATv4_updateStoreAuth' || GM_getValue('ATv4_updateStoreAuth')) && window.location.host === 'store.steampowered.com') {
      debug('检测到Steam商店认证窗口');
      $((() => {
        if ($('[data-miniprofile]').length === 0) {
          return;
        }
        handleSteamStoreAuth();
      }));
    } else if ((window.name === 'ATv4_updateCommunityAuth' || GM_getValue('ATv4_updateCommunityAuth')) && window.location.host === 'steamcommunity.com') {
      debug('检测到Steam社区认证窗口');
      $((() => {
        handleSteamCommunityAuth();
      }));
    } else {
      if (window.location.hostname === 'key-hub.eu') {
        debug('检测到key-hub.eu,设置全局变量');
        unsafeWindow.keyhubtracker = 1;
        unsafeWindow.gaData = {};
      }
      debug('加载主脚本');
      $(loadScript);
    }
  } catch (error) {
    debug('主程序入口发生异常', {
      error: error
    });
  }
})(Swal, Cookies, browser, util, dayjs, keyboardJS);