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

This commit is contained in:
Isaac Connor 2017-12-04 20:52:43 -05:00
commit f3d3357365
99 changed files with 1843 additions and 1271 deletions

View File

@ -233,6 +233,8 @@ CREATE TABLE `Filters` (
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
`AutoExecuteCmd` tinytext,
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
`AutoMove` tinyint(3) unsigned NOT NULL default '0',
`AutoMoveTo` smallint(5) 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',
@ -268,10 +270,24 @@ CREATE TABLE `Groups` (
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(64) NOT NULL default '',
`ParentId` int(10) unsigned,
`MonitorIds` text NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
--
--Table structure for table `Groups_Monitors`
--
DROP TABLE IF EXISTS `Groups_Monitors`
CREATE TABLE `Groups_Monitors` (
`Id` INT(10) unsigned NOT NULL auto_increment,
`GroupId` int(10) unsigned NOT NULL,
`MonitorId` int(10) unsigned NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
CREATE INDEX `Groups_Monitors_GroupId_idx` ON `Groups` (`GroupId`);
CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups` (`MonitorId`);
--
-- Table structure for table `Logs`
--

96
db/zm_update-1.31.16.sql Normal file
View File

@ -0,0 +1,96 @@
--
-- 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 = 'AutoMove'
) > 0,
"SELECT 'Column AutoMove already exists in Filters'",
"ALTER TABLE Filters ADD `AutoMove` tinyint(3) unsigned NOT NULL default '0' AFTER `AutoDelete`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Filters'
AND column_name = 'AutoMoveTo'
) > 0,
"SELECT 'Column AutoMoveTo already exists in Filters'",
"ALTER TABLE Filters ADD `AutoMoveTo` smallint(5) unsigned NOT NULL default '0' AFTER `AutoMove`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'Groups_Monitors'
AND table_schema = DATABASE()
) > 0,
"SELECT 'Groups_Monitors table exists'",
"CREATE TABLE `Groups_Monitors` (
`Id` INT(10) unsigned NOT NULL auto_increment,
`GroupId` int(10) unsigned NOT NULL,
`MonitorId` int(10) unsigned NOT NULL,
PRIMARY KEY (`Id`)
)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'Groups_Monitors'
AND table_schema = DATABASE()
AND index_name = 'Groups_Monitors_GroupId_idx'
) > 0,
"SELECT 'Groups_Monitors_GroupId_idx already exists on Groups table'",
"CREATE INDEX `Groups_Monitors_GroupId_idx` ON `Groups_Monitors` (`GroupId`)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*)
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'Groups_Monitors'
AND table_schema = DATABASE()
AND index_name = 'Groups_Monitors_MonitorId_idx'
) > 0,
"SELECT 'Groups_Monitors_MonitorId_idx already exists on Groups table'",
"CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups_Monitors` (`MonitorId`)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Groups'
AND column_name = 'MonitorIds'
) > 0,
"REPLACE INTO Groups_Monitors (GroupId,MonitorId) SELECT Id,SUBSTRING_INDEX(SUBSTRING_INDEX(t.MonitorIds, ',', n.n), ',', -1) value FROM Groups t CROSS JOIN ( SELECT a.N + b.N * 10 + 1 n FROM (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b ORDER BY n ) n WHERE t.MonitorIds != '' AND n.n <= 1 + (LENGTH(t.MonitorIds) - LENGTH(REPLACE(t.MonitorIds, ',', ''))) ORDER BY value;",
"SELECT 'MonitorIds has already been removed.'"
));
/*
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Groups'
AND column_name = 'MonitorIds'
) > 0,
"ALTER TABLE Groups DROP MonitorIds",
"SELECT 'MonitorIds has already been removed.'"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
*/

View File

@ -79,13 +79,13 @@ BEGIN {
# Search for user created config files. If one or more are found then
# update the Config hash with those values
if ( -d ZM_CONFIG_SUBDIR ) {
if ( -R ZM_CONFIG_SUBDIR ) {
foreach my $filename ( glob ZM_CONFIG_SUBDIR."/*.conf" ) {
process_configfile($filename);
}
} else {
print( STDERR "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on ".ZM_CONFIG_SUBDIR.".\n" );
if ( -R ZM_CONFIG_SUBDIR ) {
foreach my $filename ( glob ZM_CONFIG_SUBDIR."/*.conf" ) {
process_configfile($filename);
}
} else {
print( STDERR "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on ".ZM_CONFIG_SUBDIR.".\n" );
}
}
use DBI;
@ -94,14 +94,14 @@ BEGIN {
if ( defined($portOrSocket) ) {
if ( $portOrSocket =~ /^\// ) {
$socket = ";mysql_socket=".$portOrSocket;
$socket = ';mysql_socket='.$portOrSocket;
} else {
$socket = ";host=".$host.";port=".$portOrSocket;
$socket = ';host='.$host.';port='.$portOrSocket;
}
} else {
$socket = ";host=".$Config{ZM_DB_HOST};
$socket = ';host='.$Config{ZM_DB_HOST};
}
my $sslOptions = "";
my $sslOptions = '';
if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = ';'.join(';',
"mysql_ssl=1",
@ -123,7 +123,8 @@ BEGIN {
}
$sth->finish();
#$dbh->disconnect();
if ( ! exists $Config{ZM_SERVER_ID} ) {
#
if ( ! $Config{ZM_SERVER_ID} ) {
$Config{ZM_SERVER_ID} = undef;
$sth = $dbh->prepare_cached( 'SELECT * FROM Servers WHERE Name=?' );
if ( $Config{ZM_SERVER_NAME} ) {
@ -140,32 +141,32 @@ BEGIN {
# This subroutine must be inside the BEGIN block
sub process_configfile {
my $config_file = shift;
my $config_file = shift;
if ( -R $config_file ) {
open( my $CONFIG, "<", $config_file )
or croak( "Can't open config file '$config_file': $!" );
foreach my $str ( <$CONFIG> ) {
next if ( $str =~ /^\s*$/ );
next if ( $str =~ /^\s*#/ );
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
if ( ! $name ) {
print( STDERR "Warning, bad line in $config_file: $str\n" );
next;
} # end if
$name =~ tr/a-z/A-Z/;
$Config{$name} = $value;
}
close( $CONFIG );
} else {
print( STDERR "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $config_file\n" );
if ( -R $config_file ) {
open( my $CONFIG, '<', $config_file )
or croak( "Can't open config file '$config_file': $!" );
foreach my $str ( <$CONFIG> ) {
next if ( $str =~ /^\s*$/ );
next if ( $str =~ /^\s*#/ );
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
if ( ! $name ) {
print( STDERR "Warning, bad line in $config_file: $str\n" );
next;
} # end if
$name =~ tr/a-z/A-Z/;
$Config{$name} = $value;
}
close( $CONFIG );
} else {
print( STDERR "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $config_file\n" );
}
}
} # end BEGIN
sub loadConfigFromDB {
print( "Loading config from DB" );
print( 'Loading config from DB' );
my $dbh = ZoneMinder::Database::zmDbConnect();
if ( !$dbh ) {
print( "Error: unable to load options from database: $DBI::errstr\n" );
@ -188,7 +189,7 @@ sub loadConfigFromDB {
#next if ( $option->{category} eq 'hidden' );
if ( defined($value) ) {
if ( $option->{type} == $types{boolean} ) {
$option->{value} = $value?"yes":"no";
$option->{value} = $value?'yes':'no';
} else {
$option->{value} = $value;
}
@ -201,7 +202,7 @@ sub loadConfigFromDB {
} # end sub loadConfigFromDB
sub saveConfigToDB {
print( "Saving config to DB " . @options . " entries\n" );
print( 'Saving config to DB ' . @options . " entries\n" );
my $dbh = ZoneMinder::Database::zmDbConnect();
if ( !$dbh ) {
print( "Error: unable to save options to database: $DBI::errstr\n" );
@ -214,7 +215,7 @@ sub saveConfigToDB {
$dbh->do('LOCK TABLE Config WRITE')
or croak( "Can't lock Config table: " . $dbh->errstr() );
my $sql = "delete from Config";
my $sql = 'DELETE FROM Config';
my $res = $dbh->do( $sql )
or croak( "Can't do '$sql': ".$dbh->errstr() );
@ -228,8 +229,8 @@ sub saveConfigToDB {
$option->{db_hint} = $option->{type}->{hint};
$option->{db_pattern} = $option->{type}->{pattern};
$option->{db_format} = $option->{type}->{format};
if ( $option->{db_type} eq "boolean" ) {
$option->{db_value} = ($option->{value} eq "yes") ? "1" : "0";
if ( $option->{db_type} eq 'boolean' ) {
$option->{db_value} = ($option->{value} eq 'yes') ? '1' : '0';
} else {
$option->{db_value} = $option->{value};
}
@ -237,7 +238,7 @@ sub saveConfigToDB {
$option->{db_requires} = join( ";",
map {
my $value = $_->{value};
$value = ($value eq "yes") ? 1 : 0 if ( $options_hash{$_->{name}}->{db_type} eq "boolean" );
$value = ($value eq 'yes') ? 1 : 0 if ( $options_hash{$_->{name}}->{db_type} eq 'boolean' );
( "$_->{name}=$value" )
} @$requires
);

View File

@ -2933,6 +2933,16 @@ our @options = (
type => $types{integer},
category => 'highband',
},
{
name => 'ZM_WEB_H_REFRESH_NAVBAR',
default => '5',
description => 'How often (in seconds) the navigation header should refresh itself',
help => q`
The navigation header contains the general status information about server load and storage space.
`,
type => $types{integer},
category => 'highband',
},
{
name => 'ZM_WEB_H_REFRESH_CYCLE',
default => '10',
@ -3196,6 +3206,16 @@ our @options = (
`,
category => 'medband',
},
{
name => 'ZM_WEB_M_REFRESH_NAVBAR',
default => '15',
description => 'How often (in seconds) the navigation header should refresh itself',
help => q`
The navigation header contains the general status information about server load and storage space.
`,
type => $types{integer},
category => 'medband',
},
{
name => 'ZM_WEB_M_REFRESH_CYCLE',
default => '20',
@ -3459,6 +3479,16 @@ our @options = (
type => $types{integer},
category => 'lowband',
},
{
name => 'ZM_WEB_L_REFRESH_NAVBAR',
default => '35',
description => 'How often (in seconds) the navigation header should refresh itself',
help => q`
The navigation header contains the general status information about server load and storage space.
`,
type => $types{integer},
category => 'lowband',
},
{
name => 'ZM_WEB_L_REFRESH_CYCLE',
default => '30',

View File

@ -33,6 +33,8 @@ require ZoneMinder::Object;
require ZoneMinder::Storage;
require Date::Manip;
require File::Find;
require File::Path;
require File::Copy;
#our @ISA = qw(ZoneMinder::Object);
use parent qw(ZoneMinder::Object);
@ -401,6 +403,54 @@ sub DiskSpace {
}
}
sub MoveTo {
my ( $self, $NewStorage ) = @_;
my ( $OldPath ) = ( $self->Path() =~ /^(.*)$/ ); # De-taint
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) {
return "New storage does not have an id. Moving will not happen.";
} elsif ( !$NewPath) {
return "$NewPath is empty.";
}elsif ( $NewPath eq $OldPath ) {
return "New path and old path are the same! $NewPath";
} elsif ( ! -e $NewPath ) {
return "New path $NewPath does not exist.";
}elsif ( ! -e $OldPath ) {
return "Old path $OldPath does not exist.";
}
my $error = '';
File::Path::make_path( $NewPath, {error => \my $err} );
if ( @$err ) {
for my $diag (@$err) {
my ($file, $message) = %$diag;
if ($file eq '') {
$error .= "general error: $message\n";
} else {
$error .= "problem unlinking $file: $message\n";
}
}
}
return $error if $error;
my @files = glob("$OldPath/*");
for my $file (@files) {
next if $file =~ /^\./;
( $file ) = ( $file =~ /^(.*)$/ ); # De-taint
if ( ! File::Copy::copy( $file, $NewPath ) ) {
$error .= "Copy failed: for $file to $NewPath: $!";
last;
}
} # end foreach file.
if ( ! $error ) {
# Succeeded in copying all files, so we may now update the Event.
$$self{StorageId} = $$NewStorage{Id};
$error .= $self->save();
}
return $error;
} # end sub MoveTo
1;
__END__

View File

@ -207,10 +207,11 @@ sub Sql {
if ( $term->{attr} =~ /^Monitor/ ) {
$value = "'$temp_value'";
} elsif ( $term->{attr} eq 'ServerId' ) {
Debug("ServerId, temp_value is ($temp_value) ($ZoneMinder::Config::Config{ZM_SERVER_ID})");
if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$Config{ZM_SERVER_ID}'";
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
# This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server( $Config{ZM_SERVER_ID} );
$$self{Server} = new ZoneMinder::Server( $ZoneMinder::Config::Config{ZM_SERVER_ID} );
} else {
$value = "'$temp_value'";
# This gets used later, I forget for what
@ -225,7 +226,7 @@ sub Sql {
) {
$value = "'$temp_value'";
} elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) {
if ( $temp_value == 'NULL' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL( $temp_value );
@ -237,7 +238,7 @@ sub Sql {
$value = "'$value'";
}
} elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) {
if ( $temp_value == 'NULL' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL( $temp_value );
@ -249,7 +250,7 @@ sub Sql {
$value = "to_days( '$value' )";
}
} elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) {
if ( $temp_value == 'NULL' ) {
if ( $temp_value eq 'NULL' ) {
$value = $temp_value;
} else {
$value = DateTimeToSQL( $temp_value );

View File

@ -47,7 +47,7 @@ use vars qw/ $AUTOLOAD $log $dbh/;
*log = \$ZoneMinder::Logger::logger;
*dbh = \$ZoneMinder::Database::dbh;
my $debug = 1;
my $debug = 0;
use constant DEBUG_ALL=>1;
sub new {

View File

@ -207,7 +207,7 @@ sub getFilters {
} else {
$sql .= ' Background = 1 AND';
}
$sql .= '( AutoArchive = 1
$sql .= '( AutoArchive = 1
or AutoVideo = 1
or AutoUpload = 1
or AutoEmail = 1
@ -215,16 +215,17 @@ sub getFilters {
or AutoExecute = 1
or AutoDelete = 1
or UpdateDiskSpace = 1
or AutoMove = 1
) ORDER BY Name';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr() );
my $res;
if ( $filter_name ) {
$res = $sth->execute( $filter_name )
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
} else {
$res = $sth->execute()
or Fatal( "Unable toexecute '$sql': ".$sth->errstr() );
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
}
FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter );
@ -263,6 +264,7 @@ sub checkFilter {
($filter->{AutoEmail}?'email':()),
($filter->{AutoMessage}?'message':()),
($filter->{AutoExecute}?'execute':()),
($filter->{AutoMove}?'move':()),
($filter->{UpdateDiskSpace}?'update disk space':()),
),
'returned' , scalar @Events , 'events',
@ -270,12 +272,12 @@ sub checkFilter {
) );
foreach my $event ( @Events ) {
Debug( "Checking event $event->{Id}\n" );
Debug( "Checking event $event->{Id}" );
my $delete_ok = !undef;
$dbh->ping();
if ( $filter->{AutoArchive} ) {
Info( "Archiving event $event->{Id}\n" );
# Do it individually to avoid locking up the table for new events
Info( "Archiving event $event->{Id}" );
# Do it individually to avoid locking up the table for new events
my $sql = 'UPDATE Events SET Archived = 1 WHERE Id = ?';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Unable toprepare '$sql': ".$dbh->errstr() );
@ -315,11 +317,17 @@ sub checkFilter {
Error( "Unable toto delete event $event->{Id} as previous operations failed\n" );
}
} # end if AutoDelete
if ( $filter->{AutoMove} ) {
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
my $NewStorage = new ZoneMinder::Storage( $filter->{AutoMoveTo} );
$_ = $Event->MoveTo( $NewStorage );
Error($_) if $_;
}
if ( $filter->{UpdateDiskSpace} ) {
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
$Event->DiskSpace(undef);
$Event->save();
my $Event = new ZoneMinder::Event( $$event{Id}, $event );
$Event->DiskSpace(undef);
$Event->save();
} # end if UpdateDiskSpace
} # end foreach event
}

View File

@ -28,8 +28,9 @@ MYSQL dbconn;
int zmDbConnected = false;
void zmDbConnect() {
if ( zmDbConnected )
return;
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
//if ( zmDbConnected )
//return;
if ( !mysql_init( &dbconn ) ) {
Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) );

View File

@ -190,7 +190,7 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat
return ret;
} else {
s->oformat = oformat;
#if 0
#if 1
// This is some very wrong code, and I don't think it is neccessary
if (s->oformat->priv_data_size > 0) {
s->priv_data = av_mallocz(s->oformat->priv_data_size);

View File

@ -328,6 +328,9 @@ int FfmpegCamera::PostCapture() {
int FfmpegCamera::OpenFfmpeg() {
Debug ( 2, "OpenFfmpeg called." );
uint32_t last_event_id = monitor->GetLastEventId() ;
uint32_t video_writer_event_id = monitor->GetVideoWriterEventId();
Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
int ret;
@ -372,6 +375,9 @@ int FfmpegCamera::OpenFfmpeg() {
//FIXME can speed up initial analysis but need sensible parameters...
//mFormatContext->probesize = 32;
//mFormatContext->max_analyze_duration = 32;
last_event_id = monitor->GetLastEventId() ;
video_writer_event_id = monitor->GetVideoWriterEventId();
Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() );
if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) != 0 )
#endif
@ -380,12 +386,18 @@ int FfmpegCamera::OpenFfmpeg() {
Error( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) );
return -1;
}
AVDictionaryEntry *e;
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
last_event_id = monitor->GetLastEventId() ;
video_writer_event_id = monitor->GetVideoWriterEventId();
Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
AVDictionaryEntry *e=NULL;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Warning( "Option %s not recognized by ffmpeg", e->key);
}
last_event_id = monitor->GetLastEventId() ;
video_writer_event_id = monitor->GetVideoWriterEventId();
Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
mIsOpening = false;
Debug ( 1, "Opened input" );
@ -524,15 +536,15 @@ int FfmpegCamera::OpenFfmpeg() {
Debug ( 1, "Calling avcodec_open2" );
if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) {
#endif
AVDictionaryEntry *e;
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
AVDictionaryEntry *e = NULL;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Warning( "Option %s not recognized by ffmpeg", e->key);
}
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
} else {
AVDictionaryEntry *e;
if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
AVDictionaryEntry *e = NULL;
if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Warning( "Option %s not recognized by ffmpeg", e->key);
}
}
@ -567,7 +579,7 @@ int FfmpegCamera::OpenFfmpeg() {
}
}
Debug ( 1, "Opened codec" );
Debug ( 1, "Opened audio codec" );
// Allocate space for the native video frame
mRawFrame = zm_av_frame_alloc();
@ -666,12 +678,16 @@ int FfmpegCamera::CloseFfmpeg() {
if ( mVideoCodecContext ) {
avcodec_close(mVideoCodecContext);
//av_free(mVideoCodecContext);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_free_context(&mVideoCodecContext);
#endif
mVideoCodecContext = NULL; // Freed by av_close_input_file
}
if ( mAudioCodecContext ) {
avcodec_close(mAudioCodecContext);
//av_free(mAudioCodecContext);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_free_context(&mAudioCodecContext);
#endif
mAudioCodecContext = NULL; // Freed by av_close_input_file
}
@ -780,9 +796,10 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
if ( recording.tv_sec ) {
uint32_t last_event_id = monitor->GetLastEventId() ;
uint32_t video_writer_event_id = monitor->GetVideoWriterEventId();
if ( last_event_id != monitor->GetVideoWriterEventId() ) {
Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, monitor->GetVideoWriterEventId() );
if ( last_event_id != video_writer_event_id ) {
Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, video_writer_event_id );
if ( videoStore ) {
Info("Re-starting video storage module");

View File

@ -73,7 +73,12 @@ std::vector<std::string> split(const std::string &s, char delim) {
return elems;
}
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) {
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) :
id( p_id ),
shared_data(NULL),
trigger_data(NULL),
video_store_data(NULL)
{
strncpy( name, p_name, sizeof(name) );
#if ZM_MEM_MAPPED
@ -468,9 +473,12 @@ Monitor::Monitor(
videoRecording = ((GetOptVideoWriter() == H264PASSTHROUGH) && camera->SupportsNativeVideo());
if ( purpose == ANALYSIS ) {
while( shared_data->last_write_index == (unsigned int)image_buffer_count
&& shared_data->last_write_time == 0) {
Debug(2,"last_write_index(%d), last_write_time(%d)", shared_data->last_write_index, shared_data->last_write_time );
while(
( shared_data->last_write_index == (unsigned int)image_buffer_count )
&&
( shared_data->last_write_time == 0)
) {
Warning( "Waiting for capture daemon" );
sleep( 1 );
}
@ -771,7 +779,14 @@ unsigned int Monitor::GetLastWriteIndex() const {
return( shared_data->last_write_index!=(unsigned int)image_buffer_count?shared_data->last_write_index:-1 );
}
unsigned int Monitor::GetLastEvent() const {
uint32_t Monitor::GetLastEventId() const {
Debug(2, "mem_ptr(%x), State(%d) last_read_index(%d) last_read_time(%d) last_event(%d)",
mem_ptr,
shared_data->state,
shared_data->last_read_index,
shared_data->last_read_time,
shared_data->last_event
);
return( shared_data->last_event );
}

View File

@ -432,7 +432,6 @@ public:
int GetOptSaveJPEGs() const { return( savejpegspref ); }
VideoWriter GetOptVideoWriter() const { return( videowriter ); }
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return( &encoderparamsvec ); }
uint32_t GetLastEventId() const { return shared_data->last_event; }
uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; }
void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; }
@ -448,7 +447,7 @@ public:
int GetAlarmCaptureDelay() const { return( alarm_capture_delay ); }
unsigned int GetLastReadIndex() const;
unsigned int GetLastWriteIndex() const;
unsigned int GetLastEvent() const;
uint32_t GetLastEventId() const;
double GetFPS() const;
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
void ForceAlarmOff();

View File

@ -69,8 +69,8 @@ void StreamBase::updateFrameRate( double fps ) {
while( effective_fps > maxfps ) {
effective_fps /= 2.0;
frame_mod *= 2;
}
Debug( 3, "aEFPS:%.2f, aFM:%d", effective_fps, frame_mod );
}
}
bool StreamBase::checkCommandQueue() {

View File

@ -195,6 +195,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
converted_in_samples = NULL;
audio_out_codec = NULL;
audio_in_codec = NULL;
audio_in_ctx = NULL;
audio_out_stream = NULL;
in_frame = NULL;
@ -411,12 +412,34 @@ VideoStore::~VideoStore() {
// Just do a file open/close/writeheader/etc.
// What if we were only doing audio recording?
if (video_out_stream) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// We allocate and copy in newer ffmpeg, so need to free it
avcodec_free_context(&video_in_ctx);
#endif
video_in_ctx=NULL;
avcodec_close(video_out_ctx);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_free_context(&video_out_ctx);
#endif
video_out_ctx = NULL;
Debug(4, "Success freeing video_out_ctx");
}
if (audio_out_stream) {
if ( audio_out_stream ) {
if ( audio_in_codec ) {
avcodec_close(audio_in_ctx);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// We allocate and copy in newer ffmpeg, so need to free it
avcodec_free_context(&audio_in_ctx);
#endif
audio_in_ctx = NULL;
audio_in_codec = NULL;
} // end if audio_in_codec
avcodec_close(audio_out_ctx);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_free_context(&audio_out_ctx);
#endif
audio_out_ctx = NULL;
#ifdef HAVE_LIBAVRESAMPLE
if (resample_ctx) {
@ -459,10 +482,10 @@ bool VideoStore::setup_resampler() {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
// decoder, can't reuse the one from the camera.
AVCodec *audio_in_codec =
audio_in_codec =
avcodec_find_decoder(audio_in_stream->codecpar->codec_id);
#else
AVCodec *audio_in_codec =
audio_in_codec =
avcodec_find_decoder(audio_in_ctx->codec_id);
#endif
ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL);
@ -783,7 +806,6 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
}
opkt.flags = ipkt->flags;
int keyframe = opkt.flags & AV_PKT_FLAG_KEY;
opkt.pos = -1;
opkt.data = ipkt->data;
@ -797,7 +819,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
Debug(1,
"writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) "
"ipkt.duration(%d)",
keyframe, opkt.pts, opkt.dts, duration, ipkt->duration);
opkt.flags & AV_PKT_FLAG_KEY, opkt.pts, opkt.dts, duration, ipkt->duration);
if ((opkt.data == NULL) || (opkt.size < 1)) {
Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__);
dumpPacket(ipkt);
@ -870,6 +892,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
* If we are at the end of the file, pass an empty packet to the decoder
* to flush it.
*/
int data_present;
if ((ret = avcodec_decode_audio4(audio_in_ctx, in_frame,
&data_present, ipkt)) < 0) {
Error("Could not decode frame (error '%s')\n",

View File

@ -16,7 +16,6 @@ extern "C" {
class VideoStore {
private:
unsigned int packets_written;
AVOutputFormat *out_format;
AVFormatContext *oc;
@ -34,13 +33,13 @@ private:
AVFrame *out_frame;
AVCodecContext *video_in_ctx;
AVCodec *audio_in_codec;
AVCodecContext *audio_in_ctx;
int ret;
// The following are used when encoding the audio stream to AAC
AVCodec *audio_out_codec;
AVCodecContext *audio_out_ctx;
int data_present;
AVAudioFifo *fifo;
int out_frame_size;
#ifdef HAVE_LIBAVRESAMPLE

View File

@ -514,10 +514,10 @@ int main( int argc, char *argv[] ) {
}
if ( function & ZMU_EVENT ) {
if ( verbose )
printf( "Last event id: %d\n", monitor->GetLastEvent() );
printf( "Last event id: %d\n", monitor->GetLastEventId() );
else {
if ( have_output ) printf( "%c", separator );
printf( "%d", monitor->GetLastEvent() );
printf( "%d", monitor->GetLastEventId() );
have_output = true;
}
}
@ -712,7 +712,7 @@ int main( int argc, char *argv[] ) {
tv.tv_sec, tv.tv_usec/10000,
monitor->GetLastReadIndex(),
monitor->GetLastWriteIndex(),
monitor->GetLastEvent(),
monitor->GetLastEventId(),
monitor->GetFPS()
);
delete monitor;

View File

@ -1 +1 @@
1.31.15
1.31.16

View File

@ -76,6 +76,19 @@ if ( canView( 'Events' ) ) {
ajaxError( 'Export Failed' );
break;
}
case 'download' :
{
require_once( ZM_SKIN_PATH.'/includes/export_functions.php' );
$exportVideo = 1;
$exportFormat = $_REQUEST['exportFormat'];
$exportStructure = 'flat';
$exportIds = !empty($_REQUEST['eids'])?$_REQUEST['eids']:$_REQUEST['id'];
if ( $exportFile = exportEvents( $exportIds, false, false, false, $exportVideo, false, $exportFormat, $exportStructure ) )
ajaxResponse( array( 'exportFile'=>$exportFile ) );
else
ajaxError( 'Export Failed' );
break;
}
}
}

View File

@ -1,4 +1,8 @@
<?php
if ($_REQUEST['entity'] == "navBar") {
ajaxResponse(getNavBarHtml('reload'));
return;
}
$statusData = array(
'system' => array(

View File

@ -116,7 +116,9 @@ switch ( $data['type'] ) {
case MSG_DATA_WATCH :
{
$data = unpack( "ltype/imonitor/istate/dfps/ilevel/irate/ddelay/izoom/Cdelayed/Cpaused/Cenabled/Cforced", $msg );
Logger::Debug("FPS: " . $data['fps'] );
$data['fps'] = round( $data['fps'], 2 );
Logger::Debug("FPS: " . $data['fps'] );
$data['rate'] /= RATE_BASE;
$data['delay'] = round( $data['delay'], 2 );
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );

View File

@ -14,16 +14,14 @@ class EventsController extends AppController {
*/
public $components = array('RequestHandler', 'Scaler', 'Image', 'Paginator');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('eventPermission');
if ($canView =='None')
{
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('eventPermission');
if ($canView =='None') {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
@ -48,14 +46,7 @@ public function beforeFilter() {
} else {
$conditions = array();
}
// How many events to return
$this->loadModel('Config');
$limit = $this->Config->find('list', array(
'conditions' => array('Name' => 'ZM_WEB_EVENTS_PER_PAGE'),
'fields' => array('Name', 'Value')
));
$this->Paginator->settings = array(
$settings = array(
// https://github.com/ZoneMinder/ZoneMinder/issues/995
// 'limit' => $limit['ZM_WEB_EVENTS_PER_PAGE'],
// 25 events per page which is what the above
@ -65,11 +56,31 @@ public function beforeFilter() {
// make a nice ZM_API_ITEMS_PER_PAGE for all pagination
// API
'limit' => '100',
'limit' => '100',
'order' => array('StartTime', 'MaxScore'),
'paramType' => 'querystring',
'conditions' => array (array($conditions, $mon_options))
);
);
//if ( $this->request->params['GroupId'] ) {
$settings['joins'] = array(
array(
'table' => 'Groups_Monitors',
'type' => 'inner',
'conditions' => array(
'Groups_Monitors.MonitorId = Event.MonitorId'
),
),
);
$settings['contain'] = array('Group');
//}
$settings['conditions'] = array($conditions, $mon_options);
// How many events to return
$this->loadModel('Config');
$limit = $this->Config->find('list', array(
'conditions' => array('Name' => 'ZM_WEB_EVENTS_PER_PAGE'),
'fields' => array('Name', 'Value')
));
$this->Paginator->settings = $settings;
$events = $this->Paginator->paginate('Event');
// For each event, get its thumbnail data (path, width, height)
@ -89,282 +100,281 @@ public function beforeFilter() {
* @param string $id
* @return void
*/
public function view($id = null)
{
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),
'conditions' => array('Name' => array('ZM_DIR_EVENTS'))
));
public function view($id = null) {
$this->loadModel('Config');
$configs = $this->Config->find('list', array(
'fields' => array('Name', 'Value'),
'conditions' => array('Name' => array('ZM_DIR_EVENTS'))
));
$this->Event->recursive = 1;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$this->Event->recursive = 1;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
if (!empty($allowedMonitors))
{
$mon_options = array('Event.MonitorId' => $allowedMonitors);
}
else
{
$mon_options='';
}
$options = array('conditions' => array(array('Event.' . $this->Event->primaryKey => $id), $mon_options));
$event = $this->Event->find('first', $options);
if (!empty($allowedMonitors))
{
$mon_options = array('Event.MonitorId' => $allowedMonitors);
}
else
{
$mon_options='';
}
$path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/';
$event['Event']['BasePath'] = $path;
$options = array('conditions' => array(array('Event.' . $this->Event->primaryKey => $id), $mon_options));
$event = $this->Event->find('first', $options);
# Get the previous and next events for any monitor
$this->Event->id = $id;
$event_neighbors = $this->Event->find('neighbors');
$event['Event']['Next'] = $event_neighbors['next']['Event']['Id'];
$event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id'];
$path = $configs['ZM_DIR_EVENTS'].'/'.$this->Image->getEventPath($event).'/';
$event['Event']['BasePath'] = $path;
# Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array(
'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId'])
));
$event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id'];
$event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id'];
# Get the previous and next events for any monitor
$this->Event->id = $id;
$event_neighbors = $this->Event->find('neighbors');
$event['Event']['Next'] = $event_neighbors['next']['Event']['Id'];
$event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id'];
$this->set(array(
'event' => $event,
'_serialize' => array('event')
));
}
# Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array(
'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId'])
));
$event['Event']['NextOfMonitor'] = $event_monitor_neighbors['next']['Event']['Id'];
$event['Event']['PrevOfMonitor'] = $event_monitor_neighbors['prev']['Event']['Id'];
$this->set(array(
'event' => $event,
'_serialize' => array('event')
));
}
/**
* add method
*
* @return void
*/
public function add() {
/**
* add method
*
* @return void
*/
public function add() {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->request->is('post')) {
$this->Event->create();
if ($this->Event->save($this->request->data)) {
return $this->flash(__('The event has been saved.'), array('action' => 'index'));
}
}
$monitors = $this->Event->Monitor->find('list');
$this->set(compact('monitors'));
}
if ($this->request->is('post')) {
$this->Event->create();
if ($this->Event->save($this->request->data)) {
return $this->flash(__('The event has been saved.'), array('action' => 'index'));
}
}
$monitors = $this->Event->Monitor->find('list');
$this->set(compact('monitors'));
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id;
$this->Event->id = $id;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
if ($this->Event->save($this->request->data)) {
$message = 'Saved';
} else {
$message = 'Error';
}
if ($this->Event->save($this->request->data)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id;
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
$this->request->allowMethod('post', 'delete');
if ($this->Event->delete()) {
//$this->loadModel('Frame');
//$this->Event->Frame->delete();
return $this->flash(__('The event has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index'));
}
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
if ($this->Session->Read('eventPermission') != 'Edit')
{
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Event->id = $id;
if (!$this->Event->exists()) {
throw new NotFoundException(__('Invalid event'));
}
$this->request->allowMethod('post', 'delete');
if ($this->Event->delete()) {
//$this->loadModel('Frame');
//$this->Event->Frame->delete();
return $this->flash(__('The event has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The event could not be deleted. Please, try again.'), array('action' => 'index'));
}
}
public function search() {
$this->Event->recursive = -1;
$conditions = array();
public function search() {
$this->Event->recursive = -1;
$conditions = array();
foreach ($this->params['named'] as $param_name => $value) {
// Transform params into mysql
if (preg_match("/interval/i", $value, $matches)) {
$condition = array("$param_name >= (date_sub(now(), $value))");
} else {
$condition = array($param_name => $value);
}
array_push($conditions, $condition);
}
foreach ($this->params['named'] as $param_name => $value) {
// Transform params into mysql
if (preg_match("/interval/i", $value, $matches)) {
$condition = array("$param_name >= (date_sub(now(), $value))");
} else {
$condition = array($param_name => $value);
}
array_push($conditions, $condition);
}
$results = $this->Event->find('all', array(
'conditions' => $conditions
));
$results = $this->Event->find('all', array(
'conditions' => $conditions
));
$this->set(array(
'results' => $results,
'_serialize' => array('results')
));
$this->set(array(
'results' => $results,
'_serialize' => array('results')
));
}
// format expected:
// you can changed AlarmFrames to any other named params
// consoleEvents/1 hour/AlarmFrames >=: 1/AlarmFrames <=: 20.json
}
public function consoleEvents($interval = null) {
$this->Event->recursive = -1;
$results = array();
// format expected:
// you can changed AlarmFrames to any other named params
// consoleEvents/1 hour/AlarmFrames >=: 1/AlarmFrames <=: 20.json
$moreconditions ="";
foreach ($this->request->params['named'] as $name => $param) {
$moreconditions = $moreconditions . " AND ".$name.$param;
}
$query = $this->Event->query("select MonitorId, COUNT(*) AS Count from Events WHERE (StartTime >= (DATE_SUB(NOW(), interval $interval)) $moreconditions) GROUP BY MonitorId;");
public function consoleEvents($interval = null) {
$this->Event->recursive = -1;
$results = array();
foreach ($query as $result) {
$results[$result['Events']['MonitorId']] = $result[0]['Count'];
}
$moreconditions ="";
foreach ($this->request->params['named'] as $name => $param) {
$moreconditions = $moreconditions . " AND ".$name.$param;
}
$this->set(array(
'results' => $results,
'_serialize' => array('results')
));
}
$query = $this->Event->query("select MonitorId, COUNT(*) AS Count from Events WHERE (StartTime >= (DATE_SUB(NOW(), interval $interval)) $moreconditions) GROUP BY MonitorId;");
// Create a thumbnail and return the thumbnail's data for a given event id.
public function createThumbnail($id = null) {
$this->Event->recursive = -1;
foreach ($query as $result) {
$results[$result['Events']['MonitorId']] = $result[0]['Count'];
}
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$this->set(array(
'results' => $results,
'_serialize' => array('results')
));
}
$event = $this->Event->find('first', array(
'conditions' => array('Id' => $id)
));
// Create a thumbnail and return the thumbnail's data for a given event id.
public function createThumbnail($id = null) {
$this->Event->recursive = -1;
// Find the max Frame for this Event. Error out otherwise.
$this->loadModel('Frame');
if (! $frame = $this->Frame->find('first', array(
'conditions' => array(
'EventId' => $event['Event']['Id'],
'Score' => $event['Event']['MaxScore']
)
))) {
throw new NotFoundException(__("Can not find Frame for Event " . $event['Event']['Id']));
}
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$this->loadModel('Config');
$event = $this->Event->find('first', array(
'conditions' => array('Id' => $id)
));
// Get the config options required for reScale and getImageSrc
// The $bw, $thumbs and unset() code is a workaround / temporary
// until I have a better way of handing per-bandwidth config options
$bw = (isset($_COOKIE['zmBandwidth']) ? strtoupper(substr($_COOKIE['zmBandwidth'], 0, 1)) : 'L');
$thumbs = "ZM_WEB_${bw}_SCALE_THUMBS";
// Find the max Frame for this Event. Error out otherwise.
$this->loadModel('Frame');
if (! $frame = $this->Frame->find('first', array(
'conditions' => array(
'EventId' => $event['Event']['Id'],
'Score' => $event['Event']['MaxScore']
)
))) {
throw new NotFoundException(__("Can not find Frame for Event " . $event['Event']['Id']));
}
$config = $this->Config->find('list', array(
'conditions' => array('OR' => array(
'Name' => array('ZM_WEB_LIST_THUMB_WIDTH',
'ZM_WEB_LIST_THUMB_HEIGHT',
'ZM_EVENT_IMAGE_DIGITS',
'ZM_DIR_IMAGES',
"$thumbs",
'ZM_DIR_EVENTS'
)
)),
'fields' => array('Name', 'Value')
));
$config['ZM_WEB_SCALE_THUMBS'] = $config[$thumbs];
unset($config[$thumbs]);
$this->loadModel('Config');
// reScale based on either the width, or the hight, of the event.
if ( $config['ZM_WEB_LIST_THUMB_WIDTH'] ) {
$thumbWidth = $config['ZM_WEB_LIST_THUMB_WIDTH'];
$scale = (100 * $thumbWidth) / $event['Event']['Width'];
$thumbHeight = $this->Scaler->reScale( $event['Event']['Height'], $scale );
}
elseif ( $config['ZM_WEB_LIST_THUMB_HEIGHT'] ) {
$thumbHeight = $config['ZM_WEB_LIST_THUMB_HEIGHT'];
$scale = (100*$thumbHeight)/$event['Event']['Height'];
$thumbWidth = $this->Scaler->reScale( $event['Event']['Width'], $scale );
}
else {
throw new NotFoundException(__('No thumbnail width or height specified, please check in Options->Web'));
}
// Get the config options required for reScale and getImageSrc
// The $bw, $thumbs and unset() code is a workaround / temporary
// until I have a better way of handing per-bandwidth config options
$bw = (isset($_COOKIE['zmBandwidth']) ? strtoupper(substr($_COOKIE['zmBandwidth'], 0, 1)) : 'L');
$thumbs = "ZM_WEB_${bw}_SCALE_THUMBS";
$imageData = $this->Image->getImageSrc( $event, $frame, $scale, $config );
$thumbData['Path'] = $imageData['thumbPath'];
$thumbData['Width'] = (int)$thumbWidth;
$thumbData['Height'] = (int)$thumbHeight;
return( $thumbData );
$config = $this->Config->find('list', array(
'conditions' => array('OR' => array(
'Name' => array('ZM_WEB_LIST_THUMB_WIDTH',
'ZM_WEB_LIST_THUMB_HEIGHT',
'ZM_EVENT_IMAGE_DIGITS',
'ZM_DIR_IMAGES',
"$thumbs",
'ZM_DIR_EVENTS'
)
)),
'fields' => array('Name', 'Value')
));
$config['ZM_WEB_SCALE_THUMBS'] = $config[$thumbs];
unset($config[$thumbs]);
}
// reScale based on either the width, or the hight, of the event.
if ( $config['ZM_WEB_LIST_THUMB_WIDTH'] ) {
$thumbWidth = $config['ZM_WEB_LIST_THUMB_WIDTH'];
$scale = (100 * $thumbWidth) / $event['Event']['Width'];
$thumbHeight = $this->Scaler->reScale( $event['Event']['Height'], $scale );
}
elseif ( $config['ZM_WEB_LIST_THUMB_HEIGHT'] ) {
$thumbHeight = $config['ZM_WEB_LIST_THUMB_HEIGHT'];
$scale = (100*$thumbHeight)/$event['Event']['Height'];
$thumbWidth = $this->Scaler->reScale( $event['Event']['Width'], $scale );
}
else {
throw new NotFoundException(__('No thumbnail width or height specified, please check in Options->Web'));
}
public function archive($id = null) {
$this->Event->recursive = -1;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
$imageData = $this->Image->getImageSrc( $event, $frame, $scale, $config );
$thumbData['Path'] = $imageData['thumbPath'];
$thumbData['Width'] = (int)$thumbWidth;
$thumbData['Height'] = (int)$thumbHeight;
// Get the current value of Archive
$archived = $this->Event->find('first', array(
'fields' => array('Event.Archived'),
'conditions' => array('Event.Id' => $id)
));
// If 0, 1, if 1, 0
$archiveVal = (($archived['Event']['Archived'] == 0) ? 1 : 0);
return( $thumbData );
// Save the new value
$this->Event->id = $id;
$this->Event->saveField('Archived', $archiveVal);
}
$this->set(array(
'archived' => $archiveVal,
'_serialize' => array('archived')
));
}
public function archive($id = null) {
$this->Event->recursive = -1;
if (!$this->Event->exists($id)) {
throw new NotFoundException(__('Invalid event'));
}
// Get the current value of Archive
$archived = $this->Event->find('first', array(
'fields' => array('Event.Archived'),
'conditions' => array('Event.Id' => $id)
));
// If 0, 1, if 1, 0
$archiveVal = (($archived['Event']['Archived'] == 0) ? 1 : 0);
// Save the new value
$this->Event->id = $id;
$this->Event->saveField('Archived', $archiveVal);
$this->set(array(
'archived' => $archiveVal,
'_serialize' => array('archived')
));
}
}

View File

@ -0,0 +1,108 @@
<?php
App::uses('AppController', 'Controller');
/**
* Groups Controller
*
* @property Group $Group
*/
class GroupsController extends AppController {
/**
* Components
*
* @var array
*/
public $components = array('RequestHandler');
/**
* index method
*
* @return void
*/
public function index() {
$this->Group->recursive = -1;
$groups = $this->Group->find('all');
$this->set(array(
'groups' => $groups,
'_serialize' => array('groups')
));
}
/**
* view method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function view($id = null) {
$this->Group->recursive = -1;
if (!$this->Group->exists($id)) {
throw new NotFoundException(__('Invalid group'));
}
$options = array('conditions' => array('Group.' . $this->Group->primaryKey => $id));
$group = $this->Group->find('first', $options);
$this->set(array(
'group' => $group,
'_serialize' => array('group')
));
}
/**
* add method
*
* @return void
*/
public function add() {
if ($this->request->is('post')) {
$this->Group->create();
if ($this->Group->save($this->request->data)) {
return $this->flash(__('The group has been saved.'), array('action' => 'index'));
}
}
$monitors = $this->Group->Monitor->find('list');
$this->set(compact('monitors'));
}
/**
* edit method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function edit($id = null) {
if (!$this->Group->exists($id)) {
throw new NotFoundException(__('Invalid group'));
}
if ($this->request->is(array('post', 'put'))) {
if ($this->Group->save($this->request->data)) {
return $this->flash(__('The group has been saved.'), array('action' => 'index'));
}
} else {
$options = array('conditions' => array('Group.' . $this->Group->primaryKey => $id));
$this->request->data = $this->Group->find('first', $options);
}
$monitors = $this->Group->Monitor->find('list');
$this->set(compact('monitors'));
}
/**
* delete method
*
* @throws NotFoundException
* @param string $id
* @return void
*/
public function delete($id = null) {
$this->Group->id = $id;
if (!$this->Group->exists()) {
throw new NotFoundException(__('Invalid group'));
}
$this->request->allowMethod('post', 'delete');
if ($this->Group->delete()) {
return $this->flash(__('The group has been deleted.'), array('action' => 'index'));
} else {
return $this->flash(__('The group could not be deleted. Please, try again.'), array('action' => 'index'));
}
}}

View File

@ -8,7 +8,6 @@ App::uses('AppController', 'Controller');
*/
class MonitorsController extends AppController {
/**
* Components
*
@ -16,18 +15,14 @@ class MonitorsController extends AppController {
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('monitorPermission');
if ($canView =='None')
{
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('monitorPermission');
if ($canView =='None') {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
@ -36,7 +31,7 @@ public function beforeFilter() {
*/
public function index() {
$this->Monitor->recursive = 0;
if ($this->request->params['named']) {
$this->FilterComponent = $this->Components->load('Filter');
$conditions = $this->FilterComponent->buildFilter($this->request->params['named']);
@ -48,7 +43,28 @@ public function beforeFilter() {
if (!empty($allowedMonitors)) {
$conditions['Monitor.Id' ] = $allowedMonitors;
}
$monitors = $this->Monitor->find('all',array('conditions'=>$conditions));
$find_array = array('conditions'=>$conditions,'contain'=>array('Group'));
//if ( $this->request->params['GroupId'] ) {
$find_array['joins'] = array(
array(
'table' => 'Groups_Monitors',
'type' => 'inner',
'conditions' => array(
'Groups_Monitors.MonitorId = Monitor.Id'
),
),
//array(
//'table' => 'Groups',
//'type' => 'inner',
//'conditions' => array(
//'Groups.Id = Groups_Monitors.GroupId',
//'Groups.Id' => $this->request->params['GroupId'],
//),
//)
);
//}
$monitors = $this->Monitor->find('all',$find_array);
$this->set(array(
'monitors' => $monitors,
'_serialize' => array('monitors')

View File

@ -68,4 +68,28 @@ class Event extends AppModel {
)
);
/**
* * * hasMany associations
* * *
* * * @var array
* * */
public $hasAndBelongsToMany = array(
'Group' => array(
'className' => 'Group',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'MonitorId',
'associationForeignKey' => 'GroupId',
'unique' => true,
'dependent' => false,
'conditions' => 'Groups_Monitors.MonitorId=Event.MonitorId',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
}

View File

@ -0,0 +1,68 @@
<?php
App::uses('AppModel', 'Model');
/**
* Group Model
*
* @property Event $Event
*/
class Group extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Groups';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'Name' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
);
public $recursive = -1;
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* hasMany associations
*
* @var array
*/
public $hasMany = array(
'Monitor' => array(
'className' => 'Monitor',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'GroupId',
'associationForeignKey' => 'MonitorId',
'unique'=>true,
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
}

View File

@ -85,4 +85,28 @@ class Monitor extends AppModel {
)
);
/**
* * hasMany associations
* *
* * @var array
* */
public $hasAndBelongsToMany = array(
'Group' => array(
'className' => 'Group',
'joinTable' => 'Groups_Monitors',
'foreignKey' => 'MonitorId',
'associationForeignKey' => 'GroupId',
'unique' => true,
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
);
}

View File

@ -1,2 +1,2 @@
$xml = Xml::fromArray(array('response' => $monitors));
$xml = Xml::fromArray(array('response' => $servers));
echo $xml->asXML();

View File

@ -1,2 +1,2 @@
$xml = Xml::fromArray(array('response' => $monitor));
$xml = Xml::fromArray(array('response' => $server));
echo $xml->asXML();

View File

@ -12,6 +12,8 @@ public $defaults = array(
'AutoArchive' => 0,
'AutoVideo' => 0,
'AutoMessage' => 0,
'AutoMove' => 0,
'AutoMoveTo' => 0,
'UpdateDiskSpace' => 0,
'Background' => 0,
'Concurrent' => 0,

View File

@ -6,7 +6,6 @@ public $defaults = array(
'Id' => null,
'Name' => '',
'ParentId' => null,
'MonitorIds' => '',
);
public function __construct( $IdOrRow=NULL ) {
@ -88,7 +87,8 @@ public $defaults = array(
public function delete() {
if ( array_key_exists( 'Id', $this ) ) {
dbQuery( 'DELETE FROM Groups WHERE Id = ?', array($this->{'Id'}) );
dbQuery( 'DELETE FROM Groups WHERE Id=?', array($this->{'Id'}) );
dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($this->{'Id'}) );
if ( isset($_COOKIE['zmGroup']) ) {
if ( $this->{'Id'} == $_COOKIE['zmGroup'] ) {
unset( $_COOKIE['zmGroup'] );
@ -128,6 +128,13 @@ public $defaults = array(
return $this->{'depth'};
} // end public function depth
public function MonitorIds( ) {
if ( ! array_key_exists( 'MonitorIds', $this ) ) {
$this->{'MonitorIds'} = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($this->{'Id'}) );
}
return $this->{'MonitorIds'};
}
public static function get_group_dropdowns() {
# This will end up with the group_id of the deepest selection
$group_id = 0;
@ -164,19 +171,14 @@ public $defaults = array(
return $group_id;
} # end public static function get_group_dropdowns()
public static function get_group_sql( $group_id ) {
$groupSql = '';
if ( $group_id ) {
if ( $group = dbFetchOne( 'SELECT MonitorIds FROM Groups WHERE Id=?', NULL, array($group_id) ) ) {
$groupIds = array();
if ( $group['MonitorIds'] )
$groupIds = explode( ',', $group['MonitorIds'] );
$MonitorIds = dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId=?', 'MonitorId', array($group_id) );
foreach ( dbFetchAll( 'SELECT MonitorIds FROM Groups WHERE ParentId = ?', NULL, array($group_id) ) as $group )
if ( $group['MonitorIds'] )
$groupIds = array_merge( $groupIds, explode( ',', $group['MonitorIds'] ) );
}
$groupSql = " find_in_set( Id, '".implode( ',', $groupIds )."' )";
$MonitorIds = array_merge( $MonitorIds, dbFetchAll( 'SELECT MonitorId FROM Groups_Monitors WHERE GroupId IN (SELECT Id FROM Groups WHERE ParentId = ?)', 'MonitorId', array($group_id) ) );
$groupSql = " find_in_set( Id, '".implode( ',', $MonitorIds )."' )";
}
return $groupSql;
} # end public static function get_group_sql( $group_id )

View File

@ -142,7 +142,6 @@ if ( canView( 'Events' ) ) {
if ( isset( $_REQUEST['object'] ) and ( $_REQUEST['object'] == 'filter' ) ) {
if ( $action == 'addterm' ) {
Warning("Addterm");
$_REQUEST['filter'] = addFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
} elseif ( $action == 'delterm' ) {
$_REQUEST['filter'] = delFilterTerm( $_REQUEST['filter'], $_REQUEST['line'] );
@ -173,6 +172,11 @@ Warning("Addterm");
$sql .= ', AutoExecute = '. ( !empty($_REQUEST['filter']['AutoExecute']) ? 1 : 0);
$sql .= ', AutoExecuteCmd = '.dbEscape($_REQUEST['filter']['AutoExecuteCmd']);
$sql .= ', AutoDelete = '. ( !empty($_REQUEST['filter']['AutoDelete']) ? 1 : 0);
if ( !empty($_REQUEST['filter']['AutoMove']) ? 1 : 0) {
$sql .= ', AutoMove = 1, AutoMoveTo='. validInt($_REQUEST['filter']['AutoMoveTo']);
} else {
$sql .= ', AutoMove = 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);
@ -542,7 +546,7 @@ if ( canEdit( 'Monitors' ) ) {
$saferName = basename($_REQUEST['newMonitor']['Name']);
symlink( $mid, ZM_DIR_EVENTS.'/'.$saferName );
if ( isset($_COOKIE['zmGroup']) ) {
dbQuery( "UPDATE Groups SET MonitorIds = concat(MonitorIds,',".$mid."') WHERE Id=?", array($_COOKIE['zmGroup']) );
dbQuery( 'INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($_COOKIE['zmGroup'],$mid) );
}
} else {
Error("Users with Monitors restrictions cannot create new monitors.");
@ -662,12 +666,16 @@ if ( canEdit( 'Groups' ) ) {
if ( $action == 'group' ) {
$monitors = empty( $_POST['newGroup']['MonitorIds'] ) ? '' : implode(',', $_POST['newGroup']['MonitorIds']);
if ( !empty($_POST['gid']) ) {
dbQuery( 'UPDATE Groups SET Name=?, ParentId=?, MonitorIds=? WHERE Id=?',
array($_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors, $_POST['gid']) );
dbQuery( 'UPDATE Groups SET Name=?, ParentId=? WHERE Id=?',
array($_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $_POST['gid']) );
dbQuery( 'DELETE FROM Groups_Monitors WHERE GroupId=?', array($_POST['gid']) );
} else {
dbQuery( 'INSERT INTO Groups SET Name=?, ParentId=?, MonitorIds=?',
array( $_POST['newGroup']['Name'], ( $_POST['newGroup']['ParentId'] == '' ? null : $_POST['newGroup']['ParentId'] ), $monitors ) );
}
foreach ( $_POST['newGroup']['MonitorIds'] as $mid ) {
dbQuery( 'INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($_POST['gid'], $mid) );
}
$view = 'none';
$refreshParent = true;
} else if ( $action == 'delete' ) {

View File

@ -137,19 +137,19 @@ require_once( 'database.php' );
loadConfig();
$GLOBALS['defaultUser'] = array(
"Username" => "admin",
"Password" => "",
"Language" => "",
"Enabled" => 1,
"Stream" => 'View',
"Events" => 'Edit',
"Control" => 'Edit',
"Monitors" => 'Edit',
"Groups" => 'Edit',
"Devices" => 'Edit',
"System" => 'Edit',
"MaxBandwidth" => "",
"MonitorIds" => false
'Username' => "admin",
'Password' => "",
'Language' => "",
'Enabled' => 1,
'Stream' => 'View',
'Events' => 'Edit',
'Control' => 'Edit',
'Monitors' => 'Edit',
'Groups' => 'Edit',
'Devices' => 'Edit',
'System' => 'Edit',
'MaxBandwidth' => '',
'MonitorIds' => false
);
function loadConfig( $defineConsts=true ) {
@ -179,7 +179,7 @@ function loadConfig( $defineConsts=true ) {
}
require_once( 'logger.php' );
// For Human-readability, user ZM_SERVER in zm.conf, and convert it here to a ZM_SERVER_ID
// For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID
if ( ! defined('ZM_SERVER_ID') ) {
if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) {
$server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_NAME));

View File

@ -189,21 +189,21 @@ function csrf_check($fatal = true) {
$tokens = '';
do {
if (!isset($_POST[$name])) {
Logger::Debug("POST[$name] is not set");
#Logger::Debug("POST[$name] is not set");
break;
} else {
Logger::Debug("POST[$name] is set as " . $_POST[$name] );
#} else {
#Logger::Debug("POST[$name] is set as " . $_POST[$name] );
}
// we don't regenerate a token and check it because some token creation
// schemes are volatile.
$tokens = $_POST[$name];
if (!csrf_check_tokens($tokens)) {
Logger::Debug("Failed checking tokens");
#Logger::Debug("Failed checking tokens");
break;
} else {
Logger::Debug("Token passed");
#} else {
#Logger::Debug("Token passed");
}
$ok = true;
} while (false);
@ -308,27 +308,27 @@ function csrf_check_tokens($tokens) {
* Checks if a token is valid.
*/
function csrf_check_token($token) {
Logger::Debug("Checking CSRF token $token");
#Logger::Debug("Checking CSRF token $token");
if (strpos($token, ':') === false) {
Logger::Debug("Checking CSRF token $token bad because no :");
#Logger::Debug("Checking CSRF token $token bad because no :");
return false;
}
list($type, $value) = explode(':', $token, 2);
if (strpos($value, ',') === false) {
Logger::Debug("Checking CSRF token $token bad because no ,");
#Logger::Debug("Checking CSRF token $token bad because no ,");
return false;
}
list($x, $time) = explode(',', $token, 2);
if ($GLOBALS['csrf']['expires']) {
if (time() > $time + $GLOBALS['csrf']['expires']) {
Logger::Debug("Checking CSRF token $token bad because expired");
#Logger::Debug("Checking CSRF token $token bad because expired");
return false;
}
}
switch ($type) {
case 'sid':
{
Logger::Debug("Checking sid: $value === " . csrf_hash(session_id(), $time) );
#Logger::Debug("Checking sid: $value === " . csrf_hash(session_id(), $time) );
return $value === csrf_hash(session_id(), $time);
}
case 'cookie':
@ -341,7 +341,7 @@ return false;
Logger::Debug("Checking key: no key set" );
return false;
}
Logger::Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );
#Logger::Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );
return $value === csrf_hash($GLOBALS['csrf']['key'], $time);
// We could disable these 'weaker' checks if 'key' was set, but
// that doesn't make me feel good then about the cookie-based

View File

@ -134,7 +134,7 @@ function dbQuery( $sql, $params=NULL ) {
} else {
$result = $dbConn->query( $sql );
}
if ( 0 ) {
if ( defined('ZM_DB_DEBUG') ) {
if ( $params )
Warning("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() );
else

View File

@ -1872,7 +1872,10 @@ function monitorIdsToNames( $ids ) {
}
}
$names = array();
foreach ( preg_split( '/\s*,\s*/', $ids ) as $id ) {
if ( ! is_array($ids) ) {
$ids = preg_split( '/\s*,\s*/', $ids );
}
foreach ( $ids as $id ) {
if ( visibleMonitor( $id ) ) {
if ( isset($mITN_monitors[$id]) ) {
$names[] = $mITN_monitors[$id]['Name'];

View File

@ -195,7 +195,7 @@ isset($action) || $action = NULL;
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $view != 'video' && $request != 'control' && $view != 'frames') {
require_once( 'includes/csrf/csrf-magic.php' );
Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
#Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();
}

View File

@ -50,7 +50,10 @@ function logReport( level, message, file, line )
if ( !debugReq )
{
debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+Browser.Platform.name;
if ( Browser )
debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown');
else
debugParms = "view=request&request=log&task=create&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown";
debugReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain' } );
}
var requestParms = debugParms;

View File

@ -322,6 +322,8 @@ $SLANG = array(
'ExportDetails' => 'Export Event Details',
'Exif' => 'Embed EXIF data into image',
'Export' => 'Export',
'DownloadVideo' => 'Download Video',
'GenerateDownload' => 'Generate Download',
'ExportFailed' => 'Export Failed',
'ExportFormat' => 'Export File Format',
'ExportFormatTar' => 'Tar',

View File

@ -1,3 +1,4 @@
/*
* ZoneMinder Base Stylesheet, $Date$, $Revision$
* Copyright (C) 2001-2008 Philip Coombes
@ -346,9 +347,11 @@ th.table-th-sort-rev span.table-th-sort-span {
#header {
width: 100%;
line-height: 24px;
margin: 8px auto;
margin: 0 auto 4px auto;
line-height: 1;
text-align: left;
padding: 3px 0;
border-bottom: 1px solid #555555;
}
#header h2 {
@ -378,7 +381,7 @@ th.table-th-sort-rev span.table-th-sort-span {
#content {
width: 96%;
margin: 8px auto;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
}

View File

@ -12,109 +12,64 @@
.alarmCue {
background-color: #222222;
height: 1.5em;
height: 1.25em;
text-align: left;
margin: 0 auto 0 auto;
border-radius: 0 0 .3em .3em;
}
.alarmCue span {
background-color:red;
height: 1.5em;
height: 100%;
display: inline-block;
border-radius: 0;
}
span.noneCue {
background: none;
}
#header {
display: flex;
justify-content: space-between;
flex-direction: column;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#dataBar {
width: 100%;
margin: 2px auto;
text-align: center;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
}
#dataBar #dataTable {
#menuBar1 {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
table-layout: fixed;
text-align: center;
margin: 4px 0 0 0;
}
#dataBar #dataTable td {
text-align: center;
padding: 2px;
#menuBar1 #replayControl {
margin: 0 4px 0 auto;
}
#menuBar1 div {
margin: auto 5px;
}
#nameControl input[type="button"]{
height: 100%;
}
#eventVideo {
display: inline-block;
postion: relative;
}
#menuBar1 {
width: 100%;
padding: 3px 0;
text-align: center;
clear: both;
}
#menuBar1 #nameControl {
float: left;
}
#menuBar1 #nameControl #eventName {
margin-right: 4px;
}
#menuBar1 #replayControl {
float: right;
margin-left: 8px;
}
#menuBar1 #scaleControl {
float: right;
margin-left: 8px;
}
#menuBar2 {
width: 100%;
padding: 3px 0;
margin-bottom: 4px;
}
#menuBar2 div {
text-align: left;
float: left;
padding: 0 12px;
}
#menuBar2 #closeWindow {
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#videoBar1 div {
text-align: center;
float: center;
}
#videoBar1 #prevEvent {
float: left;
}
#videoBar1 #dlEvent {
float: center;
}
#videoBar1 #nextEvent {
float: right;
position: relative;
}
#imageFeed {
@ -184,14 +139,16 @@ span.noneCue {
#progressBar {
position: relative;
top: -1.5em;
height: 1.5em;
margin: 0 auto -1.5em auto;
top: -1.25em;
height: 1.25em;
margin: 0 auto -1.25em auto;
}
#progressBar .progressBox {
height: 1.5em;
transition: width .1s;
height: 100%;
background: rgba(170, 170, 170, .7);
border-radius: 0 0 .3em .3em;
}
#eventStills {
@ -223,6 +180,7 @@ span.noneCue {
}
#eventImagePanel {
display: none;
position: absolute;
top: 0;
left: 0;
@ -267,7 +225,7 @@ span.noneCue {
#eventImageNav {
position: relative;
margin: 4px 0 0 0;
margin: 0 0 4px 0;
}
#eventImageNav input {
@ -276,20 +234,20 @@ span.noneCue {
}
#thumbsSliderPanel {
width: 400px;
margin: 4px auto 0;
background: #888888;
padding: 1px;
width: 80%;
margin: 0px auto 4px auto;
}
#thumbsSlider {
width: 400px;
height: 10px;
background: #dddddd;
width: 100%;
height: 1.25em;
position: relative;
top: -1.25em;
margin: 0 0 -1.25em 0;
}
#thumbsKnob {
width: 8px;
height: 10px;
background-color: #444444;
width: 1em;
height: 100%;
background-color: #999999;
}

View File

@ -2,36 +2,6 @@
background-color: #f8f8f8;;
}
#controls {
height: 16px;
width: 100%;
text-align: center;
margin: 0 auto;
position: relative;
}
#controls a {
width: 32%;
}
#controls #refreshLink {
position: absolute;
left: 0%;
text-align: left;
}
#controls #filterLink {
position: absolute;
left: 34%;
text-align: center;
}
#controls #timelineLink {
position: absolute;
left: 68%;
text-align: right;
}
#contentTable.major .colTime {
white-space: nowrap;
}
@ -44,3 +14,26 @@
text-align: right;
padding-right: 8px;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #pagination, #header #controls {
display: flex;
flex-direction: column;
}
#header #controls {
align-items: flex-end;
}
#header #pagination {
align-items: center;
}

View File

@ -1,33 +1,16 @@
#scaleControl {
float: right;
}
#controls {
width: 80%;
text-align: center;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
#controls a {
width: 40px;
margin-left: -20px;
}
#firstLink {
position: absolute;
left: 13%;
}
#prevLink {
position: absolute;
left: 37%;
}
#nextLink {
position: absolute;
left: 63%;
}
#lastLink {
position: absolute;
left: 87%;
}

View File

@ -19,6 +19,10 @@
#monitors .alert {
color: #ffa500;
margin: 0;
padding: 0;
border-radius: 0;
border: none;
}
#monitors .imageFeed {

View File

@ -36,3 +36,7 @@
input[type=range]::-ms-tooltip {
display: none;
}
#downloadVideo {
margin-left: 5px;
}

View File

@ -5,6 +5,25 @@
margin: 0 auto;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #headerButtons {
display: flex;
flex-direction: column;
}
#header #headerButtons {
align-items: flex-end;
}
#title {
position: relative;
margin: 0 auto;
@ -15,20 +34,6 @@
line-height: 20px;
}
#listLink {
position: absolute;
top: 5px;
left: 20px;
height: 15px;
}
#closeLink {
position: absolute;
top: 5px;
right: 20px;
height: 15px;
}
#topPanel {
position: relative;
height: 220px;

View File

@ -1,37 +1,17 @@
@import url(../control.css);
#menuBar {
margin: 6px auto 4px;
text-align: center;
#header {
display: flex;
justify-content: space-between;
}
#menuBar #monitorName {
float: left;
#menuControls {
display: flex;
align-items: center;
}
#menuBar #closeControl {
float: right;
}
#menuBar #menuControls {
margin: 0 auto;
width: 60%;
}
#menuBar #menuControls #controlControl {
float: left;
}
#menuBar #menuControls #eventsControl {
float: left;
}
#menuBar #menuControls #settingsControl {
float: right;
}
#menuBar #menuControls #scaleControl {
margin: 0 auto;
#menuControls div {
margin: 0 0 0 1em;
}
#imageFeed{

View File

@ -373,11 +373,12 @@ th.table-th-sort-rev span.table-th-sort-span {
#header {
width: 100%;
line-height: 24px;
line-height: 1;
text-align: left;
margin-bottom: 10px;
padding: 10px 20px;
padding: 5px 20px;
margin: 0 auto 4px auto;
font-weight: 300;
border-bottom: 1px solid #000000;
}
#header h2 {
@ -407,7 +408,7 @@ th.table-th-sort-rev span.table-th-sort-span {
#content {
width: 96%;
margin: 8px auto;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
}
@ -460,9 +461,9 @@ th.table-th-sort-rev span.table-th-sort-span {
button,
input[type=button],
input[type=submit] {
background-color: #3498db;
color: #fff;
border-color: #3498db;
background-color: #444444;
color: #eeeeee;
border-color: #444444;
text-transform: uppercase;
font-weight: 200;
padding: 5px 10px;
@ -472,7 +473,7 @@ input[type=submit] {
button:hover,
input[type=button]:hover,
input[type=submit]:hover {
background-color: #34a2ee;
background-color: #555555;
}
@ -482,9 +483,9 @@ button:disabled,
input[disabled],
input[type=button]:disabled,
input[type=submit]:disabled {
color: #ffffff;
background-color: #aaaaaa;
border-color: #bbbbbb;
color: #888888;
background-color: #666666;
border-color: #666666;
}
/*
@ -534,8 +535,10 @@ input[type=submit]:disabled {
margin-left: 0;
}
.table-striped > tbody > tr:nth-of-type(2n+1) {
background: none;
background-color: #333333;
}
.table-hover>tbody>tr:hover {
background-color: #444444;
}

View File

@ -12,91 +12,63 @@
.alarmCue {
background-color: #222222;
height: 1.5em;
height: 1.25em;
text-align: left;
margin: 0 auto 0 auto;
border-radius: 0 0 .3em .3em;
}
.alarmCue span {
background-color:red;
height: 1.5em;
height: 100%;
display: inline-block;
border-radius: 0;
}
span.noneCue {
background: none;
}
#eventVideo {
display: inline-block;
#header {
display: flex;
justify-content: space-between;
flex-direction: column;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#dataBar {
width: 100%;
margin: 2px auto;
text-align: center;
}
#dataBar #dataTable {
width: 100%;
table-layout: fixed;
}
#dataBar #dataTable td {
text-align: center;
padding: 2px;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
}
#menuBar1 {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
padding: 3px 0;
text-align: center;
clear: both;
}
#menuBar1 #nameControl {
float: left;
}
#menuBar1 #nameControl #eventName {
margin-right: 4px;
margin: 4px 0 0 0;
}
#menuBar1 #replayControl {
float: right;
margin-left: 8px;
margin: 0 4px 0 auto;
}
#menuBar1 #scaleControl {
float: right;
margin-left: 8px;
#menuBar1 div {
margin: auto 5px;
}
#menuBar2 {
width: 100%;
padding: 3px 0;
margin-bottom: 4px;
#nameControl input[type="button"]{
height: 100%;
}
#menuBar2 div {
text-align: left;
float: left;
padding: 0 12px;
}
#menuBar2 #closeWindow {
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
#eventVideo {
display: inline-block;
}
#imageFeed {
@ -166,14 +138,16 @@ span.noneCue {
#progressBar {
position: relative;
top: -1.5em;
height: 1.5em;
margin: 0 auto -1.5em auto;
top: -1.25em;
height: 1.25em;
margin: 0 auto -1.25em auto;
}
#progressBar .progressBox {
height: 1.5em;
transition: width .1s;
height: 100%;
background: rgba(170, 170, 170, .7);
border-radius: 0 0 .3em .3em;
}
#eventStills {
@ -206,6 +180,7 @@ span.noneCue {
}
#eventImagePanel {
display: none;
position: absolute;
top: 0;
left: 0;
@ -250,7 +225,7 @@ span.noneCue {
#eventImageNav {
position: relative;
margin: 4px 0 0 0;
margin: 0 0 4px 0;
}
#eventImageNav input {
@ -259,25 +234,20 @@ span.noneCue {
}
#thumbsSliderPanel {
width: 400px;
margin: 4px auto 0;
background: #888888;
padding: 1px;
width: 80%;
margin: 0px auto 4px auto;
}
#thumbsSlider {
width: 400px;
height: 10px;
background: #dddddd;
}
#eventVideo {
display: inline-block;
width: 100%;
height: 1.25em;
position: relative;
top: -1.25em;
margin: 0 0 -1.25em 0;
}
#thumbsKnob {
width: 8px;
height: 10px;
background-color: #444444;
width: 1em;
height: 100%;
background-color: #999999;
}

View File

@ -2,36 +2,6 @@
background-color: #2e2e2e;
}
#controls {
height: 16px;
width: 100%;
text-align: center;
margin: 0 auto;
position: relative;
}
#controls a {
width: 32%;
}
#controls #refreshLink {
position: absolute;
left: 0%;
text-align: left;
}
#controls #filterLink {
position: absolute;
left: 34%;
text-align: center;
}
#controls #timelineLink {
position: absolute;
left: 68%;
text-align: right;
}
#contentTable.major .colTime {
white-space: nowrap;
}
@ -44,3 +14,26 @@
text-align: right;
padding-right: 8px;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #pagination, #header #controls {
display: flex;
flex-direction: column;
}
#header #controls {
align-items: flex-end;
}
#header #pagination {
align-items: center;
}

View File

@ -1,33 +1,16 @@
#scaleControl {
float: right;
}
#controls {
width: 80%;
text-align: center;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
#controls a {
width: 40px;
margin-left: -20px;
}
#firstLink {
position: absolute;
left: 13%;
}
#prevLink {
position: absolute;
left: 37%;
}
#nextLink {
position: absolute;
left: 63%;
}
#lastLink {
position: absolute;
left: 87%;
}

View File

@ -16,6 +16,10 @@
#monitors .alert {
color: #ffa500;
margin: 0;
padding: 0;
border-radius: 0;
border: none;
}
#monitors .imageFeed {

View File

@ -36,3 +36,7 @@
input[type=range]::-ms-tooltip {
display: none;
}
#downloadVideo {
margin-left: 5px;
}

View File

@ -5,6 +5,25 @@
margin: 0 auto;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #headerButtons {
display: flex;
flex-direction: column;
}
#header #headerButtons {
align-items: flex-end;
}
#title {
position: relative;
margin: 0 auto;
@ -15,20 +34,6 @@
line-height: 20px;
}
#listLink {
position: absolute;
top: 5px;
left: 20px;
height: 15px;
}
#closeLink {
position: absolute;
top: 5px;
right: 20px;
height: 15px;
}
#topPanel {
position: relative;
height: 220px;

View File

@ -1,37 +1,17 @@
@import url(../control.css);
#menuBar {
margin: 6px auto 4px;
text-align: center;
#header {
display: flex;
justify-content: space-between;
}
#menuBar #monitorName {
float: left;
#menuControls {
display: flex;
align-items: center;
}
#menuBar #closeControl {
float: right;
}
#menuBar #menuControls {
margin: 0 auto;
width: 60%;
}
#menuBar #menuControls #controlControl {
float: left;
}
#menuBar #menuControls #eventsControl {
float: left;
}
#menuBar #menuControls #settingsControl {
float: right;
}
#menuBar #menuControls #scaleControl {
margin: 0 auto;
#menuControls div {
margin: 0 0 0 1em;
}
#imageFeed{

View File

@ -368,11 +368,11 @@ th.table-th-sort-rev span.table-th-sort-span {
#header {
width: 100%;
line-height: 24px;
line-height: 1;
text-align: left;
background-color: #383836;
margin-bottom: 10px;
padding: 10px 20px;
padding: 5px 20px;
margin: 0 auto 4px auto;
color: #f2f2f2;
font-weight: 300;
}
@ -410,7 +410,7 @@ th.table-th-sort-rev span.table-th-sort-span {
#content {
width: 96%;
margin: 8px auto;
margin: 0 auto 8px auto;
line-height: 130%;
text-align: center;
}

View File

@ -12,98 +12,71 @@
.alarmCue {
background-color: #222222;
height: 1.5em;
height: 1.25em;
text-align: left;
margin: 0 auto 0 auto;
border-radius: 0 0 .3em .3em;
}
.alarmCue span {
background-color:red;
height: 1.5em;
height: 100%;
display: inline-block;
border-radius: 0;
}
span.noneCue {
background: none;
}
#header {
display: flex;
justify-content: space-between;
flex-direction: column;
margin: 0 0 4px 0;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#dataBar {
width: 100%;
margin: 2px auto;
text-align: center;
}
#dataBar #dataTable {
width: 100%;
table-layout: fixed;
}
#dataBar #dataTable td {
text-align: center;
padding: 2px;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
}
#menuBar1 {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
padding: 3px 0;
text-align: center;
clear: both;
margin: 4px 0 0 0;
}
#menuBar1 #nameControl {
float: left;
}
#menuBar1 #nameControl #eventName {
margin-right: 4px;
#menuBar1 input, #menuBar1 select {
padding: 2px 5px;
}
#menuBar1 #replayControl {
float: right;
margin-left: 8px;
margin: 0 4px 0 auto;
}
#menuBar1 #scaleControl {
float: right;
margin-left: 8px;
#menuBar1 div {
margin: auto 5px;
}
#menuBar2 {
width: 100%;
padding: 3px 0;
margin-bottom: 4px;
#nameControl input[type="button"]{
height: 100%;
}
#menuBar2 div {
text-align: left;
float: left;
padding: 0 12px;
#eventVideo {
display: inline-block;
position: relative;
}
#menuBar2 #closeWindow {
float: right;
text-align: right;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#menuBar1:after,
#menuBar2:after {
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#imageFeed {
display: inline-block;
position: relative;
@ -177,14 +150,16 @@ span.noneCue {
#progressBar {
position: relative;
top: -1.5em;
height: 1.5em;
margin: 0 auto -1.5em auto;
top: -1.25em;
height: 1.25em;
margin: 0 auto -1.25em auto;
}
#progressBar .progressBox {
height: 1.5em;
transition: width .1s;
height: 100%;
background: rgba(170, 170, 170, .7);
border-radius: 0 0 .3em .3em;
}
#eventStills {
@ -217,6 +192,7 @@ span.noneCue {
}
#eventImagePanel {
display: none;
position: absolute;
top: 0;
left: 0;
@ -261,7 +237,7 @@ span.noneCue {
#eventImageNav {
position: relative;
margin: 4px 0 0 0;
margin: 0 0 4px 0;
}
#eventImageNav input {
@ -270,82 +246,20 @@ span.noneCue {
}
#thumbsSliderPanel {
width: 400px;
margin: 4px auto 0;
background: #888888;
padding: 1px;
width: 80%;
margin: 0px auto 4px auto;
}
#thumbsSlider {
width: 400px;
height: 10px;
background: #dddddd;
width: 100%;
height: 1.25em;
position: relative;
top: -1.25em;
margin: 0 0 -1.25em 0;
}
#thumbsKnob {
width: 8px;
height: 10px;
background-color: #444444;
}
#eventVideo {
display: inline-block;
position: relative;
}
#video-controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 5px;
opacity: 0;
-webkit-transition: opacity .3s;
-moz-transition: opacity .3s;
-o-transition: opacity .3s;
-ms-transition: opacity .3s;
transition: opacity .3s;
background-image: linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
background-image: -o-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
background-image: -moz-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
background-image: -webkit-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
background-image: -ms-linear-gradient(bottom, rgb(3,113,168) 13%, rgb(0,136,204) 100%);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.13, rgb(3,113,168)),
color-stop(1, rgb(0,136,204))
);
}
#eventVideo:hover #video-controls {
opacity: .9;
}
button {
background: rgba(0,0,0,.5);
border: 0;
color: #EEE;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
padding: 0;
}
button:hover {
cursor: pointer;
}
#seekbar {
width: 360px;
border: 0;
padding: 0;
}
#volume-bar {
width: 60px;
border: 0;
padding: 0;
width: 1em;
height: 100%;
background-color: #999999;
}

View File

@ -2,36 +2,6 @@
background-color: #f8f8f8;;
}
#controls {
height: 16px;
width: 100%;
text-align: center;
margin: 0 auto;
position: relative;
}
#controls a {
width: 32%;
}
#controls #refreshLink {
position: absolute;
left: 0%;
text-align: left;
}
#controls #filterLink {
position: absolute;
left: 34%;
text-align: center;
}
#controls #timelineLink {
position: absolute;
left: 68%;
text-align: right;
}
#contentTable.major .colTime {
white-space: nowrap;
}
@ -44,3 +14,26 @@
text-align: right;
padding-right: 8px;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #pagination, #header #controls {
display: flex;
flex-direction: column;
}
#header #controls {
align-items: flex-end;
}
#header #pagination {
align-items: center;
}

View File

@ -6,29 +6,11 @@
width: 80%;
text-align: center;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
#controls a {
width: 40px;
margin-left: -20px;
}
#firstLink {
position: absolute;
left: 13%;
}
#prevLink {
position: absolute;
left: 37%;
}
#nextLink {
position: absolute;
left: 63%;
}
#lastLink {
position: absolute;
left: 87%;
}

View File

@ -4,7 +4,7 @@
display: inline-flex;
border: 1px solid black;
width: 25%;
padding: 9px;
padding: 4px;
}
#ScaleDiv label,
#SpeedDiv label {
@ -42,3 +42,7 @@ input[type=range]::-ms-tooltip {
color: white;
font-size: 40px;
}
#downloadVideo {
margin-left: 5px;
}

View File

@ -5,6 +5,25 @@
margin: 0 auto;
}
#header {
display: flex;
justify-content: space-between;
}
#header h2, #header a {
line-height: 1.1;
margin:5px 0 0 0;
}
#header #info, #header #headerButtons {
display: flex;
flex-direction: column;
}
#header #headerButtons {
align-items: flex-end;
}
#title {
position: relative;
margin: 0 auto;
@ -15,20 +34,6 @@
line-height: 20px;
}
#listLink {
position: absolute;
top: 5px;
left: 20px;
height: 15px;
}
#closeLink {
position: absolute;
top: 5px;
right: 20px;
height: 15px;
}
#topPanel {
position: relative;
height: 220px;

View File

@ -1,37 +1,17 @@
@import url(../control.css);
#menuBar {
margin: 6px auto 4px;
text-align: center;
#header {
display: flex;
justify-content: space-between;
}
#menuBar #monitorName {
float: left;
#menuControls {
display: flex;
align-items: center;
}
#menuBar #closeControl {
float: right;
}
#menuBar #menuControls {
margin: 0 auto;
width: 60%;
}
#menuBar #menuControls #controlControl {
float: left;
}
#menuBar #menuControls #eventsControl {
float: left;
}
#menuBar #menuControls #settingsControl {
float: right;
}
#menuBar #menuControls #scaleControl {
margin: 0 auto;
#menuControls div {
margin: 0 0 0 1em;
}
#imageFeed{

View File

@ -45,7 +45,7 @@ $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
if (isset($_REQUEST['view'])) unset($scales[$_REQUEST['view'] == 'montage' ? 'auto' : '']); //Only use fixed width/Height on montage
$bandwidth_options = array(
'high' => translate('High'),
@ -56,6 +56,7 @@ $bandwidth_options = array(
switch ( $_COOKIE['zmBandwidth'] ) {
case 'high' : {
define( 'ZM_WEB_REFRESH_MAIN', ZM_WEB_H_REFRESH_MAIN ); // How often (in seconds) the main console window refreshes
define( 'ZM_WEB_REFRESH_NAVBAR', ZM_WEB_H_REFRESH_NAVBAR ); // How often (in seconds) the nav header refreshes
define( 'ZM_WEB_REFRESH_CYCLE', ZM_WEB_H_REFRESH_CYCLE ); // How often the cycle watch windows swaps to the next monitor
define( 'ZM_WEB_REFRESH_IMAGE', ZM_WEB_H_REFRESH_IMAGE ); // How often the watched image is refreshed (if not streaming)
define( 'ZM_WEB_REFRESH_STATUS', ZM_WEB_H_REFRESH_STATUS ); // How often the little status frame refreshes itself in the watch window
@ -73,6 +74,7 @@ switch ( $_COOKIE['zmBandwidth'] ) {
break;
} case 'medium' : {
define( 'ZM_WEB_REFRESH_MAIN', ZM_WEB_M_REFRESH_MAIN ); // How often (in seconds) the main console window refreshes
define( 'ZM_WEB_REFRESH_NAVBAR', ZM_WEB_M_REFRESH_NAVBAR ); // How often (in seconds) the nav header refreshes
define( 'ZM_WEB_REFRESH_CYCLE', ZM_WEB_M_REFRESH_CYCLE ); // How often the cycle watch windows swaps to the next monitor
define( 'ZM_WEB_REFRESH_IMAGE', ZM_WEB_M_REFRESH_IMAGE ); // How often the watched image is refreshed (if not streaming)
define( 'ZM_WEB_REFRESH_STATUS', ZM_WEB_M_REFRESH_STATUS ); // How often the little status frame refreshes itself in the watch window
@ -90,6 +92,7 @@ switch ( $_COOKIE['zmBandwidth'] ) {
break;
} case 'low' : {
define( 'ZM_WEB_REFRESH_MAIN', ZM_WEB_L_REFRESH_MAIN ); // How often (in seconds) the main console window refreshes
define( 'ZM_WEB_REFRESH_NAVBAR', ZM_WEB_L_REFRESH_NAVBAR ); // How often (in seconds) the nav header refreshes
define( 'ZM_WEB_REFRESH_CYCLE', ZM_WEB_L_REFRESH_CYCLE ); // How often the cycle watch windows swaps to the next monitor
define( 'ZM_WEB_REFRESH_IMAGE', ZM_WEB_L_REFRESH_IMAGE ); // How often the watched image is refreshed (if not streaming)
define( 'ZM_WEB_REFRESH_STATUS', ZM_WEB_L_REFRESH_STATUS ); // How often the little status frame refreshes itself in the watch window

View File

@ -853,7 +853,7 @@ function exportFileList( $eid, $exportDetail, $exportFrames, $exportImages, $exp
return( array_values( $exportFileList ) );
}
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat )
function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $exportVideo, $exportMisc, $exportFormat, $exportStructure = false )
{
if ( canView( 'Events' ) && !empty($eids) )
@ -907,8 +907,12 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
{
$archive = ZM_DIR_EXPORTS."/".$export_root.".tar.gz";
@unlink( $archive );
$command = "tar --create --gzip --file=$archive --files-from=$listFile";
exec( escapeshellcmd( $command ), $output, $status );
if ($exportStructure == 'flat') { //strip file paths if we choose
$command = "nice -10 tar --create --gzip --file=".escapeshellarg($archive)." --files-from=".escapeshellarg($listFile)." --xform='s#^.+/##x'";
} else {
$command = "nice -10 tar --create --gzip --file=".escapeshellarg($archive)." --files-from=".escapeshellarg($listFile);
}
exec( $command, $output, $status );
if ( $status )
{
Error( "Command '$command' returned with status $status" );
@ -921,7 +925,11 @@ function exportEvents( $eids, $exportDetail, $exportFrames, $exportImages, $expo
{
$archive = ZM_DIR_EXPORTS."/".$export_root.".zip";
@unlink( $archive );
$command = "cat ".escapeshellarg($listFile)." | zip -q ".escapeshellarg($archive)." -@";
if ($exportStructure == 'flat') {
$command = "cat ".escapeshellarg($listFile)." | nice -10 zip -q -j ".escapeshellarg($archive)." -@";
} else {
$command = "cat ".escapeshellarg($listFile)." | nice -10 zip -q ".escapeshellarg($archive)." -@";
}
//cat zmFileList.txt | zip -q zm_export.zip -@
//-bash: zip: command not found

View File

@ -159,26 +159,29 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
<?php
} // end function xhtmlHeaders( $file, $title )
function getNavBarHTML() {
function getNavBarHTML($reload = null) {
$versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText':'';
ob_start();
global $running;
if ( $running == null )
$running = daemonCheck();
$status = $running?translate('Running'):translate('Stopped');
global $user;
global $bandwidth_options;
global $view;
global $filterQuery;
if (!$filterQuery) {
parseFilter( $_REQUEST['filter'] );
$filterQuery = $_REQUEST['filter']['query'];
}
if ($reload === null) {
ob_start();
if ( $running == null )
$running = daemonCheck();
$status = $running?translate('Running'):translate('Stopped');
?>
<noscript>
<div style="background-color:red;color:white;font-size:x-large;">
ZoneMinder requires Javascript. Please enable Javascript in your browser for this site.
</div>
</noscript>
<div class="navbar navbar-inverse navbar-static-top">
<div class="container-fluid">
<div class="navbar-header">
@ -212,7 +215,7 @@ 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>
<li><a href="?view=filter"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
<li><a href="?view=filter<?php echo $filterQuery ?>"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
<?php
if ( canView( 'Stream' ) ) {
@ -221,9 +224,23 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
<li><a href="?view=montage"<?php echo $view=='montage'?' class="selected"':''?>><?php echo translate('Montage') ?></a></li>
<?php
}
if (isset($_REQUEST['filter']['Query']['terms'])) {
$terms = $_REQUEST['filter']['Query']['terms'];
$count = 0;
foreach ($terms as $term) {
if ($term['attr'] == "StartDateTime") {
$count += 1;
if ($term['op'] == '>=') $minTime = $term['val'];
if ($term['op'] == '<=') $maxTime = $term['val'];
}
}
if ($count == 2) {
$montageReviewQuery = '&minTime='.$minTime.'&maxTime='.$maxTime;
}
}
if ( canView('Events') ) {
?>
<li><a href="?view=montagereview"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
<li><a href="?view=montagereview<?php echo isset($montageReviewQuery)?'&fit=1'.$montageReviewQuery.'&live=0':'' ?>"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
<?php
}
?>
@ -243,7 +260,11 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
</div>
</div><!-- End .navbar-collapse -->
</div> <!-- End .container-fluid -->
<div class="container-fluid">
<?php
}//end reload null. Runs on full page load
if ($reload == 'reload') ob_start();
?>
<div id="reload" class="container-fluid">
<div class="pull-left">
<?php echo makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', $bandwidth_options[$_COOKIE['zmBandwidth']] . ' ' . translate('BandwidthHead'), ($user && $user['MaxBandwidth'] != 'low' ) ) ?>
</div>
@ -277,9 +298,11 @@ if ( ZM_OPT_X10 && canView( 'Devices' ) ) { ?>
echo ' ' . ZM_PATH_MAP .': '. getDiskPercent(ZM_PATH_MAP).'%';
?></li>
</ul>
</div> <!-- End .footer -->
</div> <!-- End .navbar .navbar-default -->
</div> <!-- End .footer/reload -->
<?php
if ($reload == 'reload') return( ob_get_clean() );
?>
</div><!-- End .navbar .navbar-default -->
<?php
return( ob_get_clean() );
} // end function getNavBarHTML()

View File

@ -104,6 +104,10 @@ function parseFilterToTree( $filter ) {
$sqlValue = "E.StartTime";
$dtAttr = true;
break;
case 'StartDateTime':
$sqlValue = "E.StartTime";
$dtAttr = true;
break;
case 'Date':
$sqlValue = "to_days( E.StartTime )";
$dtAttr = true;
@ -196,6 +200,9 @@ function parseFilterToTree( $filter ) {
case 'DateTime':
$value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'";
break;
case 'StartDateTime':
$value = "'".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."'";
break;
case 'Date':
$value = "to_days( '".strftime( STRF_FMT_DATETIME_DB, strtotime( $value ) )."' )";
break;
@ -359,7 +366,7 @@ function parseTreeToFilter( $tree )
$level = 0;
_parseTreeToFilter( $tree, $terms, $level );
}
return( array( 'terms' => $terms ) );
return( array( 'Query' => array( 'terms' => $terms ) ) );
}
function parseTreeToQuery( $tree )
@ -461,7 +468,7 @@ function extractDatetimeRange( &$tree, &$minTime, &$maxTime, &$expandable )
function appendDatetimeRange( &$tree, $minTime, $maxTime=false )
{
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'DateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$minTime, 'sqlValue'=>$minTime ), 'count'=>0 );
$opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'>=', 'sqlValue'=>'>=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode );
if ( isset($tree) )
@ -476,7 +483,7 @@ function appendDatetimeRange( &$tree, $minTime, $maxTime=false )
if ( $maxTime )
{
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'DateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$attrNode = array( 'data'=>array( 'type'=>'attr', 'value'=>'StartDateTime', 'sqlValue'=>'E.StartTime', 'dtAttr'=>true ), 'count'=>0 );
$valNode = array( 'data'=>array( 'type'=>'val', 'value'=>$maxTime, 'sqlValue'=>$maxTime ), 'count'=>0 );
$opNode = array( 'data'=>array( 'type'=>'op', 'value'=>'<=', 'sqlValue'=>'<=' ), 'count'=>2, 'left'=>$attrNode, 'right'=>$valNode );
$cnjNode = array( 'data'=>array( 'type'=>'cnj', 'value'=>'and', 'sqlValue'=>'and' ), 'count'=>2+$tree['count']+$opNode['count'], 'left'=>$tree, 'right'=>$opNode );

View File

@ -33,6 +33,7 @@ var popupSizes = {
'device': { 'width': 260, 'height': 150 },
'devices': { 'width': 400, 'height': 240 },
'donate': { 'width': 500, 'height': 280 },
'download': { 'width': 350, 'height': 215 },
'event': { 'addWidth': 108, 'minWidth': 496, 'addHeight': 230, 'minHeight': 540 },
'eventdetail': { 'width': 600, 'height': 420 },
'events': { 'width': 1220, 'height': 780 },

View File

@ -182,6 +182,22 @@ function refreshParentWindow() {
}
}
if (currentView !='none') {
$j.ajaxSetup ({timeout: AJAX_TIMEOUT }); //sets timeout for all getJSON.
$j(document).ready(function() {
if ($j('.navbar').length) setInterval(getNavBar, navBarRefresh)
});
function getNavBar () {
$j.getJSON(thisUrl + '?view=request&request=status&entity=navBar', setNavBar);
}
function setNavBar (data) {
$j('#reload').replaceWith(data.message);
}
}
//Shows a message if there is an error in the streamObj or the stream doesn't exist. Returns true if error, false otherwise.
function checkStreamForErrors( funcName, streamObj ) {
if ( !streamObj ) {
@ -333,3 +349,36 @@ function changeFilter( e ) {
Cookie.write( e.name, e.value, { duration: 10*365 } );
window.location = window.location;
}
var resizeTimer;
function endOfResize(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(changeScale, 250);
}
function scaleToFit (baseWidth, baseHeight, scaleEl, bottomEl) {
$j(window).on('resize', endOfResize) //set delayed scaling when Scale to Fit is selected
let ratio = baseWidth / baseHeight;
let container = $j('#content');
let viewPort = $j(window);
// jquery does not provide a bottom offet, and offset dows not include margins. outerHeight true minus false gives total vertical margins.
let bottomLoc = bottomEl.offset().top + (bottomEl.outerHeight(true) - bottomEl.outerHeight()) + bottomEl.outerHeight(true);
let newHeight = viewPort.height() - (bottomLoc - scaleEl.outerHeight(true))
let newWidth = ratio * newHeight;
if (newWidth > container.innerWidth()) {
newWidth = container.innerWidth();
newHeight = newWidth / ratio;
}
let autoScale = Math.round(newWidth / baseWidth * SCALE_BASE);
let scales = $j('#scale option').map(function() {return parseInt($j(this).val());}).get();
scales.shift();
let closest;
$j(scales).each(function () { //Set zms scale to nearest regular scale. Zoom does not like arbitrary scale values.
if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) {
closest = this.valueOf();
}
});
autoScale = closest;
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
}

View File

@ -26,6 +26,8 @@
?>
var AJAX_TIMEOUT = <?php echo ZM_WEB_AJAX_TIMEOUT ?>;
var navBarRefresh = <?php echo 1000*ZM_WEB_REFRESH_NAVBAR ?>;
var currentView = '<?php echo $view ?>';
var thisUrl = "<?php echo ZM_BASE_URL.$_SERVER['PHP_SELF'] ?>";
var skinPath = "<?php echo ZM_SKIN_PATH ?>";

View File

@ -1,5 +1,6 @@
.vjs-tech {
pointer-events: none;
transition: transform .25s;
}
.vjs-captions-button {

View File

@ -45,7 +45,7 @@ xhtmlHeaders(__FILE__, translate('AddMonitors'));
<div style="width:50%;position: absolute; top:0; left: 0;height: 100%;">
<fieldset><legend>Enter by IP or URL</legend>
<!--<input type="text" name="newMonitor[Name]" />-->
<input type="url" name="newMonitor[Url]" oninput="probe(this);"/>
<input type="text" name="newMonitor[Url]" oninput="probe(this);"/>
</fieldset>
<fieldset><legend>Import CSV Spreadsheet</legend>
Spreadsheet should have the following format:<br/>

View File

@ -208,11 +208,11 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<?php
if ( ZM_WEB_ID_ON_CONSOLE ) {
?>
<td class="colId"><?php echo makePopupLink( '?view=watch&amp;mid='.$monitor['Id'], 'zmWatch'.$monitor['Id'], array( 'watch', reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ) ), $monitor['Id'], ($monitor['Function'] != 'None') && canView('Stream') ) ?></td>
<td class="colId"><a <?php echo (canView('Stream') && $running && $monitor['Function'] != 'None' ? 'href="?view=watch&amp;mid='.$monitor['Id'].'">' : '>') . $monitor['Id'] ?></a></td>
<?php
}
?>
<td class="colName"><?php echo makePopupLink( '?view=watch&amp;mid='.$monitor['Id'], 'zmWatch'.$monitor['Id'], array( 'watch', reScale( $monitor['Width'], $scale ), reScale( $monitor['Height'], $scale ) ), $monitor['Name'], ($monitor['Function'] != 'None') && canView('Stream') ) ?></td>
<td class="colName"><a <?php echo (canView('Stream') && $monitor['Function'] != 'None' ? 'href="?view=watch&amp;mid='.$monitor['Id'].'">' : '>') . $monitor['Name'] ?></a></td>
<td class="colFunction">
<?php echo makePopupLink( '?view=function&amp;mid='.$monitor['Id'], 'zmFunction', 'function', '<span class="'.$fclass.'">'.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'</span>', canEdit( 'Monitors' ) ) ?><br/>
<?php echo $monitor['CaptureFPS'] . ( ( $monitor['Function'] == 'Mocord' or $monitor['Function'] == 'Modect' ) ? ' / ' . $monitor['AnalysisFPS'] : '' ) . ' FPS' ?>
@ -245,8 +245,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
foreach ( array_keys( $eventCounts ) as $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[$i.'Events'] . '<br/>' . human_filesize($monitor[$i.'EventDiskSpace']), canView( 'Events' ) ) ?></td>
<td class="colEvents"><a <?php echo (canView('Events') ? 'href="?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$monitor['eventCounts'][$i]['filter']['query'].'">' : '') .
$monitor[$i.'Events'] . '<br/>' . human_filesize($monitor[$i.'EventDiskSpace']) ?></a></td>
<?php
}
?>
@ -281,9 +281,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
parseFilter( $eventCounts[$i]['filter'] );
?>
<td class="colEvents">
<?php echo makePopupLink( '?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$eventCounts[$i]['filter']['query'], $eventsWindow, ZM_WEB_EVENTS_VIEW,
$eventCounts[$i]['totalevents'].'<br/>'.human_filesize($eventCounts[$i]['totaldiskspace']), canView( 'Events' ) ) ?>
</td>
<a <?php echo (canView('Events') ? 'href="?view='.ZM_WEB_EVENTS_VIEW.'&amp;page=1'.$eventCounts[$i]['filter']['query'].'">' : '') .
$eventCounts[$i]['totalevents'].'<br/>'.human_filesize($eventCounts[$i]['totaldiskspace']) ?></a></td>
<?php
}
?>

View File

@ -31,52 +31,26 @@ if ( empty($_REQUEST['mode']) ) {
} else {
$mode = validHtmlStr($_REQUEST['mode']);
}
ob_start();
include('_monitor_filters.php');
$filterbar = ob_get_contents();
ob_end_clean();
$group_id = 0;
if ( isset($_REQUEST['group']) ) {
$group_id = $_REQUEST['group'];
} else if ( isset($_COOKIE['zmGroup'] ) ) {
$group_id = $_COOKIE['zmGroup'];
}
$subgroup_id = 0;
if ( isset($_REQUEST['subgroup']) ) {
$subgroup_id = $_REQUEST['subgroup'];
} else if ( isset($_COOKIE['zmSubGroup'] ) ) {
$subgroup_id = $_COOKIE['zmSubGroup'];
}
$groupIds = null;
if ( $group_id ) {
$groupIds = array();
if ( $group = dbFetchOne( 'SELECT MonitorIds FROM Groups WHERE Id = ?', NULL, array($group_id) ) )
if ( $group['MonitorIds'] )
$groupIds = explode( ',', $group['MonitorIds'] );
if ( $subgroup_id ) {
if ( $group = dbFetchOne( 'SELECT MonitorIds FROM Groups WHERE Id = ?', NULL, array($subgroup_id) ) )
if ( $group['MonitorIds'] )
$groupIds = array_merge( $groupIds, explode( ',', $group['MonitorIds'] ) );
} else {
foreach ( dbFetchAll( 'SELECT MonitorIds FROM Groups WHERE ParentId = ?', NULL, array($group_id) ) as $group )
if ( $group['MonitorIds'] )
$groupIds = array_merge( $groupIds, explode( ',', $group['MonitorIds'] ) );
}
}
$groupSql = '';
if ( $groupIds )
$groupSql = " and find_in_set( Id, '".implode( ',', $groupIds )."' )";
$sql = "SELECT * FROM Monitors WHERE Function != 'None'$groupSql ORDER BY Sequence";
$monitors = array();
$monIdx = 0;
foreach( dbFetchAll( $sql ) as $row ) {
if ( !visibleMonitor( $row['Id'] ) )
$monitors = array();
foreach( $displayMonitors as &$row ) {
if ( $row['Function'] == 'None' )
continue;
if ( isset($_REQUEST['mid']) && $row['Id'] == $_REQUEST['mid'] )
$monIdx = count($monitors);
$row['ScaledWidth'] = reScale( $row['Width'], $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$row['ScaledHeight'] = reScale( $row['Height'], $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$row['PopupScale'] = reScale( SCALE_BASE, $row['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$row['connKey'] = generateConnKey();
$monitors[] = new Monitor( $row );
}
} # end foreach Monitor
if ( $monitors ) {
$monitor = $monitors[$monIdx];
@ -103,22 +77,7 @@ xhtmlHeaders(__FILE__, translate('CycleWatch') );
<?php } ?>
</div>
<div class="controlHeader">
<span id="groupControl"><label><?php echo translate('Group') ?>:</label>
<?php
$groups = array(0=>'All');
foreach ( Group::find_all( array('ParentId'=>null) ) as $Group ) {
$groups[$Group->Id()] = $Group->Name();
}
echo htmlSelect( 'group', $groups, $group_id, 'changeGroup(this);' );
$groups = array(0=>'All');
if ( $group_id ) {
foreach ( Group::find_all( array('ParentId'=>$group_id) ) as $Group ) {
$groups[$Group->Id()] = $Group->Name();
}
}
echo htmlSelect( 'subgroup', $groups, $subgroup_id, 'changeSubGroup(this);' );
?>
<?php echo $filterbar ?>
</div>
</div>
<div id="content">

View File

@ -0,0 +1,111 @@
<?php
//
// ZoneMinder web export 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 ( !canView('Events') ) {
$view = 'error';
return;
}
if (isset($_SESSION['montageReviewFilter'])) { //Handles montageReview filter
$eventsSql = 'SELECT E.Id FROM Events as E WHERE 1';
$eventsSql .= $_SESSION['montageReviewFilter']['sql'];
$results = dbQuery($eventsSql);
$eids = [];
while ( $event_row = dbFetchNext( $results ) ) {
array_push($eids, 'eids[]='.$event_row['Id']);
}
$_REQUEST['eids'] = $eids;
session_start();
unset($_SESSION['montageReviewFilter']);
session_write_close();
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Download') );
?>
<body>
<div id="page">
<div id="header">
<div id="headerButtons">
<a href="#" onclick="closeWindow()"><?php echo translate('Close') ?></a>
</div>
<h2><?php echo translate('Download') ?></h2>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<?php
if ( !empty($_REQUEST['eid']) ) {
?>
<input type="hidden" name="id" value="<?php echo validInt($_REQUEST['eid']) ?>"/>
<?php
} else if ( !empty($_REQUEST['eids']) ) {
foreach ( $_REQUEST['eids'] as $eid ) {
?>
<input type="hidden" name="eids[]" value="<?php echo validInt($eid) ?>"/>
<?php
}
unset( $eid );
}
?>
<table id="contentTable" class="minor" cellspacing="0">
<tbody>
<tr>
<td><input type="hidden" name="exportVideo" value="1"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('ExportFormat') ?></th>
<td>
<input type="radio" id="exportFormatTar" name="exportFormat" value="tar" onclick="configureExportButton(this)"/>
<label for="exportFormatTar"><?php echo translate('ExportFormatTar') ?></label>
<input type="radio" id="exportFormatZip" name="exportFormat" value="zip" checked="checked" onclick="configureExportButton(this);"/>
<label for="exportFormatZip"><?php echo translate('ExportFormatZip') ?></label>
</td>
</tr>
</tbody>
</table>
<input type="button" id="exportButton" name="exportButton" value="<?php echo translate('GenerateDownload') ?>" onclick="exportEvent(this.form);" />
</form>
</div>
<?php
if ( isset($_REQUEST['generated']) ) {
?>
<h2 id="exportProgress" class="<?php echo $_REQUEST['generated']?'infoText':'errorText' ?>">
<span id="exportProgressText"><?php echo $_REQUEST['generated']?translate('ExportSucceeded'):translate('ExportFailed') ?></span>
<span id="exportProgressTicker"></span>
</h2>
<?php
} else {
?>
<h2 id="exportProgress" class="hidden warnText">
<span id="exportProgressText"><?php echo translate('Exporting') ?></span>
<span id="exportProgressTicker"></span>
</h2>
<?php
}
if ( !empty($_REQUEST['generated']) ) {
?>
<h3 id="downloadLink"><a href="<?php echo validHtmlStr($_REQUEST['exportFile']) ?>"><?php echo translate('Download') ?></a></h3>
<?php
}
?>
</div>
</body>
</html>

View File

@ -96,34 +96,27 @@ xhtmlHeaders(__FILE__, translate('Event') );
?>
<body>
<div id="page">
<div id="content">
<?php echo getNavBarHTML() ?>
<div id="header">
<?php
if ( ! $Event->Id() ) {
echo 'Event was not found.';
} else {
?>
<div id="dataBar">
<table id="dataTable" class="major">
<tr>
<td><span id="dataId" title="<?php echo translate('Id') ?>"><?php echo $Event->Id() ?></span></td>
<td><span id="dataCause" title="<?php echo $Event->Notes()?validHtmlStr($Event->Notes()):translate('AttrCause') ?>"><?php echo validHtmlStr($Event->Cause()) ?></span></td>
<td><span id="dataTime" title="<?php echo translate('Time') ?>"><?php echo strftime( STRF_FMT_DATETIME_SHORT, strtotime($Event->StartTime() ) ) ?></span></td>
<td><span id="dataDuration" title="<?php echo translate('Duration') ?>"><?php echo $Event->Length() ?></span>s</td>
<td><span id="dataFrames" title="<?php echo translate('AttrFrames')."/".translate('AttrAlarmFrames') ?>"><?php echo $Event->Frames() ?>/<?php echo $Event->AlarmFrames() ?></span></td>
<td><span id="dataScore" title="<?php echo translate('AttrTotalScore')."/".translate('AttrAvgScore')."/".translate('AttrMaxScore') ?>"><?php echo $Event->TotScore() ?>/<?php echo $Event->AvgScore() ?>/<?php echo $Event->MaxScore() ?></span></td>
</tr>
</table>
<span id="dataId" title="<?php echo translate('Id') ?>"><?php echo $Event->Id() ?></span>
<span id="dataCause" title="<?php echo $Event->Notes()?validHtmlStr($Event->Notes()):translate('AttrCause') ?>"><?php echo validHtmlStr($Event->Cause()) ?></span>
<span id="dataTime" title="<?php echo translate('Time') ?>"><?php echo strftime( STRF_FMT_DATETIME_SHORT, strtotime($Event->StartTime() ) ) ?></span>
<span id="dataDuration" title="<?php echo translate('Duration') ?>"><?php echo $Event->Length().'s' ?></span>
<span id="dataFrames" title="<?php echo translate('AttrFrames')."/".translate('AttrAlarmFrames') ?>"><?php echo $Event->Frames() ?>/<?php echo $Event->AlarmFrames() ?></span>
<span id="dataScore" title="<?php echo translate('AttrTotalScore')."/".translate('AttrAvgScore')."/".translate('AttrMaxScore') ?>"><?php echo $Event->TotScore() ?>/<?php echo $Event->AvgScore() ?>/<?php echo $Event->MaxScore() ?></span>
<div id="closeWindow"><a href="#" onclick="window.history.back();"><?php echo translate('Back') ?></a></div>
</div>
<div id="menuBar1">
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect( "scale", $scales, "changeScale();" ); ?></div>
<div id="replayControl"><label for="replayMode"><?php echo translate('Replay') ?></label><?php echo buildSelect( "replayMode", $replayModes, "changeReplayMode();" ); ?></div>
<div id="nameControl">
<input type="text" id="eventName" name="eventName" value="<?php echo validHtmlStr($Event->Name()) ?>" />
<input type="button" value="<?php echo translate('Rename') ?>" onclick="renameEvent()"<?php if ( !canEdit( 'Events' ) ) { ?> disabled="disabled"<?php } ?>/>
</div>
</div>
<div id="menuBar2">
<div id="closeWindow"><a href="#" onclick="closeWindow();"><?php echo translate('Close') ?></a></div>
<?php
if ( canEdit('Events') ) {
?>
@ -149,7 +142,11 @@ if ( canEdit('Events') ) {
} // end if Event->DefaultVideo
?>
<div id="exportEvent"><a href="#" onclick="exportEvent();"><?php echo translate('Export') ?></a></div>
<div id="replayControl"><label for="replayMode"><?php echo translate('Replay') ?></label><?php echo buildSelect( "replayMode", $replayModes, "changeReplayMode();" ); ?></div>
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect( "scale", $scales, "changeScale();" ); ?></div>
</div>
</div>
<div id="content">
<div id="eventVideo" class="">
<?php
if ( $Event->DefaultVideo() ) {
@ -180,7 +177,7 @@ Warning("Streamsrc: $streamSrc");
}
} // end if stream method
?>
<div id="alarmCue" class="alarmCue" style="width: <?php echo reScale($Event->Width(), $scale);?>px;"></div>
<div id="alarmCue" class="alarmCue"></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-->
@ -220,6 +217,13 @@ Warning("Streamsrc: $streamSrc");
</div>
</div>
<div id="eventImageNav">
<div id="thumbsSliderPanel">
<div id="alarmCue" class="alarmCue"></div>
<div id="thumbsSlider">
<div id="thumbsKnob">
</div>
</div>
</div>
<div id="eventImageButtons">
<div id="prevButtonsPanel">
<input id="prevEventBtn" type="button" value="&lt;E" onclick="prevEvent()" disabled="disabled"/>
@ -230,12 +234,6 @@ Warning("Streamsrc: $streamSrc");
<input id="nextEventBtn" type="button" value="E&gt;" onclick="nextEvent()" disabled="disabled"/>
</div>
</div>
<div id="thumbsSliderPanel">
<div id="thumbsSlider">
<div id="thumbsKnob">
</div>
</div>
</div>
</div>
</div>
<?php

View File

@ -81,10 +81,6 @@ if ( !empty($page) ) {
$eventsSql .= ' limit 0, '.$limit;
}
$maxWidth = 0;
$maxHeight = 0;
$archived = false;
$unarchived = false;
$maxShortcuts = 5;
$pagination = getPagination( $pages, $page, $maxShortcuts, $filterQuery.$sortQuery.'&amp;limit='.$limit );
@ -95,8 +91,20 @@ xhtmlHeaders(__FILE__, translate('Events') );
?>
<body>
<div id="page">
<?php echo getNavBarHTML() ?>
<div id="header">
<div id="headerButtons">
<div id="info">
<h2><?php echo sprintf( $CLANG['EventCount'], $nEvents, zmVlang( $VLANG['Event'], $nEvents ) ) ?></h2>
<a id="refreshLink" href="#" onclick="location.reload(true);"><?php echo translate('Refresh') ?></a>
</div>
<div id="pagination">
<?php
if ( $pagination ) {
?>
<h2 class="pagination"><?php echo $pagination ?></h2>
<?php
}
?>
<?php
if ( $pages > 1 ) {
if ( !empty($page) ) {
@ -110,9 +118,11 @@ if ( $pages > 1 ) {
}
}
?>
<a href="#" onclick="closeWindows();"><?php echo translate('Close') ?></a>
</div>
<h2><?php echo sprintf( $CLANG['EventCount'], $nEvents, zmVlang( $VLANG['Event'], $nEvents ) ) ?></h2>
<div id="controls">
<a href="#" onclick="window.history.back();"><?php echo translate('Back') ?></a>
<a id="timelineLink" href="?view=timeline<?php echo $filterQuery ?>"><?php echo translate('ShowTimeline') ?></a>
</div>
</div>
<div id="content">
<form name="contentForm" id="contentForm" method="post" action="">
@ -123,18 +133,6 @@ if ( $pages > 1 ) {
<input type="hidden" name="sort_field" value="<?php echo validHtmlStr($_REQUEST['sort_field']) ?>"/>
<input type="hidden" name="sort_asc" value="<?php echo validHtmlStr($_REQUEST['sort_asc']) ?>"/>
<input type="hidden" name="limit" value="<?php echo $limit ?>"/>
<?php
if ( $pagination ) {
?>
<h3 class="pagination"><?php echo $pagination ?></h3>
<?php
}
?>
<p id="controls">
<a id="refreshLink" href="#" onclick="location.reload(true);"><?php echo translate('Refresh') ?></a>
<a id="filterLink" href="#" onclick="createPopup( '?view=filter&amp;page=<?php echo $page ?><?php echo $filterQuery ?>', 'zmFilter', 'filter' );"><?php echo translate('ShowFilterWindow') ?></a>
<a id="timelineLink" href="#" onclick="createPopup( '?view=timeline<?php echo $filterQuery ?>', 'zmTimeline', 'timeline' );"><?php echo translate('ShowTimeline') ?></a>
</p>
<table id="contentTable" class="major">
<tbody>
<?php
@ -144,11 +142,6 @@ $disk_space_total = 0;
$results = dbQuery( $eventsSql );
while ( $event_row = dbFetchNext( $results ) ) {
$event = new Event( $event_row );
$scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
$eventWidth = reScale( $event_row['Width'], $scale );
$eventHeight = reScale( $event_row['Height'], $scale );
if ( $maxWidth < $eventWidth ) $maxWidth = $eventWidth;
if ( $maxHeight < $eventHeight ) $maxHeight = $eventHeight;
if ( $event_row['Archived'] )
$archived = true;
else
@ -187,8 +180,8 @@ while ( $event_row = dbFetchNext( $results ) ) {
$scale = max( reScale( SCALE_BASE, $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
?>
<tr<?php if ($event->Archived()) echo ' class="archived"' ?>>
<td class="colId"><?php echo makePopupLink( '?view=event&amp;eid='.$event->Id().$filterQuery.$sortQuery.'&amp;page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->Id().($event->Archived()?'*':'') ) ?></td>
<td class="colName"><?php echo makePopupLink( '?view=event&amp;eid='.$event->Id().$filterQuery.$sortQuery.'&amp;page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), reScale( $event->Height(), $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ) ), validHtmlStr($event->Name()).($event->Archived()?'*':'' ) ) ?></td>
<td class="colId"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1"> '.$event->Id().($event->Archived()?'*':'') ?></a></td>
<td class="colName"><a href="?view=event&amp;eid=<?php echo $event->Id().$filterQuery.$sortQuery.'&amp;page=1"> '.validHtmlStr($event->Name()).($event->Archived()?'*':'') ?></a></td>
<td class="colMonitorName"><?php echo makePopupLink( '?view=monitor&amp;mid='.$event->MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) ?></td>
<td class="colCause"><?php echo makePopupLink( '?view=eventdetail&amp;eid='.$event->Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?></td>
<td class="colTime"><?php echo strftime( STRF_FMT_DATETIME_SHORTER, strtotime($event->StartTime()) ) ?></td>
@ -276,6 +269,7 @@ if ( true || canEdit( 'Events' ) ) {
<input type="button" name="unarchiveBtn" value="<?php echo translate('Unarchive') ?>" onclick="unarchiveEvents( this, 'markEids' );" disabled="disabled"/>
<input type="button" name="editBtn" value="<?php echo translate('Edit') ?>" onclick="editEvents( this, 'markEids' )" disabled="disabled"/>
<input type="button" name="exportBtn" value="<?php echo translate('Export') ?>" onclick="exportEvents( this, 'markEids' )" disabled="disabled"/>
<input type="button" name="downloadBtn" value="<?php echo translate('DownloadVideo') ?>" onclick="downloadVideo( this, 'markEids' )" disabled="disabled"/>
<input type="button" name="deleteBtn" value="<?php echo translate('Delete') ?>" onclick="deleteEvents( this, 'markEids' );" disabled="disabled"/>
</div>
<?php
@ -288,8 +282,6 @@ if ( true || canEdit( 'Events' ) ) {
// These are defined in the .js.php but need to be updated down here.
archivedEvents = <?php echo !empty($archived)?'true':'false' ?>;
unarchivedEvents = <?php echo !empty($unarchived)?'true':'false' ?>;
maxWidth = <?php echo $maxWidth?$maxWidth:0 ?>;
maxHeight = <?php echo $maxHeight?$maxHeight:0 ?>;
</script>
</body>
</html>

View File

@ -231,7 +231,7 @@ for ( $i = 0; $i < count($terms); $i++ ) {
<?php
} elseif ( $term['attr'] == 'MonitorName' ) {
$monitors = array();
foreach ( dbFetchAll( 'select Id,Name from Monitors order by Sequence asc' ) as $monitor ) {
foreach ( dbFetchAll( 'select Id,Name from Monitors order by Name asc' ) as $monitor ) {
if ( visibleMonitor( $monitor['Id'] ) ) {
$monitors[$monitor['Name']] = $monitor['Name'];
}
@ -385,7 +385,11 @@ if ( ZM_OPT_MESSAGE ) {
</p>
<p>
<label><?php echo translate('FilterDeleteEvents') ?></label>
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( !empty($filter->AutoDelete()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons( this )"/>
<input type="checkbox" name="filter[AutoDelete]" value="1"<?php if ( !empty($filter->AutoDelete()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this)"/>
</p>
<p><label><?php echo translate('FilterMoveEvents') ?></label>
<input type="checkbox" name="filter[AutoMove]" value="1"<?php if ( !empty($filter->AutoMove()) ) { ?> checked="checked"<?php } ?> onclick="updateButtons(this);if(this.checked){$j(this.form.elements['filter[AutoMoveTo]']).css('display','inline');}else{this.form.elements['filter[AutoMoveTo]'].hide();};"/>
<?php echo htmlSelect( "filter[AutoMoveTo]", $storageareas, $filter->AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;' ) ); ?>
</p>
<p>
<label for="background"><?php echo translate('BackgroundFilter') ?></label>

View File

@ -51,7 +51,7 @@ $lastFid = $maxFid;
$alarmFrame = $Frame->Type()=='Alarm';
if ( isset( $_REQUEST['scale'] ) ) {
$scale = validInt($_REQUEST['scale']);
$scale = $_REQUEST['scale'];
} else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) {
$scale = $_COOKIE['zmWatchScale'.$Monitor->Id()];
} else if ( isset( $_COOKIE['zmWatchScale'] ) ) {

View File

@ -104,7 +104,7 @@ echo htmlSelect( 'newGroup[ParentId]', $options, $newGroup->ParentId(), array('o
<select name="newGroup[MonitorIds][]" size="4" multiple="multiple" onchange="configureButtons(this);">
<?php
$monitors = dbFetchAll( 'SELECT Id,Name FROM Monitors ORDER BY Sequence ASC' );
$monitorIds = array_flip( explode( ',', $newGroup->MonitorIds() ) );
$monitorIds = $newGroup->MonitorIds();
foreach ( $monitors as $monitor ) {
if ( visibleMonitor( $monitor['Id'] ) ) {
?>

View File

@ -0,0 +1,37 @@
function startDownload( exportFile ) {
window.location.replace( exportFile );
}
var exportTimer = null;
function exportProgress() {
var tickerText = $('exportProgressTicker').get('text');
if ( tickerText.length < 1 || tickerText.length > 4 )
$('exportProgressTicker').set( 'text', '.' );
else
$('exportProgressTicker').appendText( '.' );
}
function exportResponse( respObj, respText ) {
window.location.replace( thisUrl+'?view='+currentView+'&'+eidParm+'&exportFile='+respObj.exportFile+'&generated='+((respObj.result=='Ok')?1:0) );
}
function exportEvent( form ) {
var parms = 'view=request&request=event&action=download';
parms += '&'+$(form).toQueryString();
var query = new Request.JSON( { url: thisUrl, method: 'post', data: parms, onSuccess: exportResponse } );
query.send();
$('exportProgress').removeClass( 'hidden' );
$('exportProgress').setProperty( 'class', 'warnText' );
$('exportProgressText').set( 'text', exportProgressString );
exportProgress();
exportTimer = exportProgress.periodical( 500 );
}
function initPage() {
if ( exportReady ) {
startDownload.pass( exportFile ).delay( 1500 );
}
}
window.addEvent( 'domready', initPage );

View File

@ -0,0 +1,19 @@
<?php
if ( isset($_REQUEST['eids']) ) {
$eidParms = array();
foreach ( $_REQUEST['eids'] as $eid )
$eidParms[] = "eids[]=".validInt($eid);
?>
var eidParm = '<?php echo join( '&', $eidParms ) ?>';
<?php
} else if (isset($_REQUEST['eid'])) {
?>
var eidParm = 'eid=<?php echo validInt($_REQUEST['eid']) ?>';
<?php
}
?>
var exportReady = <?php echo !empty($_REQUEST['generated'])?'true':'false' ?>;
var exportFile = '<?php echo !empty($_REQUEST['exportFile'])?validJsStr($_REQUEST['exportFile']):'' ?>';
var exportProgressString = '<?php echo addslashes(translate('Exporting')) ?>';

View File

@ -40,8 +40,6 @@ function vjsReplay() {
}
}
$j.ajaxSetup ({timeout: AJAX_TIMEOUT }); //sets timeout for all getJSON.
var cueFrames = null; //make cueFrames availaible even if we don't send another ajax query
function initialAlarmCues (eventId) {
@ -50,13 +48,13 @@ function initialAlarmCues (eventId) {
function setAlarmCues (data) {
cueFrames = data.frames;
alarmSpans = renderAlarmCues();
alarmSpans = renderAlarmCues(vid ? $j("#videoobj") : $j("#evtStream"));//use videojs width or zms width
$j(".alarmCue").html(alarmSpans);
}
function renderAlarmCues () {
function renderAlarmCues (containerEl) {
if (cueFrames) {
var cueRatio = (vid ? $j("#videoobj").width() : $j("#evtStream").width()) / (cueFrames[cueFrames.length - 1].Delta * 100);//use videojs width or zms width
var cueRatio = containerEl.width() / (cueFrames[cueFrames.length - 1].Delta * 100);
var minAlarm = Math.ceil(1/cueRatio);
var spanTimeStart = 0;
var spanTimeEnd = 0;
@ -134,45 +132,21 @@ 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;
}
let autoScale = Math.round(newWidth / eventData.Width * SCALE_BASE);
let scales = $j('#scale option').map(function() {return parseInt($j(this).val());}).get();
scales.shift();
let closest = null;
$j(scales).each(function () { //Set zms scale to nearest regular scale. Zoom does not like arbitrary scale values.
if (closest == null || Math.abs(this - autoScale) < Math.abs(closest - autoScale)) {
closest = this.valueOf();
}
});
autoScale = closest;
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
}
function changeScale() {
let scale = $j('#scale').val();
let newWidth = null;
let newHeight = null;
let autoScale = null;
let newWidth;
let newHeight;
let autoScale;
let eventViewer;
let alarmCue = $j('div.alarmCue');
let bottomEl = streamMode == 'stills' ? $j('#eventImageNav') : $j('#replayStatus');
if (streamMode == 'stills') {
eventViewer = $j('#eventThumbs');
} else {
eventViewer = $j(vid ? '#videoobj' : '#evtStream');
}
if (scale == "auto") {
let newSize = scaleToFit();
let newSize = scaleToFit(eventData.Width, eventData.Height, eventViewer, bottomEl);
newWidth = newSize.width;
newHeight = newSize.height;
autoScale = newSize.autoScale;
@ -181,16 +155,18 @@ function changeScale() {
newWidth = eventData.Width * scale / SCALE_BASE;
newHeight = eventData.Height * scale / SCALE_BASE;
}
let alarmCue = $j('div.alarmCue');
let eventViewer = $j(vid ? '#videoobj' : '#evtStream')
eventViewer.width(newWidth);
if (!(streamMode == 'stills')) eventViewer.width(newWidth); //stills handles its own width
eventViewer.height(newHeight);
if ( !vid ) { // zms needs extra sizing
streamScale(scale == "auto" ? autoScale : scale);
alarmCue.width(newWidth);
drawProgressBar();
}
alarmCue.html(renderAlarmCues());//just re-render alarmCues. skip ajax call
if (streamMode == 'stills') {
slider.autosize();
alarmCue.html(renderAlarmCues($j('#thumbsSliderPanel')));
} else {
alarmCue.html(renderAlarmCues(eventViewer));//just re-render alarmCues. skip ajax call
}
if (scale == "auto") {
Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365});
}else{
@ -505,6 +481,7 @@ function streamQuery() {
var slider = null;
var scroll = null;
var currEventId = null;
var CurEventDefVideoPath = null;
function getEventResponse( respObj, respText ) {
@ -698,13 +675,11 @@ function resetEventStills() {
fid = 1;
else if ( fid > eventData.Frames )
fid = eventData.Frames;
checkFrames( eventData.Id, fid );
checkFrames( eventData.Id, fid, ($j('#eventImagePanel').css('display')=='none'?'':'true'));
scroll.toElement( 'eventThumb'+fid );
}
} ).set( 0 );
}
if ( $('eventThumbs').getStyle( 'height' ).match( /^\d+/ ) < (parseInt(eventData.Height)+80) )
$('eventThumbs').setStyle( 'height', ($j(vid ? '#videoobj' : '#evtStream').height())+'px' );
}
function getFrameResponse( respObj, respText ) {
@ -837,10 +812,6 @@ function getActResponse( respObj, respText ) {
if ( checkStreamForErrors( "getActResponse", respObj ) )
return;
if ( respObj.refreshParent )
if (refreshParent == false) refreshParent = true; //Bypass filter window redirect fix.
refreshParentWindow();
if ( respObj.refreshEvent )
eventQuery( eventData.Id );
}
@ -893,6 +864,7 @@ function showStream() {
$('streamEvent').addClass( 'hidden' );
streamMode = 'video';
if (scale == 'auto') changeScale();
}
function showStills() {
@ -924,6 +896,7 @@ function showStills() {
);
}
resetEventStills();
if (scale == 'auto') changeScale();
}
function showFrameStats() {

View File

@ -48,6 +48,7 @@ var canEditEvents = <?php echo canEdit( 'Events' )?'true':'false' ?>;
var streamTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
var streamMode = '<?php echo $streamMode ?>';
//
// Strings

View File

@ -15,6 +15,7 @@ function toggleCheckbox( element, name ) {
form.editBtn.disabled = !checked;
form.archiveBtn.disabled = unarchivedEvents?!checked:true;
form.unarchiveBtn.disabled = archivedEvents?!checked:true;
form.downloadBtn.disabled = !checked;
form.exportBtn.disabled = !checked;
form.deleteBtn.disabled = !checked;
}
@ -38,6 +39,7 @@ function configureButton( element, name ) {
form.editBtn.disabled = !checked;
form.archiveBtn.disabled = (!checked)||(!unarchivedEvents);
form.unarchiveBtn.disabled = (!checked)||(!archivedEvents);
form.downloadBtn.disabled = !checked;
form.exportBtn.disabled = !checked;
form.deleteBtn.disabled = !checked;
}
@ -74,6 +76,19 @@ function editEvents( element, name ) {
createPopup( '?view=eventdetail&'+eids.join( '&' ), 'zmEventDetail', 'eventdetail' );
}
function downloadVideo( element, name ) {
var form = element.form;
var eids = new Array();
for (var i = 0; i < form.elements.length; i++) {
if (form.elements[i].name.indexOf(name) == 0) {
if ( form.elements[i].checked ) {
eids[eids.length] = 'eids[]='+form.elements[i].value;
}
}
}
createPopup( '?view=download&'+eids.join( '&' ), 'zmDownload', 'download' );
}
function exportEvents( element, name ) {
var form = element.form;
var eids = new Array();

View File

@ -4,10 +4,7 @@ var openFilterWindow = false;
var archivedEvents = <?php echo !empty($archived)?'true':'false' ?>;
var unarchivedEvents = <?php echo !empty($unarchived)?'true':'false' ?>;
var filterQuery = '<?php echo isset($filterQuery)?validJsStr($filterQuery):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr($sortQuery):'' ?>';
var maxWidth = <?php echo $maxWidth?$maxWidth:0 ?>;
var maxHeight = <?php echo $maxHeight?$maxHeight:0 ?>;
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
var confirmDeleteEventsString = "<?php echo addslashes(translate('ConfirmDeleteEvents')) ?>";

View File

@ -49,7 +49,6 @@ function submitToFilter( element ) {
function submitToEvents( element ) {
var form = element.form;
if ( validateForm( form ) ) {
form.target = 'zmEvents';
form.action = thisUrl + '?view=events';
form.submit();
}
@ -58,7 +57,6 @@ function submitToEvents( element ) {
function executeFilter( element ) {
var form = element.form;
if ( validateForm( form ) ) {
form.target = 'zmEvents';
form.action = thisUrl + '?view=events';
form.elements['action'].value = 'execute';
form.submit();
@ -67,8 +65,6 @@ function executeFilter( element ) {
function saveFilter( element ) {
var form = element.form;
//form.target = 'zmFilter';
form.target = window.name;
form.elements['action'].value = element.value;
form.action = thisUrl + '?view=filter';

View File

@ -1,3 +1,6 @@
var filterQuery = '<?php echo isset($filterQuery)?validJsStr(htmlspecialchars_decode($filterQuery)):'' ?>';
var sortQuery = '<?php echo isset($sortQuery)?validJsStr(htmlspecialchars_decode($sortQuery)):'' ?>';
var deleteSavedFilterString = "<?php echo translate('DeleteSavedFilter') ?>";
function validateForm( form ) {
<?php

View File

@ -1,15 +1,35 @@
function changeScale() {
var scale = $('scale').get('value');
var img = $('frameImg');
if ( img ) {
var baseWidth = $('base_width').value;
var baseHeight = $('base_height').value;
var newWidth = ( baseWidth * scale ) / SCALE_BASE;
var newHeight = ( baseHeight * scale ) / SCALE_BASE;
let scale = $j('#scale').val();
let img = $j('#frameImg');
let controlsLinks = {
next: $j('#nextLink'),
prev: $j('#prevLink'),
first: $j('#firstLink'),
last: $j('#lastLink')
}
img.style.width = newWidth + "px";
img.style.height = newHeight + "px";
if (img) {
let baseWidth = $j('#base_width').val();
let baseHeight = $j('#base_height').val();
if (scale == "auto") {
let newSize = scaleToFit(baseWidth, baseHeight, img, $j('#controls'));
newWidth = newSize.width;
newHeight = newSize.height;
autoScale = newSize.autoScale;
} else {
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
newWidth = baseWidth * scale / SCALE_BASE;
newHeight = baseHeight * scale / SCALE_BASE;
}
img.css('width', newWidth + "px");
img.css('height', newHeight + "px");
}
Cookie.write( 'zmWatchScale', scale, { duration: 10*365 } );
$j.each(controlsLinks, function(k, anchor) { //Make frames respect scale choices
anchor.prop('href', anchor.prop('href').replace(/scale=.*&/, 'scale=' + scale + '&'));
});
}
if (scale == "auto") $j(document).ready(changeScale);

View File

@ -1,2 +1,3 @@
var scale = "<?php echo $scale ?>";
var SCALE_BASE = <?php echo SCALE_BASE ?>;

View File

@ -42,7 +42,7 @@ function evaluateLoadTimes() {
imageLoadTimesEvaluated=0;
setSpeed(speedIndex);
$('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + ".";
}
} // end evaluateLoadTimes()
// time is seconds since epoch
function SetImageSource( monId, time ) {
@ -335,6 +335,7 @@ function redrawScreen() {
$('zoomout').style.display="none";
$('panleft').style.display="none";
$('panright').style.display="none";
if ($('downloadVideo')) $('downloadVideo').style.display="none";
} else {
// switch out of liveview mode
@ -351,6 +352,7 @@ function redrawScreen() {
$('panleft').style.display="inline-flex";
$('panright').style.display="inline";
$('panright').style.display="inline-flex";
if ($('downloadVideo')) $('downloadVideo').style.display="inline";
}
if ( fitMode == 1 ) {
@ -465,12 +467,12 @@ function setSpeed( speed_index ) {
playSecsperInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000;
console.log("playSecsPerInterval: " + playSecsperInterval + " = currentspeed:" + currentSpeed + " * " + currentDisplayInterval + " /1000");
showSpeed(speed_index);
if ( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
if ( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
}
function setLive(value) {
liveMode = value;
redrawScreen();
changeDateTime();
}
@ -510,16 +512,12 @@ function clicknav(minSecs,maxSecs,live) {// we use the current time if we can
if ( live == 1 )
liveStr="&live=1";
var fitStr="&fit=0";
if ( fitMode == 1 )
fitStr="&fit=1";
var zoomStr="";
for ( var i=0; i < numMonitors; i++ )
if ( monitorZoomScale[monitorPtr[i]] < 0.99 || monitorZoomScale[monitorPtr[i]] > 1.01 ) // allow for some up/down changes and just treat as 1 of almost 1
zoomStr += "&z" + monitorPtr[i].toString() + "=" + monitorZoomScale[monitorPtr[i]].toFixed(2);
var uri = "?view=" + currentView + fitStr + groupStr + minStr + maxStr + currentStr + intervalStr + liveStr + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value];
var uri = "?view=" + currentView + '&fit='+(fitMode==1?'1':'0') + groupStr + minStr + maxStr + currentStr + intervalStr + liveStr + zoomStr + "&scale=" + $j("#scaleslider")[0].value + "&speed=" + speeds[$j("#speedslider")[0].value];
window.location = uri;
} // end function clicknav
@ -557,6 +555,9 @@ function click_panright() {
maxTimeSecs = minTimeSecs + rangeTimeSecs - 1;
clicknav(minTimeSecs,maxTimeSecs,0);
}
function click_download() {
createPopup( '?view=download', 'zmDownload', 'download' );
}
function click_all_events() {
clicknav(0,0,0);
}

View File

@ -31,14 +31,18 @@ var groupStr=<?php echo $group_id ? "'&group=$group_id'" : '""'; ?>;
// Because we might not have time as the criteria, figure out the min/max time when we run the query
$minTimeSecs = strtotime('2036-01-01 01:01:01');
$maxTimeSecs = strtotime('1950-01-01 01:01:01');
if ( ! $maxTimeSecs )
$maxTimeSecs = time();
if ( ! $minTimeSecs )
$minTimeSecs = strtotime('2010-01-01 01:01:01');
// This builds the list of events that are eligible from this range
$index = 0;
$anyAlarms = false;
if ( ! $initialModeIsLive ) {
$result = dbQuery( $eventsSql );
if ( ! $result ) {
Fatal('SQL-ERR');
@ -81,6 +85,7 @@ if ( !isset($minTime) || !isset($maxTime) ) {
$minTime = strftime($minTimeSecs);
} else {
$minTimeSecs = strtotime($minTime);
$maxTimeSecs = strtotime($maxTime);
}
@ -136,6 +141,7 @@ if ( $mId > 0 ) {
}
echo "var maxScore=$maxScore;\n"; // used to skip frame load if we find no alarms.
} // end if initialmodeislive
echo "var monitorName = [];\n";
echo "var monitorLoading = [];\n";
echo "var monitorImageObject = [];\n";

View File

@ -3,8 +3,7 @@ var events = {};
function showEvent( eid, fid, width, height ) {
var url = '?view=event&eid='+eid+'&fid='+fid;
url += filterQuery;
var pop=createPopup( url, 'zmEvent', 'event', width, height );
pop.vid=$('preview');
window.location.href = url;
//video element is blocking video elements elsewhere in chrome possible interaction with mouseover event?
//FIXME unless an exact cause can be determined should store all video controls and do something to the other controls when we want to load a new video seek etc or whatever may block
@ -144,13 +143,13 @@ function loadEventImage( imagePath, eid, fid, width, height, fps, videoName, dur
function tlZoomBounds( minTime, maxTime ) {
console.log( "Zooming" );
window.location = '?view='+currentView+filterQuery+'&minTime='+minTime+'&maxTime='+maxTime;
location.replace('?view='+currentView+filterQuery+'&minTime='+minTime+'&maxTime='+maxTime);
}
function tlZoomRange( midTime, range ) {
window.location = '?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range;
location.replace('?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range);
}
function tlPan( midTime, range ) {
window.location = '?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range;
location.replace('?view='+currentView+filterQuery+'&midTime='+midTime+'&range='+range);
}

View File

@ -25,8 +25,19 @@ function showPtzControls() {
function changeScale() {
var scale = $('scale').get('value');
var newWidth = ( monitorWidth * scale ) / SCALE_BASE;
var newHeight = ( monitorHeight * scale ) / SCALE_BASE;
var newWidth;
var newHeight;
if (scale == "auto") {
let newSize = scaleToFit(monitorWidth, monitorHeight, $j('#liveStream'+monitorId), $j('#replayStatus'));
newWidth = newSize.width;
newHeight = newSize.height;
autoScale = newSize.autoScale;
} else {
$j(window).off('resize', endOfResize); //remove resize handler when Scale to Fit is not active
newWidth = monitorWidth * scale / SCALE_BASE;
newHeight = monitorHeight * scale / SCALE_BASE;
}
Cookie.write( 'zmWatchScale'+monitorId, scale, { duration: 10*365 } );
@ -36,7 +47,7 @@ function changeScale() {
streamImg.style.width = newWidth + "px";
streamImg.style.height = newHeight + "px";
streamImg.src = streamImg.src.replace(/scale=\d+/i, 'scale='+scale);
streamImg.src = streamImg.src.replace(/scale=\d+/i, 'scale='+(scale== 'auto' ? autoScale : scale));
} else {
console.error("No element found for liveStream.");
}
@ -655,6 +666,7 @@ function initPage() {
if ( refreshApplet && appletRefreshTime )
appletRefresh.delay( appletRefreshTime*1000 );
if (scale == "auto") changeScale();
}
// Kick everything off

View File

@ -50,7 +50,7 @@ var monitorWidth = <?php echo $monitor->Width() ?>;
var monitorHeight = <?php echo $monitor->Height() ?>;
var monitorUrl = '<?php echo ( $monitor->Server()->Url() ) ?>';
var scale = <?php echo $scale ?>;
var scale = '<?php echo $scale ?>';
var statusRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_STATUS ?>;
var eventsRefreshTimeout = <?php echo 1000*ZM_WEB_REFRESH_EVENTS ?>;

View File

@ -78,7 +78,7 @@ if ( isset($_COOKIE['zmMontageLayout']) ) {
$options = array();
$Layout = '';
$Positions = '';
if ( $layout_id ) {
if ( $layout_id and is_numeric($layout_id) and isset($layoutsById[$layout_id]) ) {
$Layout = $layoutsById[$layout_id];
$Positions = json_decode( $Layout->Positions(), true );
}

View File

@ -59,6 +59,35 @@ include('_monitor_filters.php');
$filter_bar = ob_get_contents();
ob_end_clean();
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) {
$filter = array(
'Query' => array(
'terms' => array(
array('attr' => 'StartDateTime', 'op' => '>=', 'val' => $_REQUEST['minTime'], 'obr' => '1'),
array('attr' => 'StartDateTime', 'op' => '<=', 'val' => $_REQUEST['maxTime'], 'cnj' => 'and', 'cbr' => '1'),
)
),
);
if (isset($_SESSION['MonitorId'])) {
$filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => '=', 'val' => $_SESSION['MonitorId'], 'cnj' => 'and'));
}
if (( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) && !isset($_SESSION['MonitorId'])) {
for ($i=0; $i < count($displayMonitors); $i++) {
if ($i == '0') {
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1');
} else if ($i == (count($displayMonitors)-1)) {
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1');
} else {
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or');
}
}
}
parseFilter( $filter );
session_start();
$_SESSION['montageReviewFilter'] = $filter;
session_write_close();
}
// 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)
// Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly.
@ -106,6 +135,7 @@ if ( !isset($_REQUEST['minTime']) && !isset($_REQUEST['maxTime']) ) {
$time = time();
$maxTime = strftime("%FT%T",$time);
$minTime = strftime("%FT%T",$time - 3600);
Logger::Debug("Defaulting to $minTime to $maxTime");
}
if ( isset($_REQUEST['minTime']) )
$minTime = validHtmlStr($_REQUEST['minTime']);
@ -113,7 +143,7 @@ if ( isset($_REQUEST['minTime']) )
if ( isset($_REQUEST['maxTime']) )
$maxTime = validHtmlStr($_REQUEST['maxTime']);
// AS a special case a "all" is passed in as an exterme interval - if so , clear them here and let the database query find them
// AS a special case a "all" is passed in as an extreme interval - if so, clear them here and let the database query find them
if ( (strtotime($maxTime) - strtotime($minTime))/(365*24*3600) > 30 ) {
// test years
@ -161,6 +191,7 @@ $eventsSql .= ' GROUP BY E.Id,E.Name,E.StartTime,E.Length,E.Frames,E.MaxScore,E.
if ( isset($minTime) && isset($maxTime) ) {
$minTimeSecs = strtotime($minTime);
$maxTimeSecs = strtotime($maxTime);
Logger::Debug("Min/max time secs: $minTimeSecs $maxTimeSecs");
$eventsSql .= " HAVING CalcEndTimeSecs > '" . $minTimeSecs . "' AND StartTimeSecs < '" . $maxTimeSecs . "'";
$frameSql .= " AND TimeStamp > '" . $minTime . "' AND TimeStamp < '" . $maxTime . "'";
}
@ -190,31 +221,38 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
<input type="datetime-local" name="maxTime" id="maxTime" value="<?php echo preg_replace('/ /', 'T', $maxTime ) ?>" onchange="changeDateTime(this);">
</div>
<div id="ScaleDiv">
<label for="scaleslider"><?php echo translate('Scale')?></label>
<input id="scaleslider" type="range" min="0.1" max="1.0" value="<?php echo $defaultScale ?>" step="0.10" onchange="setScale(this.value);" oninput="showScale(this.value);"/>
<span id="scaleslideroutput"><?php echo number_format((float)$defaultScale,2,'.','')?> x</span>
<label for="scaleslider"><?php echo translate('Scale')?></label>
<input id="scaleslider" type="range" min="0.1" max="1.0" value="<?php echo $defaultScale ?>" step="0.10" onchange="setScale(this.value);" oninput="showScale(this.value);"/>
<span id="scaleslideroutput"><?php echo number_format((float)$defaultScale,2,'.','')?> x</span>
</div>
<div id="SpeedDiv">
<label for="speedslider"><?php echo translate('Speed') ?></label>
<input id="speedslider" type="range" min="0" max="<?php echo count($speeds)-1?>" value="<?php echo $speedIndex ?>" step="1" onchange="setSpeed(this.value);" oninput="showSpeed(this.value);"/>
<span id="speedslideroutput"><?php echo $speeds[$speedIndex] ?> fps</span>
<label for="speedslider"><?php echo translate('Speed') ?></label>
<input id="speedslider" type="range" min="0" max="<?php echo count($speeds)-1?>" value="<?php echo $speedIndex ?>" step="1" onchange="setSpeed(this.value);" oninput="showSpeed(this.value);"/>
<span id="speedslideroutput"><?php echo $speeds[$speedIndex] ?> fps</span>
</div>
<div style="display: inline-flex; border: 1px solid black; flex-flow: row wrap;">
<button type="button" id="panleft" onclick="click_panleft();" >&lt; <?php echo translate('Pan') ?></button>
<button type="button" id="zoomin" onclick="click_zoomin();" ><?php echo translate('In +') ?></button>
<button type="button" id="zoomout" onclick="click_zoomout();" ><?php echo translate('Out -') ?></button>
<button type="button" id="lasteight" onclick="click_lastEight();" ><?php echo translate('8 Hour') ?></button>
<button type="button" id="lasthour" onclick="click_lastHour();" ><?php echo translate('1 Hour') ?></button>
<button type="button" id="allof" onclick="click_all_events();" ><?php echo translate('All Events') ?></button>
<button type="button" id="live" onclick="setLive(1-liveMode);"><?php echo translate('Live') ?></button>
<button type="button" id="fit" onclick="setFit(1-fitMode);" ><?php echo translate('Fit') ?></button>
<button type="button" id="panright" onclick="click_panright();" ><?php echo translate('Pan') ?> &gt;</button>
<button type="button" id="panleft" onclick="click_panleft();" >&lt; <?php echo translate('Pan') ?></button>
<button type="button" id="zoomin" onclick="click_zoomin();" ><?php echo translate('In +') ?></button>
<button type="button" id="zoomout" onclick="click_zoomout();" ><?php echo translate('Out -') ?></button>
<button type="button" id="lasteight" onclick="click_lastEight();" ><?php echo translate('8 Hour') ?></button>
<button type="button" id="lasthour" onclick="click_lastHour();" ><?php echo translate('1 Hour') ?></button>
<button type="button" id="allof" onclick="click_all_events();" ><?php echo translate('All Events') ?></button>
<button type="button" id="live" onclick="setLive(1-liveMode);"><?php echo translate('Live') ?></button>
<button type="button" id="fit" onclick="setFit(1-fitMode);" ><?php echo translate('Fit') ?></button>
<button type="button" id="panright" onclick="click_panright();" ><?php echo translate('Pan') ?> &gt;</button>
<?php
if (count($displayMonitors) != 0) {
?>
<button type="button" id="downloadVideo" onclick="click_download();"><?php echo translate('Download Video') ?></button>
<?php
}
?>
</div>
<div id="timelinediv">
<canvas id="timeline" onmousemove="mmove(event);" ontouchmove="tmove(event);" onmousedown="mdown(event);" onmouseup="mup(event);" onmouseout="mout(event);"></canvas>
<span id="scrubleft"></span>
<span id="scrubright"></span>
<span id="scruboutput"></span>
<canvas id="timeline" onmousemove="mmove(event);" ontouchmove="tmove(event);" onmousedown="mdown(event);" onmouseup="mup(event);" onmouseout="mout(event);"></canvas>
<span id="scrubleft"></span>
<span id="scrubright"></span>
<span id="scruboutput"></span>
</div>
</div>
</div>

View File

@ -700,12 +700,16 @@ xhtmlHeaders(__FILE__, translate('Timeline') );
?>
<body>
<div id="page">
<?php echo getNavBarHTML() ?>
<div id="header">
<div id="headerButtons">
<?php echo makePopupLink( '?view=events&amp;page=1'.htmlspecialchars($filterQuery), 'zmEvents', 'events', translate('List'), canView( 'Events' ) ) ?>
<a href="#" onclick="closeWindow();"><?php echo translate('Close') ?></a>
<div id="info">
<h2><?php echo translate('Timeline') ?></h2>
<a id="refreshLink" href="#" onclick="location.reload(true);"><?php echo translate('Refresh') ?></a>
</div>
<div id="headerButtons">
<a href="#" onclick="window.history.back();"><?php echo translate('Back') ?></a>
<a href="?view=events&amp;page=1<?php echo htmlspecialchars($filterQuery) ?>"><?php echo translate('List') ?></a>
</div>
<h2><?php echo translate('Timeline') ?></h2>
</div>
<div id="content" class="chartSize">
<div id="topPanel" class="graphWidth">

View File

@ -61,14 +61,9 @@ xhtmlHeaders( __FILE__, $monitor->Name()." - ".translate('Feed') );
?>
<body>
<div id="page">
<div id="content">
<div id="menuBar">
<?php echo getNavBarHTML() ?>
<div id="header">
<div id="monitorName"><?php echo $monitor->Name() ?></div>
<script type="text/javascript">
if ( window.opener ) {
document.write('<div id="closeControl"><a href="#" onclick="closeWindow(); return( false );"><?php echo translate('Close') ?></a></div>');
}
</script>
<div id="menuControls">
<?php
if ( canView( 'Control' ) && $monitor->Type() == 'Local' ) {
@ -79,7 +74,9 @@ if ( canView( 'Control' ) && $monitor->Type() == 'Local' ) {
?>
<div id="scaleControl"><?php echo translate('Scale') ?>: <?php echo buildSelect( "scale", $scales, "changeScale( this );" ); ?></div>
</div>
</div>
<div id="closeControl"><a href="#" onclick="window.history.back()"><?php echo translate('Back') ?></a></div>
</div>
<div id="content">
<div id="imageFeed"><?php echo getStreamHTML( $monitor, array('scale'=>$scale) ); ?></div>
<div id="monitorStatus">
<?php if ( canEdit( 'Monitors' ) ) { ?>

View File

@ -47,6 +47,7 @@ if ( $archivetype ) {
if ( is_readable($filename_path) ) {
header( "Content-type: application/$mimetype" );
header( "Content-Disposition: attachment; filename=$filename");
set_time_limit(0);
readfile( $filename_path );
} else {
Error("$filename_path does not exist or is not readable.");