Greasy Fork is available in English.

gifshowjs

自用库

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/520147/1504838/gifshowjs.js

auto.waitFor();
global.AppName = "快手极速版";
global.packageName = "com.kuaishou.nebula";
global.running = false; //是否正在刷视频中
global.working = false; //是否正在刷视频中
global.startSec = Date.now();//刷视频计时
global.ver = 'v1.3';//版本号
if (!auto.service || device.width == 0) {
    console.warn("2.请重新开启无障碍服务");
    auto.service.disableSelf();
    app.startActivity({ action: "android.settings.ACCESSIBILITY_SETTINGS" });
    android.os.Process.killProcess(android.os.Process.myPid());
}
if (device.fingerprint + '/' + ver != storages.create("gifshow").get('device_info')) { setTimeout(function () { update(); }, 60 * 1000); }
engines.all().map((ScriptEngine) => { if (engines.myEngine().toString() !== ScriptEngine.toString()) { ScriptEngine.forceStop(); } });

//判断签到层
function singlecheck() {
    toastLog('判断签到提示');
    var today = new Date();
    if(storages.create("gifshow").get('singlecheck')==today.getDate()){
        toastLog('今天已完成签到');
        return;
    }
    //查找立即签到
    var single = className('Button').textMatches(/立即签到/).clickable(true).visibleToUser(true).findOne(1000);
    if (single) {
        toastLog('1.点击立即签到');
        single.click();
        sleep(3000);

        toastLog('2.再次点击签到');
        click(single.bounds().centerX(), single.bounds().centerY());
        sleep(3000);
        back();

        toastLog('3.签到结束关闭');
    } else {
        toastLog('没有签到提示');
    }
    storages.create("gifshow").put('singlecheck', today.getDate());//记录是否检测过签到
}
//装载任务列表
function tasklist() {
    toastLog('查找金币暴涨tasklist');
    gohome();
    let moneybtn = className('androidx.appcompat.app.ActionBar$c').desc('去赚钱').clickable(true).boundsInside(device.width/2, device.height-300, device.width, device.height).visibleToUser(true).findOne(1000);
    if(moneybtn){
        console.error('点击去赚钱tasklist');
        click(moneybtn.bounds().centerX(),moneybtn.bounds().centerY());
        sleep(8000);
        singlecheck();//判断签到层
    }
    var TempArray = new Array();
    if(className('Button').text('金币暴涨').findOne(1000)){
        console.error('装载任务');
        idMatches(/.*dailyTask/).className('android.view.View').visibleToUser(true).find().forEach(function (tv) {
            let list = tv.children();
            for (i = 0; i < list.length; i++) {
                if (list[i].id()) {
                    let title = list[i].find(className('TextView'));
                    for (j = 0; j < title.length; j++) {
                        if (title[j]) {
                            //log(title[j].text());
                            if (title[j].text().match(/看广告得.*|看短剧得.*|看\d+次直播领金币|刷广告视频赚金币|看指定视频赚金币|.*签到.*/)) {
                                let btn = list[i].find(className('android.view.View').clickable(true));
                                //log(btn[1]);
                                let temp=[title[j].text(),btn[1]];
                                TempArray.push(temp);
                            }
                        }
                    }
                }
            }
        });
        console.error('装载完成:',TempArray.length);
    }else{
        toastLog('没有找到金币暴涨tasklist');
    }
    return TempArray;
}
//点击右下角宝箱函数
function moneybox() {
    toastLog('查找右下角宝箱moneybox');
    gohome();
    let moneybtn = className('androidx.appcompat.app.ActionBar$c').desc('去赚钱').clickable(true).boundsInside(device.width/2, device.height-300, device.width, device.height).visibleToUser(true).findOne(1000);
    if(moneybtn){
        console.error('点击去赚钱moneybox');
        click(moneybtn.bounds().centerX(),moneybtn.bounds().centerY());
        sleep(8000);
        singlecheck();//判断签到层
    }
    if(className('Button').text('金币暴涨').findOne(1000)){
        console.error('点击宝箱');
        click(device.width - 150, device.height - 300);
        sleep(8000);
        //倒计时结束,才能开宝箱哦
        let x = className('Button').textMatches(/去看广告得最高\d+金币/).visibleToUser(true).findOne(1000);
        if (x) {
            click(x.bounds().centerX(), x.bounds().centerY());//再次点弹出宝箱层中的红色按钮
            sleep(5000);
        } else {
            var popdiv=textMatches(/倒计时结束.*/).visibleToUser(true).findOne(1000);
            if(popdiv){
                toastLog('等待宝箱倒计时');
                let closebtn=popdiv.parent().parent().parent().child(0);
                if(closebtn)click(closebtn.bounds().centerX(),closebtn.bounds().centerY());
            }else{
                toastLog('1.未进入宝箱视频');
            }
            return;
        }
        //如果进入看视频赚金币则观看视频
        let advedio = idMatches(/.*countdown_info_container/).boundsInside(0, 0, device.width, 500).visibleToUser(true).findOne(1000);
        let liveing = idMatches(/.*live_close_container/).boundsInside(device.width - 500, 0, device.width, 500).visibleToUser(true).findOne(1000);
        if (advedio || liveing) {
            playvideo('A');
            console.error('宝箱任务结束moneybox');
        } else {
            toastLog('2.未进入宝箱视频');
        }
    }else{
        toastLog('没有找到金币暴涨moneybox');
    }
}

//判断进入看广告视频赚金币
function playvideo(m) {
    function stopvideo(n) {
        sleep(1000);
        //操作弹出提示
        var okbtn = className('TextView').textMatches(/再看\d{1,2}.*/).visibleToUser(true).findOnce();
        if (okbtn) {
            let btn = className('TextView').text('放弃奖励').visibleToUser(true).findOnce();
            if(btn)click(btn.bounds().centerX(), btn.bounds().centerY() - 120);
            var b = okbtn.text().match(/\d+/);
            var t = 1 * (b ? b[0] : 1) + random(8, 13);
            cutDownBySleep(t, '再看');
            back();
        }
        var okbtn = className('TextView').textMatches(/领取奖励|退出直播间/).visibleToUser(true).findOnce();
        if (okbtn) {
            click(okbtn.bounds().centerX(), okbtn.bounds().centerY());
            var t = random(8, 13);
            cutDownBySleep(t, okbtn.text());
        }
        var okbtn = className('Button').textMatches(/继续赚金币/).visibleToUser(true).findOnce();
        if (okbtn) {
            click(okbtn.bounds().centerX(), okbtn.bounds().centerY());
            var t = random(8, 13);
            cutDownBySleep(t, '继续');
        }
        sleep(1000);
        console.log(n+'.0.-----------------------e');
    }

    working = true;
    console.error('开始循环赚金币playvideo');
    let x = className('Button').textMatches(/去看广告得最高\d+金币/).visibleToUser(true).findOne(1000);
    if (x) {
        click(x.bounds().centerX(), x.bounds().centerY());
        sleep(5000);
    }
    let i=0;
    var okbtn = className('TextView').textMatches(/\d{1,2}s后可领取.*|已成功领取.*/).boundsInside(0, 0, device.width / 2, 300).visibleToUser(true).findOnce();
    while (okbtn) {
        console.log(m+'.1.-----------------------'+i);
        var b = okbtn.text().match(/^\d+/);
        var t = 1 * (b ? b[0] : 1) + random(5, 9);
        cutDownBySleep(t, '看广告');
        //点击左上角或back()
        click(okbtn.bounds().centerX(), okbtn.bounds().centerY());
        stopvideo(m);
        okbtn = className('TextView').textMatches(/\d{1,2}s后可领取.*|已成功领取.*/).boundsInside(0, 0, device.width / 2, 300).visibleToUser(true).findOnce();
        i++;
    }

    //看直播领金币
    let title=className('TextView').text('看直播领金币').visibleToUser(true).findOnce();
    if (title) {
        //选择直播间,这里应该循环10次,每4次向上滚动一次
        let view = idMatches(/.*recycler_view/).findOne(1000);
        if(view){
            i=0;
            while(i<99&&title){
                console.log(m+'.2.-----------------------'+i);
                for (j = 0; j < view.childCount(); j++) {
                    toastLog(m+'.观看第'+(i*4+j+1)+'个直播');
                    if(view.child(j))view.child(j).click();//进入直播间
                    sleep(3000);
                    let liveing = idMatches(/.*live_close_container/).boundsInside(device.width - 500, 0, device.width, 500).visibleToUser(true).findOne(1000);
                    if(liveing){
                        cutDownBySleep(random(8,13), '看直播领金币');
                        //点击退出直播间
                        click(liveing.bounds().centerX(),liveing.bounds().centerY());
                        sleep(1000);
                        var okbtn = className('TextView').textMatches(/继续观看|领取奖励|退出.*/).visibleToUser(true).findOne(1000);
                        if (okbtn) {
                            sleep(1000);
                            click(okbtn.bounds().centerX(),okbtn.bounds().centerY());
                            if(okbtn.text()=='继续观看'){
                                let a = idMatches(/.*close_dialog_title/).className('TextView').visibleToUser(true).findOne(1000);
                                let b = a?a.text().match(/\d+/):3;
                                let t = 1 * (b ? b[0] : 1) + random(8,13);
                                cutDownBySleep(t, okbtn.text());
                            }
                            sleep(1000);
                        }
                    }
                }
                if((i*4+j+1)>random(9,15)){
                    log('=============',(i*4+j+1));
                    break;
                }
                i++;
                view.scrollForward();
                sleep(3000);
                title=className('TextView').text('看直播领金币').visibleToUser(true).findOnce();
            }
        }
    }

    //刷广告视频赚金币
    let back_btn = className('ImageView').desc("返回").clickable(true).boundsInside(0, 0, 500, 500).visibleToUser(true).findOne(1000);
    if (back_btn) {
        console.log('刷广告视频赚金币');
        i=0;
        while(back_btn){
            if(i>50)break;
            console.log(m+'.3.-----------------------'+i);
            var t = random(20, 30);
            cutDownBySleep(t, '刷广告');
            click(back_btn.bounds().centerX(),back_btn.bounds().centerY());
            stopvideo(m);
            back_btn = className('ImageView').desc("返回").clickable(true).boundsInside(0, 0, 500, 500).visibleToUser(true).findOne(1000);
            i++;
        }
        back();
    }

    //返回
    if (!className('Button').text('金币暴涨').findOne(1000)) { back(); sleep(1000); }
    let btn = className('TextView').text('放弃奖励').visibleToUser(true).findOnce();
    if (btn) click(btn.bounds().centerX(), btn.bounds().centerY());

    console.error('循环赚金币结束playvideo');
    working = false;
}

//主程序函数===============================================================
function Main(){
    var loopTimes = random(3,5); //work循环次数
    function work() {
        toastLog("开始工作work");
        var listArray = tasklist();
        if (listArray.length > 0) {
            sleep(3000);
            toastLog('开始做任务');
            for (i = 0; i < listArray.length; i++) {
                if (listArray[i][1]) {
                    toastLog(i+'.'+listArray[i][0]);
                    //点击任务,这里不可以用坐标点击,因为有的条目可能会在屏幕外面
                    listArray[i][1].click();
                    sleep(3000);
                    playvideo(i);
                }
            }
        }
        //开宝箱
        moneybox();
        //回到首页准备刷视频
        console.error("开始刷视频模式+++++++++++++");
        gohome(); startSec = Date.now(); gogogo(50);
        console.error("刷视频模式结束+++++++++++++");
    }
    //打开快手App
    if (getPackageName(AppName)) {
        openApp(AppName);
        //等待进入主界面成功
        toastLog('进入主函数'+ver);
        gohome();
        sleep(3000);
        //先检测签到提示是否自动弹出在【首页】
        //singlecheck();
        //sleep(3000);
        toastLog("刚启动先刷视频提高活跃度");
        gogogo(20);

        while (loopTimes > 0) {
            work();//开始工作
            sleep(5000);
            loopTimes--;
        }

        console.clear();
        console.warn('运行结束关闭应用');
    } else {
        console.warn("未安装:" + AppName);
        work_thread.interrupt();
        device.cancelKeepingAwake();
        engines.myEngine().forceStop();
        return;
    }
    console.show();
    console.warn('执行完成用时' + SecondsToHMS((Date.now() - starttime) / 1000));
    cutDownBySleep(5,'5秒后进入息屏挂机模式');
    console.hide();
    closeApp(AppName);
    sleep(3000);
    oled(random(600,900));//熄屏挂机约10~15分钟左右
}
function getHomeBtn(){
    var homepage = idMatches(/.*left_btn/).desc("侧边栏").clickable(true).boundsInside(0, 0, 500, 500).visibleToUser(true).findOne(1000);
    var topbtn = descMatches(/发现|关注/).selected(true).boundsInside(0, 0, device.width, 500).visibleToUser(true).findOne(1000);
    return (homepage!=null&&topbtn!=null);
}
function gohome() {
    function closediv(){
        //关闭弹出层
        var popdiv=className('Image').text('huge_sign_marketing_popup').findOne(1000);
        if(popdiv){
            let closebtn=popdiv.parent().parent().child(0);
            if(closebtn)click(closebtn.bounds().centerX(),closebtn.bounds().centerY());
        }
    }
    toastLog('回到首页gohome');
    closediv();
    var homepage = idMatches(/.*left_btn/).desc("侧边栏").clickable(true).boundsInside(0, 0, 500, 500).visibleToUser(true).findOne(1000);
    if(!homepage){
        var MaxLoop = 5;
        while (!homepage && MaxLoop > 0) {
            MaxLoop--;
            back(); sleep(3000);
            var okbtn = className('TextView').textMatches(/退出.*/).findOnce();
            if(okbtn){okbtn.click();sleep(3000);}
            homepage = idMatches(/.*left_btn/).desc("侧边栏").clickable(true).boundsInside(0, 0, 500, 500).visibleToUser(true).findOne(1000);
        }
    }
    if(homepage){
        var btn=idMatches(/.*textView/).desc("发现").visibleToUser(true).findOne(1000);
        if(btn)click(btn.bounds().centerX(),btn.bounds().centerY());
        sleep(3000);closediv();
    }else{
        toastLog('需要重启软件【截图】');
        //截图保存界面,以备后续查看
        captureScreen(files.getSdcardPath() + '/脚本/gohome1_' + currentActivity() + '.png');
        sleep(1000);
        device.wakeUp();//唤醒设备
        sleep(1000);
        left2right(1);
        sleep(1000);
        closeApp(AppName);
        sleep(5000);
        openApp(AppName);
        sleep(1000);
    }
}
function randomHeart(num) {
    let randomIndex = num ? num : random(1, 30);
    //随机恢复到首页
    if (randomIndex % 5 == 0) {
        console.log('拟人:随机回首页');
        gohome();
        return;
    }
    //随机点赞
    if (randomIndex % 6 == 0) {
        var like = id('like_element_click_layout').clickable(true).boundsInside(device.width-300, device.height/2, device.width, device.height).visibleToUser(true).findOnce();
        if (like) {
            console.log('拟人:随机点赞');
            click(like.bounds().centerX(),like.bounds().centerY());
            return;
        }
    }
    //随机评论
    if(randomIndex % 7 == 0){
        var plug = id('comment_element_click_layout').longClickable(true).boundsInside(device.width-300, device.height/2, device.width, device.height).visibleToUser(true).findOne(1000);
        if(plug){
            console.log('拟人:随机评论');
            //长按评论按钮
            longClick(plug.bounds().centerX(),plug.bounds().centerY());
            sleep(1000);
            var plugdiv=id('emoji_quick_send_list').className('android.view.ViewGroup').visibleToUser(true).findOne(1000);
            if(plugdiv){
                let icoY=plugdiv.bounds().bottom-90;
                let icoX=[
                    plugdiv.bounds().left+90,
                    plugdiv.bounds().left+220,
                    plugdiv.bounds().left+350,
                    plugdiv.bounds().left+500
                ];
                let index = random(2, icoX.length) - 1;
                //console.log(icoX[index],icoY);
                click(icoX[index],icoY);
                sleep(3000);
            }
        }
    }
    //随机收藏
    if (randomIndex % 8 == 0) {
        var collect = id('click_area_collect').clickable(true).boundsInside(device.width-300, device.height/2, device.width, device.height).visibleToUser(true).findOnce();
        if (collect) {
            console.log('拟人:随机收藏');
            click(collect.bounds().centerX(),collect.bounds().centerY());
            return;
        }
    }
    //随机下滑
    if (randomIndex % 9 == 0) {
        console.log('拟人:随机下滑');
        swipe(device.width / 2, device.height * 0.1 + randomIndex, device.width / 2, device.height * 0.9 - randomIndex, random(500, 1500));
        return;
    }
    //连续上滑
    if (randomIndex % 10 == 0) {
        console.log('拟人:连续上滑');
        var k = random(2, 4);
        for (var i = 0; i < k; i++) {
            var j = random(2, 5);
            if (j == 3) {
                swipe(device.width / j, device.height * 0.1 + j * k, device.width / j, device.height * 0.9 - j * k, j * 50);
            } else {
                swipe(device.width / j, device.height * 0.9 - j * k, device.width / j, device.height * 0.1 + j * k, j * 50);
            }
            sleep(j * 250);
        }
        return;
    }
    //向上滑
    slidingByCurve();
}
function isvideoPage() {
    console.verbose("检测是否视频播放中isvideoPage");
    var isvideo = false;
    var homepage = getHomeBtn();
    if (homepage) {
        //关闭自动弹出的层
        var div1 = idMatches(/.*design_bottom_sheet.*|.*content_nest.*|.*recyclerView.*/).visibleToUser(true).findOnce();
        if (div1) {
            toastLog('0.关闭弹出层');
            //captureScreen(files.getSdcardPath() + '/脚本/isvideoPage_' + currentActivity() + '.png');
            //sleep(1000);
            click(80, 150);
            sleep(3000);
        }
        var living = idMatches(/.*live_close_container/).boundsInside(device.width-300, 0, device.width, 300).visibleToUser(true).findOnce();//直播间
        if (living) {
            toastLog("1.退出直播间");
            click(living.bounds().centerX(), living.bounds().centerY());
            sleep(2000);
            var div0=text('退出直播间').visibleToUser(true).findOnce();
            if(div0)click(div0.bounds().centerX(), div0.bounds().centerY());
            sleep(2000);
        }
        //id=live_slide_view_pager
        if (currentActivity() == 'com.kuaishou.live.core.basic.activity.LiveSlideActivity') {
            toastLog("2.退出直播间");
            back();sleep(2000);
            var div0=text('退出直播间').visibleToUser(true).findOnce();
            if(div0)click(div0.bounds().centerX(), div0.bounds().centerY());
        }
        isvideo=idMatches(/.*nasa_groot_view_pager/).visibleToUser(true).findOne(1000);
        //log(isvideo);
    }
    return isvideo;
}
function gogogo(n) {
    let gotime = random(3,6); //刷视频每n分钟结束一次
    for (var i = 1; i <= n; i++) {
        let flashtime=parseInt((Date.now() - startSec) / 1000);
        console.log('第'+i+'次刷视频,累计用时:',flashtime,'秒');
        if( flashtime > gotime*60){console.warn(gotime+'分种超时,停止刷视频'); running = false; floaty.closeAll(); break;}
        if (isvideoPage()) {
            running = true;

            randomHeart();//拟人化
            cutDownBySleep(random(6, 30),'观看视频:');//每个视频随机时间 6-30s
        } else {
            running = false;
            toastLog('not at the video page');
            var dialog = currentActivity();
            if (!dialog.match(/android\.app\.Dialog|android\.widget\.FrameLayout/)) {
                //截图保存界面,以备后续查看
                console.info('【gogogo截图】',dialog);
                captureScreen(files.getSdcardPath() + '/脚本/gogogo_' + dialog + '.png');
                gohome();
            }
            sleep(3000);
        }
    }
    running = false;
}
function cutDownBySleep(lasterSecend, message) {
    message = message || "";
    floaty.closeAll();
    var fwin = floaty.rawWindow(
        `<frame id="frame" alpha="0" w="{{device.width-500}}px" h="150px" marginTop="{{device.height-550}}px" marginLeft="250px" marginRight="250px">
            <card w="auto" h="auto" layout_gravity="center" cardCornerRadius="5dp" cardBackgroundColor="#eeeeee" >
                <text id="title" text="" textColor="#333333" textSize="13sp" padding="12 8" />
            </card>
        </frame>`
    );
    fwin.setTouchable(false);
    sleep(300);
    for (let i = lasterSecend; i >= 0; i--) {
        if (!running && !working) { break; }
        if (!fwin || !fwin.title) { break; }
        ui.run(() => { fwin.title.setText(message + "剩余" + i + "秒"); fwin.frame.attr("alpha", 0.8); });
        sleep(1000);
    }
    fwin=null;
    floaty.closeAll();
}
function slidingByLine() {
    // top X,Y范围
    tx = randomPointLoc(parseInt(device.width / 3), parseInt(device.width / 2));
    ty = randomPointLoc(parseInt(device.height / 5), parseInt(device.height / 4));
    // bottom X,Y 范围
    bx = randomPointLoc(parseInt(device.width / 3), parseInt(device.width / 2));
    by = randomPointLoc(parseInt(3 * device.height / 4), parseInt(4 * device.height / 5));

    slidingTime = randomRangeTime(0.8, 1.3);
    log("上滑:随机直线");
    //log("X: "+ Math.abs(bx-tx) + " Y: "+ Math.abs(by - ty));
    swipe(bx, by, tx, ty, slidingTime);
}
function left2right(direction) {
    var intX=parseInt(Math.random()*200+400);
    var intY=parseInt(Math.random()*200+200);
    var distance=parseInt(Math.random()*100+device.height/4);
    switch (direction) {
        case 1:
            //向上小距离
            sml_move(intX, intY + distance, intX, intY, 400);
            break;
        case 2:
            //向下小距离
            sml_move(intX, intY, intX, intY + distance, 400);
            break;
        case 3:
            //向左翻屏
            sml_move(
                device.width / 2 + parseInt(Math.random() * 100) + 300,
                device.height / 4 - parseInt(Math.random() * 200) + 100,
                0 + parseInt(Math.random() * 100),
                device.height / 5 + parseInt(Math.random() * 100),
                500
            );
            break;
        case 4:
            //向右翻屏
            sml_move(
                device.width / 2 - parseInt(Math.random() * 100) - 300,
                device.height / 5 - parseInt(Math.random() * 200) + 100,
                device.width - parseInt(Math.random() * 100),
                device.height / 4 + parseInt(Math.random() * 100),
                500
            );
            break;
    }
    sleep(1000);
}
function slidingByCurve() {
    // top X,Y范围
    tx = randomPointLoc(parseInt(device.width / 3), parseInt(device.width / 2));
    ty = randomPointLoc(parseInt(device.height / 5), parseInt(device.height / 4));
    // bottom X,Y 范围
    bx = randomPointLoc(parseInt(device.width / 3), parseInt(device.width / 2));
    by = randomPointLoc(parseInt(2 * device.height / 3), parseInt(3 * device.height / 4));

    slidingTime = randomRangeTime(0.2, 0.6);
    log("上滑:仿真曲线");
    //log("X: "+ Math.abs(bx-tx) + " Y: "+ Math.abs(by - ty));
    sml_move(bx, by, tx, ty, slidingTime);
}
function randomPointLoc(start, end) {
    len = Math.abs(end - start);
    loc = Math.floor(Math.random() * len) + start;
    return loc;
}
function randomRangeTime(start, end) {
    len = Math.abs(end - start) * 1000;
    ms = Math.floor(Math.random() * len) + start * 1000;
    return ms;
}
function sml_move(qx, qy, zx, zy, time) {
    var xxy = [time];
    var point = [];
    var dx0 = {
        "x": qx,
        "y": qy
    };
    var dx1 = {
        "x": random(qx - 100, qx + 100),
        "y": random(qy, qy + 50)
    };
    var dx2 = {
        "x": random(zx - 100, zx + 100),
        "y": random(zy, zy + 50),
    };
    var dx3 = {
        "x": zx,
        "y": zy
    };
    for (var i = 0; i < 4; i++) {
        eval("point.push(dx" + i + ")");
    }
    // log(point[3].x)
    for (let i = 0; i < 1; i += 0.08) {
        let newPoint=bezier_curves(point, i);
        xxyy = [parseInt(newPoint.x), parseInt(newPoint.y)]
        xxy.push(xxyy);
    }
    try {
        gesture.apply(null, xxy);
    } catch (e) {
        log('error:',xxy);
    }
}
function bezier_curves(cp, t) {
    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;
}
function SecondsToHMS(seconds) {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const remainingSeconds = Math.floor(seconds % 60);
    return (hours > 0 ? hours + "时" : "") + (minutes > 0 ? minutes + "分" : "") + remainingSeconds + "秒";
}
function getindexInParent(child) {
    var parent = child.parent();
    for (var i = 0; i < parent.childCount(); i++) {
        if (parent.child(i).find(className('CheckBox').checked(true).visibleToUser(true)).length > 0) {
            return i;
        }
    }
    return -1; // 如果找不到子元素,则返回-1
}
function isRectInScreen(bounds) {
    var x = bounds.left, y = bounds.top,
        a = bounds.right, b = bounds.bottom;
    return (
      x >= 0 && x <= device.width &&
      y >= 0 && y <= device.height &&
      a > 0 && a <= device.width &&
      b > 0 && b <=device.height
    );
}
function openApp(appname){
    console.warn('启动应用:' + appname);
    var appstate = launchApp(appname);
    sleep(5000);
    if (appstate) {
        toastLog("应用正在运行");
    } else {
        toastLog("无法自启动,需模拟点击");
        home();//要启动的APP必须放在第一页中
        sleep(3000);
        var app = id("item_title").text(appname).visibleToUser(true).findOne(2000);
        if (app) {
            click(app.bounds().centerX(), app.bounds().top - 50);
            sleep(8000);
        }else{
            toastLog('要启动的APP必须放在首页,即按Home能看到的那一页');
            work_thread.interrupt();
            engines.myEngine().forceStop();
            exit();
        }
    }
}
function closeApp(appname) {
    let packageName = getPackageName(appname);
    // 使用ADB命令强行结束进程
    //shell("adb shell am force-stop " + packageName);
    console.warn('关闭应用:' + appname);
    app.openAppSetting(packageName);
    text(app.getAppName(packageName)).waitFor();
    let is_sure = textMatches(/.*强行停止.*/).visibleToUser(true).findOnce();
    if (is_sure&&is_sure.enabled()) {
        try {
            var btn = className("Button").text('强行停止').visibleToUser(true).findOnce();
            if (btn) btn.click();
            sleep(1000);
            btn = className("Button").text('强行停止').visibleToUser(true).findOnce();
            if (btn) btn.click();
            sleep(1000);
            btn = className("Button").text('确定').visibleToUser(true).findOnce();
            if (btn) btn.click();
            back(); back(); back();
            home();
        } catch (e) {
            log(app.getAppName(packageName) + "应用已被关闭");
            sleep(1000);
            back(); back(); back();
            home();
        }
    } else {
        log(app.getAppName(packageName) + "应用不能被正常关闭");
        back(); back(); back();
        home();
    }
}
function update(){
    http.get('https://update.greasyfork.org/scripts/520135/%E5%BF%AB%E6%89%8B%E8%84%9A%E6%9C%AC.js', {}, function(res, err){
        if(res.statusCode == 200){
            var Source = res.body.bytes();
            if(Source){
                files.writeBytes(files.getSdcardPath() + '/脚本/快手脚本.js', Source);
                console.verbose('更新主程序:成功',ver);
            }else{
                console.verbose('更新主程序:错误',ver);
            }
        }else{
            console.verbose('更新主程序:失败',ver);
        }
    });
}

//===================================================================================
requestScreenCapture(false);//请求截图权限
runtime.getImages().initOpenCvIfNeeded();//初始化OpenCv
global.starttime = Date.now();//程序运行开始时间

var oledwin = null, win = null;
function oled(i) {
    let j=i||3;
    floaty.closeAll();
    oledwin = floaty.rawWindow(
        `<frame bg="#000000">
            <card w="auto" h="auto" layout_gravity="center" cardBackgroundColor="#000000" >
            <vertical>
                <text id="texts" text="息屏挂机模式" textColor="#999999" textSize="13sp" />
                <button id="button" text="退出挂机" margin="0 20" />
            </vertical>
            </card>
        </frame>`
    );
    oledwin.button.on("click", function () {
        console.info('手动停止挂机');
        floaty.closeAll();
        oledwin=null;
    });
    oledwin.setSize(-1, -1);
    oledwin.setTouchable(true);
    sleep(300);
    console.info('挂机模式开启……');
    //保持脚本运行
    while (j > 0 && oledwin) {
        if (oledwin.texts) {
            let t = parseInt(j / 60) + "分" + parseInt(j % 60) + "秒";
            ui.run(() => { oledwin.texts.setText("息屏挂机倒计时:" + t + "\n\n倒计时结束后重启主线程gifshow") });
        }
        j--;
        sleep(1000);
    }
    floaty.closeAll();
    oledwin=null;
    console.info('挂机结束用时:',(parseInt((i-j) / 60) + "分" + parseInt((i-j) % 60) + "秒"));
}

function Observer() {
    function unique(arr) {
        let newArr = [arr[0]];
        for (let i = 1; i < arr.length; i++) {
            let flag = false;
            for (var j = 0; j < newArr.length; j++) {
                if (arr[i] == newArr[j]) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                newArr.push(arr[i]);
            }
        }
        return newArr;
    }
    var currentActis = new Array();
    for (let c = 0; c < 59; c++) {//连续扫描60秒后返回结果,如果60秒停留在同一活动页面,则就要重启线程了
        //关闭自动弹出的层
        var btn=idMatches(/close/).visibleToUser(true).findOnce();
        if (btn) { 
            console.log('点左上角关闭弹出层Observer');
            click(btn.bounds().centerX(), btn.bounds().centerY());
        }
        var btntxt = textMatches(/同意|满意|关闭|关闭应用|不在提醒|我知道了|以后再说|暂不使用|忽略提醒|仍要退出/).visibleToUser(true).findOnce();
        if (btntxt && btntxt.packageName() == packageName) {
            console.warn('点击:' + btntxt.text());
            //截图保存界面,以备后续查看
            //captureScreen(files.getSdcardPath() + '/脚本/Observer1_' + currentActivity() + '.png');
            click(btntxt.bounds().centerX(),btntxt.bounds().centerY());
        }
        //toastLog(currentActivity());
        currentActis[c] = currentActivity();
        sleep(1000);//这是每秒扫描一次活动页
    }
    //检测oled挂机模式结束,则重启main线程
    if (oledwin) { win = oledwin; return true; } else if (win) { win = null; return false; }
    //toastLog(currentActivity());
    let ac = unique(currentActis);
    let cc = currentActivity().match(/.*HomeActivity|.*PhotoDetailActivity|.*AwardVideoPlayActivity|.*AdKwaiRnActivity|.*app\.Dialog|android\.widget\.FrameLayout/);
    if (ac.length == 1 && !cc) {
        console.info('60秒卡顿:',ac[0]);
        //截图保存界面,以备后续查看
        captureScreen(files.getSdcardPath() + '/脚本/Observer2_' + currentActivity() + '.png');
        return false;
    }
    return true;
}

// 》》》》》》》》》》》》》》》》》》》 START
work_thread = threads.start(function () {
    Main();
});

observer_thread = threads.start(function () {
    setInterval(function () {
        console.verbose('--------多线程安全检测---------');
        if(oledwin){if(oledwin.texts)console.verbose(oledwin.texts.text().split("\n").shift());}
        if (running) {
            let worktime = parseInt((Date.now() - starttime) / 1000);
            console.verbose("脚本连续运行:" + SecondsToHMS(worktime));
            //如果运行时间超过4小时,则关闭应用,停止脚本。
            if (worktime > 60 * 60 * 4) {
                device.cancelKeepingAwake();
                work_thread.interrupt();
                console.show();
                console.clear();
                console.warn("脚本连续运行超4小时,终止运行!");
                sleep(5000);
                console.hide();
                closeApp(AppName);
                sleep(5000);
                //熄屏
                runtime.accessibilityBridge.getService().performGlobalAction(android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN);
                //停止本脚本
                //engines.myEngine().forceStop();
                //结束所有Autojx进程
                engines.stopAll();
                exit();
            }
        }
        if (!Observer()) {
            work_thread.interrupt();
            work_thread = threads.start(function () {
                toast("Main线程在5秒后重启!");
                console.show();
                console.clear();
                console.warn("Main线程在5秒后重启!");
                running=false;
                sleep(5000);
                console.hide();
                if(currentPackage() == packageName)closeApp(AppName);
                sleep(5000);
                Main();
            });
        }
    }, 3000);//这个时间是线程休息时间
});