-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecorder
executable file
·274 lines (234 loc) · 8.11 KB
/
recorder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/usr/bin/env bash
## Description:
# This script records screen and audio using FFmpeg, with support for Intel and NVIDIA GPU encoding.
# It can handle screen recording, area recording, and audio-only recording.
# The script uses `gpu-screen-recorder` for capturing video and `ffmpeg` for encoding.
## Dependencies:
# - `gpu-screen-recorder` for GPU-accelerated screen recording.
# - `ffmpeg` for video and audio processing.
# - `awk` and `grep` for processing command outputs.
# - `pactl` for interacting with PulseAudio.
# - `zenity` for GUI dialogs (optional).
# - `ffmpegthumbnailer` for creating video thumbnails (optional).
# - `notify-send` for notifications.
# - `pkill` for terminating processes.
# - `polybar-msg` for interacting with Polybar (optional).
## TODO:
## Add a config file
# Define directory and file extension based on what needs to be recorded
user="$(whoami)"
backend="$XDG_SESSION_TYPE"
recorder_log="/tmp/recorder-$user.log"
recorder_lock="/tmp/recorder-$user.lock"
recorder_lock_audio="/tmp/recorder-$user-audio.lock"
if [[ "$1" == "--audio" ]] || [[ -e "$recorder_lock_audio" ]]; then
file_type="m4a"
dir="$HOME/Music/Recordings"
else
file_type="mp4"
dir="$HOME/Videos/Recordings"
fi
# Get current timestamp
time="$(date +%Y-%m-%d-%H-%M-%S)"
# Get segment number for generating filenames
segment_number="$(cat $recorder_lock 2>/dev/null | wc -l)"
file="recording_${time}_segment_${segment_number}.$file_type"
# Set frames per second for recording
fps="60"
# Video quality: either 'medium', 'high', 'very_high', or 'ultra'.
quality="very_high"
# Set the logging level for FFmpeg to reduce clutter
ffmpeg_command=(ffmpeg -hide_banner -loglevel error)
if [[ "$2" == "--noaudio" ]]; then
audio_command=()
else
# Get default audio sink and source
audio_sink=$(pactl info | grep 'Default Sink' | awk '{print $3}')
audio_source=$(pactl info | grep 'Default Source' | awk '{print $3}')
audio_command=(-a "${audio_sink}.monitor|${audio_source}" -a "${audio_sink}.monitor" -a "${audio_source}")
fi
# Check if FFmpeg is running or paused
if [[ $(pidof gpu-screen-recorder) ]] || [[ $(pidof ffmpeg) ]]; then
state="on"
elif [[ -e "$recorder_lock" ]]; then
state="paused"
else
state="off"
fi
# Create directory if it doesn't exist
if [[ ! -d "$dir" ]]; then
mkdir -p "$dir"
fi
# Function for countdown before starting recording
countdown() {
for sec in $(seq $1 -1 1); do
notify-send -e -a "Recorder" -t 1000 -r 699 "Starting in: $sec"
sleep 1
done
}
pre_notify () {
notify-send -u low -a "Recorder" -t 500 -r 699 "Recording Now!"
# Logging
echo "-----------------$time-----------------" >> "$recorder_log"
sleep 0.5
}
# Function to notify the user about recording status
notify_user() {
if [[ -e "$1" ]]; then
local file_name="$1"
zenity --question --title="Rename Recording" --text="Do you want to rename the recorded file?" &&
new_filename=$(zenity --entry --title="Rename Recording" --text="Enter a new filename")
if [[ -n "$new_filename" ]]; then
# Rename the file if a new filename is provided
mv "${dir}/${file_name##*/}" "${dir}/${new_filename}.$file_type"
file_name="${dir}/${new_filename}.$file_type"
fi
ffmpegthumbnailer -i "$file_name" -o /tmp/"${file_name##*/}".jpg -s 500
notify_action=$(notify-send -a "Recorder" -u low -r 699 "Recording Saved" "Click to open" -i /tmp/"${file_name##*/}".jpg \
--action="Delete" --action="Open")
case "$notify_action" in
"0")
rm "$file_name"
;;
"1")
exo-open "$file_name"
;;
esac
else
notify-send -a "Recorder" -u low -r 699 "Recording Canceled"
fi
}
# Function to cancel the recording if FFmpeg fails to record
catch_error(){
exit_code="$?"
if [[ -e "$recorder_lock_audio" ]]; then
[[ "$exit_code" != 255 ]] && cancel_recording
else
[[ "$exit_code" != 0 ]] && cancel_recording
fi
}
# Function to capture screen recording with or without audio
record_screen() {
signal_start
gpu-screen-recorder -v no -w screen -f "$fps" -cr "full" -q "$quality" -c "$file_type" "${audio_command[@]}" -o "${dir}/${file}"
catch_error # Check execution status after the command
}
# Function to capture area recording with or without audio
record_area() {
signal_start
gpu-screen-recorder -v no -f "$fps" -cr "full" -q "$quality" -c "$file_type" "${session_command[@]}" "${audio_command[@]}" -o "${dir}/${file}"
catch_error # Check execution status after the command
}
# Function to capture audio only
record_audio() {
touch "$recorder_lock_audio"
signal_start
"${ffmpeg_command[@]}" -f pulse -i ${audio_sink}.monitor -f pulse -i ${audio_source} \
-filter_complex "[1:a][0:a]amerge=inputs=2[out]" \
-map "[out]" -map 0:a -map 1:a -c:a aac -b:a 256k \
"${dir}/${file}"
catch_error # Check execution status after the command
}
# Function to stop ongoing recording and merge segments
toggle_recording() {
if [[ "$state" == "on" ]]; then
# Pause recording
[[ -e "$recorder_lock_audio" ]] && pkill ffmpeg || pkill -SIGINT gpu-screen-reco
[[ $(pidof polybar) ]] && polybar-msg action "#recorder.hook.2"
else
# Resume recording
[[ $(pidof polybar) ]] && polybar-msg action "#recorder.hook.1"
if [[ -e "$recorder_lock_audio" ]]; then
record_audio &
else
record_screen &
fi
fi
}
# Function to signal the start of recording
signal_start(){
pre_notify
[[ $(pidof polybar) ]] && polybar-msg action "#recorder.hook.1"
echo "file '${dir}/${file}'" >> "$recorder_lock"
}
# Function to signal the stop of recording
signal_stop(){
[[ $(pidof polybar) ]] && polybar-msg action "#recorder.hook.0"
rm /tmp/recorder*
}
stop_recording(){
if [[ ! -e "$recorder_lock" ]]; then exit 1 ;fi
if [[ -e "$recorder_lock_audio" ]]; then
pkill ffmpeg && while pgrep -l ffmpeg; do sleep 0.5;done
else
pkill -SIGINT gpu-screen-reco && while pgrep -l gpu-screen-reco; do sleep 0.5;done
fi
# Merge all segments into a single file
merged_file="$(awk -F"'" 'NR==1 {gsub("_segment_0", "", $2); print $2}' "$recorder_lock")"
"${ffmpeg_command[@]}" -y -f concat -safe 0 -i "$recorder_lock" -c copy -map 0:v? -map 0:a? "${merged_file}"
if [[ "$?" == 0 ]]; then
# Remove individual segment files
rm "${dir}/recording_"*"_segment_"*.*
else
# Move segments to a different directory when merging fails
mkdir -p "${dir}/Corrupt"
for file in "${dir}"/recording_*_segment_*.*; do
mv "$file" "${dir}/Corrupt/$(basename "$file")"
done
fi
signal_stop
notify_user "$merged_file" &
}
# Function to cancel ongoing recording
cancel_recording() {
if [[ ! -e "$recorder_lock" ]]; then exit 1 ;fi
[[ -e "$recorder_lock_audio" ]] && pkill -9 ffmpeg || pkill -9 gpu-screen-reco
rm "${dir}/recording_"*"_segment_"*.*
signal_stop
notify_user
}
# Help section
show_help() {
echo "Usage: ${0##*/} [ -- ]"
echo "Options:"
echo " --screen Start screen recording"
echo " --area Start area recording"
echo " --audio Start audio recording"
echo " --toggle Pause/resume ongoing recording"
echo " --stop Stop ongoing recording"
echo " --cancel Cancel ongoing recording"
echo " --status Check recording status"
echo " --help Show this help message"
}
# Command-line argument handling
case "$1" in
"--status")
echo "$state"
;;
"--toggle")
toggle_recording
;;
"--stop")
stop_recording
;;
"--cancel")
cancel_recording
;;
"--screen")
countdown 3
record_screen &
;;
"--area")
countdown 3
record_area &
;;
"--audio")
record_audio &
;;
"--help")
show_help
;;
*)
show_help
;;
esac