// ==UserScript==
// @name Cookie获取助手
// @namespace http://tampermonkey.net/
// @version 2.2.0
// @description 帮助新手用户获取网站Cookie,仅用于学习和个人使用
// @author Your Name
// @match *://*/*
// @match about:blank
// @match about:newtab
// @grant GM_setClipboard
// @grant GM_notification
// @grant GM_openInTab
// @grant GM_cookie
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 免责声明
const DISCLAIMER = `
【免责声明】
本脚本仅用于学习和个人使用目的,帮助不熟悉技术的用户了解Cookie的获取方式。
- 本脚本不会存储、上传或泄露任何用户数据
- 所有Cookie信息仅在本地显示,不会发送到任何服务器
- 请勿将本脚本用于任何违法违规行为
- 使用本脚本即表示您同意自行承担使用风险
- 请遵守相关网站的服务条款和法律法规
`.trim();
// 平台配置
const PLATFORMS = {
xiaohongshu: {
name: '小红书',
domain: 'xiaohongshu.com',
url: 'https://www.xiaohongshu.com',
checkLogin: checkXiaohongshuLogin,
getCookie: getXiaohongshuCookie,
verifyCookie: verifyXiaohongshuCookie,
icon: '📕'
},
zhihu: {
name: '知乎',
domain: 'zhihu.com',
url: 'https://www.zhihu.com',
checkLogin: () => false, // 待实现
getCookie: () => null,
verifyCookie: null,
icon: '🔵',
disabled: true
},
douyin: {
name: '抖音',
domain: 'douyin.com',
url: 'https://www.douyin.com',
checkLogin: () => false, // 待实现
getCookie: () => null,
verifyCookie: null,
icon: '🎵',
disabled: true
},
iqiyi: {
name: '爱奇艺',
domain: 'iqiyi.com',
url: 'https://www.iqiyi.com',
checkLogin: () => false, // 待实现
getCookie: () => null,
verifyCookie: null,
icon: '🎬',
disabled: true
},
tencent: {
name: '腾讯视频',
domain: 'v.qq.com',
url: 'https://v.qq.com',
checkLogin: () => false, // 待实现
getCookie: () => null,
verifyCookie: null,
icon: '🎥',
disabled: true
}
};
// 检测当前平台
function getCurrentPlatform() {
const hostname = window.location.hostname;
for (const [key, platform] of Object.entries(PLATFORMS)) {
if (hostname.includes(platform.domain)) {
return key;
}
}
return null;
}
// 小红书登录检测(使用页面检测,避开反爬虫)
async function checkXiaohongshuLogin() {
console.log('[Cookie助手] 开始检测登录状态...');
// 方法1: 检查是否有登录按钮(未登录才有)
const loginButtons = document.querySelectorAll('button, a');
let hasLoginButton = false;
for (const btn of loginButtons) {
const text = btn.textContent.trim();
if (text === '登录' || text === '注册' || text === '登录 / 注册') {
hasLoginButton = true;
console.log('[Cookie助手] 发现登录按钮:', text);
break;
}
}
// 如果有登录按钮,肯定未登录
if (hasLoginButton) {
console.log('[Cookie助手] 登录状态: false (发现登录按钮)');
return false;
}
// 方法2: 检查是否在个人主页
const isUserPage = window.location.pathname.includes('/user/profile');
if (isUserPage) {
console.log('[Cookie助手] 登录状态: true (在个人主页)');
return true;
}
// 方法3: 检查页面标题和内容
const pageTitle = document.title;
const bodyText = document.body.textContent;
// 如果页面提示需要登录
if (bodyText.includes('登录后推荐更懂你的笔记') ||
bodyText.includes('扫码登录') ||
pageTitle.includes('登录')) {
console.log('[Cookie助手] 登录状态: false (页面提示登录)');
return false;
}
// 方法4: 检查是否有用户相关元素
const hasUserElements = document.querySelector('[class*="user-card"]') !== null ||
document.querySelector('[class*="UserCard"]') !== null ||
document.querySelector('[data-v-*][class*="avatar"]') !== null;
console.log('[Cookie助手] 登录状态:', hasUserElements, '(页面元素检测)');
return hasUserElements;
}
// 获取小红书Cookie(尝试使用GM_cookie API获取完整Cookie)
async function getXiaohongshuCookie() {
// 方法1: 尝试使用GM_cookie API(支持获取HttpOnly Cookie)
if (typeof GM_cookie !== 'undefined') {
try {
const cookies = await new Promise((resolve, reject) => {
GM_cookie.list({
domain: '.xiaohongshu.com'
}, (cookies, error) => {
if (error) {
reject(error);
} else {
resolve(cookies);
}
});
});
if (cookies && cookies.length > 0) {
// 将Cookie数组转换为字符串格式
const cookieString = cookies.map(c => `${c.name}=${c.value}`).join('; ');
return cookieString;
}
} catch (error) {
console.log('GM_cookie API不可用,使用备用方法');
}
}
// 方法2: 降级到document.cookie(只能获取非HttpOnly Cookie)
const cookies = document.cookie;
if (!cookies) {
return null;
}
return cookies;
}
// 检查Cookie是否完整
function checkCookieComplete(cookies) {
// 检查是否包含关键的HttpOnly字段
const hasWebSession = cookies.includes('web_session=');
const hasIdToken = cookies.includes('id_token=');
const hasAcwTc = cookies.includes('acw_tc=');
return {
complete: hasWebSession || hasIdToken,
missing: []
.concat(!hasWebSession ? ['web_session'] : [])
.concat(!hasIdToken ? ['id_token'] : [])
.concat(!hasAcwTc ? ['acw_tc'] : [])
};
}
// 验证小红书Cookie有效性(通过设置Cookie并测试登录)
async function verifyXiaohongshuCookie() {
try {
// 方法1: 尝试调用用户信息API
const response = await fetch('https://edith.xiaohongshu.com/api/sns/web/v1/user/selfinfo', {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://www.xiaohongshu.com/',
'User-Agent': navigator.userAgent,
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.status === 406) {
// 如果遇到406,使用备用验证方法:检查页面元素
return verifyByPageContent();
}
if (!response.ok) {
return {
valid: false,
message: `请求失败 (${response.status})`,
details: '无法连接到服务器或Cookie已失效'
};
}
const data = await response.json();
// 检查返回数据
if (data.success && data.data) {
return {
valid: true,
message: 'Cookie有效',
details: `用户: ${data.data.nickname || data.data.red_id || '已登录用户'}`,
userData: data.data
};
} else {
return {
valid: false,
message: 'Cookie无效或已过期',
details: data.msg || '请重新登录'
};
}
} catch (error) {
// 如果API调用失败,尝试备用方法
return verifyByPageContent();
}
}
// 通过设置Cookie并测试登录来验证(最准确的方法)
async function testLoginWithCookie(cookieString) {
if (typeof GM_cookie === 'undefined') {
return {
valid: false,
message: '不支持Cookie登录测试',
details: '您的油猴管理器不支持GM_cookie API,请使用Tampermonkey或Violentmonkey'
};
}
try {
// 解析Cookie字符串
const cookiePairs = cookieString.split(';').map(c => c.trim());
const cookieMap = {};
cookiePairs.forEach(pair => {
const [name, ...valueParts] = pair.split('=');
if (name) {
cookieMap[name.trim()] = valueParts.join('=');
}
});
// 获取当前域名
const currentDomain = window.location.hostname;
// 确定Cookie域名(使用当前域名或其父域名)
let cookieDomain = currentDomain;
if (currentDomain.includes('xiaohongshu.com')) {
// 对于小红书,尝试使用当前完整域名
cookieDomain = currentDomain;
}
// 设置关键Cookie
const criticalCookies = ['web_session', 'a1', 'webId', 'id_token', 'acw_tc', 'xsecappid', 'websectiga', 'sec_poison_id'];
let setCount = 0;
let failedCookies = [];
for (const name of criticalCookies) {
if (cookieMap[name]) {
try {
await new Promise((resolve, reject) => {
// 尝试不同的域名设置
const cookieOptions = {
name: name,
value: cookieMap[name],
url: window.location.href, // 使用当前URL而不是domain
path: '/',
secure: window.location.protocol === 'https:',
httpOnly: name === 'web_session' || name === 'id_token'
};
GM_cookie.set(cookieOptions, (error) => {
if (error) {
console.log(`设置Cookie ${name} 失败:`, error);
failedCookies.push(name);
resolve(); // 继续设置其他Cookie
} else {
console.log(`设置Cookie ${name} 成功`);
setCount++;
resolve();
}
});
});
} catch (e) {
console.log(`设置Cookie ${name} 异常:`, e);
failedCookies.push(name);
}
}
}
console.log(`成功设置 ${setCount} 个Cookie,失败 ${failedCookies.length} 个`);
if (failedCookies.length > 0) {
console.log('失败的Cookie:', failedCookies.join(', '));
}
if (setCount === 0) {
return {
valid: false,
message: 'Cookie设置失败',
details: '未找到关键Cookie字段或全部设置失败。请确保Cookie格式正确。'
};
}
// 等待Cookie设置生效
await new Promise(resolve => setTimeout(resolve, 1000));
// 测试登录:调用API
const response = await fetch('https://edith.xiaohongshu.com/api/sns/web/v1/user/selfinfo', {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Referer': 'https://www.xiaohongshu.com/',
'User-Agent': navigator.userAgent,
'X-Requested-With': 'XMLHttpRequest'
}
});
console.log('API响应状态:', response.status);
if (response.status === 406) {
// 406错误:反爬虫机制,但Cookie可能已经设置成功
return {
valid: true,
message: '✅ Cookie已设置!',
details: `已成功设置${setCount}个Cookie。由于反爬虫限制,无法通过API验证,但Cookie已生效。页面将在3秒后刷新以确认登录状态。`,
needRefresh: true
};
}
if (response.ok) {
const data = await response.json();
console.log('API响应数据:', data);
if (data.success && data.data) {
return {
valid: true,
message: '✅ Cookie有效!登录测试成功',
details: `已成功使用Cookie登录,用户: ${data.data.nickname || data.data.red_id || '已登录用户'}。页面将在3秒后刷新。`,
userData: data.data,
needRefresh: true
};
}
}
return {
valid: false,
message: 'Cookie可能无效',
details: `已设置${setCount}个Cookie(失败${failedCookies.length}个),但登录验证失败。Cookie可能已过期或不完整。建议刷新页面后重试。`
};
} catch (error) {
console.error('登录测试错误:', error);
return {
valid: false,
message: '登录测试失败',
details: error.message || '发生未知错误'
};
}
}
// 备用验证方法:通过页面内容验证
function verifyByPageContent() {
// 检查Cookie是否存在关键字段
const cookies = document.cookie;
const hasWebSession = cookies.includes('web_session=');
const hasWebId = cookies.includes('webId=');
const hasXsecToken = cookies.includes('xsec_token=');
const hasA1 = cookies.includes('a1=');
if (!hasWebSession && !hasXsecToken && !hasWebId && !hasA1) {
return {
valid: false,
message: 'Cookie无效',
details: '未找到必要的Cookie字段'
};
}
// 检查页面上是否有登录用户信息
const userAvatar = document.querySelector('.avatar, [class*="avatar"], [class*="Avatar"]');
const userInfo = document.querySelector('.user-info, [class*="user"], [class*="User"]');
const loginBtn = document.querySelector('[class*="login"], [class*="Login"]');
// 如果找到用户头像或用户信息,且没有登录按钮,说明已登录
if ((userAvatar || userInfo) && !loginBtn) {
return {
valid: true,
message: 'Cookie可能有效',
details: '检测到登录状态,Cookie包含必要字段。建议在小红书网站测试功能(如点赞、评论)以确认。'
};
}
// 如果有关键Cookie但无法确认页面状态
return {
valid: true,
message: 'Cookie包含必要字段',
details: '已检测到登录Cookie,但无法完全验证。建议在小红书网站测试功能(如点赞、评论)以确认有效性。'
};
}
// 创建UI面板
function createPanel() {
const panel = document.createElement('div');
panel.id = 'cookie-helper-panel';
panel.innerHTML = `
⚠️ 免责声明(请先阅读)
${DISCLAIMER}
请选择一个平台
⚠️ Cookie不完整
由于浏览器安全限制,脚本无法获取HttpOnly Cookie(如web_session、id_token等)。
请使用下方的"手动输入"功能获取完整Cookie:
点击后将清除当前登录,使用此Cookie重新登录以验证有效性
1
打开开发者工具
按 F12 或右键点击页面选择"检查"
2
切换到"网络"标签
找到顶部的"Network"或"网络"标签并点击
4
找到homefeed请求
在左侧列表中搜索"homefeed"或"feed",点击任意一个请求
5
复制Cookie
在右侧找到"请求标头"→"Cookie",点击Cookie值,全选并复制
6
粘贴到脚本
点击下方"手动输入完整Cookie"按钮,粘贴刚才复制的内容
`;
// 添加样式
const style = document.createElement('style');
style.textContent = `
#cookie-helper-panel {
position: fixed;
top: 50%;
right: 20px;
transform: translateY(-50%);
width: 360px;
max-height: 80vh;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
z-index: 999999;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
overflow: hidden;
display: none;
flex-direction: column;
}
.ch-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 16px 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.ch-title {
font-size: 16px;
font-weight: 600;
}
.ch-close {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
font-size: 24px;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}
.ch-close:hover {
background: rgba(255, 255, 255, 0.3);
}
.ch-disclaimer {
padding: 12px 20px;
background: #fff3cd;
border-bottom: 1px solid #ffeaa7;
}
.ch-disclaimer details {
cursor: pointer;
}
.ch-disclaimer summary {
font-size: 13px;
color: #856404;
font-weight: 500;
user-select: none;
}
.ch-disclaimer pre {
margin: 10px 0 0 0;
font-size: 11px;
color: #856404;
white-space: pre-wrap;
line-height: 1.5;
}
.ch-platforms {
padding: 16px 20px;
border-bottom: 1px solid #e9ecef;
max-height: 200px;
overflow-y: auto;
}
.ch-platform-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
margin-bottom: 8px;
background: #f8f9fa;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
border: 2px solid transparent;
}
.ch-platform-info {
display: flex;
align-items: center;
flex: 1;
}
.ch-platform-item:hover:not(.disabled) {
background: #e9ecef;
transform: translateX(4px);
}
.ch-platform-item.active {
background: #e7f3ff;
border-color: #667eea;
}
.ch-platform-item.disabled {
opacity: 0.5;
cursor: not-allowed;
}
.ch-platform-test-btn {
background: #17a2b8;
color: white;
border: none;
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
opacity: 0.8;
}
.ch-platform-test-btn:hover {
opacity: 1;
background: #138496;
transform: scale(1.05);
}
.ch-platform-test-btn:active {
transform: scale(0.95);
}
.ch-platform-icon {
font-size: 24px;
margin-right: 12px;
}
.ch-platform-name {
flex: 1;
font-size: 14px;
font-weight: 500;
}
.ch-badge {
font-size: 11px;
padding: 2px 8px;
background: #6c757d;
color: white;
border-radius: 10px;
}
.ch-content {
padding: 20px;
flex: 1;
overflow-y: auto;
}
.ch-status {
text-align: center;
padding: 20px;
color: #6c757d;
font-size: 14px;
}
.ch-status.success {
color: #28a745;
}
.ch-status.error {
color: #dc3545;
}
.ch-actions {
text-align: center;
margin-top: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.ch-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 32px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.ch-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
.ch-btn:disabled {
background: #6c757d;
cursor: not-allowed;
transform: none;
}
.ch-btn-refresh {
background: #17a2b8;
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
font-size: 13px;
cursor: pointer;
transition: background 0.2s;
}
.ch-btn-refresh:hover {
background: #138496;
}
.ch-result {
margin-top: 16px;
}
.ch-result-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
font-size: 13px;
font-weight: 500;
color: #495057;
}
.ch-btn-small {
background: #28a745;
color: white;
border: none;
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
cursor: pointer;
transition: background 0.2s;
}
.ch-btn-small:hover {
background: #218838;
}
.ch-cookie-text {
width: 100%;
min-height: 120px;
max-height: 200px;
padding: 12px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 12px;
font-family: 'Courier New', monospace;
resize: vertical;
background: #f8f9fa;
}
.ch-verify-section {
margin-top: 12px;
display: flex;
flex-direction: column;
gap: 8px;
}
.ch-btn-verify {
width: 100%;
background: #17a2b8;
color: white;
border: none;
padding: 10px 16px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
}
.ch-btn-verify:hover {
background: #138496;
}
.ch-btn-verify:disabled {
background: #6c757d;
cursor: not-allowed;
}
.ch-btn-login-test {
width: 100%;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border: none;
padding: 10px 16px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.ch-btn-login-test:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
}
.ch-btn-login-test:disabled {
background: #6c757d;
cursor: not-allowed;
transform: none;
}
.ch-test-section {
margin-top: 12px;
}
.ch-btn-test {
width: 100%;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border: none;
padding: 12px 16px;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
margin-bottom: 8px;
}
.ch-btn-test:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
}
.ch-btn-test:disabled {
background: #6c757d;
cursor: not-allowed;
transform: none;
}
.ch-test-hint {
font-size: 11px;
color: #6c757d;
text-align: center;
line-height: 1.4;
}
.ch-test-result {
margin-top: 12px;
padding: 12px;
border-radius: 6px;
font-size: 13px;
line-height: 1.5;
}
.ch-test-result.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.ch-test-result.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.ch-test-result .ch-test-title {
font-weight: 600;
margin-bottom: 4px;
}
.ch-test-result .ch-test-details {
font-size: 12px;
opacity: 0.9;
}
.ch-verify-result {
margin-top: 10px;
padding: 12px;
border-radius: 6px;
font-size: 13px;
line-height: 1.5;
}
.ch-verify-result.valid {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.ch-verify-result.invalid {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.ch-verify-result .ch-verify-title {
font-weight: 600;
margin-bottom: 4px;
}
.ch-verify-result .ch-verify-details {
font-size: 12px;
opacity: 0.9;
}
.ch-cookie-warning {
background: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 8px;
padding: 12px;
margin-bottom: 12px;
}
.ch-warning-title {
font-weight: 600;
color: #856404;
margin-bottom: 8px;
font-size: 14px;
}
.ch-warning-text {
font-size: 12px;
color: #856404;
line-height: 1.6;
margin-bottom: 10px;
}
.ch-btn-tutorial {
width: 100%;
background: #ffc107;
color: #000;
border: none;
padding: 8px 16px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
}
.ch-btn-tutorial:hover {
background: #ffb300;
}
.ch-manual-input-section {
margin-top: 12px;
}
.ch-btn-manual {
width: 100%;
background: #28a745;
color: white;
border: none;
padding: 10px 16px;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
}
.ch-btn-manual:hover {
background: #218838;
}
.ch-tutorial {
padding: 0;
border-top: 1px solid #e9ecef;
}
.ch-tutorial-header {
background: #f8f9fa;
padding: 16px 20px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e9ecef;
}
.ch-tutorial-title {
font-size: 15px;
font-weight: 600;
color: #495057;
}
.ch-close-tutorial {
background: rgba(0, 0, 0, 0.1);
border: none;
color: #495057;
font-size: 24px;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}
.ch-close-tutorial:hover {
background: rgba(0, 0, 0, 0.2);
}
.ch-tutorial-content {
padding: 20px;
max-height: 400px;
overflow-y: auto;
}
.ch-tutorial-step {
display: flex;
gap: 12px;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #e9ecef;
}
.ch-tutorial-step:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.ch-step-number {
flex-shrink: 0;
width: 32px;
height: 32px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
}
.ch-step-text {
flex: 1;
font-size: 13px;
line-height: 1.6;
color: #495057;
}
.ch-step-text strong {
display: block;
margin-bottom: 4px;
color: #212529;
}
.ch-step-text code {
background: #f8f9fa;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
font-size: 12px;
color: #e83e8c;
}
.ch-toggle-btn {
position: fixed;
bottom: 20px;
right: 20px;
width: 120px;
height: 48px;
border-radius: 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4);
z-index: 999998;
transition: transform 0.2s, box-shadow 0.3s;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
}
.ch-toggle-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5);
}
.ch-toggle-btn::before {
content: '🍪';
font-size: 20px;
}
`;
document.head.appendChild(style);
document.body.appendChild(panel);
// 创建切换按钮
const toggleBtn = document.createElement('button');
toggleBtn.className = 'ch-toggle-btn';
toggleBtn.id = 'ch-toggle-btn';
toggleBtn.textContent = 'Cookie助手';
toggleBtn.title = 'Cookie获取助手 - 点击打开';
document.body.appendChild(toggleBtn);
return panel;
}
// 初始化
function init() {
const panel = createPanel();
const currentPlatform = getCurrentPlatform();
// 事件处理
const closeBtn = document.getElementById('ch-close-btn');
const toggleBtn = document.getElementById('ch-toggle-btn');
const platformItems = document.querySelectorAll('.ch-platform-item:not(.disabled)');
const getCookieBtn = document.getElementById('ch-get-cookie-btn');
const copyBtn = document.getElementById('ch-copy-btn');
const refreshBtn = document.getElementById('ch-refresh-btn');
const testCookieBtn = document.getElementById('ch-test-cookie-btn');
const manualInputBtn = document.getElementById('ch-manual-input-btn');
const showTutorialBtn = document.getElementById('ch-show-tutorial-btn');
const closeTutorialBtn = document.getElementById('ch-close-tutorial-btn');
let selectedPlatform = null;
// 检查并更新平台状态的函数
async function updatePlatformStatus(platformKey) {
const platform = PLATFORMS[platformKey];
const statusEl = document.getElementById('ch-status');
const actionsEl = document.getElementById('ch-actions');
const resultEl = document.getElementById('ch-result');
resultEl.style.display = 'none';
// 检查是否在目标网站
const isOnTargetSite = window.location.hostname.includes(platform.domain);
if (!isOnTargetSite) {
// 不在目标网站,显示跳转按钮
statusEl.innerHTML = `📍 当前不在 ${platform.name} 网站`;
statusEl.className = 'ch-status';
actionsEl.style.display = 'block';
refreshBtn.style.display = 'none';
getCookieBtn.textContent = `前往 ${platform.name}`;
getCookieBtn.onclick = () => {
if (typeof GM_openInTab !== 'undefined') {
GM_openInTab(platform.url, { active: true });
} else {
window.open(platform.url, '_blank');
}
};
} else {
// 在目标网站,检查登录状态
statusEl.textContent = '🔄 正在检测登录状态...';
statusEl.className = 'ch-status';
const isLoggedIn = await platform.checkLogin();
if (isLoggedIn) {
statusEl.textContent = `✅ 已登录 ${platform.name}`;
statusEl.className = 'ch-status success';
actionsEl.style.display = 'block';
refreshBtn.style.display = 'block';
getCookieBtn.textContent = '获取Cookie';
getCookieBtn.onclick = async () => {
const cookie = await platform.getCookie();
const cookieTextEl = document.getElementById('ch-cookie-text');
const cookieWarningEl = document.getElementById('ch-cookie-warning');
if (cookie) {
cookieTextEl.value = cookie;
resultEl.style.display = 'block';
// 检查Cookie是否完整
const checkResult = checkCookieComplete(cookie);
if (!checkResult.complete) {
cookieWarningEl.style.display = 'block';
} else {
cookieWarningEl.style.display = 'none';
}
if (typeof GM_notification !== 'undefined') {
GM_notification({
text: checkResult.complete ? 'Cookie获取成功!' : 'Cookie不完整,请使用手动输入',
timeout: 2000
});
}
} else {
alert('获取Cookie失败,请确保已登录');
}
};
} else {
statusEl.textContent = `❌ 暂未登录 ${platform.name},请先登录`;
statusEl.className = 'ch-status error';
actionsEl.style.display = 'block';
refreshBtn.style.display = 'block';
getCookieBtn.style.display = 'none';
}
}
}
// 切换面板显示
toggleBtn.addEventListener('click', () => {
panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
// 如果打开面板且已选择平台,自动刷新状态
if (panel.style.display === 'flex' && selectedPlatform) {
updatePlatformStatus(selectedPlatform);
}
});
closeBtn.addEventListener('click', () => {
panel.style.display = 'none';
});
// 选择平台
platformItems.forEach(item => {
item.addEventListener('click', (e) => {
// 如果点击的是测试按钮,不触发平台选择
if (e.target.classList.contains('ch-platform-test-btn')) {
return;
}
const platformKey = item.dataset.platform;
// 更新选中状态
platformItems.forEach(i => i.classList.remove('active'));
item.classList.add('active');
selectedPlatform = platformKey;
// 更新平台状态
updatePlatformStatus(platformKey);
});
});
// 平台测试按钮
document.querySelectorAll('.ch-platform-test-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
e.stopPropagation(); // 阻止事件冒泡
const platformKey = btn.dataset.platform;
const platform = PLATFORMS[platformKey];
// 检查是否在目标网站
const isOnTargetSite = window.location.hostname.includes(platform.domain);
if (!isOnTargetSite) {
const goToSite = confirm(`当前不在${platform.name}网站。\n\n是否前往${platform.name}进行测试?`);
if (goToSite) {
if (typeof GM_openInTab !== 'undefined') {
GM_openInTab(platform.url, { active: true });
} else {
window.open(platform.url, '_blank');
}
}
return;
}
// 在目标网站上,弹出输入框
const cookieInput = prompt(`请输入要测试的${platform.name} Cookie:\n\n提示:可以从F12开发者工具的网络请求中复制完整Cookie`);
if (!cookieInput || !cookieInput.trim()) {
return;
}
// 执行登录测试
const verifyResultEl = document.getElementById('ch-verify-result');
const resultEl = document.getElementById('ch-result');
resultEl.style.display = 'block';
verifyResultEl.style.display = 'block';
verifyResultEl.className = 'ch-verify-result';
verifyResultEl.innerHTML = `
🔄 正在测试Cookie...
请稍候
`;
try {
const result = await testLoginWithCookie(cookieInput.trim());
verifyResultEl.className = `ch-verify-result ${result.valid ? 'valid' : 'invalid'}`;
verifyResultEl.innerHTML = `
${result.valid ? '✅ ' : '❌ '}${result.message}
${result.details}
`;
if (typeof GM_notification !== 'undefined') {
GM_notification({
text: result.message,
timeout: 3000
});
}
// 如果登录成功,3秒后刷新页面
if (result.needRefresh) {
setTimeout(() => {
window.location.reload();
}, 3000);
}
} catch (error) {
verifyResultEl.className = 'ch-verify-result invalid';
verifyResultEl.innerHTML = `
❌ 测试失败
${error.message}
`;
}
});
});
// 刷新按钮事件
refreshBtn.addEventListener('click', () => {
if (selectedPlatform) {
updatePlatformStatus(selectedPlatform);
if (typeof GM_notification !== 'undefined') {
GM_notification({
text: '状态已刷新',
timeout: 1000
});
}
}
});
// 获取Cookie
getCookieBtn.addEventListener('click', () => {
// 这个事件监听器现在只是占位,实际逻辑在平台选择时动态绑定
});
// 复制Cookie
copyBtn.addEventListener('click', () => {
const cookieTextEl = document.getElementById('ch-cookie-text');
const cookie = cookieTextEl.value;
if (typeof GM_setClipboard !== 'undefined') {
GM_setClipboard(cookie);
copyBtn.textContent = '✅ 已复制';
setTimeout(() => {
copyBtn.textContent = '📋 复制';
}, 2000);
} else {
// 降级方案
cookieTextEl.select();
document.execCommand('copy');
copyBtn.textContent = '✅ 已复制';
setTimeout(() => {
copyBtn.textContent = '📋 复制';
}, 2000);
}
});
// 测试Cookie(退出重登)
testCookieBtn.addEventListener('click', async () => {
const cookieTextEl = document.getElementById('ch-cookie-text');
const cookie = cookieTextEl.value;
if (!cookie || !cookie.trim()) {
alert('请先获取或输入Cookie');
return;
}
if (!confirm('⚠️ 此操作将清除当前登录状态,使用获取的Cookie重新登录。\n\n确定要继续吗?')) {
return;
}
testCookieBtn.disabled = true;
testCookieBtn.textContent = '🔄 测试中...';
try {
// 1. 清除当前所有Cookie
if (typeof GM_cookie !== 'undefined') {
const currentCookies = await new Promise((resolve) => {
GM_cookie.list({}, (cookies) => {
resolve(cookies || []);
});
});
for (const c of currentCookies) {
await new Promise((resolve) => {
GM_cookie.delete({
name: c.name,
url: window.location.href
}, () => resolve());
});
}
}
// 2. 设置新Cookie
const result = await testLoginWithCookie(cookie);
// 3. 刷新页面验证
if (result.valid || result.needRefresh) {
if (typeof GM_notification !== 'undefined') {
GM_notification({
text: '正在刷新页面验证登录...',
timeout: 2000
});
}
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
alert(`测试失败:${result.message}\n${result.details}`);
testCookieBtn.disabled = false;
testCookieBtn.textContent = '🧪 测试Cookie(退出重登)';
}
} catch (error) {
alert(`测试失败:${error.message}`);
testCookieBtn.disabled = false;
testCookieBtn.textContent = '🧪 测试Cookie(退出重登)';
}
});
// 手动输入Cookie
manualInputBtn.addEventListener('click', () => {
const cookieTextEl = document.getElementById('ch-cookie-text');
const cookieWarningEl = document.getElementById('ch-cookie-warning');
const userInput = prompt('请粘贴从F12开发者工具复制的完整Cookie:\n\n提示:在开发者工具的"网络"标签中,找到任意请求,复制"请求标头"中的Cookie值');
if (userInput && userInput.trim()) {
cookieTextEl.value = userInput.trim();
// 检查Cookie是否完整
const checkResult = checkCookieComplete(userInput.trim());
if (checkResult.complete) {
cookieWarningEl.style.display = 'none';
if (typeof GM_notification !== 'undefined') {
GM_notification({
text: '✅ 完整Cookie已输入!',
timeout: 2000
});
}
} else {
if (typeof GM_notification !== 'undefined') {
GM_notification({
text: '⚠️ Cookie可能仍不完整',
timeout: 2000
});
}
}
}
});
// 显示教程
showTutorialBtn.addEventListener('click', () => {
const tutorialEl = document.getElementById('ch-tutorial');
tutorialEl.style.display = 'block';
});
// 关闭教程
closeTutorialBtn.addEventListener('click', () => {
const tutorialEl = document.getElementById('ch-tutorial');
tutorialEl.style.display = 'none';
});
// 如果在支持的平台上,自动选中
if (currentPlatform && !PLATFORMS[currentPlatform].disabled) {
const platformItem = document.querySelector(`[data-platform="${currentPlatform}"]`);
if (platformItem) {
platformItem.click();
}
}
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();