// # Source: https://github.com/huwangkeji/juejin_checkin/blob/main/juejin_checkin.js // # Raw: https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin_checkin.js // # Repo: huwangkeji/juejin_checkin // # Path: juejin_checkin.js // # UploadedAt: 2026-05-19T14:34:11Z // # SHA256: 6f8a138b51c397220444c9312040dbe3407af5aeed4fa4467a36672aeb8bcfd1 // # Category: web版/账密 // # Evidence: web/H5关键词 + username/password/login // /* * @name 掘金自动签到脚本 * @description 掘金社区每日签到 + 免费抽奖 + 沾喜气 + Bug消除,支持Cookie自动签到 * @namespace https://juejin.cn * @version 1.0.0 * @author CodeBuddy * * 【青龙面板使用说明】 * 1. 依赖管理 -> NodeJS -> 添加依赖: axios * 2. 环境变量 (必填): * - JUEJIN_COOKIE: 掘金Cookie (从浏览器开发者工具复制) * - JUEJIN_AID: API参数aid (通常为2608) * - JUEJIN_UUID: API参数uuid * - JUEJIN_MSTOKEN: API参数msToken * - JUEJIN_A_BOGUS: API参数a_bogus * 3. 环境变量 (可选): * - JUEJIN_COOKIE_2 ~ JUEJIN_COOKIE_5: 多账号Cookie * - JUEJIN_NOTIFY: 是否推送通知 (默认true) * 4. 定时规则: 30 6 * * * (每天早上6:30执行) * * 【参数获取方式】 * 1. 浏览器打开 https://juejin.cn 并登录 * 2. 按F12打开开发者工具 -> Network(网络)标签 * 3. 刷新页面,找到任意一个 api.juejin.cn 的请求 * 4. 在 Request Headers 中复制完整的 Cookie 值 * 5. 在 Query String Parameters 中复制 aid, uuid, msToken, a_bogus * 6. 粘贴到青龙面板对应的环境变量中 * 7. Cookie和参数有效期约30天,过期后需重新获取 * * 【功能列表】 * - Cookie自动签到(支持多账号) * - 每日签到 * - 免费抽奖 * - 沾喜气 * - Bug消除 * - 查询矿石余额/签到天数/幸运值 * - 青龙面板通知推送 */ const axios = require('axios'); // ==================== 配置区域 ==================== const API_BASE = 'https://api.juejin.cn'; // 请求头 const DEFAULT_HEADERS = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', 'Referer': 'https://juejin.cn/', 'Origin': 'https://juejin.cn', 'Content-Type': 'application/json', 'sec-ch-ua': '"Not/A)Brand";v="99", "Chromium";v="148"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', }; // ==================== 工具函数 ==================== function log(msg) { const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }); console.log(`[${now}] ${msg}`); } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * 创建带Cookie和参数的axios实例 */ function createApiClient(cookie, params) { const instance = axios.create({ baseURL: API_BASE, headers: { ...DEFAULT_HEADERS, Cookie: cookie, }, timeout: 30000, }); // 请求拦截 - 自动添加查询参数 instance.interceptors.request.use((config) => { if (params && Object.keys(params).length > 0) { config.params = { ...config.params, ...params }; } // POST请求body为空对象 if (config.method === 'post' && !config.data) { config.data = {}; } return config; }); // 响应拦截 instance.interceptors.response.use( (response) => { const data = response.data; // 处理空响应 if (data === '' || data === null || data === undefined) { throw new Error('API返回空响应,可能需要更新参数'); } if (typeof data === 'object' && data.err_no !== 0) { throw new Error(`API错误: [${data.err_no}] ${data.err_msg || '未知错误'}`); } return data.data; }, (error) => { if (error.response) { const data = error.response.data; if (data && typeof data === 'object' && data.err_no !== undefined) { throw new Error(`API错误: [${data.err_no}] ${data.err_msg || '未知错误'}`); } throw new Error(`HTTP错误: ${error.response.status} ${error.response.statusText}`); } throw error; } ); return instance; } // ==================== API 调用 ==================== /** * 检查今日签到状态 */ async function getTodayStatus(api) { try { const data = await api.get('/growth_api/v1/get_today_status'); return data === true; } catch (e) { log('⚠️ 查询签到状态失败: ' + e.message); return null; } } /** * 执行签到 */ async function checkIn(api) { try { const data = await api.post('/growth_api/v1/check_in'); log('✅ 签到成功!'); return { success: true, data }; } catch (e) { if (e.message.includes('15001') || e.message.includes('已签到') || e.message.includes('duplicate')) { log('📌 今日已签到,无需重复签到'); return { success: true, already: true }; } if (e.message.includes('3013')) { log('📌 今日已签到 (3013)'); return { success: true, already: true }; } if (e.message.includes('空响应')) { log('⚠️ API返回空响应,参数可能已过期,建议重新获取'); return { success: false, error: e.message }; } log('❌ 签到失败: ' + e.message); return { success: false, error: e.message }; } } /** * 获取签到天数统计 */ async function getCounts(api) { try { const data = await api.get('/growth_api/v1/get_counts'); return data; } catch (e) { log('⚠️ 获取签到统计失败: ' + e.message); return null; } } /** * 获取当前矿石数 */ async function getCurrentPoint(api) { try { const data = await api.get('/growth_api/v1/get_cur_point'); return data; } catch (e) { log('⚠️ 获取矿石余额失败: ' + e.message); return null; } } /** * 获取抽奖配置 */ async function getLotteryConfig(api) { try { const data = await api.get('/growth_api/v1/lottery_config/get'); return data; } catch (e) { log('⚠️ 获取抽奖配置失败: ' + e.message); return null; } } /** * 免费抽奖 */ async function drawLottery(api) { try { const data = await api.post('/growth_api/v1/lottery/draw'); log('🎉 抽奖成功!奖品: ' + (data.lottery_name || '未知')); return { success: true, data }; } catch (e) { log('❌ 抽奖失败: ' + e.message); return { success: false, error: e.message }; } } /** * 沾喜气 */ async function dipLucky(api) { try { // 先获取幸运用户列表 const luckyUsers = await api.post('/growth_api/v1/lottery_history/global_big', { page_no: 1, page_size: 5, }); if (luckyUsers && luckyUsers.lotteries && luckyUsers.lotteries.length > 0) { const historyId = luckyUsers.lotteries[0].history_id; const data = await api.post('/growth_api/v1/lottery_lucky/dip_lucky', { lottery_history_id: historyId, }); log('🍀 沾喜气成功!幸运值: ' + (data.dip_value || 0)); return { success: true, data }; } log('⚠️ 暂无可沾喜气的用户'); return { success: false }; } catch (e) { log('❌ 沾喜气失败: ' + e.message); return { success: false, error: e.message }; } } /** * 获取我的幸运值 */ async function getMyLucky(api) { try { const data = await api.post('/growth_api/v1/lottery_lucky/my_lucky'); return data; } catch (e) { log('⚠️ 获取幸运值失败: ' + e.message); return null; } } /** * 查询用户信息 (验证Cookie有效性) */ async function getUserInfo(api) { try { const data = await api.get('/user_api/v1/user/get'); return data; } catch (e) { log('⚠️ Cookie无效或已过期: ' + e.message); return null; } } /** * 获取Bug消除配置 */ async function getBugFixConfig(api) { try { const data = await api.get('/growth_api/v1/bugfix/not_collect'); return data; } catch (e) { log('⚠️ 获取Bug配置失败: ' + e.message); return null; } } /** * 消除Bug */ async function fixBug(api, bugId) { try { const data = await api.post('/growth_api/v1/bugfix/collect', { bug_type: bugId, }); log('🐛 Bug消除成功!'); return { success: true, data }; } catch (e) { log('❌ Bug消除失败: ' + e.message); return { success: false, error: e.message }; } } // ==================== 青龙面板通知 ==================== /** * 青龙面板通知推送 */ async function sendNotify(title, content) { if (process.env.JUEJIN_NOTIFY === 'false') { log('📢 通知已禁用'); return; } try { // 尝试加载青龙面板的通知模块 const notifyPath = require('path').join(process.cwd(), 'notify.js'); if (require('fs').existsSync(notifyPath)) { const sendNotifyFn = require(notifyPath); if (typeof sendNotifyFn === 'function') { await sendNotifyFn(title, content); log('📢 青龙通知已发送'); return; } } // 尝试从全局加载 try { const { sendNotify: qinglongNotify } = require('qlnotify'); await qinglongNotify(title, content); log('📢 青龙通知已发送'); return; } catch (e) { // 忽略 } log('📢 青龙通知模块未找到,仅控制台输出'); } catch (e) { log('⚠️ 发送通知失败: ' + e.message); } } // ==================== 单个账号签到流程 ==================== async function runAccount(cookie, params, index) { const prefix = index > 1 ? `[账号${index}] ` : ''; log(''); log(`${prefix}═══════════════════════════════════════`); log(`${prefix} 开始处理账号 ${index}`); log(`${prefix}═══════════════════════════════════════`); if (!cookie || cookie.trim().length === 0) { log(`${prefix}❌ Cookie为空,跳过`); return null; } // 创建API客户端 const api = createApiClient(cookie, params); // 验证Cookie有效性 log(`${prefix}🔍 验证Cookie...`); const userInfo = await getUserInfo(api); if (!userInfo) { log(`${prefix}❌ Cookie已失效,请重新获取`); return { success: false, error: 'Cookie已失效', userName: '未知用户', }; } const userName = userInfo.user_name || userInfo.nick_name || '未知用户'; log(`${prefix}✅ Cookie有效!用户: ${userName}`); // 签到 log(`${prefix}📅 执行签到...`); const todayStatus = await getTodayStatus(api); let signInResult = { success: true, already: todayStatus === true }; if (todayStatus === true) { log(`${prefix}📌 今日已签到,跳过`); } else if (todayStatus === false) { signInResult = await checkIn(api); if (!signInResult.success) { log(`${prefix}🔄 签到失败,1秒后重试...`); await sleep(1000); signInResult = await checkIn(api); } } else { log(`${prefix}⚠️ 无法查询签到状态,直接尝试签到...`); signInResult = await checkIn(api); } // 抽奖 log(`${prefix}🎰 执行抽奖...`); const lotteryConfig = await getLotteryConfig(api); let lotteryResult = { success: false }; if (lotteryConfig && lotteryConfig.free_count > 0) { log(`${prefix}🎁 有 ${lotteryConfig.free_count} 次免费抽奖机会`); lotteryResult = await drawLottery(api); } else if (lotteryConfig) { log(`${prefix}📌 今日免费抽奖次数已用完`); } // 沾喜气 log(`${prefix}🍀 沾喜气...`); const dipResult = await dipLucky(api); // Bug消除 log(`${prefix}🐛 消除Bug...`); const bugConfig = await getBugFixConfig(api); let bugFixResult = { success: false }; if (bugConfig && Array.isArray(bugConfig) && bugConfig.length > 0) { const bug = bugConfig[0]; log(`${prefix}🔧 发现未消除的Bug: ${bug.bug_type}`); bugFixResult = await fixBug(api, bug.bug_type); } else { log(`${prefix}📌 暂无Bug可消除`); } // 查询统计信息 log(`${prefix}📊 查询统计...`); const counts = await getCounts(api); const point = await getCurrentPoint(api); const lucky = await getMyLucky(api); if (counts) { log(`${prefix}📅 连续签到: ${counts.cont_count || 0} 天`); log(`${prefix}📅 累计签到: ${counts.sum_count || 0} 天`); } if (point !== null) { log(`${prefix}💰 当前矿石: ${point}`); } if (lucky) { log(`${prefix}🍀 幸运值: ${lucky.total_value || 0}`); } log(`${prefix}✅ 账号处理完成`); return { success: true, userName, signIn: signInResult, lottery: lotteryResult, dip: dipResult, bugFix: bugFixResult, counts, point, lucky, }; } // ==================== 主流程 ==================== async function main() { log('═══════════════════════════════════════'); log(' 掘金自动签到脚本 v1.0.0'); log('═══════════════════════════════════════'); // 收集所有账号的配置 const accounts = []; // 主账号 const mainCookie = process.env.JUEJIN_COOKIE || ''; const mainParams = { aid: process.env.JUEJIN_AID || '2608', uuid: process.env.JUEJIN_UUID || '', msToken: process.env.JUEJIN_MSTOKEN || '', a_bogus: process.env.JUEJIN_A_BOGUS || '', spider: '0', }; if (mainCookie) { accounts.push({ cookie: mainCookie, params: mainParams }); } // 多账号支持 for (let i = 2; i <= 5; i++) { const cookie = process.env[`JUEJIN_COOKIE_${i}`] || ''; if (cookie) { accounts.push({ cookie, params: { aid: process.env[`JUEJIN_AID_${i}`] || mainParams.aid, uuid: process.env[`JUEJIN_UUID_${i}`] || '', msToken: process.env[`JUEJIN_MSTOKEN_${i}`] || '', a_bogus: process.env[`JUEJIN_A_BOGUS_${i}`] || '', spider: '0', }, }); } } if (accounts.length === 0) { log(''); log('❌ 未配置Cookie,请设置环境变量 JUEJIN_COOKIE'); log(''); log('【参数获取方式】'); log('1. 浏览器打开 https://juejin.cn 并登录'); log('2. 按F12打开开发者工具 -> Network(网络)标签'); log('3. 刷新页面,找到任意一个 api.juejin.cn 的请求'); log('4. 在 Request Headers 中复制完整的 Cookie 值'); log('5. 在 Query String Parameters 中复制 aid, uuid, msToken, a_bogus'); log('6. 粘贴到青龙面板对应的环境变量中'); log(''); process.exit(1); } log(`📱 共配置 ${accounts.length} 个账号`); // 执行每个账号的签到 const results = []; for (let i = 0; i < accounts.length; i++) { const result = await runAccount(accounts[i].cookie, accounts[i].params, i + 1); if (result) results.push(result); } // 生成通知内容 log(''); log('📢 发送通知...'); let notifyTitle = '掘金每日签到报告'; let notifyContent = ''; for (let i = 0; i < results.length; i++) { const r = results[i]; const prefix = results.length > 1 ? `【账号${i + 1}】` : ''; if (!r.success) { notifyContent += `${prefix}❌ ${r.userName}: ${r.error}\n`; continue; } notifyContent += `${prefix}👤 ${r.userName}\n`; notifyContent += ` 📅 连续签到: ${r.counts?.cont_count || 0} 天\n`; notifyContent += ` 📅 累计签到: ${r.counts?.sum_count || 0} 天\n`; notifyContent += ` 💰 当前矿石: ${r.point ?? '未知'}\n`; notifyContent += ` 🍀 幸运值: ${r.lucky?.total_value || 0}\n`; notifyContent += ` ✅ 签到: ${r.signIn.already ? '今日已签到' : r.signIn.success ? '成功' : '失败'}\n`; notifyContent += ` 🎰 抽奖: ${r.lottery.success ? '成功 - ' + (r.lottery.data?.lottery_name || '') : '未抽奖/失败'}\n`; notifyContent += ` 🍀 沾喜气: ${r.dip.success ? '成功' : '失败'}\n`; notifyContent += ` 🐛 Bug消除: ${r.bugFix.success ? '成功' : '无/失败'}\n`; notifyContent += '\n'; } await sendNotify(notifyTitle, notifyContent); log(''); log('═══════════════════════════════════════'); log(' 脚本执行完成!'); log('═══════════════════════════════════════'); } // 执行主函数 main().catch((error) => { log('💥 脚本异常退出: ' + error.message); console.error(error); process.exit(1); });