README.md
· 699 B · Markdown
Orginalformat
# Windows录屏脚本
Windows 中使用 PowerShell 进行录屏的脚本,只在用户活动的时(鼠标点击或移动或敲打键盘)才进行录制
## 准备
- 安装 `ffmpeg` 用来将截屏的png转换为视频.
## 用法
1. 用powsershell执行 `screenshot.ps1` 开始截屏生成png文件.
2. 停止powershell,执行 `make.cmd` 开始导出视频.
3. `generate-input-list.py` 可选的python脚本用来重新生成`duration.txt`当你删除了部分png文件时.
## 说明
- `duration.txt` 是给`ffmpeg`合成视频时用的时间轴文件,里面指明了每个png图片的播放时长。如果删除了部分png图片,需要使用`generate-input-list.py`来重新生成它
Windows录屏脚本
Windows 中使用 PowerShell 进行录屏的脚本,只在用户活动的时(鼠标点击或移动或敲打键盘)才进行录制
准备
- 安装
ffmpeg
用来将截屏的png转换为视频.
用法
- 用powsershell执行
screenshot.ps1
开始截屏生成png文件. - 停止powershell,执行
make.cmd
开始导出视频. generate-input-list.py
可选的python脚本用来重新生成duration.txt
当你删除了部分png文件时.
说明
duration.txt
是给ffmpeg
合成视频时用的时间轴文件,里面指明了每个png图片的播放时长。如果删除了部分png图片,需要使用generate-input-list.py
来重新生成它
generate-input-list.py
· 919 B · Python
Orginalformat
import os
from datetime import datetime
time_format = '%Y%m%d_%H%M%S%f'
# 获取当前目录下所有的png文件名,无扩展名
png_files = [f.split('.')[0] for f in os.listdir('./shots') if f.endswith('.png')]
# 解析文件名并排序
sorted_files = sorted(png_files, key=lambda x: datetime.strptime(x, time_format))
# 计算时间间隔并生成输入文件
with open('./shots/duration.txt', 'w') as f:
for i in range(len(sorted_files)):
current_file = sorted_files[i]
current_time = datetime.strptime(current_file, time_format)
if i != 0:
prev_file = sorted_files[i-1]
prev_time = datetime.strptime(prev_file, time_format)
duration = (current_time - prev_time).total_seconds()
f.write(f"duration {duration}\n")
f.write(f"file '{current_file}.png'\n")
print("输入文件列表已生成为 duration.txt")
1 | import os |
2 | from datetime import datetime |
3 | |
4 | time_format = '%Y%m%d_%H%M%S%f' |
5 | |
6 | # 获取当前目录下所有的png文件名,无扩展名 |
7 | png_files = [f.split('.')[0] for f in os.listdir('./shots') if f.endswith('.png')] |
8 | |
9 | # 解析文件名并排序 |
10 | sorted_files = sorted(png_files, key=lambda x: datetime.strptime(x, time_format)) |
11 | |
12 | # 计算时间间隔并生成输入文件 |
13 | with open('./shots/duration.txt', 'w') as f: |
14 | for i in range(len(sorted_files)): |
15 | current_file = sorted_files[i] |
16 | current_time = datetime.strptime(current_file, time_format) |
17 | |
18 | if i != 0: |
19 | prev_file = sorted_files[i-1] |
20 | prev_time = datetime.strptime(prev_file, time_format) |
21 | duration = (current_time - prev_time).total_seconds() |
22 | f.write(f"duration {duration}\n") |
23 | |
24 | f.write(f"file '{current_file}.png'\n") |
25 | |
26 | print("输入文件列表已生成为 duration.txt") |
make.cmd
· 86 B · Batchfile
Orginalformat
ffmpeg -f concat -i ./shots/duration.txt -pix_fmt yuv420p -c:v libx264 -r 5 output.mp4
1 | ffmpeg -f concat -i ./shots/duration.txt -pix_fmt yuv420p -c:v libx264 -r 5 output.mp4 |
screenshot.ps1
· 4.2 KiB · PowerShell
Orginalformat
# 定义保存截图的文件夹路径为当前脚本所在目录下的shots文件夹
$folderPath = Join-Path -Path $PSScriptRoot -ChildPath "shots"
if (-not (Test-Path -Path $folderPath)) {
New-Item -ItemType Directory -Path $folderPath
}
# 导入用户32.dll,用于检测鼠标键盘活动
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class UserActivity {
[DllImport("user32.dll")]
public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[StructLayout(LayoutKind.Sequential)]
public struct LASTINPUTINFO {
public uint cbSize;
public uint dwTime;
}
}
"@
# 检测用户是否活跃
function IsUserActive {
$lastInput = New-Object UserActivity+LASTINPUTINFO
$lastInput.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($lastInput)
if ([UserActivity]::GetLastInputInfo([ref]$lastInput)) {
$idleTime = [Math]::Floor([TimeSpan]::FromMilliseconds([Environment]::TickCount - $lastInput.dwTime).TotalSeconds)
# 如果空闲时间小于5秒,认为用户是活跃的
return ($idleTime -lt 1)
}
return $false
}
$durationTxt = Join-Path -Path $folderPath -ChildPath "duration.txt"
$fileMatches = if (Test-Path -Path $durationTxt) { (Get-Content -Path $durationTxt -Tail 3 | Select-String -Pattern "^file '(.*\.png)'$").Matches } else { @() }
$script:lastScreenshotFile = if ($fileMatches.Count -gt 0) { $fileMatches[0].Groups[1].Value } else { "" }
# Write-Host "lastScreenshotFile: $lastScreenshotFile"
$script:isFirstRun = $true
$script:lastScreenshotTime = if ($script:lastScreenshotFile -ne "") { [DateTime]::ParseExact($script:lastScreenshotFile.Substring(0, 18), "yyyyMMdd_HHmmssfff", $null) } else { [DateTime]::MinValue }
# 截屏函数
function TakeScreenshot {
$now = Get-Date
$timestamp = $now.ToString("yyyyMMdd_HHmmssfff")
$filePath = Join-Path -Path $folderPath -ChildPath "$timestamp.png"
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$bitmap = New-Object System.Drawing.Bitmap([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width, [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height)
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
# Capture the screen
$graphics.CopyFromScreen(0, 0, 0, 0, $bitmap.Size)
# Draw the cursor
$cursorPosition = [System.Windows.Forms.Cursor]::Position
$cursorRectangle = New-Object System.Drawing.Rectangle($cursorPosition, [System.Drawing.Size]::new(32, 32)) # Adjust size if needed
# [System.Windows.Forms.Cursor]::Current.Draw($graphics, $cursorRectangle)
[System.Windows.Forms.Cursors]::Arrow.Draw($graphics, $cursorRectangle)
$bitmap.Save($filePath, [System.Drawing.Imaging.ImageFormat]::Png)
# Add filename to duration.txt
if ($script:lastScreenshotFile -ne "") {
$duration = ([TimeSpan]::FromTicks(($now - $script:lastScreenshotTime).Ticks)).TotalSeconds
$durationStr = "duration {0:F3}" -f $duration
if ($script:isFirstRun) {
$lastDuration = Get-Content -Path $durationTxt -Tail 1 | Select-String -Pattern "^duration [\d\.]+$"
if ($lastDuration) {
# remove last line
$lines = Get-Content -Path $durationTxt
$lines = $lines[0..($lines.Length - 2)]
$lines += $durationStr
$lines | Set-Content -Path $durationTxt
} else {
Add-Content -Path $durationTxt -Value $durationStr
}
$script:isFirstRun = $false
} else {
Add-Content -Path $durationTxt -Value $durationStr
}
}
Add-Content -Path $durationTxt -Value "file '$timestamp.png'"
Write-Host "Screenshot saved: $timestamp.png"
[console]::beep(1000, 500) # 播放提示音
$script:lastScreenshotTime = $now
$script:lastScreenshotFile = "$timestamp.png"
}
# Delay 3 seconds to start
Start-Sleep -Seconds 3
# 主循环
while ($true) {
try {
if (IsUserActive) {
TakeScreenshot
}
Start-Sleep -Seconds 1
} catch {
Write-Host "An error occurred: $_"
Start-Sleep -Seconds 5 # 出错时等待5秒再继续
}
}
1 | # 定义保存截图的文件夹路径为当前脚本所在目录下的shots文件夹 |
2 | $folderPath = Join-Path -Path $PSScriptRoot -ChildPath "shots" |
3 | if (-not (Test-Path -Path $folderPath)) { |
4 | New-Item -ItemType Directory -Path $folderPath |
5 | } |
6 | |
7 | # 导入用户32.dll,用于检测鼠标键盘活动 |
8 | Add-Type @" |
9 | using System; |
10 | using System.Runtime.InteropServices; |
11 | public class UserActivity { |
12 | [DllImport("user32.dll")] |
13 | public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); |
14 | |
15 | [StructLayout(LayoutKind.Sequential)] |
16 | public struct LASTINPUTINFO { |
17 | public uint cbSize; |
18 | public uint dwTime; |
19 | } |
20 | } |
21 | "@ |
22 | |
23 | # 检测用户是否活跃 |
24 | function IsUserActive { |
25 | $lastInput = New-Object UserActivity+LASTINPUTINFO |
26 | $lastInput.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($lastInput) |
27 | |
28 | if ([UserActivity]::GetLastInputInfo([ref]$lastInput)) { |
29 | $idleTime = [Math]::Floor([TimeSpan]::FromMilliseconds([Environment]::TickCount - $lastInput.dwTime).TotalSeconds) |
30 | # 如果空闲时间小于5秒,认为用户是活跃的 |
31 | return ($idleTime -lt 1) |
32 | } |
33 | return $false |
34 | } |
35 | |
36 | $durationTxt = Join-Path -Path $folderPath -ChildPath "duration.txt" |
37 | $fileMatches = if (Test-Path -Path $durationTxt) { (Get-Content -Path $durationTxt -Tail 3 | Select-String -Pattern "^file '(.*\.png)'$").Matches } else { @() } |
38 | $script:lastScreenshotFile = if ($fileMatches.Count -gt 0) { $fileMatches[0].Groups[1].Value } else { "" } |
39 | # Write-Host "lastScreenshotFile: $lastScreenshotFile" |
40 | $script:isFirstRun = $true |
41 | $script:lastScreenshotTime = if ($script:lastScreenshotFile -ne "") { [DateTime]::ParseExact($script:lastScreenshotFile.Substring(0, 18), "yyyyMMdd_HHmmssfff", $null) } else { [DateTime]::MinValue } |
42 | |
43 | # 截屏函数 |
44 | function TakeScreenshot { |
45 | $now = Get-Date |
46 | $timestamp = $now.ToString("yyyyMMdd_HHmmssfff") |
47 | $filePath = Join-Path -Path $folderPath -ChildPath "$timestamp.png" |
48 | |
49 | Add-Type -AssemblyName System.Windows.Forms |
50 | Add-Type -AssemblyName System.Drawing |
51 | $bitmap = New-Object System.Drawing.Bitmap([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width, [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height) |
52 | $graphics = [System.Drawing.Graphics]::FromImage($bitmap) |
53 | # Capture the screen |
54 | $graphics.CopyFromScreen(0, 0, 0, 0, $bitmap.Size) |
55 | |
56 | # Draw the cursor |
57 | $cursorPosition = [System.Windows.Forms.Cursor]::Position |
58 | $cursorRectangle = New-Object System.Drawing.Rectangle($cursorPosition, [System.Drawing.Size]::new(32, 32)) # Adjust size if needed |
59 | # [System.Windows.Forms.Cursor]::Current.Draw($graphics, $cursorRectangle) |
60 | [System.Windows.Forms.Cursors]::Arrow.Draw($graphics, $cursorRectangle) |
61 | |
62 | $bitmap.Save($filePath, [System.Drawing.Imaging.ImageFormat]::Png) |
63 | |
64 | # Add filename to duration.txt |
65 | if ($script:lastScreenshotFile -ne "") { |
66 | $duration = ([TimeSpan]::FromTicks(($now - $script:lastScreenshotTime).Ticks)).TotalSeconds |
67 | $durationStr = "duration {0:F3}" -f $duration |
68 | if ($script:isFirstRun) { |
69 | $lastDuration = Get-Content -Path $durationTxt -Tail 1 | Select-String -Pattern "^duration [\d\.]+$" |
70 | if ($lastDuration) { |
71 | # remove last line |
72 | $lines = Get-Content -Path $durationTxt |
73 | $lines = $lines[0..($lines.Length - 2)] |
74 | $lines += $durationStr |
75 | $lines | Set-Content -Path $durationTxt |
76 | } else { |
77 | Add-Content -Path $durationTxt -Value $durationStr |
78 | } |
79 | $script:isFirstRun = $false |
80 | } else { |
81 | Add-Content -Path $durationTxt -Value $durationStr |
82 | } |
83 | } |
84 | Add-Content -Path $durationTxt -Value "file '$timestamp.png'" |
85 | |
86 | Write-Host "Screenshot saved: $timestamp.png" |
87 | [console]::beep(1000, 500) # 播放提示音 |
88 | |
89 | $script:lastScreenshotTime = $now |
90 | $script:lastScreenshotFile = "$timestamp.png" |
91 | } |
92 | |
93 | # Delay 3 seconds to start |
94 | Start-Sleep -Seconds 3 |
95 | |
96 | # 主循环 |
97 | while ($true) { |
98 | try { |
99 | if (IsUserActive) { |
100 | TakeScreenshot |
101 | } |
102 | Start-Sleep -Seconds 1 |
103 | } catch { |
104 | Write-Host "An error occurred: $_" |
105 | Start-Sleep -Seconds 5 # 出错时等待5秒再继续 |
106 | } |
107 | } |