screenshot.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. const { spawn } = require('child_process')
  2. const { execSync } = require('child_process')
  3. const path = require('path')
  4. const fs = require('fs')
  5. const config = require(path.join(__dirname, '..', '..', 'configs', 'config.js'))
  6. const projectRoot = path.resolve(__dirname, '..', '..')
  7. const adbPath = path.resolve(projectRoot, config.adbPath.path)
  8. const scrcpyDir = path.dirname(adbPath)
  9. const scrcpyPath = path.join(scrcpyDir, 'scrcpy.exe')
  10. const scrcpyVbs = path.join(scrcpyDir, 'scrcpy-noconsole.vbs')
  11. const stopBat = path.join(scrcpyDir, 'stop.bat')
  12. const pidFile = path.join(projectRoot, 'static', 'scrcpy-pid.json')
  13. const action = process.argv[2]
  14. const pidArg = process.argv[3]
  15. // 获取 scrcpy 进程 PID
  16. function getScrcpyPid() {
  17. const output = execSync(`tasklist /FI "IMAGENAME eq scrcpy.exe" /FO CSV`, { encoding: 'utf-8' })
  18. const lines = output.split('\n').filter(line => line.includes('scrcpy.exe'))
  19. if (lines.length === 0) {
  20. return null
  21. }
  22. const pidMatch = lines[0].match(/"(\d+)"/)
  23. if (!pidMatch) {
  24. return null
  25. }
  26. return parseInt(pidMatch[1])
  27. }
  28. // 检查并终止指定 PID 的进程
  29. function killPidIfRunning(pid) {
  30. spawn('taskkill.exe', ['/F', '/PID', pid.toString()], {
  31. stdio: 'ignore',
  32. detached: true
  33. }).unref()
  34. }
  35. /** 判断是否为 IP(或 IP:port),用于无线设备选择器 */
  36. function isDeviceIp(val) {
  37. return val && !/^\d+$/.test(val) && /[\d.]/.test(val)
  38. }
  39. /** 根据传入的 IP 得到 adb/scrcpy 设备选择器,无线默认 5555 */
  40. function toDeviceSelector(ipOrSelector) {
  41. return ipOrSelector.includes(':') ? ipOrSelector : `${ipOrSelector}:5555`
  42. }
  43. // 启动 scrcpy:若传入 IP 则先 adb connect 再以该设备启动 lib/scrcpy-adb/scrcpy-noconsole.vbs
  44. function startScrcpy() {
  45. const targetPid = pidArg && /^\d+$/.test(pidArg) ? parseInt(pidArg) : 7788
  46. killPidIfRunning(targetPid)
  47. let deviceSelector = ''
  48. if (isDeviceIp(pidArg)) {
  49. deviceSelector = toDeviceSelector(pidArg)
  50. execSync(`"${adbPath}" connect ${deviceSelector}`, { encoding: 'utf-8', cwd: scrcpyDir })
  51. }
  52. const vbsArgs = deviceSelector ? ` "${deviceSelector}"` : (pidArg && !/^\d+$/.test(pidArg) ? ` "${pidArg}"` : '')
  53. execSync(`wscript.exe "${scrcpyVbs}"${vbsArgs}`, {
  54. cwd: scrcpyDir,
  55. stdio: 'ignore'
  56. })
  57. const sleep = (ms) => {
  58. const start = Date.now()
  59. while (Date.now() - start < ms) {}
  60. }
  61. sleep(2000)
  62. const runningPid = getScrcpyPid()
  63. if (!runningPid) {
  64. console.log(JSON.stringify({
  65. success: false,
  66. error: 'Failed to start scrcpy'
  67. }))
  68. process.exit(1)
  69. return
  70. }
  71. fs.writeFileSync(pidFile, JSON.stringify({ pid: runningPid }), 'utf-8')
  72. console.log(JSON.stringify({
  73. success: true,
  74. pid: runningPid
  75. }))
  76. process.exit(0)
  77. }
  78. // 停止 scrcpy
  79. function stopScrcpy() {
  80. const pid = JSON.parse(fs.readFileSync(pidFile, 'utf-8')).pid
  81. execSync(`"${stopBat}" ${pid}`, { stdio: 'ignore', cwd: scrcpyDir })
  82. fs.unlinkSync(pidFile)
  83. console.log(JSON.stringify({
  84. success: true
  85. }))
  86. process.exit(0)
  87. }
  88. switch (action) {
  89. case 'start':
  90. startScrcpy()
  91. break
  92. case 'stop':
  93. stopScrcpy()
  94. break
  95. default:
  96. console.log(JSON.stringify({
  97. success: false,
  98. error: 'Usage: node screenshot.js [start|stop] [pid|deviceIp]'
  99. }))
  100. process.exit(1)
  101. }