screenshot.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. let projectRoot = path.resolve(__dirname, '..', '..')
  7. if (projectRoot.includes('app.asar') && !projectRoot.includes('app.asar.unpacked')) {
  8. projectRoot = projectRoot.replace('app.asar', 'app.asar.unpacked')
  9. }
  10. const adbPath = path.resolve(projectRoot, config.adbPath.path)
  11. const scrcpyDir = path.dirname(adbPath)
  12. const scrcpyPath = path.join(scrcpyDir, 'scrcpy.exe')
  13. const staticRoot = process.env.STATIC_ROOT ? path.resolve(process.env.STATIC_ROOT) : path.join(projectRoot, 'static')
  14. const pidFile = path.join(staticRoot, 'scrcpy-pid.json')
  15. const action = process.argv[2]
  16. const pidArg = process.argv[3]
  17. /** 终止指定 PID 的进程 */
  18. function killPidIfRunning(pid) {
  19. spawn('taskkill.exe', ['/F', '/PID', pid.toString()], {
  20. stdio: 'ignore',
  21. detached: true
  22. }).unref()
  23. }
  24. /** 从 tasklist 获取 scrcpy.exe 的 PID(用 bat start 启动后需轮询得到 pid) */
  25. function getScrcpyPid() {
  26. const output = execSync('tasklist /FI "IMAGENAME eq scrcpy.exe" /FO CSV', { encoding: 'utf-8' })
  27. const lines = output.split('\n').filter(line => line.includes('scrcpy.exe'))
  28. if (lines.length === 0) return null
  29. const pidMatch = lines[0].match(/"(\d+)"/)
  30. return pidMatch ? parseInt(pidMatch[1]) : null
  31. }
  32. /** 判断是否为 IP(或 IP:port),用于无线设备选择器 */
  33. function isDeviceIp(val) {
  34. return val && !/^\d+$/.test(val) && /[\d.]/.test(val)
  35. }
  36. /** 根据传入的 IP 得到 adb/scrcpy 设备选择器,无线默认 5555 */
  37. function toDeviceSelector(ipOrSelector) {
  38. return ipOrSelector.includes(':') ? ipOrSelector : `${ipOrSelector}:5555`
  39. }
  40. /** 启动 scrcpy:先 adb connect(若有 IP),再用 scrcpy-noconsole.bat(start "" scrcpy.exe %*)无控制台启动 */
  41. function startScrcpy() {
  42. if (fs.existsSync(pidFile)) {
  43. const { pid } = JSON.parse(fs.readFileSync(pidFile, 'utf-8'))
  44. killPidIfRunning(pid)
  45. }
  46. let deviceSelector = ''
  47. if (isDeviceIp(pidArg)) {
  48. deviceSelector = toDeviceSelector(pidArg)
  49. execSync(`"${adbPath}" connect ${deviceSelector}`, { encoding: 'utf-8', cwd: scrcpyDir })
  50. }
  51. const serial = deviceSelector || (pidArg && !/^\d+$/.test(pidArg) ? pidArg : '')
  52. const args = serial
  53. ? ['--pause-on-exit=if-error', '-s', serial]
  54. : ['-e', '--pause-on-exit=if-error']
  55. const argsStr = args.join(' ')
  56. const vbsPath = path.join(scrcpyDir, 'scrcpy-noconsole.vbs')
  57. execSync(`wscript "${vbsPath.replace(/"/g, '""')}" ${argsStr}`, { cwd: scrcpyDir })
  58. const sleep = (ms) => { const t = Date.now(); while (Date.now() - t < ms) {} }
  59. sleep(1500)
  60. const runningPid = getScrcpyPid()
  61. if (!runningPid) {
  62. console.log(JSON.stringify({ success: false, error: 'scrcpy did not appear in tasklist' }))
  63. process.exit(1)
  64. }
  65. fs.writeFileSync(pidFile, JSON.stringify({ pid: runningPid }), 'utf-8')
  66. console.log(JSON.stringify({ success: true, pid: runningPid }))
  67. process.exit(0)
  68. }
  69. /** 停止 scrcpy:有 pid 则 taskkill 并删文件,返回 action: 'stop';无 pid 文件返回 action: 'none',供前端区分是否继续执行 start */
  70. function stopScrcpy() {
  71. if (!fs.existsSync(pidFile)) {
  72. console.log(JSON.stringify({ success: true, action: 'none' }))
  73. process.exit(0)
  74. return
  75. }
  76. const pid = JSON.parse(fs.readFileSync(pidFile, 'utf-8')).pid
  77. killPidIfRunning(pid)
  78. fs.unlinkSync(pidFile)
  79. console.log(JSON.stringify({ success: true, action: 'stop' }))
  80. process.exit(0)
  81. }
  82. switch (action) {
  83. case 'start':
  84. startScrcpy()
  85. break
  86. case 'stop':
  87. stopScrcpy()
  88. break
  89. default:
  90. console.log(JSON.stringify({
  91. success: false,
  92. error: 'Usage: node screenshot.js [start|stop] [pid|deviceIp]'
  93. }))
  94. process.exit(1)
  95. }