Browse Source

新增for 结点

yichael 2 months ago
parent
commit
5b60f94e93
24 changed files with 557 additions and 85 deletions
  1. 6 2
      nodejs/ef-compiler/components/actions/delay-parser.js
  2. 2 1
      nodejs/ef-compiler/components/actions/for-parser.js
  3. 23 8
      nodejs/ef-compiler/components/actions/set-parser.js
  4. 20 0
      nodejs/ef-compiler/components/actions/try-parser.js
  5. 67 14
      nodejs/ef-compiler/components/sequence-runner.js
  6. 3 0
      nodejs/ef-compiler/components/workflow-json-parser.js
  7. 1 0
      nodejs/ef-compiler/ef-compiler.js
  8. 1 4
      nodejs/run-process.js
  9. 1 2
      static/device_list.json
  10. 27 16
      static/process/RedNoteAIThumbsUp/process.json
  11. BIN
      static/process/RedNoteAIThumbsUp/resources/图文点赞.png
  12. BIN
      static/process/RedNoteAIThumbsUp/resources/点赞按钮_已点赞.png
  13. BIN
      static/process/RedNoteAIThumbsUp/resources/点赞按钮_未点赞2.png
  14. 0 0
      static/process/RedNoteAIThumbsUp/resources/视频点赞.png
  15. 72 38
      static/process/RedNoteBrowsingAndThumbsUp/process.json
  16. BIN
      static/process/RedNoteBrowsingAndThumbsUp/resources/图文点赞.png
  17. BIN
      static/process/RedNoteBrowsingAndThumbsUp/resources/点赞按钮_已点赞.png
  18. BIN
      static/process/RedNoteBrowsingAndThumbsUp/resources/点赞按钮_未点赞2.png
  19. 0 0
      static/process/RedNoteBrowsingAndThumbsUp/resources/视频点赞.png
  20. 200 0
      static/process/RedNoteBrowsingAndThumbsUpTest/bp.json
  21. 131 0
      static/process/RedNoteBrowsingAndThumbsUpTest/process.json
  22. 3 0
      static/process/RedNoteBrowsingAndThumbsUpTest/readme.md
  23. BIN
      static/process/RedNoteBrowsingAndThumbsUpTest/resources/图文点赞.png
  24. BIN
      static/process/RedNoteBrowsingAndThumbsUpTest/resources/视频点赞.png

+ 6 - 2
nodejs/ef-compiler/components/actions/delay-parser.js

@@ -1,4 +1,4 @@
-/** 语句:delay 延迟 */
+/** 语句:delay 延迟(value 支持变量,如 "{{stay-duration}}s";格式:数字+单位 s/m/h) */
 const types = ['delay']
 
 function parse(action, parseContext) {
@@ -7,7 +7,11 @@ function parse(action, parseContext) {
 }
 
 async function execute(action, ctx) {
-  const delayMs = ctx.parseDelayString(action.value || action.delay || '0s')
+  const raw = action.value || action.delay || '0s'
+  const resolved = ctx.replaceVariablesInString && ctx.variableContext
+    ? ctx.replaceVariablesInString(String(raw), ctx.variableContext)
+    : raw
+  const delayMs = ctx.parseDelayString(resolved)
   if (delayMs > 0) await new Promise(r => setTimeout(r, delayMs))
   return { success: true }
 }

+ 2 - 1
nodejs/ef-compiler/components/actions/for-parser.js

@@ -7,7 +7,8 @@ function parse(action, parseContext) {
   const parsed = {
     type: 'for',
     variable: action.variable,
-    items: resolveValue(action.items, variableContext),
+    times: action.times,
+    items: action.items != null ? resolveValue(action.items, variableContext) : null,
     body: action.body ? parseActions(action.body) : [],
   }
   return Object.assign({}, action, parsed)

+ 23 - 8
nodejs/ef-compiler/components/actions/set-parser.js

@@ -74,19 +74,34 @@ function parseTimeString(timeStr) {
   }
 }
 
+const DELAY_UNIT_MS = {
+  ms: 1,
+  s: 1000,
+  m: 60 * 1000,
+  h: 60 * 60 * 1000,
+  d: 24 * 60 * 60 * 1000,
+  w: 7 * 24 * 60 * 60 * 1000,
+  '月': 30 * 24 * 60 * 60 * 1000,
+  y: 365 * 24 * 60 * 60 * 1000,
+}
+
+/** 解析时长字符串,支持单位 ms/s/m/h/d/w/月,支持组合如 1h3m48s、2d30m */
 function parseDelayString(delayStr) {
   if (!delayStr || typeof delayStr !== 'string' || delayStr.trim() === '') return 0
   try {
     const trimmed = delayStr.trim()
-    const unit = trimmed.slice(-1).toLowerCase()
-    const value = parseInt(trimmed.slice(0, -1), 10)
-    if (isNaN(value) || value < 0) return null
-    switch (unit) {
-      case 's': return value * 1000
-      case 'm': return value * 60 * 1000
-      case 'h': return value * 60 * 60 * 1000
-      default: return null
+    const re = /(\d+)\s*(ms|s|m|h|d|w|月|y)/g
+    let total = 0
+    let hadMatch = false
+    let match
+    while ((match = re.exec(trimmed)) !== null) {
+      const value = parseInt(match[1], 10)
+      const unit = match[2]
+      if (value < 0 || !DELAY_UNIT_MS[unit]) continue
+      total += value * DELAY_UNIT_MS[unit]
+      hadMatch = true
     }
+    return hadMatch ? total : null
   } catch (e) {
     return null
   }

+ 20 - 0
nodejs/ef-compiler/components/actions/try-parser.js

@@ -0,0 +1,20 @@
+/** 语句:try 尝试执行,成功走 success、失败走 fail(解析在此,执行在 sequence-runner) */
+const types = ['try']
+
+function parse(action, parseContext) {
+  const { parseActions } = parseContext
+  const failActions = action.fail || action.catch
+  const parsed = {
+    type: 'try',
+    try: (action.try || action.body) ? parseActions(action.try || action.body) : [],
+    success: action.success ? parseActions(action.success) : [],
+    fail: failActions ? parseActions(failActions) : [],
+  }
+  return Object.assign({}, action, parsed)
+}
+
+async function execute() {
+  return { success: true }
+}
+
+module.exports = { types, parse, execute }

+ 67 - 14
nodejs/ef-compiler/components/sequence-runner.js

@@ -14,7 +14,7 @@ async function executeActionSequence(
   depth,
   ctx
 ) {
-  const { executeAction, logMessage, evaluateCondition, getActionName, parseDelayString, calculateWaitTime, state } = ctx
+  const { executeAction, logMessage, evaluateCondition, getActionName, parseDelayString, calculateWaitTime, replaceVariablesInString, state } = ctx
   const variableContext = state.variableContext
   const DEFAULT_STEP_INTERVAL = ctx.DEFAULT_STEP_INTERVAL ?? 1000
 
@@ -22,7 +22,6 @@ async function executeActionSequence(
     state.globalStepCounter = 0
     state.variableContextInitialized = false
     state.currentWorkflowFolderPath = folderPath
-    await logMessage('========================', folderPath)
   }
 
   let completedSteps = 0
@@ -34,8 +33,16 @@ async function executeActionSequence(
 
     if (action.type === 'schedule') {
       const condition = action.condition || {}
-      const intervalStr = condition.interval || '0s'
-      const repeat = condition.repeat !== undefined ? condition.repeat : 1
+      let intervalStr = condition.interval || '0s'
+      if (replaceVariablesInString && typeof intervalStr === 'string') {
+        intervalStr = replaceVariablesInString(intervalStr, variableContext)
+      }
+      let repeat = condition.repeat !== undefined ? condition.repeat : 1
+      if (typeof repeat === 'string' && variableContext) {
+        const varName = repeat.replace(/^\{|\}$/g, '').trim()
+        const resolved = variableContext[varName]
+        repeat = resolved !== undefined && resolved !== null && resolved !== '' ? (parseInt(resolved, 10) || 1) : 1
+      }
       const actionsToExecute = action.interval || []
       const intervalMs = parseDelayString(intervalStr) || 0
       const maxIterations = repeat === -1 ? Infinity : (typeof repeat === 'number' ? repeat : 1)
@@ -75,14 +82,33 @@ async function executeActionSequence(
     }
 
     if (action.type === 'for') {
-      const items = Array.isArray(action.items) ? action.items : []
-      for (const item of items) {
-        if (shouldStop && shouldStop()) return { success: false, error: '执行被停止', completedSteps }
-        if (action.variable) variableContext[action.variable] = item
-        if (action.body && action.body.length > 0) {
-          const result = await executeActionSequence(action.body, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
-          if (!result.success) return result
-          completedSteps += result.completedSteps || 0
+      if (action.times != null) {
+        let count = action.times
+        if (typeof count === 'string') {
+          const varName = count.replace(/^\{|\}$/g, '').trim()
+          count = Math.max(0, parseInt(variableContext[varName], 10) || 0)
+        } else {
+          count = Math.max(0, parseInt(count, 10) || 0)
+        }
+        for (let i = 0; i < count; i++) {
+          if (shouldStop && shouldStop()) return { success: false, error: '执行被停止', completedSteps }
+          if (action.variable) variableContext[action.variable.replace(/^\{|\}$/g, '').trim()] = i
+          if (action.body && action.body.length > 0) {
+            const result = await executeActionSequence(action.body, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
+            if (!result.success) return result
+            completedSteps += result.completedSteps || 0
+          }
+        }
+      } else {
+        const items = Array.isArray(action.items) ? action.items : []
+        for (const item of items) {
+          if (shouldStop && shouldStop()) return { success: false, error: '执行被停止', completedSteps }
+          if (action.variable) variableContext[action.variable.replace(/^\{|\}$/g, '').trim()] = item
+          if (action.body && action.body.length > 0) {
+            const result = await executeActionSequence(action.body, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
+            if (!result.success) return result
+            completedSteps += result.completedSteps || 0
+          }
         }
       }
       continue
@@ -100,6 +126,34 @@ async function executeActionSequence(
       continue
     }
 
+    if (action.type === 'try') {
+      const tryActions = action.try || action.body || []
+      const successActions = action.success || []
+      const failActions = action.fail || action.catch || []
+      const result = tryActions.length > 0
+        ? await executeActionSequence(tryActions, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
+        : { success: true, completedSteps: 0 }
+      if (result.success && successActions.length > 0) {
+        const successResult = await executeActionSequence(successActions, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
+        if (!successResult.success) return successResult
+        completedSteps += (result.completedSteps || 0) + (successResult.completedSteps || 0)
+      } else if (result.success) {
+        completedSteps += result.completedSteps || 0
+      } else {
+        const errMsg = result.error || '未知错误'
+        const timeStr = new Date().toISOString().replace('T', ' ').slice(0, 19)
+        await logMessage(`[try 失败] ${timeStr} ${errMsg}`, folderPath).catch(() => {})
+        if (failActions.length > 0) {
+          const failResult = await executeActionSequence(failActions, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
+          if (!failResult.success) return failResult
+          completedSteps += (result.completedSteps || 0) + (failResult.completedSteps || 0)
+        } else {
+          return result
+        }
+      }
+      continue
+    }
+
     const times = action.times || 1
     if (onStepComplete) onStepComplete(i + 1, actions.length, getActionName(action), 0, times, 0)
 
@@ -123,11 +177,10 @@ async function executeActionSequence(
 
       state.globalStepCounter++
       const typeName = getActionName(action)
-      await logMessage(`[步骤] 开始: ${typeName}`, folderPath).catch(() => {})
 
       const result = await executeAction(action, device, folderPath, resolution)
 
-      if (result.success && result.skipped) await logMessage(`[提示] 步骤已跳过(条件不满足): ${typeName}`, folderPath).catch(() => {})
+      if (result.success && result.skipped) { /* 步骤跳过不写 log */ }
 
       if (!result.success) {
         const now = new Date()

+ 3 - 0
nodejs/ef-compiler/components/workflow-json-parser.js

@@ -17,6 +17,7 @@ const actionModules = [
   require('./actions/if-parser.js'),
   require('./actions/for-parser.js'),
   require('./actions/while-parser.js'),
+  require('./actions/try-parser.js'),
   require('./actions/fun-parser.js'),
 ]
 
@@ -75,6 +76,7 @@ function getActionName(action) {
     'if': '条件判断',
     'for': '循环',
     'while': '循环',
+    'try': '异常捕获',
     'delay': '延迟',
     'set': '设置变量',
     'random': '生成随机数',
@@ -99,6 +101,7 @@ function getActionName(action) {
   }
   if (action.type === 'if') return `${typeName}: ${action.condition || ''}`
   if (action.type === 'for') return `${typeName}: ${action.variable || ''}`
+  if (action.type === 'try') return typeName
   if (action.type === 'set') return `${typeName}: ${action.variable || ''}`
   if (action.type === 'fun') return `${typeName}: ${displayValue}`
   return `${typeName}: ${displayValue}`

+ 1 - 0
nodejs/ef-compiler/ef-compiler.js

@@ -123,6 +123,7 @@ async function executeActionSequence(actions, device, folderPath, resolution, st
     getActionName,
     parseDelayString,
     calculateWaitTime,
+    replaceVariablesInString,
     state,
     DEFAULT_STEP_INTERVAL,
   }

+ 1 - 4
nodejs/run-process.js

@@ -36,7 +36,6 @@ function appendLog(text) {
 function logLine(msg) {
   const line = `[${new Date().toISOString()}] ${msg}\n`
   process.stdout.write(line)
-  appendLog(line)
 }
 const { parseWorkflow } = require('./ef-compiler/ef-compiler.js')
 const actions = parseWorkflow(JSON.parse(fs.readFileSync(path.join(folderPath, 'process.json'), 'utf8'))).actions
@@ -69,9 +68,8 @@ async function ensureDeviceConnected(ip, port, logLineFn) {
   return false
 }
 
-/** 启动执行:遍历 ip 列表并异步执行脚本;任一台失败则停止全部并返回失败设备 IP */
+/** 启动执行:遍历 ip 列表并异步执行脚本;任一台失败则停止全部并返回失败设备 IP;log.txt 仅写入报错与带 log:true 的 echo */
 async function start() {
-  appendLog(`\n========== Run ${new Date().toISOString()} ==========\n`)
   logLine(`Process "${scriptName}" start, devices: ${ipList.length}`)
   let failedIp = null
   const runOne = async (ip) => {
@@ -100,7 +98,6 @@ async function start() {
   logLine(failedIp ? `Process finished with failed device: ${failedIp}` : 'Process finished successfully.')
   const resultLine = JSON.stringify(output) + '\n'
   process.stdout.write(resultLine)
-  appendLog(resultLine)
   process.exit(failedIp ? 1 : 0)
 }
 

+ 1 - 2
static/device_list.json

@@ -1,6 +1,5 @@
 {
   "devices": [
-    "192.168.0.101",
-    "10.103.239.139"
+    "192.168.0.107"
   ]
 }

+ 27 - 16
static/process/RedNoteAIThumbsUp/process.json

@@ -1,20 +1,31 @@
 {
-	"name": "RedNoteAIThumbsUp",
-    	"description": "小红书自动点赞",
-	"variables": {
-		"sendBtnPos": ""
-	},
-	"execute": [
-		{
+  "name": "RedNoteAIThumbsUp",
+  "description": "小红书自动点赞",
+  "variables": { "sendBtnPos": "" },
+  "execute": [
+    {
+      "type": "try",
+      "try": 
+	  [
+        {
+          "type": "img-center-point-location",
+          "inVars": ["视频点赞.png"],
+          "outVars": ["{sendBtnPos}"]
+        }
+      ],
+      "catch": 
+	  [
+        {
 			"type": "img-center-point-location",
-			"inVars": ["点赞按钮_未点赞.png"],
+			"inVars": ["图文点赞.png"],
 			"outVars": ["{sendBtnPos}"]
-		},
-		{
-			
-			"type": "adb",
-			"method": "click",
-			"inVars": ["{sendBtnPos}"]
-		}		
-	]
+		  }
+      ]
+    },
+    { 
+		"type": "adb", 
+		"method": "click", 
+		"inVars": ["{sendBtnPos}"] 
+	}
+  ]
 }

BIN
static/process/RedNoteAIThumbsUp/resources/图文点赞.png


BIN
static/process/RedNoteAIThumbsUp/resources/点赞按钮_已点赞.png


BIN
static/process/RedNoteAIThumbsUp/resources/点赞按钮_未点赞2.png


+ 0 - 0
static/process/RedNoteAIThumbsUp/resources/点赞按钮_未点赞.png → static/process/RedNoteAIThumbsUp/resources/视频点赞.png


+ 72 - 38
static/process/RedNoteBrowsingAndThumbsUp/process.json

@@ -11,15 +11,12 @@
 		"stay-duration":0,
 		"send-btn-pos": ""
 	},
-	"execute": [
+	"execute": 
+	[
 		{
-			"type": "schedule",
-			"condition": 
-			{
-				"interval": "1s",
-				"repeat": -1
-			},
-			"interval": 
+			"type": "while",
+			"condition": "1",
+			"body": 
 			[
 				{
 					"type": "random",
@@ -30,23 +27,22 @@
 					"type": "schedule",
 					"condition": 
 					{
-						"interval": "1s",
+						"interval": "7s",
 						"repeat": "{swipeCount}"
 					},
 					"interval": 
 					[
 						{
-					
 							"type": "adb",
 							"method": "swipe",
-							"inVars": ["down-up"],
+							"inVars": ["up-down"],
 							"outVars": []
 						}
 					]
 				},
 				{
 					"type": "random",
-					"inVars": ["200", "880"],
+					"inVars": ["200", "780"],
 					"outVars": ["{clickX}"]
 				},
 				{
@@ -71,40 +67,78 @@
 					"outVars": ["{stay-duration}"]
 				},
 				{
-					"type": "delay",
-					"value": "{{stay-duration}}m"
-				},
-				{
-					"type": "random",
-					"inVars": [0, 1],
-					"outVars": ["{b-like-click}"]
-				},
-				{
-					"type": "if",
-					"condition": "{b-like-click} == 1",
-					"ture": 
+					"type": "try",
+					"try": 
 					[
 						{
 							"type": "img-center-point-location",
-							"inVars": ["点赞按钮_未点赞.png"],
+							"inVars": ["视频点赞.png"],
 							"outVars": ["{send-btn-pos}"]
+						}
+					],
+					"success": 
+					[
+						{
+							"type": "random",
+							"inVars": ["2", "10"],
+							"outVars": ["{swipeCount}"]
 						},
 						{
-							"type": "adb",
-							"method": "click",
-							"inVars": ["{send-btn-pos}"]
+							"type": "for",
+							"times": "{swipeCount}",
+							"variable": "{i}",
+							"body": 
+							[
+								{
+									"type": "random",
+									"inVars": [5,30],
+									"outVars": ["{stay-duration}"]
+								},
+								{
+									"type": "delay",
+									"value": "{{stay-duration}}s"
+								},
+								{
+									"type": "adb",
+									"method": "swipe",
+									"inVars": ["down-up"],
+									"outVars": []
+								},
+								{
+									"type": "if",
+									"condition": "{stay-duration} > 25",
+									"ture": 
+									[
+										{
+											"type": "random",
+											"inVars": [0, 1],
+											"outVars": ["{b-like-click}"]
+										},
+										{
+											"type": "if",
+											"condition": "{b-like-click} == 1",
+											"ture": 
+											[
+												{
+													"type": "adb",
+													"method": "click",
+													"inVars": ["{send-btn-pos}"]
+												}
+											]
+										}
+									]
+								}	
+							]
+						}
+					],
+					"fail": 
+					[
+						{
+							"type": "echo",
+							"value": "点赞图标匹配失败"
 						}
 					]
-				},
-				{
-					"type": "random",
-					"inVars": [5, 12],
-					"outVars": ["{back-duration}"]
-				},
-				{
-					"type": "delay",
-					"value": "{{back-duration}}s"
-				},
+			    },
 				{
 					"type": "adb",
 					"method": "keyevent",

BIN
static/process/RedNoteBrowsingAndThumbsUp/resources/图文点赞.png


BIN
static/process/RedNoteBrowsingAndThumbsUp/resources/点赞按钮_已点赞.png


BIN
static/process/RedNoteBrowsingAndThumbsUp/resources/点赞按钮_未点赞2.png


+ 0 - 0
static/process/RedNoteBrowsingAndThumbsUp/resources/点赞按钮_未点赞.png → static/process/RedNoteBrowsingAndThumbsUp/resources/视频点赞.png


+ 200 - 0
static/process/RedNoteBrowsingAndThumbsUpTest/bp.json

@@ -0,0 +1,200 @@
+{
+	"nodePositions": {
+		"node_begin_1768681618551": {
+			"x": 150,
+			"y": 100
+		},
+		"node_0": {
+			"x": 150,
+			"y": 300
+		},
+		"node_1": {
+			"x": 470,
+			"y": 100
+		},
+		"node_2": {
+			"x": 470,
+			"y": 300
+		},
+		"node_3": {
+			"x": 470,
+			"y": 500
+		},
+		"node_4": {
+			"x": 470,
+			"y": 700
+		},
+		"node_5": {
+			"x": 470,
+			"y": 900
+		},
+		"node_6": {
+			"x": 470,
+			"y": 1100
+		},
+		"node_7": {
+			"x": 470,
+			"y": 1300
+		},
+		"node_8": {
+			"x": 470,
+			"y": 1500
+		},
+		"node_9": {
+			"x": 470,
+			"y": 1700
+		},
+		"node_10": {
+			"x": 150,
+			"y": 1900
+		},
+		"node_11": {
+			"x": 790,
+			"y": 100
+		},
+		"node_12": {
+			"x": 790,
+			"y": 300
+		},
+		"node_13": {
+			"x": 150,
+			"y": 2100
+		},
+		"node_14": {
+			"x": 150,
+			"y": 2300
+		},
+		"node_15": {
+			"x": 150,
+			"y": 2500
+		},
+		"node_16": {
+			"x": 150,
+			"y": 2700
+		},
+		"node_17": {
+			"x": 150,
+			"y": 2900
+		},
+		"node_18": {
+			"x": 150,
+			"y": 3100
+		},
+		"node_19": {
+			"x": 150,
+			"y": 3300
+		},
+		"node_20": {
+			"x": 150,
+			"y": 500
+		},
+		"node_21": {
+			"x": 150,
+			"y": 700
+		},
+		"node_22": {
+			"x": 150,
+			"y": 900
+		},
+		"node_23": {
+			"x": 1110,
+			"y": 100
+		},
+		"node_24": {
+			"x": 1110,
+			"y": 300
+		},
+		"node_25": {
+			"x": 1430,
+			"y": 100
+		},
+		"node_26": {
+			"x": 1430,
+			"y": 300
+		},
+		"node_27": {
+			"x": 790,
+			"y": 500
+		},
+		"node_28": {
+			"x": 790,
+			"y": 700
+		},
+		"node_29": {
+			"x": 790,
+			"y": 900
+		},
+		"node_30": {
+			"x": 150,
+			"y": 1100
+		},
+		"node_31": {
+			"x": 150,
+			"y": 1300
+		},
+		"node_32": {
+			"x": 150,
+			"y": 1500
+		},
+		"node_33": {
+			"x": 150,
+			"y": 1700
+		},
+		"var_turn_1768681618551": {
+			"x": 50,
+			"y": 200
+		},
+		"var_relationBg_1768681618551": {
+			"x": 50,
+			"y": 320
+		},
+		"var_chatArea_1768681618551": {
+			"x": 50,
+			"y": 440
+		},
+		"var_chatHistoryMessage_1768681618551": {
+			"x": 50,
+			"y": 560
+		},
+		"var_currentChatMessage_1768681618551": {
+			"x": 50,
+			"y": 680
+		},
+		"var_lastHistoryMessage_1768681618551": {
+			"x": 50,
+			"y": 800
+		},
+		"var_lastChatMessage_1768681618551": {
+			"x": 50,
+			"y": 920
+		},
+		"var_lastChatRole_1768681618551": {
+			"x": 50,
+			"y": 1040
+		},
+		"var_lastHistoryChatMessage_1768681618551": {
+			"x": 50,
+			"y": 1160
+		},
+		"var_lastHistoryChatRole_1768681618551": {
+			"x": 50,
+			"y": 1280
+		},
+		"var_aiReply_1768681618551": {
+			"x": 50,
+			"y": 1400
+		},
+		"var_aiCallBack_1768681618551": {
+			"x": 50,
+			"y": 1520
+		},
+		"var_sendBtnPos_1768681618551": {
+			"x": 50,
+			"y": 1640
+		},
+		"var_newChatMessage_1768681618551": {
+			"x": 50,
+			"y": 1760
+		}
+	}
+}

+ 131 - 0
static/process/RedNoteBrowsingAndThumbsUpTest/process.json

@@ -0,0 +1,131 @@
+{
+	"name": "RedNoteBrowsingAndThumbsUpTest",
+        "description": "测试版小红书随机浏览和点赞",
+	"variables": {
+		"page-index":0,
+		"up-or-down":0,
+		"swipe-count":0,
+		"click-x":0,
+		"click-y":0,
+		"random-click-pos":"",
+		"stay-duration":0,
+		"send-btn-pos": ""
+	},
+	"execute": [
+		{
+			"type": "schedule",
+			"condition": 
+			{
+				"interval": "1s",
+				"repeat": -1
+			},
+			"interval": 
+			[
+				{
+					"type": "random",
+					"inVars": ["1", "3"],
+					"outVars": ["{swipeCount}"]
+				},
+				{
+					"type": "schedule",
+					"condition": 
+					{
+						"interval": "1s",
+						"repeat": "{swipeCount}"
+					},
+					"interval": 
+					[
+						{
+					
+							"type": "adb",
+							"method": "swipe",
+							"inVars": ["down-up"],
+							"outVars": []
+						}
+					]
+				},
+				{
+					"type": "random",
+					"inVars": ["200", "880"],
+					"outVars": ["{clickX}"]
+				},
+				{
+					"type": "random",
+					"inVars": ["400", "2000"],
+					"outVars": ["{clickY}"]
+				},
+				{
+					"type": "set",
+					"variable": "{random-click-pos}",
+					"value": "{clickX},{clickY}"
+				},
+				{
+					
+					"type": "adb",
+					"method": "click",
+					"inVars": ["{random-click-pos}"]
+				},
+				{
+					"type": "random",
+					"inVars": [10, 2000],
+					"outVars": ["{stay-duration}"]
+				},
+				{
+					"type": "delay",
+					"value": "{{stay-duration}}m"
+				},
+				{
+					"type": "random",
+					"inVars": [0, 1],
+					"outVars": ["{b-like-click}"]
+				},
+				{
+					"type": "if",
+					"condition": "{b-like-click} == 1",
+					"ture": 
+					[
+						{
+							"type": "try",
+							"try": 
+							[
+								{
+									"type": "img-center-point-location",
+									"inVars": ["视频点赞.png"],
+									"outVars": ["{send-btn-pos}"]
+								}
+							],
+							"catch": 
+							[
+								{
+									"type": "img-center-point-location",
+									"inVars": ["图文点赞.png"],
+									"outVars": ["{send-btn-pos}"]
+								}
+							]
+						},
+						{
+							"type": "adb",
+							"method": "click",
+							"inVars": ["{send-btn-pos}"]
+						}
+					]
+				},
+				{
+					"type": "random",
+					"inVars": [5, 12],
+					"outVars": ["{back-duration}"]
+				},
+				{
+					"type": "delay",
+					"value": "{{back-duration}}s"
+				},
+				{
+					"type": "adb",
+					"method": "keyevent",
+					"inVars": ["4"],
+					"outVars": []
+				}
+			]
+		}		
+	]
+}

+ 3 - 0
static/process/RedNoteBrowsingAndThumbsUpTest/readme.md

@@ -0,0 +1,3 @@
+# WeChatChating
+
+用于微信聊天机器人

BIN
static/process/RedNoteBrowsingAndThumbsUpTest/resources/图文点赞.png


BIN
static/process/RedNoteBrowsingAndThumbsUpTest/resources/视频点赞.png