~voidraven/s4

s4/s4ctl.sh -rwxr-xr-x 7.0 KiB
601836d4voidraven updated version output format 1 year, 9 days ago
                                                                                
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
#!/bin/sh
#
# s4 - shell script sureveillance system
# author: voidraven
# https://git.sr.ht/~voidraven/s4
# license: ISC
#
# This file the main controller utility


VERSION="0.1.3"

# NOTE: variable preceeded by "L_" are "local" variables


# create the s4 directory tree
# args: 2
# 1: number of cameras we are working with
# 2: video storage path ( /mnt/where/i/want/vids )
fun_make_tree () {
    L1_CAMERAS="$1"
    L1_STORAGE="$2"
    L1_COUNT=0
    if ! [ -d "$L1_STORAGE"/s4 ] ; then
	mkdir -p "$L1_STORAGE"/s4/cameras
    fi
    while [ "$L1_COUNT" -lt "$L1_CAMERAS" ] ; do
	mkdir "$L1_STORAGE"/s4/cameras/"$L1_COUNT"
	L1_COUNT=$((L1_COUNT+1))
    done
    for CAM in "$L1_STORAGE"/s4/cameras/* ; do
	echo "false" > "$CAM"/run.status
	echo "true" > "$CAM"/stop.status
	cp ~/.s4/watch.sh "./watch$(basename "$CAM").sh"
    done
    unset L1_CAMERAS L1_STORAGE L1_COUNT
}


# make sure we received good user input
# args: 2
# 1: number of cameras (1-99)
# 2: video recording resolution (640x480, 1280x720, etc)
fun_check_input () {
    L2_CAMERAS="$1"
    L2_REZ="$2"
    L_REZOK="FALSE"
    if [ "$L2_CAMERAS" -lt 1 ] || [ "$L2_CAMERAS" -gt 99 ] ; then
	unset L2_CAMERAS L2_REZ
	fun_error "Bad number of cameras given! (0 < cameras < 100)"
    elif  [ "$L2_REZ" = "1920x1080" ] ; then
        L_REZOK="TRUE"
    elif  [ "$L2_REZ" = "1280x720" ] ; then
        L_REZOK="TRUE"
    elif  [ "$L2_REZ" = "640x480" ] ; then
        L_REZOK="TRUE"
    elif  [ "$L2_REZ" = "320x240" ] ; then
        L_REZOK="TRUE"
    fi
    unset L2_CAMERAS L2_REZ
    if [ "$L_REZOK" = "FALSE" ] ; then
	unset L_REZOK
	fun_error "Bad resolution: use 1920x1080, 1280x720, 640x480, or 320x240"
    fi
    unset L_REZOK
    return 0
}


# edit each of the watch templates to use the provided settings
# args: 4
# 1: number of cameras to set up
# 2: video recording resolution (640x480, 1280x720, etc)
# 3: root video storage location
# 4: video recording framerate (60 for 60fps)
fun_edit_templates () {
    L3_CAMERAS="$1"
    L3_REZ="$2"
    # this one liner escapes the '/' in the path, i.e. /mnt/nas becomes \/mnt\/nas
    L3_STORAGE=$(echo "$3" | sed 's/\//\\\//g')
    L3_FRAMER8="$4"
    L3_COUNT=0
    while [ "$L3_COUNT" -lt "$L3_CAMERAS" ] ; do
	printf ",s/XXX/%s\n,s/YYY/%s\n,s/ZZZ/%s\n,s/WWW/%s\nw\nq\n" \
	       "$L3_COUNT" "$L3_REZ" "$L3_STORAGE" "$L3_FRAMER8" \
	       | ed ./watch$L3_COUNT.sh > /dev/null 2>&1
	L3_COUNT=$((L3_COUNT+1))
    done
    unset L3_CAMERAS L3_REZ L3_STORAGE L3_FRAMER8 L3_COUNT
}


# creates watch files and config
fun_get_input () {
    L_CAMERAS=""
    L_REZ=""
    L_STORAGE=""
    L_FRAMER8=""
    printf "> How many cameras do you want to setup?: "
    read -r L_CAMERAS
    # example valid resolutions: 640x480, 1280x720, 1920x1080
    printf "> What resolution are you recording at?: "
    read -r L_REZ
    printf "> What framerate do you want to record at? [30/60]: "
    read -r L_FRAMER8
    printf "> Where do you want to store your video files?: "
    read -r L_STORAGE
    echo "Configuring storage..."
    echo "Generating watch files..."
    if fun_check_input "$L_CAMERAS" "$L_REZ" ; then
	L_WRITE=""
	if [ -s ~/.s4/config ] ; then
	    printf "> Config file already exists, did you want to overwrite it? [y/n]: "
	    read -r L_WRITE
	fi
	if [ "$L_WRITE" = "y" ] || [ "$L_WRITE" = "" ] ; then
	    {
		echo "#!/bin/sh"
		echo "S4_CAMERAS=\"$L_CAMERAS\""
		echo "S4_REZ=\"$L_REZ\""
		echo "S4_STORAGE=\"$L_STORAGE\""
	    } >> ~/.s4/config
	    # check if s4 folder exists in user provided path
	    if ! [ -d "$L_STORAGE/s4" ] ; then
		fun_make_tree "$L_CAMERAS" "$L_STORAGE"
	    fi
	    fun_edit_templates "$L_CAMERAS" "$L_REZ" "$L_STORAGE" "$L_FRAMER8"
	    echo "OK"
	    unset L_CAMERAS L_REZ L_STORAGE L_FRAMER8 L_WRITE
	else
	    echo "Ok, exiting early.. (config preserved)"
	    unset L_CAMERAS L_REZ L_STORAGE L_FRAMER8 L_WRITE
	    exit 1
	fi
    else
	unset L_CAMERAS L_REZ L_STORAGE L_FRAMER8 L_WRITE
    fi
}


fun_init () {
    # setup config file and make directory tree at storage location
    if ! [ -d "$HOME/.s4/" ] ; then
	fun_error "Missing config - You still need to run 'make deps' !"
    else
	# run user input loop
	fun_get_input
    fi
}


fun_check_config () {
    if ! [ -s "$HOME/.s4/config" ] ; then
	echo "No config file found at ~/.s4/config"
	echo "Make sure you have run 'make deps && make install' , then run:"
	echo "$ s4ctl -i"
	echo "in order to initialize your configuration"
	exit 1
    fi
}


# start/stop the camera(s)
# args: 1
# 1: action to perform; start or stop
fun_start_or_stop () {
    L_ACTION="$1"
    fun_check_config
    # The preceding line makes sure that the config exists, ok to ignore SC1090
    # shellcheck source=/dev/null
    . ~/.s4/config
    L_RUN_STAT="true" # defaults to start action
    L_STOP_STAT="false"
    if [ "$L_ACTION" = "stop" ] ; then
	L_RUN_STAT="false"
	L_STOP_STAT="true"
    fi
    # S4_STORAGE is brought in by sourcing the config file
    # will error earlier if not present, we can safely ignore the following SC2153 warning
    # shellcheck disable=SC2153
    for CAM in "$S4_STORAGE"/s4/cameras/* ; do
	echo "$L_RUN_STAT" > "$CAM"/run.status
	echo "$L_STOP_STAT" > "$CAM"/stop.status
    done
    unset L_RUN_STAT L_STOP_STAT
}


# list the camera(s) and their status(es)
fun_list () {
    fun_check_config
    # The preceding line makes sure that the config exists, ok to ignore SC1090
    # shellcheck source=/dev/null
    . ~/.s4/config
    # S4_STORAGE is brought in by sourcing the config file
    # will error earlier if not present, we can safely ignore the following SC2153 warning
    # shellcheck disable=SC2153
    for CAM in "$S4_STORAGE"/s4/cameras/* ; do
	echo "Camera $(basename "$CAM") - Running Status: $(cat "$CAM"/run.status)"
    done
}


# print out the version information
fun_print_ver () {
    echo "s4 version: $VERSION"
}


# print out the program info
fun_print_info () {
    echo "s4 - the shell script surveillance system"
    fun_print_ver
    echo "author: https://git.zerohack.xyz/lotus"
    echo "license: ISC"
}


# print an error message
# args: 1
# 1: error message to print
fun_error () {
    echo "Uh Oh, something borked!"
    echo "$1"
    fun_print_help
    exit 1
}


# prints out the help menu
fun_print_help () {
    fun_print_info
    echo "--- usage --------------------------------------------------"
    echo "s4ctl -i                          # initialize a new configuration"
    echo "s4ctl -s                          # start the camera(s)"
    echo "s4ctl -p                          # stop the camera(s)"
    echo "s4ctl -l                          # list all the available cameras"
    echo "s4ctl -h                          # shows this help message"
    echo "s4ctl -v                          # show the version info"
    echo ""
    echo "s4 stores configuration/cache files in ~/.s4"
}


while getopts 'spilhv' OPT ; do
	case "$OPT" in
	s)	fun_start_or_stop start;;
	p)	fun_start_or_stop stop;;
	i)      fun_init;;
	l)	fun_list;;
	h)      fun_print_help;;
	v)      fun_print_ver && exit 0;;
	[?])	fun_error "Bad argument passed!";;
	esac
done

exit 0