initial commit
21
NOTES/CAMERA-CMDS
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# setup: http://www.raspberrypi.org/help/camera-module-setup/
|
||||||
|
sudo apt-get install python-picamera
|
||||||
|
|
||||||
|
vcgencmd version
|
||||||
|
vcgencmd get_camera
|
||||||
|
|
||||||
|
# camera commands:
|
||||||
|
# http://www.raspberrypi.org/documentation/usage/camera/raspicam/README.md
|
||||||
|
|
||||||
|
# raspistill:
|
||||||
|
# http://www.raspberrypi.org/documentation/usage/camera/raspicam/raspistill.md
|
||||||
|
raspistill -o click.jpg
|
||||||
|
|
||||||
|
# raspivid:
|
||||||
|
# http://www.raspberrypi.org/documentation/usage/camera/raspicam/raspivid.md
|
||||||
|
# default 5 seconds, use -t <msecs> to customize
|
||||||
|
raspivid -o vid.h264
|
||||||
|
|
||||||
|
# picamera docs:
|
||||||
|
http://www.raspberrypi.org/documentation/usage/camera/python/README.md
|
||||||
|
http://picamera.readthedocs.org/en/latest/api.html
|
6
NOTES/CameraLinks
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
http://www.raspberrypi.org/forums/viewtopic.php?f=43&t=62364&p=463001
|
||||||
|
http://www.raspberrypi.org/forums/viewtopic.php?t=62945&p=466490
|
||||||
|
http://www.instructables.com/id/Raspberry-Pi-as-low-cost-HD-surveillance-camera/?ALLSTEPS
|
||||||
|
https://rbnrpi.wordpress.com/project-list/setting-up-wireless-motion-detect-cam/
|
||||||
|
http://www.raspberrypi.org/learning/parent-detector/
|
||||||
|
http://www.raspberrypi.org/turn-your-pi-into-a-low-cost-hd-surveillance-cam/
|
16
NOTES/FILE_LIST
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.ssh/authorized_keys
|
||||||
|
.bashrc
|
||||||
|
.profile
|
||||||
|
.vimrc
|
||||||
|
configs
|
||||||
|
drivers
|
||||||
|
make_tar
|
||||||
|
network_info
|
||||||
|
NOTES
|
||||||
|
scripts
|
||||||
|
setup_pi
|
||||||
|
setup_smb
|
||||||
|
setup_wifi
|
||||||
|
sync_osss_files
|
||||||
|
TODO
|
||||||
|
video.log
|
11
NOTES/NODE
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
download from source:
|
||||||
|
http://nodejs.org/dist/v0.10.34/node-v0.10.34.tar.gz
|
||||||
|
|
||||||
|
precompiled binary:
|
||||||
|
docs: https://gist.github.com/adammw/3245130
|
||||||
|
DOWNLOAD THIS: https://gist.github.com/raw/3245130/v0.10.24/node-v0.10.24-linux-arm-armv6j-vfp-hard.tar.gz
|
||||||
|
cd /usr/local
|
||||||
|
tar xzvf /path/to/binary.tar.gz --strip=1
|
||||||
|
|
||||||
|
fix the path:
|
||||||
|
echo 'export NODE_PATH="'$(npm root -g)'"' >> ~/.bash_profile && . ~/.bash_profile
|
3
NOTES/TRY_THIS
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
The command:
|
||||||
|
vlc http://doorcam/img/video.asf --sout '#transcode{vcodec=MJPG,venc=ffmpeg{strict=1}}:standard{access=http{mime=image/jpeg},mux=mpjpeg,dst=:8080/doorcam.mjpg}'
|
||||||
|
|
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
raspberrypi
|
||||||
|
===========
|
||||||
|
|
||||||
|
This is a repository containing various Raspberry Pi-based projects.
|
||||||
|
|
BIN
TODO/carhartl-jquery-cookie-v1.4.1-0-g7f88a4e.zip
Normal file
BIN
TODO/datetimepicker-master.zip
Normal file
BIN
TODO/plain_weather_icons_by_merlinthered-d2lkj4g.zip
Normal file
BIN
TODO/weather-icon-1.png
Normal file
After Width: | Height: | Size: 52 KiB |
9
configs/avahi/apache.service
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||||
|
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||||
|
<service-group>
|
||||||
|
<name replace-wildcards="yes">%h HTTP</name>
|
||||||
|
<service>
|
||||||
|
<type>_http._tcp</type>
|
||||||
|
<port>80</port>
|
||||||
|
</service>
|
||||||
|
</service-group>
|
9
configs/avahi/sftp.service
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||||
|
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||||
|
<service-group>
|
||||||
|
<name replace-wildcards="yes">%h SFTP</name>
|
||||||
|
<service>
|
||||||
|
<type>_sftp-ssh._tcp</type>
|
||||||
|
<port>22</port>
|
||||||
|
</service>
|
||||||
|
</service-group>
|
9
configs/avahi/ssh.service
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||||
|
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||||
|
<service-group>
|
||||||
|
<name replace-wildcards="yes">%h SSH</name>
|
||||||
|
<service>
|
||||||
|
<type>_ssh._tcp</type>
|
||||||
|
<port>22</port>
|
||||||
|
</service>
|
||||||
|
</service-group>
|
17
configs/lighttpd/c3test.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<title>C3 test</title>
|
||||||
|
<!-- Load c3.css -->
|
||||||
|
<link href="css/c3.css" rel="stylesheet" type="text/css">
|
||||||
|
|
||||||
|
<!-- Load d3.js and c3.js -->
|
||||||
|
<script src="js/jquery.min.js"></script>
|
||||||
|
<script src="js/d3.min.js" charset="utf-8"></script>
|
||||||
|
<script src="js/c3.min.js"></script>
|
||||||
|
<script src="js/c3test.js"></script>
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<h1>C3 test</h1>
|
||||||
|
<div id="chart"></div>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
24
configs/lighttpd/cgi-bin/fake_wind_data.py
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import os, sys
|
||||||
|
from cgi import escape
|
||||||
|
from random import randint
|
||||||
|
import cgitb; cgitb.enable()
|
||||||
|
import json
|
||||||
|
|
||||||
|
GRID_SIZE = 50
|
||||||
|
|
||||||
|
def r(max):
|
||||||
|
return randint(0, max)
|
||||||
|
|
||||||
|
weather_data = []
|
||||||
|
|
||||||
|
for i in range(0, GRID_SIZE*GRID_SIZE):
|
||||||
|
temp = []
|
||||||
|
temp.append( r(25) )
|
||||||
|
temp.append( r(360) )
|
||||||
|
weather_data.append(temp)
|
||||||
|
|
||||||
|
print "Content-Type: application/json"
|
||||||
|
print
|
||||||
|
print(json.JSONEncoder().encode(weather_data))
|
31
configs/lighttpd/cgi-bin/get_current_readings.py
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# 1 2014-12-28 06:58:39.599004 101629 14.3 55.358172338 4.89756118958
|
||||||
|
|
||||||
|
import os, sys
|
||||||
|
from cgi import escape
|
||||||
|
import cgitb; cgitb.enable()
|
||||||
|
from random import uniform, randint
|
||||||
|
import json
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
data_format_version = 1
|
||||||
|
|
||||||
|
def r(max):
|
||||||
|
return randint(0, max)
|
||||||
|
|
||||||
|
ret = {}
|
||||||
|
|
||||||
|
ret["version"] = data_format_version
|
||||||
|
ret["timestamp"] = datetime.datetime.now().isoformat()
|
||||||
|
ret["pressure"] = randint(8000, 20000);
|
||||||
|
ret["pressure_trend"] = randint(-1, 1);
|
||||||
|
ret["temperature"] = uniform(-100, 100);
|
||||||
|
ret["temperature_trend"] = randint(-1, 1);
|
||||||
|
ret["humidity"] = uniform(0, 100);
|
||||||
|
ret["humidity_trend"] = randint(-1, 1);
|
||||||
|
ret["dewpoint"] = uniform(-100, 100);
|
||||||
|
ret["dewpoint_trend"] = randint(-1, 1);
|
||||||
|
|
||||||
|
print "Content-Type: application/json"
|
||||||
|
print
|
||||||
|
print(json.JSONEncoder().encode(ret))
|
24
configs/lighttpd/cgi-bin/get_topo.py
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import os, sys
|
||||||
|
from cgi import escape
|
||||||
|
import cgitb; cgitb.enable()
|
||||||
|
from random import randint
|
||||||
|
import json
|
||||||
|
|
||||||
|
ret = {}
|
||||||
|
|
||||||
|
with open('LOCLTOPO') as f:
|
||||||
|
array = []
|
||||||
|
for line in f:
|
||||||
|
array.append([int(x) for x in line.split()])
|
||||||
|
|
||||||
|
#print "rows = %d" % len(array)
|
||||||
|
#print "columns = %d" % len(array[0])
|
||||||
|
|
||||||
|
ret["rows"] = len(array)
|
||||||
|
ret["columns"] = len(array[0])
|
||||||
|
ret["data"] = array
|
||||||
|
|
||||||
|
print "Content-Type: application/json"
|
||||||
|
print
|
||||||
|
print(json.JSONEncoder().encode(ret))
|
14
configs/lighttpd/cgi-bin/test.py
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
print "Content-type: text/html"
|
||||||
|
print
|
||||||
|
print "<h1>Stupid Test CGI</h1>"
|
||||||
|
print "<pre>"
|
||||||
|
import os, sys
|
||||||
|
from cgi import escape
|
||||||
|
import cgitb; cgitb.enable()
|
||||||
|
print "<strong>Python %s</strong>" % sys.version
|
||||||
|
keys = os.environ.keys()
|
||||||
|
keys.sort()
|
||||||
|
for k in keys:
|
||||||
|
print "%s\t%s" % (escape(k), escape(os.environ[k]))
|
||||||
|
print "</pre>"
|
217
configs/lighttpd/css/external/c3.css
vendored
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
/*-- Chart --*/
|
||||||
|
|
||||||
|
.c3 svg {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
}
|
||||||
|
.c3 path, .c3 line {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
}
|
||||||
|
.c3 text {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-legend-item-tile,
|
||||||
|
.c3-xgrid-focus,
|
||||||
|
.c3-ygrid,
|
||||||
|
.c3-event-rect,
|
||||||
|
.c3-bars path {
|
||||||
|
shape-rendering: crispEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-chart-arc path {
|
||||||
|
stroke: #fff;
|
||||||
|
|
||||||
|
}
|
||||||
|
.c3-chart-arc text {
|
||||||
|
fill: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Axis --*/
|
||||||
|
|
||||||
|
.c3-axis-x .tick {
|
||||||
|
}
|
||||||
|
.c3-axis-x-label {
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-axis-y .tick {
|
||||||
|
}
|
||||||
|
.c3-axis-y-label {
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-axis-y2 .tick {
|
||||||
|
}
|
||||||
|
.c3-axis-y2-label {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Grid --*/
|
||||||
|
|
||||||
|
.c3-grid line {
|
||||||
|
stroke: #aaa;
|
||||||
|
}
|
||||||
|
.c3-grid text {
|
||||||
|
fill: #aaa;
|
||||||
|
}
|
||||||
|
.c3-xgrid, .c3-ygrid {
|
||||||
|
stroke-dasharray: 3 3;
|
||||||
|
}
|
||||||
|
.c3-xgrid-focus {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Text on Chart --*/
|
||||||
|
|
||||||
|
.c3-text {
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-text.c3-empty {
|
||||||
|
fill: #808080;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Line --*/
|
||||||
|
|
||||||
|
.c3-line {
|
||||||
|
stroke-width: 1px;
|
||||||
|
}
|
||||||
|
/*-- Point --*/
|
||||||
|
|
||||||
|
.c3-circle._expanded_ {
|
||||||
|
stroke-width: 1px;
|
||||||
|
stroke: white;
|
||||||
|
}
|
||||||
|
.c3-selected-circle {
|
||||||
|
fill: white;
|
||||||
|
stroke-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Bar --*/
|
||||||
|
|
||||||
|
.c3-bar {
|
||||||
|
stroke-width: 0;
|
||||||
|
}
|
||||||
|
.c3-bar._expanded_ {
|
||||||
|
fill-opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Arc --*/
|
||||||
|
|
||||||
|
.c3-chart-arcs-title {
|
||||||
|
dominant-baseline: middle;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Focus --*/
|
||||||
|
|
||||||
|
.c3-target.c3-focused {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.c3-target.c3-focused path.c3-line, .c3-target.c3-focused path.c3-step {
|
||||||
|
stroke-width: 2px;
|
||||||
|
}
|
||||||
|
.c3-target.c3-defocused {
|
||||||
|
opacity: 0.3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-- Region --*/
|
||||||
|
|
||||||
|
.c3-region {
|
||||||
|
fill: steelblue;
|
||||||
|
fill-opacity: .1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Brush --*/
|
||||||
|
|
||||||
|
.c3-brush .extent {
|
||||||
|
fill-opacity: .1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Select - Drag --*/
|
||||||
|
|
||||||
|
.c3-dragarea {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Legend --*/
|
||||||
|
|
||||||
|
.c3-legend-item {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.c3-legend-item-hidden {
|
||||||
|
opacity: 0.15;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-legend-background {
|
||||||
|
opacity: 0.75;
|
||||||
|
fill: white;
|
||||||
|
stroke: lightgray;
|
||||||
|
stroke-width: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Tooltip --*/
|
||||||
|
|
||||||
|
.c3-tooltip-container {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.c3-tooltip {
|
||||||
|
border-collapse:collapse;
|
||||||
|
border-spacing:0;
|
||||||
|
background-color:#fff;
|
||||||
|
empty-cells:show;
|
||||||
|
-webkit-box-shadow: 7px 7px 12px -9px rgb(119,119,119);
|
||||||
|
-moz-box-shadow: 7px 7px 12px -9px rgb(119,119,119);
|
||||||
|
box-shadow: 7px 7px 12px -9px rgb(119,119,119);
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
.c3-tooltip tr {
|
||||||
|
border:1px solid #CCC;
|
||||||
|
}
|
||||||
|
.c3-tooltip th {
|
||||||
|
background-color: #aaa;
|
||||||
|
font-size:14px;
|
||||||
|
padding:2px 5px;
|
||||||
|
text-align:left;
|
||||||
|
color:#FFF;
|
||||||
|
}
|
||||||
|
.c3-tooltip td {
|
||||||
|
font-size:13px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
background-color:#fff;
|
||||||
|
border-left:1px dotted #999;
|
||||||
|
}
|
||||||
|
.c3-tooltip td > span {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
.c3-tooltip td.value{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-area {
|
||||||
|
stroke-width: 0;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-chart-arcs .c3-chart-arcs-background {
|
||||||
|
fill: #e0e0e0;
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
.c3-chart-arcs .c3-chart-arcs-gauge-unit {
|
||||||
|
fill: #000;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.c3-chart-arcs .c3-chart-arcs-gauge-max {
|
||||||
|
fill: #777;
|
||||||
|
}
|
||||||
|
.c3-chart-arcs .c3-chart-arcs-gauge-min {
|
||||||
|
fill: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3-chart-arc .c3-gauge-value {
|
||||||
|
fill: #000;
|
||||||
|
/* font-size: 28px !important;*/
|
||||||
|
}
|
1
configs/lighttpd/css/external/c3.min.css
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
|
BIN
configs/lighttpd/css/external/images/ui-bg_flat_30_cccccc_40x100.png
vendored
Normal file
After Width: | Height: | Size: 220 B |
BIN
configs/lighttpd/css/external/images/ui-bg_flat_50_5c5c5c_40x100.png
vendored
Normal file
After Width: | Height: | Size: 230 B |
BIN
configs/lighttpd/css/external/images/ui-bg_glass_20_555555_1x400.png
vendored
Normal file
After Width: | Height: | Size: 260 B |
BIN
configs/lighttpd/css/external/images/ui-bg_glass_40_0078a3_1x400.png
vendored
Normal file
After Width: | Height: | Size: 342 B |
BIN
configs/lighttpd/css/external/images/ui-bg_glass_40_ffc73d_1x400.png
vendored
Normal file
After Width: | Height: | Size: 316 B |
BIN
configs/lighttpd/css/external/images/ui-bg_gloss-wave_25_333333_500x100.png
vendored
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
configs/lighttpd/css/external/images/ui-bg_highlight-soft_80_eeeeee_1x100.png
vendored
Normal file
After Width: | Height: | Size: 276 B |
BIN
configs/lighttpd/css/external/images/ui-bg_inset-soft_25_000000_1x100.png
vendored
Normal file
After Width: | Height: | Size: 275 B |
BIN
configs/lighttpd/css/external/images/ui-bg_inset-soft_30_f58400_1x100.png
vendored
Normal file
After Width: | Height: | Size: 340 B |
BIN
configs/lighttpd/css/external/images/ui-icons_222222_256x240.png
vendored
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
configs/lighttpd/css/external/images/ui-icons_4b8e0b_256x240.png
vendored
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
configs/lighttpd/css/external/images/ui-icons_a83300_256x240.png
vendored
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
configs/lighttpd/css/external/images/ui-icons_cccccc_256x240.png
vendored
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
configs/lighttpd/css/external/images/ui-icons_ffffff_256x240.png
vendored
Normal file
After Width: | Height: | Size: 6.2 KiB |
1225
configs/lighttpd/css/external/jquery-ui.css
vendored
Normal file
7
configs/lighttpd/css/external/jquery-ui.min.css
vendored
Normal file
833
configs/lighttpd/css/external/jquery-ui.structure.css
vendored
Normal file
|
@ -0,0 +1,833 @@
|
||||||
|
/*!
|
||||||
|
* jQuery UI CSS Framework 1.11.2
|
||||||
|
* http://jqueryui.com
|
||||||
|
*
|
||||||
|
* Copyright 2014 jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license.
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* http://api.jqueryui.com/category/theming/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Layout helpers
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-helper-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-helper-hidden-accessible {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
.ui-helper-reset {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
line-height: 1.3;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 100%;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix:before,
|
||||||
|
.ui-helper-clearfix:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix {
|
||||||
|
min-height: 0; /* support: IE7 */
|
||||||
|
}
|
||||||
|
.ui-helper-zfix {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
filter:Alpha(Opacity=0); /* support: IE8 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-front {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Interaction Cues
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-disabled {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Icons
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* states and images */
|
||||||
|
.ui-icon {
|
||||||
|
display: block;
|
||||||
|
text-indent: -99999px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc visuals
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.ui-widget-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-draggable-handle {
|
||||||
|
-ms-touch-action: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.ui-resizable {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ui-resizable-handle {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 0.1px;
|
||||||
|
display: block;
|
||||||
|
-ms-touch-action: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.ui-resizable-disabled .ui-resizable-handle,
|
||||||
|
.ui-resizable-autohide .ui-resizable-handle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-resizable-n {
|
||||||
|
cursor: n-resize;
|
||||||
|
height: 7px;
|
||||||
|
width: 100%;
|
||||||
|
top: -5px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-resizable-s {
|
||||||
|
cursor: s-resize;
|
||||||
|
height: 7px;
|
||||||
|
width: 100%;
|
||||||
|
bottom: -5px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-resizable-e {
|
||||||
|
cursor: e-resize;
|
||||||
|
width: 7px;
|
||||||
|
right: -5px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-resizable-w {
|
||||||
|
cursor: w-resize;
|
||||||
|
width: 7px;
|
||||||
|
left: -5px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-resizable-se {
|
||||||
|
cursor: se-resize;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
right: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
}
|
||||||
|
.ui-resizable-sw {
|
||||||
|
cursor: sw-resize;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
left: -5px;
|
||||||
|
bottom: -5px;
|
||||||
|
}
|
||||||
|
.ui-resizable-nw {
|
||||||
|
cursor: nw-resize;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
left: -5px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
.ui-resizable-ne {
|
||||||
|
cursor: ne-resize;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
right: -5px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
.ui-selectable {
|
||||||
|
-ms-touch-action: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.ui-selectable-helper {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 100;
|
||||||
|
border: 1px dotted black;
|
||||||
|
}
|
||||||
|
.ui-sortable-handle {
|
||||||
|
-ms-touch-action: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.ui-accordion .ui-accordion-header {
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
margin: 2px 0 0 0;
|
||||||
|
padding: .5em .5em .5em .7em;
|
||||||
|
min-height: 0; /* support: IE7 */
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
.ui-accordion .ui-accordion-icons {
|
||||||
|
padding-left: 2.2em;
|
||||||
|
}
|
||||||
|
.ui-accordion .ui-accordion-icons .ui-accordion-icons {
|
||||||
|
padding-left: 2.2em;
|
||||||
|
}
|
||||||
|
.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: .5em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
.ui-accordion .ui-accordion-content {
|
||||||
|
padding: 1em 2.2em;
|
||||||
|
border-top: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.ui-autocomplete {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.ui-button {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
line-height: normal;
|
||||||
|
margin-right: .1em;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
overflow: visible; /* removes extra width in IE */
|
||||||
|
}
|
||||||
|
.ui-button,
|
||||||
|
.ui-button:link,
|
||||||
|
.ui-button:visited,
|
||||||
|
.ui-button:hover,
|
||||||
|
.ui-button:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
/* to make room for the icon, a width needs to be set here */
|
||||||
|
.ui-button-icon-only {
|
||||||
|
width: 2.2em;
|
||||||
|
}
|
||||||
|
/* button elements seem to need a little more width */
|
||||||
|
button.ui-button-icon-only {
|
||||||
|
width: 2.4em;
|
||||||
|
}
|
||||||
|
.ui-button-icons-only {
|
||||||
|
width: 3.4em;
|
||||||
|
}
|
||||||
|
button.ui-button-icons-only {
|
||||||
|
width: 3.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button text element */
|
||||||
|
.ui-button .ui-button-text {
|
||||||
|
display: block;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.ui-button-text-only .ui-button-text {
|
||||||
|
padding: .4em 1em;
|
||||||
|
}
|
||||||
|
.ui-button-icon-only .ui-button-text,
|
||||||
|
.ui-button-icons-only .ui-button-text {
|
||||||
|
padding: .4em;
|
||||||
|
text-indent: -9999999px;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-primary .ui-button-text,
|
||||||
|
.ui-button-text-icons .ui-button-text {
|
||||||
|
padding: .4em 1em .4em 2.1em;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-secondary .ui-button-text,
|
||||||
|
.ui-button-text-icons .ui-button-text {
|
||||||
|
padding: .4em 2.1em .4em 1em;
|
||||||
|
}
|
||||||
|
.ui-button-text-icons .ui-button-text {
|
||||||
|
padding-left: 2.1em;
|
||||||
|
padding-right: 2.1em;
|
||||||
|
}
|
||||||
|
/* no icon support for input elements, provide padding by default */
|
||||||
|
input.ui-button {
|
||||||
|
padding: .4em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button icon element(s) */
|
||||||
|
.ui-button-icon-only .ui-icon,
|
||||||
|
.ui-button-text-icon-primary .ui-icon,
|
||||||
|
.ui-button-text-icon-secondary .ui-icon,
|
||||||
|
.ui-button-text-icons .ui-icon,
|
||||||
|
.ui-button-icons-only .ui-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
.ui-button-icon-only .ui-icon {
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -8px;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-primary .ui-button-icon-primary,
|
||||||
|
.ui-button-text-icons .ui-button-icon-primary,
|
||||||
|
.ui-button-icons-only .ui-button-icon-primary {
|
||||||
|
left: .5em;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-secondary .ui-button-icon-secondary,
|
||||||
|
.ui-button-text-icons .ui-button-icon-secondary,
|
||||||
|
.ui-button-icons-only .ui-button-icon-secondary {
|
||||||
|
right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button sets */
|
||||||
|
.ui-buttonset {
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
.ui-buttonset .ui-button {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: -.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* workarounds */
|
||||||
|
/* reset extra padding in Firefox, see h5bp.com/l */
|
||||||
|
input.ui-button::-moz-focus-inner,
|
||||||
|
button.ui-button::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker {
|
||||||
|
width: 17em;
|
||||||
|
padding: .2em .2em 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-header {
|
||||||
|
position: relative;
|
||||||
|
padding: .2em 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev,
|
||||||
|
.ui-datepicker .ui-datepicker-next {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev-hover,
|
||||||
|
.ui-datepicker .ui-datepicker-next-hover {
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev {
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-next {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev-hover {
|
||||||
|
left: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-next-hover {
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-prev span,
|
||||||
|
.ui-datepicker .ui-datepicker-next span {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -8px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-title {
|
||||||
|
margin: 0 2.3em;
|
||||||
|
line-height: 1.8em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-title select {
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1px 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker select.ui-datepicker-month,
|
||||||
|
.ui-datepicker select.ui-datepicker-year {
|
||||||
|
width: 45%;
|
||||||
|
}
|
||||||
|
.ui-datepicker table {
|
||||||
|
width: 100%;
|
||||||
|
font-size: .9em;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 0 0 .4em;
|
||||||
|
}
|
||||||
|
.ui-datepicker th {
|
||||||
|
padding: .7em .3em;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker td {
|
||||||
|
border: 0;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
.ui-datepicker td span,
|
||||||
|
.ui-datepicker td a {
|
||||||
|
display: block;
|
||||||
|
padding: .2em;
|
||||||
|
text-align: right;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-buttonpane {
|
||||||
|
background-image: none;
|
||||||
|
margin: .7em 0 0 0;
|
||||||
|
padding: 0 .2em;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-buttonpane button {
|
||||||
|
float: right;
|
||||||
|
margin: .5em .2em .4em;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: .2em .6em .3em .6em;
|
||||||
|
width: auto;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* with multiple calendars */
|
||||||
|
.ui-datepicker.ui-datepicker-multi {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group table {
|
||||||
|
width: 95%;
|
||||||
|
margin: 0 auto .4em;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi-2 .ui-datepicker-group {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi-3 .ui-datepicker-group {
|
||||||
|
width: 33.3%;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi-4 .ui-datepicker-group {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
|
||||||
|
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
.ui-datepicker-multi .ui-datepicker-buttonpane {
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
.ui-datepicker-row-break {
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RTL support */
|
||||||
|
.ui-datepicker-rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-prev {
|
||||||
|
right: 2px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-next {
|
||||||
|
left: 2px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-prev:hover {
|
||||||
|
right: 1px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-next:hover {
|
||||||
|
left: 1px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-buttonpane {
|
||||||
|
clear: right;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-group {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
|
||||||
|
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
|
||||||
|
border-right-width: 0;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
.ui-dialog {
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: .2em;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-titlebar {
|
||||||
|
padding: .4em 1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-title {
|
||||||
|
float: left;
|
||||||
|
margin: .1em 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 90%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-titlebar-close {
|
||||||
|
position: absolute;
|
||||||
|
right: .3em;
|
||||||
|
top: 50%;
|
||||||
|
width: 20px;
|
||||||
|
margin: -10px 0 0 0;
|
||||||
|
padding: 1px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-content {
|
||||||
|
position: relative;
|
||||||
|
border: 0;
|
||||||
|
padding: .5em 1em;
|
||||||
|
background: none;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-buttonpane {
|
||||||
|
text-align: left;
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
background-image: none;
|
||||||
|
margin-top: .5em;
|
||||||
|
padding: .3em 1em .5em .4em;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-buttonpane button {
|
||||||
|
margin: .5em .4em .5em 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-resizable-se {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
right: -5px;
|
||||||
|
bottom: -5px;
|
||||||
|
background-position: 16px 16px;
|
||||||
|
}
|
||||||
|
.ui-draggable .ui-dialog-titlebar {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
.ui-menu {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: block;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.ui-menu .ui-menu {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.ui-menu .ui-menu-item {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
padding: 3px 1em 3px .4em;
|
||||||
|
cursor: pointer;
|
||||||
|
min-height: 0; /* support: IE7 */
|
||||||
|
/* support: IE10, see #8844 */
|
||||||
|
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||||
|
}
|
||||||
|
.ui-menu .ui-menu-divider {
|
||||||
|
margin: 5px 0;
|
||||||
|
height: 0;
|
||||||
|
font-size: 0;
|
||||||
|
line-height: 0;
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
}
|
||||||
|
.ui-menu .ui-state-focus,
|
||||||
|
.ui-menu .ui-state-active {
|
||||||
|
margin: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon support */
|
||||||
|
.ui-menu-icons {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ui-menu-icons .ui-menu-item {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* left-aligned */
|
||||||
|
.ui-menu .ui-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: .2em;
|
||||||
|
margin: auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* right-aligned */
|
||||||
|
.ui-menu .ui-menu-icon {
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.ui-progressbar {
|
||||||
|
height: 2em;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.ui-progressbar .ui-progressbar-value {
|
||||||
|
margin: -1px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-progressbar .ui-progressbar-overlay {
|
||||||
|
background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
|
||||||
|
height: 100%;
|
||||||
|
filter: alpha(opacity=25); /* support: IE8 */
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
.ui-progressbar-indeterminate .ui-progressbar-value {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-menu {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-menu .ui-menu {
|
||||||
|
overflow: auto;
|
||||||
|
/* Support: IE7 */
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding: 2px 0.4em;
|
||||||
|
margin: 0.5em 0 0 0;
|
||||||
|
height: auto;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-button {
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-button span.ui-icon {
|
||||||
|
right: 0.5em;
|
||||||
|
left: auto;
|
||||||
|
margin-top: -8px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
.ui-selectmenu-button span.ui-selectmenu-text {
|
||||||
|
text-align: left;
|
||||||
|
padding: 0.4em 2.1em 0.4em 1em;
|
||||||
|
display: block;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.ui-slider {
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.ui-slider .ui-slider-handle {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
cursor: default;
|
||||||
|
-ms-touch-action: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.ui-slider .ui-slider-range {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
font-size: .7em;
|
||||||
|
display: block;
|
||||||
|
border: 0;
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* support: IE8 - See #6727 */
|
||||||
|
.ui-slider.ui-state-disabled .ui-slider-handle,
|
||||||
|
.ui-slider.ui-state-disabled .ui-slider-range {
|
||||||
|
filter: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-slider-horizontal {
|
||||||
|
height: .8em;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-handle {
|
||||||
|
top: -.3em;
|
||||||
|
margin-left: -.6em;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-range {
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-range-min {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-range-max {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-slider-vertical {
|
||||||
|
width: .8em;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-handle {
|
||||||
|
left: -.3em;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-bottom: -.6em;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-range {
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-range-min {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-range-max {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.ui-spinner {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.ui-spinner-input {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: inherit;
|
||||||
|
padding: 0;
|
||||||
|
margin: .2em 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: .4em;
|
||||||
|
margin-right: 22px;
|
||||||
|
}
|
||||||
|
.ui-spinner-button {
|
||||||
|
width: 16px;
|
||||||
|
height: 50%;
|
||||||
|
font-size: .5em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
cursor: default;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
/* more specificity required here to override default borders */
|
||||||
|
.ui-spinner a.ui-spinner-button {
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
/* vertically center icon */
|
||||||
|
.ui-spinner .ui-icon {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: -8px;
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-spinner-up {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.ui-spinner-down {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TR overrides */
|
||||||
|
.ui-spinner .ui-icon-triangle-1-s {
|
||||||
|
/* need to fix icons sprite */
|
||||||
|
background-position: -65px -16px;
|
||||||
|
}
|
||||||
|
.ui-tabs {
|
||||||
|
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||||
|
padding: .2em;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav {
|
||||||
|
margin: 0;
|
||||||
|
padding: .2em .2em 0;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav li {
|
||||||
|
list-style: none;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
margin: 1px .2em 0 0;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
|
||||||
|
float: left;
|
||||||
|
padding: .5em 1em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-panel {
|
||||||
|
display: block;
|
||||||
|
border-width: 0;
|
||||||
|
padding: 1em 1.4em;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.ui-tooltip {
|
||||||
|
padding: 8px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9999;
|
||||||
|
max-width: 300px;
|
||||||
|
-webkit-box-shadow: 0 0 5px #aaa;
|
||||||
|
box-shadow: 0 0 5px #aaa;
|
||||||
|
}
|
||||||
|
body .ui-tooltip {
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
5
configs/lighttpd/css/external/jquery-ui.structure.min.css
vendored
Normal file
410
configs/lighttpd/css/external/jquery-ui.theme.css
vendored
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
/*!
|
||||||
|
* jQuery UI CSS Framework 1.11.2
|
||||||
|
* http://jqueryui.com
|
||||||
|
*
|
||||||
|
* Copyright 2014 jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license.
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* http://api.jqueryui.com/category/theming/
|
||||||
|
*
|
||||||
|
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Segoe%20UI%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=333333&bgTextureHeader=gloss_wave&bgImgOpacityHeader=25&borderColorHeader=333333&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=000000&bgTextureContent=inset_soft&bgImgOpacityContent=25&borderColorContent=666666&fcContent=ffffff&iconColorContent=cccccc&bgColorDefault=555555&bgTextureDefault=glass&bgImgOpacityDefault=20&borderColorDefault=666666&fcDefault=eeeeee&iconColorDefault=cccccc&bgColorHover=0078a3&bgTextureHover=glass&bgImgOpacityHover=40&borderColorHover=59b4d4&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=f58400&bgTextureActive=inset_soft&bgImgOpacityActive=30&borderColorActive=ffaf0f&fcActive=ffffff&iconColorActive=222222&bgColorHighlight=eeeeee&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=80&borderColorHighlight=cccccc&fcHighlight=2e7db2&iconColorHighlight=4b8e0b&bgColorError=ffc73d&bgTextureError=glass&bgImgOpacityError=40&borderColorError=ffb73d&fcError=111111&iconColorError=a83300&bgColorOverlay=5c5c5c&bgTextureOverlay=flat&bgImgOpacityOverlay=50&opacityOverlay=80&bgColorShadow=cccccc&bgTextureShadow=flat&bgImgOpacityShadow=30&opacityShadow=60&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Component containers
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-widget {
|
||||||
|
font-family: Segoe UI,Arial,sans-serif;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
.ui-widget .ui-widget {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.ui-widget input,
|
||||||
|
.ui-widget select,
|
||||||
|
.ui-widget textarea,
|
||||||
|
.ui-widget button {
|
||||||
|
font-family: Segoe UI,Arial,sans-serif;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.ui-widget-content {
|
||||||
|
border: 1px solid #666666;
|
||||||
|
background: #000000 url("images/ui-bg_inset-soft_25_000000_1x100.png") 50% bottom repeat-x;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-widget-content a {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-widget-header {
|
||||||
|
border: 1px solid #333333;
|
||||||
|
background: #333333 url("images/ui-bg_gloss-wave_25_333333_500x100.png") 50% 50% repeat-x;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ui-widget-header a {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaction states
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-default,
|
||||||
|
.ui-widget-content .ui-state-default,
|
||||||
|
.ui-widget-header .ui-state-default {
|
||||||
|
border: 1px solid #666666;
|
||||||
|
background: #555555 url("images/ui-bg_glass_20_555555_1x400.png") 50% 50% repeat-x;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #eeeeee;
|
||||||
|
}
|
||||||
|
.ui-state-default a,
|
||||||
|
.ui-state-default a:link,
|
||||||
|
.ui-state-default a:visited {
|
||||||
|
color: #eeeeee;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-state-hover,
|
||||||
|
.ui-widget-content .ui-state-hover,
|
||||||
|
.ui-widget-header .ui-state-hover,
|
||||||
|
.ui-state-focus,
|
||||||
|
.ui-widget-content .ui-state-focus,
|
||||||
|
.ui-widget-header .ui-state-focus {
|
||||||
|
border: 1px solid #59b4d4;
|
||||||
|
background: #0078a3 url("images/ui-bg_glass_40_0078a3_1x400.png") 50% 50% repeat-x;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-state-hover a,
|
||||||
|
.ui-state-hover a:hover,
|
||||||
|
.ui-state-hover a:link,
|
||||||
|
.ui-state-hover a:visited,
|
||||||
|
.ui-state-focus a,
|
||||||
|
.ui-state-focus a:hover,
|
||||||
|
.ui-state-focus a:link,
|
||||||
|
.ui-state-focus a:visited {
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-state-active,
|
||||||
|
.ui-widget-content .ui-state-active,
|
||||||
|
.ui-widget-header .ui-state-active {
|
||||||
|
border: 1px solid #ffaf0f;
|
||||||
|
background: #f58400 url("images/ui-bg_inset-soft_30_f58400_1x100.png") 50% 50% repeat-x;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.ui-state-active a,
|
||||||
|
.ui-state-active a:link,
|
||||||
|
.ui-state-active a:visited {
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaction Cues
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-highlight,
|
||||||
|
.ui-widget-content .ui-state-highlight,
|
||||||
|
.ui-widget-header .ui-state-highlight {
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
background: #eeeeee url("images/ui-bg_highlight-soft_80_eeeeee_1x100.png") 50% top repeat-x;
|
||||||
|
color: #2e7db2;
|
||||||
|
}
|
||||||
|
.ui-state-highlight a,
|
||||||
|
.ui-widget-content .ui-state-highlight a,
|
||||||
|
.ui-widget-header .ui-state-highlight a {
|
||||||
|
color: #2e7db2;
|
||||||
|
}
|
||||||
|
.ui-state-error,
|
||||||
|
.ui-widget-content .ui-state-error,
|
||||||
|
.ui-widget-header .ui-state-error {
|
||||||
|
border: 1px solid #ffb73d;
|
||||||
|
background: #ffc73d url("images/ui-bg_glass_40_ffc73d_1x400.png") 50% 50% repeat-x;
|
||||||
|
color: #111111;
|
||||||
|
}
|
||||||
|
.ui-state-error a,
|
||||||
|
.ui-widget-content .ui-state-error a,
|
||||||
|
.ui-widget-header .ui-state-error a {
|
||||||
|
color: #111111;
|
||||||
|
}
|
||||||
|
.ui-state-error-text,
|
||||||
|
.ui-widget-content .ui-state-error-text,
|
||||||
|
.ui-widget-header .ui-state-error-text {
|
||||||
|
color: #111111;
|
||||||
|
}
|
||||||
|
.ui-priority-primary,
|
||||||
|
.ui-widget-content .ui-priority-primary,
|
||||||
|
.ui-widget-header .ui-priority-primary {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ui-priority-secondary,
|
||||||
|
.ui-widget-content .ui-priority-secondary,
|
||||||
|
.ui-widget-header .ui-priority-secondary {
|
||||||
|
opacity: .7;
|
||||||
|
filter:Alpha(Opacity=70); /* support: IE8 */
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.ui-state-disabled,
|
||||||
|
.ui-widget-content .ui-state-disabled,
|
||||||
|
.ui-widget-header .ui-state-disabled {
|
||||||
|
opacity: .35;
|
||||||
|
filter:Alpha(Opacity=35); /* support: IE8 */
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.ui-state-disabled .ui-icon {
|
||||||
|
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* states and images */
|
||||||
|
.ui-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
.ui-icon,
|
||||||
|
.ui-widget-content .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_cccccc_256x240.png");
|
||||||
|
}
|
||||||
|
.ui-widget-header .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_ffffff_256x240.png");
|
||||||
|
}
|
||||||
|
.ui-state-default .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_cccccc_256x240.png");
|
||||||
|
}
|
||||||
|
.ui-state-hover .ui-icon,
|
||||||
|
.ui-state-focus .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_ffffff_256x240.png");
|
||||||
|
}
|
||||||
|
.ui-state-active .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_222222_256x240.png");
|
||||||
|
}
|
||||||
|
.ui-state-highlight .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_4b8e0b_256x240.png");
|
||||||
|
}
|
||||||
|
.ui-state-error .ui-icon,
|
||||||
|
.ui-state-error-text .ui-icon {
|
||||||
|
background-image: url("images/ui-icons_a83300_256x240.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* positioning */
|
||||||
|
.ui-icon-blank { background-position: 16px 16px; }
|
||||||
|
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||||
|
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||||
|
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||||
|
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||||
|
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||||
|
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||||
|
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||||
|
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||||
|
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||||
|
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||||
|
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||||
|
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||||
|
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||||
|
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||||
|
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||||
|
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||||
|
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||||
|
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||||
|
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||||
|
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||||
|
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||||
|
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||||
|
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||||
|
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||||
|
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||||
|
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||||
|
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||||
|
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||||
|
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||||
|
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||||
|
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||||
|
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||||
|
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||||
|
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||||
|
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||||
|
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||||
|
.ui-icon-extlink { background-position: -32px -80px; }
|
||||||
|
.ui-icon-newwin { background-position: -48px -80px; }
|
||||||
|
.ui-icon-refresh { background-position: -64px -80px; }
|
||||||
|
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||||
|
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||||
|
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||||
|
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||||
|
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||||
|
.ui-icon-document { background-position: -32px -96px; }
|
||||||
|
.ui-icon-document-b { background-position: -48px -96px; }
|
||||||
|
.ui-icon-note { background-position: -64px -96px; }
|
||||||
|
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||||
|
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||||
|
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||||
|
.ui-icon-comment { background-position: -128px -96px; }
|
||||||
|
.ui-icon-person { background-position: -144px -96px; }
|
||||||
|
.ui-icon-print { background-position: -160px -96px; }
|
||||||
|
.ui-icon-trash { background-position: -176px -96px; }
|
||||||
|
.ui-icon-locked { background-position: -192px -96px; }
|
||||||
|
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||||
|
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||||
|
.ui-icon-tag { background-position: -240px -96px; }
|
||||||
|
.ui-icon-home { background-position: 0 -112px; }
|
||||||
|
.ui-icon-flag { background-position: -16px -112px; }
|
||||||
|
.ui-icon-calendar { background-position: -32px -112px; }
|
||||||
|
.ui-icon-cart { background-position: -48px -112px; }
|
||||||
|
.ui-icon-pencil { background-position: -64px -112px; }
|
||||||
|
.ui-icon-clock { background-position: -80px -112px; }
|
||||||
|
.ui-icon-disk { background-position: -96px -112px; }
|
||||||
|
.ui-icon-calculator { background-position: -112px -112px; }
|
||||||
|
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||||
|
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||||
|
.ui-icon-search { background-position: -160px -112px; }
|
||||||
|
.ui-icon-wrench { background-position: -176px -112px; }
|
||||||
|
.ui-icon-gear { background-position: -192px -112px; }
|
||||||
|
.ui-icon-heart { background-position: -208px -112px; }
|
||||||
|
.ui-icon-star { background-position: -224px -112px; }
|
||||||
|
.ui-icon-link { background-position: -240px -112px; }
|
||||||
|
.ui-icon-cancel { background-position: 0 -128px; }
|
||||||
|
.ui-icon-plus { background-position: -16px -128px; }
|
||||||
|
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||||
|
.ui-icon-minus { background-position: -48px -128px; }
|
||||||
|
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||||
|
.ui-icon-close { background-position: -80px -128px; }
|
||||||
|
.ui-icon-closethick { background-position: -96px -128px; }
|
||||||
|
.ui-icon-key { background-position: -112px -128px; }
|
||||||
|
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||||
|
.ui-icon-scissors { background-position: -144px -128px; }
|
||||||
|
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||||
|
.ui-icon-copy { background-position: -176px -128px; }
|
||||||
|
.ui-icon-contact { background-position: -192px -128px; }
|
||||||
|
.ui-icon-image { background-position: -208px -128px; }
|
||||||
|
.ui-icon-video { background-position: -224px -128px; }
|
||||||
|
.ui-icon-script { background-position: -240px -128px; }
|
||||||
|
.ui-icon-alert { background-position: 0 -144px; }
|
||||||
|
.ui-icon-info { background-position: -16px -144px; }
|
||||||
|
.ui-icon-notice { background-position: -32px -144px; }
|
||||||
|
.ui-icon-help { background-position: -48px -144px; }
|
||||||
|
.ui-icon-check { background-position: -64px -144px; }
|
||||||
|
.ui-icon-bullet { background-position: -80px -144px; }
|
||||||
|
.ui-icon-radio-on { background-position: -96px -144px; }
|
||||||
|
.ui-icon-radio-off { background-position: -112px -144px; }
|
||||||
|
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||||
|
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||||
|
.ui-icon-play { background-position: 0 -160px; }
|
||||||
|
.ui-icon-pause { background-position: -16px -160px; }
|
||||||
|
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||||
|
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||||
|
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||||
|
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||||
|
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||||
|
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||||
|
.ui-icon-stop { background-position: -96px -160px; }
|
||||||
|
.ui-icon-eject { background-position: -112px -160px; }
|
||||||
|
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||||
|
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||||
|
.ui-icon-power { background-position: 0 -176px; }
|
||||||
|
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||||
|
.ui-icon-signal { background-position: -32px -176px; }
|
||||||
|
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||||
|
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||||
|
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||||
|
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||||
|
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||||
|
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||||
|
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||||
|
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||||
|
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||||
|
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||||
|
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||||
|
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||||
|
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||||
|
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||||
|
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||||
|
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||||
|
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||||
|
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||||
|
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||||
|
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||||
|
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||||
|
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||||
|
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||||
|
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||||
|
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||||
|
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||||
|
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||||
|
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||||
|
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||||
|
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc visuals
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* Corner radius */
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-top,
|
||||||
|
.ui-corner-left,
|
||||||
|
.ui-corner-tl {
|
||||||
|
border-top-left-radius: 6px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-top,
|
||||||
|
.ui-corner-right,
|
||||||
|
.ui-corner-tr {
|
||||||
|
border-top-right-radius: 6px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-bottom,
|
||||||
|
.ui-corner-left,
|
||||||
|
.ui-corner-bl {
|
||||||
|
border-bottom-left-radius: 6px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-bottom,
|
||||||
|
.ui-corner-right,
|
||||||
|
.ui-corner-br {
|
||||||
|
border-bottom-right-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.ui-widget-overlay {
|
||||||
|
background: #5c5c5c url("images/ui-bg_flat_50_5c5c5c_40x100.png") 50% 50% repeat-x;
|
||||||
|
opacity: .8;
|
||||||
|
filter: Alpha(Opacity=80); /* support: IE8 */
|
||||||
|
}
|
||||||
|
.ui-widget-shadow {
|
||||||
|
margin: -7px 0 0 -7px;
|
||||||
|
padding: 7px;
|
||||||
|
background: #cccccc url("images/ui-bg_flat_30_cccccc_40x100.png") 50% 50% repeat-x;
|
||||||
|
opacity: .6;
|
||||||
|
filter: Alpha(Opacity=60); /* support: IE8 */
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
5
configs/lighttpd/css/external/jquery-ui.theme.min.css
vendored
Normal file
BIN
configs/lighttpd/css/images/spinner.gif
Normal file
After Width: | Height: | Size: 1.8 KiB |
17
configs/lighttpd/css/weather.css
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
.ui-wait-button .ui-icon-waiting {
|
||||||
|
background-image: url("images/spinner.gif");
|
||||||
|
background-position: 0 center;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Verdana,Arial,sans-serif;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
32
configs/lighttpd/css/wind_field.css
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
body {
|
||||||
|
background-color: #000000;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
.wind-arrow {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #ffffff;
|
||||||
|
}
|
||||||
|
.wind-arrow-0 {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #ffffff;
|
||||||
|
}
|
||||||
|
.wind-arrow-5 {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #00ff00;
|
||||||
|
}
|
||||||
|
.wind-arrow-10 {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #66ff00;
|
||||||
|
}
|
||||||
|
.wind-arrow-15 {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #ffff00;
|
||||||
|
}
|
||||||
|
.wind-arrow-20 {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #ff6600;
|
||||||
|
}
|
||||||
|
.wind-arrow-25 {
|
||||||
|
fill: #ff0000;
|
||||||
|
stroke: #ff0000;
|
||||||
|
}
|
11
configs/lighttpd/index.html.webroot
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Pi Webserver</title>
|
||||||
|
<META http-equiv="refresh" content="5;URL=/~pi/">
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#ffffff">
|
||||||
|
<center>This is not the web page you're looking for... <A HREF="/~pi/">move along, move along</a>
|
||||||
|
</center>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
3
configs/lighttpd/info.php
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
phpinfo();
|
||||||
|
?>
|
513
configs/lighttpd/jquery-ui.html
Normal file
|
@ -0,0 +1,513 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="us">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>jQuery UI Example Page</title>
|
||||||
|
<link href="css/external/jquery-ui.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
font: 62.5% "Trebuchet MS", sans-serif;
|
||||||
|
margin: 50px;
|
||||||
|
}
|
||||||
|
.demoHeaders {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
#dialog-link {
|
||||||
|
padding: .4em 1em .4em 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#dialog-link span.ui-icon {
|
||||||
|
margin: 0 5px 0 0;
|
||||||
|
position: absolute;
|
||||||
|
left: .2em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
#icons {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#icons li {
|
||||||
|
margin: 2px;
|
||||||
|
position: relative;
|
||||||
|
padding: 4px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
float: left;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#icons span.ui-icon {
|
||||||
|
float: left;
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
.fakewindowcontain .ui-widget-overlay {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Welcome to jQuery UI!</h1>
|
||||||
|
|
||||||
|
<div class="ui-widget">
|
||||||
|
<p>This page demonstrates the widgets and theme you selected in Download Builder. Please make sure you are using them with a compatible jQuery version.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>YOUR COMPONENTS:</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Accordion -->
|
||||||
|
<h2 class="demoHeaders">Accordion</h2>
|
||||||
|
<div id="accordion">
|
||||||
|
<h3>First</h3>
|
||||||
|
<div>Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.</div>
|
||||||
|
<h3>Second</h3>
|
||||||
|
<div>Phasellus mattis tincidunt nibh.</div>
|
||||||
|
<h3>Third</h3>
|
||||||
|
<div>Nam dui erat, auctor a, dignissim quis.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Autocomplete -->
|
||||||
|
<h2 class="demoHeaders">Autocomplete</h2>
|
||||||
|
<div>
|
||||||
|
<input id="autocomplete" title="type "a"">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Button -->
|
||||||
|
<h2 class="demoHeaders">Button</h2>
|
||||||
|
<button id="button">A button element</button>
|
||||||
|
<form style="margin-top: 1em;">
|
||||||
|
<div id="radioset">
|
||||||
|
<input type="radio" id="radio1" name="radio"><label for="radio1">Choice 1</label>
|
||||||
|
<input type="radio" id="radio2" name="radio" checked="checked"><label for="radio2">Choice 2</label>
|
||||||
|
<input type="radio" id="radio3" name="radio"><label for="radio3">Choice 3</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Tabs -->
|
||||||
|
<h2 class="demoHeaders">Tabs</h2>
|
||||||
|
<div id="tabs">
|
||||||
|
<ul>
|
||||||
|
<li><a href="#tabs-1">First</a></li>
|
||||||
|
<li><a href="#tabs-2">Second</a></li>
|
||||||
|
<li><a href="#tabs-3">Third</a></li>
|
||||||
|
</ul>
|
||||||
|
<div id="tabs-1">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
|
||||||
|
<div id="tabs-2">Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum.</div>
|
||||||
|
<div id="tabs-3">Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Dialog NOTE: Dialog is not generated by UI in this demo so it can be visually styled in themeroller-->
|
||||||
|
<h2 class="demoHeaders">Dialog</h2>
|
||||||
|
<p><a href="#" id="dialog-link" class="ui-state-default ui-corner-all"><span class="ui-icon ui-icon-newwin"></span>Open Dialog</a></p>
|
||||||
|
|
||||||
|
<h2 class="demoHeaders">Overlay and Shadow Classes <em>(not currently used in UI widgets)</em></h2>
|
||||||
|
<div style="position: relative; width: 96%; height: 200px; padding:1% 2%; overflow:hidden;" class="fakewindowcontain">
|
||||||
|
<p>Lorem ipsum dolor sit amet, Nulla nec tortor. Donec id elit quis purus consectetur consequat. </p><p>Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. </p><p>Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. </p><p>Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. </p><p>Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. </p><p>Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. </p>
|
||||||
|
|
||||||
|
<!-- ui-dialog -->
|
||||||
|
<div class="ui-overlay"><div class="ui-widget-overlay"></div><div class="ui-widget-shadow ui-corner-all" style="width: 302px; height: 152px; position: absolute; left: 50px; top: 30px;"></div></div>
|
||||||
|
<div style="position: absolute; width: 280px; height: 130px;left: 50px; top: 30px; padding: 10px;" class="ui-widget ui-widget-content ui-corner-all">
|
||||||
|
<div class="ui-dialog-content ui-widget-content" style="background: none; border: 0;">
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ui-dialog -->
|
||||||
|
<div id="dialog" title="Dialog Title">
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 class="demoHeaders">Framework Icons (content color preview)</h2>
|
||||||
|
<ul id="icons" class="ui-widget ui-helper-clearfix">
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-n"><span class="ui-icon ui-icon-carat-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-ne"><span class="ui-icon ui-icon-carat-1-ne"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-e"><span class="ui-icon ui-icon-carat-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-se"><span class="ui-icon ui-icon-carat-1-se"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-s"><span class="ui-icon ui-icon-carat-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-sw"><span class="ui-icon ui-icon-carat-1-sw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-w"><span class="ui-icon ui-icon-carat-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-1-nw"><span class="ui-icon ui-icon-carat-1-nw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-2-n-s"><span class="ui-icon ui-icon-carat-2-n-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-carat-2-e-w"><span class="ui-icon ui-icon-carat-2-e-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-n"><span class="ui-icon ui-icon-triangle-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-ne"><span class="ui-icon ui-icon-triangle-1-ne"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-e"><span class="ui-icon ui-icon-triangle-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-se"><span class="ui-icon ui-icon-triangle-1-se"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-s"><span class="ui-icon ui-icon-triangle-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-sw"><span class="ui-icon ui-icon-triangle-1-sw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-w"><span class="ui-icon ui-icon-triangle-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-1-nw"><span class="ui-icon ui-icon-triangle-1-nw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-2-n-s"><span class="ui-icon ui-icon-triangle-2-n-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-triangle-2-e-w"><span class="ui-icon ui-icon-triangle-2-e-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-n"><span class="ui-icon ui-icon-arrow-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-ne"><span class="ui-icon ui-icon-arrow-1-ne"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-e"><span class="ui-icon ui-icon-arrow-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-se"><span class="ui-icon ui-icon-arrow-1-se"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-s"><span class="ui-icon ui-icon-arrow-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-sw"><span class="ui-icon ui-icon-arrow-1-sw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-w"><span class="ui-icon ui-icon-arrow-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-1-nw"><span class="ui-icon ui-icon-arrow-1-nw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-n-s"><span class="ui-icon ui-icon-arrow-2-n-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-ne-sw"><span class="ui-icon ui-icon-arrow-2-ne-sw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-e-w"><span class="ui-icon ui-icon-arrow-2-e-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-2-se-nw"><span class="ui-icon ui-icon-arrow-2-se-nw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-n"><span class="ui-icon ui-icon-arrowstop-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-e"><span class="ui-icon ui-icon-arrowstop-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-s"><span class="ui-icon ui-icon-arrowstop-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowstop-1-w"><span class="ui-icon ui-icon-arrowstop-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-n"><span class="ui-icon ui-icon-arrowthick-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-ne"><span class="ui-icon ui-icon-arrowthick-1-ne"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-e"><span class="ui-icon ui-icon-arrowthick-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-se"><span class="ui-icon ui-icon-arrowthick-1-se"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-s"><span class="ui-icon ui-icon-arrowthick-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-sw"><span class="ui-icon ui-icon-arrowthick-1-sw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-w"><span class="ui-icon ui-icon-arrowthick-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-1-nw"><span class="ui-icon ui-icon-arrowthick-1-nw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-n-s"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-ne-sw"><span class="ui-icon ui-icon-arrowthick-2-ne-sw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-e-w"><span class="ui-icon ui-icon-arrowthick-2-e-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthick-2-se-nw"><span class="ui-icon ui-icon-arrowthick-2-se-nw"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-n"><span class="ui-icon ui-icon-arrowthickstop-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-e"><span class="ui-icon ui-icon-arrowthickstop-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-s"><span class="ui-icon ui-icon-arrowthickstop-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowthickstop-1-w"><span class="ui-icon ui-icon-arrowthickstop-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-w"><span class="ui-icon ui-icon-arrowreturnthick-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-n"><span class="ui-icon ui-icon-arrowreturnthick-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-e"><span class="ui-icon ui-icon-arrowreturnthick-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturnthick-1-s"><span class="ui-icon ui-icon-arrowreturnthick-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-w"><span class="ui-icon ui-icon-arrowreturn-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-n"><span class="ui-icon ui-icon-arrowreturn-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-e"><span class="ui-icon ui-icon-arrowreturn-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowreturn-1-s"><span class="ui-icon ui-icon-arrowreturn-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-w"><span class="ui-icon ui-icon-arrowrefresh-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-n"><span class="ui-icon ui-icon-arrowrefresh-1-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-e"><span class="ui-icon ui-icon-arrowrefresh-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrowrefresh-1-s"><span class="ui-icon ui-icon-arrowrefresh-1-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-4"><span class="ui-icon ui-icon-arrow-4"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-arrow-4-diag"><span class="ui-icon ui-icon-arrow-4-diag"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-extlink"><span class="ui-icon ui-icon-extlink"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-newwin"><span class="ui-icon ui-icon-newwin"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-refresh"><span class="ui-icon ui-icon-refresh"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-shuffle"><span class="ui-icon ui-icon-shuffle"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-transfer-e-w"><span class="ui-icon ui-icon-transfer-e-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-transferthick-e-w"><span class="ui-icon ui-icon-transferthick-e-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-folder-collapsed"><span class="ui-icon ui-icon-folder-collapsed"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-folder-open"><span class="ui-icon ui-icon-folder-open"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-document"><span class="ui-icon ui-icon-document"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-document-b"><span class="ui-icon ui-icon-document-b"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-note"><span class="ui-icon ui-icon-note"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-mail-closed"><span class="ui-icon ui-icon-mail-closed"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-mail-open"><span class="ui-icon ui-icon-mail-open"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-suitcase"><span class="ui-icon ui-icon-suitcase"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-comment"><span class="ui-icon ui-icon-comment"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-person"><span class="ui-icon ui-icon-person"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-print"><span class="ui-icon ui-icon-print"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-trash"><span class="ui-icon ui-icon-trash"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-locked"><span class="ui-icon ui-icon-locked"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-unlocked"><span class="ui-icon ui-icon-unlocked"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-bookmark"><span class="ui-icon ui-icon-bookmark"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-tag"><span class="ui-icon ui-icon-tag"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-home"><span class="ui-icon ui-icon-home"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-flag"><span class="ui-icon ui-icon-flag"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-calculator"><span class="ui-icon ui-icon-calculator"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-cart"><span class="ui-icon ui-icon-cart"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-pencil"><span class="ui-icon ui-icon-pencil"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-clock"><span class="ui-icon ui-icon-clock"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-disk"><span class="ui-icon ui-icon-disk"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-calendar"><span class="ui-icon ui-icon-calendar"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-zoomin"><span class="ui-icon ui-icon-zoomin"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-zoomout"><span class="ui-icon ui-icon-zoomout"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-search"><span class="ui-icon ui-icon-search"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-wrench"><span class="ui-icon ui-icon-wrench"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-gear"><span class="ui-icon ui-icon-gear"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-heart"><span class="ui-icon ui-icon-heart"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-star"><span class="ui-icon ui-icon-star"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-link"><span class="ui-icon ui-icon-link"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-cancel"><span class="ui-icon ui-icon-cancel"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-plus"><span class="ui-icon ui-icon-plus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-plusthick"><span class="ui-icon ui-icon-plusthick"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-minus"><span class="ui-icon ui-icon-minus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-minusthick"><span class="ui-icon ui-icon-minusthick"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-close"><span class="ui-icon ui-icon-close"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-closethick"><span class="ui-icon ui-icon-closethick"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-key"><span class="ui-icon ui-icon-key"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-lightbulb"><span class="ui-icon ui-icon-lightbulb"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-scissors"><span class="ui-icon ui-icon-scissors"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-clipboard"><span class="ui-icon ui-icon-clipboard"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-copy"><span class="ui-icon ui-icon-copy"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-contact"><span class="ui-icon ui-icon-contact"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-image"><span class="ui-icon ui-icon-image"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-video"><span class="ui-icon ui-icon-video"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-script"><span class="ui-icon ui-icon-script"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-alert"><span class="ui-icon ui-icon-alert"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-info"><span class="ui-icon ui-icon-info"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-notice"><span class="ui-icon ui-icon-notice"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-help"><span class="ui-icon ui-icon-help"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-check"><span class="ui-icon ui-icon-check"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-bullet"><span class="ui-icon ui-icon-bullet"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-radio-off"><span class="ui-icon ui-icon-radio-off"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-radio-on"><span class="ui-icon ui-icon-radio-on"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-pin-w"><span class="ui-icon ui-icon-pin-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-pin-s"><span class="ui-icon ui-icon-pin-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-play"><span class="ui-icon ui-icon-play"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-pause"><span class="ui-icon ui-icon-pause"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-next"><span class="ui-icon ui-icon-seek-next"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-prev"><span class="ui-icon ui-icon-seek-prev"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-end"><span class="ui-icon ui-icon-seek-end"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-seek-first"><span class="ui-icon ui-icon-seek-first"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-stop"><span class="ui-icon ui-icon-stop"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-eject"><span class="ui-icon ui-icon-eject"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-volume-off"><span class="ui-icon ui-icon-volume-off"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-volume-on"><span class="ui-icon ui-icon-volume-on"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-power"><span class="ui-icon ui-icon-power"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-signal-diag"><span class="ui-icon ui-icon-signal-diag"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-signal"><span class="ui-icon ui-icon-signal"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-0"><span class="ui-icon ui-icon-battery-0"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-1"><span class="ui-icon ui-icon-battery-1"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-2"><span class="ui-icon ui-icon-battery-2"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-battery-3"><span class="ui-icon ui-icon-battery-3"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-plus"><span class="ui-icon ui-icon-circle-plus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-minus"><span class="ui-icon ui-icon-circle-minus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-close"><span class="ui-icon ui-icon-circle-close"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-e"><span class="ui-icon ui-icon-circle-triangle-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-s"><span class="ui-icon ui-icon-circle-triangle-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-w"><span class="ui-icon ui-icon-circle-triangle-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-triangle-n"><span class="ui-icon ui-icon-circle-triangle-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-e"><span class="ui-icon ui-icon-circle-arrow-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-s"><span class="ui-icon ui-icon-circle-arrow-s"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-w"><span class="ui-icon ui-icon-circle-arrow-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-arrow-n"><span class="ui-icon ui-icon-circle-arrow-n"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-zoomin"><span class="ui-icon ui-icon-circle-zoomin"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-zoomout"><span class="ui-icon ui-icon-circle-zoomout"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circle-check"><span class="ui-icon ui-icon-circle-check"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circlesmall-plus"><span class="ui-icon ui-icon-circlesmall-plus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circlesmall-minus"><span class="ui-icon ui-icon-circlesmall-minus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-circlesmall-close"><span class="ui-icon ui-icon-circlesmall-close"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-squaresmall-plus"><span class="ui-icon ui-icon-squaresmall-plus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-squaresmall-minus"><span class="ui-icon ui-icon-squaresmall-minus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-squaresmall-close"><span class="ui-icon ui-icon-squaresmall-close"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-dotted-vertical"><span class="ui-icon ui-icon-grip-dotted-vertical"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-dotted-horizontal"><span class="ui-icon ui-icon-grip-dotted-horizontal"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-solid-vertical"><span class="ui-icon ui-icon-grip-solid-vertical"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-solid-horizontal"><span class="ui-icon ui-icon-grip-solid-horizontal"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-gripsmall-diagonal-se"><span class="ui-icon ui-icon-gripsmall-diagonal-se"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-diagonal-se"><span class="ui-icon ui-icon-grip-diagonal-se"></span></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Slider -->
|
||||||
|
<h2 class="demoHeaders">Slider</h2>
|
||||||
|
<div id="slider"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Datepicker -->
|
||||||
|
<h2 class="demoHeaders">Datepicker</h2>
|
||||||
|
<div id="datepicker"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Progressbar -->
|
||||||
|
<h2 class="demoHeaders">Progressbar</h2>
|
||||||
|
<div id="progressbar"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Progressbar -->
|
||||||
|
<h2 class="demoHeaders">Selectmenu</h2>
|
||||||
|
<select id="selectmenu">
|
||||||
|
<option>Slower</option>
|
||||||
|
<option>Slow</option>
|
||||||
|
<option selected="selected">Medium</option>
|
||||||
|
<option>Fast</option>
|
||||||
|
<option>Faster</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Spinner -->
|
||||||
|
<h2 class="demoHeaders">Spinner</h2>
|
||||||
|
<input id="spinner">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<h2 class="demoHeaders">Menu</h2>
|
||||||
|
<ul style="width:100px;" id="menu">
|
||||||
|
<li>Item 1</li>
|
||||||
|
<li>Item 2</li>
|
||||||
|
<li>Item 3
|
||||||
|
<ul>
|
||||||
|
<li>Item 3-1</li>
|
||||||
|
<li>Item 3-2</li>
|
||||||
|
<li>Item 3-3</li>
|
||||||
|
<li>Item 3-4</li>
|
||||||
|
<li>Item 3-5</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Item 4</li>
|
||||||
|
<li>Item 5</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Tooltip -->
|
||||||
|
<h2 class="demoHeaders">Tooltip</h2>
|
||||||
|
<p id="tooltip">
|
||||||
|
<a href="#" title="That's what this widget is">Tooltips</a> can be attached to any element. When you hover
|
||||||
|
the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Highlight / Error -->
|
||||||
|
<h2 class="demoHeaders">Highlight / Error</h2>
|
||||||
|
<div class="ui-widget">
|
||||||
|
<div class="ui-state-highlight ui-corner-all" style="margin-top: 20px; padding: 0 .7em;">
|
||||||
|
<p><span class="ui-icon ui-icon-info" style="float: left; margin-right: .3em;"></span>
|
||||||
|
<strong>Hey!</strong> Sample ui-state-highlight style.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="ui-widget">
|
||||||
|
<div class="ui-state-error ui-corner-all" style="padding: 0 .7em;">
|
||||||
|
<p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span>
|
||||||
|
<strong>Alert:</strong> Sample ui-state-error style.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="js/external/jquery.js"></script>
|
||||||
|
<script src="js/external/jquery-ui.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$( "#accordion" ).accordion();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var availableTags = [
|
||||||
|
"ActionScript",
|
||||||
|
"AppleScript",
|
||||||
|
"Asp",
|
||||||
|
"BASIC",
|
||||||
|
"C",
|
||||||
|
"C++",
|
||||||
|
"Clojure",
|
||||||
|
"COBOL",
|
||||||
|
"ColdFusion",
|
||||||
|
"Erlang",
|
||||||
|
"Fortran",
|
||||||
|
"Groovy",
|
||||||
|
"Haskell",
|
||||||
|
"Java",
|
||||||
|
"JavaScript",
|
||||||
|
"Lisp",
|
||||||
|
"Perl",
|
||||||
|
"PHP",
|
||||||
|
"Python",
|
||||||
|
"Ruby",
|
||||||
|
"Scala",
|
||||||
|
"Scheme"
|
||||||
|
];
|
||||||
|
$( "#autocomplete" ).autocomplete({
|
||||||
|
source: availableTags
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#button" ).button();
|
||||||
|
$( "#radioset" ).buttonset();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#tabs" ).tabs();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#dialog" ).dialog({
|
||||||
|
autoOpen: false,
|
||||||
|
width: 400,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: "Ok",
|
||||||
|
click: function() {
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Cancel",
|
||||||
|
click: function() {
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Link to open the dialog
|
||||||
|
$( "#dialog-link" ).click(function( event ) {
|
||||||
|
$( "#dialog" ).dialog( "open" );
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#datepicker" ).datepicker({
|
||||||
|
inline: true
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#slider" ).slider({
|
||||||
|
range: true,
|
||||||
|
values: [ 17, 67 ]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#progressbar" ).progressbar({
|
||||||
|
value: 20
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#spinner" ).spinner();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#menu" ).menu();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#tooltip" ).tooltip();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$( "#selectmenu" ).selectmenu();
|
||||||
|
|
||||||
|
|
||||||
|
// Hover states on the static widgets
|
||||||
|
$( "#dialog-link, #icons li" ).hover(
|
||||||
|
function() {
|
||||||
|
$( this ).addClass( "ui-state-hover" );
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
$( this ).removeClass( "ui-state-hover" );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
11
configs/lighttpd/js/c3test.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
$(document).ready(function(){
|
||||||
|
var chart = c3.generate({
|
||||||
|
bindto: '#chart',
|
||||||
|
data: {
|
||||||
|
columns: [
|
||||||
|
['data1', 30, 200, 100, 400, 150, 250],
|
||||||
|
['data2', 50, 20, 10, 40, 15, 25]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
6799
configs/lighttpd/js/external/c3.js
vendored
Normal file
5
configs/lighttpd/js/external/c3.min.js
vendored
Normal file
9470
configs/lighttpd/js/external/d3.js
vendored
Normal file
5
configs/lighttpd/js/external/d3.min.js
vendored
Normal file
16582
configs/lighttpd/js/external/jquery-ui.js
vendored
Normal file
13
configs/lighttpd/js/external/jquery-ui.min.js
vendored
Normal file
117
configs/lighttpd/js/external/jquery.cookie.js
vendored
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*!
|
||||||
|
* jQuery Cookie Plugin v1.4.1
|
||||||
|
* https://github.com/carhartl/jquery-cookie
|
||||||
|
*
|
||||||
|
* Copyright 2013 Klaus Hartl
|
||||||
|
* Released under the MIT license
|
||||||
|
*/
|
||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
}(function ($) {
|
||||||
|
|
||||||
|
var pluses = /\+/g;
|
||||||
|
|
||||||
|
function encode(s) {
|
||||||
|
return config.raw ? s : encodeURIComponent(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decode(s) {
|
||||||
|
return config.raw ? s : decodeURIComponent(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyCookieValue(value) {
|
||||||
|
return encode(config.json ? JSON.stringify(value) : String(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCookieValue(s) {
|
||||||
|
if (s.indexOf('"') === 0) {
|
||||||
|
// This is a quoted cookie as according to RFC2068, unescape...
|
||||||
|
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Replace server-side written pluses with spaces.
|
||||||
|
// If we can't decode the cookie, ignore it, it's unusable.
|
||||||
|
// If we can't parse the cookie, ignore it, it's unusable.
|
||||||
|
s = decodeURIComponent(s.replace(pluses, ' '));
|
||||||
|
return config.json ? JSON.parse(s) : s;
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read(s, converter) {
|
||||||
|
var value = config.raw ? s : parseCookieValue(s);
|
||||||
|
return $.isFunction(converter) ? converter(value) : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = $.cookie = function (key, value, options) {
|
||||||
|
|
||||||
|
// Write
|
||||||
|
|
||||||
|
if (value !== undefined && !$.isFunction(value)) {
|
||||||
|
options = $.extend({}, config.defaults, options);
|
||||||
|
|
||||||
|
if (typeof options.expires === 'number') {
|
||||||
|
var days = options.expires, t = options.expires = new Date();
|
||||||
|
t.setTime(+t + days * 864e+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (document.cookie = [
|
||||||
|
encode(key), '=', stringifyCookieValue(value),
|
||||||
|
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
||||||
|
options.path ? '; path=' + options.path : '',
|
||||||
|
options.domain ? '; domain=' + options.domain : '',
|
||||||
|
options.secure ? '; secure' : ''
|
||||||
|
].join(''));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read
|
||||||
|
|
||||||
|
var result = key ? undefined : {};
|
||||||
|
|
||||||
|
// To prevent the for loop in the first place assign an empty array
|
||||||
|
// in case there are no cookies at all. Also prevents odd result when
|
||||||
|
// calling $.cookie().
|
||||||
|
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||||
|
|
||||||
|
for (var i = 0, l = cookies.length; i < l; i++) {
|
||||||
|
var parts = cookies[i].split('=');
|
||||||
|
var name = decode(parts.shift());
|
||||||
|
var cookie = parts.join('=');
|
||||||
|
|
||||||
|
if (key && key === name) {
|
||||||
|
// If second argument (value) is a function it's a converter...
|
||||||
|
result = read(cookie, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent storing a cookie that we couldn't decode.
|
||||||
|
if (!key && (cookie = read(cookie)) !== undefined) {
|
||||||
|
result[name] = cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
config.defaults = {};
|
||||||
|
|
||||||
|
$.removeCookie = function (key, options) {
|
||||||
|
if ($.cookie(key) === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must not alter options, thus extending a fresh object...
|
||||||
|
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
|
||||||
|
return !$.cookie(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
}));
|
9205
configs/lighttpd/js/external/jquery.js
vendored
Normal file
4
configs/lighttpd/js/external/jquery.min.js
vendored
Normal file
2936
configs/lighttpd/js/external/moment.js
vendored
Normal file
736
configs/lighttpd/js/weather.js
Normal file
|
@ -0,0 +1,736 @@
|
||||||
|
// WeatherPi main script of doom
|
||||||
|
// Donald Burr, VCT Labs
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cookie stuff: http://plugins.jquery.com/cookie/
|
||||||
|
*
|
||||||
|
* Set a cookie
|
||||||
|
*
|
||||||
|
* Simple cookie with no options
|
||||||
|
* $.cookie("example", "foo");
|
||||||
|
*
|
||||||
|
* Cookie that expires after 7 days
|
||||||
|
* $.cookie("example", "foo", { expires: 7 });
|
||||||
|
*
|
||||||
|
* Cookie that expires after 7 days and is only valid for site paths under /admin
|
||||||
|
* $.cookie("example", "foo", { path: '/admin', expires: 7 }); // Sample 3
|
||||||
|
*
|
||||||
|
* Get a cookie
|
||||||
|
*
|
||||||
|
* alert( $.cookie("example") );
|
||||||
|
*
|
||||||
|
* Get all cookies
|
||||||
|
*
|
||||||
|
* $.cookie();
|
||||||
|
*
|
||||||
|
* Delete the cookie.
|
||||||
|
* Returns true if delete was successful, otherwise false
|
||||||
|
* NOTE: for deletion to work you must use same attributes (path, expires, etc.) as when the cookie was created
|
||||||
|
*
|
||||||
|
* $.removeCookie("example");
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Message pane: http://stackoverflow.com/questions/5267569/display-messages-with-jquery-ui
|
||||||
|
|
||||||
|
// up arrow = ↑ ↑
|
||||||
|
// down arrow = ↓ ↓
|
||||||
|
// bar = ― ―
|
||||||
|
|
||||||
|
// Default configuration options
|
||||||
|
var defaults = [["time_format", "local", "form-time"], ["temperature_units", "celsius", "form-temperature_units"], ["refresh_interval", "60", "form-refresh_interval"]];
|
||||||
|
|
||||||
|
// keep track of stuff
|
||||||
|
var current_temperature = 0;
|
||||||
|
var last_temperature;
|
||||||
|
var highest_temperature;
|
||||||
|
var lowest_temperature;
|
||||||
|
var highest_temperature_timestamp;
|
||||||
|
var lowest_temperature_timestamp;
|
||||||
|
|
||||||
|
// keep track of stuff
|
||||||
|
var current_pressure = 0;
|
||||||
|
var last_pressure;
|
||||||
|
var highest_pressure;
|
||||||
|
var lowest_pressure;
|
||||||
|
var highest_pressure_timestamp;
|
||||||
|
var lowest_pressure_timestamp;
|
||||||
|
|
||||||
|
// keep track of stuff
|
||||||
|
var current_humidity = 0;
|
||||||
|
var last_humidity;
|
||||||
|
var highest_humidity;
|
||||||
|
var lowest_humidity;
|
||||||
|
var highest_humidity_timestamp;
|
||||||
|
var lowest_humidity_timestamp;
|
||||||
|
|
||||||
|
// keep track of stuff
|
||||||
|
var current_dewpoint = 0;
|
||||||
|
var last_dewpoint;
|
||||||
|
var highest_dewpoint;
|
||||||
|
var lowest_dewpoint;
|
||||||
|
var highest_dewpoint_timestamp;
|
||||||
|
var lowest_dewpoint_timestamp;
|
||||||
|
|
||||||
|
// Set to 0 to disable debugging, 1+ to enable debugging (higher = more verbose)
|
||||||
|
var DEBUG_LEVEL = 1;
|
||||||
|
|
||||||
|
// debug logging
|
||||||
|
function LOG(level, msg)
|
||||||
|
{
|
||||||
|
if (DEBUG_LEVEL > 0 && DEBUG_LEVEL >= level) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function, runs automatically at document-ready (i.e. when the page is finished loading)
|
||||||
|
$(document).ready(function(){
|
||||||
|
// set up default options if not present
|
||||||
|
setup_defaults();
|
||||||
|
|
||||||
|
// load historical data (if available)
|
||||||
|
load_historical_data();
|
||||||
|
|
||||||
|
// set up clock to update every second
|
||||||
|
setInterval('update_clock()', 1000);
|
||||||
|
|
||||||
|
// set up UI (buttons, etc.)
|
||||||
|
setup_ui_elements();
|
||||||
|
set_unit_labels();
|
||||||
|
|
||||||
|
// set up button handlers
|
||||||
|
setup_button_handlers();
|
||||||
|
|
||||||
|
// update settings ui
|
||||||
|
update_settings_ui();
|
||||||
|
|
||||||
|
// set some default content
|
||||||
|
$( "#tab-historical" ).html("<p>Placeholder - not yet implemented</p>");
|
||||||
|
$( "#tab-windfield" ).html("<p>Placeholder - not yet implemented</p>");
|
||||||
|
|
||||||
|
// populate screen with initial data
|
||||||
|
update_current_display();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up UI elements (tabs, buttons, etc.)
|
||||||
|
function setup_ui_elements()
|
||||||
|
{
|
||||||
|
LOG(1, "setup_ui_elements()");
|
||||||
|
// set title
|
||||||
|
document.title = "WeatherPi @ " + window.location.hostname;
|
||||||
|
$( "#header" ).html("<h1>WeatherPi @ " + window.location.hostname + "</h1>");
|
||||||
|
|
||||||
|
// set up tabs
|
||||||
|
$( "#tabs" ).tabs({
|
||||||
|
create: function(event, ui) {
|
||||||
|
var theTab = ui.tab.index();
|
||||||
|
LOG(1, "INIT tab created " + theTab);
|
||||||
|
set_up_tab(theTab);
|
||||||
|
},
|
||||||
|
activate: function(event, ui) {
|
||||||
|
var theTab = ui.newTab.index();
|
||||||
|
LOG(1, "INIT tab selected " + theTab);
|
||||||
|
set_up_tab(theTab);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// set up dialogs
|
||||||
|
$('#error-dialog').dialog({
|
||||||
|
autoOpen: false,
|
||||||
|
height: 140,
|
||||||
|
modal: true,
|
||||||
|
open: function(event, ui){
|
||||||
|
setTimeout("$('#error-dialog').dialog('close')",3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// set up settings accordion
|
||||||
|
$('#settings_accordion').accordion({heightStyle: 'panel'});
|
||||||
|
|
||||||
|
// set up buttons
|
||||||
|
$( "#button-update" ).button();
|
||||||
|
$( "#button-save_settings" ).button();
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_up_tab(tab)
|
||||||
|
{
|
||||||
|
switch(tab) {
|
||||||
|
case 0: current_tab_selected(); break;
|
||||||
|
case 1: previous_tab_selected(); break;
|
||||||
|
case 2: wind_tab_selected(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_button_handlers()
|
||||||
|
{
|
||||||
|
// handle time set button
|
||||||
|
$("#button-save_settings").click(function (evt) {
|
||||||
|
update_settings();
|
||||||
|
});
|
||||||
|
$("#button-update").click(function(evt) {
|
||||||
|
force_update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_historical_data()
|
||||||
|
{
|
||||||
|
last_temperature = $.cookie("last_temperature");
|
||||||
|
highest_temperature = $.cookie("highest_temperature");
|
||||||
|
lowest_temperature = $.cookie("lowest_temperature");
|
||||||
|
highest_temperature_timestamp = $.cookie("highest_temperature_timestamp");
|
||||||
|
LOG(1, "date cookie load " + highest_temperature_timestamp + " type " + typeof highest_temperature_timestamp);
|
||||||
|
lowest_temperature_timestamp = $.cookie("lowest_temperature_timestamp");
|
||||||
|
if (typeof last_temperature === "undefined") {
|
||||||
|
last_temperature = 0;
|
||||||
|
} else {
|
||||||
|
last_temperature = parseFloat(last_temperature);
|
||||||
|
}
|
||||||
|
if (typeof highest_temperature === "undefined") {
|
||||||
|
LOG(1, "no highest temp, initializing to Number.MIN_VALUE");
|
||||||
|
//highest_temperature = Number.MIN_SAFE_INTEGER;
|
||||||
|
highest_temperature = Number.MIN_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing highest temp of " + highest_temperature);
|
||||||
|
highest_temperature = parseFloat(highest_temperature);
|
||||||
|
LOG(1, "after parse = " + highest_temperature);
|
||||||
|
}
|
||||||
|
if (typeof lowest_temperature === "undefined") {
|
||||||
|
LOG(1, "no lowest temp, initializing to Number.MAX_VALUE");
|
||||||
|
//lowest_temperature = Number.MAX_SAFE_INTEGER;
|
||||||
|
lowest_temperature = Number.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing lowest temp of " + lowest_temperature);
|
||||||
|
lowest_temperature = parseFloat(lowest_temperature);
|
||||||
|
LOG(1, "after parse = " + lowest_temperature);
|
||||||
|
}
|
||||||
|
if (typeof highest_temperature_timestamp === "undefined") {
|
||||||
|
LOG(1, "DATE UNDEFINED");
|
||||||
|
highest_temperature_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
LOG(1, "NEED TO PARSE " + highest_temperature_timestamp);
|
||||||
|
highest_temperature_timestamp = new Date(highest_temperature_timestamp);
|
||||||
|
LOG(1, "AFTER PARSE " + highest_temperature_timestamp);
|
||||||
|
}
|
||||||
|
if (typeof lowest_temperature_timestamp === "undefined") {
|
||||||
|
lowest_temperature_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
lowest_temperature_timestamp = new Date(lowest_temperature_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_pressure = $.cookie("last_pressure");
|
||||||
|
highest_pressure = $.cookie("highest_pressure");
|
||||||
|
lowest_pressure = $.cookie("lowest_pressure");
|
||||||
|
highest_pressure_timestamp = $.cookie("highest_pressure_timestamp");
|
||||||
|
lowest_pressure_timestamp = $.cookie("lowest_pressure_timestamp");
|
||||||
|
if (typeof last_pressure === "undefined") {
|
||||||
|
last_pressure = 0;
|
||||||
|
} else {
|
||||||
|
last_pressure = parseInt(last_pressure);
|
||||||
|
}
|
||||||
|
if (typeof highest_pressure === "undefined") {
|
||||||
|
LOG(1, "no highest pressure, initializing to Number.MIN_VALUE");
|
||||||
|
//highest_pressure = Number.MIN_SAFE_INTEGER;
|
||||||
|
highest_pressure = Number.MIN_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing highest pressure of " + highest_pressure);
|
||||||
|
highest_pressure = parseInt(highest_pressure);
|
||||||
|
LOG(1, "after parse = " + highest_pressure);
|
||||||
|
}
|
||||||
|
if (typeof lowest_pressure === "undefined") {
|
||||||
|
LOG(1, "no lowest pressure, initializing to Number.MAX_VALUE");
|
||||||
|
//lowest_pressure = Number.MAX_SAFE_INTEGER;
|
||||||
|
lowest_pressure = Number.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing lowest pressure of " + lowest_pressure);
|
||||||
|
lowest_pressure = parseInt(lowest_pressure);
|
||||||
|
LOG(1, "after parse = " + lowest_pressure);
|
||||||
|
}
|
||||||
|
if (typeof highest_pressure_timestamp === "undefined") {
|
||||||
|
highest_pressure_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
highest_pressure_timestamp = new Date(highest_pressure_timestamp);
|
||||||
|
}
|
||||||
|
if (typeof lowest_pressure_timestamp === "undefined") {
|
||||||
|
lowest_pressure_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
lowest_pressure_timestamp = new Date(lowest_pressure_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_humidity = $.cookie("last_humidity");
|
||||||
|
highest_humidity = $.cookie("highest_humidity");
|
||||||
|
lowest_humidity = $.cookie("lowest_humidity");
|
||||||
|
highest_humidity_timestamp = $.cookie("highest_humidity_timestamp");
|
||||||
|
lowest_humidity_timestamp = $.cookie("lowest_humidity_timestamp");
|
||||||
|
if (typeof last_humidity === "undefined") {
|
||||||
|
last_humidity = 0;
|
||||||
|
} else {
|
||||||
|
last_humidity = parseFloat(last_humidity);
|
||||||
|
}
|
||||||
|
if (typeof highest_humidity === "undefined") {
|
||||||
|
LOG(1, "no highest humidity, initializing to Number.MIN_VALUE");
|
||||||
|
//highest_humidity = Number.MIN_SAFE_INTEGER;
|
||||||
|
highest_humidity = Number.MIN_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing highest humidity of " + highest_humidity);
|
||||||
|
highest_humidity = parseFloat(highest_humidity);
|
||||||
|
LOG(1, "after parse = " + highest_humidity);
|
||||||
|
}
|
||||||
|
if (typeof lowest_humidity === "undefined") {
|
||||||
|
LOG(1, "no lowest humidity, initializing to Number.MAX_VALUE");
|
||||||
|
//lowest_humidity = Number.MAX_SAFE_INTEGER;
|
||||||
|
lowest_humidity = Number.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing lowest humidity of " + lowest_humidity);
|
||||||
|
lowest_humidity = parseFloat(lowest_humidity);
|
||||||
|
LOG(1, "after parse = " + lowest_humidity);
|
||||||
|
}
|
||||||
|
if (typeof highest_humidity_timestamp === "undefined") {
|
||||||
|
highest_humidity_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
highest_humidity_timestamp = new Date(highest_humidity_timestamp);
|
||||||
|
}
|
||||||
|
if (typeof lowest_humidity_timestamp === "undefined") {
|
||||||
|
lowest_humidity_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
lowest_humidity_timestamp = new Date(lowest_humidity_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_dewpoint = $.cookie("last_dewpoint");
|
||||||
|
highest_dewpoint = $.cookie("highest_dewpoint");
|
||||||
|
lowest_dewpoint = $.cookie("lowest_dewpoint");
|
||||||
|
highest_dewpoint_timestamp = $.cookie("highest_dewpoint_timestamp");
|
||||||
|
lowest_dewpoint_timestamp = $.cookie("lowest_dewpoint_timestamp");
|
||||||
|
if (typeof last_dewpoint === "undefined") {
|
||||||
|
last_dewpoint = 0;
|
||||||
|
} else {
|
||||||
|
last_dewpoint = parseFloat(last_dewpoint);
|
||||||
|
}
|
||||||
|
if (typeof highest_dewpoint === "undefined") {
|
||||||
|
LOG(1, "no highest dewpoint, initializing to Number.MIN_VALUE");
|
||||||
|
//highest_dewpoint = Number.MIN_SAFE_INTEGER;
|
||||||
|
highest_dewpoint = Number.MIN_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing highest dewpoint of " + highest_dewpoint);
|
||||||
|
highest_dewpoint = parseFloat(highest_dewpoint);
|
||||||
|
LOG(1, "after parse = " + highest_dewpoint);
|
||||||
|
}
|
||||||
|
if (typeof lowest_dewpoint === "undefined") {
|
||||||
|
LOG(1, "no lowest dewpoint, initializing to Number.MAX_VALUE");
|
||||||
|
//lowest_dewpoint = Number.MAX_SAFE_INTEGER;
|
||||||
|
lowest_dewpoint = Number.MAX_VALUE;
|
||||||
|
} else {
|
||||||
|
LOG(1, "parsing lowest dewpoint of " + lowest_dewpoint);
|
||||||
|
lowest_dewpoint = parseFloat(lowest_dewpoint);
|
||||||
|
LOG(1, "after parse = " + lowest_dewpoint);
|
||||||
|
}
|
||||||
|
if (typeof highest_dewpoint_timestamp === "undefined") {
|
||||||
|
highest_dewpoint_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
highest_dewpoint_timestamp = new Date(highest_dewpoint_timestamp);
|
||||||
|
}
|
||||||
|
if (typeof lowest_dewpoint_timestamp === "undefined") {
|
||||||
|
lowest_dewpoint_timestamp = new Date();
|
||||||
|
} else {
|
||||||
|
lowest_dewpoint_timestamp = new Date(lowest_dewpoint_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(1, "t highesst " + highest_temperature + " type " + typeof highest_temperature);
|
||||||
|
LOG(1, "p highesst " + highest_pressure + " type " + typeof highest_pressure);
|
||||||
|
LOG(1, "date " + highest_temperature_timestamp + " type " + typeof highest_temperature_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_defaults()
|
||||||
|
{
|
||||||
|
LOG(1, "setup_defaults()");
|
||||||
|
for (var i = 0; i < defaults.length; i++) {
|
||||||
|
var default_pair = defaults[i];
|
||||||
|
var setting_name = default_pair[0];
|
||||||
|
var setting_value = default_pair[1];
|
||||||
|
var current_value = get_saved_setting(setting_name);
|
||||||
|
LOG(1, "current value for " + setting_name + " is: " + current_value);
|
||||||
|
if (typeof current_value === "undefined") {
|
||||||
|
LOG(1, "setting default = " + setting_value);
|
||||||
|
set_setting(setting_name, setting_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_settings_ui()
|
||||||
|
{
|
||||||
|
LOG(1, "update_settings_ui()");
|
||||||
|
// time_format
|
||||||
|
// temperature_units
|
||||||
|
// refresh_interval
|
||||||
|
for (var i = 0; i < defaults.length; i++) {
|
||||||
|
var setting_name = defaults[i][0];
|
||||||
|
var form = defaults[i][2];
|
||||||
|
var setting_value = get_saved_setting(setting_name);
|
||||||
|
LOG(1, "name = " + setting_name + " value = " + setting_value);
|
||||||
|
$("input[name=" + setting_name + "][value=" + setting_value + "]").attr('checked', 'checked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_settings()
|
||||||
|
{
|
||||||
|
LOG(1, "update_settings()");
|
||||||
|
for (var i = 0; i < defaults.length; i++) {
|
||||||
|
var setting_name = defaults[i][0];
|
||||||
|
LOG(1, setting_name);
|
||||||
|
var setting_value = get_current_setting(setting_name);
|
||||||
|
LOG(1, setting_value);
|
||||||
|
LOG(1, "setting name = " + setting_name + " value = " + setting_value);
|
||||||
|
set_setting(setting_name, setting_value);
|
||||||
|
}
|
||||||
|
var update_process = window.update_current_display_process;
|
||||||
|
LOG(1, "update process pid = " + update_process);
|
||||||
|
if (typeof update_process != "undefined") {
|
||||||
|
LOG(1, "stopping it");
|
||||||
|
clearTimeout(update_process);
|
||||||
|
}
|
||||||
|
var update_interval = get_saved_setting("refresh_interval");
|
||||||
|
if (update_interval > 0) {
|
||||||
|
window.update_current_display_process = setTimeout(update_current_display, update_interval * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#save_success').show().delay(1000).fadeOut('slow');
|
||||||
|
set_unit_labels();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_current_setting(setting)
|
||||||
|
{
|
||||||
|
return $('input:radio[name=' + setting + ']:checked').val();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_saved_setting(setting)
|
||||||
|
{
|
||||||
|
return $.cookie(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_setting(name, value)
|
||||||
|
{
|
||||||
|
$.cookie(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_date_string(d)
|
||||||
|
{
|
||||||
|
LOG(2, "get_date_string called with type=" + typeof d + ": " + d);
|
||||||
|
var time_format = $.cookie("time_format");
|
||||||
|
|
||||||
|
if (time_format === "utc") {
|
||||||
|
s = d.toUTCString();
|
||||||
|
} else if (time_format === "local") {
|
||||||
|
var weekdays = new Array(7);
|
||||||
|
weekdays[0] = "Sunday";
|
||||||
|
weekdays[1] = "Monday";
|
||||||
|
weekdays[2] = "Tuesday";
|
||||||
|
weekdays[3] = "Wednesday";
|
||||||
|
weekdays[4] = "Thursday";
|
||||||
|
weekdays[5] = "Friday";
|
||||||
|
weekdays[6] = "Saturday";
|
||||||
|
w = d.getDay();
|
||||||
|
s = weekdays[w] + ", " + d.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_clock()
|
||||||
|
{
|
||||||
|
d = new Date();
|
||||||
|
$("#clock").text(get_date_string(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_unit_labels()
|
||||||
|
{
|
||||||
|
var units = get_saved_setting("temperature_units");
|
||||||
|
if (units === "fahrenheit") {
|
||||||
|
unit_label = "F";
|
||||||
|
} else if (units === "celsius") {
|
||||||
|
unit_label = "C";
|
||||||
|
} else {
|
||||||
|
unit_label = "?";
|
||||||
|
}
|
||||||
|
$("#field_temperature_unit").text(unit_label);
|
||||||
|
$("#field_dewpoint_unit").text(unit_label);
|
||||||
|
$("#field_temperature_high_unit").text(unit_label);
|
||||||
|
$("#field_temperature_low_unit").text(unit_label);
|
||||||
|
$("#field_dewpoint_high_unit").text(unit_label);
|
||||||
|
$("#field_dewpoint_low_unit").text(unit_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
function current_tab_selected()
|
||||||
|
{
|
||||||
|
LOG(1, "CURRENT TAB SELECTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
function previous_tab_selected()
|
||||||
|
{
|
||||||
|
LOG(1, "PREV TAB SELECTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
function wind_tab_selected()
|
||||||
|
{
|
||||||
|
LOG(1, "WIND TAB SELECTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_current_display()
|
||||||
|
{
|
||||||
|
force_update(function() {
|
||||||
|
// Schedule the next request when the current one's complete
|
||||||
|
var update_interval = get_saved_setting("refresh_interval");
|
||||||
|
if (update_interval > 0) {
|
||||||
|
window.update_current_display_process = setTimeout(update_current_display, update_interval * 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function convert_to_current_temperature_unit(deg_celsius)
|
||||||
|
{
|
||||||
|
var return_value = deg_celsius;
|
||||||
|
var units = get_saved_setting("temperature_units");
|
||||||
|
LOG(1, "convert " + return_value + " to " + units);
|
||||||
|
if (units === "fahrenheit") {
|
||||||
|
return_value = return_value * 1.8000 + 32.00;
|
||||||
|
} else {
|
||||||
|
// units are in celsius so if that is the selected unit then no conversion is necessary
|
||||||
|
LOG(1, "no conversion necessary");
|
||||||
|
}
|
||||||
|
LOG(1, "returning " + return_value);
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function force_update(completion_handler)
|
||||||
|
{
|
||||||
|
LOG(1, "UPDATING (new-style)");
|
||||||
|
|
||||||
|
// disable the refresh button and replace it with a spinner
|
||||||
|
toggleButton("#button-update");
|
||||||
|
|
||||||
|
var jqxhr = $.getJSON( "wxdata.json", function(data) {
|
||||||
|
LOG(1, "success" );
|
||||||
|
LOG(1, "SUCCESS, received data: " + JSON.stringify(data, null, 4));
|
||||||
|
process_observations(data);
|
||||||
|
})
|
||||||
|
.fail(function(error) {
|
||||||
|
LOG(1, "FAILED, error details: " + JSON.stringify(error, null, 4));
|
||||||
|
// window.alert("Error loading data: " + error.status + " " + error.statusText);
|
||||||
|
$("#error-text").text("Error loading data: " + error.status + " " + error.statusText);
|
||||||
|
$("#error-dialog").dialog("open");
|
||||||
|
})
|
||||||
|
.always(function() {
|
||||||
|
// restore the update button
|
||||||
|
toggleButton("#button-update");
|
||||||
|
if (typeof completion_handler === "function") {
|
||||||
|
LOG(1, "calling completion handler");
|
||||||
|
completion_handler();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_observations(data)
|
||||||
|
{
|
||||||
|
LOG(1, data);
|
||||||
|
|
||||||
|
// first decode all the things!!
|
||||||
|
var version = data["ver-tag"];
|
||||||
|
var temperature;
|
||||||
|
var pressure;
|
||||||
|
var humidity;
|
||||||
|
var dewpoint;
|
||||||
|
var datetime;
|
||||||
|
var update_date;
|
||||||
|
|
||||||
|
if (version == 1) {
|
||||||
|
LOG(1, "version 1 data detected");
|
||||||
|
datetime = data["time-tag"];
|
||||||
|
temperature = parseFloat(data["bmp-temp"]);
|
||||||
|
pressure = parseInt(data["bmp-pres"]);
|
||||||
|
humidity = parseFloat(data["sht-hum"]);
|
||||||
|
dewpoint = parseFloat(data["sht-dew"]);
|
||||||
|
}
|
||||||
|
// hack to turn this into an ISO 8601 format date string
|
||||||
|
update_date = datetime.substring(0, datetime.indexOf('.')).replace(" ", "T") + "Z";
|
||||||
|
LOG(1, "UPDATE DATE = " + update_date);
|
||||||
|
//test_ts = Date.parseExact(update_date, "yyyy-MM-dd HH:mm:ss");
|
||||||
|
//test_ts = new Date(update_date);
|
||||||
|
update_date = moment(update_date).toDate();
|
||||||
|
LOG(1, "(processed update_date) " + update_date);
|
||||||
|
|
||||||
|
// now compute trends
|
||||||
|
temperature_trend = (temperature > last_temperature ? 1 : (temperature < last_temperature ? -1 : 0));
|
||||||
|
pressure_trend = (pressure > last_pressure ? 1 : (pressure < last_pressure ? -1 : 0));
|
||||||
|
humidity_trend = (humidity > last_humidity ? 1 : (humidity < last_humidity ? -1 : 0));
|
||||||
|
dewpoint_trend = (dewpoint > last_dewpoint ? 1 : (dewpoint < last_dewpoint ? -1 : 0));
|
||||||
|
|
||||||
|
// now store the last-values
|
||||||
|
last_temperature = temperature;
|
||||||
|
last_pressure = pressure;
|
||||||
|
last_dewpoint = dewpoint;
|
||||||
|
last_humidity = humidity;
|
||||||
|
|
||||||
|
$.cookie("last_temperature", last_temperature);
|
||||||
|
$.cookie("last_pressure", last_pressure);
|
||||||
|
$.cookie("last_humidity", last_humidity);
|
||||||
|
$.cookie("last_dewpoint", last_dewpoint);
|
||||||
|
|
||||||
|
// now handle min/max
|
||||||
|
if (temperature < lowest_temperature) {
|
||||||
|
lowest_temperature = temperature;
|
||||||
|
lowest_temperature_timestamp = update_date;
|
||||||
|
}
|
||||||
|
if (temperature > highest_temperature) {
|
||||||
|
highest_temperature = temperature;
|
||||||
|
highest_temperature_timestamp = update_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressure < lowest_pressure) {
|
||||||
|
lowest_pressure = pressure;
|
||||||
|
lowest_pressure_timestamp = update_date;
|
||||||
|
}
|
||||||
|
if (pressure > highest_pressure) {
|
||||||
|
highest_pressure = pressure;
|
||||||
|
highest_pressure_timestamp = update_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humidity < lowest_humidity) {
|
||||||
|
lowest_humidity = humidity;
|
||||||
|
lowest_humidity_timestamp = update_date;
|
||||||
|
}
|
||||||
|
if (humidity > highest_humidity) {
|
||||||
|
highest_humidity = humidity;
|
||||||
|
highest_humidity_timestamp = update_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dewpoint < lowest_dewpoint) {
|
||||||
|
lowest_dewpoint = dewpoint;
|
||||||
|
lowest_dewpoint_timestamp = update_date;
|
||||||
|
}
|
||||||
|
if (dewpoint > highest_dewpoint) {
|
||||||
|
highest_dewpoint = dewpoint;
|
||||||
|
highest_dewpoint_timestamp = update_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(1, "update_date " + update_date + " " + typeof update_date);
|
||||||
|
LOG(1, "temp hi " + highest_temperature_timestamp + " " + typeof highest_temperature_timestamp);
|
||||||
|
|
||||||
|
// now save them out
|
||||||
|
$.cookie("lowest_temperature", lowest_temperature);
|
||||||
|
$.cookie("highest_temperature", highest_temperature);
|
||||||
|
$.cookie("lowest_temperature_timestamp", lowest_temperature_timestamp);
|
||||||
|
$.cookie("highest_temperature_timestamp", highest_temperature_timestamp);
|
||||||
|
|
||||||
|
$.cookie("lowest_pressure", lowest_pressure);
|
||||||
|
$.cookie("highest_pressure", highest_pressure);
|
||||||
|
$.cookie("lowest_pressure_timestamp", lowest_pressure_timestamp);
|
||||||
|
$.cookie("highest_pressure_timestamp", highest_pressure_timestamp);
|
||||||
|
|
||||||
|
$.cookie("lowest_humidity", lowest_humidity);
|
||||||
|
$.cookie("highest_humidity", highest_humidity);
|
||||||
|
$.cookie("lowest_humidity_timestamp", lowest_humidity_timestamp);
|
||||||
|
$.cookie("highest_humidity_timestamp", highest_humidity_timestamp);
|
||||||
|
|
||||||
|
$.cookie("lowest_dewpoint", lowest_dewpoint);
|
||||||
|
$.cookie("highest_dewpoint", highest_dewpoint);
|
||||||
|
$.cookie("lowest_dewpoint_timestamp", lowest_dewpoint_timestamp);
|
||||||
|
$.cookie("highest_dewpoint_timestamp", highest_dewpoint_timestamp);
|
||||||
|
|
||||||
|
// lastly update the display
|
||||||
|
$("#field_temperature").text(convert_to_current_temperature_unit(temperature).toFixed(2));
|
||||||
|
$("#field_pressure").text(pressure);
|
||||||
|
$("#field_humidity").text(humidity.toFixed(2));
|
||||||
|
$("#field_dewpoint").text(dewpoint.toFixed(2));
|
||||||
|
|
||||||
|
switch(temperature_trend) {
|
||||||
|
case -1: $("#trend_temperature").html("↓"); break;
|
||||||
|
case 0: $("#trend_temperature").html("―"); break;
|
||||||
|
case 1: $("#trend_temperature").html("↑"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pressure_trend) {
|
||||||
|
case -1: $("#trend_pressure").html("↓"); break;
|
||||||
|
case 0: $("#trend_pressure").html("―"); break;
|
||||||
|
case 1: $("#trend_pressure").html("↑"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(humidity_trend) {
|
||||||
|
case -1: $("#trend_humidity").html("↓"); break;
|
||||||
|
case 0: $("#trend_humidity").html("―"); break;
|
||||||
|
case 1: $("#trend_humidity").html("↑"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(dewpoint_trend) {
|
||||||
|
case -1: $("#trend_dewpoint").html("↓"); break;
|
||||||
|
case 0: $("#trend_dewpoint").html("―"); break;
|
||||||
|
case 1: $("#trend_dewpoint").html("↑"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(1, "temps: low = " + lowest_temperature + ", high = " + highest_temperature);
|
||||||
|
|
||||||
|
$("#field_temperature_high").text(convert_to_current_temperature_unit(highest_temperature).toFixed(2));
|
||||||
|
$("#field_pressure_high").text(highest_pressure);
|
||||||
|
LOG(1, typeof highest_humidity);
|
||||||
|
$("#field_humidity_high").text(highest_humidity.toFixed(2));
|
||||||
|
$("#field_dewpoint_high").text(highest_dewpoint.toFixed(2));
|
||||||
|
|
||||||
|
$("#field_temperature_low").text(convert_to_current_temperature_unit(lowest_temperature).toFixed(2));
|
||||||
|
$("#field_pressure_low").text(lowest_pressure);
|
||||||
|
$("#field_humidity_low").text(lowest_humidity.toFixed(2));
|
||||||
|
$("#field_dewpoint_low").text(lowest_dewpoint.toFixed(2));
|
||||||
|
|
||||||
|
// display update date
|
||||||
|
// example: 2014-12-31 01:52:32.414871
|
||||||
|
// docs: https://code.google.com/p/datejs/wiki/FormatSpecifiers
|
||||||
|
// Date.parseExact doesn't like the millisecond part of python date, so just strip
|
||||||
|
// it out. Oh well, so much for millisecond-level accuracy. :-P
|
||||||
|
LOG(1, "datetime before munge [" + datetime + "]");
|
||||||
|
datetime = datetime.substring(0, datetime.indexOf('.'));
|
||||||
|
//var update_date = Date.parseExact(datetime, "yyyy-MM-dd HH:mm:ss");
|
||||||
|
//var update_date = new Date();
|
||||||
|
LOG(1, "datetime type = " + typeof datetime);
|
||||||
|
LOG(1, "datetime = [" + datetime + "]");
|
||||||
|
LOG(1, "typeof update_date = " + typeof update_date);
|
||||||
|
LOG(1, "update_date = " + update_date.toLocaleDateString());
|
||||||
|
$("#field_last_updated").html(get_date_string(update_date));
|
||||||
|
LOG(1, "highest temp timestamp " + highest_temperature_timestamp + " type " + typeof highest_temperature_timestamp);
|
||||||
|
$("#field_temperature_high_timestamp").html(get_date_string(highest_temperature_timestamp));
|
||||||
|
$("#field_pressure_high_timestamp").html(get_date_string(highest_pressure_timestamp));
|
||||||
|
$("#field_humidity_high_timestamp").html(get_date_string(highest_humidity_timestamp));
|
||||||
|
$("#field_dewpoint_high_timestamp").html(get_date_string(highest_dewpoint_timestamp));
|
||||||
|
$("#field_temperature_low_timestamp").html(get_date_string(lowest_temperature_timestamp));
|
||||||
|
$("#field_pressure_low_timestamp").html(get_date_string(lowest_pressure_timestamp));
|
||||||
|
$("#field_humidity_low_timestamp").html(get_date_string(lowest_humidity_timestamp));
|
||||||
|
$("#field_dewpoint_low_timestamp").html(get_date_string(lowest_dewpoint_timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
function force_update_old(completion_handler)
|
||||||
|
{
|
||||||
|
LOG(1, "UPDATING zzz");
|
||||||
|
|
||||||
|
// disable the refresh button and replace it with a spinner
|
||||||
|
toggleButton("#button-update");
|
||||||
|
|
||||||
|
var jqxhr = $.ajax("wxdata.json" /*"cgi-bin/get_current_readings.py"*/ )
|
||||||
|
.done(function(data) {
|
||||||
|
LOG(1, "SUCCESS, received data: " + JSON.stringify(data, null, 4));
|
||||||
|
process_observations(data);
|
||||||
|
})
|
||||||
|
.fail(function(error) {
|
||||||
|
LOG(1, "FAILED, error details: " + JSON.stringify(error, null, 4));
|
||||||
|
// window.alert("Error loading data: " + error.status + " " + error.statusText);
|
||||||
|
$("#error-text").text("Error loading data: " + error.status + " " + error.statusText);
|
||||||
|
$("#error-dialog").dialog("open");
|
||||||
|
})
|
||||||
|
.always(function() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleButton ( el )
|
||||||
|
{
|
||||||
|
if ( $(el).button( 'option', 'disabled' ) ) {
|
||||||
|
$(el).button( 'enable' );
|
||||||
|
$(el).button( 'option', 'label', 'Update' );
|
||||||
|
$(el).button( 'option', 'icons', { primary: null } );
|
||||||
|
} else {
|
||||||
|
$(el).button( 'disable' );
|
||||||
|
$(el).button( 'option', 'label', 'Updating..' );
|
||||||
|
$(el).button( 'option', 'icons', { primary: 'ui-icon-waiting' } );
|
||||||
|
}
|
||||||
|
}
|
167
configs/lighttpd/js/wind_field.js
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/* Creates a wind arrow for display in station model */
|
||||||
|
/* The default size of the arrow is: width = 8, height = 2.
|
||||||
|
The size is then given by the @arrowWidth parameter.
|
||||||
|
The canvas is a square of 2*arroWidth.
|
||||||
|
The arrow is drawn in the center of the square and rotated to the corresponding angle (@direction).
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
//console.log("O HAI");
|
||||||
|
|
||||||
|
$("p").click(function(){
|
||||||
|
$(this).hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
var lines = [];
|
||||||
|
|
||||||
|
$.getJSON( "cgi-bin/fake_wind_data.py", function( data ) {
|
||||||
|
for (i = 0; i < data.length; i++) {
|
||||||
|
// console.log("Grid " + i + ": speed " + data[i][0] + ", direction " + data[i][1]);
|
||||||
|
lines[i] = new WindArrow(data[i][0], data[i][1], "#square" + i, 8);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var WindArrow = function (speed, direction, container, arrowWidth) {
|
||||||
|
'use strict';
|
||||||
|
var index = 0,
|
||||||
|
i;
|
||||||
|
this.speed = speed;
|
||||||
|
this.direction = direction;
|
||||||
|
this.trigDirection = direction + 90;
|
||||||
|
this.scale = arrowWidth / 8;
|
||||||
|
|
||||||
|
this.ten = 0;
|
||||||
|
this.five = 0;
|
||||||
|
this.fifty = 0;
|
||||||
|
|
||||||
|
if (this.speed >= 25.0) {
|
||||||
|
this.className = "wind-arrow-25";
|
||||||
|
} else if (this.speed >= 20.0) {
|
||||||
|
this.className = "wind-arrow-20";
|
||||||
|
} else if (this.speed >= 15.0) {
|
||||||
|
this.className = "wind-arrow-15";
|
||||||
|
} else if (this.speed >= 10.0) {
|
||||||
|
this.className = "wind-arrow-10";
|
||||||
|
} else if (this.speed >= 5.0) {
|
||||||
|
this.className = "wind-arrow-5";
|
||||||
|
} else {
|
||||||
|
this.className = "wind-arrow-0";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the canvas
|
||||||
|
this.main = d3.select(container)
|
||||||
|
.append('svg:svg')
|
||||||
|
.attr('height', 2 * arrowWidth)
|
||||||
|
.attr('width', 2 * arrowWidth);
|
||||||
|
this.main.append('defs').append('clipPath')
|
||||||
|
.attr('id', 'clip')
|
||||||
|
.append('rect')
|
||||||
|
.attr('height', 2 * arrowWidth)
|
||||||
|
.attr('width', 2 * arrowWidth);
|
||||||
|
|
||||||
|
// Draw the widget area
|
||||||
|
this.widget = this.main
|
||||||
|
.append('g')
|
||||||
|
.attr('class', this.className /*'wind-arrow'*/);
|
||||||
|
|
||||||
|
if (this.speed > 0) {
|
||||||
|
// Prepare the path
|
||||||
|
this.path = "";
|
||||||
|
if (this.speed <= 7) {
|
||||||
|
// Draw a single line
|
||||||
|
this.longBar();
|
||||||
|
index = 1;
|
||||||
|
} else {
|
||||||
|
this.shortBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the number of lines in function of the speed
|
||||||
|
this.five = Math.floor(this.speed / 5);
|
||||||
|
if (this.speed % 5 >= 3) {
|
||||||
|
this.five += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add triangles (5 * 10)
|
||||||
|
this.fifty = Math.floor(this.five / 10);
|
||||||
|
this.five -= this.fifty * 10;
|
||||||
|
// Add tenLines (5 * 2)
|
||||||
|
this.ten = Math.floor(this.five / 2);
|
||||||
|
this.five -= this.ten * 2;
|
||||||
|
|
||||||
|
// Draw first the triangles
|
||||||
|
for (i = 0; i < this.fifty; i++) {
|
||||||
|
this.addFifty(index + 2 * i);
|
||||||
|
}
|
||||||
|
if (this.fifty > 0) {
|
||||||
|
index += 2 * (this.fifty - 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the long segments
|
||||||
|
for (i = 0; i < this.ten; i++) {
|
||||||
|
this.addTen(index + i);
|
||||||
|
}
|
||||||
|
index += this.ten;
|
||||||
|
|
||||||
|
// Draw the short segments
|
||||||
|
for (i = 0; i < this.five; i++) {
|
||||||
|
this.addFive(index + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.path += "Z";
|
||||||
|
|
||||||
|
// Add to the widget
|
||||||
|
this.widget.append('g')
|
||||||
|
.append('path')
|
||||||
|
.attr('d', this.path)
|
||||||
|
.attr('vector-effect', 'non-scaling-stroke')
|
||||||
|
.attr('transform', 'translate(' + arrowWidth + ', ' + arrowWidth + ') scale(' + this.scale + ') rotate(' + this.trigDirection + ' ' + 0 + ' ' + 0 + ') translate(-8, -2)')
|
||||||
|
.attr('class', this.className /*'wind-arrow'*/);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// No wind, draw double circles
|
||||||
|
this.zeroWind();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
WindArrow.prototype.shortBar = function () {
|
||||||
|
// Draw an horizontal short bar.
|
||||||
|
'use strict';
|
||||||
|
this.path += "M1 2 L8 2 ";
|
||||||
|
};
|
||||||
|
WindArrow.prototype.longBar = function () {
|
||||||
|
// Draw an horizontal long bar.
|
||||||
|
'use strict';
|
||||||
|
this.path += "M0 2 L8 2 ";
|
||||||
|
};
|
||||||
|
WindArrow.prototype.addTen = function (index) {
|
||||||
|
// Draw an oblique long segment corresponding to 10 kn.
|
||||||
|
'use strict';
|
||||||
|
this.path += "M" + index + " 0 L" + (index + 1) + " 2 ";
|
||||||
|
};
|
||||||
|
WindArrow.prototype.addFive = function (index) {
|
||||||
|
// Draw an oblique short segment corresponding to 10 kn.
|
||||||
|
'use strict';
|
||||||
|
this.path += "M" + (index + 0.5) + " 1 L" + (index + 1) + " 2 ";
|
||||||
|
};
|
||||||
|
WindArrow.prototype.addFifty = function (index) {
|
||||||
|
// Draw a triangle corresponding to 50 kn.
|
||||||
|
'use strict';
|
||||||
|
this.path += "M" + index + " 0 L" + (index + 1) + " 2 L" + index + " 2 L" + index + " 0 ";
|
||||||
|
};
|
||||||
|
WindArrow.prototype.zeroWind = function () {
|
||||||
|
// Draw two circles corresponding to null wind.
|
||||||
|
'use strict';
|
||||||
|
var circle = d3.svg.arc()
|
||||||
|
.innerRadius(0.5)
|
||||||
|
.outerRadius(1)
|
||||||
|
.startAngle(-Math.PI)
|
||||||
|
.endAngle(Math.PI);
|
||||||
|
|
||||||
|
this.widget.append('g')
|
||||||
|
.attr('class', 'wind-circle')
|
||||||
|
.append('path').attr('d', circle)
|
||||||
|
.attr('vector-effect', 'non-scaling-stroke')
|
||||||
|
.attr('transform', 'translate(8, 2)');
|
||||||
|
};
|
12
configs/lighttpd/test.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import json
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
dthandler = lambda obj: (
|
||||||
|
obj.isoformat()
|
||||||
|
if isinstance(obj, datetime.datetime)
|
||||||
|
or isinstance(obj, datetime.date)
|
||||||
|
else None)
|
||||||
|
|
||||||
|
json.dumps(datetime.datetime.now(), default=dthandler)
|
148
configs/lighttpd/weather.html
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>WeatherPi</title>
|
||||||
|
<link href="css/external/jquery-ui.css" rel="stylesheet">
|
||||||
|
<link href="css/weather.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
font: 62.5% "Trebuchet MS", sans-serif;
|
||||||
|
margin: 50px;
|
||||||
|
background-color: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="js/external/jquery.min.js"></script>
|
||||||
|
<script src="js/external/jquery.cookie.js"></script>
|
||||||
|
<script src="js/external/jquery-ui.min.js"></script>
|
||||||
|
<script src="js/external/moment.js"></script>
|
||||||
|
<script src="js/weather.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="header" align="center">
|
||||||
|
<h1>WeatherPi</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<p>Current Date & Time: <span id="clock">---</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tabs">
|
||||||
|
<ul>
|
||||||
|
<li><a href="#tab-current">Current Observations</a></li>
|
||||||
|
<li><a href="#tab-historical">Historical Data</a></li>
|
||||||
|
<li><a href="#tab-windfield">Wind Field</a></li>
|
||||||
|
<li><a href="#tab-settings">Settings</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div id="tab-current">
|
||||||
|
<div align="center">
|
||||||
|
<table border="0" cellpadding="20">
|
||||||
|
<tr>
|
||||||
|
<td align="center"></td>
|
||||||
|
<td align="center"><h1>TEMPERATURE</h1></td>
|
||||||
|
<td align="center"><h1>PRESSURE</h1></td>
|
||||||
|
<td align="center"><h1>HUMIDITY</h1></td>
|
||||||
|
<td align="center"><h1>DEWPOINT</h1></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><h1>CURRENT</h1></td>
|
||||||
|
<td align="center"><h1><span id="field_temperature">--</span>°<span id="field_temperature_unit">-</span> <span ID="trend_temperature">―</span></h1></td>
|
||||||
|
<td align="center"><h1><span id="field_pressure">--</span> Pa <span id="trend_pressure">―</span></h1></td>
|
||||||
|
<td align="center"><h1><span id="field_humidity">--</span>% <span ID="trend_humidity">―</span></h1></td>
|
||||||
|
<td align="center"><h1><span id="field_dewpoint">--</span>°<span id="field_dewpoint_unit">-</span> <span ID="trend_dewpoint">―</span></h1></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td align="center"><h1>HIGH</h1></td>
|
||||||
|
<td align="center"><h1><span id="field_temperature_high">--</span>°<span id="field_temperature_high_unit">-</span></h1><h3>as of <span id="field_temperature_high_timestamp">---</span></h3></td>
|
||||||
|
<td align="center"><h1><span id="field_pressure_high">--</span> Pa</h1><h3>as of <span id="field_pressure_high_timestamp">---</span></h3></td>
|
||||||
|
<td align="center"><h1><span id="field_humidity_high">--</span>%</h1><h3>as of <span ID="field_humidity_high_timestamp">---</span></h3></td>
|
||||||
|
<td align="center"><h1><span id="field_dewpoint_high">--</span>°<span id="field_dewpoint_high_unit">-</span></h1><h3>as of <span ID="field_dewpoint_high_timestamp">---</span></h3></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><h1>LOW</h1></td>
|
||||||
|
<td align="center"><h1><span id="field_temperature_low">--</span>°<span id="field_temperature_low_unit">-</span></h1><h3>as of <span id="field_temperature_low_timestamp">---</span></h3></td>
|
||||||
|
<td align="center"><h1><span id="field_pressure_low">--</span> Pa</h1><h3>as of <span id="field_pressure_low_timestamp">---</span></h3></td>
|
||||||
|
<td align="center"><h1><span id="field_humidity_low">--</span>%</h1><h3>as of <span ID="field_humidity_low_timestamp">---</span></h3></td>
|
||||||
|
<td align="center"><h1><span id="field_dewpoint_low">--</span>°<span id="field_dewpoint_low_unit">-</span></h1><h3>as of <span ID="field_dewpoint_low_timestamp">---</span></h3></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ui-widget" style="display: none;">
|
||||||
|
<div class="ui-state-error ui-corner-all" style="padding: 0 .7em;">
|
||||||
|
<p>
|
||||||
|
<span class="ui-icon ui-icon-alert"
|
||||||
|
style="float: left; margin-right: .3em;"></span>
|
||||||
|
<strong>Alert:</strong> <span id="x-error-text">---</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div align="center">
|
||||||
|
Last updated <span id="field_last_updated">---</span><br /><br />
|
||||||
|
<div id="button-update" class="ui-wait-button">Update</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tab-historical">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tab-windfield">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tab-settings">
|
||||||
|
|
||||||
|
<div id="settings_accordion">
|
||||||
|
<h3>Time format</h3>
|
||||||
|
<div>
|
||||||
|
<form id="form-time" action="">
|
||||||
|
<input type="radio" name="time_format" value="local">Local<br>
|
||||||
|
<input type="radio" name="time_format" value="utc">UTC
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Temperature units</h3>
|
||||||
|
<div>
|
||||||
|
<form id="form-temperature_units" action="">
|
||||||
|
<input type="radio" name="temperature_units" value="celsius">Celsius<br>
|
||||||
|
<input type="radio" name="temperature_units" value="fahrenheit">Fahrenheit
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Auto-refresh current observation data</h3>
|
||||||
|
<div>
|
||||||
|
<form id="form-refresh_interval" action="">
|
||||||
|
<input type="radio" name="refresh_interval" value="0">disabled<br>
|
||||||
|
<input type="radio" name="refresh_interval" value="10">10 seconds<br>
|
||||||
|
<input type="radio" name="refresh_interval" value="30">30 seconds<br>
|
||||||
|
<input type="radio" name="refresh_interval" value="60">1 minute<br>
|
||||||
|
<input type="radio" name="refresh_interval" value="120">2 minutes<br>
|
||||||
|
<input type="radio" name="refresh_interval" value="300">5 minutes<br>
|
||||||
|
<input type="radio" name="refresh_interval" value="600">10 minutes<br>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<span id="button-save_settings">
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
<span id="save_success" style="display:none">
|
||||||
|
Settings have been saved.
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="error-dialog" title="Error">
|
||||||
|
<p><span id="error-text" /></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
2562
configs/lighttpd/wind_field.html
Normal file
1
configs/lighttpd/wxdata.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"time-tag": "2014-12-31 01:52:32.414871", "bmp-temp": "19.8", "sht-dew": "7.79612740893", "sht-hum": "46.437628328", "bmp-pres": "99982", "ver-tag": "01"}
|
1
configs/lighttpd/wxdata2.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"time-tag": "2015-01-04 22:22:42.796492", "bmp-temp": "21.7", "sht-dew": "3.67506275795", "sht-hum": "31.462910898", "bmp-pres": "98755", "ver-tag": "01"}
|
498
configs/motion/.old/server.js.old
Normal file
|
@ -0,0 +1,498 @@
|
||||||
|
// OSSS (Open Source Surveillance and Security)
|
||||||
|
// Simple Web App
|
||||||
|
//
|
||||||
|
// Donald Burr <dburr@vctlabs.com>, 12/12/2014
|
||||||
|
|
||||||
|
var async = require('/usr/local/lib/node_modules/async');
|
||||||
|
var http = require('http')
|
||||||
|
var url = require('url')
|
||||||
|
var fs = require('fs')
|
||||||
|
var path = require('path')
|
||||||
|
var os = require("os");
|
||||||
|
var metalib = require('/usr/local/lib/node_modules/fluent-ffmpeg').Metadata
|
||||||
|
var sprintf = require('/usr/local/lib/node_modules/sprintf-js').sprintf;
|
||||||
|
|
||||||
|
// workaround for some node.js api changes
|
||||||
|
fs.exists = fs.exists || require('path').exists;
|
||||||
|
fs.existsSync = fs.existsSync || require('path').existsSync;
|
||||||
|
|
||||||
|
// debug mode
|
||||||
|
var DEBUG = false;
|
||||||
|
|
||||||
|
// sort order defaults to forward
|
||||||
|
var reverse_sort_order = 0;
|
||||||
|
|
||||||
|
// get arguments
|
||||||
|
var args = process.argv.slice(2);
|
||||||
|
if (args.length > 0) {
|
||||||
|
if (args[0] === "-d") {
|
||||||
|
console.log("Debug mode enabled.");
|
||||||
|
DEBUG = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// port to use
|
||||||
|
var PORT = 80;
|
||||||
|
if (DEBUG) {
|
||||||
|
console.log("Using port 8000 since we are in DEBUG mode.");
|
||||||
|
PORT = 8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// these MUST match "width" and "height" settings in /etc/motion/motion.conf!
|
||||||
|
var WIDTH = 320;
|
||||||
|
var HEIGHT = 240;
|
||||||
|
|
||||||
|
// number of pixels of padding to add to IFRAME (required by some browsers,
|
||||||
|
// notably Firefox, to prevent scroll bars from appearing within the IFRAME)
|
||||||
|
var PADDING = 20;
|
||||||
|
|
||||||
|
// pretty-print # of seconds as hrs:mintes:seconds
|
||||||
|
function secondsToString(seconds, shortFormat)
|
||||||
|
{
|
||||||
|
shortFormat = typeof shortFormat !== 'undefined' ? shortFormat : false;
|
||||||
|
var str = "";
|
||||||
|
//var numyears = Math.floor(seconds / 31536000);
|
||||||
|
var numdays = Math.floor((seconds % 31536000) / 86400);
|
||||||
|
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
|
||||||
|
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
|
||||||
|
var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
|
||||||
|
if (shortFormat) {
|
||||||
|
if (numdays > 0) {
|
||||||
|
str += sprintf("%02dd", numdays);
|
||||||
|
}
|
||||||
|
if (numhours > 0) {
|
||||||
|
str += sprintf("%02dh", numhours);
|
||||||
|
}
|
||||||
|
if (numminutes > 0) {
|
||||||
|
str += sprintf("%02dd", numminutes);
|
||||||
|
}
|
||||||
|
if (numseconds > 0) {
|
||||||
|
str += sprintf("%02ds", numseconds);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (numdays > 0) {
|
||||||
|
str += numdays + " days, ";
|
||||||
|
}
|
||||||
|
if (numhours > 0) {
|
||||||
|
str += numhours + " hours, ";
|
||||||
|
}
|
||||||
|
if (numminutes > 0) {
|
||||||
|
str += numminutes + " minutes, ";
|
||||||
|
}
|
||||||
|
if (numseconds > 0) {
|
||||||
|
str += numseconds + " seconds";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fun with timezone offsets
|
||||||
|
function pad(value) {
|
||||||
|
return value < 10 ? '0' + value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOffset(offset_in) {
|
||||||
|
var sign = (offset_in > 0) ? "-" : "+";
|
||||||
|
var offset = Math.abs(offset_in);
|
||||||
|
var hours = pad(Math.floor(offset / 60));
|
||||||
|
var minutes = pad(offset % 60);
|
||||||
|
return sign + hours + ":" + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAMPM(date) {
|
||||||
|
var hours = date.getHours();
|
||||||
|
var minutes = date.getMinutes();
|
||||||
|
var ampm = hours >= 12 ? 'pm' : 'am';
|
||||||
|
hours = hours % 12;
|
||||||
|
hours = hours ? hours : 12; // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? '0'+minutes : minutes;
|
||||||
|
var strTime = hours + ':' + minutes + ' ' + ampm;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanFileSize(bytes, si) {
|
||||||
|
var thresh = si ? 1000 : 1024;
|
||||||
|
if(bytes < thresh) return bytes + ' B';
|
||||||
|
var units = si ? ['kB','MB','GB','TB','PB','EB','ZB','YB'] : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
|
||||||
|
var u = -1;
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while(bytes >= thresh);
|
||||||
|
return bytes.toFixed(1)+' '+units[u];
|
||||||
|
};
|
||||||
|
|
||||||
|
function endsWith(str, suffix) {
|
||||||
|
return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function r(max) {
|
||||||
|
return Math.floor(Math.random() * max);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCookies (request) {
|
||||||
|
var list = {},
|
||||||
|
rc = request.headers.cookie;
|
||||||
|
|
||||||
|
rc && rc.split(';').forEach(function( cookie ) {
|
||||||
|
var parts = cookie.split('=');
|
||||||
|
list[parts.shift().trim()] = decodeURI(parts.join('='));
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function respondToHttpRequest(req, res) {
|
||||||
|
var hostname = os.hostname();
|
||||||
|
var host = req.headers["host"];
|
||||||
|
var hostport = host
|
||||||
|
var cookies = parseCookies(req);
|
||||||
|
if (cookies["reverse_sort_order"]) {
|
||||||
|
reverse_sort_order = parseInt(cookies["reverse_sort_order"]);
|
||||||
|
}
|
||||||
|
if(host.indexOf(":") > -1) {
|
||||||
|
host = host.substring(0, host.indexOf(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ua = req.headers['user-agent'],
|
||||||
|
$ = {};
|
||||||
|
|
||||||
|
if (/mobile/i.test(ua))
|
||||||
|
$.Mobile = true;
|
||||||
|
|
||||||
|
if (/like Mac OS X/.test(ua)) {
|
||||||
|
$.iOS = /CPU( iPhone)? OS ([0-9\._]+) like Mac OS X/.exec(ua)[2].replace(/_/g, '.');
|
||||||
|
$.iPhone = /iPhone/.test(ua);
|
||||||
|
$.iPad = /iPad/.test(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/Android/.test(ua))
|
||||||
|
$.Android = /Android ([0-9\.]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
if (/webOS\//.test(ua))
|
||||||
|
$.webOS = /webOS\/([0-9\.]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
if (/(Intel|PPC) Mac OS X/.test(ua))
|
||||||
|
$.Mac = /(Intel|PPC) Mac OS X ?([0-9\._]*)[\)\;]/.exec(ua)[2].replace(/_/g, '.') || true;
|
||||||
|
|
||||||
|
if (/[Ll]inux/.test(ua))
|
||||||
|
$.Linux = true;
|
||||||
|
|
||||||
|
if (/Windows NT/.test(ua))
|
||||||
|
$.Windows = /Windows NT ([0-9\._]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
console.log("USER AGENT DETECTION RESULTS:");
|
||||||
|
console.log($);
|
||||||
|
|
||||||
|
//console.log("host = " + host);
|
||||||
|
// console.log(url);
|
||||||
|
var queryData = url.parse(req.url, true, true).query;
|
||||||
|
console.log("Responding to http request: " + req.url);
|
||||||
|
//console.log("query data: " + queryData);
|
||||||
|
|
||||||
|
if (queryData.mode) {
|
||||||
|
console.log("mode = " + queryData.mode);
|
||||||
|
if (queryData.mode === "live_view") {
|
||||||
|
// <iframe src="http://www.w3schools.com"></iframe>
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Live View"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<DIV ALIGN=\"CENTER\">"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Live View</H1>";
|
||||||
|
if ($.Android) {
|
||||||
|
//rhtml += "<A HREF=\"vlc://" + host + ":8080/\">Click here to view</A>.<br />(Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)</A>";
|
||||||
|
rhtml += "<IMG WIDTH=\"" + WIDTH + "\" HEIGHT=\"" + HEIGHT + "\" SRC=\"http://" + host + ":8080\"></IMG>";
|
||||||
|
} else if ($.iOS) {
|
||||||
|
//rhtml += "<A HREF=\"infuse://" + host + ":8080\">Click here to view</A>.<br />(Requires the free Infuse app. <A HREF=\"https://itunes.apple.com/us/app/infuse-3/id577130046\">Download it here</A>.)</A>";
|
||||||
|
rhtml += "<A HREF=\"vlc://http://" + host + ":8080/\">Click here to view</A>.<br />(Requires the free VLC app for iOS. <A HREF=\"http://get.videolan.org/vlc-iOS/2.3.0/vlc-iOS-2.3.0.ipa\">Download it here</A>.)</A>";
|
||||||
|
} else {
|
||||||
|
rhtml += "<IFRAME WIDTH=\"" + (WIDTH + PADDING) + "\" HEIGHT=\"" + (HEIGHT + PADDING) + "\" frameBorder=\"0\" seamless=\"seamless\" scrolling=\"no\" frameborder=\"0\" hspace=\"0\" vspace=\"0\" marginheight=\"0\" marginwidth=\"0\" SRC=\"http://" + host + ":8080\"></IFRAME>";
|
||||||
|
}
|
||||||
|
rhtml += "<P><A HREF=\"http://" + hostport + "/\">Back</A></p>"
|
||||||
|
+ "</DIV>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else if (queryData.mode === "file_list") {
|
||||||
|
var headers = {"Content-Type": "text/html"};
|
||||||
|
if (queryData.set_reverse_sort_order) {
|
||||||
|
reverse_sort_order = parseInt(queryData.set_reverse_sort_order);
|
||||||
|
headers["Set-Cookie"] = "reverse_sort_order=" + queryData.set_reverse_sort_order;
|
||||||
|
}
|
||||||
|
fs.readdir("/var/spool/motion", function(err, list) {
|
||||||
|
if(err) {
|
||||||
|
res.writeHead(200, headers);
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: unable to get file list: " + err + "</h1></BODY></HTML>");
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, headers);
|
||||||
|
res.write("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Saved Recordings</TITLE></HEAD><BODY><h1>" + hostname + " - Saved Recordings</h1>");
|
||||||
|
var regex = new RegExp(".*\.avi");
|
||||||
|
var fileList = new Array()
|
||||||
|
var done = false;
|
||||||
|
console.log("start foreach");
|
||||||
|
async.forEachSeries(list, function(item) {
|
||||||
|
if(regex.test(item)) {
|
||||||
|
var metaobject = new metalib("/var/spool/motion/" + item);
|
||||||
|
var eventNumber = item.substr(0, 2);
|
||||||
|
var offset = new Date().getTimezoneOffset();
|
||||||
|
var dateString = item.substr(3, item.indexOf(".avi")-3).replace(/\./g, ':') + createOffset(offset);
|
||||||
|
var dateObject = new Date(dateString);
|
||||||
|
var stats = fs.statSync("/var/spool/motion/" + item)
|
||||||
|
var fileSizeInBytes = stats["size"]
|
||||||
|
var fileInfo = new Array();
|
||||||
|
fileInfo[0] = dateObject;
|
||||||
|
fileInfo[1] = item;
|
||||||
|
fileInfo[2] = eventNumber;
|
||||||
|
fileInfo[3] = fileSizeInBytes;
|
||||||
|
metaobject.get(function(metadata, err) {
|
||||||
|
if (!err) {
|
||||||
|
fileInfo[4] = metadata["durationsec"];
|
||||||
|
} else {
|
||||||
|
fileInfo[4] = -1;
|
||||||
|
}
|
||||||
|
fileList.push(fileInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, function(err) {
|
||||||
|
console.log("REALLY ALL DONE NOW");
|
||||||
|
done = true
|
||||||
|
});
|
||||||
|
console.log("about to start while");
|
||||||
|
console.log("done = " + done);
|
||||||
|
while (!done) {console.log('waiting');};
|
||||||
|
if (fileList.length > 0) {
|
||||||
|
// sort by date
|
||||||
|
fileList.sort(function(a,b){
|
||||||
|
a = a[0];
|
||||||
|
b = b[0];
|
||||||
|
if (reverse_sort_order) {
|
||||||
|
c = a > b ? -1 : a < b ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
c = a < b ? -1 : a > b ? 1 : 0;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
res.write("<p>Current Sort Order: " +
|
||||||
|
(reverse_sort_order ? "Reverse" : "Forward") +
|
||||||
|
" (<A HREF=\"http://" + hostport + "/?mode=file_list&set_reverse_sort_order=" + (reverse_sort_order ? "0" : "1") + "\">change</A>)</p>");
|
||||||
|
res.write("<UL>");
|
||||||
|
for (var i in fileList) {
|
||||||
|
var item = fileList[i];
|
||||||
|
res.write("<LI>" + item[0].toLocaleDateString() + " @ " + formatAMPM(item[0]) + " (Event #" + item[2] + ") (" + humanFileSize(item[3], true) + ", " + (item[4] == -1 ? "cannot calculate duration" : secondsToString(item[4], true)) + ") (<A HREF=\"http://" + hostport + "/?mode=view&filename=" + item[1] + ($.Linux && !$.Android ? "&use_vlc_plugin=true" : "") + "\">view</A>) (<A HREF=\"http://" + hostport + "/?mode=download&filename=" + item[1] + "\">download</A>) (<A HREF=\"http://" + hostport + "/?mode=delete&filename=" + item[1] + "\">delete</A>)</LI>");
|
||||||
|
}
|
||||||
|
res.end("</ul><h3><A HREF=\"http://" + hostport + "/?mode=delete&filename=ALL\">Delete ALL Videos</A></h3><p><A HREF=\"http://" + hostport + "/\">Back</A></p></BODY><FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER></HTML>");
|
||||||
|
} else {
|
||||||
|
res.write("<h3>No Files Found</h3>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.end("<p><A HREF=\"http://" + hostport + "/\">Back</A></p></BODY><FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER></HTML>");
|
||||||
|
});
|
||||||
|
} else if (queryData.mode === "delete") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
if (queryData.confirmed) {
|
||||||
|
var confirmed = queryData.confirmed;
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Delete File(s)"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Delete File(s)</H1>"
|
||||||
|
+ "<p><h3>";
|
||||||
|
if (confirmed === "yes") {
|
||||||
|
var numDeleted = 0;
|
||||||
|
var numErrors = 0;
|
||||||
|
var path = "/var/spool/motion/";
|
||||||
|
if (filename === "ALL") {
|
||||||
|
var files = fs.readdirSync(path);
|
||||||
|
var success = true
|
||||||
|
files.forEach(function(file) {
|
||||||
|
if (file.match("^.*avi$")) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path + file);
|
||||||
|
numDeleted++;
|
||||||
|
rhtml += "Deleted \"" + file + "\"<br />";
|
||||||
|
} catch (ex) {
|
||||||
|
numErrors++;
|
||||||
|
rhtml += "Could not delete \"" + file + "\": " + ex + "<br />";
|
||||||
|
success = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rhtml += "<br />";
|
||||||
|
} else {
|
||||||
|
path += filename;
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path);
|
||||||
|
numDeleted++;
|
||||||
|
success = true;
|
||||||
|
} catch (ex) {
|
||||||
|
numErrors++;
|
||||||
|
rhtml += "Could not delete \"" + filename + "\": " + ex + "<br /><br />";
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
rhtml += numDeleted + " file" + (numDeleted > 1 ? "s" : "") + " deleted successfully.";
|
||||||
|
} else {
|
||||||
|
rhtml += numDeleted > 0 ? numDeleted + " file" + (numDeleted > 1 ? "s" : "") + " deleted successfully." : "";
|
||||||
|
rhtml += numErrors + " delete failure" + (numErrors > 1 ? "s" : "") + ".";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rhtml += "Delete cancelled.";
|
||||||
|
}
|
||||||
|
rhtml += "<h3><A HREF=\"" + hostport + "/?mode=file_list\">OK</A></h3></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else {
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Delete File(s)"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Delete File(s)</H1>"
|
||||||
|
+ "<p><h3>You are about to delete "
|
||||||
|
+ (filename === "ALL" ? "ALL videos!" : "\"" + filename + "\"")
|
||||||
|
+ "<br /><br />"
|
||||||
|
+ "Are you SURE you want to do this?<br /><br />"
|
||||||
|
+ "<A HREF=\"" + hostport + "/?mode=delete&filename=" + filename + "&confirmed=yes\">YES</A> <A HREF=\"" + hostport + "/?mode=delete&filename=" + filename + "&confirmed=no\">NO</A></h3></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
} else if (queryData.mode === "view") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
var filePath = "/var/spool/motion/" + filename;
|
||||||
|
fs.exists(filePath, function(exists) {
|
||||||
|
if (exists) {
|
||||||
|
console.log('viewing contents of local file: ' + filePath);
|
||||||
|
var stat = fs.statSync(filePath);
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'text/html'
|
||||||
|
});
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Video Playback - " + filename
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<DIV ALIGN=\"CENTER\">"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - " + filename + "</H1>";
|
||||||
|
if (queryData.use_vlc_plugin) {
|
||||||
|
rhtml += "<embed type=\"application/x-vlc-plugin\""
|
||||||
|
+ "pluginspage=\"http://www.videolan.org\""
|
||||||
|
+ "name=\"video1\""
|
||||||
|
+ "id=\"video1\""
|
||||||
|
+ "controls=\"yes\" toolbar=\"yes\" autoplay=\"no\" loop=\"yes\" width=\"" + WIDTH + "\" height=\"" + HEIGHT + "\""
|
||||||
|
+ "target=\"http://" + hostport + "/?mode=download&filename=" + filename + "\" />"
|
||||||
|
+ "<br />"
|
||||||
|
+ "(Note: if you don't see a video window above, then you must <A HREF=\"http://www.videolan.org/vlc/download-ubuntu.html\">install the VLC browser plugin</A>.)"
|
||||||
|
+ "<br />";
|
||||||
|
/*
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.play()'>[Play]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.pause()'>[Pause]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.stop()'>[Stop]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.fullscreen()'>[fullscreen]</a>";
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
if ($.Android) {
|
||||||
|
//rhtml += "<A HREF=\"vlc://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)";
|
||||||
|
rhtml += "<A HREF=\"http://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to download this file</A>.<br />Once the file is downloaded, swipe down Notification Center, and tap on the file to open it in VLC. (Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)";
|
||||||
|
rhtml += "<br />Note #2: you may get an error message saying VLC encounterd an error with this media. If so, tap the \"Refresh\" (two arrows going around in circles) button in VLC, and the downloaded file should appear. Seems to be a bug with the latest VLC, they broke it. :-P";
|
||||||
|
} else if ($.iOS) {
|
||||||
|
rhtml += "<A HREF=\"vlc://http://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free VLC app for iOS. <A HREF=\"http://get.videolan.org/vlc-iOS/2.3.0/vlc-iOS-2.3.0.ipa\">Download it here</A>.)";
|
||||||
|
//rhtml += "<A HREF=\"infuse://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free Infuse app. <A HREF=\"https://itunes.apple.com/us/app/infuse-3/id577130046?mt=8\">Download it here</A>.)";
|
||||||
|
} else {
|
||||||
|
rhtml += "<video width=\"" + WIDTH + "\" height=\"" + HEIGHT + "\" controls>"
|
||||||
|
+ "<source src=\"http://" + hostport + "/?mode=download&filename=" + filename + "\" type=\"video/x-msvideo\">"
|
||||||
|
+ "Your browser does not support the video tag."
|
||||||
|
+ "</video>"
|
||||||
|
+ "<br />";
|
||||||
|
// + "<A HREF=\"http://" + hostport + "/?mode=view&filename=" + filename + "&use_vlc_plugin=true\">(Don't see any video? Try this...)</A>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rhtml += "<P><A HREF=\"http://" + hostport + "/?mode=file_list\">Back</A></p>"
|
||||||
|
+ "</DIV>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else {
|
||||||
|
console.log('returning 404, could not find: ' + filePath);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found. Go away kid, you\'re bothering me.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
} else if (queryData.mode === "download") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
var filePath = "/var/spool/motion/" + filename;
|
||||||
|
fs.exists(filePath, function(exists) {
|
||||||
|
if (exists) {
|
||||||
|
console.log('sending contents of local file: ' + filePath);
|
||||||
|
var stat = fs.statSync(filePath);
|
||||||
|
var contenttype = "video/x-msvideo";
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': contenttype,
|
||||||
|
'Content-Length': stat.size,
|
||||||
|
'Content-Disposition': "attachment; filename=" + filename
|
||||||
|
});
|
||||||
|
var readStream = fs.createReadStream(filePath);
|
||||||
|
readStream.pipe(res);
|
||||||
|
} else {
|
||||||
|
console.log('returning 404, could not find: ' + filePath);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found. Go away kid, you\'re bothering me.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// send the index page
|
||||||
|
console.log("Responding with index page");
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML>"
|
||||||
|
+ "<HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS (Open Source Surveillance and Security) - " + hostname + "</TITLE>"
|
||||||
|
+ "</HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<p><h1>OSSS (Open Source Surveillance and Security) - " + hostname + "</h1></p>"
|
||||||
|
+ "<p>"
|
||||||
|
+ "<ul>"
|
||||||
|
+ "<li><A HREF=\"http://" + hostport + "/?mode=live_view\">Live View</A></li>"
|
||||||
|
+ "<li><A HREF=\"http://" + hostport + "/?mode=file_list\">Saved Recordings</A></li>"
|
||||||
|
+ "</UL>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the HTTP listener
|
||||||
|
var server = http.createServer(function (req, res) {
|
||||||
|
respondToHttpRequest(req, res);
|
||||||
|
}).listen(PORT);
|
||||||
|
server.on('connection', function(sock) {
|
||||||
|
console.log('Incoming HTTP connection from ' + sock.remoteAddress);
|
||||||
|
});
|
||||||
|
console.log('HTTP server running on port ' + PORT + '.');
|
677
configs/motion/.old/server.js.xxx
Normal file
|
@ -0,0 +1,677 @@
|
||||||
|
// OSSS (Open Source Surveillance and Security)
|
||||||
|
// (Not-so-)Simple Web App
|
||||||
|
//
|
||||||
|
// Donald Burr <dburr@vctlabs.com>, 12/12/2014
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var http = require('http')
|
||||||
|
var url = require('url')
|
||||||
|
var fs = require('fs')
|
||||||
|
var path = require('path')
|
||||||
|
var os = require("os");
|
||||||
|
var ffmpeg = require('fluent-ffmpeg')
|
||||||
|
//var metalib = ffmpeg.Metadata
|
||||||
|
var nStore = require('nstore').extend(require('nstore/query')());
|
||||||
|
var dbIsReady = false;
|
||||||
|
|
||||||
|
// workaround for some node.js api changes
|
||||||
|
fs.exists = fs.exists || require('path').exists;
|
||||||
|
fs.existsSync = fs.existsSync || require('path').existsSync;
|
||||||
|
|
||||||
|
// debug mode
|
||||||
|
var DEBUG = false;
|
||||||
|
var NOISY_DEBUG = false;
|
||||||
|
|
||||||
|
// sort order defaults to forward
|
||||||
|
var reverse_sort_order = 0;
|
||||||
|
|
||||||
|
// get arguments
|
||||||
|
var args = process.argv.slice(2);
|
||||||
|
if (args.length > 0) {
|
||||||
|
if (args[0] === "-d") {
|
||||||
|
console.log("Debug mode enabled.");
|
||||||
|
DEBUG = true;
|
||||||
|
}
|
||||||
|
if (args[0] === "-n") {
|
||||||
|
console.log("Noisy debug mode enabled.");
|
||||||
|
DEBUG = true;
|
||||||
|
NOISY_DEBUG = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// port to use
|
||||||
|
var PORT = 80;
|
||||||
|
if (DEBUG) {
|
||||||
|
console.log("Using port 8000 since we are in DEBUG mode.");
|
||||||
|
PORT = 8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// these MUST match "width" and "height" settings in /etc/motion/motion.conf!
|
||||||
|
var WIDTH = 320;
|
||||||
|
var HEIGHT = 240;
|
||||||
|
|
||||||
|
// number of pixels of padding to add to IFRAME (required by some browsers,
|
||||||
|
// notably Firefox, to prevent scroll bars from appearing within the IFRAME)
|
||||||
|
var PADDING = 20;
|
||||||
|
|
||||||
|
// TODO: example process code
|
||||||
|
function ps_test()
|
||||||
|
{
|
||||||
|
var ps = require('/usr/local/lib/node_modules/ps-node');
|
||||||
|
|
||||||
|
// A simple pid lookup
|
||||||
|
ps.lookup({
|
||||||
|
command: 'motion',
|
||||||
|
psargs: 'aux'
|
||||||
|
}, function(err, resultList ) {
|
||||||
|
if (err) {
|
||||||
|
throw new Error( err );
|
||||||
|
}
|
||||||
|
|
||||||
|
resultList.forEach(function( process ){
|
||||||
|
if( process ){
|
||||||
|
|
||||||
|
console.log( 'PID: %s, COMMAND: %s, ARGUMENTS: %s', process.pid, process.command, process.arguments );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pretty-print # of seconds as hrs:mintes:seconds
|
||||||
|
function secondsToString(seconds, shortFormat)
|
||||||
|
{
|
||||||
|
shortFormat = typeof shortFormat !== 'undefined' ? shortFormat : false;
|
||||||
|
var str = "";
|
||||||
|
//var numyears = Math.floor(seconds / 31536000);
|
||||||
|
var numdays = Math.floor((seconds % 31536000) / 86400);
|
||||||
|
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
|
||||||
|
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
|
||||||
|
var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
|
||||||
|
if (shortFormat) {
|
||||||
|
if (numdays > 0) {
|
||||||
|
str += numdays + "d";
|
||||||
|
}
|
||||||
|
if (numhours > 0) {
|
||||||
|
str += numhours + "h";
|
||||||
|
}
|
||||||
|
if (numminutes > 0) {
|
||||||
|
str += numminutes + "m";
|
||||||
|
}
|
||||||
|
if (numseconds > 0) {
|
||||||
|
str += numseconds + "s";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (numdays > 0) {
|
||||||
|
str += numdays + " days, ";
|
||||||
|
}
|
||||||
|
if (numhours > 0) {
|
||||||
|
str += numhours + " hours, ";
|
||||||
|
}
|
||||||
|
if (numminutes > 0) {
|
||||||
|
str += numminutes + " minutes, ";
|
||||||
|
}
|
||||||
|
if (numseconds > 0) {
|
||||||
|
str += numseconds + " seconds";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fun with timezone offsets
|
||||||
|
function pad(value) {
|
||||||
|
return value < 10 ? '0' + value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOffset(offset_in) {
|
||||||
|
var sign = (offset_in > 0) ? "-" : "+";
|
||||||
|
var offset = Math.abs(offset_in);
|
||||||
|
var hours = pad(Math.floor(offset / 60));
|
||||||
|
var minutes = pad(offset % 60);
|
||||||
|
return sign + hours + ":" + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAMPM(date) {
|
||||||
|
var hours = date.getHours();
|
||||||
|
var minutes = date.getMinutes();
|
||||||
|
var ampm = hours >= 12 ? 'pm' : 'am';
|
||||||
|
hours = hours % 12;
|
||||||
|
hours = hours ? hours : 12; // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? '0'+minutes : minutes;
|
||||||
|
var strTime = hours + ':' + minutes + ' ' + ampm;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanFileSize(bytes, si) {
|
||||||
|
var thresh = si ? 1000 : 1024;
|
||||||
|
if(bytes < thresh) return bytes + ' B';
|
||||||
|
var units = si ? ['kB','MB','GB','TB','PB','EB','ZB','YB'] : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
|
||||||
|
var u = -1;
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while(bytes >= thresh);
|
||||||
|
return bytes.toFixed(1)+' '+units[u];
|
||||||
|
};
|
||||||
|
|
||||||
|
function endsWith(str, suffix) {
|
||||||
|
return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function r(max) {
|
||||||
|
return Math.floor(Math.random() * max);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCookies (request) {
|
||||||
|
var list = {},
|
||||||
|
rc = request.headers.cookie;
|
||||||
|
|
||||||
|
rc && rc.split(';').forEach(function( cookie ) {
|
||||||
|
var parts = cookie.split('=');
|
||||||
|
list[parts.shift().trim()] = decodeURI(parts.join('='));
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileData(key, getFileData_callback) {
|
||||||
|
var master_key = key;
|
||||||
|
if (NOISY_DEBUG) {
|
||||||
|
console.log("getFileData called with " + key);
|
||||||
|
}
|
||||||
|
if (dbIsReady) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("getFileData db is ready");
|
||||||
|
db.get(key, function (err, doc, key) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("db.get callback, err=" + err + ", doc=" + doc + ", key=" + key);
|
||||||
|
if (err) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: oops, " + err + ", reading file info directly");
|
||||||
|
// grab the data
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("KEY = " + master_key);
|
||||||
|
storeFileData(master_key, getFileData_callback);
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("Got data " + doc);
|
||||||
|
var fileInfo = new Array();
|
||||||
|
fileInfo[0] = new Date(doc.date);
|
||||||
|
fileInfo[1] = doc.file_name;
|
||||||
|
fileInfo[2] = doc.event_num;
|
||||||
|
fileInfo[3] = doc.size;
|
||||||
|
fileInfo[4] = doc.length;
|
||||||
|
var stats = fs.statSync("/var/spool/motion/" + master_key)
|
||||||
|
var fileSizeInBytes = stats["size"]
|
||||||
|
if (fileSizeInBytes != doc.size) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: file " + master_key + " file size is different than cache, assuming it has changed");
|
||||||
|
storeFileData(master_key, getFileData_callback, true);
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("calling getFileData_callback with " + fileInfo);
|
||||||
|
getFileData_callback(fileInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: database not ready, reading file info directly");
|
||||||
|
storeFileData(key, getFileData_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeFileData(key, storeFileData_callback, needs_deletion) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("at start of storeFileData, key=" + key);
|
||||||
|
needs_deletion = typeof needs_deletion !== 'undefined' ? needs_deletion : false;
|
||||||
|
var fileInfo = new Array();
|
||||||
|
var eventNumber = key.substr(0, 2);
|
||||||
|
var offset = new Date().getTimezoneOffset();
|
||||||
|
var dateString = key.substr(3, key.indexOf(".avi")-3).replace(/\./g, ':') + createOffset(offset);
|
||||||
|
var dateObject = new Date(dateString);
|
||||||
|
var stats = fs.statSync("/var/spool/motion/" + key)
|
||||||
|
var fileSizeInBytes = stats["size"]
|
||||||
|
fileInfo[0] = dateObject;
|
||||||
|
fileInfo[1] = key;
|
||||||
|
fileInfo[2] = eventNumber;
|
||||||
|
fileInfo[3] = fileSizeInBytes;
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("beginning async.series with fileInfo = " + fileInfo);
|
||||||
|
async.series([
|
||||||
|
function(seriesCallback) {
|
||||||
|
console.log(key);
|
||||||
|
console.log(ffmpeg);
|
||||||
|
ffmpeg.ffprobe("/var/spool/motion/" + key, function(err, metadata) {
|
||||||
|
console.dir(metadata);
|
||||||
|
});
|
||||||
|
// var metaobject = new metalib("/var/spool/motion/" + key);
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("part 1, about to look up metadata");
|
||||||
|
metaobject.get(function(metadata, err) {
|
||||||
|
if (!err) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("got metadata");
|
||||||
|
fileInfo[4] = metadata["durationsec"];
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("couldn't get metadata, assuming 0s");
|
||||||
|
fileInfo[4] = -1;
|
||||||
|
}
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("about to call seriesCallback 1");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(seriesCallback) {
|
||||||
|
// delete if desired
|
||||||
|
if (needs_deletion) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("need to delete " + key);
|
||||||
|
// Remove our new document
|
||||||
|
db.remove(key, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log("ERROR attempting to delete " + key + ": " + err);
|
||||||
|
}
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(seriesCallback) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("part 2, about to write to database");
|
||||||
|
// only try this if db is ready
|
||||||
|
if (dbIsReady) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("db is ready, writing");
|
||||||
|
db.save(key, {
|
||||||
|
date: fileInfo[0],
|
||||||
|
file_name: fileInfo[1],
|
||||||
|
event_num: fileInfo[2],
|
||||||
|
size: fileInfo[3],
|
||||||
|
length: fileInfo[4]
|
||||||
|
}, function(err) {
|
||||||
|
var responseMsg;
|
||||||
|
var success;
|
||||||
|
if (err) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR WRITING TO DB: " + err);
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("SUCCESS, wrote db");
|
||||||
|
}
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("database write finished, calling seriesCallback 2");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: database not ready, calling seriesCallback 2");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
}
|
||||||
|
}, function(seriesCallback) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("part 3, about to call final callback");
|
||||||
|
storeFileData_callback(fileInfo);
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function respondToHttpRequest(req, res) {
|
||||||
|
var hostname = os.hostname();
|
||||||
|
var host = req.headers["host"];
|
||||||
|
var hostport = host
|
||||||
|
var cookies = parseCookies(req);
|
||||||
|
if (cookies["reverse_sort_order"]) {
|
||||||
|
reverse_sort_order = parseInt(cookies["reverse_sort_order"]);
|
||||||
|
}
|
||||||
|
if(host.indexOf(":") > -1) {
|
||||||
|
host = host.substring(0, host.indexOf(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ua = req.headers['user-agent'],
|
||||||
|
$ = {};
|
||||||
|
|
||||||
|
if (/mobile/i.test(ua))
|
||||||
|
$.Mobile = true;
|
||||||
|
|
||||||
|
if (/like Mac OS X/.test(ua)) {
|
||||||
|
$.iOS = /CPU( iPhone)? OS ([0-9\._]+) like Mac OS X/.exec(ua)[2].replace(/_/g, '.');
|
||||||
|
$.iPhone = /iPhone/.test(ua);
|
||||||
|
$.iPad = /iPad/.test(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/Android/.test(ua))
|
||||||
|
$.Android = /Android ([0-9\.]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
if (/webOS\//.test(ua))
|
||||||
|
$.webOS = /webOS\/([0-9\.]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
if (/(Intel|PPC) Mac OS X/.test(ua))
|
||||||
|
$.Mac = /(Intel|PPC) Mac OS X ?([0-9\._]*)[\)\;]/.exec(ua)[2].replace(/_/g, '.') || true;
|
||||||
|
|
||||||
|
if (/[Ll]inux/.test(ua))
|
||||||
|
$.Linux = true;
|
||||||
|
|
||||||
|
if (/Windows NT/.test(ua))
|
||||||
|
$.Windows = /Windows NT ([0-9\._]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
console.log("USER AGENT DETECTION RESULTS:");
|
||||||
|
console.log($);
|
||||||
|
|
||||||
|
//console.log("host = " + host);
|
||||||
|
// console.log(url);
|
||||||
|
var queryData = url.parse(req.url, true, true).query;
|
||||||
|
console.log("Responding to http request: " + req.url);
|
||||||
|
//console.log("query data: " + queryData);
|
||||||
|
|
||||||
|
if (queryData.mode) {
|
||||||
|
console.log("mode = " + queryData.mode);
|
||||||
|
if (queryData.mode === "live_view") {
|
||||||
|
// <iframe src="http://www.w3schools.com"></iframe>
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Live View"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<DIV ALIGN=\"CENTER\">"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Live View</H1>";
|
||||||
|
if ($.Android) {
|
||||||
|
//rhtml += "<A HREF=\"vlc://" + host + ":8080/\">Click here to view</A>.<br />(Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)</A>";
|
||||||
|
rhtml += "<IMG WIDTH=\"" + WIDTH + "\" HEIGHT=\"" + HEIGHT + "\" SRC=\"http://" + host + ":8080\"></IMG>";
|
||||||
|
} else if ($.iOS) {
|
||||||
|
//rhtml += "<A HREF=\"infuse://" + host + ":8080\">Click here to view</A>.<br />(Requires the free Infuse app. <A HREF=\"https://itunes.apple.com/us/app/infuse-3/id577130046\">Download it here</A>.)</A>";
|
||||||
|
rhtml += "<A HREF=\"vlc://http://" + host + ":8080/\">Click here to view</A>.<br />(Requires the free VLC app for iOS. <A HREF=\"http://get.videolan.org/vlc-iOS/2.3.0/vlc-iOS-2.3.0.ipa\">Download it here</A>.)</A>";
|
||||||
|
} else {
|
||||||
|
rhtml += "<IFRAME WIDTH=\"" + (WIDTH + PADDING) + "\" HEIGHT=\"" + (HEIGHT + PADDING) + "\" frameBorder=\"0\" seamless=\"seamless\" scrolling=\"no\" frameborder=\"0\" hspace=\"0\" vspace=\"0\" marginheight=\"0\" marginwidth=\"0\" SRC=\"http://" + host + ":8080\"></IFRAME>";
|
||||||
|
}
|
||||||
|
rhtml += "<P><A HREF=\"http://" + hostport + "/\">Back</A></p>"
|
||||||
|
+ "</DIV>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else if (queryData.mode === "file_list") {
|
||||||
|
var headers = {"Content-Type": "text/html"};
|
||||||
|
if (queryData.set_reverse_sort_order) {
|
||||||
|
reverse_sort_order = parseInt(queryData.set_reverse_sort_order);
|
||||||
|
headers["Set-Cookie"] = "reverse_sort_order=" + queryData.set_reverse_sort_order;
|
||||||
|
}
|
||||||
|
fs.readdir("/var/spool/motion", function(err, list) {
|
||||||
|
if(err) {
|
||||||
|
res.writeHead(200, headers);
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: unable to get file list: " + err + "</h1></BODY></HTML>");
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, headers);
|
||||||
|
res.write("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Saved Recordings</TITLE></HEAD><BODY><h1>" + hostname + " - Saved Recordings</h1>");
|
||||||
|
var regex = new RegExp(".*\.avi");
|
||||||
|
var fileList = new Array()
|
||||||
|
async.each(list, function(item, callback) {
|
||||||
|
if(regex.test(item)) {
|
||||||
|
getFileData(item, function(data) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("in final value callback, adding data = " + data);
|
||||||
|
fileList.push(data);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}, function(err) {
|
||||||
|
if (NOISY_DEBUG) {
|
||||||
|
console.log("DONE PROCESSING DIRECTORY LISTING");
|
||||||
|
console.log("fileList = " + fileList);
|
||||||
|
}
|
||||||
|
if (fileList.length > 0) {
|
||||||
|
// sort by date
|
||||||
|
fileList.sort(function(a,b){
|
||||||
|
a = a[0];
|
||||||
|
b = b[0];
|
||||||
|
if (reverse_sort_order) {
|
||||||
|
c = a > b ? -1 : a < b ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
c = a < b ? -1 : a > b ? 1 : 0;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
res.write("<p>Current Sort Order: " +
|
||||||
|
(reverse_sort_order ? "Reverse" : "Forward") +
|
||||||
|
" (<A HREF=\"http://" + hostport + "/?mode=file_list&set_reverse_sort_order=" + (reverse_sort_order ? "0" : "1") + "\">change</A>)</p>");
|
||||||
|
res.write("<UL>");
|
||||||
|
for (var i in fileList) {
|
||||||
|
var item = fileList[i];
|
||||||
|
res.write("<LI>" + item[0].toLocaleDateString() + " @ " + formatAMPM(item[0]) + " (Event #" + item[2] + ") (" + humanFileSize(item[3], true) + (item[4] < 1 ? ", <1s" : ", " + secondsToString(item[4], true)) + ") (<A HREF=\"http://" + hostport + "/?mode=view&filename=" + item[1] + ($.Linux && !$.Android ? "&use_vlc_plugin=true" : "") + "\">view</A>) (<A HREF=\"http://" + hostport + "/?mode=download&filename=" + item[1] + "\">download</A>) (<A HREF=\"http://" + hostport + "/?mode=delete&filename=" + item[1] + "\">delete</A>)</LI>");
|
||||||
|
}
|
||||||
|
res.end("</ul><h3><A HREF=\"http://" + hostport + "/?mode=delete&filename=ALL\">Delete ALL Videos</A></h3><p><A HREF=\"http://" + hostport + "/\">Back</A></p></BODY><FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER></HTML>");
|
||||||
|
} else {
|
||||||
|
res.write("<h3>No Files Found</h3>");
|
||||||
|
res.end("<p><A HREF=\"http://" + hostport + "/\">Back</A></p></BODY><FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER></HTML>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (queryData.mode === "delete") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
if (queryData.confirmed) {
|
||||||
|
var confirmed = queryData.confirmed;
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Delete File(s)"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Delete File(s)</H1>"
|
||||||
|
+ "<p><h3>";
|
||||||
|
if (confirmed === "yes") {
|
||||||
|
var numDeleted = 0;
|
||||||
|
var numErrors = 0;
|
||||||
|
var path = "/var/spool/motion/";
|
||||||
|
if (filename === "ALL") {
|
||||||
|
var files = fs.readdirSync(path);
|
||||||
|
var success = true
|
||||||
|
// nuke the database
|
||||||
|
// db.clear(function(err) {
|
||||||
|
// if (NOISY_DEBUG)
|
||||||
|
// console.log("DATABASE NUKED");
|
||||||
|
// });
|
||||||
|
files.forEach(function(file) {
|
||||||
|
if (file.match("^.*avi$")) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path + file);
|
||||||
|
numDeleted++;
|
||||||
|
rhtml += "Deleted \"" + file + "\"<br />";
|
||||||
|
} catch (ex) {
|
||||||
|
numErrors++;
|
||||||
|
rhtml += "Could not delete \"" + file + "\": " + ex + "<br />";
|
||||||
|
success = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rhtml += "<br />";
|
||||||
|
} else {
|
||||||
|
path += filename;
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path);
|
||||||
|
numDeleted++;
|
||||||
|
success = true;
|
||||||
|
} catch (ex) {
|
||||||
|
numErrors++;
|
||||||
|
rhtml += "Could not delete \"" + filename + "\": " + ex + "<br /><br />";
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
rhtml += numDeleted + " file" + (numDeleted > 1 ? "s" : "") + " deleted successfully.";
|
||||||
|
} else {
|
||||||
|
rhtml += numDeleted > 0 ? numDeleted + " file" + (numDeleted > 1 ? "s" : "") + " deleted successfully." : "";
|
||||||
|
rhtml += numErrors + " delete failure" + (numErrors > 1 ? "s" : "") + ".";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rhtml += "Delete cancelled.";
|
||||||
|
}
|
||||||
|
rhtml += "<h3><A HREF=\"" + hostport + "/?mode=file_list\">OK</A></h3></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else {
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Delete File(s)"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Delete File(s)</H1>"
|
||||||
|
+ "<p><h3>You are about to delete "
|
||||||
|
+ (filename === "ALL" ? "ALL videos!" : "\"" + filename + "\"")
|
||||||
|
+ "<br /><br />"
|
||||||
|
+ "Are you SURE you want to do this?<br /><br />"
|
||||||
|
+ "<A HREF=\"" + hostport + "/?mode=delete&filename=" + filename + "&confirmed=yes\">YES</A> <A HREF=\"" + hostport + "/?mode=delete&filename=" + filename + "&confirmed=no\">NO</A></h3></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
} else if (queryData.mode === "view") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
var filePath = "/var/spool/motion/" + filename;
|
||||||
|
fs.exists(filePath, function(exists) {
|
||||||
|
if (exists) {
|
||||||
|
console.log('viewing contents of local file: ' + filePath);
|
||||||
|
var stat = fs.statSync(filePath);
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'text/html'
|
||||||
|
});
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Video Playback - " + filename
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<DIV ALIGN=\"CENTER\">"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - " + filename + "</H1>";
|
||||||
|
if (queryData.use_vlc_plugin) {
|
||||||
|
rhtml += "<embed type=\"application/x-vlc-plugin\""
|
||||||
|
+ "pluginspage=\"http://www.videolan.org\""
|
||||||
|
+ "name=\"video1\""
|
||||||
|
+ "id=\"video1\""
|
||||||
|
+ "controls=\"yes\" toolbar=\"yes\" autoplay=\"no\" loop=\"yes\" width=\"" + WIDTH + "\" height=\"" + HEIGHT + "\""
|
||||||
|
+ "target=\"http://" + hostport + "/?mode=download&filename=" + filename + "\" />"
|
||||||
|
+ "<br />"
|
||||||
|
+ "(Note: if you don't see a video window above, then you must <A HREF=\"http://www.videolan.org/vlc/download-ubuntu.html\">install the VLC browser plugin</A>.)"
|
||||||
|
+ "<br />";
|
||||||
|
/*
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.play()'>[Play]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.pause()'>[Pause]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.stop()'>[Stop]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.fullscreen()'>[fullscreen]</a>";
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
if ($.Android) {
|
||||||
|
//rhtml += "<A HREF=\"vlc://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)";
|
||||||
|
rhtml += "<A HREF=\"http://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to download this file</A>.<br />Once the file is downloaded, swipe down Notification Center, and tap on the file to open it in VLC. (Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)";
|
||||||
|
rhtml += "<br />Note #2: you may get an error message saying VLC encounterd an error with this media. If so, tap the \"Refresh\" (two arrows going around in circles) button in VLC, and the downloaded file should appear. Seems to be a bug with the latest VLC, they broke it. :-P";
|
||||||
|
} else if ($.iOS) {
|
||||||
|
rhtml += "<A HREF=\"vlc://http://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free VLC app for iOS. <A HREF=\"http://get.videolan.org/vlc-iOS/2.3.0/vlc-iOS-2.3.0.ipa\">Download it here</A>.)";
|
||||||
|
//rhtml += "<A HREF=\"infuse://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free Infuse app. <A HREF=\"https://itunes.apple.com/us/app/infuse-3/id577130046?mt=8\">Download it here</A>.)";
|
||||||
|
} else {
|
||||||
|
rhtml += "<video width=\"" + WIDTH + "\" height=\"" + HEIGHT + "\" controls>"
|
||||||
|
+ "<source src=\"http://" + hostport + "/?mode=download&filename=" + filename + "\" type=\"video/x-msvideo\">"
|
||||||
|
+ "Your browser does not support the video tag."
|
||||||
|
+ "</video>"
|
||||||
|
+ "<br />";
|
||||||
|
// + "<A HREF=\"http://" + hostport + "/?mode=view&filename=" + filename + "&use_vlc_plugin=true\">(Don't see any video? Try this...)</A>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rhtml += "<P><A HREF=\"http://" + hostport + "/?mode=file_list\">Back</A></p>"
|
||||||
|
+ "</DIV>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else {
|
||||||
|
console.log('returning 404, could not find: ' + filePath);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found. Go away kid, you\'re bothering me.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
} else if (queryData.mode === "download") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
var filePath = "/var/spool/motion/" + filename;
|
||||||
|
fs.exists(filePath, function(exists) {
|
||||||
|
if (exists) {
|
||||||
|
console.log('sending contents of local file: ' + filePath);
|
||||||
|
var stat = fs.statSync(filePath);
|
||||||
|
var contenttype = "video/x-msvideo";
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': contenttype,
|
||||||
|
'Content-Length': stat.size,
|
||||||
|
'Content-Disposition': "attachment; filename=" + filename
|
||||||
|
});
|
||||||
|
var readStream = fs.createReadStream(filePath);
|
||||||
|
readStream.pipe(res);
|
||||||
|
} else {
|
||||||
|
console.log('returning 404, could not find: ' + filePath);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found. Go away kid, you\'re bothering me.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// send the index page
|
||||||
|
console.log("Responding with index page");
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML>"
|
||||||
|
+ "<HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS (Open Source Surveillance and Security) - " + hostname + "</TITLE>"
|
||||||
|
+ "</HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<p><h1>OSSS (Open Source Surveillance and Security) - " + hostname + "</h1></p>"
|
||||||
|
+ "<p>"
|
||||||
|
+ "<ul>"
|
||||||
|
+ "<li><A HREF=\"http://" + hostport + "/?mode=live_view\">Live View</A></li>"
|
||||||
|
+ "<li><A HREF=\"http://" + hostport + "/?mode=file_list\">Saved Recordings</A></li>"
|
||||||
|
+ "</UL>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize database
|
||||||
|
var cache_filename = '/tmp/dir_cache';
|
||||||
|
if (DEBUG)
|
||||||
|
cache_filename = '/tmp/dir_cache.debug';
|
||||||
|
var db = nStore.new(cache_filename, function () {
|
||||||
|
console.log('Database initialization complete.');
|
||||||
|
dbIsReady = true;
|
||||||
|
});
|
||||||
|
db.filterFn = function (doc, meta) {
|
||||||
|
//return doc.lastAccess > Date.now() - 360000;
|
||||||
|
return doc.lastAccess > Date.now() - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up the HTTP listener
|
||||||
|
var server = http.createServer(function (req, res) {
|
||||||
|
respondToHttpRequest(req, res);
|
||||||
|
}).listen(PORT);
|
||||||
|
server.on('connection', function(sock) {
|
||||||
|
console.log('Incoming HTTP connection from ' + sock.remoteAddress);
|
||||||
|
});
|
||||||
|
console.log('HTTP server running on port ' + PORT + '.');
|
2
configs/motion/kill_server
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
sudo killall node
|
753
configs/motion/motion-mmal.conf
Normal file
|
@ -0,0 +1,753 @@
|
||||||
|
############################################################
|
||||||
|
# Daemon
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Start in daemon (background) mode and release terminal (default: off)
|
||||||
|
daemon on
|
||||||
|
|
||||||
|
# File to store the process ID, also called pid file. (default: not defined)
|
||||||
|
process_id_file /var/run/motion/motion.pid
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Basic Setup Mode
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Start in Setup-Mode, daemon disabled. (default: off)
|
||||||
|
setup_mode off
|
||||||
|
|
||||||
|
# Use a file to save logs messages, if not defined stderr and syslog is used. (default: not defined)
|
||||||
|
logfile /var/log/motion.log
|
||||||
|
|
||||||
|
# Level of log messages [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC)
|
||||||
|
log_level 5
|
||||||
|
|
||||||
|
# Filter to log messages by type (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). (default: ALL)
|
||||||
|
log_type all
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# Capture device options
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Videodevice to be used for capturing (default /dev/video0)
|
||||||
|
# for FreeBSD default is /dev/bktr0
|
||||||
|
#videodevice /dev/video0
|
||||||
|
|
||||||
|
# v4l2_palette allows to choose preferable palette to be use by motion
|
||||||
|
# to capture from those supported by your videodevice. (default: 17)
|
||||||
|
# E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and
|
||||||
|
# V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG.
|
||||||
|
# Setting v4l2_palette to 2 forces motion to use V4L2_PIX_FMT_SBGGR8
|
||||||
|
# instead.
|
||||||
|
#
|
||||||
|
# Values :
|
||||||
|
# V4L2_PIX_FMT_SN9C10X : 0 'S910'
|
||||||
|
# V4L2_PIX_FMT_SBGGR16 : 1 'BYR2'
|
||||||
|
# V4L2_PIX_FMT_SBGGR8 : 2 'BA81'
|
||||||
|
# V4L2_PIX_FMT_SPCA561 : 3 'S561'
|
||||||
|
# V4L2_PIX_FMT_SGBRG8 : 4 'GBRG'
|
||||||
|
# V4L2_PIX_FMT_SGRBG8 : 5 'GRBG'
|
||||||
|
# V4L2_PIX_FMT_PAC207 : 6 'P207'
|
||||||
|
# V4L2_PIX_FMT_PJPG : 7 'PJPG'
|
||||||
|
# V4L2_PIX_FMT_MJPEG : 8 'MJPEG'
|
||||||
|
# V4L2_PIX_FMT_JPEG : 9 'JPEG'
|
||||||
|
# V4L2_PIX_FMT_RGB24 : 10 'RGB3'
|
||||||
|
# V4L2_PIX_FMT_SPCA501 : 11 'S501'
|
||||||
|
# V4L2_PIX_FMT_SPCA505 : 12 'S505'
|
||||||
|
# V4L2_PIX_FMT_SPCA508 : 13 'S508'
|
||||||
|
# V4L2_PIX_FMT_UYVY : 14 'UYVY'
|
||||||
|
# V4L2_PIX_FMT_YUYV : 15 'YUYV'
|
||||||
|
# V4L2_PIX_FMT_YUV422P : 16 '422P'
|
||||||
|
# V4L2_PIX_FMT_YUV420 : 17 'YU12'
|
||||||
|
#
|
||||||
|
v4l2_palette 17
|
||||||
|
|
||||||
|
# Tuner device to be used for capturing using tuner as source (default /dev/tuner0)
|
||||||
|
# This is ONLY used for FreeBSD. Leave it commented out for Linux
|
||||||
|
; tunerdevice /dev/tuner0
|
||||||
|
|
||||||
|
# The video input to be used (default: -1)
|
||||||
|
# Should normally be set to 0 or 1 for video/TV cards, and -1 for USB cameras
|
||||||
|
input -1
|
||||||
|
|
||||||
|
# The video norm to use (only for video capture and TV tuner cards)
|
||||||
|
# Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL)
|
||||||
|
norm 0
|
||||||
|
|
||||||
|
# The frequency to set the tuner to (kHz) (only for TV tuner cards) (default: 0)
|
||||||
|
frequency 0
|
||||||
|
|
||||||
|
# Rotate image this number of degrees. The rotation affects all saved images as
|
||||||
|
# well as movies. Valid values: 0 (default = no rotation), 90, 180 and 270.
|
||||||
|
rotate 0
|
||||||
|
|
||||||
|
# Image width (pixels). Valid range: Camera dependent, default: 352
|
||||||
|
width 1280
|
||||||
|
|
||||||
|
# Image height (pixels). Valid range: Camera dependent, default: 288
|
||||||
|
height 720
|
||||||
|
|
||||||
|
# Maximum number of frames to be captured per second.
|
||||||
|
# Valid range: 2-100. Default: 100 (almost no limit).
|
||||||
|
framerate 30
|
||||||
|
|
||||||
|
# Minimum time in seconds between capturing picture frames from the camera.
|
||||||
|
# Default: 0 = disabled - the capture rate is given by the camera framerate.
|
||||||
|
# This option is used when you want to capture images at a rate lower than 2 per second.
|
||||||
|
minimum_frame_time 0
|
||||||
|
|
||||||
|
# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// mjpg:// or file:///)
|
||||||
|
# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. Default: Not defined
|
||||||
|
;netcam_url http://127.0.0.1/cgi-bin/raspicam.sh
|
||||||
|
|
||||||
|
# Username and password for network camera (only if required). Default: not defined
|
||||||
|
# Syntax is user:password
|
||||||
|
; netcam_userpass value
|
||||||
|
|
||||||
|
# The setting for keep-alive of network socket, should improve performance on compatible net cameras.
|
||||||
|
# off: The historical implementation using HTTP/1.0, closing the socket after each http request.
|
||||||
|
# force: Use HTTP/1.0 requests with keep alive header to reuse the same connection.
|
||||||
|
# on: Use HTTP/1.1 requests that support keep alive as default.
|
||||||
|
# Default: off
|
||||||
|
netcam_keepalive off
|
||||||
|
|
||||||
|
# URL to use for a netcam proxy server, if required, e.g. "http://myproxy".
|
||||||
|
# If a port number other than 80 is needed, use "http://myproxy:1234".
|
||||||
|
# Default: not defined
|
||||||
|
; netcam_proxy value
|
||||||
|
|
||||||
|
# Set less strict jpeg checks for network cameras with a poor/buggy firmware.
|
||||||
|
# Default: off
|
||||||
|
netcam_tolerant_check off
|
||||||
|
|
||||||
|
# Let motion regulate the brightness of a video device (default: off).
|
||||||
|
# The auto_brightness feature uses the brightness option as its target value.
|
||||||
|
# If brightness is zero auto_brightness will adjust to average brightness value 128.
|
||||||
|
# Only recommended for cameras without auto brightness
|
||||||
|
auto_brightness off
|
||||||
|
|
||||||
|
# Set the initial brightness of a video device.
|
||||||
|
# If auto_brightness is enabled, this value defines the average brightness level
|
||||||
|
# which Motion will try and adjust to.
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
brightness 0
|
||||||
|
|
||||||
|
# Set the contrast of a video device.
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
contrast 0
|
||||||
|
|
||||||
|
# Set the saturation of a video device.
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
saturation 0
|
||||||
|
|
||||||
|
# Set the hue of a video device (NTSC feature).
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
hue 0
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# File "camera" support - read raw YUV data from a file
|
||||||
|
############################################################
|
||||||
|
#filecam_path /home/pi/test-cap/motion-mmal.capture
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# OpenMax/MMAL camera support for Raspberry Pi
|
||||||
|
############################################################
|
||||||
|
mmalcam_name vc.ril.camera
|
||||||
|
#mmalcam_control_params
|
||||||
|
#mmalcam_raw_capture_file /home/pi/motion-mmal.capture
|
||||||
|
|
||||||
|
# Switch this setting to "on" to use the still image mode of the Pi's camera
|
||||||
|
# instead of video. This gives a wider field of view, but requires
|
||||||
|
# a much slower frame-rate to achieve exposure stability
|
||||||
|
# (e.g. 0.25 fps or slower). You can use the minimum_frame_time
|
||||||
|
# parameter above to achieve this
|
||||||
|
|
||||||
|
mmalcam_use_still off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Round Robin (multiple inputs on same video device name)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Number of frames to capture in each roundrobin step (default: 1)
|
||||||
|
roundrobin_frames 1
|
||||||
|
|
||||||
|
# Number of frames to skip before each roundrobin step (default: 1)
|
||||||
|
roundrobin_skip 1
|
||||||
|
|
||||||
|
# Try to filter out noise generated by roundrobin (default: off)
|
||||||
|
switchfilter off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Motion Detection Settings:
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Threshold for number of changed pixels in an image that
|
||||||
|
# triggers motion detection (default: 1500)
|
||||||
|
threshold 1500
|
||||||
|
|
||||||
|
# Automatically tune the threshold down if possible (default: off)
|
||||||
|
threshold_tune off
|
||||||
|
|
||||||
|
# Noise threshold for the motion detection (default: 32)
|
||||||
|
noise_level 32
|
||||||
|
|
||||||
|
# Automatically tune the noise threshold (default: on)
|
||||||
|
noise_tune on
|
||||||
|
|
||||||
|
# Despeckle motion image using (e)rode or (d)ilate or (l)abel (Default: not defined)
|
||||||
|
# Recommended value is EedDl. Any combination (and number of) of E, e, d, and D is valid.
|
||||||
|
# (l)abeling must only be used once and the 'l' must be the last letter.
|
||||||
|
# Comment out to disable
|
||||||
|
despeckle_filter EedDl
|
||||||
|
|
||||||
|
# Detect motion in predefined areas (1 - 9). Areas are numbered like that: 1 2 3
|
||||||
|
# A script (on_area_detected) is started immediately when motion is 4 5 6
|
||||||
|
# detected in one of the given areas, but only once during an event. 7 8 9
|
||||||
|
# One or more areas can be specified with this option. Take care: This option
|
||||||
|
# does NOT restrict detection to these areas! (Default: not defined)
|
||||||
|
; area_detect value
|
||||||
|
|
||||||
|
# PGM file to use as a sensitivity mask.
|
||||||
|
# Full path name to. (Default: not defined)
|
||||||
|
; mask_file value
|
||||||
|
|
||||||
|
# Dynamically create a mask file during operation (default: 0)
|
||||||
|
# Adjust speed of mask changes from 0 (off) to 10 (fast)
|
||||||
|
smart_mask_speed 0
|
||||||
|
|
||||||
|
# Ignore sudden massive light intensity changes given as a percentage of the picture
|
||||||
|
# area that changed intensity. Valid range: 0 - 100 , default: 0 = disabled
|
||||||
|
lightswitch 0
|
||||||
|
|
||||||
|
# Picture frames must contain motion at least the specified number of frames
|
||||||
|
# in a row before they are detected as true motion. At the default of 1, all
|
||||||
|
# motion is detected. Valid range: 1 to thousands, recommended 1-5
|
||||||
|
minimum_motion_frames 1
|
||||||
|
|
||||||
|
# Specifies the number of pre-captured (buffered) pictures from before motion
|
||||||
|
# was detected that will be output at motion detection.
|
||||||
|
# Recommended range: 0 to 5 (default: 0)
|
||||||
|
# Do not use large values! Large values will cause Motion to skip video frames and
|
||||||
|
# cause unsmooth movies. To smooth movies use larger values of post_capture instead.
|
||||||
|
pre_capture 2
|
||||||
|
|
||||||
|
# Number of frames to capture after motion is no longer detected (default: 0)
|
||||||
|
post_capture 2
|
||||||
|
|
||||||
|
max_mpeg_time 600
|
||||||
|
|
||||||
|
# Event Gap is the seconds of no motion detection that triggers the end of an event.
|
||||||
|
# An event is defined as a series of motion images taken within a short timeframe.
|
||||||
|
# Recommended value is 60 seconds (Default). The value -1 is allowed and disables
|
||||||
|
# events causing all Motion to be written to one single movie file and no pre_capture.
|
||||||
|
# If set to 0, motion is running in gapless mode. Movies don't have gaps anymore. An
|
||||||
|
# event ends right after no more motion is detected and post_capture is over.
|
||||||
|
event_gap 60
|
||||||
|
|
||||||
|
# Maximum length in seconds of a movie
|
||||||
|
# When value is exceeded a new movie file is created. (Default: 0 = infinite)
|
||||||
|
max_movie_time 0
|
||||||
|
|
||||||
|
# Always save images even if there was no motion (default: off)
|
||||||
|
emulate_motion off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Image File Output
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Output 'normal' pictures when motion is detected (default: on)
|
||||||
|
# Valid values: on, off, first, best, center
|
||||||
|
# When set to 'first', only the first picture of an event is saved.
|
||||||
|
# Picture with most motion of an event is saved when set to 'best'.
|
||||||
|
# Picture with motion nearest center of picture is saved when set to 'center'.
|
||||||
|
# Can be used as preview shot for the corresponding movie.
|
||||||
|
output_pictures on
|
||||||
|
|
||||||
|
# Output pictures with only the pixels moving object (ghost images) (default: off)
|
||||||
|
output_debug_pictures off
|
||||||
|
|
||||||
|
# The quality (in percent) to be used by the jpeg compression (default: 75)
|
||||||
|
quality 75
|
||||||
|
|
||||||
|
# Type of output images
|
||||||
|
# Valid values: jpeg, ppm (default: jpeg)
|
||||||
|
picture_type jpeg
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# FFMPEG related options
|
||||||
|
# Film (movies) file output, and deinterlacing of the video input
|
||||||
|
# The options movie_filename and timelapse_filename are also used
|
||||||
|
# by the ffmpeg feature
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Use ffmpeg to encode movies in realtime (default: off)
|
||||||
|
ffmpeg_output_movies on
|
||||||
|
|
||||||
|
# Use ffmpeg to make movies with only the pixels moving
|
||||||
|
# object (ghost images) (default: off)
|
||||||
|
ffmpeg_output_debug_movies off
|
||||||
|
|
||||||
|
# Use ffmpeg to encode a timelapse movie
|
||||||
|
# Default value 0 = off - else save frame every Nth second
|
||||||
|
ffmpeg_timelapse 0
|
||||||
|
|
||||||
|
# The file rollover mode of the timelapse video
|
||||||
|
# Valid values: hourly, daily (default), weekly-sunday, weekly-monday, monthly, manual
|
||||||
|
ffmpeg_timelapse_mode daily
|
||||||
|
|
||||||
|
# Bitrate to be used by the ffmpeg encoder (default: 400000)
|
||||||
|
# This option is ignored if ffmpeg_variable_bitrate is not 0 (disabled)
|
||||||
|
ffmpeg_bps 500000
|
||||||
|
|
||||||
|
# Enables and defines variable bitrate for the ffmpeg encoder.
|
||||||
|
# ffmpeg_bps is ignored if variable bitrate is enabled.
|
||||||
|
# Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps,
|
||||||
|
# or the range 2 - 31 where 2 means best quality and 31 is worst.
|
||||||
|
ffmpeg_variable_bitrate 0
|
||||||
|
|
||||||
|
# Codec to used by ffmpeg for the video compression.
|
||||||
|
# Timelapse mpegs are always made in mpeg1 format independent from this option.
|
||||||
|
# Supported formats are: mpeg1 (ffmpeg-0.4.8 only), mpeg4 (default), and msmpeg4.
|
||||||
|
# mpeg1 - gives you files with extension .mpg
|
||||||
|
# mpeg4 or msmpeg4 - gives you files with extension .avi
|
||||||
|
# msmpeg4 is recommended for use with Windows Media Player because
|
||||||
|
# it requires no installation of codec on the Windows client.
|
||||||
|
# swf - gives you a flash film with extension .swf
|
||||||
|
# flv - gives you a flash video with extension .flv
|
||||||
|
# ffv1 - FF video codec 1 for Lossless Encoding ( experimental )
|
||||||
|
# mov - QuickTime ( testing )
|
||||||
|
# ogg - Ogg/Theora ( testing )
|
||||||
|
#ffmpeg_video_codec mpeg4
|
||||||
|
ffmpeg_video_codec msmpeg4
|
||||||
|
|
||||||
|
# Use ffmpeg to deinterlace video. Necessary if you use an analog camera
|
||||||
|
# and see horizontal combing on moving objects in video or pictures.
|
||||||
|
# (default: off)
|
||||||
|
ffmpeg_deinterlace off
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# SDL Window
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Number of motion thread to show in SDL Window (default: 0 = disabled)
|
||||||
|
#sdl_threadnr 0
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# External pipe to video encoder
|
||||||
|
# Replacement for FFMPEG builtin encoder for ffmpeg_output_movies only.
|
||||||
|
# The options movie_filename and timelapse_filename are also used
|
||||||
|
# by the ffmpeg feature
|
||||||
|
#############################################################
|
||||||
|
|
||||||
|
# Bool to enable or disable extpipe (default: off)
|
||||||
|
use_extpipe off
|
||||||
|
|
||||||
|
# External program (full path and opts) to pipe raw video to
|
||||||
|
# Generally, use '-' for STDIN...
|
||||||
|
;extpipe mencoder -demuxer rawvideo -rawvideo w=320:h=240:i420 -ovc x264 -x264encopts bframes=4:frameref=1:subq=1:scenecut=-1:nob_adapt:threads=1:keyint=1000:8x8dct:vbv_bufsize=4000:crf=24:partitions=i8x8,i4x4:vbv_maxrate=800:no-chroma-me -vf denoise3d=16:12:48:4,pp=lb -of avi -o %f.avi - -fps %fps
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Snapshots (Traditional Periodic Webcam File Output)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Make automated snapshot every N seconds (default: 0 = disabled)
|
||||||
|
snapshot_interval 0
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Text Display
|
||||||
|
# %Y = year, %m = month, %d = date,
|
||||||
|
# %H = hour, %M = minute, %S = second, %T = HH:MM:SS,
|
||||||
|
# %v = event, %q = frame number, %t = thread (camera) number,
|
||||||
|
# %D = changed pixels, %N = noise level, \n = new line,
|
||||||
|
# %i and %J = width and height of motion area,
|
||||||
|
# %K and %L = X and Y coordinates of motion center
|
||||||
|
# %C = value defined by text_event - do not use with text_event!
|
||||||
|
# You can put quotation marks around the text to allow
|
||||||
|
# leading spaces
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Locate and draw a box around the moving object.
|
||||||
|
# Valid values: on, off, preview (default: off)
|
||||||
|
# Set to 'preview' will only draw a box in preview_shot pictures.
|
||||||
|
locate_motion_mode on
|
||||||
|
|
||||||
|
# Set the look and style of the locate box if enabled.
|
||||||
|
# Valid values: box, redbox, cross, redcross (default: box)
|
||||||
|
# Set to 'box' will draw the traditional box.
|
||||||
|
# Set to 'redbox' will draw a red box.
|
||||||
|
# Set to 'cross' will draw a little cross to mark center.
|
||||||
|
# Set to 'redcross' will draw a little red cross to mark center.
|
||||||
|
locate_motion_style box
|
||||||
|
|
||||||
|
# Draws the timestamp using same options as C function strftime(3)
|
||||||
|
# Default: %Y-%m-%d\n%T = date in ISO format and time in 24 hour clock
|
||||||
|
# Text is placed in lower right corner
|
||||||
|
text_right %Y-%m-%d\n%T-%q
|
||||||
|
|
||||||
|
# Draw a user defined text on the images using same options as C function strftime(3)
|
||||||
|
# Default: Not defined = no text
|
||||||
|
# Text is placed in lower left corner
|
||||||
|
; text_left CAMERA %t
|
||||||
|
|
||||||
|
# Draw the number of changed pixed on the images (default: off)
|
||||||
|
# Will normally be set to off except when you setup and adjust the motion settings
|
||||||
|
# Text is placed in upper right corner
|
||||||
|
text_changes off
|
||||||
|
|
||||||
|
# This option defines the value of the special event conversion specifier %C
|
||||||
|
# You can use any conversion specifier in this option except %C. Date and time
|
||||||
|
# values are from the timestamp of the first image in the current event.
|
||||||
|
# Default: %Y%m%d%H%M%S
|
||||||
|
# The idea is that %C can be used filenames and text_left/right for creating
|
||||||
|
# a unique identifier for each event.
|
||||||
|
text_event %Y%m%d%H%M%S
|
||||||
|
|
||||||
|
# Draw characters at twice normal size on images. (default: off)
|
||||||
|
text_double on
|
||||||
|
|
||||||
|
|
||||||
|
# Text to include in a JPEG EXIF comment
|
||||||
|
# May be any text, including conversion specifiers.
|
||||||
|
# The EXIF timestamp is included independent of this text.
|
||||||
|
;exif_text %i%J/%K%L
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Target Directories and filenames For Images And Films
|
||||||
|
# For the options snapshot_, picture_, movie_ and timelapse_filename
|
||||||
|
# you can use conversion specifiers
|
||||||
|
# %Y = year, %m = month, %d = date,
|
||||||
|
# %H = hour, %M = minute, %S = second,
|
||||||
|
# %v = event, %q = frame number, %t = thread (camera) number,
|
||||||
|
# %D = changed pixels, %N = noise level,
|
||||||
|
# %i and %J = width and height of motion area,
|
||||||
|
# %K and %L = X and Y coordinates of motion center
|
||||||
|
# %C = value defined by text_event
|
||||||
|
# Quotation marks round string are allowed.
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Target base directory for pictures and films
|
||||||
|
# Recommended to use absolute path. (Default: current working directory)
|
||||||
|
target_dir /var/spool/motion
|
||||||
|
|
||||||
|
# File path for snapshots (jpeg or ppm) relative to target_dir
|
||||||
|
# Default: %v-%Y%m%d%H%M%S-snapshot
|
||||||
|
# Default value is equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-snapshot
|
||||||
|
# File extension .jpg or .ppm is automatically added so do not include this.
|
||||||
|
# Note: A symbolic link called lastsnap.jpg created in the target_dir will always
|
||||||
|
# point to the latest snapshot, unless snapshot_filename is exactly 'lastsnap'
|
||||||
|
#snapshot_filename FINDME
|
||||||
|
snapshot_filename %v-%Y-%m-%dT%H:%M:%S-snapshot
|
||||||
|
|
||||||
|
# File path for motion triggered images (jpeg or ppm) relative to target_dir
|
||||||
|
# Default: %v-%Y%m%d%H%M%S-%q
|
||||||
|
# Default value is equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q
|
||||||
|
# File extension .jpg or .ppm is automatically added so do not include this
|
||||||
|
# Set to 'preview' together with best-preview feature enables special naming
|
||||||
|
# convention for preview shots. See motion guide for details
|
||||||
|
#picture_filename %v-%Y%m%d%H%M%S-%q
|
||||||
|
picture_filename %v-%Y-%m-%dT%H:%M:%S-%q
|
||||||
|
|
||||||
|
# File path for motion triggered ffmpeg films (movies) relative to target_dir
|
||||||
|
# Default: %v-%Y%m%d%H%M%S
|
||||||
|
# Default value is equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H%M%S
|
||||||
|
# File extension .mpg or .avi is automatically added so do not include this
|
||||||
|
# This option was previously called ffmpeg_filename
|
||||||
|
#movie_filename %v-%Y%m%d%H%M%S
|
||||||
|
movie_filename %v-%Y-%m-%dT%H:%M:%S
|
||||||
|
|
||||||
|
# File path for timelapse movies relative to target_dir
|
||||||
|
# Default: %Y%m%d-timelapse
|
||||||
|
# Default value is near equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d-timelapse
|
||||||
|
# File extension .mpg is automatically added so do not include this
|
||||||
|
#timelapse_filename %Y%m%d-timelapse
|
||||||
|
timelapse_filename %Y-%m-%d-timelapse
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Global Network Options
|
||||||
|
############################################################
|
||||||
|
# Enable or disable IPV6 for http control and stream (default: off )
|
||||||
|
ipv6_enabled off
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Live Stream Server
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# The mini-http server listens to this port for requests (default: 0 = disabled)
|
||||||
|
stream_port 8080
|
||||||
|
|
||||||
|
# Quality of the jpeg (in percent) images produced (default: 50)
|
||||||
|
stream_quality 50
|
||||||
|
|
||||||
|
# Output frames at 1 fps when no motion is detected and increase to the
|
||||||
|
# rate given by stream_maxrate when motion is detected (default: off)
|
||||||
|
stream_motion off
|
||||||
|
|
||||||
|
# Maximum framerate for stream streams (default: 1)
|
||||||
|
stream_maxrate 1
|
||||||
|
|
||||||
|
# Restrict stream connections to localhost only (default: on)
|
||||||
|
stream_localhost off
|
||||||
|
|
||||||
|
# Limits the number of images per connection (default: 0 = unlimited)
|
||||||
|
# Number can be defined by multiplying actual stream rate by desired number of seconds
|
||||||
|
# Actual stream rate is the smallest of the numbers framerate and stream_maxrate
|
||||||
|
stream_limit 0
|
||||||
|
|
||||||
|
# Set the authentication method (default: 0)
|
||||||
|
# 0 = disabled
|
||||||
|
# 1 = Basic authentication
|
||||||
|
# 2 = MD5 digest (the safer authentication)
|
||||||
|
stream_auth_method 0
|
||||||
|
|
||||||
|
# Authentication for the stream. Syntax username:password
|
||||||
|
# Default: not defined (Disabled)
|
||||||
|
; stream_authentication username:password
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# HTTP Based Control
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# TCP/IP port for the http server to listen on (default: 0 = disabled)
|
||||||
|
webcontrol_port 8081
|
||||||
|
|
||||||
|
# Restrict control connections to localhost only (default: on)
|
||||||
|
webcontrol_localhost off
|
||||||
|
|
||||||
|
# Output for http server, select off to choose raw text plain (default: on)
|
||||||
|
webcontrol_html_output on
|
||||||
|
|
||||||
|
# Authentication for the http based control. Syntax username:password
|
||||||
|
# Default: not defined (Disabled)
|
||||||
|
; webcontrol_authentication username:password
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Tracking (Pan/Tilt)
|
||||||
|
#############################################################
|
||||||
|
|
||||||
|
# Type of tracker (0=none (default), 1=stepper, 2=iomojo, 3=pwc, 4=generic, 5=uvcvideo, 6=servo)
|
||||||
|
# The generic type enables the definition of motion center and motion size to
|
||||||
|
# be used with the conversion specifiers for options like on_motion_detected
|
||||||
|
track_type 0
|
||||||
|
|
||||||
|
# Enable auto tracking (default: off)
|
||||||
|
track_auto off
|
||||||
|
|
||||||
|
# Serial port of motor (default: none)
|
||||||
|
;track_port /dev/ttyS0
|
||||||
|
|
||||||
|
# Motor number for x-axis (default: 0)
|
||||||
|
;track_motorx 0
|
||||||
|
|
||||||
|
# Set motorx reverse (default: 0)
|
||||||
|
;track_motorx_reverse 0
|
||||||
|
|
||||||
|
# Motor number for y-axis (default: 0)
|
||||||
|
;track_motory 1
|
||||||
|
|
||||||
|
# Set motory reverse (default: 0)
|
||||||
|
;track_motory_reverse 0
|
||||||
|
|
||||||
|
# Maximum value on x-axis (default: 0)
|
||||||
|
;track_maxx 200
|
||||||
|
|
||||||
|
# Minimum value on x-axis (default: 0)
|
||||||
|
;track_minx 50
|
||||||
|
|
||||||
|
# Maximum value on y-axis (default: 0)
|
||||||
|
;track_maxy 200
|
||||||
|
|
||||||
|
# Minimum value on y-axis (default: 0)
|
||||||
|
;track_miny 50
|
||||||
|
|
||||||
|
# Center value on x-axis (default: 0)
|
||||||
|
;track_homex 128
|
||||||
|
|
||||||
|
# Center value on y-axis (default: 0)
|
||||||
|
;track_homey 128
|
||||||
|
|
||||||
|
# ID of an iomojo camera if used (default: 0)
|
||||||
|
track_iomojo_id 0
|
||||||
|
|
||||||
|
# Angle in degrees the camera moves per step on the X-axis
|
||||||
|
# with auto-track (default: 10)
|
||||||
|
# Currently only used with pwc type cameras
|
||||||
|
track_step_angle_x 10
|
||||||
|
|
||||||
|
# Angle in degrees the camera moves per step on the Y-axis
|
||||||
|
# with auto-track (default: 10)
|
||||||
|
# Currently only used with pwc type cameras
|
||||||
|
track_step_angle_y 10
|
||||||
|
|
||||||
|
# Delay to wait for after tracking movement as number
|
||||||
|
# of picture frames (default: 10)
|
||||||
|
track_move_wait 10
|
||||||
|
|
||||||
|
# Speed to set the motor to (stepper motor option) (default: 255)
|
||||||
|
track_speed 255
|
||||||
|
|
||||||
|
# Number of steps to make (stepper motor option) (default: 40)
|
||||||
|
track_stepsize 40
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# External Commands, Warnings and Logging:
|
||||||
|
# You can use conversion specifiers for the on_xxxx commands
|
||||||
|
# %Y = year, %m = month, %d = date,
|
||||||
|
# %H = hour, %M = minute, %S = second,
|
||||||
|
# %v = event, %q = frame number, %t = thread (camera) number,
|
||||||
|
# %D = changed pixels, %N = noise level,
|
||||||
|
# %i and %J = width and height of motion area,
|
||||||
|
# %K and %L = X and Y coordinates of motion center
|
||||||
|
# %C = value defined by text_event
|
||||||
|
# %f = filename with full path
|
||||||
|
# %n = number indicating filetype
|
||||||
|
# Both %f and %n are only defined for on_picture_save,
|
||||||
|
# on_movie_start and on_movie_end
|
||||||
|
# Quotation marks round string are allowed.
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Do not sound beeps when detecting motion (default: on)
|
||||||
|
# Note: Motion never beeps when running in daemon mode.
|
||||||
|
quiet on
|
||||||
|
|
||||||
|
# Command to be executed when an event starts. (default: none)
|
||||||
|
# An event starts at first motion detected after a period of no motion defined by event_gap
|
||||||
|
; on_event_start value
|
||||||
|
|
||||||
|
# Command to be executed when an event ends after a period of no motion
|
||||||
|
# (default: none). The period of no motion is defined by option event_gap.
|
||||||
|
; on_event_end value
|
||||||
|
|
||||||
|
# Command to be executed when a picture (.ppm|.jpg) is saved (default: none)
|
||||||
|
# To give the filename as an argument to a command append it with %f
|
||||||
|
; on_picture_save value
|
||||||
|
|
||||||
|
# Command to be executed when a motion frame is detected (default: none)
|
||||||
|
; on_motion_detected value
|
||||||
|
|
||||||
|
# Command to be executed when motion in a predefined area is detected
|
||||||
|
# Check option 'area_detect'. (default: none)
|
||||||
|
; on_area_detected value
|
||||||
|
|
||||||
|
# Command to be executed when a movie file (.mpg|.avi) is created. (default: none)
|
||||||
|
# To give the filename as an argument to a command append it with %f
|
||||||
|
; on_movie_start value
|
||||||
|
|
||||||
|
# Command to be executed when a movie file (.mpg|.avi) is closed. (default: none)
|
||||||
|
# To give the filename as an argument to a command append it with %f
|
||||||
|
; on_movie_end value
|
||||||
|
|
||||||
|
# Command to be executed when a camera can't be opened or if it is lost
|
||||||
|
# NOTE: There is situations when motion don't detect a lost camera!
|
||||||
|
# It depends on the driver, some drivers dosn't detect a lost camera at all
|
||||||
|
# Some hangs the motion thread. Some even hangs the PC! (default: none)
|
||||||
|
; on_camera_lost value
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Common Options for database features.
|
||||||
|
# Options require database options to be active also.
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
# Log to the database when creating motion triggered picture file (default: on)
|
||||||
|
; sql_log_picture on
|
||||||
|
|
||||||
|
# Log to the database when creating a snapshot image file (default: on)
|
||||||
|
; sql_log_snapshot on
|
||||||
|
|
||||||
|
# Log to the database when creating motion triggered movie file (default: off)
|
||||||
|
; sql_log_movie off
|
||||||
|
|
||||||
|
# Log to the database when creating timelapse movies file (default: off)
|
||||||
|
; sql_log_timelapse off
|
||||||
|
|
||||||
|
# SQL query string that is sent to the database
|
||||||
|
# Use same conversion specifiers has for text features
|
||||||
|
# Additional special conversion specifiers are
|
||||||
|
# %n = the number representing the file_type
|
||||||
|
# %f = filename with full path
|
||||||
|
# Default value:
|
||||||
|
# Create tables :
|
||||||
|
##
|
||||||
|
# Mysql
|
||||||
|
# CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp(14), event_time_stamp timestamp(14));
|
||||||
|
#
|
||||||
|
# Postgresql
|
||||||
|
# CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp without time zone, event_time_stamp timestamp without time zone);
|
||||||
|
#
|
||||||
|
# insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
|
||||||
|
; sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Database Options
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# database type : mysql, postgresql, sqlite3 (default : not defined)
|
||||||
|
; database_type value
|
||||||
|
|
||||||
|
# database to log to (default: not defined)
|
||||||
|
; database_dbname value
|
||||||
|
|
||||||
|
# The host on which the database is located (default: localhost)
|
||||||
|
; database_host value
|
||||||
|
|
||||||
|
# User account name for database (default: not defined)
|
||||||
|
; database_user value
|
||||||
|
|
||||||
|
# User password for database (default: not defined)
|
||||||
|
; database_password value
|
||||||
|
|
||||||
|
# Port on which the database is located
|
||||||
|
# mysql 3306 , postgresql 5432 (default: not defined)
|
||||||
|
; database_port value
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Database Options For SQLite3
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# SQLite3 database (file path) (default: not defined)
|
||||||
|
; sqlite3_db value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Video Loopback Device (vloopback project)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Output images to a video4linux loopback device
|
||||||
|
# The value '-' means next available (default: not defined)
|
||||||
|
; video_pipe value
|
||||||
|
|
||||||
|
# Output motion images to a video4linux loopback device
|
||||||
|
# The value '-' means next available (default: not defined)
|
||||||
|
; motion_video_pipe value
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
# Thread config files - One for each camera.
|
||||||
|
# Except if only one camera - You only need this config file.
|
||||||
|
# If you have more than one camera you MUST define one thread
|
||||||
|
# config file for each camera in addition to this config file.
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
# Remember: If you have more than one camera you must have one
|
||||||
|
# thread file for each camera. E.g. 2 cameras requires 3 files:
|
||||||
|
# This motion.conf file AND thread1.conf and thread2.conf.
|
||||||
|
# Only put the options that are unique to each camera in the
|
||||||
|
# thread config files.
|
||||||
|
; thread /usr/local/etc/thread1.conf
|
||||||
|
; thread /usr/local/etc/thread2.conf
|
||||||
|
; thread /usr/local/etc/thread3.conf
|
||||||
|
; thread /usr/local/etc/thread4.conf
|
||||||
|
|
653
configs/motion/motion.conf
Normal file
|
@ -0,0 +1,653 @@
|
||||||
|
# Rename this distribution example file to motion.conf
|
||||||
|
#
|
||||||
|
# This config file was generated by motion 3.2.12
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Daemon
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Start in daemon (background) mode and release terminal (default: off)
|
||||||
|
daemon off
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logfile /var/log/motion.log
|
||||||
|
|
||||||
|
# File to store the process ID, also called pid file. (default: not defined)
|
||||||
|
process_id_file /var/run/motion/motion.pid
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Basic Setup Mode
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Start in Setup-Mode, daemon disabled. (default: off)
|
||||||
|
setup_mode off
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# Capture device options
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Videodevice to be used for capturing (default /dev/video0)
|
||||||
|
# for FreeBSD default is /dev/bktr0
|
||||||
|
videodevice /dev/video0
|
||||||
|
|
||||||
|
# v4l2_palette allows to choose preferable palette to be use by motion
|
||||||
|
# to capture from those supported by your videodevice. (default: 8)
|
||||||
|
# E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and
|
||||||
|
# V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG.
|
||||||
|
# Setting v4l2_palette to 1 forces motion to use V4L2_PIX_FMT_SBGGR8
|
||||||
|
# instead.
|
||||||
|
#
|
||||||
|
# Values :
|
||||||
|
# V4L2_PIX_FMT_SN9C10X : 0 'S910'
|
||||||
|
# V4L2_PIX_FMT_SBGGR8 : 1 'BA81'
|
||||||
|
# V4L2_PIX_FMT_MJPEG : 2 'MJPEG'
|
||||||
|
# V4L2_PIX_FMT_JPEG : 3 'JPEG'
|
||||||
|
# V4L2_PIX_FMT_RGB24 : 4 'RGB3'
|
||||||
|
# V4L2_PIX_FMT_UYVY : 5 'UYVY'
|
||||||
|
# V4L2_PIX_FMT_YUYV : 6 'YUYV'
|
||||||
|
# V4L2_PIX_FMT_YUV422P : 7 '422P'
|
||||||
|
# V4L2_PIX_FMT_YUV420 : 8 'YU12'
|
||||||
|
v4l2_palette 8
|
||||||
|
|
||||||
|
# Tuner device to be used for capturing using tuner as source (default /dev/tuner0)
|
||||||
|
# This is ONLY used for FreeBSD. Leave it commented out for Linux
|
||||||
|
; tunerdevice /dev/tuner0
|
||||||
|
|
||||||
|
# The video input to be used (default: 8)
|
||||||
|
# Should normally be set to 0 or 1 for video/TV cards, and 8 for USB cameras
|
||||||
|
input 8
|
||||||
|
|
||||||
|
# The video norm to use (only for video capture and TV tuner cards)
|
||||||
|
# Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL)
|
||||||
|
norm 0
|
||||||
|
|
||||||
|
# The frequency to set the tuner to (kHz) (only for TV tuner cards) (default: 0)
|
||||||
|
frequency 0
|
||||||
|
|
||||||
|
# Rotate image this number of degrees. The rotation affects all saved images as
|
||||||
|
# well as mpeg movies. Valid values: 0 (default = no rotation), 90, 180 and 270.
|
||||||
|
rotate 0
|
||||||
|
|
||||||
|
# Image width (pixels). Valid range: Camera dependent, default: 352
|
||||||
|
width 320
|
||||||
|
|
||||||
|
# Image height (pixels). Valid range: Camera dependent, default: 288
|
||||||
|
height 240
|
||||||
|
|
||||||
|
# Maximum number of frames to be captured per second.
|
||||||
|
# Valid range: 2-100. Default: 100 (almost no limit).
|
||||||
|
framerate 30
|
||||||
|
|
||||||
|
# Minimum time in seconds between capturing picture frames from the camera.
|
||||||
|
# Default: 0 = disabled - the capture rate is given by the camera framerate.
|
||||||
|
# This option is used when you want to capture images at a rate lower than 2 per second.
|
||||||
|
minimum_frame_time 0
|
||||||
|
|
||||||
|
# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// or file:///)
|
||||||
|
# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. Default: Not defined
|
||||||
|
; netcam_url value
|
||||||
|
|
||||||
|
# Username and password for network camera (only if required). Default: not defined
|
||||||
|
# Syntax is user:password
|
||||||
|
; netcam_userpass value
|
||||||
|
|
||||||
|
# The setting for keep-alive of network socket, should improve performance on compatible net cameras.
|
||||||
|
# 1.0: The historical implementation using HTTP/1.0, closing the socket after each http request.
|
||||||
|
# keep_alive: Use HTTP/1.0 requests with keep alive header to reuse the same connection.
|
||||||
|
# 1.1: Use HTTP/1.1 requests that support keep alive as default.
|
||||||
|
# Default: 1.0
|
||||||
|
; netcam_http 1.0
|
||||||
|
|
||||||
|
# URL to use for a netcam proxy server, if required, e.g. "http://myproxy".
|
||||||
|
# If a port number other than 80 is needed, use "http://myproxy:1234".
|
||||||
|
# Default: not defined
|
||||||
|
; netcam_proxy value
|
||||||
|
|
||||||
|
# Set less strict jpeg checks for network cameras with a poor/buggy firmware.
|
||||||
|
# Default: off
|
||||||
|
netcam_tolerant_check off
|
||||||
|
|
||||||
|
# Let motion regulate the brightness of a video device (default: off).
|
||||||
|
# The auto_brightness feature uses the brightness option as its target value.
|
||||||
|
# If brightness is zero auto_brightness will adjust to average brightness value 128.
|
||||||
|
# Only recommended for cameras without auto brightness
|
||||||
|
auto_brightness off
|
||||||
|
|
||||||
|
# Set the initial brightness of a video device.
|
||||||
|
# If auto_brightness is enabled, this value defines the average brightness level
|
||||||
|
# which Motion will try and adjust to.
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
brightness 0
|
||||||
|
|
||||||
|
# Set the contrast of a video device.
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
contrast 0
|
||||||
|
|
||||||
|
# Set the saturation of a video device.
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
saturation 0
|
||||||
|
|
||||||
|
# Set the hue of a video device (NTSC feature).
|
||||||
|
# Valid range 0-255, default 0 = disabled
|
||||||
|
hue 0
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Round Robin (multiple inputs on same video device name)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Number of frames to capture in each roundrobin step (default: 1)
|
||||||
|
roundrobin_frames 1
|
||||||
|
|
||||||
|
# Number of frames to skip before each roundrobin step (default: 1)
|
||||||
|
roundrobin_skip 1
|
||||||
|
|
||||||
|
# Try to filter out noise generated by roundrobin (default: off)
|
||||||
|
switchfilter off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Motion Detection Settings:
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Threshold for number of changed pixels in an image that
|
||||||
|
# triggers motion detection (default: 1500)
|
||||||
|
threshold 1500
|
||||||
|
|
||||||
|
# Automatically tune the threshold down if possible (default: off)
|
||||||
|
threshold_tune off
|
||||||
|
|
||||||
|
# Noise threshold for the motion detection (default: 32)
|
||||||
|
noise_level 32
|
||||||
|
|
||||||
|
# Automatically tune the noise threshold (default: on)
|
||||||
|
noise_tune on
|
||||||
|
|
||||||
|
# Despeckle motion image using (e)rode or (d)ilate or (l)abel (Default: not defined)
|
||||||
|
# Recommended value is EedDl. Any combination (and number of) of E, e, d, and D is valid.
|
||||||
|
# (l)abeling must only be used once and the 'l' must be the last letter.
|
||||||
|
# Comment out to disable
|
||||||
|
despeckle EedDl
|
||||||
|
|
||||||
|
# Detect motion in predefined areas (1 - 9). Areas are numbered like that: 1 2 3
|
||||||
|
# A script (on_area_detected) is started immediately when motion is 4 5 6
|
||||||
|
# detected in one of the given areas, but only once during an event. 7 8 9
|
||||||
|
# One or more areas can be specified with this option. (Default: not defined)
|
||||||
|
; area_detect value
|
||||||
|
|
||||||
|
# PGM file to use as a sensitivity mask.
|
||||||
|
# Full path name to. (Default: not defined)
|
||||||
|
; mask_file value
|
||||||
|
|
||||||
|
# Dynamically create a mask file during operation (default: 0)
|
||||||
|
# Adjust speed of mask changes from 0 (off) to 10 (fast)
|
||||||
|
smart_mask_speed 0
|
||||||
|
|
||||||
|
# Ignore sudden massive light intensity changes given as a percentage of the picture
|
||||||
|
# area that changed intensity. Valid range: 0 - 100 , default: 0 = disabled
|
||||||
|
lightswitch 0
|
||||||
|
|
||||||
|
# Picture frames must contain motion at least the specified number of frames
|
||||||
|
# in a row before they are detected as true motion. At the default of 1, all
|
||||||
|
# motion is detected. Valid range: 1 to thousands, recommended 1-5
|
||||||
|
minimum_motion_frames 1
|
||||||
|
|
||||||
|
# Specifies the number of pre-captured (buffered) pictures from before motion
|
||||||
|
# was detected that will be output at motion detection.
|
||||||
|
# Recommended range: 0 to 5 (default: 0)
|
||||||
|
# Do not use large values! Large values will cause Motion to skip video frames and
|
||||||
|
# cause unsmooth mpegs. To smooth mpegs use larger values of post_capture instead.
|
||||||
|
pre_capture 2
|
||||||
|
|
||||||
|
# Number of frames to capture after motion is no longer detected (default: 0)
|
||||||
|
post_capture 2
|
||||||
|
|
||||||
|
# Gap is the seconds of no motion detection that triggers the end of an event
|
||||||
|
# An event is defined as a series of motion images taken within a short timeframe.
|
||||||
|
# Recommended value is 60 seconds (Default). The value 0 is allowed and disables
|
||||||
|
# events causing all Motion to be written to one single mpeg file and no pre_capture.
|
||||||
|
gap 60
|
||||||
|
|
||||||
|
# Maximum length in seconds of an mpeg movie
|
||||||
|
# When value is exceeded a new mpeg file is created. (Default: 0 = infinite)
|
||||||
|
max_mpeg_time 0
|
||||||
|
|
||||||
|
# Always save images even if there was no motion (default: off)
|
||||||
|
output_all off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Image File Output
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Output 'normal' pictures when motion is detected (default: on)
|
||||||
|
# Valid values: on, off, first, best, center
|
||||||
|
# When set to 'first', only the first picture of an event is saved.
|
||||||
|
# Picture with most motion of an event is saved when set to 'best'.
|
||||||
|
# Picture with motion nearest center of picture is saved when set to 'center'.
|
||||||
|
# Can be used as preview shot for the corresponding movie.
|
||||||
|
output_normal on
|
||||||
|
|
||||||
|
# Output pictures with only the pixels moving object (ghost images) (default: off)
|
||||||
|
output_motion off
|
||||||
|
|
||||||
|
# The quality (in percent) to be used by the jpeg compression (default: 75)
|
||||||
|
quality 75
|
||||||
|
|
||||||
|
# Output ppm images instead of jpeg (default: off)
|
||||||
|
ppm off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# FFMPEG related options
|
||||||
|
# Film (mpeg) file output, and deinterlacing of the video input
|
||||||
|
# The options movie_filename and timelapse_filename are also used
|
||||||
|
# by the ffmpeg feature
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Use ffmpeg to encode mpeg movies in realtime (default: off)
|
||||||
|
ffmpeg_cap_new on
|
||||||
|
|
||||||
|
# Use ffmpeg to make movies with only the pixels moving
|
||||||
|
# object (ghost images) (default: off)
|
||||||
|
ffmpeg_cap_motion off
|
||||||
|
|
||||||
|
# Use ffmpeg to encode a timelapse movie
|
||||||
|
# Default value 0 = off - else save frame every Nth second
|
||||||
|
ffmpeg_timelapse 0
|
||||||
|
|
||||||
|
# The file rollover mode of the timelapse video
|
||||||
|
# Valid values: hourly, daily (default), weekly-sunday, weekly-monday, monthly, manual
|
||||||
|
ffmpeg_timelapse_mode daily
|
||||||
|
|
||||||
|
# Bitrate to be used by the ffmpeg encoder (default: 400000)
|
||||||
|
# This option is ignored if ffmpeg_variable_bitrate is not 0 (disabled)
|
||||||
|
ffmpeg_bps 500000
|
||||||
|
|
||||||
|
# Enables and defines variable bitrate for the ffmpeg encoder.
|
||||||
|
# ffmpeg_bps is ignored if variable bitrate is enabled.
|
||||||
|
# Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps,
|
||||||
|
# or the range 2 - 31 where 2 means best quality and 31 is worst.
|
||||||
|
ffmpeg_variable_bitrate 0
|
||||||
|
|
||||||
|
# Codec to used by ffmpeg for the video compression.
|
||||||
|
# Timelapse mpegs are always made in mpeg1 format independent from this option.
|
||||||
|
# Supported formats are: mpeg1 (ffmpeg-0.4.8 only), mpeg4 (default), and msmpeg4.
|
||||||
|
# mpeg1 - gives you files with extension .mpg
|
||||||
|
# mpeg4 or msmpeg4 - gives you files with extension .avi
|
||||||
|
# msmpeg4 is recommended for use with Windows Media Player because
|
||||||
|
# it requires no installation of codec on the Windows client.
|
||||||
|
# swf - gives you a flash film with extension .swf
|
||||||
|
# flv - gives you a flash video with extension .flv
|
||||||
|
# ffv1 - FF video codec 1 for Lossless Encoding ( experimental )
|
||||||
|
# mov - QuickTime ( testing )
|
||||||
|
#ffmpeg_video_codec swf
|
||||||
|
ffmpeg_video_codec msmpeg4
|
||||||
|
|
||||||
|
# Use ffmpeg to deinterlace video. Necessary if you use an analog camera
|
||||||
|
# and see horizontal combing on moving objects in video or pictures.
|
||||||
|
# (default: off)
|
||||||
|
ffmpeg_deinterlace off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Snapshots (Traditional Periodic Webcam File Output)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Make automated snapshot every N seconds (default: 0 = disabled)
|
||||||
|
snapshot_interval 0
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Text Display
|
||||||
|
# %Y = year, %m = month, %d = date,
|
||||||
|
# %H = hour, %M = minute, %S = second, %T = HH:MM:SS,
|
||||||
|
# %v = event, %q = frame number, %t = thread (camera) number,
|
||||||
|
# %D = changed pixels, %N = noise level, \n = new line,
|
||||||
|
# %i and %J = width and height of motion area,
|
||||||
|
# %K and %L = X and Y coordinates of motion center
|
||||||
|
# %C = value defined by text_event - do not use with text_event!
|
||||||
|
# You can put quotation marks around the text to allow
|
||||||
|
# leading spaces
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Locate and draw a box around the moving object.
|
||||||
|
# Valid values: on, off and preview (default: off)
|
||||||
|
# Set to 'preview' will only draw a box in preview_shot pictures.
|
||||||
|
locate on
|
||||||
|
|
||||||
|
# Set the look and style of the locate box if enabled.
|
||||||
|
# Valid values: box, redbox, cross, redcross (default: box)
|
||||||
|
# Set to 'box' will draw the traditional box.
|
||||||
|
# Set to 'redbox' will draw a red box.
|
||||||
|
# Set to 'cross' will draw a little cross to mark center.
|
||||||
|
# Set to 'redcross' will draw a little red cross to mark center.
|
||||||
|
locate_motion_style redbox
|
||||||
|
|
||||||
|
# Draws the timestamp using same options as C function strftime(3)
|
||||||
|
# Default: %Y-%m-%d\n%T = date in ISO format and time in 24 hour clock
|
||||||
|
# Text is placed in lower right corner
|
||||||
|
text_right %Y-%m-%d\n%T-%q
|
||||||
|
|
||||||
|
# Draw a user defined text on the images using same options as C function strftime(3)
|
||||||
|
# Default: Not defined = no text
|
||||||
|
# Text is placed in lower left corner
|
||||||
|
text_left osss-1
|
||||||
|
|
||||||
|
# Draw the number of changed pixed on the images (default: off)
|
||||||
|
# Will normally be set to off except when you setup and adjust the motion settings
|
||||||
|
# Text is placed in upper right corner
|
||||||
|
text_changes off
|
||||||
|
|
||||||
|
# This option defines the value of the special event conversion specifier %C
|
||||||
|
# You can use any conversion specifier in this option except %C. Date and time
|
||||||
|
# values are from the timestamp of the first image in the current event.
|
||||||
|
# Default: %Y%m%d%H%M%S
|
||||||
|
text_left osss-1
|
||||||
|
# a unique identifier for each event.
|
||||||
|
text_event %Y%m%d%H%M%S
|
||||||
|
|
||||||
|
# Draw characters at twice normal size on images. (default: off)
|
||||||
|
text_double off
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Target Directories and filenames For Images And Films
|
||||||
|
# For the options snapshot_, jpeg_, mpeg_ and timelapse_filename
|
||||||
|
# you can use conversion specifiers
|
||||||
|
# %Y = year, %m = month, %d = date,
|
||||||
|
# %H = hour, %M = minute, %S = second,
|
||||||
|
# %v = event, %q = frame number, %t = thread (camera) number,
|
||||||
|
# %D = changed pixels, %N = noise level,
|
||||||
|
# %i and %J = width and height of motion area,
|
||||||
|
# %K and %L = X and Y coordinates of motion center
|
||||||
|
# %C = value defined by text_event
|
||||||
|
# Quotation marks round string are allowed.
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Target base directory for pictures and films
|
||||||
|
# Recommended to use absolute path. (Default: current working directory)
|
||||||
|
target_dir /var/spool/motion
|
||||||
|
|
||||||
|
# File path for snapshots (jpeg or ppm) relative to target_dir
|
||||||
|
# Default: %v-%Y%m%d%H%M%S-snapshot
|
||||||
|
# Default value is equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-snapshot
|
||||||
|
# File extension .jpg or .ppm is automatically added so do not include this.
|
||||||
|
# Note: A symbolic link called lastsnap.jpg created in the target_dir will always
|
||||||
|
# point to the latest snapshot, unless snapshot_filename is exactly 'lastsnap'
|
||||||
|
#snapshot_filename %v-%Y%m%d%H%M%S-snapshot
|
||||||
|
snapshot_filename %v-%Y-%m-%dT%H.%M.%S-snapshot
|
||||||
|
|
||||||
|
# File path for motion triggered images (jpeg or ppm) relative to target_dir
|
||||||
|
# Default: %v-%Y%m%d%H%M%S-%q
|
||||||
|
# Default value is equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q
|
||||||
|
# File extension .jpg or .ppm is automatically added so do not include this
|
||||||
|
# Set to 'preview' together with best-preview feature enables special naming
|
||||||
|
# convention for preview shots. See motion guide for details
|
||||||
|
#jpeg_filename %v-%Y%m%d%H%M%S-%q
|
||||||
|
jpeg_filename %v-%Y-%m-%dT%H.%M.%S-%q
|
||||||
|
|
||||||
|
# File path for motion triggered ffmpeg films (mpeg) relative to target_dir
|
||||||
|
# Default: %v-%Y%m%d%H%M%S
|
||||||
|
# Default value is equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H%M%S
|
||||||
|
# File extension .mpg or .avi is automatically added so do not include this
|
||||||
|
# This option was previously called ffmpeg_filename
|
||||||
|
#movie_filename %v-%Y%m%d%H%M%S
|
||||||
|
movie_filename %v-%Y-%m-%dT%H.%M.%S
|
||||||
|
|
||||||
|
# File path for timelapse mpegs relative to target_dir
|
||||||
|
# Default: %Y%m%d-timelapse
|
||||||
|
# Default value is near equivalent to legacy oldlayout option
|
||||||
|
# For Motion 3.0 compatible mode choose: %Y/%m/%d-timelapse
|
||||||
|
# File extension .mpg is automatically added so do not include this
|
||||||
|
#timelapse_filename %Y%m%d-timelapse
|
||||||
|
timelapse_filename %Y-%m-%d-timelapse
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Live Webcam Server
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# The mini-http server listens to this port for requests (default: 0 = disabled)
|
||||||
|
webcam_port 8080
|
||||||
|
|
||||||
|
# Quality of the jpeg (in percent) images produced (default: 50)
|
||||||
|
webcam_quality 50
|
||||||
|
|
||||||
|
# Output frames at 1 fps when no motion is detected and increase to the
|
||||||
|
# rate given by webcam_maxrate when motion is detected (default: off)
|
||||||
|
webcam_motion off
|
||||||
|
|
||||||
|
# Maximum framerate for webcam streams (default: 1)
|
||||||
|
webcam_maxrate 30
|
||||||
|
|
||||||
|
# Restrict webcam connections to localhost only (default: on)
|
||||||
|
webcam_localhost off
|
||||||
|
|
||||||
|
# Limits the number of images per connection (default: 0 = unlimited)
|
||||||
|
# Number can be defined by multiplying actual webcam rate by desired number of seconds
|
||||||
|
# Actual webcam rate is the smallest of the numbers framerate and webcam_maxrate
|
||||||
|
webcam_limit 0
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# HTTP Based Control
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# TCP/IP port for the http server to listen on (default: 0 = disabled)
|
||||||
|
control_port 8081
|
||||||
|
|
||||||
|
# Restrict control connections to localhost only (default: on)
|
||||||
|
control_localhost off
|
||||||
|
|
||||||
|
# Output for http server, select off to choose raw text plain (default: on)
|
||||||
|
control_html_output on
|
||||||
|
|
||||||
|
# Authentication for the http based control. Syntax username:password
|
||||||
|
# Default: not defined (Disabled)
|
||||||
|
; control_authentication username:password
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Tracking (Pan/Tilt)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Type of tracker (0=none (default), 1=stepper, 2=iomojo, 3=pwc, 4=generic, 5=uvcvideo)
|
||||||
|
# The generic type enables the definition of motion center and motion size to
|
||||||
|
# be used with the conversion specifiers for options like on_motion_detected
|
||||||
|
track_type 0
|
||||||
|
|
||||||
|
# Enable auto tracking (default: off)
|
||||||
|
track_auto off
|
||||||
|
|
||||||
|
# Serial port of motor (default: none)
|
||||||
|
; track_port value
|
||||||
|
|
||||||
|
# Motor number for x-axis (default: 0)
|
||||||
|
track_motorx 0
|
||||||
|
|
||||||
|
# Motor number for y-axis (default: 0)
|
||||||
|
track_motory 0
|
||||||
|
|
||||||
|
# Maximum value on x-axis (default: 0)
|
||||||
|
track_maxx 0
|
||||||
|
|
||||||
|
# Maximum value on y-axis (default: 0)
|
||||||
|
track_maxy 0
|
||||||
|
|
||||||
|
# ID of an iomojo camera if used (default: 0)
|
||||||
|
track_iomojo_id 0
|
||||||
|
|
||||||
|
# Angle in degrees the camera moves per step on the X-axis
|
||||||
|
# with auto-track (default: 10)
|
||||||
|
# Currently only used with pwc type cameras
|
||||||
|
track_step_angle_x 10
|
||||||
|
|
||||||
|
# Angle in degrees the camera moves per step on the Y-axis
|
||||||
|
# with auto-track (default: 10)
|
||||||
|
# Currently only used with pwc type cameras
|
||||||
|
track_step_angle_y 10
|
||||||
|
|
||||||
|
# Delay to wait for after tracking movement as number
|
||||||
|
# of picture frames (default: 10)
|
||||||
|
track_move_wait 10
|
||||||
|
|
||||||
|
# Speed to set the motor to (stepper motor option) (default: 255)
|
||||||
|
track_speed 255
|
||||||
|
|
||||||
|
# Number of steps to make (stepper motor option) (default: 40)
|
||||||
|
track_stepsize 40
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# External Commands, Warnings and Logging:
|
||||||
|
# You can use conversion specifiers for the on_xxxx commands
|
||||||
|
# %Y = year, %m = month, %d = date,
|
||||||
|
# %H = hour, %M = minute, %S = second,
|
||||||
|
# %v = event, %q = frame number, %t = thread (camera) number,
|
||||||
|
# %D = changed pixels, %N = noise level,
|
||||||
|
# %i and %J = width and height of motion area,
|
||||||
|
# %K and %L = X and Y coordinates of motion center
|
||||||
|
# %C = value defined by text_event
|
||||||
|
# %f = filename with full path
|
||||||
|
# %n = number indicating filetype
|
||||||
|
# Both %f and %n are only defined for on_picture_save,
|
||||||
|
# on_movie_start and on_movie_end
|
||||||
|
# Quotation marks round string are allowed.
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Do not sound beeps when detecting motion (default: on)
|
||||||
|
# Note: Motion never beeps when running in daemon mode.
|
||||||
|
quiet on
|
||||||
|
|
||||||
|
# Command to be executed when an event starts. (default: none)
|
||||||
|
# An event starts at first motion detected after a period of no motion defined by gap
|
||||||
|
; on_event_start value
|
||||||
|
|
||||||
|
# Command to be executed when an event ends after a period of no motion
|
||||||
|
# (default: none). The period of no motion is defined by option gap.
|
||||||
|
; on_event_end value
|
||||||
|
|
||||||
|
# Command to be executed when a picture (.ppm|.jpg) is saved (default: none)
|
||||||
|
# To give the filename as an argument to a command append it with %f
|
||||||
|
; on_picture_save value
|
||||||
|
|
||||||
|
# Command to be executed when a motion frame is detected (default: none)
|
||||||
|
; on_motion_detected value
|
||||||
|
|
||||||
|
# Command to be executed when motion in a predefined area is detected
|
||||||
|
# Check option 'area_detect'. (default: none)
|
||||||
|
; on_area_detected value
|
||||||
|
|
||||||
|
# Command to be executed when a movie file (.mpg|.avi) is created. (default: none)
|
||||||
|
# To give the filename as an argument to a command append it with %f
|
||||||
|
; on_movie_start value
|
||||||
|
|
||||||
|
# Command to be executed when a movie file (.mpg|.avi) is closed. (default: none)
|
||||||
|
# To give the filename as an argument to a command append it with %f
|
||||||
|
; on_movie_end value
|
||||||
|
|
||||||
|
# Command to be executed when a camera can't be opened or if it is lost
|
||||||
|
# NOTE: There is situations when motion doesn't detect a lost camera!
|
||||||
|
# It depends on the driver, some drivers don't detect a lost camera at all
|
||||||
|
# Some hang the motion thread. Some even hang the PC! (default: none)
|
||||||
|
; on_camera_lost value
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Common Options For MySQL and PostgreSQL database features.
|
||||||
|
# Options require the MySQL/PostgreSQL options to be active also.
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Log to the database when creating motion triggered image file (default: on)
|
||||||
|
sql_log_image on
|
||||||
|
|
||||||
|
# Log to the database when creating a snapshot image file (default: on)
|
||||||
|
sql_log_snapshot on
|
||||||
|
|
||||||
|
# Log to the database when creating motion triggered mpeg file (default: off)
|
||||||
|
sql_log_mpeg off
|
||||||
|
|
||||||
|
# Log to the database when creating timelapse mpeg file (default: off)
|
||||||
|
sql_log_timelapse off
|
||||||
|
|
||||||
|
# SQL query string that is sent to the database
|
||||||
|
# Use same conversion specifiers has for text features
|
||||||
|
# Additional special conversion specifiers are
|
||||||
|
# %n = the number representing the file_type
|
||||||
|
# %f = filename with full path
|
||||||
|
# Default value:
|
||||||
|
# insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
|
||||||
|
sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Database Options For MySQL
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Mysql database to log to (default: not defined)
|
||||||
|
; mysql_db value
|
||||||
|
|
||||||
|
# The host on which the database is located (default: localhost)
|
||||||
|
; mysql_host value
|
||||||
|
|
||||||
|
# User account name for MySQL database (default: not defined)
|
||||||
|
; mysql_user value
|
||||||
|
|
||||||
|
# User password for MySQL database (default: not defined)
|
||||||
|
; mysql_password value
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Database Options For PostgreSQL
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# PostgreSQL database to log to (default: not defined)
|
||||||
|
; pgsql_db value
|
||||||
|
|
||||||
|
# The host on which the database is located (default: localhost)
|
||||||
|
; pgsql_host value
|
||||||
|
|
||||||
|
# User account name for PostgreSQL database (default: not defined)
|
||||||
|
; pgsql_user value
|
||||||
|
|
||||||
|
# User password for PostgreSQL database (default: not defined)
|
||||||
|
; pgsql_password value
|
||||||
|
|
||||||
|
# Port on which the PostgreSQL database is located (default: 5432)
|
||||||
|
; pgsql_port 5432
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Video Loopback Device (vloopback project)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Output images to a video4linux loopback device
|
||||||
|
# The value '-' means next available (default: not defined)
|
||||||
|
; video_pipe value
|
||||||
|
|
||||||
|
# Output motion images to a video4linux loopback device
|
||||||
|
# The value '-' means next available (default: not defined)
|
||||||
|
; motion_video_pipe value
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
# Thread config files - One for each camera.
|
||||||
|
# Except if only one camera - You only need this config file.
|
||||||
|
# If you have more than one camera you MUST define one thread
|
||||||
|
# config file for each camera in addition to this config file.
|
||||||
|
##############################################################
|
||||||
|
|
||||||
|
# Remember: If you have more than one camera you must have one
|
||||||
|
# thread file for each camera. E.g. 2 cameras requires 3 files:
|
||||||
|
# This motion.conf file AND thread1.conf and thread2.conf.
|
||||||
|
# Only put the options that are unique to each camera in the
|
||||||
|
# thread config files.
|
||||||
|
; thread /usr/local/etc/thread1.conf
|
||||||
|
; thread /usr/local/etc/thread2.conf
|
||||||
|
; thread /usr/local/etc/thread3.conf
|
||||||
|
; thread /usr/local/etc/thread4.conf
|
||||||
|
|
11
configs/motion/run_server
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
export NODE_PATH="$(npm root -g)"
|
||||||
|
#echo $NODE_PATH
|
||||||
|
while true; do
|
||||||
|
if [ -f "STOP" ]; then
|
||||||
|
rm -f STOP
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
node server.js
|
||||||
|
sleep 5
|
||||||
|
done
|
769
configs/motion/server.js
Normal file
|
@ -0,0 +1,769 @@
|
||||||
|
// OSSS (Open Source Surveillance and Security)
|
||||||
|
// (Not-so-)Simple Web App
|
||||||
|
//
|
||||||
|
// Donald Burr <dburr@vctlabs.com>, 12/12/2014
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var http = require('http')
|
||||||
|
var url = require('url')
|
||||||
|
var fs = require('fs')
|
||||||
|
var path = require('path')
|
||||||
|
var os = require("os");
|
||||||
|
var ffmpeg = require('fluent-ffmpeg')
|
||||||
|
var metalib = ffmpeg.Metadata
|
||||||
|
var nStore = require('nstore').extend(require('nstore/query')());
|
||||||
|
var ps = require('ps-node');
|
||||||
|
var sys = require('sys')
|
||||||
|
var exec = require('child_process').exec;
|
||||||
|
|
||||||
|
var dbIsReady = false;
|
||||||
|
|
||||||
|
// workaround for some node.js api changes
|
||||||
|
fs.exists = fs.exists || require('path').exists;
|
||||||
|
fs.existsSync = fs.existsSync || require('path').existsSync;
|
||||||
|
|
||||||
|
// debug mode
|
||||||
|
var DEBUG = false;
|
||||||
|
var NOISY_DEBUG = false;
|
||||||
|
|
||||||
|
// width and height of the video window
|
||||||
|
// these MUST match "width" and "height" settings in motion.conf!
|
||||||
|
var WIDTH = 320;
|
||||||
|
var HEIGHT = 240;
|
||||||
|
|
||||||
|
// number of pixels of padding to add to IFRAME (required by some browsers,
|
||||||
|
// notably Firefox, to prevent scroll bars from appearing within the IFRAME)
|
||||||
|
var PADDING = 20;
|
||||||
|
|
||||||
|
// where video files are stored, must match "target_dir" setting in motion.conf!
|
||||||
|
var VIDEOS_DIR = "/var/spool/motion/";
|
||||||
|
|
||||||
|
// sort order defaults to forward
|
||||||
|
var reverse_sort_order = 0;
|
||||||
|
|
||||||
|
// get arguments
|
||||||
|
var args = process.argv.slice(2);
|
||||||
|
if (args.length > 0) {
|
||||||
|
if (args[0] === "-d") {
|
||||||
|
console.log("Debug mode enabled.");
|
||||||
|
DEBUG = true;
|
||||||
|
}
|
||||||
|
if (args[0] === "-n") {
|
||||||
|
console.log("Noisy debug mode enabled.");
|
||||||
|
DEBUG = true;
|
||||||
|
NOISY_DEBUG = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// port to use
|
||||||
|
var PORT = 80;
|
||||||
|
if (DEBUG) {
|
||||||
|
console.log("Using port 8000 since we are in DEBUG mode.");
|
||||||
|
PORT = 8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see whether motion is running or not
|
||||||
|
function check_motion_state(state_callback)
|
||||||
|
{
|
||||||
|
// A simple pid lookup
|
||||||
|
ps.lookup({
|
||||||
|
command: 'motion',
|
||||||
|
psargs: 'auxw'
|
||||||
|
}, function(err, resultList ) {
|
||||||
|
if (err) {
|
||||||
|
if (NOISY_DEBUG) {
|
||||||
|
console.log("ERROR getting process info: " + err);
|
||||||
|
state_callback(false, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultList.length < 1) {
|
||||||
|
state_callback(false, 0);
|
||||||
|
} else {
|
||||||
|
state_callback(true, resultList[0].pid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pretty-print # of seconds as hrs:mintes:seconds
|
||||||
|
function secondsToString(seconds, shortFormat)
|
||||||
|
{
|
||||||
|
shortFormat = typeof shortFormat !== 'undefined' ? shortFormat : false;
|
||||||
|
var str = "";
|
||||||
|
//var numyears = Math.floor(seconds / 31536000);
|
||||||
|
var numdays = Math.floor((seconds % 31536000) / 86400);
|
||||||
|
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
|
||||||
|
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
|
||||||
|
var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
|
||||||
|
if (shortFormat) {
|
||||||
|
if (numdays > 0) {
|
||||||
|
str += numdays + "d";
|
||||||
|
}
|
||||||
|
if (numhours > 0) {
|
||||||
|
str += numhours + "h";
|
||||||
|
}
|
||||||
|
if (numminutes > 0) {
|
||||||
|
str += numminutes + "m";
|
||||||
|
}
|
||||||
|
if (numseconds > 0) {
|
||||||
|
str += numseconds + "s";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (numdays > 0) {
|
||||||
|
str += numdays + " days, ";
|
||||||
|
}
|
||||||
|
if (numhours > 0) {
|
||||||
|
str += numhours + " hours, ";
|
||||||
|
}
|
||||||
|
if (numminutes > 0) {
|
||||||
|
str += numminutes + " minutes, ";
|
||||||
|
}
|
||||||
|
if (numseconds > 0) {
|
||||||
|
str += numseconds + " seconds";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fun with timezone offsets
|
||||||
|
function pad(value) {
|
||||||
|
return value < 10 ? '0' + value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOffset(offset_in) {
|
||||||
|
var sign = (offset_in > 0) ? "-" : "+";
|
||||||
|
var offset = Math.abs(offset_in);
|
||||||
|
var hours = pad(Math.floor(offset / 60));
|
||||||
|
var minutes = pad(offset % 60);
|
||||||
|
return sign + hours + ":" + minutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAMPM(date) {
|
||||||
|
var hours = date.getHours();
|
||||||
|
var minutes = date.getMinutes();
|
||||||
|
var ampm = hours >= 12 ? 'pm' : 'am';
|
||||||
|
hours = hours % 12;
|
||||||
|
hours = hours ? hours : 12; // the hour '0' should be '12'
|
||||||
|
minutes = minutes < 10 ? '0'+minutes : minutes;
|
||||||
|
var strTime = hours + ':' + minutes + ' ' + ampm;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanFileSize(bytes, si) {
|
||||||
|
var thresh = si ? 1000 : 1024;
|
||||||
|
if(bytes < thresh) return bytes + ' B';
|
||||||
|
var units = si ? ['kB','MB','GB','TB','PB','EB','ZB','YB'] : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
|
||||||
|
var u = -1;
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while(bytes >= thresh);
|
||||||
|
return bytes.toFixed(1)+' '+units[u];
|
||||||
|
};
|
||||||
|
|
||||||
|
function endsWith(str, suffix) {
|
||||||
|
return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function r(max) {
|
||||||
|
return Math.floor(Math.random() * max);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCookies (request) {
|
||||||
|
var list = {},
|
||||||
|
rc = request.headers.cookie;
|
||||||
|
|
||||||
|
rc && rc.split(';').forEach(function( cookie ) {
|
||||||
|
var parts = cookie.split('=');
|
||||||
|
list[parts.shift().trim()] = decodeURI(parts.join('='));
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileData(key, getFileData_callback) {
|
||||||
|
var master_key = key;
|
||||||
|
if (NOISY_DEBUG) {
|
||||||
|
console.log("getFileData called with " + key);
|
||||||
|
}
|
||||||
|
if (dbIsReady) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("getFileData db is ready");
|
||||||
|
db.get(key, function (err, doc, key) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("db.get callback, err=" + err + ", doc=" + doc + ", key=" + key);
|
||||||
|
if (err) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: oops, " + err + ", reading file info directly");
|
||||||
|
// grab the data
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("KEY = " + master_key);
|
||||||
|
storeFileData(master_key, getFileData_callback);
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("Got data " + doc);
|
||||||
|
var fileInfo = new Array();
|
||||||
|
fileInfo[0] = new Date(doc.date);
|
||||||
|
fileInfo[1] = doc.file_name;
|
||||||
|
fileInfo[2] = doc.event_num;
|
||||||
|
fileInfo[3] = doc.size;
|
||||||
|
fileInfo[4] = doc.length;
|
||||||
|
var stats = fs.statSync(VIDEOS_DIR + master_key)
|
||||||
|
var fileSizeInBytes = stats["size"]
|
||||||
|
if (fileSizeInBytes != doc.size) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: file " + master_key + " file size is different than cache, assuming it has changed");
|
||||||
|
storeFileData(master_key, getFileData_callback, true);
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("calling getFileData_callback with " + fileInfo);
|
||||||
|
getFileData_callback(fileInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: database not ready, reading file info directly");
|
||||||
|
storeFileData(key, getFileData_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeFileData(key, storeFileData_callback, needs_deletion) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("at start of storeFileData, key=" + key);
|
||||||
|
needs_deletion = typeof needs_deletion !== 'undefined' ? needs_deletion : false;
|
||||||
|
var fileInfo = new Array();
|
||||||
|
var eventNumber = key.substr(0, 2);
|
||||||
|
var offset = new Date().getTimezoneOffset();
|
||||||
|
var dateString = key.substr(3, key.indexOf(".avi")-3).replace(/\./g, ':') + createOffset(offset);
|
||||||
|
var dateObject = new Date(dateString);
|
||||||
|
var stats = fs.statSync(VIDEOS_DIR + key)
|
||||||
|
var fileSizeInBytes = stats["size"]
|
||||||
|
fileInfo[0] = dateObject;
|
||||||
|
fileInfo[1] = key;
|
||||||
|
fileInfo[2] = eventNumber;
|
||||||
|
fileInfo[3] = fileSizeInBytes;
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("beginning async.series with fileInfo = " + fileInfo);
|
||||||
|
async.series([
|
||||||
|
function(seriesCallback) {
|
||||||
|
if (typeof metalib != 'undefined') {
|
||||||
|
var metaobject = new metalib(VIDEOS_DIR + key);
|
||||||
|
}
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("part 1, about to look up metadata");
|
||||||
|
if (typeof metaobject != 'undefined') {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("using metaobject.get()");
|
||||||
|
metaobject.get(function(metadata, err) {
|
||||||
|
if (!err) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("got metadata");
|
||||||
|
fileInfo[4] = metadata["durationsec"];
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("couldn't get metadata, assuming 0s");
|
||||||
|
fileInfo[4] = -1;
|
||||||
|
}
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("about to call seriesCallback 1");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("using ffprobe()");
|
||||||
|
ffmpeg.ffprobe(VIDEOS_DIR + key, function(err, metadata) {
|
||||||
|
if (!err) {
|
||||||
|
if (NOISY_DEBUG) {
|
||||||
|
console.log("got metadata!");
|
||||||
|
console.dir(metadata);
|
||||||
|
}
|
||||||
|
var duration = Math.floor(metadata.format.duration);
|
||||||
|
if (isNaN(duration)) {
|
||||||
|
duration = -1;
|
||||||
|
}
|
||||||
|
console.log("duration = " + duration);
|
||||||
|
fileInfo[4] = duration;
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("couldn't get metadata, assuming 0s");
|
||||||
|
fileInfo[4] = -1;
|
||||||
|
}
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("about to call seriesCallback 1");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(seriesCallback) {
|
||||||
|
// delete if desired
|
||||||
|
if (needs_deletion) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("need to delete " + key);
|
||||||
|
// Remove our new document
|
||||||
|
db.remove(key, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log("ERROR attempting to delete " + key + ": " + err);
|
||||||
|
}
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(seriesCallback) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("part 2, about to write to database");
|
||||||
|
// only try this if db is ready
|
||||||
|
if (dbIsReady) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("db is ready, writing");
|
||||||
|
db.save(key, {
|
||||||
|
date: fileInfo[0],
|
||||||
|
file_name: fileInfo[1],
|
||||||
|
event_num: fileInfo[2],
|
||||||
|
size: fileInfo[3],
|
||||||
|
length: fileInfo[4]
|
||||||
|
}, function(err) {
|
||||||
|
var responseMsg;
|
||||||
|
var success;
|
||||||
|
if (err) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR WRITING TO DB: " + err);
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("SUCCESS, wrote db");
|
||||||
|
}
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("database write finished, calling seriesCallback 2");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("ERROR: database not ready, calling seriesCallback 2");
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
}
|
||||||
|
}, function(seriesCallback) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("part 3, about to call final callback");
|
||||||
|
storeFileData_callback(fileInfo);
|
||||||
|
seriesCallback(null, fileInfo);
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function respondToHttpRequest(req, res) {
|
||||||
|
var hostname = os.hostname();
|
||||||
|
var host = req.headers["host"];
|
||||||
|
var hostport = host
|
||||||
|
var cookies = parseCookies(req);
|
||||||
|
if (cookies["reverse_sort_order"]) {
|
||||||
|
reverse_sort_order = parseInt(cookies["reverse_sort_order"]);
|
||||||
|
}
|
||||||
|
if(host.indexOf(":") > -1) {
|
||||||
|
host = host.substring(0, host.indexOf(':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ua = req.headers['user-agent'],
|
||||||
|
$ = {};
|
||||||
|
|
||||||
|
if (/mobile/i.test(ua))
|
||||||
|
$.Mobile = true;
|
||||||
|
|
||||||
|
if (/like Mac OS X/.test(ua)) {
|
||||||
|
$.iOS = /CPU( iPhone)? OS ([0-9\._]+) like Mac OS X/.exec(ua)[2].replace(/_/g, '.');
|
||||||
|
$.iPhone = /iPhone/.test(ua);
|
||||||
|
$.iPad = /iPad/.test(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/Android/.test(ua))
|
||||||
|
$.Android = /Android ([0-9\.]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
if (/webOS\//.test(ua))
|
||||||
|
$.webOS = /webOS\/([0-9\.]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
if (/(Intel|PPC) Mac OS X/.test(ua))
|
||||||
|
$.Mac = /(Intel|PPC) Mac OS X ?([0-9\._]*)[\)\;]/.exec(ua)[2].replace(/_/g, '.') || true;
|
||||||
|
|
||||||
|
if (/[Ll]inux/.test(ua))
|
||||||
|
$.Linux = true;
|
||||||
|
|
||||||
|
if (/Windows NT/.test(ua))
|
||||||
|
$.Windows = /Windows NT ([0-9\._]+)[\);]/.exec(ua)[1];
|
||||||
|
|
||||||
|
console.log("USER AGENT DETECTION RESULTS:");
|
||||||
|
console.log($);
|
||||||
|
|
||||||
|
//console.log("host = " + host);
|
||||||
|
// console.log(url);
|
||||||
|
var queryData = url.parse(req.url, true, true).query;
|
||||||
|
console.log("Responding to http request: " + req.url);
|
||||||
|
//console.log("query data: " + queryData);
|
||||||
|
|
||||||
|
if (queryData.mode) {
|
||||||
|
console.log("mode = " + queryData.mode);
|
||||||
|
if (queryData.mode === "stop") {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Stop"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Stop</H1>";
|
||||||
|
child = exec("/etc/init.d/motion stop", function (error, stdout, stderr) {
|
||||||
|
if (error !== null || stdout.indexOf("none killed") > -1) {
|
||||||
|
rhtml += "<p>Error stopping motion: " + stdout + "</p>";
|
||||||
|
} else {
|
||||||
|
rhtml += "<p>Motion has been successfully stopped.</p>";
|
||||||
|
}
|
||||||
|
rhtml += "<p><A HREF=\"http://" + hostport + "\">Back</A></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
});
|
||||||
|
} else if (queryData.mode === "start") {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Start"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Start</H1>";
|
||||||
|
child = exec("/etc/init.d/motion start", function (error, stdout, stderr) {
|
||||||
|
if (error !== null || stdout.indexOf("Error") > -1) {
|
||||||
|
rhtml += "<p>Error starting motion: " + stdout + "</p>";
|
||||||
|
} else {
|
||||||
|
rhtml += "<p>Motion has been successfully started.</p>";
|
||||||
|
}
|
||||||
|
rhtml += "<p><A HREF=\"http://" + hostport + "\">Back</A></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
});
|
||||||
|
} else if (queryData.mode === "live_view") {
|
||||||
|
// <iframe src="http://www.w3schools.com"></iframe>
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Live View"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<DIV ALIGN=\"CENTER\">"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Live View</H1>";
|
||||||
|
if ($.Android) {
|
||||||
|
//rhtml += "<A HREF=\"vlc://" + host + ":8080/\">Click here to view</A>.<br />(Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)</A>";
|
||||||
|
rhtml += "<IMG WIDTH=\"" + WIDTH + "\" HEIGHT=\"" + HEIGHT + "\" SRC=\"http://" + host + ":8080\"></IMG>";
|
||||||
|
} else if ($.iOS) {
|
||||||
|
//rhtml += "<A HREF=\"infuse://" + host + ":8080\">Click here to view</A>.<br />(Requires the free Infuse app. <A HREF=\"https://itunes.apple.com/us/app/infuse-3/id577130046\">Download it here</A>.)</A>";
|
||||||
|
rhtml += "<A HREF=\"vlc://http://" + host + ":8080/\">Click here to view</A>.<br />(Requires the free VLC app for iOS. <A HREF=\"http://get.videolan.org/vlc-iOS/2.3.0/vlc-iOS-2.3.0.ipa\">Download it here</A>.)</A>";
|
||||||
|
} else {
|
||||||
|
rhtml += "<IFRAME WIDTH=\"" + (WIDTH + PADDING) + "\" HEIGHT=\"" + (HEIGHT + PADDING) + "\" frameBorder=\"0\" seamless=\"seamless\" scrolling=\"no\" frameborder=\"0\" hspace=\"0\" vspace=\"0\" marginheight=\"0\" marginwidth=\"0\" SRC=\"http://" + host + ":8080\"></IFRAME>";
|
||||||
|
}
|
||||||
|
rhtml += "<P><A HREF=\"http://" + hostport + "/\">Back</A></p>"
|
||||||
|
+ "</DIV>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else if (queryData.mode === "file_list") {
|
||||||
|
var headers = {"Content-Type": "text/html"};
|
||||||
|
if (queryData.set_reverse_sort_order) {
|
||||||
|
reverse_sort_order = parseInt(queryData.set_reverse_sort_order);
|
||||||
|
headers["Set-Cookie"] = "reverse_sort_order=" + queryData.set_reverse_sort_order;
|
||||||
|
}
|
||||||
|
fs.readdir(VIDEOS_DIR, function(err, list) {
|
||||||
|
if(err) {
|
||||||
|
res.writeHead(200, headers);
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: unable to get file list: " + err + "</h1></BODY></HTML>");
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, headers);
|
||||||
|
res.write("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Saved Recordings</TITLE></HEAD><BODY><h1>" + hostname + " - Saved Recordings</h1>");
|
||||||
|
var regex = new RegExp(".*\.avi");
|
||||||
|
var fileList = new Array()
|
||||||
|
async.each(list, function(item, callback) {
|
||||||
|
if(regex.test(item)) {
|
||||||
|
getFileData(item, function(data) {
|
||||||
|
if (NOISY_DEBUG)
|
||||||
|
console.log("in final value callback, adding data = " + data);
|
||||||
|
fileList.push(data);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}, function(err) {
|
||||||
|
if (NOISY_DEBUG) {
|
||||||
|
console.log("DONE PROCESSING DIRECTORY LISTING");
|
||||||
|
console.log("fileList = " + fileList);
|
||||||
|
}
|
||||||
|
if (fileList.length > 0) {
|
||||||
|
// sort by date
|
||||||
|
fileList.sort(function(a,b){
|
||||||
|
a = a[0];
|
||||||
|
b = b[0];
|
||||||
|
if (reverse_sort_order) {
|
||||||
|
c = a > b ? -1 : a < b ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
c = a < b ? -1 : a > b ? 1 : 0;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
res.write("<p>Current Sort Order: " +
|
||||||
|
(reverse_sort_order ? "Reverse" : "Forward") +
|
||||||
|
" (<A HREF=\"http://" + hostport + "/?mode=file_list&set_reverse_sort_order=" + (reverse_sort_order ? "0" : "1") + "\">change</A>)</p>");
|
||||||
|
res.write("<UL>");
|
||||||
|
for (var i in fileList) {
|
||||||
|
var item = fileList[i];
|
||||||
|
res.write("<LI>" + item[0].toLocaleDateString() + " @ " + formatAMPM(item[0]) + " (Event #" + item[2] + ") (" + humanFileSize(item[3], true) + (item[4] == -1 ? ", file still active" : (item[4] < 1 ? ", <1s" : ", " + secondsToString(item[4], true))) + ")");
|
||||||
|
if (item[4] != -1) {
|
||||||
|
res.write(" (<A HREF=\"http://" + hostport + "/?mode=view&filename=" + item[1] + ($.Linux && !$.Android ? "&use_vlc_plugin=true" : "") + "\">view</A>) (<A HREF=\"http://" + hostport + "/?mode=download&filename=" + item[1] + "\">download</A>) (<A HREF=\"http://" + hostport + "/?mode=delete&filename=" + item[1] + "\">delete</A>)");
|
||||||
|
}
|
||||||
|
res.write("</LI>");
|
||||||
|
}
|
||||||
|
res.end("</ul><h3><A HREF=\"http://" + hostport + "/?mode=delete&filename=ALL\">Delete ALL Videos</A></h3><p><A HREF=\"http://" + hostport + "/\">Back</A></p></BODY><FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER></HTML>");
|
||||||
|
} else {
|
||||||
|
res.write("<h3>No Files Found</h3>");
|
||||||
|
res.end("<p><A HREF=\"http://" + hostport + "/\">Back</A></p></BODY><FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER></HTML>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (queryData.mode === "delete") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
if (queryData.confirmed) {
|
||||||
|
var confirmed = queryData.confirmed;
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Delete File(s)"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Delete File(s)</H1>"
|
||||||
|
+ "<p><h3>";
|
||||||
|
if (confirmed === "yes") {
|
||||||
|
var numDeleted = 0;
|
||||||
|
var numErrors = 0;
|
||||||
|
var path = VIDEOS_DIR;
|
||||||
|
if (filename === "ALL") {
|
||||||
|
var files = fs.readdirSync(path);
|
||||||
|
var success = true
|
||||||
|
// nuke the database
|
||||||
|
// db.clear(function(err) {
|
||||||
|
// if (NOISY_DEBUG)
|
||||||
|
// console.log("DATABASE NUKED");
|
||||||
|
// });
|
||||||
|
files.forEach(function(file) {
|
||||||
|
if (file.match("^.*avi$")) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path + file);
|
||||||
|
numDeleted++;
|
||||||
|
rhtml += "Deleted \"" + file + "\"<br />";
|
||||||
|
} catch (ex) {
|
||||||
|
numErrors++;
|
||||||
|
rhtml += "Could not delete \"" + file + "\": " + ex + "<br />";
|
||||||
|
success = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rhtml += "<br />";
|
||||||
|
} else {
|
||||||
|
path += filename;
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path);
|
||||||
|
numDeleted++;
|
||||||
|
success = true;
|
||||||
|
} catch (ex) {
|
||||||
|
numErrors++;
|
||||||
|
rhtml += "Could not delete \"" + filename + "\": " + ex + "<br /><br />";
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
rhtml += numDeleted + " file" + (numDeleted > 1 ? "s" : "") + " deleted successfully.";
|
||||||
|
} else {
|
||||||
|
rhtml += numDeleted > 0 ? numDeleted + " file" + (numDeleted > 1 ? "s" : "") + " deleted successfully." : "";
|
||||||
|
rhtml += numErrors + " delete failure" + (numErrors > 1 ? "s" : "") + ".";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rhtml += "Delete cancelled.";
|
||||||
|
}
|
||||||
|
rhtml += "<h3><A HREF=\"" + hostport + "/?mode=file_list\">OK</A></h3></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else {
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Delete File(s)"
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - Delete File(s)</H1>"
|
||||||
|
+ "<p><h3>You are about to delete "
|
||||||
|
+ (filename === "ALL" ? "ALL videos!" : "\"" + filename + "\"")
|
||||||
|
+ "<br /><br />"
|
||||||
|
+ "Are you SURE you want to do this?<br /><br />"
|
||||||
|
+ "<A HREF=\"" + hostport + "/?mode=delete&filename=" + filename + "&confirmed=yes\">YES</A> <A HREF=\"" + hostport + "/?mode=delete&filename=" + filename + "&confirmed=no\">NO</A></h3></p>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
} else if (queryData.mode === "view") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
var filePath = VIDEOS_DIR + filename;
|
||||||
|
fs.exists(filePath, function(exists) {
|
||||||
|
if (exists) {
|
||||||
|
console.log('viewing contents of local file: ' + filePath);
|
||||||
|
var stat = fs.statSync(filePath);
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'text/html'
|
||||||
|
});
|
||||||
|
var rhtml = "<HTML><HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS @ " + hostname + " - Video Playback - " + filename
|
||||||
|
+ "</TITLE></HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<DIV ALIGN=\"CENTER\">"
|
||||||
|
+ "<H1>OSSS @ " + hostname + " - " + filename + "</H1>";
|
||||||
|
if (queryData.use_vlc_plugin) {
|
||||||
|
rhtml += "<embed type=\"application/x-vlc-plugin\""
|
||||||
|
+ "pluginspage=\"http://www.videolan.org\""
|
||||||
|
+ "name=\"video1\""
|
||||||
|
+ "id=\"video1\""
|
||||||
|
+ "controls=\"yes\" toolbar=\"yes\" autoplay=\"no\" loop=\"yes\" width=\"" + WIDTH + "\" height=\"" + HEIGHT + "\""
|
||||||
|
+ "target=\"http://" + hostport + "/?mode=download&filename=" + filename + "\" />"
|
||||||
|
+ "<br />"
|
||||||
|
+ "(Note: if you don't see a video window above, then you must <A HREF=\"http://www.videolan.org/vlc/download-ubuntu.html\">install the VLC browser plugin</A>.)"
|
||||||
|
+ "<br />";
|
||||||
|
/*
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.play()'>[Play]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.pause()'>[Pause]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.stop()'>[Stop]</a> "
|
||||||
|
+ "<a href=\"javascript:;\" onclick='document.video1.fullscreen()'>[fullscreen]</a>";
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
if ($.Android) {
|
||||||
|
//rhtml += "<A HREF=\"vlc://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)";
|
||||||
|
rhtml += "<A HREF=\"http://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to download this file</A>.<br />Once the file is downloaded, swipe down Notification Center, and tap on the file to open it in VLC. (Requires the free VLC app for Android. <A HREF=\"https://play.google.com/store/apps/details?id=org.videolan.vlc.betav7neon&hl=en\">Download it here</A>.)";
|
||||||
|
rhtml += "<br />Note #2: you may get an error message saying VLC encounterd an error with this media. If so, tap the \"Refresh\" (two arrows going around in circles) button in VLC, and the downloaded file should appear. Seems to be a bug with the latest VLC, they broke it. :-P";
|
||||||
|
} else if ($.iOS) {
|
||||||
|
rhtml += "<A HREF=\"vlc://http://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free VLC app for iOS. <A HREF=\"http://get.videolan.org/vlc-iOS/2.3.0/vlc-iOS-2.3.0.ipa\">Download it here</A>.)";
|
||||||
|
//rhtml += "<A HREF=\"infuse://" + hostport + "/?mode=download&filename=" + filename + "\">Tap here to play this video</A>.<br />(Requires the free Infuse app. <A HREF=\"https://itunes.apple.com/us/app/infuse-3/id577130046?mt=8\">Download it here</A>.)";
|
||||||
|
} else {
|
||||||
|
rhtml += "<video width=\"" + WIDTH + "\" height=\"" + HEIGHT + "\" controls>"
|
||||||
|
+ "<source src=\"http://" + hostport + "/?mode=download&filename=" + filename + "\" type=\"video/x-msvideo\">"
|
||||||
|
+ "Your browser does not support the video tag."
|
||||||
|
+ "</video>"
|
||||||
|
+ "<br />";
|
||||||
|
// + "<A HREF=\"http://" + hostport + "/?mode=view&filename=" + filename + "&use_vlc_plugin=true\">(Don't see any video? Try this...)</A>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rhtml += "<P><A HREF=\"http://" + hostport + "/?mode=file_list\">Back</A></p>"
|
||||||
|
+ "</DIV>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
} else {
|
||||||
|
console.log('returning 404, could not find: ' + filePath);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found. Go away kid, you\'re bothering me.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
} else if (queryData.mode === "download") {
|
||||||
|
if (queryData.filename) {
|
||||||
|
var filename = queryData.filename;
|
||||||
|
var filePath = VIDEOS_DIR + filename;
|
||||||
|
fs.exists(filePath, function(exists) {
|
||||||
|
if (exists) {
|
||||||
|
console.log('sending contents of local file: ' + filePath);
|
||||||
|
var stat = fs.statSync(filePath);
|
||||||
|
var contenttype = "video/x-msvideo";
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': contenttype,
|
||||||
|
'Content-Length': stat.size,
|
||||||
|
'Content-Disposition': "attachment; filename=" + filename
|
||||||
|
});
|
||||||
|
var readStream = fs.createReadStream(filePath);
|
||||||
|
readStream.pipe(res);
|
||||||
|
} else {
|
||||||
|
console.log('returning 404, could not find: ' + filePath);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found. Go away kid, you\'re bothering me.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
res.end("<HTML><HEAD><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /><TITLE>OSSS @ " + hostname + " - Error</TITLE></HEAD><BODY><h1>Error: filename not specified.</h1></BODY></HTML>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// send the index page
|
||||||
|
console.log("Responding with index page");
|
||||||
|
check_motion_state(function(is_running, pid) {
|
||||||
|
res.writeHead(200, "Content-Type: text/html");
|
||||||
|
var rhtml = "<HTML>"
|
||||||
|
+ "<HEAD>"
|
||||||
|
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />"
|
||||||
|
+ "<TITLE>OSSS (Open Source Surveillance and Security) - " + hostname + "</TITLE>"
|
||||||
|
+ "</HEAD>"
|
||||||
|
+ "<BODY>"
|
||||||
|
+ "<p><h1>OSSS (Open Source Surveillance and Security) - " + hostname + "</h1></p>"
|
||||||
|
+ "<p>";
|
||||||
|
if (is_running) {
|
||||||
|
rhtml += "<p>State: RUNNING (pid = " + pid + ") (<A HREF=\"http://" + hostport + "/?mode=stop\">stop</A>)</p>"
|
||||||
|
+ "<ul>"
|
||||||
|
+ "<li><A HREF=\"http://" + hostport + "/?mode=live_view\">Live View</A></li>";
|
||||||
|
} else {
|
||||||
|
if (pid == -1) {
|
||||||
|
rhtml += "<p>State: UNKNOWN</p>"
|
||||||
|
+ "<ul>"
|
||||||
|
+ "<li><A HREF=\"http://" + hostport + "/?mode=live_view\">Live View</A> (note: may be unavailable if process is not running)</li>";
|
||||||
|
} else {
|
||||||
|
rhtml += "<p>State: STOPPED (<A HREF=\"http://" + hostport + "/?mode=start\">start</A>)</p>"
|
||||||
|
+ "<ul>"
|
||||||
|
+ "<li><i>Live View is unavailable while motion is stopped.</i></A></li>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rhtml += "<li><A HREF=\"http://" + hostport + "/?mode=file_list\">Saved Recordings</A></li>"
|
||||||
|
+ "</UL>"
|
||||||
|
+ "</BODY>"
|
||||||
|
+ "<FOOTER><HR><p>OSSS @ " + hostname + "</p></FOOTER>"
|
||||||
|
+ "</HTML>";
|
||||||
|
res.end(rhtml);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize database
|
||||||
|
var cache_filename = '/tmp/dir_cache';
|
||||||
|
if (DEBUG)
|
||||||
|
cache_filename = '/tmp/dir_cache.debug';
|
||||||
|
var db = nStore.new(cache_filename, function () {
|
||||||
|
console.log('Database initialization complete.');
|
||||||
|
dbIsReady = true;
|
||||||
|
});
|
||||||
|
db.filterFn = function (doc, meta) {
|
||||||
|
//return doc.lastAccess > Date.now() - 360000;
|
||||||
|
return doc.lastAccess > Date.now() - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up the HTTP listener
|
||||||
|
var server = http.createServer(function (req, res) {
|
||||||
|
respondToHttpRequest(req, res);
|
||||||
|
}).listen(PORT);
|
||||||
|
server.on('connection', function(sock) {
|
||||||
|
console.log('Incoming HTTP connection from ' + sock.remoteAddress);
|
||||||
|
});
|
||||||
|
console.log('HTTP server running on port ' + PORT + '.');
|
15
configs/wifi/interfaces
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
auto lo
|
||||||
|
auto eth0
|
||||||
|
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
iface eth0 inet dhcp
|
||||||
|
#iface eth0 inet static
|
||||||
|
# address 192.168.24.22
|
||||||
|
# netmask 255.255.255.0
|
||||||
|
# gateway 192.168.24.1
|
||||||
|
|
||||||
|
allow-hotplug wlan0
|
||||||
|
iface wlan0 inet manual
|
||||||
|
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
iface default inet dhcp
|
8
configs/wifi/wpa_supplicant.conf
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
|
||||||
|
update_config=1
|
||||||
|
|
||||||
|
network={
|
||||||
|
ssid="#SSID#"
|
||||||
|
psk="#PASSWORD#"
|
||||||
|
key_mgmt=WPA-PSK
|
||||||
|
}
|
117
dotfiles/dot.bashrc
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# ~/.bashrc: executed by bash(1) for non-login shells.
|
||||||
|
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
||||||
|
# for examples
|
||||||
|
|
||||||
|
# If not running interactively, don't do anything
|
||||||
|
[ -z "$PS1" ] && return
|
||||||
|
|
||||||
|
# don't put duplicate lines or lines starting with space in the history.
|
||||||
|
# See bash(1) for more options
|
||||||
|
HISTCONTROL=ignoreboth
|
||||||
|
|
||||||
|
# append to the history file, don't overwrite it
|
||||||
|
shopt -s histappend
|
||||||
|
|
||||||
|
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
|
||||||
|
HISTSIZE=1000
|
||||||
|
HISTFILESIZE=2000
|
||||||
|
|
||||||
|
# check the window size after each command and, if necessary,
|
||||||
|
# update the values of LINES and COLUMNS.
|
||||||
|
shopt -s checkwinsize
|
||||||
|
|
||||||
|
# If set, the pattern "**" used in a pathname expansion context will
|
||||||
|
# match all files and zero or more directories and subdirectories.
|
||||||
|
#shopt -s globstar
|
||||||
|
|
||||||
|
# make less more friendly for non-text input files, see lesspipe(1)
|
||||||
|
#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
||||||
|
|
||||||
|
# set variable identifying the chroot you work in (used in the prompt below)
|
||||||
|
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
|
||||||
|
debian_chroot=$(cat /etc/debian_chroot)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set a fancy prompt (non-color, unless we know we "want" color)
|
||||||
|
case "$TERM" in
|
||||||
|
xterm-color) color_prompt=yes;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# uncomment for a colored prompt, if the terminal has the capability; turned
|
||||||
|
# off by default to not distract the user: the focus in a terminal window
|
||||||
|
# should be on the output of commands, not on the prompt
|
||||||
|
force_color_prompt=yes
|
||||||
|
|
||||||
|
if [ -n "$force_color_prompt" ]; then
|
||||||
|
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
||||||
|
# We have color support; assume it's compliant with Ecma-48
|
||||||
|
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
||||||
|
# a case would tend to support setf rather than setaf.)
|
||||||
|
color_prompt=yes
|
||||||
|
else
|
||||||
|
color_prompt=
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$color_prompt" = yes ]; then
|
||||||
|
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\w \$\[\033[00m\] '
|
||||||
|
else
|
||||||
|
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
|
||||||
|
fi
|
||||||
|
unset color_prompt force_color_prompt
|
||||||
|
|
||||||
|
# If this is an xterm set the title to user@host:dir
|
||||||
|
case "$TERM" in
|
||||||
|
xterm*|rxvt*)
|
||||||
|
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# enable color support of ls and also add handy aliases
|
||||||
|
if [ -x /usr/bin/dircolors ]; then
|
||||||
|
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
||||||
|
alias ls='ls -lFh --color=auto'
|
||||||
|
alias lsc='ls -CFh --color=auto'
|
||||||
|
#alias dir='dir --color=auto'
|
||||||
|
#alias vdir='vdir --color=auto'
|
||||||
|
alias cp="cp -i"
|
||||||
|
alias mv="mv -i"
|
||||||
|
alias rm="rm -i"
|
||||||
|
alias h="history 20"
|
||||||
|
alias j="jobs"
|
||||||
|
alias du="du -h"
|
||||||
|
alias df="df -h"
|
||||||
|
|
||||||
|
alias grep='grep --color=auto'
|
||||||
|
alias fgrep='fgrep --color=auto'
|
||||||
|
alias egrep='egrep --color=auto'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# some more ls aliases
|
||||||
|
#alias ll='ls -l'
|
||||||
|
#alias la='ls -A'
|
||||||
|
#alias l='ls -CF'
|
||||||
|
|
||||||
|
# Alias definitions.
|
||||||
|
# You may want to put all your additions into a separate file like
|
||||||
|
# ~/.bash_aliases, instead of adding them here directly.
|
||||||
|
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
|
||||||
|
|
||||||
|
if [ -f ~/.bash_aliases ]; then
|
||||||
|
. ~/.bash_aliases
|
||||||
|
fi
|
||||||
|
|
||||||
|
# enable programmable completion features (you don't need to enable
|
||||||
|
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
||||||
|
# sources /etc/bash.bashrc).
|
||||||
|
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
|
||||||
|
. /etc/bash_completion
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up ibeacon
|
||||||
|
export IBEACON_UUID=37db7c0b-c706-4374-8f96-d37ba5e1b0a6
|
||||||
|
export IBEACON_MAJOR=42
|
||||||
|
export IBEACON_MINOR=1
|
||||||
|
export NODE_PATH="/usr/lib/node_modules"
|
38
dotfiles/dot.gitconfig
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[user]
|
||||||
|
name = Donald Burr
|
||||||
|
email = dburr@borg-cube.com
|
||||||
|
signingkey = dburr@borg-cube.com
|
||||||
|
[color]
|
||||||
|
ui = true
|
||||||
|
diff = auto
|
||||||
|
status = auto
|
||||||
|
branch = auto
|
||||||
|
[core]
|
||||||
|
#excludesfile = ~/.gitignore
|
||||||
|
editor = vim
|
||||||
|
autocrlf = input
|
||||||
|
[push]
|
||||||
|
default = current
|
||||||
|
[credential]
|
||||||
|
helper = osxkeychain
|
||||||
|
#helper = store
|
||||||
|
[alias]
|
||||||
|
tree = log --graph --simplify-by-decoration --pretty=format:'%d' --all
|
||||||
|
tree2 = log --graph --full-history --all --color --pretty=format:"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s" --simplify-by-decoration
|
||||||
|
l = log --graph --oneline --decorate
|
||||||
|
ll = log --graph --oneline --decorate --branches --tags
|
||||||
|
lll = log --graph --oneline --decorate --all
|
||||||
|
lp = log --graph --all --format='%C(cyan dim) %p %Cred %h %C(white dim) %s %Cgreen(%cr)%C(cyan dim) <%an>%C(bold yellow)%d%Creset'
|
||||||
|
lsi = clean -ndX
|
||||||
|
lg1 = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
|
||||||
|
lg2 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
|
||||||
|
lg = !"git lg1"
|
||||||
|
gitignore = "!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi"
|
||||||
|
[difftool "sourcetree"]
|
||||||
|
cmd = opendiff \"$LOCAL\" \"$REMOTE\"
|
||||||
|
path =
|
||||||
|
[mergetool "sourcetree"]
|
||||||
|
cmd = /Applications/SourceTree.app/Contents/Resources/opendiff-w.sh \"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"
|
||||||
|
trustExitCode = true
|
||||||
|
#[merge]
|
||||||
|
# ff = false
|
22
dotfiles/dot.profile
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# ~/.profile: executed by the command interpreter for login shells.
|
||||||
|
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
|
||||||
|
# exists.
|
||||||
|
# see /usr/share/doc/bash/examples/startup-files for examples.
|
||||||
|
# the files are located in the bash-doc package.
|
||||||
|
|
||||||
|
# the default umask is set in /etc/profile; for setting the umask
|
||||||
|
# for ssh logins, install and configure the libpam-umask package.
|
||||||
|
#umask 022
|
||||||
|
|
||||||
|
# if running bash
|
||||||
|
if [ -n "$BASH_VERSION" ]; then
|
||||||
|
# include .bashrc if it exists
|
||||||
|
if [ -f "$HOME/.bashrc" ]; then
|
||||||
|
. "$HOME/.bashrc"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set PATH so it includes user's private bin if it exists
|
||||||
|
if [ -d "$HOME/bin" ] ; then
|
||||||
|
PATH="$HOME/bin:$PATH"
|
||||||
|
fi
|
23
dotfiles/dot.ssh/authorized_keys
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# current Mac desktop key
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA1REri3QFMLofxDKDjtAUVVJSUGp95aIjccuI9OYP/3XVv9ZIpcr1MXtz03kwkHpMd2jCsATzvJp7EITTGzO2rMGZTVSagU9Y7gf30U8uaRaMNmxfeFNUerT1D0KRmu0LYDjpRuMDdQJ1R1VW6Gk0XzP3uNthCejbCn22wUv43+3jruK6gVdFKVfi0lo2n+NeASflhxM+266WkWF7wBhZae4A5D6cWvladlBBJhP6ziYhXoQ5v6Xoh7YDQJiKJUgNujhHYZha7RGRa+sLvlUXS8uVtzPqWNJU+1uImXSMm0u/4jhd2i0nzJSQbz+7DRqnlKpOEYfxCYM8QjEunmEKZQ== dburr@megadoomer
|
||||||
|
|
||||||
|
# current Mac laptop key
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA2Dm5yabp4S5EomJYvzO8X9YIUUNXe/noKFVBIyh2Vegt9xtRLqOQzfqwy/+1I+vVoXMyz5BlAoPCP7Er26TSZvV1twHFRFWMOZB+jL25plYpn7erXDtOVXwGkmLLd7P1GmyZA7fRdRXeozWRHhqTGXsAJw8u9gnGx6aoy0f2UtCpBOAeznsKKVzlNQsxdBeWSnY4Qf+PKUQGE5kGAlEBAGCKqB9cBT5rceojsC+2eBWBV697pPKPhAhHHkA1uKF8CMsdvi/POP6tNAx0rPNoCRSjXobFtjVRZ/69ARX/TTVCChvRYMfBdySv4gyKzW4+ba1VcbIuP/Vc7V5wae43fw== dburr@locutus-wifi
|
||||||
|
|
||||||
|
# development VM key
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAtfJf91J5HF2UP3pY7SWtEaNBHrr8Juntq5rOZ4LTvpn8ksmmpUraXEdAI0Dda03eek+6sVF1yWuKTsu6EAqig9Pu8y3Z6YHLe1ElPmiL5n/bdsV/loDokDq87HGuR7KMo1fOYdctBhR7ZR/sam1z5RHcVQaNfN5jYEzT9YQZl6Ef+LT2TuVWpdMcFS0Piu5JBR+k57cqOW/dQtfC+/z0w4xm8COB9iDXBHJKgVwTTZOYARyzGmBidC/DK/zoKpu/PH+buHKsWyfO1x1w7a6DFUQQlnjCF6VeWJ9Xf2ZBS1iCkE3poHZDB6r/UAUVhDDDfEt7npHyAU6T75VdBY35ZQ== dburr@xo-devel
|
||||||
|
|
||||||
|
# 1and1 server key (for automated backups)
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3vLUvXQZmbnRsj5stIJ+TidC7XaSAHuCPgLyZgcZOMts99OdejMxQzrUVvAmjk/jyQSFtgWvavL35yLlCYvBj0F0Y5Zmx96Muen5po4daDjh1+vzMEVJ3PzKuQgTzAa8/XYzavyDIXzErq0Qa4VR5fa5H/p6ZiBQSUolnOphBsEcMKcYOhXvLwuSamfdRhdvjlJYsDklZSYG7aKX/dYFXx6CtsNYkbpgU1m838b+9IWt90mmlCLT/Tlr/2BbG3w3F/2Sde2iNGGNrEWh1DOKGMDW4b4GYhpS5BW5N6K9CcFWUjaJnPShl8/U3XrsO/HIwffDQJ/GesigxSz3znFCOQ== root@server.borg-cube.com
|
||||||
|
|
||||||
|
# Linux key on Nadesico
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAx4WVbrJpNVoYXy7T8C9CBFITx154DFQxm/I1eJnRYMTI2EZMmZWVJTGzActrBcYplG+6duStAh/VmYGEfhvx8kTbBZu0iI8AYzeZhYyfT2y5/vPQzp5Bs5AD8M6Kxyc6Bli0Mzr/ofpACAh7OJ1EIvE/oRPPxBYqAS2/Q3ihvb7JE1aKE1EDGqrwxS45dV6uc0tF1BFUAWDCHAixEzM92+HNeEILr7xAtfnUMKOUptPy6SlUZNZeOzJkEOQ9bXbzMZ0cbDb8l6E7bHgvJZ7ywYcV7dIcGJhm02ilbTcomhzhDsfagPYpJC/dPkn5npIvxPRBRIbPmijCWiLZIUhV6Q== dburr@Nadesico
|
||||||
|
|
||||||
|
# BorgPhone iSSH key
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAwH/mXBc5sKfArdsTJm9TlfbnLvGStl7UUZ0WSMW5puu58+ayxY+l7x3/ESTQfqx69Ig36XjF96M9saPaM3DjFm3S/f0ULPAIefqyaQWQU9XFR1vZ3LeDd7hGL4QhYLIUh2oEu8rUobYuifVj96GFuqNZqP+G+Z8tbATwa95SE3s= iphone-rsa-key-20130919
|
||||||
|
|
||||||
|
# iPADD iSSH key
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIBnaiJS9/RotSN9l2niAGCdds+h1CD8Sh24wddE1VQkNGxquYk9lkqtiq9lR6ZD6HvVxtKu19qA0VaT+Wb/7IK3uIJfLpzp66jwBU9+obUjOkEQvSevIPu1TO8MXLmeboiIliypI1HyCQDiIi6C0irMPIAmbgryJaj1s69vk1sikQ== iphone-rsa-key-20130919
|
||||||
|
|
||||||
|
# pbx
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAk/ZoHi5Ln2SFPZGLQx/Z7QMYK+/OBMu0ccRXU9oPiA5okkAcSfJoGSXEsnM6RxCdxKPyM3FIOE3KV2qqlsvbr9E9jNyfK0b4xYEVIy/eFFghZ4DLFBISGx3D4NM8cq7eNadnAH1RE6XXg10ZdwcQC9kGU98pBwAVz6efvA24i0bMVUUUKfs7Y2Ik6zanJJZnDD55Ta+HoafhzRrwbbUHhE0exHWqtE8MwskLwhVVWMC718CX2Nin6NK3WaqdP5MQe/A8qQ06/IM1pZPII6GNJ1N6I3phvfd59BOB6zOP7JiGfQLNFRDdh7j/3wINGkl/dVsQaAtljpumxL2IGsL0Nw== dburr@pbx
|
38
dotfiles/dot.vimrc
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
syntax on
|
||||||
|
filetype plugin indent on
|
||||||
|
|
||||||
|
set smartindent
|
||||||
|
set tabstop=2
|
||||||
|
set shiftwidth=2
|
||||||
|
set expandtab
|
||||||
|
|
||||||
|
" disable auto comment
|
||||||
|
autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o
|
||||||
|
|
||||||
|
" Tell vim to remember certain things when we exit
|
||||||
|
" '10 : marks will be remembered for up to 10 previously edited files
|
||||||
|
" "100 : will save up to 100 lines for each register
|
||||||
|
" :20 : up to 20 lines of command-line history will be remembered
|
||||||
|
" % : saves and restores the buffer list
|
||||||
|
" n... : where to save the viminfo files
|
||||||
|
set viminfo='10,\"100,:20,%,n~/.viminfo
|
||||||
|
|
||||||
|
function! ResCur()
|
||||||
|
let do_it = "YES"
|
||||||
|
if @% =~ "COMMIT_EDITMSG"
|
||||||
|
let do_it = "NO"
|
||||||
|
elseif @% =~ "MERGE_MSG"
|
||||||
|
let do_it = "NO"
|
||||||
|
endif
|
||||||
|
if do_it == "YES"
|
||||||
|
if line("'\"") <= line("$")
|
||||||
|
normal! g`"
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup resCur
|
||||||
|
autocmd!
|
||||||
|
autocmd BufWinEnter * call ResCur()
|
||||||
|
augroup END
|
BIN
drivers/8188eu-20140908.tar.gz
Normal file
BIN
drivers/wolfson_drivers.tar.gz
Normal file
5
make_tar
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
cd $HOME
|
||||||
|
> video.log
|
||||||
|
rm -vf rpi_setup.tar*
|
||||||
|
tar cvjf rpi_setup.tar.bz2 `cat NOTES/FILE_LIST`
|
16
network_info
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Script that prints out active network interfaces' IP and MAC addresses
|
||||||
|
#
|
||||||
|
# Donald Burr <dburr@vctlabs.com>
|
||||||
|
|
||||||
|
if ip a | grep -Eq ': eth0:.*state UP'; then
|
||||||
|
eth_ip=$(ip addr | awk '/inet/ && /eth0/{sub(/\/.*$/,"",$2); print $2}')
|
||||||
|
eth_mac=`ifconfig eth0 | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
|
||||||
|
echo "ethernet: IP=$eth_ip MAC=$eth_mac"
|
||||||
|
fi
|
||||||
|
if ip a | grep -Eq ': wlan0:.*state UP'; then
|
||||||
|
wifi_ip=$(ip addr | awk '/inet/ && /wlan0/{sub(/\/.*$/,"",$2); print $2}')
|
||||||
|
wifi_mac=`ifconfig wlan0 | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
|
||||||
|
echo " wifi: IP=$wifi_ip MAC=$wifi_mac"
|
||||||
|
fi
|
231
scripts/ibeacon
Executable file
|
@ -0,0 +1,231 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Usage: sudo ibeacon [-u|--uuid=UUID or `random' (default=Beacon Toolkit app)]
|
||||||
|
[-M|--major=major (0-65535, default=0)]
|
||||||
|
[-m|--minor=minor (0-65535, default=0)]
|
||||||
|
[-p|--power=power (0-255, default=200)]
|
||||||
|
[-d|--device=BLE device to use (default=hci0)]
|
||||||
|
[-z|--down]
|
||||||
|
[-v|--verbose]
|
||||||
|
[-n|--simulate (implies -v)]
|
||||||
|
[-h|--help]
|
||||||
|
|
||||||
|
The default UUID matches that which the "Beacon Toolkit" app uses.
|
||||||
|
https://itunes.apple.com/us/app/beacon-toolkit/id728479775
|
||||||
|
|
||||||
|
UUID, major, minor and power may also be specified by setting the environment
|
||||||
|
variables `IBEACON_UUID,' `IBEACON_MAJOR,' `IBEACON_MINOR' and `IBEACON_POWER.'
|
||||||
|
Options set with command line switches always override defaults or environment.
|
||||||
|
|
||||||
|
NOTE: for environment variables to work, the following must be present
|
||||||
|
in your `sudoers' file:
|
||||||
|
Defaults env_keep += "IBEACON_UUID IBEACON_MAJOR IBEACON_MINOR IBEACON_POWER"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import getopt
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
# option flags
|
||||||
|
simulate = False
|
||||||
|
verbose = False
|
||||||
|
|
||||||
|
# prints usage information
|
||||||
|
class Usage(Exception):
|
||||||
|
def __init__(self, msg):
|
||||||
|
self.msg = msg
|
||||||
|
|
||||||
|
# return a random UUID
|
||||||
|
def get_random_uuid():
|
||||||
|
return uuid.uuid4().hex
|
||||||
|
|
||||||
|
# convert an integer into a hex value of a given number of digits
|
||||||
|
def hexify(i, digits=2):
|
||||||
|
format_string = "0%dx" % digits
|
||||||
|
return format(i, format_string).upper()
|
||||||
|
|
||||||
|
# swap the byte order of a 16-bit hex value
|
||||||
|
# NOT USED, leaving this here just in case, turns out major/minor ids
|
||||||
|
# are big-endian (i.e. no swap required)
|
||||||
|
def endian_swap(hex):
|
||||||
|
hexbyte1 = hex[0] + hex[1]
|
||||||
|
hexbyte2 = hex[2] + hex[3]
|
||||||
|
newhex = hexbyte2 + hexbyte1
|
||||||
|
return newhex
|
||||||
|
|
||||||
|
# split a hex string into 8-bit/2-hex-character groupings separated by spaces
|
||||||
|
def hexsplit(string):
|
||||||
|
return ' '.join([string[i:i+2] for i in range(0, len(string), 2)])
|
||||||
|
|
||||||
|
# process a command string - print it if verbose is on,
|
||||||
|
# and if not simulating, then actually run the command
|
||||||
|
def process_command(c):
|
||||||
|
global verbose
|
||||||
|
if verbose:
|
||||||
|
print ">>> %s" % c
|
||||||
|
if not simulate:
|
||||||
|
os.system(c)
|
||||||
|
|
||||||
|
# check to see if we are the superuser - returns 1 if yes, 0 if no
|
||||||
|
def check_for_sudo():
|
||||||
|
if 'SUDO_UID' in os.environ.keys():
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
print "Error: this script requires superuser privileges. Please re-run with `sudo.'"
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# check to see if the hci device is valid
|
||||||
|
# kind of a cheaty way of doing this, we just grep the output of
|
||||||
|
# `hcitool list' to make sure the passed-in device string is present
|
||||||
|
def is_valid_device(device):
|
||||||
|
return not os.system("hciconfig list 2>/dev/null | grep -q ^%s:" % device)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
|
||||||
|
# option flags
|
||||||
|
global verbose
|
||||||
|
global simulate
|
||||||
|
|
||||||
|
# default uuid, this is the uuid that the "Beacon Toolkit" iOS app uses
|
||||||
|
# https://itunes.apple.com/us/app/beacon-toolkit/id728479775
|
||||||
|
# can be overriden with environment variable
|
||||||
|
uuid = os.getenv("IBEACON_UUID", "E20A39F473F54BC4A12F17D1AD07A961")
|
||||||
|
|
||||||
|
# major and minor ids, can be overriden with environment variable
|
||||||
|
major = int(os.getenv("IBEACON_MAJOR", "0"))
|
||||||
|
minor = int(os.getenv("IBEACON_MINOR", "0"))
|
||||||
|
|
||||||
|
# default to the first available bluetooth device
|
||||||
|
device = "hci0"
|
||||||
|
|
||||||
|
# default power level
|
||||||
|
power = int(os.getenv("IBEACON_POWER", "200"))
|
||||||
|
|
||||||
|
# regexp to test for a valid UUID
|
||||||
|
# here the - separators are optional
|
||||||
|
valid_uuid_match = re.compile('^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$', re.I)
|
||||||
|
|
||||||
|
# grab command line arguments
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv
|
||||||
|
|
||||||
|
# parse command line options
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(argv[1:], "hu:M:m:p:vd:nz", ["help", "uuid=", "major=", "minor=", "power=", "verbose", "device=", "simulate", "down"])
|
||||||
|
|
||||||
|
except getopt.error, msg:
|
||||||
|
raise Usage(msg)
|
||||||
|
|
||||||
|
for o, a in opts:
|
||||||
|
if o in ("-h", "--help"):
|
||||||
|
print __doc__
|
||||||
|
return 0
|
||||||
|
elif o in ("-n", "--simulate"):
|
||||||
|
simulate = True
|
||||||
|
verbose = True
|
||||||
|
elif o in ("-u", "--uuid"):
|
||||||
|
uuid = a
|
||||||
|
if uuid == "random":
|
||||||
|
uuid = get_random_uuid()
|
||||||
|
elif o in ("-M", "--major"):
|
||||||
|
major = int(a)
|
||||||
|
elif o in ("-m", "--minor"):
|
||||||
|
minor = int(a)
|
||||||
|
elif o in ("-p", "--power"):
|
||||||
|
power = int(a)
|
||||||
|
elif o in ("-v", "--verbose"):
|
||||||
|
verbose = True
|
||||||
|
elif o in ( "-d", "--device"):
|
||||||
|
temp_device = str(a)
|
||||||
|
# devices can be specified as "X" or "hciX"
|
||||||
|
if not temp_device.startswith("hci"):
|
||||||
|
device = "hci%s" % temp_device
|
||||||
|
else:
|
||||||
|
device = temp_device
|
||||||
|
elif o in ( "-z", "--down"):
|
||||||
|
if check_for_sudo():
|
||||||
|
if is_valid_device(device):
|
||||||
|
print "Downing iBeacon on %s" % device
|
||||||
|
process_command("hciconfig %s noleadv" % device)
|
||||||
|
process_command("hciconfig %s piscan" % device)
|
||||||
|
process_command("hciconfig %s down" % device)
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print "Error: no such device: %s (try `hciconfig list')" % device
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# test for valid UUID
|
||||||
|
if not valid_uuid_match.match(uuid):
|
||||||
|
print "Error: `%s' is an invalid UUID." % uuid
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# strip out - symbols from uuid and turn it into uppercase
|
||||||
|
uuid = uuid.replace("-","")
|
||||||
|
uuid = uuid.upper()
|
||||||
|
|
||||||
|
# bounds check major/minor ids
|
||||||
|
if major < 0 or major > 65535:
|
||||||
|
print "Error: major id is out of bounds (0-65535)"
|
||||||
|
return 1
|
||||||
|
if minor < 0 or minor > 65535:
|
||||||
|
print "Error: minor id is out of bounds (0-65535)"
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# bail if we're not running as superuser (don't care if we are simulating)
|
||||||
|
if not simulate and not check_for_sudo():
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# split the uuid into 8 bit (=2 hex digit) chunks
|
||||||
|
split_uuid = hexsplit(uuid)
|
||||||
|
|
||||||
|
# convert major/minor id into hex
|
||||||
|
major_hex = hexify(major, 4)
|
||||||
|
minor_hex = hexify(minor, 4)
|
||||||
|
|
||||||
|
# create split versions of these (for the hcitool command)
|
||||||
|
split_major_hex = hexsplit(major_hex)
|
||||||
|
split_minor_hex = hexsplit(minor_hex)
|
||||||
|
|
||||||
|
# convert power into hex
|
||||||
|
power_hex = hexify(power, 2)
|
||||||
|
|
||||||
|
# make sure we are using a valid hci device
|
||||||
|
if not simulate and not is_valid_device(device):
|
||||||
|
print "Error: no such device: %s (try `hciconfig list')" % device
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# print status info
|
||||||
|
print "Advertising on %s with:" % device
|
||||||
|
print " uuid: 0x%s" % uuid
|
||||||
|
print "major/minor: %d/%d (0x%s/0x%s)" % (major, minor, major_hex, minor_hex)
|
||||||
|
print " power: %d (0x%s)" % (power, power_hex)
|
||||||
|
|
||||||
|
# first bring up bluetooth
|
||||||
|
process_command("hciconfig %s up" % device)
|
||||||
|
# now turn on LE advertising
|
||||||
|
process_command("hciconfig %s leadv" % device)
|
||||||
|
# now turn off scanning
|
||||||
|
process_command("hciconfig %s noscan" % device)
|
||||||
|
# set up the beacon
|
||||||
|
# pipe stdout to /dev/null to get rid of the ugly "here's what I did"
|
||||||
|
# message from hcitool
|
||||||
|
process_command("hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 %s %s %s %s 00 >/dev/null" % (split_uuid, split_major_hex, split_minor_hex, power_hex))
|
||||||
|
|
||||||
|
except Usage, err:
|
||||||
|
print >>sys.stderr, err.msg
|
||||||
|
print >>sys.stderr, "for help use --help"
|
||||||
|
return 2
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
96
scripts/start_video
Executable file
|
@ -0,0 +1,96 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
local var=$@
|
||||||
|
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
|
||||||
|
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
|
||||||
|
echo -n "$var"
|
||||||
|
}
|
||||||
|
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
IP=`ip route get 8.8.8.8 | awk 'NR==1 {print $NF}'`
|
||||||
|
VIDEO_DEVICE=`trim \`v4l2-ctl --list-devices | grep \/dev\/video | head -n 1\``
|
||||||
|
|
||||||
|
# bail if no valid video devices
|
||||||
|
if [ -z "$VIDEO_DEVICE" ]; then
|
||||||
|
echo "error: could not find a valid v4l device"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# run as sudo if necessary
|
||||||
|
#[ "$(whoami)" != "root" ] && exec sudo -- "$0" "$@"
|
||||||
|
|
||||||
|
# at this point we should be root
|
||||||
|
echo "operating on video device $VIDEO_DEVICE"
|
||||||
|
|
||||||
|
# touch log
|
||||||
|
touch video.log
|
||||||
|
echo "" >> video.log
|
||||||
|
echo "*** BEGINNING RUN AT `date` ***" >> video.log
|
||||||
|
echo "" >> video.log
|
||||||
|
|
||||||
|
# configure v4l2
|
||||||
|
sudo v4l2-ctl --device=$VIDEO_DEVICE --set-fmt-video=width=800,height=600,pixelformat=1 >>video.log 2>&1
|
||||||
|
|
||||||
|
# set mic volume
|
||||||
|
amixer -c 1 sset Mic,0 80%,80% unmute cap >>video.log 2>&1
|
||||||
|
|
||||||
|
# now stream
|
||||||
|
echo "stream is available as http://$IP:8080/"
|
||||||
|
echo "log file is available as video.log"
|
||||||
|
|
||||||
|
# working, video only
|
||||||
|
#cvlc \
|
||||||
|
#v4l2://$VIDEO_DEVICE:chroma=MJPG:width=800:height=600 \
|
||||||
|
#--sout '#standard{access=http,mux=ts,dst=:8080,name=stream,mime=video/ts}' \
|
||||||
|
#-vvv \
|
||||||
|
#>>video.log 2>&1
|
||||||
|
|
||||||
|
# working, video+audio with vlc, audio-only with mplayer*
|
||||||
|
cvlc \
|
||||||
|
v4l2://$VIDEO_DEVICE:chroma=MJPG:width=800:height=600 \
|
||||||
|
:input-slave="alsa://hw:1,0" \
|
||||||
|
--sout '#transcode{acodec=a52,ab=32}:http{mux=ts,dst=:8080,name=stream}' \
|
||||||
|
-vvv \
|
||||||
|
>>video.log 2>&1
|
||||||
|
|
||||||
|
# gstraemer version
|
||||||
|
#gst-launch-1.0 -v v4l2src \
|
||||||
|
#! "image/jpeg,width=320,height=240,framerate=30/1" \
|
||||||
|
#! multipartmux \
|
||||||
|
#! tcpserversink host=127.0.0.1 port=5000 sync=false alsasrc device=hw:1 \
|
||||||
|
#! audioconvert ! audioresample \
|
||||||
|
#! 'audio/x-raw,format=S16LE,channels=1,layout=interleaved' \
|
||||||
|
#! udpsink host=127.0.0.1 port=5001
|
||||||
|
#! 'audio/x-raw-int,rate=8000,width=16,channels=1' \
|
||||||
|
|
||||||
|
# attempt at using mp4v
|
||||||
|
#cvlc \
|
||||||
|
#v4l2://$VIDEO_DEVICE:chroma=MJPG:width=800:height=600 \
|
||||||
|
#:input-slave="alsa://hw:1,0" \
|
||||||
|
#--sout '#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128}:standard{access=http,mux=ts,dst=:8080}' \
|
||||||
|
#-vvv \
|
||||||
|
#>>video.log 2>&1
|
||||||
|
|
||||||
|
# attempt at using x264
|
||||||
|
#cvlc v4l2://$VIDEO_DEVICE:chroma=YUY2:width=800:height=600 :input-slave="alsa://hw:1,0" --sout '#transcode{vcodec=h264,vb=1024,fps=25,width=800,height=600,venc=x264{profile=baseline,level=1},acodec=mp3,ab=128,channels=2,samplerate=48000}:http{dst=:8080,mux=ts}' -vvv
|
||||||
|
|
||||||
|
# attempt at using webm
|
||||||
|
#cvlc \
|
||||||
|
#v4l2://$VIDEO_DEVICE:chroma=YUY2:width=800:height=600 \
|
||||||
|
#:input-slave="alsa://hw:1,0" \
|
||||||
|
#--sout '#transcode{vcodec=VP80,vb=1000}:std{access=http{mime=video/webm},mux=webm,dst=:8080}' \
|
||||||
|
#-vvv \
|
||||||
|
#>>video.log 2>&1
|
||||||
|
|
||||||
|
# attempt at using ogg
|
||||||
|
#cvlc \
|
||||||
|
#v4l2://$VIDEO_DEVICE:chroma=YUY2:width=800:height=600 \
|
||||||
|
#:input-slave="alsa://hw:1,0" \
|
||||||
|
#--sout '#transcode{vcodec=theo,vb=2000}:std{access=http{mime=video/ogg},mux=ogg,dst=:8080}' \
|
||||||
|
#-vvv \
|
||||||
|
#>>video.log 2>&1
|
||||||
|
|
||||||
|
#cvlc v4l2://$VIDEO_DEVICE:chroma=h264:width=1280:height=720 :input-slave="alsa://hw:1,0" --sout '#transcode{acodec=a52,ab=32}:http{mux=ts,dst=:8080,name=stream,mime=video/ts}' -vvv
|
||||||
|
|
||||||
|
#new stream broadcast enabled input "http://192.168.0.205:8001/1:0:1:6E2E:431:1:C00000:0:0:0:" output #transcode{vcodec=h264,vb=1024,fps=25,width=800,height=480,venc=x264{profile=baseline,level=1},acodec=mp3,ab=128,channels=2,samplerate=48000}:http{dst=:8080/stream.ts}
|
23
scripts/still_test
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# camera orientation should be with the cable pointing downward.
|
||||||
|
# if you have it mounted the opposite (cable pointed upward) you
|
||||||
|
# will need to set both camera.hflip and camera.vflip to True.
|
||||||
|
|
||||||
|
import picamera
|
||||||
|
import threading
|
||||||
|
|
||||||
|
camera = picamera.PiCamera()
|
||||||
|
|
||||||
|
def snap():
|
||||||
|
snap.counter += 1
|
||||||
|
threading.Timer(5.0, snap).start()
|
||||||
|
print "Taking picture %d" % snap.counter
|
||||||
|
camera.capture('image_%d.jpg' % snap.counter)
|
||||||
|
|
||||||
|
camera.resolution = (640, 480)
|
||||||
|
camera.hflip = True
|
||||||
|
camera.vflip = True
|
||||||
|
snap.counter = 0
|
||||||
|
|
||||||
|
snap()
|
3
scripts/stream2
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
ffserver -f /etc/ff.conf &
|
||||||
|
ffmpeg -v quiet -r 5 -s 320x240 -f video4linux2 -i /dev/video0 http://localhost/webcam.ffm
|
561
setup_pi
Executable file
|
@ -0,0 +1,561 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Raspberry Pi Setup Script
|
||||||
|
# Donald Burr <dburr@vctlabs.com>
|
||||||
|
|
||||||
|
# set to YES for debugging
|
||||||
|
DEBUG="NO"
|
||||||
|
# use older motion-mmal with its own built-in raspi camera driver
|
||||||
|
USE_MMAL_MOTION="NO"
|
||||||
|
# use newer (third party) version of node.js
|
||||||
|
USE_THIRD_PARTY_NODE_JS="YES"
|
||||||
|
# install newer (third party) ffmpeg in /usr?
|
||||||
|
INSTALL_FFMPEG_IN_USR="NO"
|
||||||
|
# disable the red LED that turns on when the camera module is active?
|
||||||
|
DISABLE_CAMERA_LED="YES"
|
||||||
|
# also install PHP when installing lighttpd?
|
||||||
|
INSTALL_PHP="NO"
|
||||||
|
|
||||||
|
# store location that this script is in
|
||||||
|
D="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
# convenience function, install a package but only if it isn't already present
|
||||||
|
function install_package
|
||||||
|
{
|
||||||
|
local PACKAGE=$1
|
||||||
|
if dpkg -s $PACKAGE >/dev/null 2>&1; then
|
||||||
|
echo "skipping install of $PACKAGE, it is already present"
|
||||||
|
else
|
||||||
|
echo "installing $PACKAGE"
|
||||||
|
sudo aptitude -q=2 -y install $PACKAGE
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ffmpeg setup code is broken out into its own function because it
|
||||||
|
# is used in 2 spots in this script
|
||||||
|
function install_ffmpeg
|
||||||
|
{
|
||||||
|
if [ "$DEBUG" = "YES" ]; then
|
||||||
|
echo "skipping install of ffmpeg, we are in DEBUG Mode"
|
||||||
|
echo "NOTE: this may break other apps that depend on it."
|
||||||
|
elif hash ffserver 2>/dev/null; then
|
||||||
|
echo "skipping install of ffmpeg, it is already present"
|
||||||
|
else
|
||||||
|
echo "*** building current ffmpeg from source ***"
|
||||||
|
mkdir $HOME/src
|
||||||
|
cd $HOME/src
|
||||||
|
git clone git://source.ffmpeg.org/ffmpeg.git
|
||||||
|
cd ffmpeg
|
||||||
|
if [ "$INSTALL_FFMPEG_IN_USR" = "YES" ]; then
|
||||||
|
./configure --prefix=/usr
|
||||||
|
else
|
||||||
|
./configure
|
||||||
|
fi
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
echo "*** setting up symlinks ***"
|
||||||
|
if [ "$INSTALL_FFMPEG_IN_USR" != "YES" ]; then
|
||||||
|
for COMMAND in ffmpeg ffprobe ffserver; do
|
||||||
|
sudo rm -f /usr/bin/$COMMAND && sudo ln -sf ../local/bin/$COMMAND /usr/bin/$COMMAND
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# start of script
|
||||||
|
|
||||||
|
if ! dpkg -s screen >/dev/null 2>&1; then
|
||||||
|
echo "*** BEGINNING RPI SETUP ***"
|
||||||
|
echo "This script assumes you have gone through \`raspi-config' (must be run as root)"
|
||||||
|
echo "and configured all the values there, especially Internationalization,"
|
||||||
|
echo "Keyboard and the Raspberry Pi Camera (if one is installed.)"
|
||||||
|
echo ""
|
||||||
|
echo "If you haven't performed those steps, hit Ctrl-C now and do so, then"
|
||||||
|
echo -n "re-run this script. Otherwise, press Return to proceed. "
|
||||||
|
read BLAH
|
||||||
|
echo ""
|
||||||
|
echo "*** performing initial setup ***"
|
||||||
|
sudo aptitude -y update
|
||||||
|
for PKG in screen mosh; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
|
||||||
|
if grep -q raspberrypi /etc/hostname; then
|
||||||
|
echo "You still have the default hostname set. We recommend changing the"
|
||||||
|
echo "hostname so that your Pi can be uniquely identified."
|
||||||
|
echo "If you wish to change it, enter a new hostname now, otherwise"
|
||||||
|
echo -n "just press Return: "
|
||||||
|
read NEW_HOSTNAME
|
||||||
|
if [ ! -z "$NEW_HOSTNAME" ]; then
|
||||||
|
echo "$NEW_HOSTNAME" > /tmp/HOSTNAME.$$
|
||||||
|
sudo rm -f /etc/hostname
|
||||||
|
sudo mv /tmp/HOSTNAME.$$ /etc/hostname
|
||||||
|
sudo chown root:root /etc/hostname
|
||||||
|
sudo chmod 644 /etc/hostname
|
||||||
|
sudo /etc/init.d/hostname.sh
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Would you like to set up a Wi-Fi adapter? [yn] "
|
||||||
|
read WIFI_YORN
|
||||||
|
if [ "$WIFI_YORN" = "y" ]; then
|
||||||
|
echo "Please make sure the Wi-Fi adapter is plugged in, then at the prompt below,"
|
||||||
|
echo "enter which type of adapter you wish to set up."
|
||||||
|
echo ""
|
||||||
|
echo "1. TP-LINK TL-WN725N"
|
||||||
|
echo "2. Edimax EW-7811Un"
|
||||||
|
echo ""
|
||||||
|
WIFI_ADAPTER=0
|
||||||
|
VALID="NO"
|
||||||
|
while [ "$VALID" = "NO" ]; do
|
||||||
|
echo -n "Your choice: "
|
||||||
|
read WIFI_ADAPTER
|
||||||
|
if ! [[ "$WIFI_ADAPTER" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Error, that is not a valid answer."
|
||||||
|
elif [ "$WIFI_ADAPTER" -lt 1 -o "$WIFI_ADAPTER" -gt 2 ]; then
|
||||||
|
echo "Error, that is not a valid answer."
|
||||||
|
else
|
||||||
|
VALID="YES"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $WIFI_ADAPTER -eq 1 ]; then
|
||||||
|
# TP-link
|
||||||
|
SKIP_RPI_UPDATE="YES"
|
||||||
|
KERNEL_DATE_LONG=`uname -v | sed -e 's/^.*PREEMPT //g'`
|
||||||
|
KERNEL_DATE=`date -d"$KERNEL_DATE_LONG" +%Y%m%d`
|
||||||
|
if [ ! -f "$D/drivers/8188eu-$KERNEL_DATE.tar.gz" ]; then
|
||||||
|
echo "Could not find a driver matching your kernel version. Will attempt to"
|
||||||
|
echo "fetch one now."
|
||||||
|
cd $D/drivers
|
||||||
|
wget https://dl.dropboxusercontent.com/u/80256631/8188eu-$KERNEL_DATE.tar.gz
|
||||||
|
fi
|
||||||
|
if [ -f "$D/drivers/8188eu-$KERNEL_DATE.tar.gz" ]; then
|
||||||
|
mkdir /tmp/wifi.$$
|
||||||
|
cd /tmp/wifi.$$
|
||||||
|
tar xzf $D/drivers/8188eu-$KERNEL_DATE.tar.gz
|
||||||
|
sudo install -p -m 644 8188eu.ko /lib/modules/`uname -r`/kernel/drivers/net/wireless
|
||||||
|
sudo insmod /lib/modules/`uname -r`/kernel/drivers/net/wireless/8188eu.ko
|
||||||
|
sudo depmod -a
|
||||||
|
PROCEED_WITH_WIFI_SETUP="YES"
|
||||||
|
else
|
||||||
|
echo "ERROR: could not find a version of the TP-link driver for your kernel."
|
||||||
|
echo "Cannot proceed with wifi setup."
|
||||||
|
PROCEED_WITH_WIFI_SETUP="NO"
|
||||||
|
fi
|
||||||
|
elif [ $WIFI_ADAPTER -eq 2 ]; then
|
||||||
|
# edimax
|
||||||
|
# no further configuration necessary, the driver is already in the kernel
|
||||||
|
SKIP_RPI_UPDATE="NO"
|
||||||
|
PROCEED_WITH_WIFI_SETUP="YES"
|
||||||
|
else
|
||||||
|
# fallthrough, we can't proceed
|
||||||
|
SKIP_RPI_UPDATE="NO"
|
||||||
|
PROCEED_WITH_WIFI_SETUP="NO"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# the rest is common to all wifi adapters
|
||||||
|
if [ "$PROCEED_WITH_WIFI_SETUP" = "YES" ]; then
|
||||||
|
echo -n "Enter your wireless network's SSID: "
|
||||||
|
read SSID
|
||||||
|
PASSWORD="foo"
|
||||||
|
PASSWORD_TEMP="bar"
|
||||||
|
stty -echo
|
||||||
|
while [ "$PASSWORD" != "$PASSWORD_TEMP" ]; do
|
||||||
|
echo "Note: Only WPA and/or WPA2 passwords are currently supported."
|
||||||
|
echo -n "Enter your wireless network's password: "
|
||||||
|
read PASSWORD
|
||||||
|
echo
|
||||||
|
echo -n "Re-enter for verification: "
|
||||||
|
read PASSWORD_TEMP
|
||||||
|
echo
|
||||||
|
if [ "$PASSWORD" != "$PASSWORD_TEMP" ]; then
|
||||||
|
echo "Error: passwords do not match"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
stty echo
|
||||||
|
if [ -f /etc/network/interfaces ]; then
|
||||||
|
sudo mv -f /etc/network/interfaces /etc/network/interfaces.bak
|
||||||
|
fi
|
||||||
|
sudo cp $D/configs/wifi/interfaces /etc/network/interfaces
|
||||||
|
sudo chown root:root /etc/network/interfaces
|
||||||
|
sudo chmod 644 /etc/network/interfaces
|
||||||
|
if [ -f /etc/wpa_supplicant/wpa_supplicant.conf ]; then
|
||||||
|
sudo mv -f /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf.bak
|
||||||
|
fi
|
||||||
|
sudo cp $D/configs/wifi/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
sudo sed -i.sed.bak -e "s/#SSID#/$SSID/g" -e "s/#PASSWORD#/$PASSWORD/g" /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
sudo chown root:root /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
echo "*** attempting to bring up Wi-Fi... ***"
|
||||||
|
sudo ifdown wlan0
|
||||||
|
sudo ifdown --force wlan0
|
||||||
|
sudo ifup wlan0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# some wifi adapters haven't yet had their drivers updated to work with
|
||||||
|
# the newer kernel installed by rpi-update, so we may have to skip it
|
||||||
|
if [ "$SKIP_RPI_UPDATE" != "YES" ]; then
|
||||||
|
echo "*** updating RPI firmware ***"
|
||||||
|
install_package rpi-update
|
||||||
|
sudo rpi-update
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "*** initial setup is now complete."
|
||||||
|
echo "*** please reboot your Pi now."
|
||||||
|
echo "*** after it has booted up, login and re-run this script."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# initial set up is done
|
||||||
|
|
||||||
|
echo "*** Ready to perform second stage of setup."
|
||||||
|
echo "*** This stage will take a long time. It is recommended to run this"
|
||||||
|
echo "*** script within \`screen' so that it will continue running even if"
|
||||||
|
echo "*** something bad were to occur (lose connection, etc.)"
|
||||||
|
echo "*** If you are not currently running within \`screen', press Ctrl-C"
|
||||||
|
echo "*** and re-run this script from within \`screen.' Otherwise,"
|
||||||
|
echo -n "*** press Return to proceed: "
|
||||||
|
read FAILSAFE
|
||||||
|
|
||||||
|
echo "*** installing additional packages ***"
|
||||||
|
for PKG in cifs-utils git pv vim; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
|
||||||
|
# for vlc/gstreamer
|
||||||
|
echo -n "Install vlc & gstreamer? [yn] "
|
||||||
|
read INSTALL_VLC
|
||||||
|
if [ "$INSTALL_VLC" = "y" ]; then
|
||||||
|
echo "*** setting up vlc and gstreamer streaming ***"
|
||||||
|
for PKG in vlc gstreamer1.0 libasound2-dev; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# for bluetooth
|
||||||
|
echo -n "Install bluetooth & ibeacon? [yn] "
|
||||||
|
read INSTALL_BT
|
||||||
|
if [ "$INSTALL_BT" = "y" ]; then
|
||||||
|
echo "*** setting up bluetooth and ibeacon ***"
|
||||||
|
for PKG in bluetooth bluez-utils blueman; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
sudo cp $D/scripts/ibeacon /usr/bin
|
||||||
|
sudo chown root:root /usr/bin/ibeacon
|
||||||
|
sudo chmod 755 /usr/bin/ibeacon
|
||||||
|
if ! sudo grep -q IBEACON_UUID /etc/sudoers; then
|
||||||
|
echo "adding env_keep to sudoers"
|
||||||
|
sudo sed -i '/Defaults.*env_reset/a \
|
||||||
|
Defaults env_keep += "IBEACON_UUID IBEACON_MAJOR IBEACON_MINOR IBEACON_POWER"' /etc/sudoers
|
||||||
|
else
|
||||||
|
echo "do not need to edit sudoers"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up ffmpeg
|
||||||
|
# NOTE: we are using the latest version from git instead of the packaged version
|
||||||
|
# skip when debugging, it takes forever
|
||||||
|
echo -n "Install latest ffmpeg from source (takes a LONG time, about 4-5 hours)? [yn] "
|
||||||
|
read INSTALL_FFMPEG
|
||||||
|
if [ "$INSTALL_FFMPEG" = "y" ]; then
|
||||||
|
install_ffmpeg
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up avahi
|
||||||
|
# http://holyarmy.org/2008/01/advertising-linux-services-via-avahibonjour/
|
||||||
|
echo -n "Install avahi (Bonjour/zeroconf autodiscovery)? [yn] "
|
||||||
|
read INSTALL_AVAHI
|
||||||
|
if [ "$INSTALL_AVAHI" = "y" ]; then
|
||||||
|
echo "*** setting up avahi (bonjour/autodiscovery) ***"
|
||||||
|
for PKG in avahi-daemon avahi-utils; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
for F in $D/configs/avahi/*.service; do
|
||||||
|
echo "installing $F..."
|
||||||
|
sudo cp $F /etc/avahi/services
|
||||||
|
done
|
||||||
|
sudo chown root:root /etc/avahi/services/*.service
|
||||||
|
sudo chmod 644 /etc/avahi/services/*.service
|
||||||
|
sudo service avahi-daemon restart
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up lighttpd+php
|
||||||
|
# http://www.instructables.com/id/Setup-a-Raspberry-Pi-PHP-web-server/?ALLSTEPS
|
||||||
|
echo -n "Install Pi webserver environment (lighttpd+php)? [yn] "
|
||||||
|
read INSTALL_LIGHTTPD
|
||||||
|
if [ "$INSTALL_LIGHTTPD" = "y" ]; then
|
||||||
|
echo "*** installing lighttpd and php packages ***"
|
||||||
|
install_package lighttpd
|
||||||
|
if [ "$INSTALL_PHP" = "YES" ]; then
|
||||||
|
echo "*** installing php ***"
|
||||||
|
for PKG in php5-common php5-cgi php5; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo "*** enabling lighttpd modules ***"
|
||||||
|
MODULES="cgi fastcgi userdir"
|
||||||
|
if [ "$INSTALL_PHP" = "YES" ]; then
|
||||||
|
MODULES="$MODULES fastcgi-php"
|
||||||
|
fi
|
||||||
|
for MODULE in $MODULES; do
|
||||||
|
echo "...$MODULE"
|
||||||
|
sudo lighty-enable-mod $MODULE
|
||||||
|
done
|
||||||
|
echo "*** enabling cgi-bin directories ***"
|
||||||
|
sudo sed -i.bak -e 's/^\($HTTP\["url"\] =~ "\)[^"]*\(".*$\)/\1\/cgi-bin\/\2/' /etc/lighttpd/conf-available/10-cgi.conf
|
||||||
|
echo "*** enabling directory listings for directories that lack index.html ***"
|
||||||
|
sudo sed -i.bak -e '$adir-listing.activate = "enable"' /etc/lighttpd/lighttpd.conf
|
||||||
|
echo "*** setting permissions for /var/www directory ***"
|
||||||
|
sudo chown www-data:www-data /var/www
|
||||||
|
sudo chmod 775 /var/www
|
||||||
|
sudo usermod -a -G www-data pi
|
||||||
|
echo "*** installing default www files ***"
|
||||||
|
mkdir -p $HOME/public_html
|
||||||
|
cp -a $D/configs/lighttpd/* $HOME/public_html
|
||||||
|
chmod -R g+w $HOME/public_html
|
||||||
|
sudo cp -a $D/configs/lighttpd/* /var/www
|
||||||
|
sudo chmod -R g+w /var/www
|
||||||
|
if [ -f /var/www/index.html.webroot ]; then
|
||||||
|
cp /var/www/index.html.webroot /var/www/index.html
|
||||||
|
fi
|
||||||
|
if [ -f $HOME/public_html/index.html.home ]; then
|
||||||
|
cp $HOME/public_html/index.html.home $HOME/public_html/index.html
|
||||||
|
fi
|
||||||
|
echo "*** restarting lighttpd ***"
|
||||||
|
sudo service lighttpd force-reload
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up osss
|
||||||
|
echo -n "Install OSSS (Open Source Surveillance & Security)? [yn] "
|
||||||
|
read INSTALL_OSSS
|
||||||
|
if [ "$INSTALL_OSSS" = "y" ]; then
|
||||||
|
echo "*** setting up motion ***"
|
||||||
|
if [ "$USE_MMAL_MOTION" = "YES" ]; then
|
||||||
|
for PKG in libjpeg62 libjpeg62-dev libavformat53 libavformat-dev libavcodec53 libavcodec-dev libavutil51 libavutil-dev libc6-dev zlib1g-dev libmysqlclient18 libmysqlclient-dev libpq5 libpq-dev motion; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
if [ ! -f /usr/bin/motion.orig ]; then
|
||||||
|
echo "*** fetching version of motion patched for raspi camera ***"
|
||||||
|
mkdir /tmp/motion.$$
|
||||||
|
cd /tmp/motion.$$ && wget https://www.dropbox.com/s/xdfcxm5hu71s97d/motion-mmal.tar.gz
|
||||||
|
tar xzf motion-mmal.tar.gz
|
||||||
|
sudo mv /usr/bin/motion /usr/bin/motion.stock
|
||||||
|
sudo cp motion /usr/bin/motion.mmal
|
||||||
|
sudo chown root:root /usr/bin/motion.mmal
|
||||||
|
sudo chmod 755 /usr/bin/motion.mmal
|
||||||
|
sudo ln -sf motion.stock /usr/bin/motion
|
||||||
|
fi
|
||||||
|
if [ ! -f /etc/motion.conf ]; then
|
||||||
|
echo "*** installing motion-mmal config file ***"
|
||||||
|
sudo cp $D/configs/motion/motion-mmal.conf /etc/motion.conf
|
||||||
|
sudo sed -i.sed.bak "s/^.*\btext_left\b.*$/text_left `hostname`/" /etc/motion.conf
|
||||||
|
sudo chown root:root /etc/motion.conf
|
||||||
|
sudo chmod 644 /etc/motion.conf
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
for PKG in motion; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
if [ ! -f /etc/motion/motion.conf.orig ]; then
|
||||||
|
echo "*** installing motion config file ***"
|
||||||
|
sudo mv /etc/motion/motion.conf /etc/motion/motion.conf.orig
|
||||||
|
sudo cp $D/configs/motion/motion.conf /etc/motion/motion.conf
|
||||||
|
sudo sed -i.sed.bak "s/^.*\btext_left\b.*$/text_left `hostname`/" /etc/motion/motion.conf
|
||||||
|
sudo chown root:motion /etc/motion/motion.conf
|
||||||
|
sudo chmod 644 /etc/motion/motion.conf
|
||||||
|
fi
|
||||||
|
if ! grep -q bcm2835-v4l2 /etc/modules; then
|
||||||
|
echo "*** setting camera driver to load at boot (and loading it now) ***"
|
||||||
|
sudo sed -i.bak -e "\$a\
|
||||||
|
bcm2835-v4l2" /etc/modules
|
||||||
|
sudo modprobe bcm2835-v4l2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ ! -f /var/log/motion ]; then
|
||||||
|
echo "*** creating motion log file ***"
|
||||||
|
sudo touch /var/log/motion.log
|
||||||
|
sudo chown motion:motion /var/log/motion.log
|
||||||
|
sudo chmod 644 /var/log/motion.log
|
||||||
|
fi
|
||||||
|
if [ ! -d /var/spool/motion ]; then
|
||||||
|
echo "*** creating motion spool directory ***"
|
||||||
|
sudo mkdir /var/spool/motion
|
||||||
|
sudo chown motion:motion /var/spool/motion
|
||||||
|
sudo chmod 755 /var/spool/motion
|
||||||
|
fi
|
||||||
|
if ! grep -q "start_motion_daemon.*=.*yes" /etc/default/motion; then
|
||||||
|
echo "*** enabling auto-run motion at startup ***"
|
||||||
|
sudo sed -i 's/^\(start_motion_daemon\s*=\s*\).*$/\1yes/' /etc/default/motion
|
||||||
|
fi
|
||||||
|
if [ ! -d /home/motion ]; then
|
||||||
|
echo "*** creating motion home directory ***"
|
||||||
|
sudo mkdir /home/motion
|
||||||
|
sudo chown motion:motion /home/motion
|
||||||
|
fi
|
||||||
|
echo "*** setting up node.js ***"
|
||||||
|
if [ "$USE_THIRD_PARTY_NODE_JS" = "YES" ]; then
|
||||||
|
echo "Downloading node.js..."
|
||||||
|
mkdir -p /tmp/node.$$
|
||||||
|
cd /tmp/node.$$ && curl -L# https://gist.github.com/raw/3245130/v0.10.24/node-v0.10.24-linux-arm-armv6j-vfp-hard.tar.gz -o node-v0.10.24-linux-arm-armv6j-vfp-hard.tar.gz
|
||||||
|
echo "Installing node.js..."
|
||||||
|
pv /tmp/node.$$/node-v0.10.24-linux-arm-armv6j-vfp-hard.tar.gz | sudo tar --owner=root --group=root -C /usr/ -xzf - --strip=1
|
||||||
|
else
|
||||||
|
for PKG in nodejs npm; do
|
||||||
|
install_package $PKG
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ "$USE_THIRD_PARTY_NODE_JS" != "YES" ]; then
|
||||||
|
# raspbian standard node needs special ssl configuration
|
||||||
|
#
|
||||||
|
#echo "*** upgrading to SSL-compliant version of npm ***"
|
||||||
|
#sudo npm install npm -g --ca=""
|
||||||
|
echo "*** configuring npm to use standard SSL certificates ***"
|
||||||
|
npm config set ca ""
|
||||||
|
sudo npm config set ca ""
|
||||||
|
fi
|
||||||
|
# ffmpeg is used by the fluent-ffmpeg module
|
||||||
|
echo "*** setting up ffmpeg (used by node.js modules) ***"
|
||||||
|
echo "*** NOTE: this takes a LONG time (~3-4 hours) ***"
|
||||||
|
install_ffmpeg
|
||||||
|
echo "*** installing node.js modules ***"
|
||||||
|
# express@2.5.1
|
||||||
|
MODULE_LIST="async express fluent-ffmpeg nstore ps-node"
|
||||||
|
if [ "$USE_THIRD_PARTY_NODE_JS" = "YES" ]; then
|
||||||
|
# only the newer node.js seems to like express
|
||||||
|
MODULE_LIST="express express-generator@4 $MODULE_LIST"
|
||||||
|
fi
|
||||||
|
for MODULE in $MODULE_LIST; do
|
||||||
|
echo "...$MODULE"
|
||||||
|
sudo npm install -g $MODULE
|
||||||
|
done
|
||||||
|
if [ "$USE_THIRD_PARTY_NODE_JS" != "YES" ]; then
|
||||||
|
# only needed for stock raspbian node.js
|
||||||
|
echo "*** creating node -> nodejs symlink ***"
|
||||||
|
sudo ln -sf nodejs /usr/bin/node
|
||||||
|
fi
|
||||||
|
echo "*** adding node.js modules path to bashrc ***"
|
||||||
|
echo 'export NODE_PATH="'$(npm root -g)'"' >> $HOME/.bashrc
|
||||||
|
if ! sudo grep -q NODE_PATH /etc/sudoers; then
|
||||||
|
echo "adding env_keep NODE_PATH to sudoers"
|
||||||
|
sudo sed -i '/Defaults.*env_reset/a \
|
||||||
|
Defaults env_keep += "NODE_PATH"' /etc/sudoers
|
||||||
|
else
|
||||||
|
echo "do not need to edit sudoers"
|
||||||
|
fi
|
||||||
|
if [ ! -f /home/motion/server.js ]; then
|
||||||
|
echo "*** installing web app ***"
|
||||||
|
if [ `hostname` = "pi-b" ]; then
|
||||||
|
sudo ln -sf $D/configs/motion/server.js /home/motion/server.js
|
||||||
|
else
|
||||||
|
sudo cp $D/configs/motion/server.js /home/motion/server.js
|
||||||
|
sudo chown motion:motion /home/motion/server.js
|
||||||
|
sudo chmod 644 /home/motion/server.js
|
||||||
|
fi
|
||||||
|
sudo cp $D/configs/motion/run_server /home/motion/run_server
|
||||||
|
sudo chown motion:motion /home/motion/run_server
|
||||||
|
sudo chmod 755 /home/motion/run_server
|
||||||
|
fi
|
||||||
|
crontab -l > /tmp/crontab.$$ 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
NEEDS_CRONTAB="YES"
|
||||||
|
elif ! grep -q SMB_BACKUP /tmp/crontab.$$; then
|
||||||
|
NEEDS_CRONTAB="YES"
|
||||||
|
else
|
||||||
|
NEEDS_CRONTAB="NO"
|
||||||
|
fi
|
||||||
|
if [ "$NEEDS_CRONTAB" = "YES" ]; then
|
||||||
|
echo "*** setting up backup script ***"
|
||||||
|
crontab -l > /tmp/cron.$$ 2>/dev/null
|
||||||
|
cat << _EOF_CRON_ >> /tmp/cron.$$
|
||||||
|
#SMB_BACKUP
|
||||||
|
0 * * * * /home/pi/sync_osss_files
|
||||||
|
_EOF_CRON_
|
||||||
|
crontab /tmp/cron.$$
|
||||||
|
rm -f /tmp/cron.$$
|
||||||
|
fi
|
||||||
|
# run server at boot
|
||||||
|
if ! grep -q RUN_MOTION_SERVER /etc/rc.local; then
|
||||||
|
echo "*** enabling motion web server at boot ***"
|
||||||
|
sudo sed -i.bak '/^exit 0$/i\
|
||||||
|
#RUN_MOTION_SERVER\
|
||||||
|
cd /home/motion && nohup bash run_server &\
|
||||||
|
' /etc/rc.local
|
||||||
|
fi
|
||||||
|
# disable camera LED
|
||||||
|
if [ "$DISABLE_CAMERA_LED" = "YES" ]; then
|
||||||
|
echo "*** disabling camera LED ***"
|
||||||
|
if grep -q disable_camera_led /boot/config.txt; then
|
||||||
|
sudo sed -i.bak -e 's/.*disable_camera_led.*/disable_camera_led=1/g' /boot/config.txt
|
||||||
|
else
|
||||||
|
sudo sed -i.bak -e '$adisable_camera_led=1' /boot/config.txt
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up streaming monitor
|
||||||
|
#echo "Note: this install includes a build of ffmpeg and nginx which takes a"
|
||||||
|
#echo "LONG time (about 3-4 hours.)"
|
||||||
|
echo -n "Install streaming video server? [yn] "
|
||||||
|
read INSTALL_STREAMER
|
||||||
|
if [ "$INSTALL_STREAMER" = "y" ]; then
|
||||||
|
# install needed packages
|
||||||
|
# libav-tools
|
||||||
|
for PACKAGE in ffmpeg libpcre3-dev libssl-dev supervisor; do
|
||||||
|
install_package $PACKAGE
|
||||||
|
done
|
||||||
|
# needs ffmpeg
|
||||||
|
#install_ffmpeg
|
||||||
|
# build nginx
|
||||||
|
echo "Fetching and building nginx..."
|
||||||
|
mkdir /tmp/nginx.$$ && cd /tmp/nginx.$$
|
||||||
|
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
|
||||||
|
wget http://nginx.org/download/nginx-1.7.9.tar.gz
|
||||||
|
tar -zxvf nginx-1.7.9.tar.gz
|
||||||
|
unzip master.zip
|
||||||
|
cd nginx-1.7.9
|
||||||
|
./configure --add-module=/tmp/nginx.$$/nginx-rtmp-module-master
|
||||||
|
make && sudo make install
|
||||||
|
# clone the rpi repo
|
||||||
|
echo "Fetching streaming code..."
|
||||||
|
cd /tmp/nginx.$$
|
||||||
|
git clone https://github.com/Tomtomgo/raspberry_livestream.git
|
||||||
|
cd /tmp/nginx.$$/raspberry_livestream
|
||||||
|
# edit stream.sh
|
||||||
|
sudo cp nginx.conf /usr/local/nginx/conf/nginx.conf
|
||||||
|
sudo cp stream.supervisor.conf /etc/supervisor/conf.d/stream.supervisor.conf
|
||||||
|
cp stream.sh $HOME/stream.sh
|
||||||
|
# restart
|
||||||
|
#sudo service supervisor stop
|
||||||
|
#sudo service supervisor start
|
||||||
|
echo "NOTE: be sure and set STREAM_NAME and RASPBERRY_IP in \$HOME/stream.sh"
|
||||||
|
echo ""
|
||||||
|
echo "Stream will be available at the url: rtmp://RASPBERRY_IP/live/STREAM_NAME"
|
||||||
|
echo "Use VLC or similar to test it out."
|
||||||
|
echo ""
|
||||||
|
echo "To set up a HTTP page with the stream, see:"
|
||||||
|
echo "https://github.com/Tomtomgo/raspberry_livestream"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "*** all done ***"
|
||||||
|
echo ""
|
||||||
|
echo "here is this machine's network info:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if ip a | grep -Eq ': eth0:.*state UP'; then
|
||||||
|
eth_ip=$(ip addr | awk '/inet/ && /eth0/{sub(/\/.*$/,"",$2); print $2}')
|
||||||
|
eth_mac=`ifconfig eth0 | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
|
||||||
|
echo "ethernet: IP=$eth_ip MAC=$eth_mac"
|
||||||
|
fi
|
||||||
|
if ip a | grep -Eq ': wlan0:.*state UP'; then
|
||||||
|
wifi_ip=$(ip addr | awk '/inet/ && /wlan0/{sub(/\/.*$/,"",$2); print $2}')
|
||||||
|
wifi_mac=`ifconfig wlan0 | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'`
|
||||||
|
echo " wifi: IP=$wifi_ip MAC=$wifi_mac"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "*** Reboot your Pi to ensure that all installed software comes up as expected."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
exit 0
|
77
setup_smb
Executable file
|
@ -0,0 +1,77 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ ! -d /smb ]; then
|
||||||
|
sudo mkdir /smb
|
||||||
|
sudo chown pi:pi /smb
|
||||||
|
fi
|
||||||
|
|
||||||
|
if mount -l | grep -q \/smb; then
|
||||||
|
sudo umount /smb
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "\/smb" /etc/fstab; then
|
||||||
|
sudo sed -i '/\/smb/d' /etc/fstab
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Are you mounting a public (passwordless) share? [yn] "
|
||||||
|
read PUBLIC
|
||||||
|
|
||||||
|
echo -n "Enter the hostname or IP address of your file server: "
|
||||||
|
read HOST
|
||||||
|
|
||||||
|
echo -n "Is this a Mac OS X machine? [yn] "
|
||||||
|
read MAC
|
||||||
|
if [ "$MAC" = "y" ]; then
|
||||||
|
EXTRA=",sec=ntlmssp,nounix"
|
||||||
|
else
|
||||||
|
EXTRA=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Enter the file share you wish to mount: "
|
||||||
|
read SHARE
|
||||||
|
|
||||||
|
if [ "$PUBLIC" = "y" ]; then
|
||||||
|
sudo sed -i.bak -e "\$a\
|
||||||
|
//$HOST/$SHARE /smb cifs guest,uid=1000,gid=1000,iocharset=utf8$EXTRA 0 0" /etc/fstab
|
||||||
|
else
|
||||||
|
echo -n "Enter the username to login as: "
|
||||||
|
read USER
|
||||||
|
|
||||||
|
PASSWORD="foo"
|
||||||
|
PASSWORD_TEMP="bar"
|
||||||
|
stty -echo
|
||||||
|
while [ "$PASSWORD" != "$PASSWORD_TEMP" ]; do
|
||||||
|
echo -n "Enter password: "
|
||||||
|
read PASSWORD
|
||||||
|
echo
|
||||||
|
echo -n "Re-enter for verification: "
|
||||||
|
read PASSWORD_TEMP
|
||||||
|
echo
|
||||||
|
if [ "$PASSWORD" != "$PASSWORD_TEMP" ]; then
|
||||||
|
echo "Error: passwords do not match"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
stty echo
|
||||||
|
|
||||||
|
(echo "username=$USER"
|
||||||
|
echo "password=$PASSWORD") > /tmp/smb.$$
|
||||||
|
|
||||||
|
sudo cp /tmp/smb.$$ /etc/smb_credentials
|
||||||
|
sudo chown root:root /etc/smb_credentials
|
||||||
|
sudo chmod 600 /etc/smb_credentials
|
||||||
|
rm -f /tmp/smb.**
|
||||||
|
|
||||||
|
sudo sed -i.bak -e "\$a\
|
||||||
|
//$HOST/$SHARE /smb cifs credentials=/etc/smb_credentials,uid=1000,gid=1000,iocharset=utf8$EXTRA 0 0" /etc/fstab
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Attempting to mount the filesystem..."
|
||||||
|
sudo mount /smb
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Success."
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Error: unable to mount. Please try running this script again, and ensure"
|
||||||
|
echo "that you typed in all values (hostname, user/pass, etc.) correctly."
|
||||||
|
exit 1
|
||||||
|
fi
|
55
setup_wifi
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Raspberry Pi Setup Script
|
||||||
|
# Donald Burr <dburr@vctlabs.com>
|
||||||
|
|
||||||
|
D="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
if grep -q raspberrypi /etc/hostname; then
|
||||||
|
echo "You still have the default hostname set."
|
||||||
|
echo "If you wish to change it, enter a new hostname now, otherwise"
|
||||||
|
echo -n "just press Return: "
|
||||||
|
read NEW_HOSTNAME
|
||||||
|
if [ ! -z "$NEW_HOSTNAME" ]; then
|
||||||
|
echo "$NEW_HOSTNAME" > /tmp/HOSTNAME.$$
|
||||||
|
sudo rm -f /etc/hostname
|
||||||
|
sudo mv /tmp/HOSTNAME.$$ /etc/hostname
|
||||||
|
sudo chown root:root /etc/hostname
|
||||||
|
sudo chmod 644 /etc/hostname
|
||||||
|
sudo /etc/init.d/hostname.sh
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Enter your wireless network's SSID: "
|
||||||
|
read SSID
|
||||||
|
PASSWORD="foo"
|
||||||
|
PASSWORD_TEMP="bar"
|
||||||
|
stty -echo
|
||||||
|
while [ "$PASSWORD" != "$PASSWORD_TEMP" ]; do
|
||||||
|
echo -n "Enter your wireless network's password (WPA/WPA2 only): "
|
||||||
|
read PASSWORD
|
||||||
|
echo
|
||||||
|
echo -n "Re-enter for verification: "
|
||||||
|
read PASSWORD_TEMP
|
||||||
|
echo
|
||||||
|
if [ "$PASSWORD" != "$PASSWORD_TEMP" ]; then
|
||||||
|
echo "Error: passwords do not match"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
stty echo
|
||||||
|
if [ -f /etc/network/interfaces ]; then
|
||||||
|
sudo mv -f /etc/network/interfaces /etc/network/interfaces.bak
|
||||||
|
fi
|
||||||
|
sudo cp $D/configs/wifi/interfaces /etc/network/interfaces
|
||||||
|
sudo chown root:root /etc/network/interfaces
|
||||||
|
sudo chmod 644 /etc/network/interfaces
|
||||||
|
if [ -f /etc/wpa_supplicant/wpa_supplicant.conf ]; then
|
||||||
|
sudo mv -f /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf.bak
|
||||||
|
fi
|
||||||
|
sudo cp $D/configs/wifi/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
sudo sed -i.sed.bak -e "s/#SSID#/$SSID/g" -e "s/#PASSWORD#/$PASSWORD/g" /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
sudo chown root:root /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
echo "*** attempting to bring up wifi... ***"
|
||||||
|
sudo ifdown wlan0
|
||||||
|
sudo ifup wlan0
|
15
sync_osss_files
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
if [ ! -f /var/log/rsync.log ]; then
|
||||||
|
sudo touch /var/log/rsync.log
|
||||||
|
sudo chown pi:pi /var/log/rsync.log
|
||||||
|
fi
|
||||||
|
echo "### rsync begin at `date`" >> /var/log/rsync.log
|
||||||
|
if mount -l | grep -q \/smb; then
|
||||||
|
if [ ! -d /smb/`hostname` ]; then
|
||||||
|
mkdir -p /smb/`hostname`
|
||||||
|
fi
|
||||||
|
rsync -avs /var/spool/motion/ /smb/`hostname`/ >> /var/log/rsync.log 2>&1
|
||||||
|
else
|
||||||
|
echo "### error: filesystem is not mounted" >> /var/log/rsync.log
|
||||||
|
fi
|
||||||
|
echo "### rsync end at `date`" >> /var/log/rsync.log
|