Merge branch 'master' into zma_to_thread
This commit is contained in:
commit
a1917d83d0
|
@ -44,10 +44,7 @@ New installs
|
|||
|
||||
5. Disable SELinux
|
||||
|
||||
We currently do not have the resources to create and maintain an accurate
|
||||
SELinux policy for ZoneMinder on Fedora. We will gladly accept pull
|
||||
reqeusts from anyone who wishes to do the work. In the meantime, SELinux
|
||||
will need to be disabled or put into permissive mode.
|
||||
SELinux must be disabled or put into permissive mode. This is not optional!
|
||||
|
||||
To immediately disbale SELinux for the current seesion, issue the following
|
||||
from the command line:
|
||||
|
@ -78,11 +75,20 @@ New installs
|
|||
sudo ln -sf /etc/zm/www/zoneminder.nginx.conf /etc/nginx/conf.d/
|
||||
sudo ln -sf /etc/zm/www/redirect.nginx.conf /etc/nginx/default.d/
|
||||
|
||||
7. Edit /etc/sysconfig/fcgiwrap and set DAEMON_PROCS to the maximum number of
|
||||
7. Configure and start fcgiwrap
|
||||
|
||||
Edit /etc/sysconfig/fcgiwrap and set DAEMON_PROCS to the maximum number of
|
||||
simulatneous streams the server should support. Generally, a good minimum
|
||||
value for this equals the total number of cameras you expect to view at the
|
||||
same time.
|
||||
|
||||
Enable the fcgiwrap *socket* in the following manner:
|
||||
|
||||
sudo systemctl enable --now fcgiwrap@nginx.socket
|
||||
|
||||
Do NOT try to start the fcgiwrap service! It must be triggered by the
|
||||
socket to work properly.
|
||||
|
||||
8. Now start the web server:
|
||||
|
||||
sudo systemctl enable nginx
|
||||
|
|
|
@ -298,7 +298,7 @@ if [ -f %{sslkey} -o -f %{sslcert} ]; then
|
|||
fi
|
||||
|
||||
umask 077
|
||||
%{_bindir}/openssl genrsa -rand /proc/apm:/proc/cpuinfo:/proc/dma:/proc/filesystems:/proc/interrupts:/proc/ioports:/proc/pci:/proc/rtc:/proc/uptime 2048 > %{sslkey} 2> /dev/null
|
||||
%{_bindir}/openssl genrsa -rand /proc/cpuinfo:/proc/filesystems:/proc/interrupts:/proc/ioports:/proc/uptime 2048 > %{sslkey} 2> /dev/null
|
||||
|
||||
FQDN=`hostname`
|
||||
# A >59 char FQDN means "root@FQDN" exceeds 64-char max length for emailAddress
|
||||
|
|
|
@ -12,9 +12,7 @@ if [ "$1" = "configure" ]; then
|
|||
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
|
||||
chown www-data:root /var/log/zm
|
||||
chown www-data:www-data /var/lib/zm
|
||||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
fi
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then
|
||||
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
|
||||
a2enmod cgi
|
||||
|
|
|
@ -49,9 +49,7 @@ if [ "$1" = "configure" ]; then
|
|||
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
|
||||
chown www-data:root /var/log/zm
|
||||
chown www-data:www-data /var/lib/zm
|
||||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
fi
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ] && [ "$(command -v a2enmod)" != "" ]; then
|
||||
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
|
||||
a2enmod cgi
|
||||
|
|
|
@ -21,6 +21,10 @@ New installs
|
|||
|
||||
1. Follow the normal instructions for your distro for installing ZoneMinder onto all the ZoneMinder servers in the normal fashion. Only a single database will be needed either as standalone, or on one of the ZoneMinder Servers.
|
||||
|
||||
.. sidebar :: Note
|
||||
|
||||
For systemd based linux distros, inspect the zoneminder service file, typically found under /lib/systemd/system. Changes may be required for multiserver to function correctly. For example, the service file may check for a running instance of mysql or mariadb running locally on the server. This check will need to be removed. Rather than edit the service file directly, copy the service file to /etc/systemd/system and edit the file in that location.
|
||||
|
||||
2. On each ZoneMinder server, edit zm.conf. Find the ZM_DB_HOST variable and set it to the name or ip address of your Database Server. Find the ZM_SERVER_HOST and enter a name for this ZoneMinder server. Use a name easily recognizable by you. This name is not used by ZoneMinder for dns or any other form of network conectivity.
|
||||
|
||||
3. Copy the file /usr/share/zoneminder/db/zm_create.sql from one of the ZoneMinder Servers to the machine targeted as the Database Server.
|
||||
|
@ -46,7 +50,9 @@ Note that these commands are just an example and might not be secure enough for
|
|||
|
||||
9. From each ZoneMinder Server, mount the shared events folder on the Storage Server to the events folder on the local ZoneMinder Server.
|
||||
|
||||
NOTE: The location of this folder varies by distro. This folder is often found under "/var/lib/zoneminder/events" for RedHat based distros and "/var/cache/zoneminder/events" for Debain based distros. This folder is NOT a Symbolic Link!
|
||||
.. sidebar :: Note
|
||||
|
||||
The location of the ZoneMinder events folder varies by distro. This folder is often found under "/var/lib/zoneminder/events" for RedHat based distros and "/var/cache/zoneminder/events" for Debain based distros. This folder is NOT a Symbolic Link!
|
||||
|
||||
10. Open your browser and point it to the web console on any of the ZoneMinder Servers (they will all be the same). Open Options, click the Servers tab,and populate this screen with all of your ZoneMinder Servers. Each server has a field for its name and its hostname. The name is what you used for ZM_SERVER_HOST in step 2. The hostname is the network name or ip address ZoneMinder should use.
|
||||
|
||||
|
|
|
@ -45,15 +45,47 @@ The following notes are based on real problems which have occurred by those who
|
|||
How to Install ZoneMinder
|
||||
-------------------------
|
||||
|
||||
ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site <https://rpmfusion.org>`__ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site <https://fedoraproject.org/wiki/EPEL>`_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline:
|
||||
ZoneMinder releases are hosted at RPM Fusion. New users should navigate to the `RPM Fusion site <https://rpmfusion.org>`__ then follow the instructions to enable that repo.
|
||||
|
||||
.. sidebar :: Note
|
||||
|
||||
RHEL/CentOS 7 users should use *yum* instead of *dnf*
|
||||
|
||||
RHEL/CentOS 7 & 8 users must enable the EPEL repo:
|
||||
|
||||
::
|
||||
|
||||
sudo dnf install zoneminder
|
||||
sudo dnf install epel-release
|
||||
|
||||
Note that RHEL/CentOS 7 users should use yum instead of dnf.
|
||||
RHEL/CentOS 8 users must also enable the PowerTools repo:
|
||||
|
||||
Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder-common. ZoneMinder will not run without completing the steps outlined in the README.
|
||||
::
|
||||
|
||||
sudo dnf install dnf-plugins-core
|
||||
sudo dnf config-manager --set-enabled PowerTools
|
||||
|
||||
Once the additional repos are enabled, install ZoneMinder from the commandline. Choose the package that matches the desired web server.
|
||||
|
||||
Install ZoneMinder for Apache web server:
|
||||
|
||||
.. sidebar :: Note
|
||||
|
||||
A virtual package called zoneminder exists. This package contains no files and will pull in the zoneminder-httpd package for backwards compatiblity.
|
||||
|
||||
::
|
||||
|
||||
sudo dnf install zoneminder-httpd
|
||||
|
||||
Install ZoneMinder for Nginx web server:
|
||||
|
||||
::
|
||||
|
||||
sudo dnf install zoneminder-nginx
|
||||
|
||||
|
|
||||
Once ZoneMinder has been installed, you must read the README file to complete the installation. Fedora users can find the README under /usr/share/doc/zoneminder-common. RHEL/CentOS users can find the README under /usr/share/doc/zoneminder-common-x.xx where x.xx is the version of zoneminder.
|
||||
|
||||
ZoneMinder will *NOT* run without completing the steps shown in the README!
|
||||
|
||||
How to Install Nightly Development Builds
|
||||
-----------------------------------------
|
||||
|
@ -62,21 +94,6 @@ ZoneMinder development packages, which represent the most recent build from our
|
|||
|
||||
The feedback we get from those who use these development packages is extremely helpful. However, please understand these packages are intended for testing the latest master branch only. They are not intended to be used on any production system. There will be new bugs, and new features may not be documented. This is bleeding edge, and there might be breakage. Please keep that in mind when using this repo. We know from our user forum that this can't be stated enough.
|
||||
|
||||
How to Change from Zmrepo to RPM Fusion
|
||||
---------------------------------------
|
||||
|
||||
As mentioned above, the place to get the latest ZoneMinder release is now `RPM Fusion <https://rpmfusion.org>`__. If you are currently using ZoneMinder release packages from Zmrepo, then the following steps will change you over to RPM Fusion:
|
||||
|
||||
- Navigate to the `RPM Fusion site <https://rpmfusion.org>`__ and enable RPM Fusion on your system
|
||||
- Now issue the following from the command line:
|
||||
|
||||
::
|
||||
|
||||
sudo dnf remove zmrepo
|
||||
sudo dnf update
|
||||
|
||||
Note that RHEL/CentOS 7 users should use yum instead of dnf.
|
||||
|
||||
How to Build Your Own ZoneMinder Package
|
||||
------------------------------------------
|
||||
|
||||
|
|
|
@ -337,7 +337,7 @@ Monitor::Monitor()
|
|||
event(nullptr),
|
||||
n_zones(0),
|
||||
zones(nullptr),
|
||||
timestamps(0),
|
||||
timestamps(nullptr),
|
||||
images(nullptr),
|
||||
privacy_bitmask(nullptr),
|
||||
event_delete_thread(nullptr),
|
||||
|
@ -2437,14 +2437,13 @@ int Monitor::Capture() {
|
|||
|
||||
// Analysis thread will take care of consuming and emptying the packets.
|
||||
Debug(2, "Have packet stream_index:%d ?= videostream_id:(%d) q.vpktcount(%d) event?(%d) ",
|
||||
packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) );
|
||||
packet->packet.stream_index, video_stream_id, packetqueue->packet_count(video_stream_id), ( event ? 1 : 0 ) );
|
||||
|
||||
if ( packet->packet.stream_index != video_stream_id ) {
|
||||
//Debug(2, "Have audio packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ",
|
||||
// packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) );
|
||||
// Only queue if we have some video packets in there. Should push this logic into packetqueue
|
||||
//mutex.lock();
|
||||
if ( packetqueue->video_packet_count || event ) {
|
||||
if ( packetqueue->packet_count(video_stream_id) or event ) {
|
||||
// Need to copy it into another ZMPacket.
|
||||
ZMPacket *audio_packet = new ZMPacket(*packet);
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
|
@ -2487,11 +2486,11 @@ int Monitor::Capture() {
|
|||
}
|
||||
}
|
||||
|
||||
if ( packetqueue->video_packet_count || packet->keyframe || event ) {
|
||||
if ( packetqueue->packet_count(video_stream_id) or packet->keyframe or event ) {
|
||||
Debug(2, "Have video packet for index (%d), adding to queue", index);
|
||||
packetqueue->queuePacket(packet);
|
||||
} else {
|
||||
Debug(2, "Not queuing video packet for index (%d) packet count %d", index, packetqueue->video_packet_count);
|
||||
Debug(2, "Not queuing video packet for index (%d) packet count %d", index, packetqueue->packet_count(video_stream_id));
|
||||
}
|
||||
|
||||
/* Deinterlacing */
|
||||
|
|
|
@ -34,7 +34,6 @@ video_stream_id(p_video_stream_id),
|
|||
video_stream_id = p_video_stream_id;
|
||||
max_video_packet_count = video_image_count-1;
|
||||
analysis_it = pktQueue.begin();
|
||||
first_video_packet_index = -1;
|
||||
|
||||
max_stream_id = p_video_stream_id > p_audio_stream_id ? p_video_stream_id : p_audio_stream_id;
|
||||
packet_counts = new int[max_stream_id+1];
|
||||
|
@ -75,9 +74,8 @@ zm_packetqueue::~zm_packetqueue() {
|
|||
*/
|
||||
|
||||
bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
|
||||
Debug(4, "packetqueue queuepacket, first_video_packet_index is %d", first_video_packet_index);
|
||||
Debug(4, "packetqueue queuepacket");
|
||||
mutex.lock();
|
||||
Debug(4, "packetqueue queuepacket, have lock first_video_packet_index is %d", first_video_packet_index);
|
||||
|
||||
pktQueue.push_back(zm_packet);
|
||||
packet_counts[zm_packet->packet.stream_index] += 1;
|
||||
|
@ -94,10 +92,16 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
|
|||
|
||||
// We have added to the queue and signalled so other processes can now work on the new packet.
|
||||
// Now to clean ups mainting the queue size.
|
||||
if ( packet_counts[video_stream_id] >= max_video_packet_count ) {
|
||||
while ( packet_counts[video_stream_id] > max_video_packet_count ) {
|
||||
//clearQueue(max_video_packet_count, video_stream_id);
|
||||
//clearQueue is rather heavy. Since this is the only packet injection spot, we can just start at the beginning of the queue and remove packets until we get to the next video keyframe
|
||||
|
||||
Debug(1, "Deleting a packet with stream index (%d) with keyframe(%d), Image_index(%d) video_frames_to_keep is (%d) max: %d",
|
||||
zm_packet->packet.stream_index, zm_packet->keyframe, zm_packet->image_index, packet_counts[video_stream_id] , max_video_packet_count);
|
||||
ZMPacket *zm_packet = *pktQueue.begin();
|
||||
pktQueue.pop_front();
|
||||
packet_counts[zm_packet->packet.stream_index] -= 1;
|
||||
if ( zm_packet->image_index == -1 )
|
||||
delete zm_packet;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -309,8 +313,6 @@ void zm_packetqueue::clearQueue() {
|
|||
delete_count += 1;
|
||||
}
|
||||
Debug(3, "Deleted (%d) packets", delete_count );
|
||||
video_packet_count = 0;
|
||||
first_video_packet_index = -1;
|
||||
analysis_it = pktQueue.begin();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
@ -401,10 +403,6 @@ unsigned int zm_packetqueue::size() {
|
|||
return pktQueue.size();
|
||||
}
|
||||
|
||||
unsigned int zm_packetqueue::get_video_packet_count() {
|
||||
return video_packet_count;
|
||||
}
|
||||
|
||||
int zm_packetqueue::packet_count( int stream_id ) {
|
||||
return packet_counts[stream_id];
|
||||
} // end int zm_packetqueue::packet_count( int stream_id )
|
||||
|
|
|
@ -38,8 +38,6 @@ class zm_packetqueue {
|
|||
std::list<ZMPacket *>::iterator analysis_it;
|
||||
|
||||
int video_stream_id;
|
||||
int video_packet_count; // keep track of how many video packets we have, because we shouldn't have more than image_buffer_count
|
||||
int first_video_packet_index;
|
||||
int max_video_packet_count; // allow a negative value to someday mean unlimited
|
||||
int max_stream_id;
|
||||
int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */
|
||||
|
@ -61,7 +59,7 @@ class zm_packetqueue {
|
|||
void clearQueue();
|
||||
void dumpQueue();
|
||||
unsigned int size();
|
||||
unsigned int get_video_packet_count();
|
||||
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
||||
|
||||
void clear_unwanted_packets(timeval *recording, int pre_event_count, int mVideoStreamId);
|
||||
int packet_count(int stream_id);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
// This is the HTML representing the Object Detection modal on the Events page
|
||||
|
||||
$eid = isset($_REQUEST['eid']) ? $_REQUEST['eid'] : '';
|
||||
|
||||
if ( !validInt($eid) ) {
|
||||
ZM\Error("Invalid event id: $eid");
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<div id="objdetectModal" class="modal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Object Detection</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<img src="?view=image&eid=<?php echo $eid ?>&fid=objdetect">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -109,7 +109,7 @@ class Monitor extends ZM_Object {
|
|||
'ReturnLocation' => -1,
|
||||
'ReturnDelay' => null,
|
||||
'DefaultRate' => 100,
|
||||
'DefaultScale' => 100,
|
||||
'DefaultScale' => 0,
|
||||
'SignalCheckPoints' => 0,
|
||||
'SignalCheckColour' => '#0000BE',
|
||||
'WebColour' => '#ff0000',
|
||||
|
|
|
@ -741,6 +741,11 @@ a.flip {
|
|||
float: right;
|
||||
margin-right: -20px;
|
||||
}
|
||||
|
||||
#content table.major .colDiskSpace {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#objdetectModal .modal-content {
|
||||
width: fit-content;
|
||||
}
|
||||
|
|
|
@ -66,10 +66,6 @@ function editMonitor( element ) {
|
|||
form.elements[i].checked
|
||||
) {
|
||||
monitorIds.push( form.elements[i].value );
|
||||
//form.elements[i].checked = false;
|
||||
//setButtonStates( form.elements[i] );
|
||||
//$(form.elements[i]).getParent( 'tr' ).removeClass( 'highlight' );
|
||||
//break;
|
||||
}
|
||||
} // end foreach checkboxes
|
||||
if ( monitorIds.length == 1 ) {
|
||||
|
@ -209,13 +205,10 @@ function initPage() {
|
|||
|
||||
function applySort(event, ui) {
|
||||
var monitor_ids = $j(this).sortable('toArray');
|
||||
var ajax = new Request.JSON( {
|
||||
url: 'index.php?request=console',
|
||||
data: {monitor_ids: monitor_ids, action: 'sort'},
|
||||
method: 'post',
|
||||
timeout: AJAX_TIMEOUT
|
||||
} );
|
||||
ajax.send();
|
||||
var data = {monitor_ids: monitor_ids, action: 'sort'};
|
||||
|
||||
$j.getJSON(thisUrl + '?request=console', data)
|
||||
.fail(logAjaxFail);
|
||||
} // end function applySort(event,ui)
|
||||
|
||||
$j(document).ready(initPage );
|
||||
|
|
|
@ -1,46 +1,56 @@
|
|||
var controlParms = "view=request&request=control";
|
||||
var controlReq = new Request.JSON( {url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, onSuccess: getControlResponse} );
|
||||
var form = $j('#controlForm');
|
||||
|
||||
function getControlResponse( respObj, respText ) {
|
||||
function controlReq(data) {
|
||||
$j.getJSON(thisUrl + '?view=request&request=control', data)
|
||||
.done(getControlResponse)
|
||||
.fail(logAjaxFail);
|
||||
}
|
||||
|
||||
function getControlResponse(respObj, respText) {
|
||||
if ( !respObj ) {
|
||||
return;
|
||||
}
|
||||
//console.log( respText );
|
||||
if ( respObj.result != 'Ok' ) {
|
||||
alert( "Control response was status = "+respObj.status+"\nmessage = "+respObj.message );
|
||||
alert("Control response was status = "+respObj.status+"\nmessage = "+respObj.message);
|
||||
}
|
||||
}
|
||||
|
||||
function controlCmd( control, event, xtell, ytell ) {
|
||||
var locParms = "&id="+$('mid').get('value');
|
||||
if ( event && (xtell || ytell) ) {
|
||||
var target = event.target;
|
||||
var coords = $(target).getCoordinates();
|
||||
var mid = $j('#mid').getAttribute('value');
|
||||
|
||||
var x = event.pageX - coords.left;
|
||||
var y = event.pageY - coords.top;
|
||||
if ( event && (xtell || ytell) ) {
|
||||
var data = {};
|
||||
var target = $j(event.target);
|
||||
var offset = target.offset();
|
||||
var width = target.width();
|
||||
var height = target.height();
|
||||
|
||||
var x = event.pageX - offset.left;
|
||||
var y = event.pageY - offset.top;
|
||||
|
||||
if ( xtell ) {
|
||||
var xge = parseInt( (x*100)/coords.width );
|
||||
var xge = parseInt( (x*100)/width );
|
||||
if ( xtell == -1 ) {
|
||||
xge = 100 - xge;
|
||||
} else if ( xtell == 2 ) {
|
||||
xge = 2*(50 - xge);
|
||||
}
|
||||
locParms += "&xge="+xge;
|
||||
data.xge = xge;
|
||||
}
|
||||
if ( ytell ) {
|
||||
var yge = parseInt( (y*100)/coords.height );
|
||||
var yge = parseInt( (y*100)/height );
|
||||
if ( ytell == -1 ) {
|
||||
yge = 100 - yge;
|
||||
} else if ( ytell == 2 ) {
|
||||
yge = 2*(50 - yge);
|
||||
}
|
||||
locParms += "&yge="+yge;
|
||||
data.yge = yge;
|
||||
}
|
||||
}
|
||||
controlReq.send( controlParms+"&control="+control+locParms );
|
||||
data.id = mid;
|
||||
data.control = control;
|
||||
controlReq(data);
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
|
|
|
@ -61,7 +61,7 @@ function processRows(rows) {
|
|||
if ( canEdit.Monitors ) row.Monitor = '<a href="?view=monitor&mid=' + mid + '">' + row.Monitor + '</a>';
|
||||
if ( canEdit.Events ) row.Cause = '<a href="#" title="' + row.Notes + '" class="eDetailLink" data-eid="' + eid + '">' + row.Cause + '</a>';
|
||||
if ( row.Notes.indexOf('detected:') >= 0 ) {
|
||||
row.Cause = row.Cause + '<a href="?view=image&eid=' + eid + '&fid=objdetect"><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></a>';
|
||||
row.Cause = row.Cause + '<a href="#" data-on-click-this="objdetectModal" data-event-id=' +eid+ '><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></div></a>';
|
||||
} else if ( row.Notes != 'Forced Web: ' ) {
|
||||
row.Cause = row.Cause + '<br/><div class="small text-nowrap text-muted">' + row.Notes + '</div>';
|
||||
}
|
||||
|
@ -141,6 +141,17 @@ function getEventDetailModal(eid) {
|
|||
.fail(logAjaxFail);
|
||||
}
|
||||
|
||||
function objdetectModal( element ) {
|
||||
var eid = element.getAttribute('data-event-id');
|
||||
|
||||
$j.getJSON(thisUrl + '?request=modal&modal=objdetect&eid=' + eid)
|
||||
.done(function(data) {
|
||||
insertModalHtml('objdetectModal', data.html);
|
||||
$j('#objdetectModal').modal('show');
|
||||
})
|
||||
.fail(logAjaxFail);
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
// Remove the thumbnail column from the DOM if thumbnails are off globally
|
||||
if ( !WEB_LIST_THUMBS ) $j('th[data-field="Thumbnail"]').remove();
|
||||
|
@ -303,6 +314,8 @@ function initPage() {
|
|||
|
||||
// Update table links each time after new data is loaded
|
||||
table.on('post-body.bs.table', function(data) {
|
||||
// Object detection inserts data-onclick-this links after DOM has loaded
|
||||
dataOnClickThis();
|
||||
// Manage the eventdetail links in the events list
|
||||
$j(".eDetailLink").click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
|
|
@ -46,7 +46,7 @@ function exportResponse(respObj, respText) {
|
|||
$j('#exportProgressTicker').text(respObj.message);
|
||||
} else {
|
||||
$j('#exportProgressTicker').text(exportSucceededString);
|
||||
startDownload.pass(decodeURIComponent(respObj.exportFile)).delay(1500);
|
||||
setTimeout(startDownload, 1500, decodeURIComponent(respObj.exportFile));
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -64,16 +64,16 @@ function exportResponse(respObj, respText) {
|
|||
}
|
||||
|
||||
function exportEvents( ) {
|
||||
var query = new Request.JSON( {
|
||||
url: '?view=event&request=event&action=export',
|
||||
method: 'post',
|
||||
data: $('contentForm').toQueryString(),
|
||||
onSuccess: exportResponse
|
||||
} );
|
||||
query.send();
|
||||
$('exportProgress').removeClass('hidden');
|
||||
$('exportProgress').setProperty('class', 'warnText');
|
||||
$('exportProgressText').set('text', exportProgressString);
|
||||
var formData = $j('#contentForm').serialize();
|
||||
|
||||
$j.getJSON(thisUrl + '?view=event&request=event&action=export', formData)
|
||||
.done(exportResponse)
|
||||
.fail(logAjaxFail);
|
||||
|
||||
$j('#exportProgress').removeClass('hidden');
|
||||
$j('#exportProgress').addClass('warnText');
|
||||
$j('#exportProgress').text(exportProgressString);
|
||||
|
||||
//exportProgress();
|
||||
exportTimer = exportProgress.periodical( 500 );
|
||||
}
|
||||
|
@ -93,9 +93,9 @@ function getEventDetailModal(eid) {
|
|||
}
|
||||
|
||||
function initPage() {
|
||||
configureExportButton( $('exportButton') );
|
||||
configureExportButton(this);
|
||||
if ( exportReady ) {
|
||||
startDownload.pass(exportFile).delay(1500);
|
||||
setTimeout(startDownload, 1500, exportFile);
|
||||
}
|
||||
document.getElementById('exportButton').addEventListener('click', exportEvents);
|
||||
|
||||
|
|
|
@ -295,11 +295,11 @@ function parseRows(rows) {
|
|||
inputTds.eq(4).html(storageSelect).children().val(storageVal).chosen({width: "101%"});
|
||||
} else if ( attr == 'MonitorName' ) { //Monitor names
|
||||
var monitorSelect = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
|
||||
for ( var monitor_id in monitors ) {
|
||||
sorted_monitor_ids.forEach(function(monitor_id) {
|
||||
monitorSelect.append('<option value="' + monitors[monitor_id].Name + '">' + escapeHTML(monitors[monitor_id].Name) + '</option>');
|
||||
}
|
||||
});
|
||||
var monitorVal = inputTds.eq(4).children().val();
|
||||
inputTds.eq(4).html(monitorSelect).children().val(monitorVal);
|
||||
inputTds.eq(4).html(monitorSelect).children().val(monitorVal).chosen({width: '101%'});
|
||||
} else if ( attr == 'ExistsInFileSystem' ) {
|
||||
var select = $j('<select></select>').attr('name', queryPrefix + rowNum + '][val]').attr('id', queryPrefix + rowNum + '][val]');
|
||||
for ( var booleanVal in booleanValues ) {
|
||||
|
|
|
@ -22,11 +22,12 @@ var opTypes = <?php echo isset($opTypes) ? json_encode($opTypes) : '' ?>;
|
|||
|
||||
var archiveTypes = <?php echo isset($archiveTypes) ? json_encode($archiveTypes) : '' ?>;
|
||||
var weekdays = <?php echo isset($weekdays) ? json_encode($weekdays) : '' ?>;
|
||||
var states = <?php echo isset($states) ? json_encode($states) : '' ?>;
|
||||
var servers = <?php echo isset($servers) ? json_encode($servers) : '' ?>;
|
||||
var storageareas = <?php echo isset($storageareas) ? json_encode($storageareas) : '' ?>;
|
||||
var monitors = <?php echo isset($monitors) ? json_encode($monitors) : '' ?>;
|
||||
var zones = <?php echo isset($zones) ? json_encode($zones) : '' ?>;
|
||||
var states = <?php echo isset($states) ? json_encode($states) : '{}' ?>;
|
||||
var servers = <?php echo isset($servers) ? json_encode($servers) : '{}' ?>;
|
||||
var storageareas = <?php echo isset($storageareas) ? json_encode($storageareas) : '{}' ?>;
|
||||
var monitors = <?php echo isset($monitors) ? json_encode($monitors) : '{}' ?>;
|
||||
var sorted_monitor_ids = <?php echo isset($monitors) ? json_encode(array_keys($monitors)) : '[]' ?>;
|
||||
var zones = <?php echo isset($zones) ? json_encode($zones) : '{}' ?>;
|
||||
var booleanValues = <?php echo json_encode($booleanValues) ?>;
|
||||
|
||||
var errorBrackets = '<?php echo translate('ErrorBrackets') ?>';
|
||||
|
|
|
@ -6,45 +6,33 @@ function showEvent(e) {
|
|||
var url = '?view=event&eid='+eid+'&fid='+fid;
|
||||
url += filterQuery;
|
||||
window.location.href = url;
|
||||
|
||||
//video element is blocking video elements elsewhere in chrome possible interaction with mouseover event?
|
||||
//FIXME unless an exact cause can be determined should store all video controls and do something to the other controls when we want to load a new video seek etc or whatever may block
|
||||
/*var vid= $('preview');
|
||||
vid.oncanplay=null;
|
||||
// vid.currentTime=vid.currentTime-0.1;
|
||||
vid.pause();*/
|
||||
}
|
||||
|
||||
function createEventHtml(zm_event, frame) {
|
||||
var eventHtml = new Element('div');
|
||||
var div = $j('<div>');
|
||||
|
||||
if ( zm_event.Archived > 0 ) {
|
||||
eventHtml.addClass('archived');
|
||||
}
|
||||
if ( zm_event.Archived ) div.addClass('archived');
|
||||
|
||||
new Element('p').inject(eventHtml).set('text', monitors[zm_event.MonitorId].Name);
|
||||
new Element('p').inject(eventHtml).set('text', zm_event.Name+(frame?('('+frame.FrameId+')'):''));
|
||||
new Element('p').inject(eventHtml).set('text', zm_event.StartDateTime+' - '+zm_event.Length+'s');
|
||||
new Element('p').inject(eventHtml).set('text', zm_event.Cause);
|
||||
if ( zm_event.Notes ) {
|
||||
new Element('p').inject(eventHtml).set('text', zm_event.Notes);
|
||||
}
|
||||
if ( zm_event.Archived > 0 ) {
|
||||
new Element('p').inject(eventHtml).set( 'text', archivedString);
|
||||
}
|
||||
var mName = $j('<p>').text(monitors[zm_event.MonitorId].Name);
|
||||
var mEvent = $j('<p>').text(zm_event.Name+(frame?('('+frame.FrameId+')'):''));
|
||||
var mDateTime = $j('<p>').text(zm_event.StartDateTime+' - '+zm_event.Length+'s');
|
||||
var mCause = $j('<p>').text(zm_event.Cause);
|
||||
var mNotes = zm_event.Notes ? $j('<p>').text(zm_event.Notes) : '';
|
||||
var mArchived = zm_event.Archived ? $j('<p>').text(archivedString) : '';
|
||||
|
||||
return eventHtml;
|
||||
var data = div.append(mName, mEvent, mDateTime, mCause, mNotes, mArchived);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function showEventDetail(eventHtml) {
|
||||
$('instruction').addClass('hidden');
|
||||
$('eventData').empty();
|
||||
$('eventData').adopt(eventHtml);
|
||||
$('eventData').removeClass('hidden');
|
||||
$j('#instruction').addClass('hidden');
|
||||
$j('#eventData').empty().append(eventHtml).removeClass('Hidden');
|
||||
}
|
||||
|
||||
function eventDataResponse(respObj, respText) {
|
||||
var zm_event = respObj.event;
|
||||
|
||||
if ( !zm_event ) {
|
||||
console.log('Null event');
|
||||
return;
|
||||
|
@ -103,29 +91,28 @@ function showEventData(eventId, frameId) {
|
|||
}
|
||||
}
|
||||
|
||||
var eventQuery = new Request.JSON({
|
||||
url: thisUrl,
|
||||
method: 'get',
|
||||
timeout: AJAX_TIMEOUT,
|
||||
link: 'cancel',
|
||||
onSuccess: eventDataResponse
|
||||
});
|
||||
function eventQuery(data) {
|
||||
$j.getJSON(thisUrl + '?view=request&request=status&entity=event', data)
|
||||
.done(eventDataResponse)
|
||||
.fail(logAjaxFail);
|
||||
}
|
||||
|
||||
var frameQuery = new Request.JSON({
|
||||
url: thisUrl,
|
||||
method: 'get',
|
||||
timeout: AJAX_TIMEOUT,
|
||||
link: 'cancel',
|
||||
onSuccess: frameDataResponse
|
||||
});
|
||||
function frameQuery(data) {
|
||||
$j.getJSON(thisUrl + '?view=request&request=status&entity=frameimage', data)
|
||||
.done(frameDataResponse)
|
||||
.fail(logAjaxFail);
|
||||
}
|
||||
|
||||
function requestFrameData( eventId, frameId ) {
|
||||
var data = {};
|
||||
|
||||
if ( !events[eventId] ) {
|
||||
eventQuery.options.data = "view=request&request=status&entity=event&id="+eventId+"&loopback="+frameId;
|
||||
eventQuery.send();
|
||||
data.id = eventId;
|
||||
data.loopback = frameId;
|
||||
eventQuery(data);
|
||||
} else {
|
||||
frameQuery.options.data = "view=request&request=status&entity=frameimage&id[0]="+eventId+"&id[1]="+frameId;
|
||||
frameQuery.send();
|
||||
data.id = [eventId, frameId];
|
||||
frameQuery(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,43 +127,17 @@ function previewEvent(slot) {
|
|||
}
|
||||
|
||||
function loadEventImage( imagePath, eid, fid, width, height, fps, videoName, duration, startTime, Monitor ) {
|
||||
var vid = $('preview');
|
||||
var imageSrc = $('imageSrc');
|
||||
if ( videoName && vid ) {
|
||||
vid.show();
|
||||
imageSrc.hide();
|
||||
var newsource=imagePath.slice(0, imagePath.lastIndexOf('/'))+'/'+videoName;
|
||||
//console.log(newsource);
|
||||
//console.log(sources[0].src.slice(-newsource.length));
|
||||
if ( newsource != vid.currentSrc.slice(-newsource.length) || vid.readyState == 0 ) {
|
||||
//console.log("loading new");
|
||||
//it is possible to set a long source list here will that be unworkable?
|
||||
var sources = vid.getElementsByTagName('source');
|
||||
sources[0].src = newsource;
|
||||
var tracks = vid.getElementsByTagName('track');
|
||||
if (tracks.length) {
|
||||
tracks[0].parentNode.removeChild(tracks[0]);
|
||||
}
|
||||
vid.load();
|
||||
addVideoTimingTrack(vid, Monitor.LabelFormat, Monitor.Name, duration, startTime);
|
||||
vid.currentTime = fid/fps;
|
||||
} else {
|
||||
if ( ! vid.seeking ) {
|
||||
vid.currentTime=fid/fps;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( vid ) vid.hide();
|
||||
imageSrc.show();
|
||||
imageSrc.setProperty('src', imagePath);
|
||||
imageSrc.setAttribute('data-event-id', eid);
|
||||
imageSrc.setAttribute('data-frame-id', fid);
|
||||
imageSrc.onclick=window['showEvent'].bind(imageSrc, imageSrc);
|
||||
}
|
||||
var imageSrc = $j('#imageSrc');
|
||||
|
||||
var eventData = $('eventData');
|
||||
eventData.removeEvent('click');
|
||||
eventData.addEvent('click', showEvent.pass());
|
||||
imageSrc.show();
|
||||
imageSrc.attr('src', imagePath);
|
||||
imageSrc.data('event-id', eid);
|
||||
imageSrc.data('frame-id', fid);
|
||||
imageSrc.click(window['showEvent'].bind(imageSrc, imageSrc));
|
||||
|
||||
var eventData = $j('#eventData');
|
||||
eventData.off('click');
|
||||
eventData.click(showEvent.pass());
|
||||
}
|
||||
|
||||
function tlZoomBounds(event) {
|
||||
|
|
Loading…
Reference in New Issue