chenxixi
2024-06-07 eb2669938522227553faccd7569b2fe6a7cec8d7
update
7 files deleted
5 files added
3423 ■■■■ changed files
ec-rpa/src/js/dy_ActionOnComments.js 590 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/dy_main.js 439 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/dy_privateLetter.js 317 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/dy_replayComment.js 384 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/enterLiveStream.js 24 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/getComments.js 19 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/http.js 41 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/randomComment.js 47 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/randomLike.js 26 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/subjs/dy_getMessage.js 322 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/subjs/dy_privateMessage.js 628 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/subjs/dy_replayComment.js 586 ●●●●● patch | view | raw | blame | history
ec-rpa/src/js/dy_ActionOnComments.js
New file
@@ -0,0 +1,590 @@
// 对命中评论进行回复, 私信, 点赞操作
// 请勿让日志窗口遮挡设备屏幕
let packageName = 'com.ss.android.ugc.aweme'; //抖音包名
let searchContent, replyWords, messageWords, hitKeywords, everyNumber, total; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量
getECloudData(); //获取任务数据
/**
 * description 获取云控参数
 * @return {boolean} : 返回是否成功
 */
function getECloudData() {
    let result = false, data, hasData = true, value;
    //通过数据组名或数据名称取得数据
    let group = [{
        "groupName" : "短视频代运营搜索词",
        "dataName" : "斗因-视频搜索词"
    },{
        "groupName" : "短视频代运营话术",
        "dataName" : "斗因-回复评论话术"
    },{
        "groupName" : "短视频代运营命中关键词",
        "dataName" : "斗因-评论命中关键词"
    },{
        "groupName" : "短视频代运营执行数量",
        "dataName" : "斗因-评论执行数量"
    },{
        "groupName" : "短视频代运营话术",
        "dataName" : "斗因-私信话术"
    }];
    for (let i = 0; i < group.length; i++) {
        data = ecloud.getData(group[i]);
        if (data[0]) {
            if (i == 0) {
                searchContent = value = data[0].content.split("|");
            } else if (i == 1) {
                replyWords = value = data[0].content.split("\n");
            } else if (i == 2) {
                hitKeywords = value = data[0].content.split("|");
            } else if (i == 3)  {
                let array = value = data[0].content.split("|");
                everyNumber = array[0];
                total = array[1];
            } else if (i == 4)  {
                messageWords = value = data[0].content.split("\n");
            }
            if (!value || value.length == 0) {
                hasData = false;
                loge('未设置' + group[i].dataName);
                break;
            }
        } else {
            hasData = false;
            loge('未获取' + group[i].dataName);
            break;
        }
    }
    if (hasData) {
        logi('已获取任务数据,开始执行...');
        randomSleep();
        result = true;
        launch(packageName, 6000, 3); //打开抖音
    }
    return result;
}
/**
 * description 通过包名启动应用
 * @param packageName {string} : 应用包名
 * @param delay {number} : 启动后等待时长(毫秒)
 * @param startNum {number} : 重试次数
 * @return {boolean} : 返回是否成功
 */
function launch(packageName, delay, startNum) {
    let result = false;
    //判断应用的包名是否存在
    if (utils.isAppExist(packageName)) {
        //判断应用是否在前台
        if (getRunningPkg() == null) {
            loge('请开启辅助功能权限');
        } else if (getRunningPkg() === packageName) {
            logi('应用已经在前台');
            result = true;
            search(); //搜索视频
        } else {
            logi('启动应用...');
            let alert_selectors = text("允许");
            let num = 0;
            //判断应用是否启动成功
            while (num < startNum) {
                if (getRunningPkg() === packageName) {
                    insertTrace('', '', '', "应用启动");
                    logi('启动成功');
                    result = true;
                    search(); //搜索视频
                    break;
                } else if (has(alert_selectors)) {
                    //初次打开应用 可能会弹出是否允许打开的弹窗
                    let node = alert_selectors.getOneNodeInfo(3000);
                    if (node) {
                        node.click();
                    }
                } else {
                    utils.openApp(packageName);
                    sleep(delay);
                    num++;
                }
            }
        }
        alert(); //应用启动后处理弹窗
    } else {
        loge('应用未安装');
    }
    return result;
}
/**
 * description 根据关键词搜索视频
 * @return {boolean} : 返回是否成功
 */
function search() {
    //定位到首页
    execSync(function () {
        isHome();
    }, 1000);
    let result = false;
    //寻找搜索按钮并点击
    toast('开始搜索...');
    let search = descMatch(".*搜索.*").getOneNodeInfo(5000);
    if (search) {
        if (search.click()) {
            randomSleep();
            //寻找输入框 输入搜索词
            toast('输入搜索内容...');
            let input_selectors = clz("android.widget.EditText").getOneNodeInfo(5000);;
            let keyword = searchContent[random(0, searchContent.length - 1)];
            if (input_selectors) {
                if (input_selectors.inputText(keyword)) {
                    randomSleep();
                    //点击搜索
                    if (search.click()) {
                        insertTrace('', '', keyword, "搜索");
                        randomSleep();
                        toast('搜索完成');
                        //进入视频页
                        let tab_node = clz("android.widget.Button").getNodeInfo(5000);
                        if (tab_node) {
                            for (let i = 0; i < tab_node.length; i++) {
                                if (tab_node[i].text === "视频") {
                                    if (tab_node[i].click()) {
                                        randomSleep();
                                        //浏览视频
                                        let video_node = depth(20).getOneNodeInfo(5000); //根据深度匹配
                                        toast('浏览视频...');
                                        if (video_node) {
                                            if (video_node.click()) {
                                                randomSleep();
                                                let nameSelectors = id("com.ss.android.ugc.aweme:id/title").getOneNodeInfo(2000);
                                                let postSelectors = id("com.ss.android.ugc.aweme:id/desc").getOneNodeInfo(2000);
                                                insertTrace(postSelectors.text, nameSelectors.text, '', "搜索");
                                                result = true;
                                                reply(); //回复评论
                                                break;
                                            } else {
                                                toast('浏览失败');
                                                exit();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        toast('搜索失败');
                        exit();
                    }
                } else {
                    toast('输入失败');
                    exit();
                }
            }
        } else {
            toast('未找到搜索按钮');
            exit();
        }
    }
    return result;
}
/**
 * description 回复一级评论
 * @param p {number} : 私信概率
 * @param everyNumber {number} : 单个视频回复数量
 * @param total {number} : 总回复数量
 */
function reply() {
    let completedNumber = 0; //已回复总数
    var flag = false;
    while (true) {
        //寻找评论图标并点击
        toast('打开评论...');
        let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000);
        if (comment_icon) {
            if (comment_icon.click()) {
                var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
                if (result) {
                    randomSleep();
                    toast('放大评论区');
                    let btn = desc("放大评论区").visible(true).getOneNodeInfo(3000);
                    if (btn) {
                        if (btn.click()) {
                            flag = true;
                            randomSleep();
                            var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
                            let num = 0 //回复数量
                            while (flag) {
                                for (var i = 0; i < result.length; i++) {
                                    var hasKey = false;
                                    if (num < everyNumber) {
                                        toast('浏览第' + (i + 1) + '条评论...');
                                        var comments = result[i].text; //评论内容
                                        for (var n = 0; n < hitKeywords.length; n++) {
                                            // execSync(function () {
                                            if (comments.includes(hitKeywords[n])) {
                                                var sub = result[i].nextSiblings()[0]; //评论节点
                                                var t = sub.child(0);
                                                var ip = sub.child(1);
                                                hasKey = true;
                                                toast('第' + (i + 1) + '条评论命中关键词,进行回复...');
                                                randomSleep();
                                                insertCommentsGot(comments, hitKeywords[n], t, ip);
                                                if (result[i].click()) {
                                                    toast('输入回复内容...');
                                                    let words = replyWords[random(0, replyWords.length - 1)];
                                                    let input_selectors = clz("android.widget.EditText").getOneNodeInfo(50000);
                                                    if (input_selectors) {
                                                        if (input_selectors.inputText(words)) {
                                                            randomSleep();
                                                            let send = text("发送").getOneNodeInfo(3000);
                                                            if (send) {
                                                                send.click();
                                                                num++;
                                                                completedNumber++;
                                                                toast('完成回复');
                                                                randomSleep();
                                                                // break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            // }, 1000);
                                        }
                                        if (i == result.length - 1 && !hasKey) {
                                            num++;
                                            completedNumber++;
                                            toast('当前视频未找到命中评论');
                                            randomSleep();
                                        }
                                    } else if (Number(completedNumber) === Number(total)) {
                                        toast("所有评论完成");
                                        shell.stopApp(packageName); //关闭抖音
                                        home();
                                        exit()
                                    } else {
                                        let btn = desc("缩小评论区").visible(true).getOneNodeInfo(3000);
                                        if (btn.click()) {
                                            randomSleep();
                                        }
                                        flag = false;
                                        go_back(1);
                                        toast('当前视频回复完成,下一个视频...');
                                        randomSleep();
                                        swiper(); //下一个视频
                                        break
                                        break;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    toast('未找到评论');
                    randomSleep();
                    go_back(2);
                    swiper(); //下一个视频
                    // break;
                }
            }
        }
    }
}
/**
 * description 异步执行线程 处理弹窗
 * @return {boolean} : 返回是否成功
 */
function alert() {
    thread.execAsync(function () {
        logd('启动线程,查找弹窗');
        let btnText = new Array(
            "下次再说",
            "以后再说",
            "关闭",
            "暂时不要",
            "暂不",
            "取消",
            "我知道了",
            "知道了",
            "允许",
            "确定",
            "确认",
        );
        while (true) {
            for (let i = 0; i < btnText.length; i++) {
                logd('检查弹窗...');
                let node = text(btnText[i]).getOneNodeInfo(1000);
                if (node) {
                    node.click();
                    toast('弹窗已处理');
                }
            }
            sleep(4000);
        }
    });
    return true;
}
/**
 * description 定位到首页
 * @return {boolean} : 返回是否成功
 */
function isHome() {
    let result = false;
    while (true) {
        var home_selectors = text("首页").getOneNodeInfo(3000); //首页按钮
        var message_selectors = text("消息").getOneNodeInfo(3000); //消息按钮
        //判断是否在首页
        if (home_selectors && message_selectors) {
            var follow_selectors = text("关注"); //关注按钮
            var recommend_selectors = text("推荐"); //推荐按钮
            if (has(follow_selectors) && has(recommend_selectors)) {
                toast('已定位首页');
                randomSleep();
                result = true;
                break;
            } else {
                home_selectors.click();
                sleep(3000);
            }
        } else {
            toast('返回首页...');
            //返回上一页
            go_back(1);
        }
    }
    return result;
}
/**
 * description 自定义返回函数
 * @param page {number} : 返回页数
 */
function go_back(page) {
    let count = 0;
    while (count < page) {
        back();
        count++;
        randomSleep();
    }
}
/**
 * description 随机暂停时间
 */
function randomSleep() {
    let min = Math.ceil(3);
    let max = Math.floor(6);
    let time = (Math.floor(Math.random() * (max - min + 1)) + min) * 1000;
    sleep(time);
}
/**
 * description 插入埋点
 * @param unique_id {string} : 用户唯一编号
 * @param post_name {string} : 作品名称
 * @param nickname {string} : 用户昵称
 * @param keyword {string} : 搜索关键词
 * @param operate_type {string} : 操作类型
 */
function insertTrace(post_name, nickname,keyword, operate_type) {
    let time = getDate();
    var deviceNo = ecloud.getDeviceNo(); //设备编号
    var unique_id = deviceNo.slice(3);
    let add = {
        "tableNameEn": "trace",
        "columns": {
            "device_no" : deviceNo, //设备编号
            "operate_time" : time, //操作时间
            "platform" : "抖音", //所属平台
            "unique_no" : unique_id, //用户唯一编号
            "post_name" : post_name, //作品名称
            "nickname" : nickname, //用户昵称
            "keyword" : keyword, //搜索关键词
            "operate_type" : operate_type //操作类型
        }
    }
    ecloud.dynamicAdd(add);
}
/**
 * description 插入命中作品评论
 * @param content {string} : 线索
 * @param got_word {string} : 命中词
 * @param comment_datetime {string} : 评论时间
 * @param province {string} : 省
 */
function insertCommentsGot(content, got_word, comment_datetime,province) {
    let time = getDate();
    let add = {
        "tableNameEn": "dy_comments_got",
        "columns": {
            "task_id" : '', //任务id
            "task_name" : '', //任务名
            "title" : "", //视频标题
            "dy_nickname" : '', //抖音昵称
            "content" : content, //线索
            "tel" : '',//手机号
            "got_word" : got_word ,//命中词
            "comment_datetime" : comment_datetime, //评论时间
            "grab_datetime" : time, //挖掘时间
            "province" : province //省
        }
    }
    ecloud.dynamicAdd(add);
}
/**
 * description 获取当前时间
 * @return {string} : 返回时间
 */
function getDate() {
    let date = new Date();
    let sign2 = ":";
    let year = date.getFullYear() // 年
    let month = date.getMonth() + 1; // 月
    let day = date.getDate(); // 日
    let hour = date.getHours(); // 时
    let minutes = date.getMinutes(); // 分
    let seconds = date.getSeconds() //秒
    let weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
    let week = weekArr[date.getDay()];
    // 给一位数的数据前面加 “0”
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (day >= 0 && day <= 9) {
        day = "0" + day;
    }
    if (hour >= 0 && hour <= 9) {
        hour = "0" + hour;
    }
    if (minutes >= 0 && minutes <= 9) {
        minutes = "0" + minutes;
    }
    if (seconds >= 0 && seconds <= 9) {
        seconds = "0" + seconds;
    }
    return year + "-" + month + "-" + day + " " + hour + sign2 + minutes + sign2 + seconds;
}
/**
 * description 滑动视频
 * @return {boolean} : 返回是否成功
 */
function swiper(){
    let result = false;
    //设定坐标 适配全分辨率
    let x = device.getScreenWidth() * 7 / 10;
    let y = device.getScreenHeight() * 8 / 10;
    let x1 = device.getScreenWidth() * 7 / 10;
    let y1 = device.getScreenHeight() * 1.5 / 10
    if (rnd_Swipe(x,y,x1,y1,100,200,200)) {
        sleep(3000);
        logd("滑动完成");
        result = true;
    }
    return result;
}
/**
 * description 仿真随机带曲线滑动
 */
function rnd_Swipe(qx, qy, zx, zy,time, times,timess) {
    //qx, qy, zx, zy, time 代表起点x,起点y,终点x,终点y,times,timess =随机时间(times,timess)
    let time1,xxy,point,dx0,dx1,dx2,dx3,xxyy
    time1=random(times,timess)
    xxy = [];
    point = [];
    dx0 = {
        "x": qx,
        "y": qy
    }
    dx1 = {
        "x": random(qx - 100, qx + 100),
        "y": random(qy , qy + 50)
    }
    dx2 = {
        "x": random(zx - 100, zx + 100),
        "y": random(zy , zy + 50),
    }
    dx3 = {
        "x": zx,
        "y": zy
    }
    for (let i = 0; i < 4; i++) {
        eval("point.push(dx" + i + ")");
    }
    for (let i = 0; i < 1; i += 0.08) {
        xxyy = [parseInt(bezier_curves(point, i).x), parseInt(bezier_curves(point, i).y)]
        xxy.push(xxyy);
    }
    gesture(xxy,time, time1);
    return true;
}
/**
 * description 贝赛尔曲线
 */
function bezier_curves(cp, t) {
    let cx,bx,ax,cy,by,ay,tSquared,tCubed,result
    cx = 3.0 * (cp[1].x - cp[0].x);
    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    ax = cp[3].x - cp[0].x - cx - bx;
    cy = 3.0 * (cp[1].y - cp[0].y);
    by = 3.0 * (cp[2].y - cp[1].y) - cy;
    ay = cp[3].y - cp[0].y - cy - by;
    tSquared = t * t;
    tCubed = tSquared * t;
    result = {
        "x": 0,
        "y": 0
    }
    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
    return result;
}
/**
 * description 手势
 */
function gesture(swipeList,time,time1) {
    let touch1 ,touch2,x,i
    touch1 = [{"action": 0, "x": swipeList[0][0], "y": swipeList[0][1], "pointer": 1, "delay": time}]
    for (i in swipeList) {
        ++i;
        if (i===swipeList.length-2) {break;}
        touch1.push({"action": 1, "x": swipeList[i][0], "y": swipeList[i][1], "pointer": 1, "delay": time});
    }
    touch1.push({"action": 2, "x": swipeList[swipeList.length-1][0], "y": swipeList[swipeList.length-1][1], "pointer": 1, "delay": time})
    x = multiTouch(touch1, null, null, time1);
    logd('仿真滑动:'+x);
    sleep(3000);
}
ec-rpa/src/js/dy_main.js
File was deleted
ec-rpa/src/js/dy_privateLetter.js
New file
@@ -0,0 +1,317 @@
/**
 * 指定用户私信
 *
 */
let packageName = 'com.ss.android.ugc.aweme';
var searchUserIds, replyWords; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量
getECloudData(); //获取用户ids
/**
 * description 获取云控参数
 * @return {boolean} : 返回是否成功
 */
function getECloudData() {
    let result = false;
    let hasData = true, value;
    let data = new Array();
    let group = [{
        "groupName": "短视频代运营用户ids",
        "dataName": "斗因-大数据用户id"
    }, {
        "groupName": "短视频代运营话术",
        "dataName": "斗因-回复评论话术"
    }];
    //通过数据组名或数据名称取得数据
    for (let i = 0; i < group.length; i++) {
        data = ecloud.getData(group[i]);
        if (data[0]) {
            if (i == 0) {
                searchUserIds = value = data[0].content.split("\n");
            } else if (i == 1) {
                replyWords = value = data[0].content.split("\n");
            }
            if (!value || value.length == 0) {
                hasData = false;
                toast('未设置' + group[i].dataName);
                break;
            }
        } else {
            hasData = false;
            toast('未获取' + group[i].dataName);
            break;
        }
    }
    if (hasData) {
        toast('已获取任务数据,开始执行...');
        randomSleep();
        result = true;
        launch(packageName, 6000, 3); //打开抖音
        // reply();
    }
    return result;
}
sendMessage();
/**
 * description 通过包名启动应用
 * @param packageName {string} : 应用包名
 * @param delay {number} : 启动后等待时长(毫秒)
 * @param startNum {number} : 重试次数
 * @return {boolean} : 返回是否成功
 */
function launch(packageName, delay, startNum) {
    let result = false;
    //判断应用的包名是否存在
    if (utils.isAppExist(packageName)) {
        //判断应用是否在前台
        if (getRunningPkg() == null) {
            toast('请开启辅助功能权限');
            exit();
        } else if (getRunningPkg() === packageName) {
            logd('应用已经在前台');
            result = true;
        } else {
            logd('启动应用...');
            let alert_selectors = text("允许");
            let num = 0;
            //判断应用是否启动成功
            while (num < startNum) {
                if (getRunningPkg() === packageName) {
                    logd('启动成功');
                    result = true;
                    break;
                } else if (has(alert_selectors)) {
                    //初次打开应用 可能会弹出是否允许打开的弹窗
                    let node = alert_selectors.getOneNodeInfo(1000);
                    if (node) {
                        node.click();
                    }
                } else {
                    utils.openApp(packageName);
                    sleep(delay);
                    num++;
                }
            }
        }
        alert(); //应用启动后处理弹窗
        operaLog(1, null);
    } else {
        toast('应用未安装');
        exit();
    }
    return result;
}
/**
 * description 随机暂停时间
 */
function randomSleep() {
    let min = Math.ceil(3);
    let max = Math.floor(6);
    let time = (Math.floor(Math.random() * (max - min + 1)) + min) * 1000;
    sleep(time);
}
function sendMessage() {
    let result = false;
    //定位到首页
    // thread.execSync(function () {
    //     isHome();
    // }, 1000);
    let search = descMatch(".*搜索.*").getOneNodeInfo(1000);
    //寻找搜索出现并点击
    if (search.click()) {
        sleep(3000);
        let input_selectors = clz("android.widget.EditText");
        let userId = searchUserIds[random(0, searchUserIds.length - 1)];
        //寻找输入框 输入关键词
        if (inputText(input_selectors, userId)) {
            sleep(3000);
            //开始搜索
            if (search.click()) {
                operaLog(2, userId);
                sleep(5000);
                //打开用户页 进入用户列表
                let tab_node = clz("android.widget.Button").getNodeInfo(1000);
                for (let i = 0; i < tab_node.length; i++) {
                    if (tab_node[i].text === "用户") {
                        tab_node[i].click();
                        sleep(2000);
                        let selector = clz("com.lynx.tasm.behavior.ui.LynxFlattenUI").getOneNodeInfo(1000);
                        if (selector.click()) {
                            operaLog(3, null);
                            // 进入用户主页
                            let words = replyWords[random(0, replyWords.length - 1)];
                            send(words);
                            operaLog(6, null)
                        } else {
                            logd("进入用户主页失败");
                        }
                    }
                }
            } else {
                loge('搜索失败');
                exit();
            }
        } else {
            loge('输入失败');
            exit();
        }
    } else {
        loge('未找到搜索按钮');
        exit();
    }
    return result;
}
/**
 * description 发私信消息
 * @param words 私信话术 私信时随机抽取
 * @return {boolean} : 返回是否成功
 */
function send(words) {
    let result = false;
    let follow = text("关注");
    let title = text("账号已经注销").getOneNodeInfo(1000);
    //判断是否关注用户
    let follow_btn = getNodeInfo(follow, 1000);
    if (follow_btn[1]) {
        follow_btn[1].click();
        operaLog(4, null);
        logd('关注用户');
        sleep(4000);
        //判断私密账户
        let private = textMatch(".*私密账号.*").getOneNodeInfo(1000);
        let okArr = new Array(
            "取消",
            "知道了",
        );
        if (private) {
            for (let i = 0; i < okArr.length; i++) {
                let ok = text(okArr[i]).getOneNodeInfo(1000);
                ok.click();
                sleep(3000);
                return result;
            }
        }
    }
    let message_btn = text("私信").getOneNodeInfo(1000);
    //判断是否注销
    if (title) {
        result = false;
    } else if (message_btn.click()) {
        logd('进入私信');
        sleep(4000);
        let input_selectors = clz("android.widget.EditText");
        //寻找输入框 输入话术
        if (inputText(input_selectors, words)) {
            sleep(4000);
            let send_btn = desc("发送").getOneNodeInfo(1000);
            if (send_btn.click()) {
                sleep(4000);
                logd("私信成功");
                operaLog(5, words);
                result = true;
            }
        }
    }
    return result;
}
/**
 * description 自定义返回函数
 * @param page {number} : 返回页数
 */
function go_back(page) {
    let count = 0;
    while (count < page) {
        back();
        count++;
        sleep(3000);
    }
}
/**
 * description 异步执行线程 处理弹窗
 * @return {boolean} : 返回是否成功
 */
function alert() {
    thread.execAsync(function () {
        logd('启动线程,查找弹窗');
        let btnText = new Array(
            "下次再说",
            "以后再说",
            "关闭",
            "允许",
            "暂不",
            "暂时不要",
            "我知道了",
            "知道了",
            "取消",
        );
        while (true) {
            for (let i = 0; i < btnText.length; i++) {
                logd('检查弹窗...');
                let node = text(btnText[i]).getOneNodeInfo(1000);
                if (node) {
                    node.click();
                    logd('弹窗已处理');
                }
            }
            sleep(3000);
        }
    });
    return true;
}
/**
 * 记录埋点数据
 */
function operaLog(num, words) {
    let paltform = '';
    let operateType = '';
    let uniqueNo = '';
    if (num === 1) {
        operateType = '应用启动'
    } else if (num === 2) {
        operateType = '搜索'
    } else if (num === 3) {
        operateType = '浏览主页'
    } else if (num === 4) {
        operateType = '关注用户'
    } else if (num === 5) {
        operateType = '私信'
    } else if (num === 6) {
        operateType = '脚本运行结束'
    }
    if ('com.ss.android.ugc.aweme'.equals(packageName)) {
        // 斗音
        paltform = '抖音'
        uniqueNo = ecloud.getDeviceNo().substring(3)
    } else if ('小红书'.equals(packageName)) {
        // 小红书
        paltform = '小红书'
        uniqueNo = ecloud.getDeviceNo().substring(4)
    } else if ('快手'.equals(packageName)) {
        // 快手
        paltform = '快手'
        uniqueNo = ecloud.getDeviceNo().substring(3)
    }
    let add = {
        "tableNameEn": "trace",
        "columns": {
            "device_no": ecloud.getDeviceNo(),
            "platform": paltform,
            "unique_no": uniqueNo,
            "post_name": '',
            "nickname": '',
            "keyword": words,
            "operate_type": operateType,
            "task_id": ecloud.getTaskInfo().taskId,
            "task_name": ecloud.getTaskInfo().taskName,
        }
    }
    ecloud.dynamicAdd(add)
    logd("getMessage 数据保存成功");
}
ec-rpa/src/js/dy_replayComment.js
File was deleted
ec-rpa/src/js/enterLiveStream.js
File was deleted
ec-rpa/src/js/getComments.js
File was deleted
ec-rpa/src/js/http.js
File was deleted
ec-rpa/src/js/randomComment.js
File was deleted
ec-rpa/src/js/randomLike.js
File was deleted
ec-rpa/src/js/subjs/dy_getMessage.js
New file
@@ -0,0 +1,322 @@
/**
 * description 进入消息模块
 */
let packageName = 'com.ss.android.ugc.aweme';
execSync(function () {
    launch(packageName, 5000, 2); //打开抖音
}, 1000);
toMessage(packageName);
/**
 * description 通过包名启动应用
 * @param packageName {string} : 应用包名
 * @param delay {number} : 启动后等待时长(毫秒)
 * @param startNum {number} : 重试次数
 * @return {boolean} : 返回是否成功
 */
function launch(packageName, delay, startNum) {
    let result = false;
    //判断应用的包名是否存在
    if (utils.isAppExist(packageName)) {
        //判断应用是否在前台
        if (getRunningPkg() == null) {
            toast('请开启辅助功能权限');
            exit();
        } else if (getRunningPkg() === packageName) {
            logd('应用已经在前台');
            result = true;
        } else {
            logd('启动应用...');
            let alert_selectors = text("允许");
            let num = 0;
            //判断应用是否启动成功
            while (num < startNum) {
                if (getRunningPkg() === packageName) {
                    logd('启动成功');
                    result = true;
                    break;
                } else if (has(alert_selectors)) {
                    //初次打开应用 可能会弹出是否允许打开的弹窗
                    let node = alert_selectors.getOneNodeInfo(1000);
                    if (node) {
                        node.click();
                    }
                } else {
                    utils.openApp(packageName);
                    sleep(delay);
                    num++;
                }
            }
        }
        alert(); //应用启动后处理弹窗
        operaLog(1);
    } else {
        toast('应用未安装');
        exit();
    }
    return result;
}
function toMessage(packageName) {
    let message_icon = text("消息").getOneNodeInfo(1000);
    //寻找消息图标并点击
    if (message_icon.click()) {
        operaLog(2);
        sleep(2000);
        let interact_message = text("互动消息").getOneNodeInfo(1000)
        //寻找互动消息图标并点击
        if (interact_message.click()) {
            operaLog(3)
            sleep(2000);
            logd('互动消息列表...');
            let grabRequestList = [];
            var node = clz("androidx.recyclerview.widget.RecyclerView").getOneNodeInfo(2000);
            var result = node.allChildren();
            logd("================"+JSON.stringify(result));
            if (result != null) {
                for (let i = 0; i < result.length; i++) {
                    let value = result[i];
                    let desc = value.desc;
                    if (desc == '' || desc == null || desc == 'undefined' || desc == undefined) {
                        break;
                    }
                    if (!value.desc.includes("主页访客")) {
                        let grabRequest = {
                            nickname: '',
                            relation: '',
                            comment: '',
                            commentTime: ''
                        }
                        let split = value.desc.split(",");
                        if (split.length >= 3) {
                            let parts = split[1].trim().split(" ");
                            let lastPart = parts.pop();
                            let time = handleTime(lastPart);
                            let nicknameAndRelation = split[0].split(",");
                            grabRequest.nickname = nicknameAndRelation[0].trim();
                            let relationArr = new Array(["朋友", "作者", "粉丝", "你的关注", "在线"])
                            let relation = '';
                            for (let j = 0; j < relationArr.length; j++) {
                                if (!nicknameAndRelation[1].trim().includes(relationArr[i])) {
                                    relation = '路人'
                                } else {
                                    relation = nicknameAndRelation[1].trim();
                                }
                            }
                            grabRequest.relation = relation;
                            grabRequest.comment = handleComment(split[1].trim(), lastPart);
                            grabRequest.commentTime = time;
                            grabRequestList.push(grabRequest);
                        } else if (split.length === 2) {
                            let parts = split[0].trim().split(" ");
                            let lastPart = parts.pop();
                            let time = handleTime(lastPart);
                            grabRequest.nickname = split[0].trim().split(",")[0];
                            grabRequest.relation = '路人';
                            grabRequest.comment = handleComment(split[0].trim(), lastPart);
                            grabRequest.commentTime = time;
                            grabRequestList.push(grabRequest);
                        }
                    }
                }
                save(grabRequestList, packageName);
                logd("数据添加成功!");
                operaLog(4)
            }else {
                logd("暂无互动消息");
            }
        }
    }
}
function handleComment(comment, lastPart) {
    return comment.substring(0, comment.length - lastPart.length)
}
function handleTime(lastPart) {
    let time = '';
    if (lastPart.includes("刚刚") || lastPart.includes("分钟前") || lastPart.includes("小时前")) {
        // 当天
        time = formatDate(getCurrentDate());
    } else if (lastPart.includes("昨天")) {
        // 昨天
        time = formatDate(getDateBeforeDays(getCurrentDate(), 1));
    } else if (lastPart.includes("天前")) {
        // 几天前
        var array = lastPart.split("天前");
        time = formatDate(getDateBeforeDays(getCurrentDate(), parseInt(array[0], 10)));
    } else if (lastPart.split("-").length === 2) {
        // 月-日
        let newTime = new Date().getFullYear() + "-" + lastPart
        time = formatDateString(newTime)
    } else if (lastPart.split("-").length === 3) {
        // 年-月-日
        time = formatDateString(lastPart)
    }
    return time;
}
function save(grabRequestList, packageName) {
    let paltform = '';
    let uniqueNo = '';
    if ('com.ss.android.ugc.aweme'.equals(packageName)) {
        // 抖音 --- dy-ningzhu97722
        paltform = '抖音'
        uniqueNo = ecloud.getDeviceNo().substring(3)
    } else if ('小红书'.equals(packageName)) {
        // 小红书 ---- xhs-ningzhu97722
        paltform = '小红书'
        uniqueNo = ecloud.getDeviceNo().substring(4)
    } else if ('快手'.equals(packageName)) {
        // 快手 ---- ks-ningzhu97722
        paltform = '快手'
        uniqueNo = ecloud.getDeviceNo().substring(3)
    }
    for (let i = 0; i < grabRequestList.length; i++) {
        let add = {
            "tableNameEn": "grab_comment",
            "columns": {
                "task_id": ecloud.getTaskInfo().taskId,
                "task_name": ecloud.getTaskInfo().taskName,
                "device_no": ecloud.getDeviceNo(),
                "nickname": grabRequestList[i].nickname,
                "unique_no": uniqueNo,
                "content": grabRequestList[i].comment,
                "comment_time": grabRequestList[i].commentTime,
                "platform": paltform,
                "relation": grabRequestList[i].relation,
            }
        }
        ecloud.dynamicAdd(add)
    }
    logd("getMessage 数据保存成功");
}
/**
 * 记录埋点数据
 */
function operaLog(num) {
    let paltform = '';
    let operateType = '';
    let uniqueNo = '';
    if (num === 1) {
        operateType = '应用启动'
    } else if (num === 2) {
        operateType = '点击消息'
    } else if (num === 3) {
        operateType = '点击互动消息'
    } else if (num === 4) {
        operateType = '脚本运行结束'
    }
    if ('com.ss.android.ugc.aweme'.equals(packageName)) {
        // 斗音
        paltform = '抖音'
        uniqueNo = ecloud.getDeviceNo().substring(3)
    } else if ('小红书'.equals(packageName)) {
        // 小红书
        paltform = '小红书'
        uniqueNo = ecloud.getDeviceNo().substring(4)
    } else if ('快手'.equals(packageName)) {
        // 快手
        paltform = '快手'
        uniqueNo = ecloud.getDeviceNo().substring(3)
    }
    let add = {
        "tableNameEn": "trace",
        "columns": {
            "device_no": ecloud.getDeviceNo(),
            "platform": paltform,
            "unique_no": uniqueNo,
            "post_name": '',
            "nickname": '',
            "keyword": '',
            "operate_type": operateType,
            "task_id": ecloud.getTaskInfo().taskId,
            "task_name": ecloud.getTaskInfo().taskName,
        }
    }
    ecloud.dynamicAdd(add)
    logd("getMessage 数据保存成功");
}
/**
 * description 异步执行线程 处理弹窗
 * @return {boolean} : 返回是否成功
 */
function alert() {
    thread.execAsync(function () {
        logd('启动线程,查找弹窗');
        let btnText = new Array(
            "下次再说",
            "以后再说",
            "关闭",
            "允许",
            "暂不",
            "暂时不要",
            "我知道了",
            "知道了",
            "取消",
        );
        while (true) {
            for (let i = 0; i < btnText.length; i++) {
                logd('检查弹窗...');
                let node = text(btnText[i]).getOneNodeInfo(1000);
                if (node) {
                    node.click();
                    logd('弹窗已处理');
                }
            }
            sleep(3000);
        }
    });
    return true;
}
// 获取当前日期
function getCurrentDate() {
    return new Date();
}
// 格式化日期为年-月-日
function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const format = 'yyyy-MM-dd'
    return format
        .replace('yyyy', year)
        .replace('MM', month)
        .replace('dd', day);
}
// 格式化日期字符串的函数
function formatDateString(dateString) {
    // 使用正则表达式分割日期字符串
    const parts = dateString.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
    if (parts) {
        // 提取年份、月份和日期
        const year = parts[1];
        const month = String(parseInt(parts[2], 10)).padStart(2, '0');
        const day = String(parseInt(parts[3], 10)).padStart(2, '0');
        // 拼接成新的日期字符串
        return year + "-" + month + "-" + day;
    } else {
        // 如果日期字符串格式不正确,返回一个错误消息或默认值
        return 'Invalid date string format';
    }
}
// 获取指定天数后的日期
function getDateAfterDays(date, days) {
    const newDate = new Date(date.getTime() + (days * 24 * 60 * 60 * 1000));
    return newDate;
}
// 获取指定天数前的日期
function getDateBeforeDays(date, days) {
    return getDateAfterDays(date, -days);
}
ec-rpa/src/js/subjs/dy_privateMessage.js
New file
@@ -0,0 +1,628 @@
//命中评论私信
// 请勿让日志窗口遮挡屏幕
let packageName = 'com.ss.android.ugc.aweme';
var searchContent, messageWords, hitKeywords, everyNumber, total; //搜索词, 私信话术, 命中关键词, 单视频回复量, 总回复量
getECloudData(); //获取任务数据
/**
 * description 获取云控参数
 * @return {boolean} : 返回是否成功
 */
function getECloudData() {
    let result = false;
    let hasData = true, value;
    let data = new Array();
    let group = [{
        "groupName" : "短视频代运营搜索词",
        "dataName" : "斗因-视频搜索词"
    },{
        "groupName" : "短视频代运营话术",
        "dataName" : "斗因-私信话术"
    },{
        "groupName" : "短视频代运营命中关键词",
        "dataName" : "斗因-评论命中关键词"
    },{
        "groupName" : "短视频代运营执行数量",
        "dataName" : "斗因-评论执行数量"
    }];
    //通过数据组名或数据名称取得数据
    for (let i = 0; i < group.length; i++) {
        data = ecloud.getData(group[i]);
        if (data[0]) {
            if (i == 0) {
                searchContent = value = data[0].content.split("|");
            } else if (i == 1) {
                messageWords = value = data[0].content.split("\n");
            } else if (i == 2) {
                hitKeywords = value = data[0].content.split("|");
            } else if (i == 3)  {
                let array = value = data[0].content.split("|");
                everyNumber = array[0];
                total = array[1];
            }
            if (!value || value.length == 0) {
                hasData = false;
                loge('未设置' + group[i].dataName);
                break;
            }
        } else {
            hasData = false;
            loge('未获取' + group[i].dataName);
            break;
        }
    }
    if (hasData) {
        logi('已获取任务数据,开始执行...');
        randomSleep();
        result = true;
        launch(packageName, 6000, 3); //打开抖音
    }
    return result;
}
/**
 * description 通过包名启动应用
 * @param packageName {string} : 应用包名
 * @param delay {number} : 启动后等待时长(毫秒)
 * @param startNum {number} : 重试次数
 * @return {boolean} : 返回是否成功
 */
function launch(packageName, delay, startNum) {
    let result = false;
    //判断应用的包名是否存在
    if (utils.isAppExist(packageName)) {
        //判断应用是否在前台
        if (getRunningPkg() == null) {
            loge('请开启辅助功能权限');
        } else if (getRunningPkg() === packageName) {
            logi('应用已经在前台');
            result = true;
            search(); //搜索视频
        } else {
            logi('启动应用...');
            let alert_selectors = text("允许");
            let num = 0;
            //判断应用是否启动成功
            while (num < startNum) {
                if (getRunningPkg() === packageName) {
                    insertTrace('', '', '', "应用启动");
                    logi('启动成功');
                    result = true;
                    search(); //搜索视频
                    break;
                } else if (has(alert_selectors)) {
                    //初次打开应用 可能会弹出是否允许打开的弹窗
                    let node = alert_selectors.getOneNodeInfo(3000);
                    if (node) {
                        node.click();
                    }
                } else {
                    utils.openApp(packageName);
                    sleep(delay);
                    num++;
                }
            }
        }
        alert(); //应用启动后处理弹窗
    } else {
        toast('应用未安装');
    }
    return result;
}
/**
 * description 根据关键词搜索视频
 * @return {boolean} : 返回是否成功
 */
function search() {
    //定位到首页
    execSync(function () {
        isHome();
    }, 1000);
    let result = false;
    //寻找搜索按钮并点击
    logi('开始搜索...');
    let search = descMatch(".*搜索.*").getOneNodeInfo(5000);
    if (search) {
        if (search.click()) {
            randomSleep();
            //寻找输入框 输入搜索词
            logi('输入搜索内容...');
            let input_selectors = clz("android.widget.EditText").getOneNodeInfo(5000);;
            let keyword = searchContent[random(0, searchContent.length - 1)];
            if (input_selectors) {
                if (input_selectors.inputText(keyword)) {
                    randomSleep();
                    //点击搜索
                    if (search.click()) {
                        insertTrace('', '', keyword, "搜索");
                        randomSleep();
                        logi('搜索完成');
                        //进入视频页
                        let tab_node = clz("android.widget.Button").getNodeInfo(5000);
                        if (tab_node) {
                            for (let i = 0; i < tab_node.length; i++) {
                                if (tab_node[i].text === "视频") {
                                    if (tab_node[i].click()) {
                                        randomSleep();
                                        //浏览视频
                                        let video_node = depth(20).getOneNodeInfo(5000); //根据深度匹配
                                        logi('浏览视频...');
                                        if (video_node) {
                                            if (video_node.click()) {
                                                randomSleep();
                                                let nameSelectors = id("com.ss.android.ugc.aweme:id/title").getOneNodeInfo(2000);
                                                let postSelectors = id("com.ss.android.ugc.aweme:id/desc").getOneNodeInfo(2000);
                                                insertTrace(postSelectors.text, nameSelectors.text, '', "搜索");
                                                result = true;
                                                message(); //私信
                                                break;
                                            } else {
                                                loge('浏览失败');
                                                exit();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        loge('搜索失败');
                        exit();
                    }
                } else {
                    loge('输入失败');
                    exit();
                }
            }
        } else {
            loge('未找到搜索按钮');
            exit();
        }
    }
    return result;
}
/**
 * description 私信评论用户
 * @param p {number} : 私信概率
 * @param everyNumber {number} : 单个视频回复数量
 * @param total {number} : 总回复数量
 */
function message() {
    let completedNumber = 0; //已私信总数
    var flag = false;
    while (true) {
        //寻找评论图标并点击
        toast('打开评论...');
        let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000);
        if (comment_icon) {
            if (comment_icon.click()) {
                var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
                if (result) {
                    randomSleep();
                    toast('放大评论区');
                    let btn = desc("放大评论区").visible(true).getOneNodeInfo(3000);
                    if (btn) {
                        if (btn.click()) {
                            flag = true;
                            randomSleep();
                            var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
                            let num = 0 //回复数量
                            while (flag) {
                                for (var i = 0; i < result.length; i++) {
                                    var hasKey = false;
                                    if (num < everyNumber) {
                                        toast('浏览第' + (i + 1) + '条评论...');
                                        var comments = result[i].text; //评论内容
                                        for (var n = 0; n < hitKeywords.length; n++) {
                                            // execSync(function () {
                                            if (comments.includes(hitKeywords[n])) {
                                                var sub = result[i].nextSiblings()[0]; //评论节点
                                                var t = sub.child(0);
                                                var ip = sub.child(1);
                                                var avatar = sub.previousSiblings()[0]; //头像节点
                                                hasKey = true;
                                                toast('第' + (i + 1) + '条评论命中关键词,进行私信...');
                                                randomSleep();
                                                insertCommentsGot(comments, hitKeywords[n], t, ip);
                                                if (avatar.click()) {
                                                    randomSleep();
                                                    thread.execSync(function () {
                                                        send();
                                                        num++;
                                                        completedNumber++;
                                                    }, 1000);
                                                }
                                            }
                                            // }, 1000);
                                        }
                                        if (i == result.length - 1 && !hasKey) {
                                            num++;
                                            completedNumber++;
                                            toast('当前视频未找到命中评论');
                                            randomSleep();
                                        }
                                    } else if (Number(completedNumber) === Number(total)) {
                                        toast("任务完成");
                                        shell.stopApp(packageName); //关闭抖音
                                        home();
                                        exit()
                                    } else {
                                        let btn = desc("缩小评论区").visible(true).getOneNodeInfo(3000);
                                        if (btn.click()) {
                                            randomSleep();
                                        }
                                        flag = false;
                                        go_back(1);
                                        toast('当前视频私信完成,下一个视频...');
                                        randomSleep();
                                        swiper(); //下一个视频
                                        break
                                        break;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    toast('未找到评论');
                    randomSleep();
                    go_back(2);
                    swiper(); //下一个视频
                    // break;
                }
            }
        }
    }
}
/**
 * description 发私信消息
 * @return {boolean} : 返回是否成功
 */
function send() {
    let result = false;
    let follow = text("关注");
    let message_btn = text("私信").getOneNodeInfo(1000);
    let title = text("账号已经注销").getOneNodeInfo(1000);
    //判断是否关注用户
    let follow_btn = getNodeInfo(follow, 1000);
    if (follow_btn[1]) {
        follow_btn[1].click();
        logd('关注用户');
        sleep(4000);
        //判断私密账户
        let private = textMatch(".*私密账号.*").getOneNodeInfo(1000);
        let ok = text("知道了").getOneNodeInfo(1000);
        if (private) {
            ok.click();
            sleep(3000);
            go_back(1);
        }
    }
    //判断是否注销
    if (title) {
        go_back(1);
        result = false;
    } else if (message_btn.click()) {
        logd('进入私信');
        randomSleep();
        let input_selectors = clz("android.widget.EditText");
        let text = messageWords[random(0, messageWords.length - 1)];
        //寻找输入框 输入话术
        if (inputText(input_selectors, text)) {
            sleep(4000);
            let send_btn = desc("发送").getOneNodeInfo(1000);
            if (send_btn.click()) {
                randomSleep();
                logd("私信成功");
                go_back(2);
                result = true;
            }
        }
    }
    return result;
}
/**
 * description 异步执行线程 处理弹窗
 * @return {boolean} : 返回是否成功
 */
function alert() {
    thread.execAsync(function () {
        logd('启动线程,查找弹窗');
        let btnText = new Array(
            "下次再说",
            "以后再说",
            "关闭",
            "允许",
            "暂不",
            "暂时不要",
            "我知道了",
            "知道了",
            "取消",
        );
        while (true) {
            for (let i = 0; i < btnText.length; i++) {
                logd('检查弹窗...');
                let node = text(btnText[i]).getOneNodeInfo(1000);
                if (node) {
                    node.click();
                    toast('弹窗已处理');
                }
            }
            sleep(4000);
        }
    });
    return true;
}
/**
 * description 定位到首页
 * @return {boolean} : 返回是否成功
 */
function isHome() {
    let result = false;
    while (true) {
        var home_selectors = text("首页").getOneNodeInfo(3000); //首页按钮
        var message_selectors = text("消息").getOneNodeInfo(3000); //消息按钮
        //判断是否在首页
        if (home_selectors && message_selectors) {
            var follow_selectors = text("关注"); //关注按钮
            var recommend_selectors = text("推荐"); //推荐按钮
            if (has(follow_selectors) && has(recommend_selectors)) {
                toast('已定位首页');
                randomSleep();
                result = true;
                break;
            } else {
                home_selectors.click();
                sleep(3000);
            }
        } else {
            toast('返回首页...');
            //返回上一页
            go_back(1);
        }
    }
    return result;
}
/**
 * description 自定义返回函数
 * @param page {number} : 返回页数
 */
function go_back(page) {
    let count = 0;
    while (count < page) {
        back();
        count++;
        randomSleep();
    }
}
/**
 * description 随机暂停时间
 */
function randomSleep() {
    let min = Math.ceil(3);
    let max = Math.floor(6);
    let time = (Math.floor(Math.random() * (max - min + 1)) + min) * 1000;
    sleep(time);
}
/**
 * description 插入埋点
 * @param unique_id {string} : 用户唯一编号
 * @param post_name {string} : 作品名称
 * @param nickname {string} : 用户昵称
 * @param keyword {string} : 搜索关键词
 * @param operate_type {string} : 操作类型
 */
function insertTrace(post_name, nickname,keyword, operate_type) {
    let time = getDate();
    var deviceNo = ecloud.getDeviceNo(); //设备编号
    var unique_id = deviceNo.slice(3);
    let add = {
        "tableNameEn": "trace",
        "columns": {
            "device_no" : deviceNo, //设备编号
            "operate_time" : time, //操作时间
            "platform" : "抖音", //所属平台
            "unique_no" : unique_id, //用户唯一编号
            "post_name" : post_name, //作品名称
            "nickname" : nickname, //用户昵称
            "keyword" : keyword, //搜索关键词
            "operate_type" : operate_type, //操作类型
            "task_id": ecloud.getTaskInfo().taskId,
            "task_name": ecloud.getTaskInfo().taskName
        }
    }
    ecloud.dynamicAdd(add);
}
/**
 * description 插入命中作品评论
 * @param content {string} : 线索
 * @param got_word {string} : 命中词
 * @param comment_datetime {string} : 评论时间
 * @param province {string} : 省
 */
function insertCommentsGot(content, got_word, comment_datetime,province) {
    let time = getDate();
    let add = {
        "tableNameEn": "dy_comments_got",
        "columns": {
            "task_id" : '', //任务id
            "task_name" : '', //任务名
            "title" : "", //视频标题
            "dy_nickname" : '', //抖音昵称
            "content" : content, //线索
            "tel" : '',//手机号
            "got_word" : got_word ,//命中词
            "comment_datetime" : comment_datetime, //评论时间
            "grab_datetime" : time, //挖掘时间
            "province" : province, //省
            "task_id": ecloud.getTaskInfo().taskId,
            "task_name": ecloud.getTaskInfo().taskName
        }
    }
    ecloud.dynamicAdd(add);
}
/**
 * description 获取当前时间
 * @return {string} : 返回时间
 */
function getDate() {
    let date = new Date();
    let sign2 = ":";
    let year = date.getFullYear() // 年
    let month = date.getMonth() + 1; // 月
    let day = date.getDate(); // 日
    let hour = date.getHours(); // 时
    let minutes = date.getMinutes(); // 分
    let seconds = date.getSeconds() //秒
    let weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
    let week = weekArr[date.getDay()];
    // 给一位数的数据前面加 “0”
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (day >= 0 && day <= 9) {
        day = "0" + day;
    }
    if (hour >= 0 && hour <= 9) {
        hour = "0" + hour;
    }
    if (minutes >= 0 && minutes <= 9) {
        minutes = "0" + minutes;
    }
    if (seconds >= 0 && seconds <= 9) {
        seconds = "0" + seconds;
    }
    return year + "-" + month + "-" + day + " " + hour + sign2 + minutes + sign2 + seconds;
}
/**
 * description 滑动视频
 * @return {boolean} : 返回是否成功
 */
function swiper(){
    let result = false;
    //设定坐标 适配全分辨率
    let x = device.getScreenWidth() * 7 / 10;
    let y = device.getScreenHeight() * 8 / 10;
    let x1 = device.getScreenWidth() * 7 / 10;
    let y1 = device.getScreenHeight() * 1.5 / 10
    if (rnd_Swipe(x,y,x1,y1,100,200,200)) {
        sleep(3000);
        logd("滑动完成");
        result = true;
    }
    return result;
}
/**
 * description 仿真随机带曲线滑动
 */
function rnd_Swipe(qx, qy, zx, zy,time, times,timess) {
    //qx, qy, zx, zy, time 代表起点x,起点y,终点x,终点y,times,timess =随机时间(times,timess)
    let time1,xxy,point,dx0,dx1,dx2,dx3,xxyy
    time1=random(times,timess)
    xxy = [];
    point = [];
    dx0 = {
        "x": qx,
        "y": qy
    }
    dx1 = {
        "x": random(qx - 100, qx + 100),
        "y": random(qy , qy + 50)
    }
    dx2 = {
        "x": random(zx - 100, zx + 100),
        "y": random(zy , zy + 50),
    }
    dx3 = {
        "x": zx,
        "y": zy
    }
    for (let i = 0; i < 4; i++) {
        eval("point.push(dx" + i + ")");
    }
    for (let i = 0; i < 1; i += 0.08) {
        xxyy = [parseInt(bezier_curves(point, i).x), parseInt(bezier_curves(point, i).y)]
        xxy.push(xxyy);
    }
    gesture(xxy,time, time1);
    return true;
}
/**
 * description 贝赛尔曲线
 */
function bezier_curves(cp, t) {
    let cx,bx,ax,cy,by,ay,tSquared,tCubed,result
    cx = 3.0 * (cp[1].x - cp[0].x);
    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    ax = cp[3].x - cp[0].x - cx - bx;
    cy = 3.0 * (cp[1].y - cp[0].y);
    by = 3.0 * (cp[2].y - cp[1].y) - cy;
    ay = cp[3].y - cp[0].y - cy - by;
    tSquared = t * t;
    tCubed = tSquared * t;
    result = {
        "x": 0,
        "y": 0
    }
    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
    return result;
}
/**
 * description 手势
 */
function gesture(swipeList,time,time1) {
    let touch1 ,touch2,x,i
    touch1 = [{"action": 0, "x": swipeList[0][0], "y": swipeList[0][1], "pointer": 1, "delay": time}]
    for (i in swipeList) {
        ++i;
        if (i===swipeList.length-2) {break;}
        touch1.push({"action": 1, "x": swipeList[i][0], "y": swipeList[i][1], "pointer": 1, "delay": time});
    }
    touch1.push({"action": 2, "x": swipeList[swipeList.length-1][0], "y": swipeList[swipeList.length-1][1], "pointer": 1, "delay": time})
    x = multiTouch(touch1, null, null, time1);
    logd('仿真滑动:'+x);
    sleep(3000);
}
ec-rpa/src/js/subjs/dy_replayComment.js
New file
@@ -0,0 +1,586 @@
//命中评论回复
// 请勿让日志窗口遮挡屏幕
let packageName = 'com.ss.android.ugc.aweme';
var searchContent, replyWords, hitKeywords, everyNumber, total; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量
getECloudData(); //获取任务数据
/**
 * description 获取云控参数
 * @return {boolean} : 返回是否成功
 */
function getECloudData() {
    let result = false;
    let hasData = true, value;
    let data = new Array();
    let group = [{
        "groupName" : "短视频代运营搜索词",
        "dataName" : "斗因-视频搜索词"
    },{
        "groupName" : "短视频代运营话术",
        "dataName" : "斗因-回复评论话术"
    },{
        "groupName" : "短视频代运营命中关键词",
        "dataName" : "斗因-评论命中关键词"
    },{
        "groupName" : "短视频代运营执行数量",
        "dataName" : "斗因-评论执行数量"
    }];
    //通过数据组名或数据名称取得数据
    for (let i = 0; i < group.length; i++) {
        data = ecloud.getData(group[i]);
        if (data[0]) {
            if (i == 0) {
                searchContent = value = data[0].content.split("|");
            } else if (i == 1) {
                replyWords = value = data[0].content.split("\n");
            } else if (i == 2) {
                hitKeywords = value = data[0].content.split("|");
            } else if (i == 3)  {
                let array = value = data[0].content.split("|");
                everyNumber = array[0];
                total = array[1];
            }
            if (!value || value.length == 0) {
                hasData = false;
                loge('未设置' + group[i].dataName);
                break;
            }
        } else {
            hasData = false;
            loge('未获取' + group[i].dataName);
            break;
        }
    }
    if (hasData) {
        logi('已获取任务数据,开始执行...');
        randomSleep();
        result = true;
        launch(packageName, 6000, 3); //打开抖音
    }
    return result;
}
/**
 * description 通过包名启动应用
 * @param packageName {string} : 应用包名
 * @param delay {number} : 启动后等待时长(毫秒)
 * @param startNum {number} : 重试次数
 * @return {boolean} : 返回是否成功
 */
function launch(packageName, delay, startNum) {
    let result = false;
    //判断应用的包名是否存在
    if (utils.isAppExist(packageName)) {
        //判断应用是否在前台
        if (getRunningPkg() == null) {
            loge('请开启辅助功能权限');
        } else if (getRunningPkg() === packageName) {
            logi('应用已经在前台');
            result = true;
            search(); //搜索视频
        } else {
            logi('启动应用...');
            let alert_selectors = text("允许");
            let num = 0;
            //判断应用是否启动成功
            while (num < startNum) {
                if (getRunningPkg() === packageName) {
                    insertTrace('', '', '', "应用启动");
                    logi('启动成功');
                    result = true;
                    search(); //搜索视频
                    break;
                } else if (has(alert_selectors)) {
                    //初次打开应用 可能会弹出是否允许打开的弹窗
                    let node = alert_selectors.getOneNodeInfo(3000);
                    if (node) {
                        node.click();
                    }
                } else {
                    utils.openApp(packageName);
                    sleep(delay);
                    num++;
                }
            }
        }
        alert(); //应用启动后处理弹窗
    } else {
        toast('应用未安装');
    }
    return result;
}
/**
 * description 根据关键词搜索视频
 * @return {boolean} : 返回是否成功
 */
function search() {
    //定位到首页
    execSync(function () {
        isHome();
    }, 1000);
    let result = false;
    //寻找搜索按钮并点击
    logi('开始搜索...');
    let search = descMatch(".*搜索.*").getOneNodeInfo(5000);
    if (search) {
        if (search.click()) {
            randomSleep();
            //寻找输入框 输入搜索词
            logi('输入搜索内容...');
            let input_selectors = clz("android.widget.EditText").getOneNodeInfo(5000);;
            let keyword = searchContent[random(0, searchContent.length - 1)];
            if (input_selectors) {
                if (input_selectors.inputText(keyword)) {
                    randomSleep();
                    //点击搜索
                    if (search.click()) {
                        insertTrace('', '', keyword, "搜索");
                        randomSleep();
                        logi('搜索完成');
                        //进入视频页
                        let tab_node = clz("android.widget.Button").getNodeInfo(5000);
                        if (tab_node) {
                            for (let i = 0; i < tab_node.length; i++) {
                                if (tab_node[i].text === "视频") {
                                    if (tab_node[i].click()) {
                                        randomSleep();
                                        //浏览视频
                                        let video_node = depth(20).getOneNodeInfo(5000); //根据深度匹配
                                        logi('浏览视频...');
                                        if (video_node) {
                                            if (video_node.click()) {
                                                randomSleep();
                                                let nameSelectors = id("com.ss.android.ugc.aweme:id/title").getOneNodeInfo(2000);
                                                let postSelectors = id("com.ss.android.ugc.aweme:id/desc").getOneNodeInfo(2000);
                                                insertTrace(postSelectors.text, nameSelectors.text, '', "搜索");
                                                result = true;
                                                reply(); //回复评论
                                                break;
                                            } else {
                                                loge('浏览失败');
                                                exit();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        loge('搜索失败');
                        exit();
                    }
                } else {
                    loge('输入失败');
                    exit();
                }
            }
        } else {
            loge('未找到搜索按钮');
            exit();
        }
    }
    return result;
}
/**
 * description 回复一级评论
 */
function reply() {
    let completedNumber = 0; //已回复总数
    var flag = false;
    while (true) {
        //寻找评论图标并点击
        toast('打开评论...');
        let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000);
        if (comment_icon) {
            if (comment_icon.click()) {
                var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
                if (result) {
                    randomSleep();
                    toast('放大评论区');
                    let btn = desc("放大评论区").visible(true).getOneNodeInfo(3000);
                    if (btn) {
                        if (btn.click()) {
                            flag = true;
                            randomSleep();
                            var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
                            let num = 0 //回复数量
                            while (flag) {
                                for (var i = 0; i < result.length; i++) {
                                    var hasKey = false;
                                    if (num < everyNumber) {
                                        toast('浏览第' + (i + 1) + '条评论...');
                                        var comments = result[i].text; //评论内容
                                        for (var n = 0; n < hitKeywords.length; n++) {
                                            // execSync(function () {
                                            if (comments.includes(hitKeywords[n])) {
                                                var sub = result[i].nextSiblings()[0]; //评论节点
                                                var t = sub.child(0);
                                                var ip = sub.child(1);
                                                hasKey = true;
                                                toast('第' + (i + 1) + '条评论命中关键词,进行回复...');
                                                randomSleep();
                                                insertCommentsGot(comments, hitKeywords[n], t, ip);
                                                if (result[i].click()) {
                                                    toast('输入回复内容...');
                                                    let words = replyWords[random(0, replyWords.length - 1)];
                                                    let input_selectors = clz("android.widget.EditText").getOneNodeInfo(50000);
                                                    if (input_selectors) {
                                                        if (input_selectors.inputText(words)) {
                                                            randomSleep();
                                                            let send = text("发送").getOneNodeInfo(3000);
                                                            if (send) {
                                                                send.click();
                                                                num++;
                                                                completedNumber++;
                                                                toast('完成回复');
                                                                randomSleep();
                                                                // break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            // }, 1000);
                                        }
                                        if (i == result.length - 1 && !hasKey) {
                                            num++;
                                            completedNumber++;
                                            toast('当前视频未找到命中评论');
                                            randomSleep();
                                        }
                                    } else if (Number(completedNumber) === Number(total)) {
                                        toast("任务完成");
                                        shell.stopApp(packageName); //关闭抖音
                                        home();
                                        exit()
                                    } else {
                                        let btn = desc("缩小评论区").visible(true).getOneNodeInfo(3000);
                                        if (btn.click()) {
                                            randomSleep();
                                        }
                                        flag = false;
                                        go_back(1);
                                        toast('当前视频回复完成,下一个视频...');
                                        randomSleep();
                                        swiper(); //下一个视频
                                        break
                                        break;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    toast('未找到评论');
                    randomSleep();
                    go_back(2);
                    swiper(); //下一个视频
                    // break;
                }
            }
        }
    }
}
/**
 * description 异步执行线程 处理弹窗
 * @return {boolean} : 返回是否成功
 */
function alert() {
    thread.execAsync(function () {
        logd('启动线程,查找弹窗');
        let btnText = new Array(
            "下次再说",
            "以后再说",
            "关闭",
            "允许",
            "暂不",
            "暂时不要",
            "我知道了",
            "知道了",
            "取消",
        );
        while (true) {
            for (let i = 0; i < btnText.length; i++) {
                logd('检查弹窗...');
                let node = text(btnText[i]).getOneNodeInfo(1000);
                if (node) {
                    node.click();
                    toast('弹窗已处理');
                }
            }
            sleep(4000);
        }
    });
    return true;
}
/**
 * description 定位到首页
 * @return {boolean} : 返回是否成功
 */
function isHome() {
    let result = false;
    while (true) {
        var home_selectors = text("首页").getOneNodeInfo(3000); //首页按钮
        var message_selectors = text("消息").getOneNodeInfo(3000); //消息按钮
        //判断是否在首页
        if (home_selectors && message_selectors) {
            var follow_selectors = text("关注"); //关注按钮
            var recommend_selectors = text("推荐"); //推荐按钮
            if (has(follow_selectors) && has(recommend_selectors)) {
                toast('已定位首页');
                randomSleep();
                result = true;
                break;
            } else {
                home_selectors.click();
                sleep(3000);
            }
        } else {
            toast('返回首页...');
            //返回上一页
            go_back(1);
        }
    }
    return result;
}
/**
 * description 自定义返回函数
 * @param page {number} : 返回页数
 */
function go_back(page) {
    let count = 0;
    while (count < page) {
        back();
        count++;
        randomSleep();
    }
}
/**
 * description 随机暂停时间
 */
function randomSleep() {
    let min = Math.ceil(3);
    let max = Math.floor(6);
    let time = (Math.floor(Math.random() * (max - min + 1)) + min) * 1000;
    sleep(time);
}
/**
 * description 插入埋点
 * @param unique_id {string} : 用户唯一编号
 * @param post_name {string} : 作品名称
 * @param nickname {string} : 用户昵称
 * @param keyword {string} : 搜索关键词
 * @param operate_type {string} : 操作类型
 */
function insertTrace(post_name, nickname,keyword, operate_type) {
    let time = getDate();
    var deviceNo = ecloud.getDeviceNo(); //设备编号
    var unique_id = deviceNo.slice(3);
    let add = {
        "tableNameEn": "trace",
        "columns": {
            "device_no" : deviceNo, //设备编号
            "operate_time" : time, //操作时间
            "platform" : "抖音", //所属平台
            "unique_no" : unique_id, //用户唯一编号
            "post_name" : post_name, //作品名称
            "nickname" : nickname, //用户昵称
            "keyword" : keyword, //搜索关键词
            "operate_type" : operate_type, //操作类型
            "task_id": ecloud.getTaskInfo().taskId,
            "task_name": ecloud.getTaskInfo().taskName
        }
    }
    ecloud.dynamicAdd(add);
}
/**
 * description 插入命中作品评论
 * @param content {string} : 线索
 * @param got_word {string} : 命中词
 * @param comment_datetime {string} : 评论时间
 * @param province {string} : 省
 */
function insertCommentsGot(content, got_word, comment_datetime,province) {
    let time = getDate();
    let add = {
        "tableNameEn": "dy_comments_got",
        "columns": {
            "task_id" : '', //任务id
            "task_name" : '', //任务名
            "title" : "", //视频标题
            "dy_nickname" : '', //抖音昵称
            "content" : content, //线索
            "tel" : '',//手机号
            "got_word" : got_word ,//命中词
            "comment_datetime" : comment_datetime, //评论时间
            "grab_datetime" : time, //挖掘时间
            "province" : province, //省
            "task_id": ecloud.getTaskInfo().taskId,
            "task_name": ecloud.getTaskInfo().taskName
        }
    }
    ecloud.dynamicAdd(add);
}
/**
 * description 获取当前时间
 * @return {string} : 返回时间
 */
function getDate() {
    let date = new Date();
    let sign2 = ":";
    let year = date.getFullYear() // 年
    let month = date.getMonth() + 1; // 月
    let day = date.getDate(); // 日
    let hour = date.getHours(); // 时
    let minutes = date.getMinutes(); // 分
    let seconds = date.getSeconds() //秒
    let weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
    let week = weekArr[date.getDay()];
    // 给一位数的数据前面加 “0”
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (day >= 0 && day <= 9) {
        day = "0" + day;
    }
    if (hour >= 0 && hour <= 9) {
        hour = "0" + hour;
    }
    if (minutes >= 0 && minutes <= 9) {
        minutes = "0" + minutes;
    }
    if (seconds >= 0 && seconds <= 9) {
        seconds = "0" + seconds;
    }
    return year + "-" + month + "-" + day + " " + hour + sign2 + minutes + sign2 + seconds;
}
/**
 * description 滑动视频
 * @return {boolean} : 返回是否成功
 */
function swiper(){
    let result = false;
    //设定坐标 适配全分辨率
    let x = device.getScreenWidth() * 7 / 10;
    let y = device.getScreenHeight() * 8 / 10;
    let x1 = device.getScreenWidth() * 7 / 10;
    let y1 = device.getScreenHeight() * 1.5 / 10
    if (rnd_Swipe(x,y,x1,y1,100,200,200)) {
        sleep(3000);
        logd("滑动完成");
        result = true;
    }
    return result;
}
/**
 * description 仿真随机带曲线滑动
 */
function rnd_Swipe(qx, qy, zx, zy,time, times,timess) {
    //qx, qy, zx, zy, time 代表起点x,起点y,终点x,终点y,times,timess =随机时间(times,timess)
    let time1,xxy,point,dx0,dx1,dx2,dx3,xxyy
    time1=random(times,timess)
    xxy = [];
    point = [];
    dx0 = {
        "x": qx,
        "y": qy
    }
    dx1 = {
        "x": random(qx - 100, qx + 100),
        "y": random(qy , qy + 50)
    }
    dx2 = {
        "x": random(zx - 100, zx + 100),
        "y": random(zy , zy + 50),
    }
    dx3 = {
        "x": zx,
        "y": zy
    }
    for (let i = 0; i < 4; i++) {
        eval("point.push(dx" + i + ")");
    }
    for (let i = 0; i < 1; i += 0.08) {
        xxyy = [parseInt(bezier_curves(point, i).x), parseInt(bezier_curves(point, i).y)]
        xxy.push(xxyy);
    }
    gesture(xxy,time, time1);
    return true;
}
/**
 * description 贝赛尔曲线
 */
function bezier_curves(cp, t) {
    let cx,bx,ax,cy,by,ay,tSquared,tCubed,result
    cx = 3.0 * (cp[1].x - cp[0].x);
    bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    ax = cp[3].x - cp[0].x - cx - bx;
    cy = 3.0 * (cp[1].y - cp[0].y);
    by = 3.0 * (cp[2].y - cp[1].y) - cy;
    ay = cp[3].y - cp[0].y - cy - by;
    tSquared = t * t;
    tCubed = tSquared * t;
    result = {
        "x": 0,
        "y": 0
    }
    result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
    result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
    return result;
}
/**
 * description 手势
 */
function gesture(swipeList,time,time1) {
    let touch1 ,touch2,x,i
    touch1 = [{"action": 0, "x": swipeList[0][0], "y": swipeList[0][1], "pointer": 1, "delay": time}]
    for (i in swipeList) {
        ++i;
        if (i===swipeList.length-2) {break;}
        touch1.push({"action": 1, "x": swipeList[i][0], "y": swipeList[i][1], "pointer": 1, "delay": time});
    }
    touch1.push({"action": 2, "x": swipeList[swipeList.length-1][0], "y": swipeList[swipeList.length-1][1], "pointer": 1, "delay": time})
    x = multiTouch(touch1, null, null, time1);
    logd('仿真滑动:'+x);
    sleep(3000);
}