Refactor GitCode daily bot
This commit is contained in:
500
test.js
500
test.js
@@ -1,213 +1,293 @@
|
||||
const { chromium } = require('playwright');
|
||||
const fs = require('fs');
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: true // 👈 Windows建议先开界面调试
|
||||
});
|
||||
|
||||
|
||||
// 👇 关键就在这里
|
||||
let context = null
|
||||
if (fs.existsSync('state.json')) {
|
||||
console.log('✅ state.json 存在');
|
||||
context = await browser.newContext({
|
||||
storageState: 'state.json',
|
||||
locale: "zh-CN"
|
||||
});
|
||||
} else {
|
||||
console.log('❌ state.json 不存在');
|
||||
context = await browser.newContext({
|
||||
locale: "zh-CN"
|
||||
})
|
||||
import * as fs from "fs";
|
||||
import axios from "axios";
|
||||
import { chromium } from 'playwright'
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: true // 👈 Windows建议先开界面调试
|
||||
});
|
||||
|
||||
|
||||
// 👇 关键就在这里
|
||||
let context = null
|
||||
if (fs.existsSync('state.json')) {
|
||||
console.log('✅ state.json 存在');
|
||||
context = await browser.newContext({
|
||||
storageState: 'state.json',
|
||||
locale: "zh-CN"
|
||||
});
|
||||
} else {
|
||||
console.log('❌ state.json 不存在');
|
||||
context = await browser.newContext({
|
||||
locale: "zh-CN"
|
||||
})
|
||||
}
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://gitcode.com/setting/points');
|
||||
await page.waitForTimeout(5000);
|
||||
const isLogin = await page.locator('.g-user-avatar').isVisible();
|
||||
if (isLogin) {
|
||||
console.log('✅ 已登录');
|
||||
runTasks(page)
|
||||
} else {
|
||||
console.log('❌ 未登录');
|
||||
await page.getByText('密码登录').click();
|
||||
await page.getByPlaceholder('请填写手机号/用户名/邮箱').fill('test');
|
||||
await page.getByPlaceholder('请填写密码').fill('test');
|
||||
await page.getByText('登录或注册完成代表你同意').click();
|
||||
await page.getByText('我同意将账号、组织、仓库等信息提供给AtomGit进行 ').click();
|
||||
await page.locator('button:has-text("登 录")').click();
|
||||
await page.waitForTimeout(1000);
|
||||
await context.storageState({ path: 'state.json' });
|
||||
runTasks(page)
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
|
||||
async function runTasks(page) {
|
||||
console.log('✅ 开始寻找每日任务');
|
||||
const tasks = await page.locator('.novice-task-item-box').all();
|
||||
console.log('✅ 共找到' + tasks.length + '个每日任务');
|
||||
for (const task of tasks) {
|
||||
const title = await task.locator('.task-card-title__label-text').innerText();
|
||||
if (title.includes("更新项目")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await doUpdateProject(page)
|
||||
}
|
||||
console.log('✅ 更新项目已完成');
|
||||
} else if (title.includes("每日分享")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyShare(task, page)
|
||||
|
||||
}
|
||||
console.log('✅ 每日分享已完成');
|
||||
} else if (title.includes("每日签到")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyCheckInTask(task, page)
|
||||
}
|
||||
console.log('✅ 每日签到已完成');
|
||||
} else if (title.includes("查看热门")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyViewTrending(task, page)
|
||||
}
|
||||
console.log('✅ 查看热门已完成');
|
||||
} else if (title.includes("每日Star")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyViewStar(task, page)
|
||||
}
|
||||
console.log('✅ 每日Star已完成');
|
||||
}
|
||||
}
|
||||
await page.waitForTimeout(2000);
|
||||
await page.reload({ waitUntil: "domcontentloaded" });
|
||||
await page.waitForTimeout(2000);
|
||||
await page.locator('button.pickup-btn:has-text("一键领取")').click();
|
||||
console.log('✅ 已完成所有任务,奖励已领取 , 开始寻找卡片, 判断所有是否完成和领取');
|
||||
const tasks2 = await page.locator('.novice-task-item-box').all();
|
||||
console.log('✅ 共找到' + tasks2.length + '个每日任务');
|
||||
for (const task of tasks2) {
|
||||
const isCompleted = await task.locator('.completed').count() > 0;
|
||||
const title = await task.locator('.task-card-title__label-text').innerText();
|
||||
console.log('✅ ' + title + ' 任务完成状态: ' + (isCompleted ? '已完成' : '未完成'));
|
||||
}
|
||||
await page.waitForTimeout(1000);
|
||||
await sendFeishuText('✅ 已完成所有任务,奖励已领取');
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
async function taskIsCompleted(task) {
|
||||
const rewardBtn = task.locator('button:has-text("领取奖励")');
|
||||
|
||||
// 如果存在领取奖励按钮 -> 说明任务已完成但奖励未领取
|
||||
if (await rewardBtn.count() > 0) {
|
||||
console.log('🎁 检测到可领取奖励,正在领取...');
|
||||
await rewardBtn.click();
|
||||
|
||||
// 等待领取按钮消失 or completed 出现
|
||||
await task.page().waitForTimeout(800);
|
||||
|
||||
const stillHasRewardBtn = await rewardBtn.count() > 0;
|
||||
const isCompleted = await task.locator('.completed').count() > 0;
|
||||
|
||||
if (!stillHasRewardBtn || isCompleted) {
|
||||
console.log('✅ 奖励领取成功');
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log('⚠️ 已点击领取奖励,但状态未变化,可能领取失败或延迟刷新');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 已完成标记
|
||||
const isCompleted = await task.locator('.completed').count() > 0;
|
||||
if (isCompleted) {
|
||||
console.log('✅ 已完成,跳过');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function doUpdateProject(page) {
|
||||
console.log('👉 执行项目更新');
|
||||
const context = page.context();
|
||||
const newPage = await context.newPage();
|
||||
await newPage.goto('https://gitcode.com/fzxlzy/test/edit/main/testjpgp11');
|
||||
// 你可以自己补逻辑
|
||||
const frame = newPage.frameLocator('#codeartside');
|
||||
|
||||
// 1️⃣ 点击编辑器
|
||||
await frame.locator('.monaco-editor').click({
|
||||
position: { x: 200, y: 100 }
|
||||
});
|
||||
|
||||
// 2️⃣ 把光标移动到末尾(关键!)
|
||||
await newPage.keyboard.press('Control+End');
|
||||
|
||||
// 3️⃣ 追加内容
|
||||
await newPage.keyboard.type(`\n测试图片生成功能
|
||||
11
|
||||
22
|
||||
33`, { delay: 50 });
|
||||
// 等按钮出现
|
||||
await newPage.locator('button:has-text("提交修改")').click();
|
||||
await page.waitForTimeout(1000);
|
||||
const submitButton = newPage.locator('button:has-text("提交修改")').nth(1); // 0 是页面按钮,1 是弹框按钮
|
||||
await submitButton.click();
|
||||
await newPage.waitForTimeout(500);
|
||||
await newPage.close();
|
||||
}
|
||||
|
||||
async function dailyShare(task, page) {
|
||||
// 等待新页面打开
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent('page'), // 等待新页面事件
|
||||
task.locator('.toComplete').click()
|
||||
]);
|
||||
|
||||
// 点击第一个
|
||||
await newPage.waitForTimeout(1000);
|
||||
await newPage.locator('.immediately-invite-btn').nth(0).click();
|
||||
await newPage.waitForTimeout(2000);
|
||||
await newPage.close();
|
||||
|
||||
}
|
||||
|
||||
async function dailyCheckInTask(task, page) {
|
||||
await page.waitForTimeout(1000);
|
||||
task.locator('button:has-text("签到")').click()
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
async function dailyViewTrending(task, page) {
|
||||
// 等待新页面打开
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent('page'), // 等待新页面事件
|
||||
task.locator('.toComplete').click()
|
||||
])
|
||||
await newPage.waitForSelector('.hot-selection .recommend-card');
|
||||
// 获取第一个热门项目卡片
|
||||
const firstHotProjectCard = await newPage.$('.hot-selection .recommend-card');
|
||||
await newPage.waitForTimeout(1000);
|
||||
// 点击它
|
||||
const [newPage2] = await Promise.all([
|
||||
newPage.context().waitForEvent('page'), // 等待新页面事件
|
||||
await firstHotProjectCard.click()
|
||||
])
|
||||
await newPage2.waitForTimeout(2000);
|
||||
newPage2.close()
|
||||
newPage.close()
|
||||
}
|
||||
|
||||
async function dailyViewStar(task, page) {
|
||||
// 等待新页面打开
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent('page'), // 等待新页面事件
|
||||
task.locator('.toComplete').click()
|
||||
])
|
||||
// 等待元素出现在 DOM(不要用 visible,容易超时)
|
||||
await newPage.waitForSelector('.hot-selection-list a.recommend-card', { state: 'attached' });
|
||||
const cards = newPage.locator('.hot-selection-list a.recommend-card');
|
||||
const count = await cards.count();
|
||||
|
||||
console.log("热门项目数量:", count);
|
||||
|
||||
if (count === 0) {
|
||||
throw new Error("没有找到热门项目");
|
||||
}
|
||||
await newPage.waitForTimeout(2000);
|
||||
// 随机选一个
|
||||
const index = Math.floor(Math.random() * count);
|
||||
console.log("随机选择 index:", index);
|
||||
// 点击并捕获新 tab
|
||||
const [newPage2] = await Promise.all([
|
||||
newPage.context().waitForEvent('page'),
|
||||
cards.nth(index).click()
|
||||
]);
|
||||
// 等待 Star 按钮出现
|
||||
const starBtn = newPage2.locator('#repo-header-tab .status-btn').filter({ hasText: 'Star' }).nth(1);
|
||||
await newPage2.waitForTimeout(2000);
|
||||
await starBtn.waitFor({ state: 'visible' });
|
||||
// 判断是否已 Starred
|
||||
const text = await starBtn.innerText();
|
||||
await newPage2.waitForTimeout(2000);
|
||||
if (text.includes('Starred')) {
|
||||
// 已经 Starred -> 先取消
|
||||
await starBtn.click();
|
||||
|
||||
// 等待变回 Star
|
||||
await newPage2.waitForTimeout(500);
|
||||
}
|
||||
await starBtn.click();
|
||||
await newPage2.waitForTimeout(2000);
|
||||
newPage2.close()
|
||||
newPage.close()
|
||||
}
|
||||
|
||||
async function sleep(ms) {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
async function sendFeishuText(text) {
|
||||
const webhook = process.env.FEISHU_WEBHOOK;
|
||||
if (!webhook) {
|
||||
console.log('FEISHU_WEBHOOK 未配置,跳过飞书通知');
|
||||
return;
|
||||
}
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://gitcode.com/setting/points');
|
||||
await page.waitForTimeout(5000);
|
||||
const isLogin = await page.locator('.g-user-avatar').isVisible();
|
||||
if (isLogin) {
|
||||
console.log('✅ 已登录');
|
||||
runTasks(page)
|
||||
} else {
|
||||
console.log('❌ 未登录');
|
||||
await page.getByText('密码登录').click();
|
||||
await page.getByPlaceholder('请填写手机号/用户名/邮箱').fill('15623979816');
|
||||
await page.getByPlaceholder('请填写密码').fill('Zzy1995115');
|
||||
await page.getByText('登录或注册完成代表你同意').click();
|
||||
await page.getByText('我同意将账号、组织、仓库等信息提供给AtomGit进行 ').click();
|
||||
await page.locator('button:has-text("登 录")').click();
|
||||
await page.waitForTimeout(1000);
|
||||
await context.storageState({ path: 'state.json' });
|
||||
runTasks(page)
|
||||
}
|
||||
})();
|
||||
|
||||
async function runTasks(page) {
|
||||
console.log('✅ 开始寻找每日任务');
|
||||
const tasks = await page.locator('.novice-task-item-box').all();
|
||||
console.log('✅ 共找到' + tasks.length + '个每日任务');
|
||||
for (const task of tasks) {
|
||||
const title = await task.locator('.task-card-title__label-text').innerText();
|
||||
if (title.includes("更新项目")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await doUpdateProject(page)
|
||||
}
|
||||
} else if (title.includes("每日分享")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyShare(task, page)
|
||||
}
|
||||
} else if (title.includes("每日签到")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyCheckInTask(task, page)
|
||||
}
|
||||
} else if (title.includes("查看热门")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyViewTrending(task, page)
|
||||
}
|
||||
} else if (title.includes("每日Star")) {
|
||||
const taskStat = await taskIsCompleted(task)
|
||||
if (!taskStat) {
|
||||
await dailyViewStar(task, page)
|
||||
}
|
||||
}
|
||||
}
|
||||
await page.waitForTimeout(2000);
|
||||
await page.reload({ waitUntil: "domcontentloaded" });
|
||||
await page.waitForTimeout(2000);
|
||||
await page.locator('button.pickup-btn:has-text("一键领取")').click();
|
||||
|
||||
const payload = {
|
||||
msg_type: "text",
|
||||
content: { text }
|
||||
};
|
||||
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 10000); // 10秒超时
|
||||
|
||||
const res = await fetch(webhook, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
clearTimeout(timeout);
|
||||
|
||||
const data = await res.text();
|
||||
console.log("Feishu response:", data);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.error(`Feishu send failed (attempt ${i})`, err);
|
||||
await sleep(3000);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Feishu webhook failed after retries");
|
||||
}
|
||||
|
||||
async function taskIsCompleted(task) {
|
||||
const taskEnd = await task.locator('button:has-text("领取奖励")').count() > 0
|
||||
if (taskEnd) {
|
||||
task.locator('button:has-text("领取奖励")').click()
|
||||
return true
|
||||
}
|
||||
const isCompleted = await task.locator('.completed').count() > 0
|
||||
if (isCompleted) {
|
||||
console.log('✅ 已完成,跳过');
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async function doUpdateProject(page) {
|
||||
console.log('👉 执行项目更新');
|
||||
const context = page.context();
|
||||
const newPage = await context.newPage();
|
||||
await newPage.goto('https://gitcode.com/fzxlzy/test/edit/main/testjpgp11');
|
||||
// 你可以自己补逻辑
|
||||
const frame = newPage.frameLocator('#codeartside');
|
||||
|
||||
// 1️⃣ 点击编辑器
|
||||
await frame.locator('.monaco-editor').click({
|
||||
position: { x: 200, y: 100 }
|
||||
});
|
||||
|
||||
// 2️⃣ 把光标移动到末尾(关键!)
|
||||
await newPage.keyboard.press('Control+End');
|
||||
|
||||
// 3️⃣ 追加内容
|
||||
await newPage.keyboard.type(`\n测试图片生成功能
|
||||
11
|
||||
22
|
||||
33`, { delay: 50 });
|
||||
// 等按钮出现
|
||||
await newPage.locator('button:has-text("提交修改")').click();
|
||||
await page.waitForTimeout(1000);
|
||||
const submitButton = newPage.locator('button:has-text("提交修改")').nth(1); // 0 是页面按钮,1 是弹框按钮
|
||||
await submitButton.click();
|
||||
await newPage.waitForTimeout(500);
|
||||
await newPage.close();
|
||||
}
|
||||
|
||||
async function dailyShare(task, page) {
|
||||
// 等待新页面打开
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent('page'), // 等待新页面事件
|
||||
task.locator('.toComplete').click()
|
||||
]);
|
||||
|
||||
// 点击第一个
|
||||
await newPage.waitForTimeout(1000);
|
||||
await newPage.locator('.immediately-invite-btn').nth(0).click();
|
||||
await newPage.waitForTimeout(2000);
|
||||
await newPage.close();
|
||||
|
||||
}
|
||||
|
||||
async function dailyCheckInTask(task, page) {
|
||||
await page.waitForTimeout(1000);
|
||||
task.locator('button:has-text("签到")').click()
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
async function dailyViewTrending(task, page) {
|
||||
// 等待新页面打开
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent('page'), // 等待新页面事件
|
||||
task.locator('.toComplete').click()
|
||||
])
|
||||
await newPage.waitForSelector('.hot-selection .recommend-card');
|
||||
// 获取第一个热门项目卡片
|
||||
const firstHotProjectCard = await newPage.$('.hot-selection .recommend-card');
|
||||
await newPage.waitForTimeout(1000);
|
||||
// 点击它
|
||||
const [newPage2] = await Promise.all([
|
||||
newPage.context().waitForEvent('page'), // 等待新页面事件
|
||||
await firstHotProjectCard.click()
|
||||
])
|
||||
await newPage2.waitForTimeout(2000);
|
||||
newPage2.close()
|
||||
newPage.close()
|
||||
}
|
||||
|
||||
async function dailyViewStar(task, page) {
|
||||
// 等待新页面打开
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent('page'), // 等待新页面事件
|
||||
task.locator('.toComplete').click()
|
||||
])
|
||||
// 等待元素出现在 DOM(不要用 visible,容易超时)
|
||||
await newPage.waitForSelector('.hot-selection-list a.recommend-card', { state: 'attached' });
|
||||
const cards = newPage.locator('.hot-selection-list a.recommend-card');
|
||||
const count = await cards.count();
|
||||
|
||||
console.log("热门项目数量:", count);
|
||||
|
||||
if (count === 0) {
|
||||
throw new Error("没有找到热门项目");
|
||||
}
|
||||
await newPage.waitForTimeout(2000);
|
||||
// 随机选一个
|
||||
const index = Math.floor(Math.random() * count);
|
||||
console.log("随机选择 index:", index);
|
||||
// 点击并捕获新 tab
|
||||
const [newPage2] = await Promise.all([
|
||||
newPage.context().waitForEvent('page'),
|
||||
cards.nth(index).click()
|
||||
]);
|
||||
// 等待 Star 按钮出现
|
||||
const starBtn = newPage2.locator('#repo-header-tab .status-btn').filter({ hasText: 'Star' }).nth(1);
|
||||
await newPage2.waitForTimeout(2000);
|
||||
await starBtn.waitFor({ state: 'visible' });
|
||||
// 判断是否已 Starred
|
||||
const text = await starBtn.innerText();
|
||||
await newPage2.waitForTimeout(2000);
|
||||
if (text.includes('Starred')) {
|
||||
// 已经 Starred -> 先取消
|
||||
await starBtn.click();
|
||||
|
||||
// 等待变回 Star
|
||||
await newPage2.waitForTimeout(500);
|
||||
}
|
||||
await starBtn.click();
|
||||
await newPage2.waitForTimeout(2000);
|
||||
newPage2.close()
|
||||
newPage.close()
|
||||
}
|
||||
Reference in New Issue
Block a user