开发日志25120809
date
Dec 9, 2025
slug
开发日志25120809
status
Published
tags
计算机
AI
summary
今天处理了若干BUG…
type
Post
今天处理一下 行为计数 功能
//==========总览
const root = 'LOG';
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
const path = `HOST/${today}.json`;
// 读取文件
let summary = {};
try {
const resHost = await fetch(`/api/file/read?root=${encodeURIComponent(root)}&path=${encodeURIComponent(path)}`);
if (resHost.ok || resHost.status === 404) {
summary = await resHost.json();
if (JSON.stringify(summary) === '{}') {
summary = { summary: {}, devices: [] };
}
} else {
throw new Error(`HTTP ${resHost.status}: ${resHost.statusText}`);
}
} catch (error) {
// 网络错误或其他异常,也使用空数组
console.warn('获取文件失败,使用空数组:', error.message);
}
//总览
let summaryHost = summary.summary;
//找到对应项
let summaryDevice = summary.devices.find(item => item.deviceId === deviceId);
if (!summaryDevice) {
summaryDevice = { deviceId }
summary.devices.push(summaryDevice);
};
//如果返回脚本执行成功
let updparam = ['totalRuns'];//需要+1的参数
if (result) {
updparam.push('successCount');
if (returns.likeVideo) updparam.push('likeVideo');
if (returns.commentVideo) updparam.push('commentVideo');
} else {
updparam.push('failureCount');
}
updSummary(updparam, summaryHost, summaryDevice);
post(`/api/file/write`, {
root,
path,
content: JSON.stringify(summary, null, 4)
});
function updSummary(keys, objs) {
if (!keys || !objs) return;
// 确保传入是数组(兼容字符串和数组两种传参方式)
const keyList = Array.isArray(keys) ? keys : [keys];
const objList = Array.isArray(objs) ? objs : [objs];
//对每个对象的对应键值+1
keyList.forEach(key => {
objList.forEach(obj => {
if (key in obj) {
obj[key]++;//次数+1
} else {
obj[key] = 1;//置为1
}
});
});
}//====================执行结果记录
const root = 'SUMMARY';
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
const hostPath = `HOST/${today}.json`;
const devicePath = `设备${deviceNo} - ${deviceId}/${today}.json`;
// 读取文件
let summary = {};
let record = {};
//执行总数记录
try {
const resHost = await fetch(`/api/file/read?root=${encodeURIComponent(root)}&path=${encodeURIComponent(hostPath)}`);
if (resHost.ok) {
summary = await resHost.json();
if (Object.keys(summary).length === 0) {
summary = { summary: {}, devices: [] };
}
} else if (resHost.status === 404) {
summary = { summary: {}, devices: [] };
} else {
throw new Error(`HTTP ${resHost.status}: ${resHost.statusText}`);
}
} catch (error) {
// 网络错误或其他异常,也使用空数组
console.warn('获取文件失败,使用空数组:', error.message);
}
//单台设备详细记录
try {
const resDevice = await fetch(`/api/file/read?root=${encodeURIComponent(root)}&path=${encodeURIComponent(devicePath)}`);
if (resDevice.ok) {
record = await resDevice.json();
if (Object.keys(record).length === 0) {
record = { summary: {}, runs: [] };//若空则初始化
}
} else if (resDevice.status === 404) {
record = { summary: {}, runs: [] };//若空则初始化
} else {
throw new Error(`HTTP ${resDevice.status}: ${resDevice.statusText}`);
}
} catch (error) {
// 网络错误或其他异常,也使用空数组
console.warn('获取文件失败,使用空数组:', error.message);
}
//执行总数记录
let summaryHost = summary.summary;
//找到设备对应对象
let summaryDevice = summary.devices.find(item => item.deviceId === deviceId);
//为空时push到数组中
if (!summaryDevice) {
summaryDevice = { deviceId }
summary.devices.push(summaryDevice);
};
//设备执行记录
let recordSummary = record.summary;
//如果返回脚本执行成功
let keys = ['totalRuns'];//总运行次数+1
let updObj = [summaryHost, summaryDevice, recordSummary]
//... 所有设备总计数 单设备计数 单设备详细记录
if (result) {
//更新到summary
keys.push('successCount');//如果成功运行+1
} else {
keys.push('failureCount');//如果失败运行+1
}
updSummary(keys, updObj);
//分平台结果分别储存
keys = [];
summaryDevice[platform] = summaryDevice[platform] || {};
recordSummary[platform] = recordSummary[platform] || {};
updObj = [summaryDevice[platform], recordSummary[platform]];
//后期可能需要自动判断
if (returns.likeVideo) keys.push('likeVideo');//如果点赞了+1
if (returns.myComment) keys.push('commentVideo');//如果评论了+1
updSummary(keys, updObj);
//固定运行记录
let currentRecord = {
task: task.name,
platform,
success: result,
returns
}
//push到数组
record.runs.push(currentRecord);
//写入总记录
post(`/api/file/write`, {
root,
path: hostPath,
content: JSON.stringify(summary, null, 4)
});
//写入详细记录
post(`/api/file/write`, {
root,
path: devicePath,
content: JSON.stringify(record, null, 4)
});优化暂停方法 现在可以强制停止脚本执行
在 runTaskChain() 函数中添加将任务放进数组的方法
let taskRunning = {};
if (!window.taskRunning.length) {
window.taskRunning.push({ deviceId, task: task.script })
} else {
taskRunning = window.taskRunning.find(item => item.deviceId === deviceId);//指示当前运行脚本的对象
}
taskRunning.task = task.script;在 main.js 中添加对应方法执行暂停
logInfo.w('强制停止所有任务');
const allDevices = window.taskRunning.map(item => item.deviceId);
const uniqueDevices = [...new Set(allDevices)]
const allTasks = window.taskRunning.map(item => item.task);
// 使用 Set 去除重复值,然后展开为数组
const uniqueTasks = [...new Set(allTasks)];
uniqueTasks.forEach(item => {
send({
"action": "StopAutoJs",
"comm": {
"deviceIds": uniqueDevices.join(','),
"filePath": item
}
});
});
});用AI写了一个读取行为记录的模块
record.html 之前用比较蠢的方法实现空对象判断
JSON.stringify(json) === '{}' 后改用更好的
Object.keys(json).length === 0 之前使用的 switch() 判断:
switch (true) {
case author === null:
logInfo.e(`找不到作者`);
returns.likeVideo = false;
break;
case author === 'isLive':
logInfo.w(`当前视频为直播间,跳过本次操作`);
returns.likeVideo = false;
break;
default:
logInfo.s(`当前视频作者: ${author},视频简介: ${desc}`);
}现发现确实并不好用 改回 if()
if (author === 'isLive') {
logInfo.w(`当前视频为直播间,跳过本次操作`);
returns.likeVideo = false;
} else if (!author) {
logInfo.e(`找不到作者`);
returns.likeVideo = false;
} else {
logInfo.s(`当前视频作者: ${author},视频简介: ${desc}`);
}之前使用的过滤屏幕外对象函数可靠性比较低 很大概率把我需要的东西过滤掉 因为传入的参数 maxTop maxBottom 有可能不满足要求 但是我不可能对每次过滤都测试太多次 进行了修改 现会先过滤一次 异常元素 例如元素的 .top 比 .bottom 大( 较大的值在下方 ) 若过滤结果只剩一个则直接返回 若还剩下多个则按传入参数二次过滤:
function filterOnScreen(element, maxTop, maxBottom) {
try {
if (element) {
// logInfo.d('element处理前\n' + element.join('\n'));
maxBottom = maxBottom || height - 500;//默认最低屏幕高度-500px
maxTop = maxTop || 100;//默认最高从上往下100px
element = element.filter(obj => {
let bounds = obj.bounds();
let top = bounds.top;
let bottom = bounds.bottom;
return bottom > top;//直接过滤底部比顶部高的对象
});
if (element.length === 1) {
logInfo.s('只剩下一个结果,过滤成功');
return element;
} else {
logInfo.w('似乎剩下不止一个结果 正在尝试严格过滤');
element = element.filter(obj => {
let bounds = obj.bounds();
logInfo.i(bounds.join());
let top = bounds.top;
return top > maxTop && top < maxBottom;//过滤不满足传入条件者
});
}
logInfo.d('element处理后\n' + element.join('\n'));
return element || [];
}
} catch (e) {
logInfo.e(e);
}
}
之前使用的查询 #title 方法只进行两次 而且代码冗长 现进行了调整 可以查询五次 增强可靠性
//寻找ID
let isFound = false;
let time = 0;
let candidates;
while (!isFound && time < 5) {
candidates = id('title').textContains('@').find();
logInfo.d(`第${time}次查询candidates:\n + ${candidates.join('\n')}`);
if (!candidates.empty()) {
//若不为空则过滤屏幕外对象
candidates = filterOnScreen(candidates, height / 2, height);
//取第一个
if (candidates.length > 0) {
authorEle = candidates[0]
author = authorEle.text();
descEle = findDesc(authorEle);
if (descEle) desc = descEle.text();
isFound = true;
}
};
time++;
}
if (!author) return { author: null, desc: null };
return { author, desc };现在的暂停按钮功能单一 只能 全部暂停全部强制停止 现添加函数可以暂停特定设备
合并了window.isPaused 和window.taskRunning 到window.taskStatus 通过一个全局数组控制任务的进行
判断是否暂停
while (true) {
// 每次都重新查找最新的状态
const currentData = window.taskStatus.find(item => item.deviceId === deviceId);
if (!currentData || currentData.status !== "paused") {
break; // 设备不存在或状态不是暂停,退出循环
}
await sleep(1000); // 等待1秒后再次检查
}更新任务列表方法 现在都是针对设备进行调控 不会因为不断push导致数组巨大重复数量又太多
//在数组中找到设备
const found = window.taskStatus.find(item => item.deviceId === deviceId);
if (found) {//如果找到设备 则替换任务
found.task = task.script;
} else {
//如果没找到 则push到数组
window.taskStatus.push({ deviceId, task: task.script, status: 'running' });
}修改了继续任务的条件 可以在判断onComplete的同时判断任务是否被停止
const deviceStatus = window.taskStatus.find(item => item.deviceId === deviceId).status;
const onComplete = task.onComplete ? task.onComplete(result, deviceLog) : (result);
const shouldContinue = deviceStatus && onComplete;重构了暂停和停止的方法 有点容易晕 明天可能要再调试一下
//查询当前设备的运行状态
const thisStatus = window.taskStatus.find(item => item.deviceId === deviceId);
//获取按钮元素
const btn = document.getElementById('pause_' + deviceId);
if (thisStatus) {//如果不为空
if (thisStatus.status === 'running') {//值为running
thisStatus.status = 'paused';
btn.textContent = '恢复';
btn.style.backgroundColor = '#e74c3c';
logInfo.w(`设备${deviceNo}已暂停`);
} else if (thisStatus.status === 'paused') {//值为paused
thisStatus.status = 'running';
btn.textContent = '暂停';
btn.style.backgroundColor = '';
logInfo.i(`设备${deviceNo}已恢复`);
}
} else {
console.log('不知道什么情况 反正找不到这台设备的运行状态');
}
});stop.addEventListener('click', () => {
const thisStatus = window.taskStatus.find(item => item.deviceId == deviceId);
let taskPath = '';
if (thisStatus) {
taskPath = thisStatus.task;
send({
"action": "StopAutoJs",
"comm": {
"deviceIds": deviceId,
"filePath": taskPath
}
});
logInfo.w(`强制停止设备 ${deviceNo} 任务`);
thisStatus.status = 'stopped';
} else {
logInfo.e(`找不到设备 ${deviceNo} 执行的任务`)
}
});//查询所有状态
const statusMap = taskStatus.map(item => item.status);
if (!statusMap.includes("paused") || btn.textContent === '暂停所有任务') {//如果不含paused 则现在状态为全部运行状态 暂停所有任务
window.taskStatus.forEach(task => {//对任务状态表里的每个项
if (task.status === 'running') {//如果状态为暂停
const deviceId = task.deviceId;
const btn = document.getElementById('pause_' + deviceId);//找到按钮
task.status = 'paused';//修改为运行
btn.textContent = '恢复';//列表按钮改为暂停
btn.style.backgroundColor = '#e74c3c';//列表按钮背景清理
}
});
btn.textContent = '恢复所有任务';
btn.style.backgroundColor = '#e74c3c';
logInfo.w('所有设备已暂停');
} else if (!statusMap.includes("running") || btn.textContent === '恢复所有任务') {//如果不含running 则现在状态为全部暂停状态 恢复所有任务
window.taskStatus.forEach(task => {//对任务状态表里的每个项
if (task.status === 'paused') {//如果状态为暂停
const deviceId = task.deviceId;
const btn = document.getElementById('pause_' + deviceId);//找到按钮
task.status = 'running';//修改为运行
btn.textContent = '暂停';//列表按钮改为暂停
btn.style.backgroundColor = '';//列表按钮背景清理
}
});
btn.textContent = '暂停所有任务';
btn.style.backgroundColor = '';
logInfo.w('所有设备已恢复');
}结束的时候发现 全局停止的功能似乎不可靠
@TODO:修复全局停止的功能
需要处理广告跳过了 已经dump下了页面的结构 就是又臭又长需要分析一下





大概就这几种广告 明天处理