Merge branch 'storageareas' of github.com:ConnorTechnology/ZoneMinder into storageareas

This commit is contained in:
Isaac Connor 2017-10-30 08:37:54 -04:00
commit 8312bf52a4
59 changed files with 1847 additions and 318 deletions

View File

@ -232,6 +232,7 @@ CREATE TABLE `Filters` (
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
`AutoExecuteCmd` tinytext,
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
`Background` tinyint(1) unsigned NOT NULL default '0',
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
PRIMARY KEY (`Id`),
@ -288,6 +289,8 @@ CREATE TABLE `Logs` (
KEY `TimeKey` (`TimeKey`)
) ENGINE=@ZM_MYSQL_ENGINE@;
CREATE INDEX `Logs_TimeKey_idx` ON `Logs` (`TimeKey`);
CREATE INDEX `Logs_Level_idx` ON `Logs` (`Level`);
--
-- Table structure for table `Manufacturers`
--
@ -402,7 +405,7 @@ CREATE TABLE `Monitors` (
`SectionLength` int(10) unsigned NOT NULL default '600',
`FrameSkip` smallint(5) unsigned NOT NULL default '0',
`MotionFrameSkip` smallint(5) unsigned NOT NULL default '0',
`AnalysisFPS` decimal(5,2) default NULL,
`AnalysisFPSLimit` decimal(5,2) default NULL,
`AnalysisUpdateDelay` smallint(5) unsigned NOT NULL default '0',
`MaxFPS` decimal(5,2) default NULL,
`AlarmMaxFPS` decimal(5,2) default NULL,
@ -425,6 +428,9 @@ CREATE TABLE `Monitors` (
`WebColour` varchar(32) NOT NULL default 'red',
`Exif` tinyint(1) unsigned NOT NULL default '0',
`Sequence` smallint(5) unsigned default NULL,
`Status` enum('Unknown','NotRunning','Running','NoSignal','Signal') NOT NULL default 'Unknown',
`zmcFPS` DECIMAL(5,2) NOT NULL default 0,
`zmaFPS` DECIMAL(5,2) NOT NULL default 0,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
@ -457,6 +463,12 @@ CREATE TABLE `Servers` (
`Hostname` TEXT,
`Name` varchar(64) NOT NULL default '',
`State_Id` int(10) unsigned,
`Status` enum('Unknown','NotRunning','Running') NOT NULL default 'Unknown',
`Load` DECIMAL(5,1),
`TotalMem` bigint unsigned default null,
`FreeMem` bigint unsigned default null,
`TotalSwap` bigint unsigned default null,
`FreeSwap` bigint unsigned default null,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
@ -741,6 +753,29 @@ INSERT INTO ZonePresets VALUES (5,'Best, low sensitivity','Active','Percent','Bl
INSERT INTO ZonePresets VALUES (6,'Best, medium sensitivity','Active','Percent','Blobs',40,NULL,16,NULL,5,5,12,NULL,10,NULL,1,NULL,0,0);
INSERT INTO ZonePresets VALUES (7,'Best, high sensitivity','Active','Percent','Blobs',20,NULL,8,NULL,3,3,6,NULL,5,NULL,1,NULL,0,0);
CREATE TABLE Maps (
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` TEXT NOT NULL,
`Filename` TEXT NOT NULL default '',
`NumCoords` tinyint(3) unsigned NOT NULL default '0',
`Coords` tinytext NOT NULL,
`ParentId` int(1) unsigned,
PRIMARY KEY (`Id`)
);
CREATE TABLE MontageLayouts (
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` TEXT NOT NULL,
`Positions` JSON,
PRIMARY KEY (`Id`)
);
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Freeform', '{ "default":{"float":"left"} }' );
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('2 Wide', '{ "default":{"float":"left", "width":"49%"} }' );
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{"float":"left", "width":"33%"} }' );
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%"} }' );
INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%"} }' );
--
-- Apply the initial configuration
--

122
db/zm_update-1.31.10.sql Normal file
View File

@ -0,0 +1,122 @@
--
-- Add Type column to Storage
--
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Servers'
AND column_name = 'Status'
) > 0,
"SELECT 'Column Status already exists in Servers'",
"ALTER TABLE Servers ADD `Status` enum('Unknown','NotRunning','Running') NOT NULL default 'Unknown' AFTER `State_Id`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Servers'
AND column_name = 'CpuLoad'
) > 0,
"SELECT 'Column CpuLoad already exists in Servers'",
"ALTER TABLE Servers ADD `CpuLoad` DECIMAL(5,1) default NULL AFTER `Status`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Servers'
AND column_name = 'TotalMem'
) > 0,
"SELECT 'Column TotalMem already exists in Servers'",
"ALTER TABLE Servers ADD `TotalMem` bigint unsigned default null AFTER `CpuLoad`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Servers'
AND column_name = 'FreeMem'
) > 0,
"SELECT 'Column FreeMem already exists in Servers'",
"ALTER TABLE Servers ADD `FreeMem` bigint unsigned default null AFTER `TotalMem`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Servers'
AND column_name = 'TotalSwap'
) > 0,
"SELECT 'Column TotalSwap already exists in Servers'",
"ALTER TABLE Servers ADD `TotalSwap` bigint unsigned default null AFTER `FreeMem`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Servers'
AND column_name = 'FreeSwap'
) > 0,
"SELECT 'Column FreeSwap already exists in Servers'",
"ALTER TABLE Servers ADD `FreeSwap` bigint unsigned default null AFTER `TotalSwap`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'Status'
) > 0,
"SELECT 'Column Status already exists in Monitors'",
"ALTER TABLE Monitors ADD `Status` enum('Unknown','NotRunning','Running','NoSignal','Signal') NOT NULL default 'Unknown' AFTER `Sequence`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'CaptureFPS'
) > 0,
"SELECT 'Column CaptureFPS already exists in Monitors'",
"ALTER TABLE Monitors ADD `CaptureFPS` DECIMAL(10,2) NOT NULL default 0 AFTER `Status`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'AnalysisFPSLimit'
) > 0,
"SELECT 'Column AnalysisFPSLimit already exists in Monitors'",
"ALTER TABLE Monitors CHANGE COLUMN `AnalysisFPS` `AnalysisFPSLimit` DECIMAL(5,2) default NULL"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'AnalysisFPS'
) > 0,
"SELECT 'Column AnalysisFPS already exists in Monitors'",
"ALTER TABLE Monitors ADD `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0 AFTER `CaptureFPS`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

69
db/zm_update-1.31.11.sql Normal file
View File

@ -0,0 +1,69 @@
--
-- Add UpdateDiskSpace action to Filters
--
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'UpdateDiskSpace'
) > 0,
"SELECT 'Column UpdateDiskSpace already exists in Filters'",
"ALTER TABLE Filters ADD `UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoDelete`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
--
-- Update Logs table to have some Indexes
--
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'Logs'
AND table_schema = DATABASE()
AND index_name = 'Logs_TimeKey_idx'
) > 0,
"SELECT 'Logs_TimeKey_idx already exists on Logs table'",
"CREATE INDEX `Logs_TimeKey_idx` ON `Logs` (`TimeKey`)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'Logs'
AND table_schema = DATABASE()
AND index_name = 'Logs_Level_idx'
) > 0,
"SELECT 'Logs_Level_idx already exists on Logs table'",
"CREATE INDEX `Logs_Level_idx` ON `Logs` (`Level`)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'OutputCodec'
) > 0,
"SELECT 'Column OutputCodec already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `OutputCodec` enum('h264','mjpeg') AFTER `VideoWriter`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'OutputContainer'
) > 0,
"SELECT 'Column OutputContainer already exists in Monitors'",
"ALTER TABLE `Monitors` ADD `OutputContainer` enum('mp4','mkv') AFTER `OutputCodec`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

64
db/zm_update-1.31.12.sql Normal file
View File

@ -0,0 +1,64 @@
--
-- This adds Manufacturers and Models
--
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'MontageLayouts'
AND table_schema = DATABASE()
) > 0,
"SELECT 'MontageLayouts table exists'",
"
CREATE TABLE MontageLayouts (
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` TEXT NOT NULL,
`Positions` JSON,
PRIMARY KEY (`Id`)
);
"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = ( SELECT IF(
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='Freeform') > 0,
"SELECT 'Freeform already in layouts'",
"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('Freeform', '{ "default":{"float":"left"} }' );"
) );
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = ( SELECT IF(
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='2 Wide') > 0,
"SELECT '2 Wide already in layouts'",
"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('2 Wide', '{ "default":{"float":"left", "width":"49%"} }' );";
) );
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = ( SELECT IF(
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='3 Wide') > 0,
"SELECT '3 Wide already in layouts'",
"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{"float":"left", "width":"33%"} }' );"
) );
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = ( SELECT IF(
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='4 Wide') > 0,
"SELECT '4 Wide already in layouts'",
"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%"} }' );"
) );
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = ( SELECT IF(
(SELECT COUNT(*) FROM MontageLayouts WHERE Name='5 Wide') > 0,
"SELECT '5 Wide already in layouts'",
"INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%"} }' );"
) );
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -60,7 +60,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
,libsoap-wsdl-perl
,libio-socket-multicast-perl
,libdigest-sha-perl
,libsys-cpu-perl, libsys-meminfo-perl
,libsys-cpu-perl, libsys-cpuload-perl, libsys-meminfo-perl
,libdata-uuid-perl
,mysql-client | virtual-mysql-client
,perl-modules

View File

@ -27,7 +27,9 @@ override_dh_auto_configure:
-DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \
-DZM_DIR_EVENTS="/var/cache/zoneminder/events" \
-DZM_DIR_IMAGES="/var/cache/zoneminder/images" \
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms"
-DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \
-DZM_NO_CURL=1 \
-DZM_NO_LIBVLC=1
override_dh_clean:
dh_clean $(MANPAGES1)

View File

@ -14,7 +14,8 @@ ExecStart=/usr/bin/zmpkg.pl start
ExecReload=/usr/bin/zmpkg.pl restart
ExecStop=/usr/bin/zmpkg.pl stop
PIDFile=/var/run/zm/zm.pid
Restart=on-abnormal
Restart=always
RestartSec=10
Environment=TZ=:/etc/localtime
[Install]

View File

@ -157,6 +157,16 @@ sub zmDbGetMonitors {
return( \@monitors );
}
sub zmSQLExecute {
my $sql = shift;
my $sth = $dbh->prepare_cached( $sql )
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( @_ )
or croak( "Can't execute '$sql': ".$sth->errstr() );
return 1;
}
sub zmDbGetMonitor {
zmDbConnect();
@ -195,6 +205,30 @@ sub zmDbGetMonitorAndControl {
return( $monitor );
}
sub start_transaction {
#my ( $caller, undef, $line ) = caller;
#$openprint::log->debug("Called start_transaction from $caller : $line");
my $d = shift;
$d = $dbh if ! $d;
my $ac = $d->{AutoCommit};
$d->{AutoCommit} = 0;
return $ac;
} # end sub start_transaction
sub end_transaction {
#my ( $caller, undef, $line ) = caller;
#$openprint::log->debug("Called end_transaction from $caller : $line");
my ( $d, $ac ) = @_;
if ( ! defined $ac ) {
Error("Undefined ac");
}
$d = $dbh if ! $d;
if ( $ac ) {
#$log->debug("Committing");
$d->commit();
} # end if
$d->{AutoCommit} = $ac;
} # end sub end_transaction
1;
__END__
# Below is stub documentation for your module. You'd better edit it!

View File

@ -359,14 +359,16 @@ sub age {
return $_[0]{age};
}
sub DiskUsage {
sub DiskSpace {
if ( @_ > 1 ) {
$_[0]{DiskUsage} = $_[1];
Debug("Cleared DiskSpace, was $_[0]{DiskSpace}");
$_[0]{DiskSpace} = $_[1];
}
if ( ! defined $_[0]{DiskUsage} ) {
if ( ! defined $_[0]{DiskSpace} ) {
my $size = 0;
File::Find::find( { wanted=>sub { $size += -f $_ ? -s _ : 0 }, untaint=>1 }, $_[0]->Path() );
$_[0]{DiskUsage} = $size;
$_[0]{DiskSpace} = $size;
Debug("DiskSpace for event $_[0]{Id} at $_[0]{Path} Updated to $size bytes");
}
}

View File

@ -125,7 +125,7 @@ sub Execute {
push @results, $event;
}
$sth->finish();
Debug("Loaded " . @results . " events for filter $_[0]{Name} using query ($sql)");
Debug('Loaded ' . @results . " events for filter $_[0]{Name} using query ($sql)");
return @results;
}
@ -147,38 +147,59 @@ sub Sql {
foreach my $term ( @{$filter_expr->{terms}} ) {
if ( exists($term->{cnj}) ) {
$self->{Sql} .= " ".$term->{cnj}." ";
$self->{Sql} .= ' '.$term->{cnj}." ";
}
if ( exists($term->{obr}) ) {
$self->{Sql} .= " ".str_repeat( "(", $term->{obr} )." ";
$self->{Sql} .= ' '.str_repeat( "(", $term->{obr} )." ";
}
my $value = $term->{val};
my @value_list;
if ( $term->{attr} ) {
if ( $term->{attr} =~ /^Monitor/ ) {
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
$self->{Sql} .= "M.".$temp_attr_name;
$self->{Sql} .= 'M.'.$temp_attr_name;
} elsif ( $term->{attr} =~ /^Server/ ) {
$self->{Sql} .= "M.".$term->{attr};
$self->{Sql} .= 'M.'.$term->{attr};
# StartTime options
} elsif ( $term->{attr} eq 'DateTime' ) {
$self->{Sql} .= "E.StartTime";
$self->{Sql} .= 'E.StartTime';
} elsif ( $term->{attr} eq 'StartDateTime' ) {
$self->{Sql} .= 'E.StartTime';
} elsif ( $term->{attr} eq 'Date' ) {
$self->{Sql} .= "to_days( E.StartTime )";
$self->{Sql} .= 'to_days( E.StartTime )';
} elsif ( $term->{attr} eq 'StartDate' ) {
$self->{Sql} .= 'to_days( E.StartTime )';
} elsif ( $term->{attr} eq 'Time' ) {
$self->{Sql} .= "extract( hour_second from E.StartTime )";
} elsif ( $term->{attr} eq 'Weekday' ) {
$self->{Sql} .= "weekday( E.StartTime )";
# EndTIme options
} elsif ( $term->{attr} eq 'EndDateTime' ) {
$self->{Sql} .= 'E.EndTime';
} elsif ( $term->{attr} eq 'EndDate' ) {
$self->{Sql} .= 'to_days( E.EndTime )';
} elsif ( $term->{attr} eq 'EndTime' ) {
$self->{Sql} .= "extract( hour_second from E.EndTime )";
} elsif ( $term->{attr} eq 'EndWeekday' ) {
$self->{Sql} .= "weekday( E.EndTime )";
#
} elsif ( $term->{attr} eq 'DiskSpace' ) {
$self->{Sql} .= 'E.DiskSpace';
$self->{HasDiskPercent} = !undef;
} elsif ( $term->{attr} eq 'DiskPercent' ) {
$self->{Sql} .= "zmDiskPercent";
$self->{Sql} .= 'zmDiskPercent';
$self->{HasDiskPercent} = !undef;
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
$self->{Sql} .= "zmDiskBlocks";
$self->{Sql} .= 'zmDiskBlocks';
$self->{HasDiskBlocks} = !undef;
} elsif ( $term->{attr} eq 'SystemLoad' ) {
$self->{Sql} .= "zmSystemLoad";
$self->{Sql} .= 'zmSystemLoad';
$self->{HasSystemLoad} = !undef;
} else {
$self->{Sql} .= "E.".$term->{attr};
$self->{Sql} .= 'E.'.$term->{attr};
}
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
@ -238,16 +259,20 @@ sub Sql {
$self->{Sql} .= " regexp $value";
} elsif ( $term->{op} eq '!~' ) {
$self->{Sql} .= " not regexp $value";
} elsif ( $term->{op} eq 'IS' ) {
$self->{Sql} .= " IS $value";
} elsif ( $term->{op} eq 'IS NOT' ) {
$self->{Sql} .= " IS NOT $value";
} elsif ( $term->{op} eq '=[]' ) {
$self->{Sql} .= " in (".join( ",", @value_list ).")";
} elsif ( $term->{op} eq '!~' ) {
$self->{Sql} .= " not in (".join( ",", @value_list ).")";
} else {
$self->{Sql} .= " ".$term->{op}." $value";
$self->{Sql} .= ' '.$term->{op}." $value";
}
} # end if has an operator
if ( exists($term->{cbr}) ) {
$self->{Sql} .= " ".str_repeat( ")", $term->{cbr} )." ";
$self->{Sql} .= ' '.str_repeat( ")", $term->{cbr} )." ";
}
} # end foreach term
} # end if terms
@ -256,15 +281,15 @@ sub Sql {
if ( $self->{AutoMessage} ) {
# Include all events, including events that are still ongoing
# and have no EndTime yet
$sql .= " and ( ".$self->{Sql}." )";
$sql .= ' AND ( '.$self->{Sql}.' )';
} else {
# Only include closed events (events with valid EndTime)
$sql .= " where not isnull(E.EndTime) and ( ".$self->{Sql}." )";
$sql .= ' WHERE (E.EndTime IS NOT NULL) AND ( '.$self->{Sql}.' )';
}
}
my @auto_terms;
if ( $self->{AutoArchive} ) {
push @auto_terms, "E.Archived = 0";
push @auto_terms, 'E.Archived = 0';
}
# Don't do this, it prevents re-generation and concatenation.
# If the file already exists, then the video won't be re-recreated
@ -284,7 +309,7 @@ sub Sql {
push @auto_terms, "E.Executed = 0";
}
if ( @auto_terms ) {
$sql .= " and ( ".join( " or ", @auto_terms )." )";
$sql .= " and ( ".join( ' or ', @auto_terms )." )";
}
if ( !$filter_expr->{sort_field} ) {
$filter_expr->{sort_field} = 'StartTime';
@ -292,30 +317,34 @@ sub Sql {
}
my $sort_column = '';
if ( $filter_expr->{sort_field} eq 'Id' ) {
$sort_column = "E.Id";
$sort_column = 'E.Id';
} elsif ( $filter_expr->{sort_field} eq 'MonitorName' ) {
$sort_column = "M.Name";
$sort_column = 'M.Name';
} elsif ( $filter_expr->{sort_field} eq 'Name' ) {
$sort_column = "E.Name";
$sort_column = 'E.Name';
} elsif ( $filter_expr->{sort_field} eq 'StartTime' ) {
$sort_column = "E.StartTime";
$sort_column = 'E.StartTime';
} elsif ( $filter_expr->{sort_field} eq 'EndTime' ) {
$sort_column = 'E.EndTime';
} elsif ( $filter_expr->{sort_field} eq 'Secs' ) {
$sort_column = "E.Length";
$sort_column = 'E.Length';
} elsif ( $filter_expr->{sort_field} eq 'Frames' ) {
$sort_column = "E.Frames";
$sort_column = 'E.Frames';
} elsif ( $filter_expr->{sort_field} eq 'AlarmFrames' ) {
$sort_column = "E.AlarmFrames";
$sort_column = 'E.AlarmFrames';
} elsif ( $filter_expr->{sort_field} eq 'TotScore' ) {
$sort_column = "E.TotScore";
$sort_column = 'E.TotScore';
} elsif ( $filter_expr->{sort_field} eq 'AvgScore' ) {
$sort_column = "E.AvgScore";
$sort_column = 'E.AvgScore';
} elsif ( $filter_expr->{sort_field} eq 'MaxScore' ) {
$sort_column = "E.MaxScore";
$sort_column = 'E.MaxScore';
} elsif ( $filter_expr->{sort_field} eq 'DiskSpace' ) {
$sort_column = 'E.DiskSpace';
} else {
$sort_column = "E.StartTime";
$sort_column = 'E.StartTime';
}
my $sort_order = $filter_expr->{sort_asc}?"asc":"desc";
$sql .= " order by ".$sort_column." ".$sort_order;
my $sort_order = $filter_expr->{sort_asc}?'asc':'desc';
$sql .= ' order by '.$sort_column." ".$sort_order;
if ( $filter_expr->{limit} ) {
$sql .= " limit 0,".$filter_expr->{limit};
}
@ -325,7 +354,7 @@ sub Sql {
} # end sub Sql
sub getDiskPercent {
my $command = "df " . ($_[0] ? $_[0] : '.');
my $command = 'df ' . ($_[0] ? $_[0] : '.');
my $df = qx( $command );
my $space = -1;
if ( $df =~ /\s(\d+)%/ms ) {
@ -335,7 +364,7 @@ sub getDiskPercent {
}
sub getDiskBlocks {
my $command = "df .";
my $command = 'df .';
my $df = qx( $command );
my $space = -1;
if ( $df =~ /\s(\d+)\s+\d+\s+\d+%/ms ) {
@ -345,7 +374,7 @@ sub getDiskBlocks {
}
sub getLoad {
my $command = "uptime .";
my $command = 'uptime .';
my $uptime = qx( $command );
my $load = -1;
if ( $uptime =~ /load average:\s+([\d.]+)/ms ) {

View File

@ -678,6 +678,8 @@ sub Dump {
fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) );
}
sub debug { $_[0]->logPrint( DEBUG, @_ ); }
sub Debug( @ ) {
fetch()->logPrint( DEBUG, @_ );
}
@ -685,14 +687,24 @@ sub Debug( @ ) {
sub Info( @ ) {
fetch()->logPrint( INFO, @_ );
}
sub info {
$_[0]->logPrint( INFO, @_ );
}
sub Warning( @ ) {
fetch()->logPrint( WARNING, @_ );
}
sub warn {
$_[0]->logPrint( WARNING, @_ );
}
sub Error( @ ) {
fetch()->logPrint( ERROR, @_ );
}
sub error {
$_[0]->logPrint( ERROR, @_ );
}
sub Fatal( @ ) {
fetch()->logPrint( FATAL, @_ );

View File

@ -42,7 +42,13 @@ use ZoneMinder::Config qw(:all);
use ZoneMinder::Logger qw(:all);
use ZoneMinder::Database qw(:all);
use vars qw/ $AUTOLOAD /;
use vars qw/ $AUTOLOAD $log $dbh/;
*log = \$ZoneMinder::Logger::logger;
*dbh = \$ZoneMinder::Database::dbh;
my $debug = 1;
use constant DEBUG_ALL=>0;
sub new {
my ( $parent, $id, $data ) = @_;
@ -110,7 +116,269 @@ sub AUTOLOAD {
return $_[0]{$name};
}
sub save {
my ( $self, $data, $force_insert ) = @_;
my $type = ref $self;
if ( ! $type ) {
my ( $caller, undef, $line ) = caller;
$log->error("No type in Object::save. self:$self from $caller:$line");
}
my $local_dbh = eval '$'.$type.'::dbh';
$local_dbh = $ZoneMinder::Database::dbh if ! $local_dbh;
$self->set( $data ? $data : {} );
if ( $debug or DEBUG_ALL ) {
if ( $data ) {
foreach my $k ( keys %$data ) {
$log->debug("Object::save after set $k => $$data{$k} $$self{$k}");
}
} else {
$log->debug("No data after set");
}
}
#$debug = 0;
my $table = eval '$'.$type.'::table';
my $fields = eval '\%'.$type.'::fields';
my $debug = eval '$'.$type.'::debug';
#$debug = DEBUG_ALL if ! $debug;
my %sql;
foreach my $k ( keys %$fields ) {
$sql{$$fields{$k}} = $$self{$k} if defined $$fields{$k};
} # end foreach
if ( ! $force_insert ) {
$sql{$$fields{updated_on}} = 'NOW()' if exists $$fields{updated_on};
} # end if
my $serial = eval '$'.$type.'::serial';
my @identified_by = eval '@'.$type.'::identified_by';
my $ac = ZoneMinder::Database::start_transaction( $local_dbh );
if ( ! $serial ) {
my $insert = $force_insert;
my %serial = eval '%'.$type.'::serial';
if ( ! %serial ) {
$log->debug("No serial") if $debug;
# No serial columns defined, which means that we will do saving by delete/insert instead of insert/update
if ( @identified_by ) {
my $where = join(' AND ', map { $$fields{$_}.'=?' } @identified_by );
if ( $debug ) {
$log->debug("DELETE FROM $table WHERE $where");
} # end if
if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM $table WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) {
$where =~ s/\?/\%s/g;
$log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr);
$local_dbh->rollback();
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $local_dbh->errstr;
} elsif ( $debug ) {
$log->debug("SQL succesful DELETE FROM $table WHERE $where");
} # end if
} # end if
$insert = 1;
} else {
foreach my $id ( @identified_by ) {
if ( ! $serial{$id} ) {
my ( $caller, undef, $line ) = caller;
$log->error("$id nor in serial for $type from $caller:$line") if $debug;
next;
}
if ( ! $$self{$id} ) {
($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} );
$log->debug("SQL statement execution SELECT nextval('$serial{$id}') returned $$self{$id}") if $debug or DEBUG_ALL;
$insert = 1;
} # end if
} # end foreach
} # end if ! %serial
if ( $insert ) {
my @keys = keys %sql;
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
if ( ! ( ( $_ = $local_dbh->prepare($command) ) and $_->execute( @sql{@keys} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;
$log->error('SQL statement execution failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $local_dbh->errstr);
$local_dbh->rollback();
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
$command =~ s/\?/\%s/g;
$log->debug('SQL statement execution: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' );
} # end if
} else {
my @keys = keys %sql;
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $_ . ' = ?' } @$fields{@identified_by} );
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys,@$fields{@identified_by}} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;
$log->error('SQL failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys, @$fields{@identified_by}}) ).'):' . $local_dbh->errstr);
$local_dbh->rollback();
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
$command =~ s/\?/\%s/g;
$log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys,@$fields{@identified_by}} ) ).'):' );
} # end if
} # end if
} else { # not identified_by
@identified_by = ('id') if ! @identified_by;
my $need_serial = ! ( @identified_by == map { $$self{$_} ? $_ : () } @identified_by );
if ( $force_insert or $need_serial ) {
if ( $need_serial ) {
if ( $serial ) {
@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} );
if ( $local_dbh->errstr() ) {
$log->error("Error getting next id. " . $local_dbh->errstr() );
$log->error("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by}));
} elsif ( $debug or DEBUG_ALL ) {
$log->debug("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by}));
} # end if
} # end if
} # end if
my @keys = keys %sql;
my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')';
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) {
$command =~ s/\?/\%s/g;
my $error = $local_dbh->errstr;
$log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $error);
$local_dbh->rollback();
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
$command =~ s/\?/\%s/g;
$log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' );
} # end if
} else {
delete $sql{created_on};
my @keys = keys %sql;
@keys = sets::exclude( [ @$fields{@identified_by} ], \@keys );
my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $$fields{$_} .'= ?' } @identified_by );
if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) {
my $error = $local_dbh->errstr;
$command =~ s/\?/\%s/g;
$log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}, @sql{@$fields{@identified_by}} ) ).'):' . $error) if $log;
$local_dbh->rollback();
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
return $error;
} # end if
if ( $debug or DEBUG_ALL ) {
$command =~ s/\?/\%s/g;
$log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? ( ref $_ eq 'ARRAY' ? join(',',@{$_}) : $_ ) : 'undef' } ( @sql{@keys}, @$self{@identified_by} ) ).'):' );
} # end if
} # end if
} # end if
ZoneMinder::Database::end_transaction( $local_dbh, $ac );
$self->load();
#if ( $$fields{id} ) {
#if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) {
#$ZoneMinder::Object::cache{$type}{$$self{id}} = $self;
#} # end if
#delete $ZoneMinder::Object::cache{$config{db_name}}{$type}{$$self{id}};
#} # end if
#$log->debug("after delete");
#eval 'if ( %'.$type.'::find_cache ) { %'.$type.'::find_cache = (); }';
#$log->debug("after clear cache");
return '';
} # end sub save
sub set {
my ( $self, $params ) = @_;
my @set_fields = ();
my $type = ref $self;
my %fields = eval ('%'.$type.'::fields');
if ( ! %fields ) {
$log->warn('ZoneMinder::Object::set called on an object with no fields');
} # end if
my %defaults = eval('%'.$type.'::defaults');
if ( ref $params ne 'HASH' ) {
my ( $caller, undef, $line ) = caller;
$openprint::log->error("$type -> set called with non-hash params from $caller $line");
}
foreach my $field ( keys %fields ) {
$log->debug("field: $field, param: ".$$params{$field}) if $debug;
if ( exists $$params{$field} ) {
$openprint::log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug;
if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) {
# Only make changes to fields that have changed
if ( defined $fields{$field} ) {
$$self{$field} = $$params{$field} if defined $fields{$field};
push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating
} # end if
$openprint::log->debug("Running $field with $$params{$field}") if $debug;
if ( my $func = $self->can( $field ) ) {
$func->( $self, $$params{$field} );
} # end if
} # end if
} # end if
if ( defined $fields{$field} ) {
if ( $$self{$field} ) {
$$self{$field} = transform( $type, $field, $$self{$field} );
} # end if $$self{field}
}
} # end foreach field
foreach my $field ( keys %defaults ) {
if ( ( ! exists $$self{$field} ) or (!defined $$self{$field}) or ( $$self{$field} eq '' ) ) {
$log->debug("Setting default ($field) ($$self{$field}) ($defaults{$field}) ") if $debug;
if ( defined $defaults{$field} ) {
$log->debug("Default $field is defined: $defaults{$field}") if $debug;
if ( $defaults{$field} eq 'NOW()' ) {
$$self{$field} = 'NOW()';
} else {
$$self{$field} = eval($defaults{$field});
$log->error( "Eval error of object default $field default ($defaults{$field}) Reason: " . $@ ) if $@;
} # end if
} else {
$$self{$field} = $defaults{$field};
} # end if
#$$self{$field} = ( defined $defaults{$field} ) ? eval($defaults{$field}) : $defaults{$field};
$log->debug("Setting default for ($field) using ($defaults{$field}) to ($$self{$field}) ") if $debug;
} # end if
} # end foreach default
return @set_fields;
} # end sub set
sub transform {
my $type = ref $_[0];
$type = $_[0] if ! $type;
my $fields = eval '\%'.$type.'::fields';
my $value = $_[2];
if ( defined $$fields{$_[1]} ) {
my @transforms = eval('@{$'.$type.'::transforms{$_[1]}}');
$openprint::log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug;
if ( @transforms ) {
foreach my $transform ( @transforms ) {
if ( $transform =~ /^s\// or $transform =~ /^tr\// ) {
eval '$value =~ ' . $transform;
} elsif ( $transform =~ /^<(\d+)/ ) {
if ( $value > $1 ) {
$value = undef;
} # end if
} else {
$openprint::log->debug("evalling $value ".$transform . " Now value is $value" );
eval '$value '.$transform;
$openprint::log->error("Eval error $@") if $@;
}
$openprint::log->debug("After $transform: $value") if $debug;
} # end foreach
} # end if
} else {
$openprint::log->error("Object::transform ($_[1]) not in fields for $type");
} # end if
return $value;
} # end sub transform
1;
__END__

View File

@ -246,7 +246,7 @@ MAIN: while( $loop ) {
$$Event{Path} = join('/', $Storage->Path(), $day_dir,$event_path);
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );
$Event->DiskUsage( undef );
$Event->DiskSpace( undef );
} # event path exists
} # end foreach event_link
chdir( $Storage->Path() );

View File

@ -55,7 +55,7 @@ use bytes;
# ==========================================================================
# in useconds, not seconds.
use constant MAX_CONNECT_DELAY => 10*1000*1000;
use constant MAX_CONNECT_DELAY => 40;
# ==========================================================================
#
@ -69,6 +69,9 @@ use POSIX;
use Socket;
use IO::Handle;
use Time::HiRes qw(usleep);
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
use Sys::CpuLoad;
use autouse 'Pod::Usage'=>qw(pod2usage);
#use Data::Dumper;
@ -140,12 +143,20 @@ foreach my $arg ( @ARGV ) {
}
}
my $dbh = zmDbConnect();
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
my $saddr = sockaddr_un( SOCK_FILE );
my $server_up = connect( CLIENT, $saddr );
if ( ! $server_up ) {
# Server is not up. Some commands can still be handled
if ( $Config{ZM_SERVER_ID} ) {
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
}
}
# Server is not up. Some commands can still be handled
if ( $command eq 'logrot' ) {
# If server is not running, then logrotate doesn't need to do anything.
exit();
@ -172,7 +183,7 @@ if ( ! $server_up ) {
my $attempts = 0;
while( !connect( CLIENT, $saddr ) ) {
$attempts++;
Error("Waiting for zmdc.pl server process, attempt $attempts" );
Error("Waiting for zmdc.pl server process at " . SOCK_FILE.", attempt $attempts" );
Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY);
usleep(200000);
} # end while
@ -219,6 +230,8 @@ use POSIX;
use Socket;
use IO::Handle;
use Time::HiRes qw(usleep);
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
use Sys::CpuLoad;
#use Data::Dumper;
use constant KILL_DELAY => 100*1000; # 1/10th of a second
@ -250,8 +263,10 @@ sub run {
killAll( 1 );
dPrint( ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE );
my $dbh = zmDbConnect(1);
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE );
unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if -e main::SOCK_FILE;
bind( SERVER, $saddr ) or Fatal( "Can't bind to " . main::SOCK_FILE . ": $!" );
listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" );
@ -265,8 +280,16 @@ sub run {
vec( $rin, fileno(SERVER), 1 ) = 1;
my $win = $rin;
my $ein = $win;
my $timeout = 0.1;
my $timeout = 1;
while( 1 ) {
if ( $Config{ZM_SERVER_ID} ) {
$dbh = zmDbConnect() if ! $dbh->ping();
my @cpuload = Sys::CpuLoad::load();
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
}
}
my $nfound = select( my $rout = $rin, undef, undef, $timeout );
if ( $nfound > 0 ) {
if ( vec( $rout, fileno(SERVER), 1 ) ) {
@ -327,6 +350,12 @@ sub run {
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
."\n"
);
if ( $Config{ZM_SERVER_ID} ) {
$dbh = zmDbConnect() if ! $dbh->ping();
if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
}
}
unlink( main::SOCK_FILE ) or Error( 'Unable to unlink ' . main::SOCK_FILE .". Error message was: $!" ) if ( -e main::SOCK_FILE );
unlink( ZM_PID ) or Error( 'Unable to unlink ' . ZM_PID .". Error message was: $!" ) if ( -e ZM_PID );
exit();
@ -393,7 +422,7 @@ sub start {
sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" );
} elsif ( defined($cpid ) ) {
# Force reconnection to the db.
zmDbConnect(1);
$dbh = zmDbConnect(1);
logReinit();
dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) )

View File

@ -214,6 +214,7 @@ sub getFilters {
or AutoMessage = 1
or AutoExecute = 1
or AutoDelete = 1
or UpdateDiskSpace = 1
) ORDER BY Name';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
@ -250,17 +251,23 @@ sub checkFilter {
my $filter = shift;
my @Events = $filter->Execute();
Info( join( "Checking filter '$filter->{Name}'",
($filter->{AutoDelete}?', delete':''),
($filter->{AutoArchive}?', archive':''),
($filter->{AutoVideo}?', video':''),
($filter->{AutoUpload}?', upload':''),
($filter->{AutoEmail}?', email':''),
($filter->{AutoMessage}?', message':''),
($filter->{AutoExecute}?', execute':''),
' returned ' , scalar @Events , ' events',
"\n",
) );
Info(
join(' ',
'Checking filter', $filter->{Name},
join( ', ',
($filter->{AutoDelete}?'delete':()),
($filter->{AutoArchive}?'archive':()),
($filter->{AutoVideo}?'video':()),
($filter->{AutoUpload}?'upload':()),
($filter->{AutoEmail}?'email':()),
($filter->{AutoMessage}?'message':()),
($filter->{AutoExecute}?'execute':()),
($filter->{UpdateDiskSpace}?'update disk space':()),
),
'returned' , scalar @Events , 'events',
"\n",
) );
foreach my $event ( @Events ) {
Debug( "Checking event $event->{Id}\n" );
@ -308,6 +315,12 @@ sub checkFilter {
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
}
} # end if AutoDelete
if ( $filter->{UpdateDiskSpace} ) {
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
$Event->DiskSpace(undef);
$Event->save();
} # end if UpdateDiskSpace
} # end foreach event
}

View File

@ -419,8 +419,8 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
strncpy( sql, "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ", sizeof(sql) );
int frameCount = 0;
for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) {
if ( !timestamps[i]->tv_sec ) {
Debug( 1, "Not adding pre-capture frame %d, zero timestamp", i );
if ( timestamps[i]->tv_sec <= 0 ) {
Debug( 1, "Not adding pre-capture frame %d, zero or less than 0 timestamp", i );
continue;
}

View File

@ -271,8 +271,7 @@ void EventStream::processCommand( const CmdMsg *msg ) {
case CMD_VARPLAY :
{
Debug( 1, "Got VARPLAY command" );
if ( paused )
{
if ( paused ) {
// Clear paused flag
paused = false;
}

View File

@ -1180,6 +1180,11 @@ bool Monitor::Analyse() {
if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) {
fps = double(fps_report_interval)/(now.tv_sec-last_fps_time);
Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps );
static char sql[ZM_SQL_SML_BUFSIZ];
snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
}
last_fps_time = now.tv_sec;
}
@ -1678,7 +1683,7 @@ void Monitor::Reload() {
static char sql[ZM_SQL_MED_BUFSIZ];
// This seems to have fallen out of date.
snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id );
snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
@ -1843,7 +1848,7 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) {
#if ZM_HAS_V4L
int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) {
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'";
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'";
;
if ( device[0] ) {
sql += " AND Device='";
@ -2032,7 +2037,7 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose
#endif // ZM_HAS_V4L
int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) {
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'";
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'";
if ( staticConfig.SERVER_ID ) {
sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID );
}
@ -2215,7 +2220,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
}
int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) {
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'";
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'";
if ( file[0] ) {
sql += " AND Path='";
sql += file;
@ -2365,7 +2370,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu
#if HAVE_LIBAVFORMAT
int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ) {
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'";
std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'";
if ( file[0] ) {
sql += " AND Path = '";
sql += file;
@ -2525,7 +2530,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose
#endif // HAVE_LIBAVFORMAT
Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) {
std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPS, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id );
std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id );
zmDbRow dbrow;
if ( ! dbrow.fetch( sql.c_str() ) ) {
@ -2981,6 +2986,11 @@ int Monitor::Capture() {
//Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps );
Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps );
last_fps_time = now;
static char sql[ZM_SQL_SML_BUFSIZ];
snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
}
}
// Icon: I'm not sure these should be here. They have nothing to do with capturing

View File

@ -553,7 +553,7 @@ void MonitorStream::runStream() {
Debug( 2, "Assigned temporary buffer" );
}
}
}
} // end if connkey & playback_buffer
float max_secs_since_last_sent_frame = 10.0; //should be > keep alive amount (5 secs)
while ( !zm_terminate ) {

View File

@ -44,7 +44,11 @@ bool StreamBase::loadMonitor( int monitor_id ) {
Fatal( "Unable to load monitor id %d for streaming", monitor_id );
return( false );
}
monitor->connect();
if ( ! monitor->connect() ) {
Fatal( "Unable to connect to monitor id %d for streaming", monitor_id );
return( false );
}
return( true );
}

View File

@ -221,6 +221,13 @@ int main(int argc, char *argv[]) {
}
Info("Starting Capture version %s", ZM_VERSION);
static char sql[ZM_SQL_SML_BUFSIZ];
for ( int i = 0; i < n_monitors; i ++ ) {
snprintf( sql, sizeof(sql), "UPDATE Monitors SET Status = 'Running' WHERE Id = '%d'", monitors[i]->Id() );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
}
}
zmSetDefaultTermHandler();
zmSetDefaultDieHandler();

View File

@ -1 +1 @@
1.31.9
1.31.12

View File

@ -108,6 +108,7 @@ $statusData = array(
"elements" => array(
"Id" => array( "sql" => "Events.Id" ),
"MonitorId" => true,
"MonitorName" => array("sql" => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"),
"Name" => true,
"Cause" => true,
"StartTime" => true,

View File

@ -44,7 +44,7 @@ switch ( $_REQUEST['command'] ) {
$remSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf("%06d",$_REQUEST['connkey']).'s.sock';
$max_socket_tries = 10;
while ( !file_exists($remSockFile) && $max_socket_tries-- ) { //sometimes we are too fast for our own good, if it hasn't been setup yet give it a second.
usleep(200000);
usleep(2000000);
}
if ( !file_exists($remSockFile) ) {

View File

@ -1,6 +1,15 @@
<?php
class Event {
private $fields = array(
'Id',
'Name',
'MonitorId',
'StorageId',
'Name',
'DiskSpace',
);
public function __construct( $IdOrRow = null ) {
$row = NULL;
if ( $IdOrRow ) {
@ -177,7 +186,10 @@ class Event {
return( $streamSrc );
} // end function getStreamSrc
function DiskSpace() {
function DiskSpace( $new='' ) {
if ( $new != '' ) {
$this->{'DiskSpace'} = $new;
}
if ( null === $this->{'DiskSpace'} ) {
$this->{'DiskSpace'} = folder_size( $this->Path() );
dbQuery( 'UPDATE Events SET DiskSpace=? WHERE Id=?', array( $this->{'DiskSpace'}, $this->{'Id'} ) );
@ -370,6 +382,13 @@ class Event {
return $filters;
}
public function save( ) {
$sql = 'UPDATE Events SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $this->fields ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $this->fields );
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
}
} # end class

View File

@ -12,6 +12,7 @@ public $defaults = array(
'AutoArchive' => 0,
'AutoVideo' => 0,
'AutoMessage' => 0,
'UpdateDiskSpace' => 0,
'Background' => 0,
'Concurrent' => 0,
'limit' => 100,

View File

@ -4,6 +4,17 @@ require_once( 'Server.php' );
class Monitor {
private $defaults = array(
'Id' => null,
'Name' => '',
'StorageId' => 0,
'ServerId' => 0,
'Function' => 'None',
'Enabled' => 1,
'Width' => null,
'Height' => null,
'Orientation' => null,
);
private $control_fields = array(
'Name' => '',
'Type' => 'Local',
@ -150,19 +161,20 @@ private $control_fields = array(
public function Server() {
return new Server( $this->{'ServerId'} );
}
public function __call( $fn, array $args){
if ( count( $args ) ) {
public function __call($fn, array $args){
if ( count($args) ) {
$this->{$fn} = $args[0];
}
if ( array_key_exists( $fn, $this ) ) {
if ( array_key_exists($fn, $this) ) {
return $this->{$fn};
#array_unshift($args, $this);
#call_user_func_array( $this->{$fn}, $args);
} else {
if ( array_key_exists( $fn, $this->control_fields ) ) {
if ( array_key_exists($fn, $this->control_fields) ) {
return $this->control_fields{$fn};
} else if ( array_key_exists( $fn, $this->defaults ) ) {
return $this->defaults{$fn};
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
@ -206,14 +218,19 @@ private $control_fields = array(
return( $streamSrc );
} // end function getStreamSrc
public function Width() {
public function Width( $new = null ) {
if ( $new )
$this->{'Width'} = $new;
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
return $this->{'Height'};
}
return $this->{'Width'};
}
public function Height() {
public function Height( $new=null ) {
if ( $new )
$this->{'Height'} = $new;
if ( $this->Orientation() == '90' or $this->Orientation() == '270' ) {
return $this->{'Width'};
}
@ -237,5 +254,121 @@ private $control_fields = array(
}
}
}
}
public static function find_all( $parameters = null, $options = null ) {
$filters = array();
$sql = 'SELECT * FROM Monitors ';
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = $field.' IS NULL';
} else if ( is_array( $value ) ) {
$func = function(){return '?';};
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
$values += $value;
} else {
$fields[] = $field.'=?';
$values[] = $value;
}
}
$sql .= implode(' AND ', $fields );
}
if ( $options and isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
$result = dbQuery($sql, $values);
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Monitor');
foreach ( $results as $row => $obj ) {
$filters[] = $obj;
}
return $filters;
}
public function save( $new_values = null ) {
if ( $new_values ) {
foreach ( $new_values as $k=>$v ) {
$this->{$k} = $v;
}
}
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, array_keys( $this->defaults ) ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $this->fields );
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
} // end function save
function zmcControl( $mode=false ) {
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$this->{'ServerId'} ) ) {
if ( $this->{'Type'} == 'Local' ) {
$zmcArgs = '-d '.$this->{'Device'};
} else {
$zmcArgs = '-m '.$this->{'Id'};
}
if ( $mode == 'stop' ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
} else {
if ( $mode == 'restart' ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
}
daemonControl( 'start', 'zmc', $zmcArgs );
}
} else {
$Server = $this->Server();
$url = $Server->Url() . '/zm/api/monitors/'.$this->{'Id'}.'.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '&auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
$url = '&user='.$_SESSION['username'];
$url = '&pass='.$_SESSION['password'];
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$url = '&user='.$_SESSION['username'];
}
}
$data = array('Monitor[Function]' => $this->{'Function'} );
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
}
} // end function zmcControl
function zmaControl( $mode=false ) {
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$this->{'ServerId'} ) ) {
if ( $this->{'Function'} == 'None' || $this->{'Function'} == 'Monitor' || $mode == 'stop' ) {
if ( ZM_OPT_CONTROL ) {
daemonControl( 'stop', 'zmtrack.pl', '-m '.$this->{'Id'} );
}
daemonControl( 'stop', 'zma', '-m '.$this->{'Id'} );
} else {
if ( $mode == 'restart' ) {
if ( ZM_OPT_CONTROL ) {
daemonControl( 'stop', 'zmtrack.pl', '-m '.$this->{'Id'} );
}
daemonControl( 'stop', 'zma', '-m '.$this->{'Id'} );
}
daemonControl( 'start', 'zma', '-m '.$this->{'Id'} );
if ( ZM_OPT_CONTROL && $this->{'Controllable'} && $this->{'TrackMotion'} && ( $this->{'Function'} == 'Modect' || $this->{'Function'} == 'Mocord' ) ) {
daemonControl( 'start', 'zmtrack.pl', '-m '.$this->{'Id'} );
}
if ( $mode == 'reload' ) {
daemonControl( 'reload', 'zma', '-m '.$this->{'Id'} );
}
}
} // end if we are on the recording server
}
} // end class Monitor
?>

View File

@ -0,0 +1,122 @@
<?php
require_once('database.php');
class MontageLayout {
private $defaults = array(
'Id' => null,
'Name' => '',
'Positions' => 0,
);
public function __construct( $IdOrRow = NULL ) {
if ( $IdOrRow ) {
$row = NULL;
if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) {
$row = dbFetchOne( 'SELECT * FROM MontageLayouts WHERE Id=?', NULL, array( $IdOrRow ) );
if ( ! $row ) {
Error("Unable to load MontageLayout record for Id=" . $IdOrRow );
}
} elseif ( is_array( $IdOrRow ) ) {
$row = $IdOrRow;
} else {
Error("Unknown argument passed to MontageLayout Constructor ($IdOrRow)");
return;
}
if ( $row ) {
foreach ($row as $k => $v) {
$this->{$k} = $v;
}
} else {
Error('No row for MontageLayout ' . $IdOrRow );
}
} # end if isset($IdOrRow)
} // end function __construct
public function __call($fn, array $args){
if ( count($args) ) {
$this->{$fn} = $args[0];
}
if ( array_key_exists($fn, $this) ) {
return $this->{$fn};
} else {
if ( array_key_exists( $fn, $this->defaults ) ) {
return $this->defaults{$fn};
} else {
$backTrace = debug_backtrace();
$file = $backTrace[1]['file'];
$line = $backTrace[1]['line'];
Warning( "Unknown function call MontageLayout->$fn from $file:$line" );
}
}
}
public function set( $data ) {
foreach ($data as $k => $v) {
if ( is_array( $v ) ) {
# perhaps should turn into a comma-separated string
$this->{$k} = implode(',',$v);
} else if ( is_string( $v ) ) {
$this->{$k} = trim( $v );
} else if ( is_integer( $v ) ) {
$this->{$k} = $v;
} else if ( is_bool( $v ) ) {
$this->{$k} = $v;
} else {
Error( "Unknown type $k => $v of var " . gettype( $v ) );
$this->{$k} = $v;
}
}
}
public static function find( $parameters = null, $options = null ) {
$filters = array();
$sql = 'SELECT * FROM MontageLayouts ';
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = $field.' IS NULL';
} else if ( is_array( $value ) ) {
$func = function(){return '?';};
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
$values += $value;
} else {
$fields[] = $field.'=?';
$values[] = $value;
}
}
$sql .= implode(' AND ', $fields );
}
if ( $options and isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
$result = dbQuery($sql, $values);
if ( $result ) {
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'MontageLayout');
foreach ( $results as $row => $obj ) {
$filters[] = $obj;
}
}
return $filters;
}
public function save( $new_values = null ) {
if ( $new_values ) {
foreach ( $new_values as $k=>$v ) {
$this->{$k} = $v;
}
}
$sql = 'UPDATE MontageLayouts SET '.implode(', ', array_map( function($field) {return $field.'=?';}, array_keys( $this->defaults ) ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $this->fields );
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
} // end function save
} // end class MontageLayout
?>

View File

@ -113,7 +113,9 @@ class Storage {
if ( ! array_key_exists( 'disk_used_space', $this ) ) {
$used = 0;
if ( $this->{'Type'} == 's3fs' ) {
foreach ( Event::find_all( array( 'StorageId'=>$this->Id() ) ) as $Event ) {
$used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) );
foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) {
$Event->Storage( $this ); // Prevent further db hit
$used += $Event->DiskSpace();
}

View File

@ -23,6 +23,28 @@
// credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/
function do_request($method, $url, $data=array(), $optional_headers = null) {
global $php_errormsg;
$params = array('http' => array(
'method' => $method,
'content' => $data
));
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url, $php_errormsg");
}
$response = @stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url, $php_errormsg");
}
return $response;
}
function do_post_request($url, $data, $optional_headers = null) {
$params = array('http' => array(
'method' => 'POST',
@ -148,6 +170,7 @@ Warning("Addterm");
$sql .= ', AutoExecute = '. ( !empty($_REQUEST['filter']['AutoExecute']) ? 1 : 0);
$sql .= ', AutoExecuteCmd = '.dbEscape($_REQUEST['filter']['AutoExecuteCmd']);
$sql .= ', AutoDelete = '. ( !empty($_REQUEST['filter']['AutoDelete']) ? 1 : 0);
$sql .= ', UpdateDiskSpace = '. ( !empty($_REQUEST['filter']['UpdateDiskSpace']) ? 1 : 0);
$sql .= ', Background = '. ( !empty($_REQUEST['filter']['Background']) ? 1 : 0);
$sql .= ', Concurrent = '. ( !empty($_REQUEST['filter']['Concurrent']) ? 1 : 0);
@ -266,6 +289,30 @@ Warning("Addterm");
}
}
if ( isset($_REQUEST['object']) and $_REQUEST['object'] == 'Monitor' ) {
if ( $action == 'save' ) {
foreach ( $_REQUEST['mids'] as $mid ) {
$mid = ValidInt( $mid );
if ( ! canEdit('Monitors', $mid ) ) {
Warning("Cannot edit monitor $mid");
continue;
}
$Monitor = new Monitor( $mid );
$Monitor->zmaControl('stop');
$Monitor->zmcControl('stop');
$Monitor->save( $_REQUEST['newMonitor'] );
if ($Monitor->Function() != 'None' ) {
$Monitor->zmcControl('start');
if ( $Monitor->Enabled() ) {
$Monitor->zmaControl('start');
}
}
} // end foreach mid
$refreshParent = true;
} // end if action == save
} // end if object is Monitor
// Monitor edit actions, require a monitor id and edit permissions for that monitor
if ( !empty($_REQUEST['mid']) && canEdit( 'Monitors', $_REQUEST['mid'] ) ) {
$mid = validInt($_REQUEST['mid']);

View File

@ -127,10 +127,10 @@ function dbQuery( $sql, $params=NULL ) {
} else {
$result = $dbConn->query( $sql );
}
//if ( $params )
//Warning("SQL: $sql" . implode(',',$params));
//else
//Warning("SQL: $sql" );
if ( $params )
Warning("SQL: $sql" . implode(',',$params));
else
Warning("SQL: $sql" );
} catch(PDOException $e) {
Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . implode(',',$params) );
}

View File

@ -853,81 +853,17 @@ function daemonControl( $command, $daemon=false, $args=false ) {
}
function zmcControl( $monitor, $mode=false ) {
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$monitor['ServerId'] ) ) {
$row = NULL;
if ( $monitor['Type'] == 'Local' ) {
$row = dbFetchOne( "SELECT count(if(Function!='None',1,NULL)) AS ActiveCount FROM Monitors WHERE Device = ?", NULL, array($monitor['Device']) );
$zmcArgs = '-d '.$monitor['Device'];
} else {
$row = dbFetchOne( "SELECT count(if(Function!='None',1,NULL)) AS ActiveCount FROM Monitors WHERE Id = ?", NULL, array($monitor['Id']) );
$zmcArgs = '-m '.$monitor['Id'];
}
$activeCount = $row['ActiveCount'];
if ( (!$activeCount) || ($mode == 'stop') ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
} else {
if ( $mode == 'restart' ) {
daemonControl( 'stop', 'zmc', $zmcArgs );
}
daemonControl( 'start', 'zmc', $zmcArgs );
}
} else {
$Server = new Server( $monitor['ServerId'] );
$url = $Server->Url() . '/zm/api/monitors/'.$monitor['Id'].'.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '&auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
$url = '&user='.$_SESSION['username'];
$url = '&pass='.$_SESSION['password'];
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$url = '&user='.$_SESSION['username'];
}
}
$data = array('Monitor[Function]' => $monitor['Function'] );
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
}
$Monitor = new Monitor( $monitor );
return $Monitor->zmcControl($mode);
}
function zmaControl( $monitor, $mode=false ) {
if ( !is_array( $monitor ) ) {
$monitor =
$monitor = dbFetchOne( 'select C.*, M.* from Monitors as M left join Controls as C on (M.ControlId = C.Id ) where M.Id=?', NULL, array($monitor) );
}
if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$monitor['ServerId'] ) ) {
if ( !$monitor || $monitor['Function'] == 'None' || $monitor['Function'] == 'Monitor' || $mode == 'stop' ) {
if ( ZM_OPT_CONTROL ) {
daemonControl( 'stop', 'zmtrack.pl', '-m '.$monitor['Id'] );
}
daemonControl( 'stop', 'zma', '-m '.$monitor['Id'] );
} else {
if ( $mode == 'restart' ) {
if ( ZM_OPT_CONTROL ) {
daemonControl( 'stop', 'zmtrack.pl', '-m '.$monitor['Id'] );
}
daemonControl( 'stop', 'zma', '-m '.$monitor['Id'] );
}
daemonControl( 'start', 'zma', '-m '.$monitor['Id'] );
if ( ZM_OPT_CONTROL && $monitor['Controllable'] && $monitor['TrackMotion'] && ( $monitor['Function'] == 'Modect' || $monitor['Function'] == 'Mocord' ) ) {
daemonControl( 'start', 'zmtrack.pl', '-m '.$monitor['Id'] );
}
if ( $mode == 'reload' ) {
daemonControl( 'reload', 'zma', '-m '.$monitor['Id'] );
}
}
} // end if we are on the recording server
$Monitor = new Monitor( $monitor );
$Monitor->zmaControl($mode);
}
function initDaemonStatus() {
@ -1121,10 +1057,17 @@ function parseSort( $saveToSession=false, $querySep='&amp;' ) {
$sortColumn = 'E.Cause';
break;
case 'DateTime' :
$_REQUEST['sort_field'] = 'StartTime';
$sortColumn = 'E.StartTime';
break;
case 'DiskSpace' :
$sortColumn = 'E.DiskSpace';
break;
case 'StartTime' :
$sortColumn = 'E.StartTime';
break;
case 'EndTime' :
$sortColumn = 'E.EndTime';
break;
case 'Length' :
$sortColumn = 'E.Length';
break;
@ -1190,6 +1133,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case 'ServerId':
$filter['sql'] .= 'M.ServerId';
break;
# Unspecified start or end, so assume start, this is to support legacy filters
case 'DateTime':
$filter['sql'] .= 'E.StartTime';
break;
@ -1202,8 +1146,35 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case 'Weekday':
$filter['sql'] .= 'weekday( E.StartTime )';
break;
# Starting Time
case 'StartDateTime':
$filter['sql'] .= 'E.StartTime';
break;
case 'StartDate':
$filter['sql'] .= 'to_days( E.StartTime )';
break;
case 'StartTime':
$filter['sql'] .= 'extract( hour_second from E.StartTime )';
break;
case 'StartWeekday':
$filter['sql'] .= 'weekday( E.StartTime )';
break;
# Ending Time
case 'EndDateTime':
$filter['sql'] .= 'E.EndTime';
break;
case 'EndDate':
$filter['sql'] .= 'to_days( E.EndTime )';
break;
case 'EndTime':
$filter['sql'] .= 'extract( hour_second from E.EndTime )';
break;
case 'EndWeekday':
$filter['sql'] .= 'weekday( E.EndTime )';
break;
case 'Id':
case 'Name':
case 'DiskSpace':
case 'MonitorId':
case 'StorageId':
case 'Length':
@ -1303,6 +1274,10 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&amp;' ) {
case '![]' :
$filter['sql'] .= ' not in ('.join( ',', $valueList ).')';
break;
case 'IS' :
$filter['sql'] .= " IS $value";
case 'IS NOT' :
$filter['sql'] .= " IS NOT $value";
}
$filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']);
@ -1917,7 +1892,8 @@ function logState() {
Logger::WARNING => array( ZM_LOG_ALERT_WAR_COUNT, ZM_LOG_ALARM_WAR_COUNT ),
);
$sql = "select Level, count(Level) as LevelCount from Logs where Level < ".Logger::INFO." and TimeKey > unix_timestamp(now() - interval ".ZM_LOG_CHECK_PERIOD." second) group by Level order by Level asc";
# This is an expensive request, as it has to hit every row of the Logs Table
$sql = 'SELECT Level, COUNT(Level) AS LevelCount FROM Logs WHERE Level < '.Logger::INFO.' AND TimeKey > unix_timestamp(now() - interval '.ZM_LOG_CHECK_PERIOD.' second) GROUP BY Level ORDER BY Level ASC';
$counts = dbFetchAll( $sql );
foreach ( $counts as $count ) {

View File

@ -34,7 +34,7 @@ if ( version_compare( phpversion(), '4.1.0', '<') ) {
}
// Useful debugging lines for mobile devices
if ( false ) {
if ( true ) {
ob_start();
phpinfo( INFO_VARIABLES );
$fp = fopen( '/tmp/env.html', 'w' );

View File

@ -116,8 +116,11 @@ $SLANG = array(
'AttrArchiveStatus' => 'Archive Status',
'AttrAvgScore' => 'Avg. Score',
'AttrCause' => 'Cause',
'AttrDate' => 'Date',
'AttrDateTime' => 'Date/Time',
'AttrStartDate' => 'Start Date',
'AttrEndDate' => 'End Date',
'AttrStartDateTime' => 'Start Date/Time',
'AttrEndDateTime' => 'End Date/Time',
'AttrDiskSpace' => 'Disk Space',
'AttrDiskBlocks' => 'Disk Blocks',
'AttrDiskPercent' => 'Disk Percent',
'AttrDuration' => 'Duration',
@ -132,9 +135,11 @@ $SLANG = array(
'AttrName' => 'Name',
'AttrNotes' => 'Notes',
'AttrSystemLoad' => 'System Load',
'AttrTime' => 'Time',
'AttrStartTime' => 'Start Time',
'AttrEndTime' => 'End Time',
'AttrTotalScore' => 'Total Score',
'AttrWeekday' => 'Weekday',
'AttrStartWeekday' => 'Start Weekday',
'AttrEndWeekday' => 'End Weekday',
'Auto' => 'Auto',
'AutoStopTimeout' => 'Auto Stop Timeout',
'Available' => 'Available',
@ -334,6 +339,7 @@ $SLANG = array(
'Ffmpeg' => 'Ffmpeg',
'File' => 'File',
'FilterArchiveEvents' => 'Archive all matches',
'FilterUpdateDiskSpace' => 'Update used disk space',
'FilterDeleteEvents' => 'Delete all matches',
'FilterEmailEvents' => 'Email details of all matches',
'FilterExecuteEvents' => 'Execute command on all matches',
@ -413,6 +419,7 @@ $SLANG = array(
'LimitResultsPre' => 'Limit to first', // This is used at the beginning of the phrase 'Limit to first N results only'
'LinkedMonitors' => 'Linked Monitors',
'List' => 'List',
'ListMatches' => 'List Matches',
'Load' => 'Load',
'Local' => 'Local',
'Log' => 'Log',
@ -549,6 +556,8 @@ $SLANG = array(
'OpNe' => 'not equal to',
'OpNotIn' => 'not in set',
'OpNotMatches' => 'does not match',
'OpIs' => 'is',
'OpIsNot' => 'is not',
'OptionalEncoderParam' => 'Optional Encoder Parameters',
'OptionHelp' => 'Option Help',
'OptionRestartWarning' => 'These changes may not come into effect fully\nwhile the system is running. When you have\nfinished making your changes please ensure that\nyou restart ZoneMinder.',

View File

@ -1,6 +1,10 @@
.vjsMessage {
font-size: 2em;
line-height: 1.5;
#content .vjsMessage {
width: 100%;
position: absolute;
left: 0;
z-index: 10;
margin: 0;
font-size: 200%;
color: white;
background-color: black;
display: inline-block;
@ -40,6 +44,7 @@ span.noneCue {
#eventVideo {
display: inline-block;
postion: relative;
}
#menuBar1 {
@ -112,6 +117,8 @@ span.noneCue {
}
#imageFeed {
display: inline-block;
position: relative;
text-align: center;
}

View File

@ -1,6 +1,10 @@
.vjsMessage {
font-size: 2em;
line-height: 1.5;
#content .vjsMessage {
width: 100%;
position: absolute;
left: 0;
z-index: 10;
margin: 0;
font-size: 200%;
color: white;
background-color: black;
display: inline-block;
@ -95,6 +99,8 @@ span.noneCue {
}
#imageFeed {
display: inline-block;
position: relative;
text-align: center;
}
@ -255,7 +261,8 @@ span.noneCue {
}
#eventVideo {
display: inline-block;
display: inline-block;
position: relative;
}
#thumbsKnob {

View File

@ -1,6 +1,10 @@
.vjsMessage {
font-size: 2em;
line-height: 1.5;
#content .vjsMessage {
width: 100%;
position: absolute;
left: 0;
z-index: 10;
margin: 0;
font-size: 200%;
color: white;
background-color: black;
display: inline-block;
@ -100,6 +104,8 @@ span.noneCue {
visibility: hidden;
}
#imageFeed {
display: inline-block;
position: relative;
text-align: center;
}
@ -272,6 +278,7 @@ span.noneCue {
}
#eventVideo {
display: inline-block;
position: relative;
}
#video-controls {

View File

@ -31,6 +31,7 @@ $rates = array(
);
$scales = array(
'auto' => translate('Scale to Fit'),
'' => translate('Fixed Width/Height'),
'400' => '4x',
'300' => '3x',
@ -44,6 +45,8 @@ $scales = array(
'12.5' => '1/8x',
);
if (isset($_REQUEST['view'])) unset($scales[$_REQUEST['view'] == 'event' ? '' : 'auto']); //Remove the option we aren't using on montage or event
$bandwidth_options = array(
'high' => translate('High'),
'medium' => translate('Medium'),

View File

@ -194,9 +194,19 @@ ZoneMinder requires Javascript. Please enable Javascript in your browser for thi
<li><a href="?view=console"><?php echo translate('Console') ?></a></li>
<?php if ( canView( 'System' ) ) { ?>
<li><a href="?view=options"><?php echo translate('Options') ?></a></li>
<li><?php if ( logToDatabase() > Logger::NOLOG ) { ?> <?php echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' ) ?><?php } ?></li>
<?php } ?>
<?php if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
<li>
<?php
if ( logToDatabase() > Logger::NOLOG ) {
if ( ! ZM_RUN_AUDIT ) {
# zmaudit can clean the logs, but if we aren't running it, then we should clecan them regularly
dbQuery("DELETE FROM Logs WHERE TimeKey < NOW()-to_days('".ZM_LOG_DATABASE_LIMIT."')");
}
echo makePopupLink( '?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>' );
}
} // end if canview(System)
?></li>
<?php
if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
<li><a href="?view=devices">Devices</a></li>
<?php } ?>
<li><a href="?view=groups"<?php echo $view=='groups'?' class="selected"':''?>><?php echo translate('Groups') ?></a></li>

View File

@ -41,7 +41,7 @@ var popupSizes = {
'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 },
'frames': { 'width': 600, 'height': 700 },
'function': { 'width': 400, 'height': 250 },
'group': { 'width': 360, 'height': 320 },
'group': { 'width': 660, 'height': 520 },
'groups': { 'width': 440, 'height': 220 },
'image': { 'addWidth': 48, 'addHeight': 80 },
'log': { 'width': 1080, 'height': 720 },
@ -51,6 +51,7 @@ var popupSizes = {
'monitorpreset':{ 'width': 440, 'height': 200 },
'monitorprobe': { 'width': 500, 'height': 240 },
'monitorselect':{ 'width': 160, 'height': 200 },
'monitors': { 'width': 300, 'height': 640 },
'montage': { 'width': -1, 'height': -1 },
'onvifprobe': { 'width': 700, 'height': 550 },
'optionhelp': { 'width': 400, 'height': 320 },

View File

@ -283,6 +283,17 @@ function convertLabelFormat(LabelFormat, monitorName){
}
function addVideoTimingTrack(video, LabelFormat, monitorName, duration, startTime){
//This is a hacky way to handle changing the texttrack. If we ever upgrade vjs in a revamp replace this. Old method preserved because it's the right way.
let cues = vid.textTracks()[0].cues();
let labelFormat = convertLabelFormat(LabelFormat, monitorName);
startTime = moment(startTime);
for (let i = 0; i <= duration; i++) {
cues[i] = {id: i, index: i, startTime: i, Ca: i+1, text: startTime.format(labelFormat)};
startTime.add(1, 's');
}
}
/*
var labelFormat = convertLabelFormat(LabelFormat, monitorName);
var webvttformat = 'HH:mm:ss.SSS', webvttdata="WEBVTT\n\n";
@ -304,6 +315,7 @@ function addVideoTimingTrack(video, LabelFormat, monitorName, duration, startTim
track.src = 'data:plain/text;charset=utf-8,'+encodeURIComponent(webvttdata);
video.appendChild(track);
}
*/
function changeGroup( e, depth ) {
var group_id = $('group'+depth).get('value');

View File

@ -14,7 +14,7 @@
font-size: .3em;
}
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar.vjs-zm {
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
visibility: visible;
opacity: 1;
bottom: -2em;

View File

@ -177,11 +177,29 @@ $groupSql = Group::get_group_sql( $group_id );
$displayMonitors = array();
$monitors_dropdown = array(''=>'All');
if ( $monitor_id ) {
$found_selected_monitor = false;
for ( $i = 0; $i < count($monitors); $i++ ) {
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
continue;
}
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
if ( $monitors[$i]['Id'] == $monitor_id ) {
$found_selected_monitor = true;
}
}
if ( ! $found_selected_monitor ) {
$monitor_id = '';
}
}
for ( $i = 0; $i < count($monitors); $i++ ) {
if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) {
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
continue;
}
if ( !visibleMonitor( $monitors[$i]['Id'] ) ) {
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
if ( $monitor_id and ( $monitors[$i]['Id'] != $monitor_id ) ) {
continue;
}
if ( $monitors[$i]['Function'] != 'None' ) {
@ -191,7 +209,6 @@ $groupSql = Group::get_group_sql( $group_id );
if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight;
}
$displayMonitors[] = $monitors[$i];
$monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name'];
}
@ -210,10 +227,10 @@ for( $i = 0; $i < count($displayMonitors); $i += 1 ) {
for ( $j = 0; $j < count($eventCounts); $j += 1 ) {
$filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) );
parseFilter( $filter );
$counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) as EventCount$j";
$counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) AS EventCount$j, SUM(if(1".$filter['sql'].",DiskSpace,NULL)) As DiskSpace$j";
$monitor['eventCounts'][$j]['filter'] = $filter;
}
$sql = 'SELECt '.join($counts,', ').' from Events as E where MonitorId = ?';
$sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?';
$counts = dbFetchOne( $sql, NULL, array($monitor['Id']) );
if ( $counts )
$displayMonitors[$i] = $monitor = array_merge( $monitor, $counts );
@ -241,6 +258,17 @@ echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSIO
<?php
}
?>
<span class="StatusFilter"><label><?php echo translate('Status')?>:</label>
<?php
$status_options = array(
''=>'All',
'Unknown' => translate('Unknown'),
'NotRunning' => translate('NotRunning'),
'Running' => translate('Running'),
);
echo htmlSelect( 'StatusFilter', $status_options, ( isset($_SESSION['StatusFilter']) ? $_SESSION['StatusFilter'] : '' ), array('onchange'=>'changeFilter(this);') );
?>
</span>
</div>
<div class="container-fluid">
@ -331,7 +359,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
for ( $i = 0; $i < count($eventCounts); $i++ ) {
?>
<td class="colEvents"><?php echo makePopupLink( '?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$monitor['eventCounts'][$i]['filter']['query'], $eventsWindow, ZM_WEB_EVENTS_VIEW, $monitor['EventCount'.$i], canView( 'Events' ) ) ?></td>
<td class="colEvents"><?php echo makePopupLink( '?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$monitor['eventCounts'][$i]['filter']['query'], $eventsWindow, ZM_WEB_EVENTS_VIEW,
$monitor['EventCount'.$i] . '<br/>' . human_filesize($monitor['DiskSpace'.$i]), canView( 'Events' ) ) ?></td>
<?php
}
?>
@ -356,7 +385,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<td class="colId"><?php echo count($displayMonitors) ?></td>
<td class="colLeftButtons" colspan="<?php echo $left_columns -1?>">
<input type="button" value="<?php echo translate('Refresh') ?>" onclick="location.reload(true);"/>
<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>
<input type="button" value="<?php echo translate('AddNewMonitor') ?>" onclick="location.href='index.php?view=add_monitors';"/>
<!--<input type="button" name="addBtn" value="<?php echo translate('AddNewMonitor') ?>" onclick="addMonitor( this )"/>-->
<!-- <?php echo makePopupButton( '?view=monitor', 'zmMonitor0', 'monitor', translate('AddNewMonitor'), (canEdit( 'Monitors' ) && !$user['MonitorIds']) ) ?> -->
<?php echo makePopupButton( '?view=filter&amp;filter[terms][0][attr]=DateTime&amp;filter[terms][0][op]=%3c&amp;filter[terms][0][val]=now', 'zmFilter', 'filter', translate('Filters'), canView( 'Events' ) ) ?>
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editMonitor( this )" disabled="disabled"/>

View File

@ -36,14 +36,17 @@ if ( $user['MonitorIds'] ) {
}
$Monitor = $Event->Monitor();
if ( isset( $_REQUEST['rate'] ) )
if (isset($_REQUEST['rate'])) {
$rate = validInt($_REQUEST['rate']);
else
$rate = reScale( RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE );
} else {
$rate = reScale(RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE);
}
if ( isset( $_REQUEST['scale'] ) ) {
if (isset($_REQUEST['scale'])) {
$scale = validInt($_REQUEST['scale']);
} else if ( isset( $_COOKIE['zmEventScale'.$Event->MonitorId()] ) ) {
} else if (isset($_COOKIE['zmEventScaleAuto'])) { //If we're using scale to fit use it on all monitors
$scale = 'auto';
} else if (isset($_COOKIE['zmEventScale'.$Event->MonitorId()])) {
$scale = $_COOKIE['zmEventScale'.$Event->MonitorId()];
} else {
$scale = reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE );
@ -153,20 +156,11 @@ if ( $Event->DefaultVideo() ) {
<div id="videoFeed">
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $Event->Width(), $scale ) ?>" height="<?php echo reScale( $Event->Height(), $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'>
<source src="<?php echo $Event->getStreamSrc( array( 'mode'=>'mpeg','format'=>'h264' ) ); ?>" type="video/mp4">
<track id="monitorCaption" kind="captions" label="English" srclang="en" src='data:plain/text;charset=utf-8,"WEBVTT\n\n 00:00:00.000 --> 00:00:01.000 ZoneMinder"' default>
Your browser does not support the video tag.
</video>
</div>
<!--script>includeVideoJs();</script-->
<script type="text/javascript">
var LabelFormat = "<?php echo validJsStr($Monitor->LabelFormat())?>";
var monitorName = "<?php echo validJsStr($Monitor->Name())?>";
var duration = <?php echo $Event->Length() ?>, startTime = '<?php echo $Event->StartTime() ?>';
addVideoTimingTrack(document.getElementById('videoobj'), LabelFormat, monitorName, duration, startTime);
nearEventsQuery( eventData.Id );
vjsReplay(<?php echo (strtotime($Event->StartTime()) + $Event->Length())*1000 ?>);
</script>
<p id="dvrControls" class="dvrControls">
<input type="button" value="&lt;+" id="prevBtn" title="<?php echo translate('Prev') ?>" class="inactive" onclick="streamPrev( true );"/>
@ -191,7 +185,7 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) {
}
} // end if stream method
?>
<div id="alarmCueJpeg" class="alarmCue" style="width: <?php echo reScale($Event->Width(), $scale);?>px;"></div>
<div id="alarmCue" class="alarmCue" style="width: <?php echo reScale($Event->Width(), $scale);?>px;"></div>
<div id="progressBar" style="width: <?php echo reScale($Event->Width(), $scale);?>px;">
<div class="progressBox" id="progressBox" title="" style="width: 0%;"></div>
</div><!--progressBar-->

View File

@ -69,10 +69,14 @@ $attrTypes = array(
'Name' => translate('AttrName'),
'Cause' => translate('AttrCause'),
'Notes' => translate('AttrNotes'),
'DateTime' => translate('AttrDateTime'),
'Date' => translate('AttrDate'),
'Time' => translate('AttrTime'),
'Weekday' => translate('AttrWeekday'),
'StartDateTime' => translate('AttrStartDateTime'),
'StartDate' => translate('AttrStartDate'),
'StartTime' => translate('AttrStartTime'),
'StartWeekday' => translate('AttrStartWeekday'),
'EndDateTime' => translate('AttrEndDateTime'),
'EndDate' => translate('AttrEndDate'),
'EndTime' => translate('AttrEndTime'),
'EndWeekday' => translate('AttrEndWeekday'),
'Length' => translate('AttrDuration'),
'Frames' => translate('AttrFrames'),
'AlarmFrames' => translate('AttrAlarmFrames'),
@ -80,8 +84,9 @@ $attrTypes = array(
'AvgScore' => translate('AttrAvgScore'),
'MaxScore' => translate('AttrMaxScore'),
'Archived' => translate('AttrArchiveStatus'),
'DiskPercent' => translate('AttrDiskPercent'),
'DiskBlocks' => translate('AttrDiskBlocks'),
'DiskPercent' => translate('AttrDiskPercent'),
'DiskSpace' => translate('AttrDiskSpace'),
'SystemLoad' => translate('AttrSystemLoad'),
'StorageId' => translate('AttrStorageArea'),
'ServerId' => translate('AttrServer'),
@ -99,6 +104,8 @@ $opTypes = array(
'!~' => translate('OpNotMatches'),
'=[]' => translate('OpIn'),
'![]' => translate('OpNotIn'),
'IS' => translate('OpIs'),
'IS NOT' => translate('OpIsNot'),
);
$archiveTypes = array(
@ -297,18 +304,19 @@ if ( count($terms) == 0 ) {
<label for="filter[Query][sort_field]"><?php echo translate('SortBy') ?></label>
<?php
$sort_fields = array(
'Id' => translate('AttrId'),
'Name' => translate('AttrName'),
'Cause' => translate('AttrCause'),
'Notes' => translate('AttrNotes'),
'MonitorName' => translate('AttrMonitorName'),
'DateTime' => translate('AttrDateTime'),
'Length' => translate('AttrDuration'),
'Frames' => translate('AttrFrames'),
'AlarmFrames' => translate('AttrAlarmFrames'),
'TotScore' => translate('AttrTotalScore'),
'AvgScore' => translate('AttrAvgScore'),
'MaxScore' => translate('AttrMaxScore'),
'Id' => translate('AttrId'),
'Name' => translate('AttrName'),
'Cause' => translate('AttrCause'),
'DiskSpace' => translate('AttrDiskSpace'),
'Notes' => translate('AttrNotes'),
'MonitorName' => translate('AttrMonitorName'),
'StartDateTime' => translate('AttrStartDateTime'),
'Length' => translate('AttrDuration'),
'Frames' => translate('AttrFrames'),
'AlarmFrames' => translate('AttrAlarmFrames'),
'TotScore' => translate('AttrTotalScore'),
'AvgScore' => translate('AttrAvgScore'),
'MaxScore' => translate('AttrMaxScore'),
);
echo htmlSelect( 'filter[Query][sort_field]', $sort_fields, $filter->sort_field() );
$sort_dirns = array(
@ -332,6 +340,9 @@ echo htmlSelect( 'filter[Query][sort_asc]', $sort_dirns, $filter->sort_asc() );
<label><?php echo translate('FilterArchiveEvents') ?></label>
<input type="checkbox" name="filter[AutoArchive]" value="1"<?php if ( !empty($filter->AutoArchive()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
</p>
<p><label><?php echo translate('FilterUpdateDiskSpace') ?></label>
<input type="checkbox" name="filter[UpdateDiskSpace]" value="1"<?php echo empty($filter->UpdateDiskSpace()) ? '' : ' checked="checked"' ?> onclick="updateButtons(this);"/>
</p>
<?php
if ( ZM_OPT_FFMPEG ) {
?>
@ -387,7 +398,7 @@ if ( ZM_OPT_MESSAGE ) {
</div>
<hr/>
<div id="contentButtons">
<input type="submit" value="<?php echo translate('Submit') ?>" onclick="submitToEvents( this );"/>
<input type="submit" value="<?php echo translate('ListMatches') ?>" onclick="submitToEvents( this );"/>
<input type="button" name="executeButton" id="executeButton" value="<?php echo translate('Execute') ?>" onclick="executeFilter( this );"/>
<?php
if ( canEdit( 'Events' ) ) {

View File

@ -13,13 +13,13 @@ function setButtonStates( element ) {
}
}
$(element).closest("tr").toggleClass("danger");
form.editBtn.disabled = (checked!=1);
form.editBtn.disabled = checked ? false : true;
form.addBtn.value = (checked==1) ? jsTranslatedCloneText:jsTranslatedAddText;
form.deleteBtn.disabled = (checked==0);
}
function addMonitor( element) {
function addMonitor(element) {
var form = element.form;
var dupParam;
var monitorId=-1;
@ -40,18 +40,23 @@ function addMonitor( element) {
function editMonitor( element ) {
var form = element.form;
var monitorIds = Array();
for ( var i = 0; i < form.elements.length; i++ ) {
if ( form.elements[i].type == "checkbox" ) {
if ( form.elements[i].checked ) {
var monitorId = form.elements[i].value;
createPopup( '?view=monitor&mid='+monitorId, 'zmMonitor'+monitorId, 'monitor' );
form.elements[i].checked = false;
setButtonStates( form.elements[i] );
monitorIds.push( form.elements[i].value );
//form.elements[i].checked = false;
//setButtonStates( form.elements[i] );
//$(form.elements[i]).getParent( 'tr' ).removeClass( 'highlight' );
break;
//break;
}
}
}
} // end foreach checkboxes
if ( monitorIds.length == 1 )
createPopup( '?view=monitor&mid='+monitorIds[0], 'zmMonitor'+monitorIds[0], 'monitor' );
else if ( monitorIds.length > 1 )
createPopup( '?view=monitors&'+(monitorIds.map(function(mid){return 'mids[]='+mid;}).join('&')), 'zmMonitors', 'monitors' );
}
function deleteMonitor( element ) {

View File

@ -1,9 +1,10 @@
var vid = null;
function vjsReplay(endTime) {
var video = videojs('videoobj').ready(function(){
function vjsReplay() {
vid.ready(function(){
var player = this;
player.on('ended', function() {
var endTime = (Date.parse(eventData.EndTime)).getTime();
switch(replayMode.value) {
case 'none':
break;
@ -12,19 +13,23 @@ function vjsReplay(endTime) {
break;
case 'all':
if (nextEventId == 0) {
$j("#videoobj").html('<p class="vjsMessage">No more events</p>');
let overLaid = $j("#videoobj");
overLaid.append('<p class="vjsMessage" style="height: '+overLaid.height()+'px; line-height: '+overLaid.height()+'px;">No more events</p>');
} else {
var nextStartTime = nextEventStartTime.getTime(); //nextEventStartTime.getTime() is a mootools workaround, highjacks Date.parse
if (nextStartTime <= endTime) {
streamNext( true );
return;
}
$j("#videoobj").html('<p class="vjsMessage"></p>');
let overLaid = $j("#videoobj");
vid.pause();
overLaid.append('<p class="vjsMessage" style="height: '+overLaid.height()+'px; line-height: '+overLaid.height()+'px;"></p>');
var gapDuration = (new Date().getTime()) + (nextStartTime - endTime);
let messageP = $j(".vjsMessage");
var x = setInterval(function() {
var now = new Date().getTime();
var remainder = new Date(Math.round(gapDuration - now)).toISOString().substr(11,8);
$j(".vjsMessage").html(remainder + ' to next event.');
messageP.html(remainder + ' to next event.');
if (remainder < 0) {
clearInterval(x);
streamNext( true );
@ -51,17 +56,12 @@ function initialAlarmCues (eventId) {
function setAlarmCues (data) {
cueFrames = data.event.Frame;
alarmSpans = renderAlarmCues();
if ( vid ) {
$j(".vjs-progress-control").append('<div class="alarmCue">' + alarmSpans + '</div>');
$j(".vjs-control-bar").addClass("vjs-zm");
} else {
$j("#alarmCueJpeg").html(alarmSpans);
}
$j(".alarmCue").html(alarmSpans);
}
function renderAlarmCues () {
if (cueFrames) {
var cueRatio = (vid ? $j("#videoobj").width() : $j("#evtStream").width()) / (cueFrames[cueFrames.length - 1].Delta * 100);//use videojs width or nph-zms width
var cueRatio = (vid ? $j("#videoobj").width() : $j("#evtStream").width()) / (cueFrames[cueFrames.length - 1].Delta * 100);//use videojs width or zms width
var minAlarm = Math.ceil(1/cueRatio);
var spanTimeStart = 0;
var spanTimeEnd = 0;
@ -118,6 +118,7 @@ function renderAlarmCues () {
spanTime = spanTimeEnd - spanTimeStart;
alarmed = 0;
pix = Math.round(cueRatio * spanTime);
if (pixSkew >= .5 || pixSkew <= -.5) pix += Math.round(pixSkew);
alarmHtml += '<span class="alarmCue" style="width: ' + pix + 'px;"></span>';
}
}
@ -134,27 +135,54 @@ function setButtonState( element, butClass ) {
}
}
var resizeTimer;
function endOfResize(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(changeScale, 250);
}
function scaleToFit () {
$j(window).on('resize', endOfResize) //set delayed scaling when Scale to Fit is selected
let ratio = eventData.Width/eventData.Height;
let container = $j('#content');
let feed = $j(vid ? '#videoobj' : '#evtStream');
let viewPort = $j(window);
let newHeight = viewPort.height() - (container.outerHeight(true) - feed.outerHeight(true));
let newWidth = ratio * newHeight;
if (newWidth > container.innerWidth()) {
newWidth = container.innerWidth();
newHeight = newWidth / ratio;
}
return {width: Math.floor(newWidth), height: Math.floor(newHeight)};
}
function changeScale() {
var scale = $('scale').get('value');
var baseWidth = eventData.Width;
var baseHeight = eventData.Height;
var newWidth = ( baseWidth * scale ) / SCALE_BASE;
var newHeight = ( baseHeight * scale ) / SCALE_BASE;
if ( vid ) {
// Using video.js
$j("#videoobj").width(newWidth);
$j("#videoobj").height(newHeight);
$j("div.alarmCue").html(renderAlarmCues());//just re-render alarmCues. skip ajax call
Cookie.write( 'zmEventScale'+eventData.MonitorId, scale, { duration: 10*365 } );
let scale = $j('#scale').val();
if (scale == "auto") {
let newSize = scaleToFit();
var newWidth = newSize.width;
var newHeight = newSize.height;
} else {
streamScale( scale );
var streamImg = document.getElementById('evtStream');
streamImg.style.width = newWidth + "px";
streamImg.style.height = newHeight + "px";
$j("#alarmCueJpeg").width(newWidth);
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
var newWidth = eventData.Width * scale / SCALE_BASE;
var newHeight = eventData.Height * scale / SCALE_BASE;
}
let alarmCue = $j('div.alarmCue');
let eventViewer = $j(vid ? '#videoobj' : '#evtStream')
eventViewer.width(newWidth);
eventViewer.height(newHeight);
if ( !vid ) { // zms needs extra sizing
streamScale(scale == "auto" ? Math.round(newWidth / eventData.Width * SCALE_BASE) : scale);
alarmCue.width(newWidth);
drawProgressBar();
$j("#alarmCueJpeg").html(renderAlarmCues());
Cookie.write( 'zmEventScale'+eventData.MonitorId, scale, { duration: 10*365 } );
}
alarmCue.html(renderAlarmCues());//just re-render alarmCues. skip ajax call
if (scale == "auto") {
Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365});
}else{
Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365});
Cookie.dispose('zmEventScaleAuto');
}
}
@ -176,7 +204,7 @@ var zmsBroke = false; //Use alternate navigation if zms has crashed
function getCmdResponse( respObj, respText ) {
if ( checkStreamForErrors( "getCmdResponse", respObj ) ) {
console.log('Got an error from getCmdResponse');
var zmsBroke = true;
zmsBroke = true;
return;
}
@ -301,7 +329,11 @@ function streamFastRev( action ) {
function streamPrev(action) {
if (action) {
if (vid || PrevEventDefVideoPath.indexOf("view_video") >=0 || $j("#vjsMessage").length || zmsBroke) { //handles this or prev being video.js, or end of events
$j(".vjsMessage").remove();
if (vid && PrevEventDefVideoPath.indexOf("view_video") > 0) {
CurEventDefVideoPath = PrevEventDefVideoPath;
eventQuery(prevEventId);
} else if (zmsBroke || (vid && PrevEventDefVideoPath.indexOf("view_video") < 0) || $j("#vjsMessage").length || PrevEventDefVideoPath.indexOf("view_video") > 0) {//zms broke, leaving videojs, last event, moving to videojs
location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery);
} else {
streamReq.send(streamParms+"&command="+CMD_PREV);
@ -311,13 +343,22 @@ function streamPrev(action) {
function streamNext(action) {
if (action) {
$j(".vjsMessage").remove();//This shouldn't happen
if (nextEventId == 0) { //handles deleting last event.
let replaceStream = $j(vid ? "#videoobj" : "#evtStream");
replaceStream.replaceWith('<p class="vjsMessage" style="width:' + replaceStream.css("width") + '; height: ' + replaceStream.css("height") + ';line-height: ' + replaceStream.css("height") + ';">No more events</p>');
} else if (vid || NextEventDefVideoPath.indexOf("view_video") >=0 || zmsBroke) { //handles current or next switch to video.js
vid ? vid.pause() : streamPause();
let hideContainer = $j( vid ? "#eventVideo" : "#imageFeed");
let hideStream = $j(vid ? "#videoobj" : "#evtStream").height() + (vid ? 0 :$j("#progressBar").height());
hideContainer.prepend('<p class="vjsMessage" style="height: ' + hideStream + 'px; line-height: ' + hideStream + 'px;">No more events</p>');
if (vid == null) zmsBroke = true;
return;
}
if (vid && NextEventDefVideoPath.indexOf("view_video") > 0) { //on and staying with videojs
CurEventDefVideoPath = NextEventDefVideoPath;
eventQuery(nextEventId);
} else if (zmsBroke || (vid && NextEventDefVideoPath.indexOf("view_video") < 0) || NextEventDefVideoPath.indexOf("view_video") > 0) {//reload zms, leaving vjs, moving to vjs
location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery);
} else {
streamReq.send( streamParms+"&command="+CMD_NEXT );
streamReq.send(streamParms+"&command="+CMD_NEXT);
}
}
}
@ -348,6 +389,7 @@ function streamQuery() {
var slider = null;
var scroll = null;
var CurEventDefVideoPath = null;
function getEventResponse( respObj, respText ) {
if ( checkStreamForErrors( "getEventResponse", respObj ) ) {
@ -374,7 +416,7 @@ function getEventResponse( respObj, respText ) {
$('dataFrames').set( 'text', eventData.Frames+"/"+eventData.AlarmFrames );
$('dataScore').set( 'text', eventData.TotScore+"/"+eventData.AvgScore+"/"+eventData.MaxScore );
$('eventName').setProperty( 'value', eventData.Name );
history.replaceState(null, null, '?view=event&eid=' + eventData.Id + filterQuery + sortQuery);//if popup removed, check if this allows forward
if ( canEditEvents ) {
if ( parseInt(eventData.Archived) ) {
$('archiveEvent').addClass( 'hidden' );
@ -387,7 +429,14 @@ function getEventResponse( respObj, respText ) {
// Technically, events can be different sizes, so may need to update the size of the image, but it might be better to have it stay scaled...
//var eventImg = $('eventImage');
//eventImg.setStyles( { 'width': eventData.width, 'height': eventData.height } );
drawProgressBar();
if (vid && CurEventDefVideoPath) {
vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use
initialAlarmCues(eventData.Id);//ajax and render, new event
addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime);
CurEventDefVideoPath = null;
} else {
drawProgressBar();
}
nearEventsQuery( eventData.Id );
}
@ -693,6 +742,7 @@ function getActResponse( respObj, respText ) {
return;
if ( respObj.refreshParent )
if (refreshParent == false) refreshParent = true; //Bypass filter window redirect fix.
refreshParentWindow();
if ( respObj.refreshEvent )
@ -793,7 +843,7 @@ function videoEvent() {
// Called on each event load because each event can be a different width
function drawProgressBar() {
var barWidth = (eventData.Width * $j('#scale').val()) / SCALE_BASE;
let barWidth = $j('#evtStream').width();
$j('#progressBar').css( 'width', barWidth );
}
@ -807,7 +857,7 @@ function updateProgressBar() {
} // end function updateProgressBar()
// Handles seeking when clicking on the progress bar.
function progressBarSeek (){
function progressBarNav (){
$j('#progressBar').click(function(e){
var x = e.pageX - $j(this).offset().left;
var seekTime = (x / $j('#progressBar').width()) * parseFloat(eventData.Length);
@ -924,11 +974,15 @@ function setupListener() {
function initPage() {
//FIXME prevent blocking...not sure what is happening or best way to unblock
if ( $('videoobj') ) {
if ($j('#videoobj').length) {
vid = videojs("videoobj");
initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues after videojs is. should be only call to initialAlarmCues on vjs streams
addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime);
$j(".vjs-progress-control").append('<div class="alarmCue"></div>');//add a place for videojs only on first load
nearEventsQuery(eventData.Id);
initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues after videojs is initialized
vjsReplay();
}
if ( vid ) {
if (vid) {
/*
setupListener();
vid.removeAttribute("controls");
@ -947,10 +1001,10 @@ function initPage() {
window.videoobj.load();
streamPlay(); */
} else {
progressBarSeek ();
progressBarNav ();
streamCmdTimer = streamQuery.delay( 250 );
eventQuery.pass( eventData.Id ).delay( 500 );
initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues for nph-zms.
initialAlarmCues(eventData.Id); //call ajax+renderAlarmCues for zms.
if ( canStreamNative ) {
var streamImg = $('imageFeed').getElement('img');
@ -959,6 +1013,7 @@ function initPage() {
$(streamImg).addEvent( 'click', function( event ) { handleClick( event ); } );
}
}
if (scale == "auto") changeScale();
}
// Kick everything off

View File

@ -30,13 +30,18 @@ var eventData = {
MonitorId: '<?php echo $Event->MonitorId() ?>',
Width: '<?php echo $Event->Width() ?>',
Height: '<?php echo $Event->Height() ?>',
Length: '<?php echo $Event->Length() ?>'
Length: '<?php echo $Event->Length() ?>',
StartTime: '<?php echo $Event->StartTime() ?>',
EndTime: '<?php echo $Event->EndTime() ?>',
MonitorName: '<?php echo $Monitor->Name() ?>'
};
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
var scale = <?php echo $scale ?>;
var scale = "<?php echo $scale ?>";
var LabelFormat = "<?php echo validJsStr($Monitor->LabelFormat())?>";
var canEditEvents = <?php echo canEdit( 'Events' )?'true':'false' ?>;
var streamTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;

View File

@ -19,6 +19,8 @@ function updateButtons( element ) {
canExecute = true;
else if ( form.elements['filter[AutoDelete]'].checked )
canExecute = true;
else if ( form.elements['filter[UpdateDiskSpace]'].checked )
canExecute = true;
form.elements['executeButton'].disabled = !canExecute;
}
}

View File

@ -55,7 +55,7 @@ function validateForm( form ) {
else if ( form.elements.mid.value == 0 && monitorNames[form.elements['newMonitor[Name]'].value] )
errors[errors.length] = "<?php echo translate('DuplicateMonitorName') ?>";
if ( form.elements['newMonitor[AnalysisFPS]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPS]'].value) > 0 ) )
if ( form.elements['newMonitor[AnalysisFPSLimit]'].value && !(parseFloat(form.elements['newMonitor[AnalysisFPSLimit]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadAnalysisFPS') ?>";
if ( form.elements['newMonitor[MaxFPS]'].value && !(parseFloat(form.elements['newMonitor[MaxFPS]'].value) > 0 ) )
errors[errors.length] = "<?php echo translate('BadMaxFPS') ?>";

View File

@ -10,8 +10,6 @@ function Monitor( monitorData ) {
this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey;
if ( auth_hash )
this.streamCmdParms += '&auth='+auth_hash;
else
console.log("No auth_hash");
this.streamCmdTimer = null;
this.start = function( delay ) {
@ -89,8 +87,12 @@ function Monitor( monitorData ) {
} else {
console.error( respObj.message );
// Try to reload the image stream.
if ( stream )
if ( stream ) {
console.log('Reloading stream: ' + stream.src );
stream.src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
} else {
console.log( 'No stream to reload?' );
}
}
var streamCmdTimeout = statusRefreshTimeout;
if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT )
@ -112,13 +114,45 @@ function Monitor( monitorData ) {
}
function selectLayout( element ) {
layout = $(element).get('value')
var cssFile = skinPath+'/css/'+Cookie.read('zmCSS')+'/views/'+layout;
if ( $('dynamicStyles') )
$('dynamicStyles').destroy();
new Asset.css( cssFile, { id: 'dynamicStyles' } );
Cookie.write( 'zmMontageLayout', layout, { duration: 10*365 } );
if ( layout != 'montage_freeform.css' ) {
layout = $(element).get('value');
if ( layout_id = parseInt(layout) ) {
layout = layouts[layout];
console.log("Have layout # " + layout_id);
for ( var i = 0; i < monitors.length; i++ ) {
monitor = monitors[i];
// Need to clear the current positioning, and apply the new
monitor_frame = $j('#monitorFrame'+monitor.id);
if ( ! monitor_frame ) {
console.log("Error finding frame for " + monitor.id );
continue;
}
// Apply default layout options, like float left
if ( layout.default ) {
styles = layout.default;
for ( style in styles ) {
console.log("applying " + style + ': ' + styles[style]);
monitor_frame.css(style, styles[style]);
}
} // end if default styles
if ( layout[monitor.id] ) {
styles = layout[monitor.id];
for ( style in styles ) {
console.log("applying " + style + ': ' + styles[style]);
monitor_frame.css(style, styles[style]);
}
} // end if specific monitor style
} // end foreach monitor
} // end if a stored layout
if ( ! layout ) {
return;
}
Cookie.write( 'zmMontageLayout', layout_id, { duration: 10*365 } );
if ( layout_id != 1 ) { // 'montage_freeform.css' ) {
Cookie.write( 'zmMontageScale', '', { duration: 10*365 } );
$('scale').set('value', '' );
$('width').set('value', '');
@ -152,6 +186,17 @@ function changeSize() {
for ( var x = 0; x < monitors.length; x++ ) {
var monitor = monitors[x];
// Scale the frame
monitor_frame = $j('#monitorFrame'+monitor.id);
if ( ! monitor_frame ) {
console.log("Error finding frame for " + monitor.id );
continue;
}
if ( width )
monitor_frame.css('width',width+'px');
if ( height )
monitor_frame.css('height',height+'px');
/*Stream could be an applet so can't use moo tools*/
var streamImg = $( 'liveStream'+monitor.id );
if ( streamImg ) {
@ -223,6 +268,42 @@ function initPage() {
monitors[i].start( delay );
}
selectLayout($('layout'));
$j('#monitors .monitorFrame').draggable({
cursor: 'crosshair',
revert: 'invalid'
});
function toGrid(value) {
return Math.round(value / 80) * 80;
}
$j('#monitors').droppable({
accept: '#monitors .monitorFrame',
drop: function(event, ui) {
//console.log(event);
$j(this).removeClass('border over');
$j(ui.draggable).detach().
appendTo($j(this).find('ul')).
draggable({
containment: '.fw-content',
cursor: 'help',
grid: [ 80, 80 ]
}).
css({
position: 'absolute',
left: toGrid(event.clientX - $j('#monitors').offset().left),
top: toGrid(event.clientY - $j('#monitors').offset().top)
});
},
over: function(event, elem) {
console.log('over');
$j(this).addClass('over');
},
out: function(event, elem) {
$j(this).removeClass('over');
}
});
}
// Kick everything off

View File

@ -31,12 +31,21 @@ var monitorData = new Array();
foreach ( $monitors as $monitor ) {
?>
monitorData[monitorData.length] = {
'id': <?php echo $monitor->Id() ?>,
'connKey': <?php echo $monitor->connKey() ?>,
'width': <?php echo $monitor->Width() ?>,
'height':<?php echo $monitor->Height() ?>,
'id': <?php echo $monitor->Id() ?>,
'connKey': <?php echo $monitor->connKey() ?>,
'width': <?php echo $monitor->Width() ?>,
'height':<?php echo $monitor->Height() ?>,
'server_url': '<?php echo $monitor->Server()->Url().(ZM_MIN_STREAMING_PORT?':'.(ZM_MIN_STREAMING_PORT+$monitor->Id()):'').$_SERVER['PHP_SELF'] ?>'
};
<?php
}
} // end foreach monitor
?>
layouts = new Array();
layouts[0] = {}; // reserved, should hold which fields to clear when transitioning
<?php
foreach ( $layouts as $layout ) {
?>
layouts[<?php echo $layout->Id() ?>] = <?php echo $layout->Positions() ?>;
<?php
} // end foreach layout
?>

View File

@ -84,7 +84,11 @@ function imagedone( obj, monId, success ) {
if ( ! success ) {
// if we had a failrue queue up the no-data image
//loadImage2Monitor(monId,"no data"); // leave the staged URL if there is one, just ignore it here.
loadNoData( monId );
if ( liveMode ) {
writeText( monId, "Camera Offline" );
} else {
writeText( monId, "No Data" );
}
} else {
if ( monitorLoadingStageURL[monId] == "" ) {
console.log("Not showing image for " + monId );
@ -114,6 +118,21 @@ function loadNoData( monId ) {
console.log("No monId in loadNoData");
}
}
function writeText( monId, text ) {
if ( monId ) {
var canvasCtx = monitorCanvasCtx[monId];
var canvasObj = monitorCanvasObj[monId];
//canvasCtx.fillStyle="white";
//canvasCtx.fillRect(0, 0, canvasObj.width, canvasObj.height);
var textSize=canvasObj.width * 0.15;
canvasCtx.font = "600 " + textSize.toString() + "px Arial";
canvasCtx.fillStyle="white";
var textWidth = canvasCtx.measureText(text).width;
canvasCtx.fillText(text,canvasObj.width/2 - textWidth/2,canvasObj.height/2);
} else {
console.log("No monId in loadNoData");
}
}
// Either draws the
function loadImage2Monitor( monId, url ) {
@ -123,14 +142,16 @@ function loadImage2Monitor( monId, url ) {
} else {
if ( monitorImageObject[monId].src == url ) return; // do nothing if it's the same
if ( url == 'no data' ) {
loadNoData( monId );
writeText(monId, 'No Data');
} else {
//writeText(monId, 'Loading...');
monitorLoading[monId] = true;
monitorLoadStartTimems[monId] = new Date().getTime();
monitorImageObject[monId].src = url; // starts a load but doesn't refresh yet, wait until ready
}
}
}
function timerFire() {
// See if we need to reschedule
if ( currentDisplayInterval != timerInterval || currentSpeed == 0 ) {
@ -665,15 +686,17 @@ function showOneMonitor(monId) {
// link out to the normal view of one event's data
// We know the monitor, need to determine the event based on current time
var url;
if ( liveMode != 0 )
if ( liveMode != 0 ) {
url="?view=watch&mid=" + monId.toString();
else
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] );
} else {
for ( var i=0, len=eId.length; i<len; i++ ) {
if ( eMonId[i] == monId && currentTimeSecs >= eStartSecs[i] && currentTimeSecs <= eEndSecs[i] )
url="?view=event&eid=" + eId[i] + '&fid=' + parseInt(Math.max(1, Math.min(eventFrames[i], eventFrames[i] * (currentTimeSecs - eStartSecs[i]) / (eEndSecs[i] - eStartSecs[i] + 1) ) ));
break;
}
createPopup(url, 'zmEvent', 'event', monitorWidth[eMonId[i]], monitorHeight[eMonId[i]]);
createPopup(url, 'zmEvent', 'event', monitorWidth[monId], monitorHeight[monId]);
}
}
function zoom(monId,scale) {

View File

@ -122,7 +122,7 @@ if ( ! $monitor ) {
'FrameSkip' => 0,
'MotionFrameSkip' => 0,
'EventPrefix' => 'Event-',
'AnalysisFPS' => '',
'AnalysisFPSLimit' => '',
'AnalysisUpdateDelay' => 0,
'MaxFPS' => '',
'AlarmMaxFPS' => '',
@ -170,8 +170,8 @@ if ( isset( $_REQUEST['newMonitor'] ) ) {
}
# What if it has less zeros? This is not robust code.
if ( $monitor->AnalysisFPS() == '0.00' )
$monitor->AnalysisFPS( '' );
if ( $monitor->AnalysisFPSLimit() == '0.00' )
$monitor->AnalysisFPSLimit( '' );
if ( $monitor->MaxFPS() == '0.00' )
$monitor->MaxFPS( '' );
if ( $monitor->AlarmMaxFPS() == '0.00' )
@ -538,7 +538,7 @@ if ( $tab != 'general' ) {
<input type="hidden" name="newMonitor[Enabled]" value="<?php echo validHtmlStr($monitor->Enabled()) ?>"/>
<input type="hidden" name="newMonitor[RefBlendPerc]" value="<?php echo validHtmlStr($monitor->RefBlendPerc()) ?>"/>
<input type="hidden" name="newMonitor[AlarmRefBlendPerc]" value="<?php echo validHtmlStr($monitor->AlarmRefBlendPerc()) ?>"/>
<input type="hidden" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS()) ?>"/>
<input type="hidden" name="newMonitor[AnalysisFPSLimit]" value="<?php echo validHtmlStr($monitor->AnalysisFPSLimit()) ?>"/>
<input type="hidden" name="newMonitor[MaxFPS]" value="<?php echo validHtmlStr($monitor->MaxFPS()) ?>"/>
<input type="hidden" name="newMonitor[AlarmMaxFPS]" value="<?php echo validHtmlStr($monitor->AlarmMaxFPS()) ?>"/>
<?php
@ -665,7 +665,7 @@ if ( ZM_HAS_V4L && ($tab != 'misc' || $monitor->Type()!= 'Local') ) {
<?php
}
?>
<table id="contentTable" class="major" cellspacing="0">
<table id="contentTable" class="major">
<tbody>
<?php
switch ( $tab ) {
@ -727,7 +727,7 @@ switch ( $tab ) {
</select>
</td>
</tr>
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPS]" value="<?php echo validHtmlStr($monitor->AnalysisFPS()) ?>" size="6"/></td></tr>
<tr><td><?php echo translate('AnalysisFPS') ?></td><td><input type="text" name="newMonitor[AnalysisFPSLimit]" value="<?php echo validHtmlStr($monitor->AnalysisFPSLimit()) ?>" size="6"/></td></tr>
<?php
if ( $monitor->Type() != 'Local' && $monitor->Type() != 'File' && $monitor->Type() != 'NVSocket' ) {
?>

View File

@ -0,0 +1,98 @@
<?php
//
// ZoneMinder web function view file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canEdit( 'Monitors' ) ) {
$view = 'error';
return;
}
$monitors = Monitor::find_all( array('Id' => $_REQUEST['mids'] ) );
$monitor = $monitors[0];
$servers = Server::find_all();
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
$storage_areas = Storage::find_all();
$StorageById = array();
foreach ( $storage_areas as $S ) {
$StorageById[$S->Id()] = $S;
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Function'));
?>
<body>
<div id="page">
<div id="header">
<h2><?php echo translate('Function') ?></h2>
</div>
<div id="content">
The following monitors will have these settings update when you click Save:<br/><br/>
<?php echo implode('<br/>', array_map( function($m){return $m->Id().' ' .$m->Name();}, $monitors ) ); ?>
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="view" value="none"/>
<input type="hidden" name="action" value="save"/>
<input type="hidden" name="object" value="Monitor"/>
<?php
echo implode(
"\n",
array_map( function($m){
return '<input type="hidden" name="mids[]" value="'.$m->Id().'"/>';
}, $monitors )
);
if ( count($ServersById) > 0 ) { ?>
<p class="Server"><label><?php echo translate('Server')?></label>
<?php echo htmlSelect( 'newMonitor[ServerId]', array(''=>'None')+$ServersById, $monitor->ServerId() ); ?>
</p>
<?php
}
if ( count($StorageById) > 0 ) {
?>
<p class="Storage"><label><?php echo translate('Storage')?></label>
<?php echo htmlSelect( 'newMonitor[StorageId]', array(''=>'All')+$StorageById, $monitor->StorageId() ); ?>
</p>
<?php
}
?>
<p><label><?php echo translate('Function') ?></label>
<?php
$options = array();
foreach ( getEnumValues('Monitors', 'Function') as $opt ) {
$options[$opt] = translate('Fn'.$opt);
}
echo htmlSelect( 'newMonitor[Function]', $options, $monitor->Function() );
?>
</p>
<p>
<label for="newMonitor[Enabled]"><?php echo translate('Enabled') ?></label>
<input type="checkbox" name="newMonitor[Enabled]" id="newMonitor[Enabled]" value="1"<?php if ( !empty($monitors[0]->Enabled()) ) { ?> checked="checked"<?php } ?>/>
</p>
<div id="contentButtons">
<input type="submit" value="<?php echo translate('Save') ?>"/>
<input type="button" value="<?php echo translate('Cancel') ?>" onclick="closeWindow()"/>
</div>
</form>
</div>
</div>
</body>
</html>

View File

@ -23,6 +23,8 @@ if ( !canView('Stream') ) {
return;
}
require_once('includes/MontageLayout.php');
$showControl = false;
$showZones = false;
if ( isset( $_REQUEST['showZones'] ) ) {
@ -59,6 +61,7 @@ if ( ! $scale )
$focusWindow = true;
/*
$layouts = array(
'montage_freeform.css' => translate('MtgDefault'),
'montage_2wide.css' => translate('Mtg2widgrd'),
@ -66,6 +69,15 @@ $layouts = array(
'montage_4wide.css' => translate('Mtg4widgrd'),
'montage_3wide50enlarge.css' => translate('Mtg3widgrx'),
);
foreach ( MontageLayout::find() as $Layout ) {
$layouts[$Layout->Id()] = $Layout->Name();
}
*/
$layouts = MontageLayout::find(NULL, array('order'=>"lower('Name')"));
$layoutsById = array();
foreach ( $layouts as $l ) {
$layoutsById[$l->Id()] = $l->Name();
}
$layout = '';
if ( isset($_COOKIE['zmMontageLayout']) )
@ -91,6 +103,35 @@ ob_end_clean();
$groupSql = Group::get_group_sql( $group_id );
$servers = Server::find_all();
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
session_start();
foreach ( array('ServerFilter','StorageFilter') as $var ) {
if ( isset( $_REQUEST[$var] ) ) {
if ( $_REQUEST[$var] != '' ) {
$_SESSION[$var] = $_REQUEST[$var];
} else {
unset( $_SESSION[$var] );
}
} else if ( isset( $_COOKIE[$var] ) ) {
if ( $_COOKIE[$var] != '' ) {
$_SESSION[$var] = $_COOKIE[$var];
} else {
unset($_SESSION[$var]);
}
}
}
session_write_close();
$storage_areas = Storage::find_all();
$StorageById = array();
foreach ( $storage_areas as $S ) {
$StorageById[$S->Id()] = $S;
}
$monitor_id = 0;
if ( isset( $_REQUEST['monitor_id'] ) ) {
$monitor_id = $_REQUEST['monitor_id'];
@ -100,15 +141,46 @@ if ( isset( $_REQUEST['monitor_id'] ) ) {
$monitors = array();
$monitors_dropdown = array( '' => 'All' );
$sql = "SELECT * FROM Monitors WHERE Function != 'None'";
if ( $groupSql ) { $sql .= ' AND ' . $groupSql; };
if ( $monitor_id ) { $sql .= ' AND Id='.$monitor_id; };
$conditions = array();
$values = array();
$sql .= ' ORDER BY Sequence';
foreach( dbFetchAll( $sql ) as $row ) {
if ( $groupSql )
$conditions[] = $groupSql;
if ( isset($_SESSION['ServerFilter']) ) {
$conditions[] = 'ServerId=?';
$values[] = $_SESSION['ServerFilter'];
}
if ( isset($_SESSION['StorageFilter']) ) {
$conditions[] = 'StorageId=?';
$values[] = $_SESSION['StorageFilter'];
}
$sql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC';
$monitor_rows = dbFetchAll( $sql, null, $values );
if ( $monitor_id ) {
$found_selected_monitor = false;
for ( $i = 0; $i < count($monitor_rows); $i++ ) {
if ( !visibleMonitor( $monitor_rows[$i]['Id'] ) ) {
continue;
}
$monitors_dropdown[$monitor_rows[$i]['Id']] = $monitor_rows[$i]['Name'];
if ( $monitor_rows[$i]['Id'] == $monitor_id ) {
$found_selected_monitor = true;
}
}
if ( ! $found_selected_monitor ) {
$monitor_id = '';
}
}
$monitors = array();
foreach( $monitor_rows as $row ) {
if ( !visibleMonitor( $row['Id'] ) ) {
continue;
}
if ( $monitor_id and $row['Id'] != $monitor_id )
continue;
$row['Scale'] = $scale;
$row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
@ -141,11 +213,11 @@ if ( $showControl ) {
}
if ( $showZones ) {
?>
<a href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=0'; ?>">Hide Zones</a>
<a id="ShowZones" href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=0'; ?>">Hide Zones</a>
<?php
} else {
?>
<a href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=1'; ?>">Show Zones</a>
<a id="ShowZones" href="<?php echo $_SERVER['PHP_SELF'].'?view=montage&showZones=1'; ?>">Show Zones</a>
<?php
}
?>
@ -157,10 +229,31 @@ if ( $showZones ) {
<span id="monitorControl"><label><?php echo translate('Monitor') ?>:</label>
<?php echo htmlSelect( 'monitor_id', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') ); ?>
</span>
<?php if ( count($ServersById) > 0 ) { ?>
<span class="ServerFilter"><label><?php echo translate('Server')?>:</label>
<?php
echo htmlSelect( 'ServerFilter', array(''=>'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') );
?>
</span>
<?php
}
if ( count($StorageById) > 0 ) { ?>
<span class="StorageFilter"><label><?php echo translate('Storage')?>:</label>
<?php
echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') );
?>
</span>
<?php
}
?>
<br/>
<span id="widthControl"><label><?php echo translate('Width') ?>:</label><?php echo htmlSelect( 'width', $widths, $options['width'], 'changeSize(this);' ); ?></span>
<span id="heightControl"><label><?php echo translate('Height') ?>:</label><?php echo htmlSelect( 'height', $heights, $options['height'], 'changeSize(this);' ); ?></span>
<span id="scaleControl"><label><?php echo translate('Scale') ?>:</label><?php echo htmlSelect( 'scale', $scales, $scale, 'changeScale(this);' ); ?></span>
<span id="layoutControl"><label for="layout"><?php echo translate('Layout') ?>:</label><?php echo htmlSelect( 'layout', $layouts, $layout, 'selectLayout(this);' )?></span>
<span id="layoutControl">
<label for="layout"><?php echo translate('Layout') ?>:</label>
<?php echo htmlSelect( 'layout', $layoutsById, $layout, 'selectLayout(this);' )?>
</span>
</div>
</div>
<div id="content">

View File

@ -62,10 +62,30 @@ ob_end_clean();
$groupSql = Group::get_group_sql( $group_id );
$servers = Server::find_all();
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
$storage_areas = Storage::find_all();
$StorageById = array();
foreach ( $storage_areas as $S ) {
$StorageById[$S->Id()] = $S;
}
session_start();
foreach ( array('minTime','maxTime') as $var ) {
foreach ( array('minTime','maxTime','ServerFilter','StorageFilter') as $var ) {
if ( isset( $_REQUEST[$var] ) ) {
$_SESSION[$var] = $_REQUEST[$var];
if ( $_REQUEST[$var] != '' ) {
$_SESSION[$var] = $_REQUEST[$var];
} else {
unset( $_SESSION[$var] );
}
} else if ( isset( $_COOKIE[$var] ) ) {
if ( $_COOKIE[$var] != '' ) {
$_SESSION[$var] = $_COOKIE[$var];
} else {
unset($_SESSION[$var]);
}
}
}
session_write_close();
@ -77,7 +97,19 @@ if ( isset( $_REQUEST['monitor_id'] ) ) {
$monitor_id = $_COOKIE['zmMonitorId'];
}
$monitorsSql = "SELECT * FROM Monitors WHERE Function != 'None'" . ( $groupSql ? ' AND ' . $groupSql : '');
$conditions = array();
$values = array();
if ( $groupSql )
$conditions[] = $groupSql;
if ( isset($_SESSION['ServerFilter']) ) {
$conditions[] = 'ServerId=?';
$values[] = $_SESSION['ServerFilter'];
}
if ( isset($_SESSION['StorageFilter']) ) {
$conditions[] = 'StorageId=?';
$values[] = $_SESSION['StorageFilter'];
}
// Note that this finds incomplete events as well, and any frame records written, but still cannot "see" to the end frame
// if the bulk record has not been written - to be able to include more current frames reduce bulk frame sizes (event size can be large)
@ -111,10 +143,14 @@ $frameSql = '
if ( ! empty( $user['MonitorIds'] ) ) {
$eventsSql .= ' AND M.Id IN ('.$user['MonitorIds'].')';
$monitorsSql .= ' AND Id IN ('.$user['MonitorIds'].')';
$monitor_ids = explode(',',$user['MonitorIds']);
$conditions[] .= 'Id IN ('.array_map( function(){return '?';}, $monitor_ids ) . ')';
array_push( $values, $monitor_ids );
$frameSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
}
if ( $monitor_id ) {
$monitorsSql .= ' AND Id='.$monitor_id;
$conditions[] = 'Id=?';
$values[] = $monitor_id;
$eventsSql .= ' AND M.Id='.$monitor_id;
$frameSql .= ' AND E.MonitorId='.$monitor_id;
}
@ -191,8 +227,8 @@ $frameSql .= ' GROUP BY E.Id, E.MonitorId, F.TimeStamp, F.Delta ORDER BY E.Monit
$monitors = array();
$monitorsSql .= ' ORDER BY Sequence ASC';
foreach( dbFetchAll( $monitorsSql ) as $row ) {
$monitorsSql = 'SELECT * FROM Monitors' . ( count($conditions) ? ' WHERE ' . implode(' AND ', $conditions ) : '' ).' ORDER BY Sequence ASC';
foreach( dbFetchAll( $monitorsSql, null, $values ) as $row ) {
$Monitor = new Monitor( $row );
$monitors[] = $Monitor;
}
@ -214,6 +250,25 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
<span id="monitorControl"><label><?php echo translate('Monitor') ?>:</label>
<?php Group::get_monitors_dropdown( $groupSql ? array( 'groupSql'=>$groupSql) : null ); ?>
</span>
<?php
if ( count($ServersById) > 0 ) { ?>
<span class="ServerFilter"><label><?php echo translate('Server')?>:</label>
<?php
echo htmlSelect( 'ServerFilter', array(''=>'All')+$ServersById, (isset($_SESSION['ServerFilter'])?$_SESSION['ServerFilter']:''), array('onchange'=>'changeFilter(this);') );
?>
</span>
<?php
}
if ( count($StorageById) > 0 ) { ?>
<span class="StorageFilter"><label><?php echo translate('Storage')?>:</label>
<?php
echo htmlSelect( 'StorageFilter', array(''=>'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') );
?>
</span>
<?php
}
?>
<div id="DateTimeDiv">
<input type="datetime-local" name="minTime" id="minTime" value="<?php echo preg_replace('/ /', 'T', $minTime ) ?>" onchange="changeDateTime(this);"> to
<input type="datetime-local" name="maxTime" id="maxTime" value="<?php echo preg_replace('/ /', 'T', $maxTime ) ?>" onchange="changeDateTime(this);">
@ -252,7 +307,7 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
<?php
// Monitor images - these had to be loaded after the monitors used were determined (after loading events)
foreach ($monitors as $m) {
echo '<canvas width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" onclick="clickMonitor(event,' . $m->Id() . ')">No Canvas Support!!</canvas>';
echo '<canvas title="'.$m->Id().' ' .$m->Name().'" width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" onclick="clickMonitor(event,' . $m->Id() . ')">No Canvas Support!!</canvas>';
}
?>
</div>

View File

@ -204,6 +204,10 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<tr>
<th class="colName"><?php echo translate('Name') ?></th>
<th class="colHostname"><?php echo translate('Hostname') ?></th>
<th class="colStatus"><?php echo translate('Status') ?></th>
<th class="colCpuLoad"><?php echo translate('CpuLoad') ?></th>
<th class="colMemory"><?php echo translate('Free').'/'.translate('Total') . ' ' . translate('Memory') ?></th>
<th class="colSwap"><?php echo translate('Free').'/'.translate('Total') . ' ' . translate('Swap') ?></th>
<th class="colMark"><?php echo translate('Mark') ?></th>
</tr>
</thead>
@ -212,6 +216,11 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<tr>
<td class="colName"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', validHtmlStr($row['Name']), $canEdit ) ?></td>
<td class="colHostname"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', validHtmlStr($row['Hostname']), $canEdit ) ?></td>
<td class="colStatus"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', validHtmlStr($row['Status']), $canEdit ) ?></td>
<td class="colCpuLoad"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server',$row['CpuLoad'], $canEdit ) ?></td>
<td class="colMemory"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeMem']) . ' / ' . human_filesize($row['TotalMem']), $canEdit ) ?></td>
<td class="colSwap"><?php echo makePopupLink( '?view=server&amp;id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeSwap']) . ' / ' . human_filesize($row['TotalSwap']) , $canEdit ) ?></td>
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $row['Id'] ?>" onclick="configureDeleteButton( this );"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td>
</tr>
<?php } #end foreach Server ?>

View File

@ -121,6 +121,8 @@ Logger::Debug("Got virtual frame from Bulk Frames previous delta: " . $previousB
header('HTTP/1.0 404 Not Found');
Fatal("Can't create frame images from video for this event (".$Event->DefaultVideo() );
}
$Event->DiskSpace( null );
$Event->save();
} else {
header('HTTP/1.0 404 Not Found');
Fatal("Can't create frame images from video becuase there is no video file for this event (".$Event->DefaultVideo() );