1
0
Fork 0
mirror of https://gitlab.com/Shinobi-Systems/ShinobiCE.git synced 2025-03-09 15:40:15 +00:00
This commit is contained in:
Moe 2019-10-26 13:34:02 -07:00
parent ef40f3f231
commit 167603dfb0
118 changed files with 16152 additions and 5441 deletions

3
web/libs/.gitignore vendored
View file

@ -1 +1,2 @@
demo
demo
impervious

41
web/libs/css/bootstrap-slider.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -460,4 +460,4 @@
opacity: 1;
transform: rotate(360deg)
}
}
}

View file

@ -87,3 +87,361 @@ img{max-width:100%}
.video_grid .thumb .title-strip{top:0;opacity:0.5}
.video_grid .thumb .button-strip{bottom:0;opacity:0}
.video_grid .thumb:hover .title-strip, .video_grid .thumb:hover .button-strip{opacity:1}
/* */
.canvas_holder canvas{z-index:11}
.demo-blog .mdl-card__media ~ .mdl-card__supporting-text{position:relative;overflow:initial;cursor:move}
.demo-blog .mdl-card__media ~ .mdl-card__supporting-text .btn-group{cursor: default}
.demo-blog .demo-blog__posts.montage{max-width:100%}
.hide-side .mdl-layout__drawer{overflow-y: hidden}
.mdl-layout__header-row{padding-left:10!important}
.mdl-layout__header-row .nav>li>a{border-radius:50%;}
.mdl-layout__drawer-button i{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;height:1em;color:#fff}
.video_video{margin:auto;max-width:100%;max-height:600px;}
#confirm_window .video_video{margin-top:15px}
#confirm_window .info-table{margin-top:15px}
@media (max-width: 768px){
.full.modal .modal-body,.medium.modal .modal-body{max-height:400px;overflow:auto}
}
@media (min-width: 768px){
.modal.full,.modal.medium{padding-left:0!important;}
.modal.full .modal-dialog{width:calc(100% - 10px)!important;margin: 30px auto;max-width: none;}
.modal.medium .modal-dialog{width:calc(70% - 10px)!important;margin: 30px auto;}
.full.modal .modal-body,.medium.modal .modal-body{height:calc(100% - 200px);overflow:auto}
}
.flex-container-modal-body{overflow: auto}
.flex-container-modal-body .flex-block>div{flex:1;float:none}
.modal{overflow:auto!important}
.videos_list .title{font-size:12pt;padding:0 10px}
.demo-drawer{background:#2b2a2a;color:#fff;}
.demo-drawer.mdl-layout__drawer .mdl-navigation{padding-top:0;}
.demo-drawer::-webkit-scrollbar{display:none;}
.small-square-img{height:40px;width:40px;border-radius:5px}
#side_menu_right.nav-xs{width:0!important;overflow:hidden}
.side-menu table{color:#fff;}
#main_canvas{background:#333;color:#fff;padding-top:0}
#main_header{background:#222;color:#fff;}
#logs_modal table tr td:first-child{width:10%}
[class_toggle]{cursor:pointer}
.form-group label{width:100%}
.table-striped>tbody>tr>td{vertical-align:middle}
.table-striped .thumbnail{width:100px;height:80px;border-radius:5px;margin:0;display:inline-block;}
.follow-list ul{padding:0;margin:0;font-family:"Roboto","Helvetica","Arial",sans-serif;}
.follow-list ul a:not(.btn){color:#fff}
.os_bars{width:600px;display:inline-block;padding:5px 0 0 10px}
@media screen and (max-width: 600px){
.os_bars{width:200px;}
.os_bars label{padding:2.5px 0;margin:0;font-size:8pt}
}
.os_bars .display-table .display-table-cell{padding:5px;vertical-align:center;width:33%}
.progress{height:5px;margin:0;}
.os_bars label,.os_bars .percent{padding:2.5px 0;margin:0;font-size:7.5pt}
.ui-pnotify-hide .ui-pnotify{display:none!important}
/*cool dropdown thing*/
ul.msg_list li {
background: #f7f7f7;color:#333;
padding: 5px;
display: list-item;
margin: 6px 6px 0;
width: 96% !important
}
ul.msg_list li div{display:block}
ul.msg_list li:last-child {
margin-bottom: 6px;
padding: 10px
}
ul.msg_list li a {
padding: 3px 5px !important
}
ul.msg_list li .progress {
height:5px;margin:10px 0 0 0;
}
ul.msg_list li .image img {
border-radius: 2px 2px 2px 2px;
-webkit-border-radius: 2px 2px 2px 2px;
float: left;
margin-right: 10px;
width: 11%
}
ul.msg_list li .time {
font-size: 11px;
font-style: italic;
font-weight: bold;
position: absolute;
}
ul.msg_list li .message {
display: block !important;
font-size: 11px
}
.dropdown-menu.msg_list span {
white-space: normal
}
.dropdown-menu {
border: medium none;
box-shadow: none;
display: none;
float: left;
font-size: 12px;
left: 0;
list-style: none outside none;
padding: 0;
position: absolute;
text-shadow: none;
top: 100%;
z-index: 9998;
border: 1px solid #D9DEE4;
border-top-left-radius: 0;
border-top-right-radius: 0
}
.dropdown-menu>li>a {
color: #5A738E
}
.navbar-nav .open .dropdown-menu {
position: absolute;
background: #fff;
margin-top: 0;
border: 1px solid #D9DEE4;
-webkit-box-shadow: none;
right: 0;
left: auto;
width: 220px
}
.is-small-screen .nav>li{display:inline-block}
.navbar-nav .open .dropdown-menu li a{padding:7px 15px}
.navbar-nav .open .dropdown-menu.msg_list {
width: 300px
}
.nav>li>a{color:#fff}
.nav>li>a:focus, .nav>li>a:hover,.nav .open>a, .nav .open>a:focus, .nav .open>a:hover{background:#867560}
.mdl-js-layout.hide-side:not(.is-small-screen){
}
@media screen and (min-width: 1025px){
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__drawer {
width: 0px;transition:0.2s;
overflow: hidden;
}
}
.mdl-js-layout.hide-side:not(.is-small-screen) .mdl-layout__header .mdl-layout__drawer-button{
display:none;
}
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__content{
margin-left: 0px;transition:0.2s
}
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__header{
margin-left: 0px;width:100%;transition:0.2s
}
.mdl-menu__item>div{display:flex;align-items: center;width:100%}
.mdl-menu__item>div>i{margin-right:5px}
/*Digital Zoom*/
.stream-block{
position: relative;
overflow: auto;
}
.zoomGlass {
overflow: hidden;
transition: none;
width: 175px; height: 175px;
position: absolute;
border-radius: 15px;
border: 3px solid #ddd;
z-index:9999;
}
.zoomGlass iframe,
.zoomGlass video,
.zoomGlass canvas{
padding: 0!important;
max-width: none!important;
position: absolute;
transition: none;
}
.zoomGlass .hoverShade{position:absolute;width:100%;height:100%}
/*** custom checkboxes ***/
.checkbox input[type=checkbox] { display:none; } /* to hide the checkbox itself */
.checkbox input[type=checkbox] + label:before {
font-family: FontAwesome;
display: inline-block;
}
.checkbox input[type=checkbox] + label:before { content: "\f096"; } /* unchecked icon */
.checkbox input[type=checkbox] + label:before { letter-spacing: 10px; } /* space between checkbox and label */
.checkbox input[type=checkbox]:checked + label:before { content: "\f046"; } /* checked icon */
.checkbox input[type=checkbox]:checked + label:before { letter-spacing: 5px; } /* allow space for check mark */
/*Clock*/
#time-date {font-size:12px; text-align:center;}
@media screen and (min-width:1025px){
#clock {padding-right:35px}
}
#clock ul { width:150px; margin:0 auto; padding:0px; list-style:none; text-align:center; }
#clock ul li { display:inline; font-size:1.6em; text-align:center;font-family:monospace;}
#clock .point { position:relative; -moz-animation:mymove 1s ease infinite; -webkit-animation:mymove 1s ease infinite; }
/*custom vis.js css*/
.vis-timeline{background:#212121;color:#fff;border-color:#444}
.vis-time-axis .vis-text{color: #dedede}
.vis-item.vis-range .vis-item-content{background:#333;color:#fff}
.vis-time-axis .vis-grid.vis-minor{border-color:#444}
@-moz-document url-prefix() {
.full.modal .modal-body, .medium.modal .modal-body {
height:70%
}
}
/*animations*/
@keyframes blink {
0% { opacity:1 }
50% { opacity:0 }
100% { opacity:1 }
}
@-webkit-keyframes blink {
0% { opacity:1 }
50% { opacity:0 }
100% { opacity:1 }
}
.blink,[mode="Record"] .lamp {
-webkit-animation: blink 1s linear infinite;
-moz-animation: blink 1s linear infinite;
animation: blink 1s linear infinite;
}
/* All-CSS Toggle Switch (Checkbox Hack) by Marcus Burnette - https://codepen.io/mburnette/pen/LxNxNg */
.marc-toggle {
width: 50px;
height: 25px;
}
.marc-toggle.abs-bot-left {
position: absolute;
bottom: 10px;
left: 10px;
}
.marc-toggle.abs-bot-right {
position: absolute;
bottom: 10px;
right: 10px;
}
.marc-toggle input[type=checkbox]{
height: 0;
width: 0;
visibility: hidden;
}
.marc-toggle label {
cursor: pointer;
text-indent: -9999px;
width: 100px;
height: 20px;
background: grey;
display: block;
border-radius: 100px;
margin-bottom: 0;
position: relative;
}
.marc-toggle label:after {
content: '';
position: absolute;
top: 5px;
left: 5px;
width: 10px;
height: 10px;
background: #fff;
border-radius: 90px;
transition: 0.3s;
}
.marc-toggle input:checked + label {
background: #00118c;
}
.marc-toggle input:checked + label:after {
left: calc(100% - 5px);
transform: translateX(-100%);
}
.marc-toggle label:active:after {
width: 10px;
}
/*hexagon pattern*/
.bg-hexagon {
background-color: #054e9f;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%23fdfdfd' fill-opacity='0.4' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}
.demo-drawer .mdl-menu__container{
max-height: 500px!important;
overflow-y: auto;
overflow-x: hidden;
}
/* */
.slider.slider-horizontal {
width:100%!important
}
/* */
.epic-text {
margin:15px 0 0 0;
text-align:center;
color:#777;
font-family: sans-serif;
text-transform: uppercase;
letter-spacing: 3pt;
font-size: 8pt;
}
/* Start of custom table sorter */
.table .table-header-sorter {
cursor: pointer;
white-space: nowrap;
}
.table th.table-header-sorter i.fa-sort {
color: #ccc;
}
.table th.table-header-sorter i {
margin-left: 10px;
}
/* End of custom table sorter */

View file

@ -0,0 +1,45 @@
.dark .list-group-item{border-color: #444;background:#222}
.dark .list-group-item.active{background:#c49a68;border-color:#a7865f}
.novideos{text-transform: uppercase;text-align: center;border-bottom:0!important;padding-top: 55%!important;letter-spacing:2px}
.btn-warning {
color: #fff;
background-color: #c49a68;
border-color: #c49a68;
}
.dark .table-striped>tbody>tr:nth-of-type(even){background:#616161}
.dark .table-striped>tbody>tr>td{border-color:#222;color:#fff}
.dark .table-striped>thead>tr>th{border-color:#222;color:#fff;background:#616161;vertical-align:middle;}
.dark .table-striped>tbody>tr:nth-of-type(odd){background-color: #4c4747;}
.dark .table>tbody>tr.active>td{background:inherit;border:0}
.dark code{color: #c49a68;background-color: #36333d;}
.dark a:not(.btn){color: #c49a68;}
.dark.form-control,.dark .form-control {
display: block;
width: 100%;
height: 35px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.5;
color: #eee;
background-color: #36333d;
background-image: none;
border: 1px solid #444;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.dark.form-control:focus,.dark .form-control:focus {
color: #ddd;
background-color: #333;
box-shadow: none;
}
.dark .slider-selection {
background:#555;
}

View file

@ -22,23 +22,25 @@ form.modal-body{margin:0}
.form-group-group .mdl-list__item:hover{background:#e6e6e6;border-radius:4px;}
.dark .form-group-group .mdl-list__item{color:#fff;border-bottom:1px solid #444;}
.dark .form-group-group .mdl-list__item:hover{background:#555;}
.form-group-group:last-child,.form-group-group > .form-group:last-child{margin-bottom:0}
.form-group-group h4{margin:0 -10px 15px -10px;padding:15px;background:#ddd;}
.form-group-group h4 small{color:#fff;}
.form-group-group:visible:last-child,.form-group-group > .form-group:last-child{margin-bottom:0}
.form-group-group > h4{margin:0 -10px 15px -10px;padding:15px;background:#ddd;}
.form-group-group > h4:empty{padding:2px}
.form-group-group > h4 small{color:#fff;}
.form-group-group.red{border-color:#d9534f}
.form-group-group.red h4{background:#d9534f;color:#fff}
.form-group-group.red > h4{background:#d9534f;color:#fff}
.form-group-group.purple{border-color:#3f51b5}
.form-group-group.purple h4{background:#3f51b5;color:#fff}
.form-group-group.purple > h4{background:#3f51b5;color:#fff}
.form-group-group.blue{border-color:#337ab7}
.form-group-group.blue h4{background:#337ab7;color:#fff}
.form-group-group.blue > h4{background:#337ab7;color:#fff}
.form-group-group.navy{border-color:#31708f}
.form-group-group.navy h4{background:#31708f;color:#fff}
.form-group-group.navy > h4{background:#31708f;color:#fff}
.form-group-group.green{border-color:#449d44}
.form-group-group.green h4{background:#449d44;color:#fff}
.form-group-group.green > h4{background:#449d44;color:#fff}
.form-group-group.forestgreen{border-color:#1e4046}
.form-group-group.forestgreen h4{background:#1e4046;color:#fff}
.form-group-group.forestgreen > h4{background:#1e4046;color:#fff}
.form-group-group.orange{border-color:#c49a68}
.form-group-group.orange h4{background:#c49a68;color:#fff}
.form-group-group.orange > h4{background:#c49a68;color:#fff}
.form-group-group.grey{border-color:#777}
.form-group-group.grey h4{background:#777;color:#fff}
.form-group-group.grey > h4{background:#777;color:#fff}
.dark .form-group-group{background:#222}
.form-group-group:last-child {margin-bottom: 0}

View file

@ -0,0 +1,17 @@
#diskUsedList .title {
letter-spacing: 2px;
font-weight: bold;
text-transform: uppercase;
font-size: 7pt;
padding-bottom: 5px;
}
#diskUsedList .value {
letter-spacing:2px;
font-weight:100;
}
#diskUsedList .log-item {
line-height: 1
}
#diskUsedList .log-item .progress {
margin: 2px 0 0 0;
}

View file

@ -4,3 +4,4 @@
.dark.modal .modal-body{background:#333;}
.dark.modal .close{color:#fff;}
.dark.modal{color:#fff;}
#confirm_window {z-index: 11111}

View file

@ -0,0 +1,26 @@
.state-monitor-row-fields{
border-bottom: 1px solid #444;
border-radius: 5px;
}
.state-monitor-row-fields .list-group{
height: 300px
}
.state-monitor-row .list-group .list-group-item:first-child{
border-top:0;
}
.state-monitor-row .list-group .list-group-item:last-child{
border-bottom:0;
}
.state-monitor-row-select-container {
margin-bottom: 10px;
}
.state-monitor-row-fields-container {
border: 1px solid #444;
border-radius: 5px;
}
.state-monitor-row-fields-field {
margin-top: 5px;
}

View file

@ -84,3 +84,20 @@ img.circle-img,div.circle-img{border-radius:50%;height:50px;width:50px}
[status="1"] .btn[video="launch"],[data-status="1"] .btn[video="launch"]{background:#337ab7;border-color:#337ab7}
[status="2"] .btn[launch="video"],[status="2"] .btn[video="launch"],[data-status="2"] .btn[video="launch"]{background:#a59100;border-color:#a59100}
.signal.red{background:#c9302c}
#monSectionStreamChannels,#monSectionInputMaps{margin-bottom: 15px;}
#monSectionStreamChannels:empty,#monSectionInputMaps:empty{display:none}
#monitors_list .monitor_block{transition:none}
.dropdown-menu.scrollable{max-height:300px}
.upload_file input{display:none}
#video_preview .stream-objects{right:0;margin:auto;display:inline-block;position:relative;width:auto}
.stream-block,.stream-objects{overflow: hidden!important}
.stream-objects{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}
.stream-objects .tag{position:absolute;bottom:100%;left:0;background:red;color:#fff;font-family:monospace;font-size:80%;border-radius:5px 5px 0 0 ;padding:3px 5px;}
.stream-objects .stream-detected-object{position:absolute;top:0;left:0;border:3px solid red;background:transparent;border-radius:5px}
.stream-objects .stream-detected-point{position:absolute;top:0;left:0;border:3px solid yellow;background:transparent;border-radius:5px}
.stream-objects .point{position:absolute;top:0;left:0;border:3px solid red;border-radius:50%}

View file

@ -0,0 +1,176 @@
#powerVideo .videoPlayer {
text-align: center;
display: inline-block;
position: relative;
}
#powerVideo .videoPlayer video{
max-width: 100%;
height: 300px;
object-fit: fill;
}
#powerVideo .videoPlayer:fullscreen video{
height: 100%;
max-height: 100%;
}
#powerVideoMonitorControls{
border-radius: 0 0 5px 5px;
padding: 5px;
background: #222;
margin: 0;
}
#powerVideoMonitorsList{
margin: 0;
}
#powerVideoMonitorsList .list-item{
cursor: pointer;
}
#powerVideoMonitorViews {
text-align: center;
min-height: 300px;
background: #444;
border-radius: 5px 5px 0 0;
overflow: hidden;
}
#powerVideo .videoPlayer .videoPlayer-detection-info {
position: absolute;
padding: 20px 10px 20px 10px;
height: 100%;
top: 0;
left: 0;
margin: auto;
z-index: 11;
opacity: 0;
background: rgba(0,0,0,0.7);
color: #fff;
font-family: monospace;
overflow: auto;
text-align: left;
}
#powerVideo .videoPlayer:hover .videoPlayer-detection-info,
#powerVideo .videoPlayer.show-detection-info .videoPlayer-detection-info {
opacity: 1
}
#powerVideo .videoPlayer .videoPlayer-stream-objects {
position: absolute;
width: 100%;
height: 100%;
left: 0;
right: 0;
margin: auto;
z-index: 10;
}
#powerVideo .videoPlayer .videoPlayer-detection-info-object div {
padding-left: 5px;
}
#powerVideo .videoPlayer .videoPlayer-detection-info-object {
text-align: left
}
.videoPlayer-stream-objects .tag {
position: absolute;
bottom: 100%;
left: 0;
background: red;
color: #fff;
font-family: monospace;
font-size: 80%;
border-radius: 5px 5px 0 0;
padding: 3px 5px;
}
.videoPlayer-stream-objects .stream-detected-object {
position: absolute;
top: 0;
left: 0;
border: 3px solid red;
background: transparent;
border-radius: 5px
}
.videoPlayer-stream-objects .stream-detected-point {
position: absolute;
top: 0;
left: 0;
border: 3px solid yellow;
background: transparent;
border-radius: 5px
}
.videoPlayer-stream-objects .point {
position: absolute;
top: 0;
left: 0;
border: 3px solid red;
border-radius: 50%
}
/* loading */
#powerVideo .loading {
font-size: 20pt;
text-align: center;
}
#powerVideo .loading > div {
margin-top: 5px
}
/* VIS.js */
#powerVideo video {
width: 100%;
padding: 6px 0 0 0
}
#powerVideo .videoAfter,
#powerVideo .videoBefore {
display: none;
}
#powerVideo .vis-timeline {
font-family: monospace;
border-radius: 5px;
border-color: #172b4d;
}
#powerVideo .vis-item {
border-color: #347af1;
background-color: #4d87d0;
color: #fff;
}
#powerVideo .vis-item.vis-selected {
border-color: #f5365c;
background-color: #f5365c;
color: #fff;
}
#powerVideo .vis-panel.vis-bottom {
border: 1px #17294b;
}
#powerVideo .vis-time-axis .vis-grid.vis-minor{
border-color: #1a539a;
}
#powerVideo .vis-time-axis .vis-grid.vis-major {
border-color: #4d87d0;
}
#powerVideo .vis-time-axis .vis-text {
color: #fff;
}
[timeline-video-file] .progress{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
opacity: 0;
}
.vis-selected [timeline-video-file] .progress{
opacity: 1;
}

View file

@ -6,3 +6,13 @@
#pvideo_viewer .bufferBar{position:absolute;left:0;top:0;opacity:0.4}
#pvideo_viewer .timeBar{position:relative;z-index: 222;background:transparent}
#pvideo_viewer h3{font-family:monospace}
#vis_pwrvideo{height:250px}
#vis_monitors{overflow:auto;max-height:400px}
#vis_monitors .btn-group-vertical{width:100%}
#motion_list{height:155px;overflow:auto;border-radius:5px;border:1px solid #444;position:relative;background: #222;margin:0}

View file

@ -3,3 +3,7 @@
#region_editor .cord_element{position:absolute;background:rgba(221, 221, 221, 0.8);z-index:11;padding:5px;}
#region_editor .cord_element.selected{z-index:12;}
#region_editor .cord_element .controls{margin-bottom:5px;}
#region_editor_live iframe,.canvas_holder canvas{border:0;position:absolute;left:0;top:0}

View file

@ -0,0 +1,34 @@
#accbtn{
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
padding: 0;
}
.side-menu .monitor_block{padding:0;position:relative}
.side-menu .monitor_block img{width:100%;height:75px;cursor:pointer;border: 0.5px inset #263238;}
@media screen and (max-width:1025px){
.side-menu .monitor_block img{height:175px;}
}
.side-menu .monitor_block:hover .icons{opacity:1}
.side-menu .monitor_block:hover .title{opacity:1}
.side-menu .monitor_block .icons,.side-menu .monitor_block .title{opacity:0;width:100%;bottom:0;left:0;background:rgba(0,0,0,0.6);position:absolute;padding:2.5px;z-index:11;cursor:move}
.side-menu .monitor_block .title{bottom:auto;top:0;color:#fff}
.nav-xs.side-menu .monitor_block{width:100%}
.side-menu .monitor_block .list-data{display:none}
.output_data:empty{display:none}
.output_data{max-height:500px;font-family:monospace;padding:10px;border-radius:5px;background:#f3f3f3;overflow:auto}
.dark .output_data{background:#222;}
#probe .output_data div>div{margin-left:10px}
.side-menu.list-blocks .monitor_block .icons,.side-menu.list-blocks .monitor_block .title{position:inherit;opacity:1;background:none}
.side-menu.list-blocks .monitor_block .title{padding:5px;border-radius:5px;background:#222;}
.side-menu.list-blocks .monitor_block:not(:last-child){border-bottom: 1px solid #54502d;}
.side-menu.list-blocks .monitor_block:first-child{border-top: 1px solid #54502d;}
.side-menu.list-blocks .monitor_block{float:none;width:100%;padding: 10px}
.side-menu.list-blocks .monitor_block.ui-sortable-helper{background:rgba(0,0,0,0.6);border-radius:5px;padding:5px;border:0}
.side-menu.list-blocks .monitor_block .list-data{display:block}
.side-menu.list-blocks .monitor_block img{width:60px;height:60px;cursor:pointer;display:inline-block;margin-right:10px;border-radius:50%;vertical-align:top;border:0}
.nav-xs.side-menu.list-blocks .monitor_block img{width:40px;height:40px;}
.side-menu.list-blocks .monitor_block .box{width:calc(100% - 70px);display:inline-block}
.nav-xs.side-menu.list-blocks .monitor_block .list-data{display:none}
.side-menu .mdl-menu{z-index: 12}

View file

@ -0,0 +1,110 @@
#timelapsejpeg .frames .frame{
height: 100px;
}
#timelapsejpeg .frames .frame img{
width: 100%;
height: 100%;
}
#timelapsejpeg .frameStrip img{
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
}
#timelapsejpeg .modal-body > .row,
#timelapsejpeg .modal-body > .row > div {
position:relative;
height: 100%;
}
#timelapsejpeg .frameIcons .frame{
border-radius: 15px;
overflow: hidden;
}
#timelapsejpeg .frameIcons .frame.selected{
border: 3px solid #ffc96b;
}
#timelapsejpeg .frameIcons > div:not(:last-child){
margin-bottom: 15px
}
#timelapsejpeg .frameIcons{
overflow-y: auto;
overflow-x: hidden;
}
#timelapsejpeg .frameIcons .frame{
background-size: cover;
width: 100%;
height: 100px;
position: relative;
cursor: pointer;
}
#timelapsejpeg .frameIcons .frame .shade{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 5px 10px;
font-family: monospace;
background: rgba(0,0,0,0.6);
color: #fff
}
#timelapsejpeg .playBackView{
position:absolute;
height: 50%;
width:100%;
top:0;
left:0;
background:#333;
}
#timelapsejpeg .playBackView img{
height:100%;
}
#timelapsejpeg .liveStreamView{
position:absolute;
text-align: center;
height: 50%;
width:100%;
top:50%;
left:0;
background:#333;
}
#timelapsejpeg .liveStreamView iframe{
width:100%;
height:100%;
display: inline-block;
margin: auto;
border: 0;
}
/* stand alone */
#timelapsejpeg.standalone {
background: #2f2f2f;
color:#fff;
}
#timelapsejpeg.standalone .fieldHolder{
padding-top: 20px;
}
.scroll-style-6::-webkit-scrollbar-track
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
background-color: #333;
border-radius: 15px;
}
.scroll-style-6::-webkit-scrollbar
{
width: 10px;
background-color: #333;
}
.scroll-style-6::-webkit-scrollbar-thumb
{
background-color: #555;
background-image: -webkit-linear-gradient(45deg,
rgba(255, 255, 255, .2) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, .2) 50%,
rgba(255, 255, 255, .2) 75%,
transparent 75%,
transparent)
}

View file

@ -1,400 +0,0 @@
#accbtn{
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
padding: 0;
}
#vis_pwrvideo{height:250px}
#monSectionStreamChannels,#monSectionInputMaps{margin-bottom: 15px;}
#monSectionStreamChannels:empty,#monSectionInputMaps:empty{display:none}
#region_editor_live iframe,.canvas_holder canvas{border:0;position:absolute;left:0;top:0}
.canvas_holder canvas{z-index:11}
.demo-blog .mdl-card__media ~ .mdl-card__supporting-text{position:relative;overflow:initial;cursor:move}
.demo-blog .mdl-card__media ~ .mdl-card__supporting-text .btn-group{cursor: default}
.demo-blog .demo-blog__posts.montage{max-width:100%}
.mdl-layout__drawer{overflow-y: visible!important}
.hide-side .mdl-layout__drawer{overflow-y: hidden}
.mdl-layout__header-row{padding-left:10!important}
.mdl-layout__header-row .nav>li>a{border-radius:50%;}
.mdl-layout__drawer-button i{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;height:1em;color:#fff}
.video_video{margin:auto;max-width:100%;max-height:600px;}
#confirm_window .video_video{margin-top:15px}
#confirm_window .info-table{margin-top:15px}
@media (max-width: 768px){
.full.modal .modal-body,.medium.modal .modal-body{max-height:400px;overflow:auto}
}
@media (min-width: 768px){
.modal.full,.modal.medium{padding-left:0!important;}
.modal.full .modal-dialog{width:calc(100% - 10px)!important;margin: 30px auto;}
.modal.medium .modal-dialog{width:calc(70% - 10px)!important;margin: 30px auto;}
.full.modal .modal-body,.medium.modal .modal-body{height:calc(100% - 200px);overflow:auto}
}
.flex-container-modal-body{overflow: auto}
.flex-container-modal-body .flex-block>div{flex:1;float:none}
.modal{overflow:auto!important}
.videos_list .title{font-size:12pt;padding:0 10px}
.demo-drawer{background:#2b2a2a;color:#fff;}
.demo-drawer.mdl-layout__drawer .mdl-navigation{padding-top:0;}
.demo-drawer::-webkit-scrollbar{display:none;}
.small-square-img{height:40px;width:40px;border-radius:5px}
.side-menu .monitor_block{padding:0;position:relative}
.side-menu .monitor_block img{width:100%;height:75px;cursor:pointer;border: 0.5px inset #263238;}
@media screen and (max-width:1025px){
.side-menu .monitor_block img{height:175px;}
}
.side-menu .monitor_block:hover .icons{opacity:1}
.side-menu .monitor_block:hover .title{opacity:1}
.side-menu .monitor_block .icons,.side-menu .monitor_block .title{opacity:0;width:100%;bottom:0;left:0;background:rgba(0,0,0,0.6);position:absolute;padding:2.5px;z-index:11;cursor:move}
.side-menu .monitor_block .title{bottom:auto;top:0;color:#fff}
.nav-xs.side-menu .monitor_block{width:100%}
.side-menu .monitor_block .list-data{display:none}
.output_data:empty{display:none}
.output_data{max-height:500px;font-family:monospace;padding:10px;border-radius:5px;background:#f3f3f3;overflow:auto}
.dark .output_data{background:#222;}
#probe .output_data div>div{margin-left:10px}
.side-menu.list-blocks .monitor_block .icons,.side-menu.list-blocks .monitor_block .title{position:inherit;opacity:1;background:none}
.side-menu.list-blocks .monitor_block .title{padding:5px;border-radius:5px;background:#222;}
.side-menu.list-blocks .monitor_block:not(:last-child){border-bottom: 1px solid #54502d;}
.side-menu.list-blocks .monitor_block:first-child{border-top: 1px solid #54502d;}
.side-menu.list-blocks .monitor_block{float:none;width:100%;padding: 10px}
.side-menu.list-blocks .monitor_block.ui-sortable-helper{background:rgba(0,0,0,0.6);border-radius:5px;padding:5px;border:0}
.side-menu.list-blocks .monitor_block .list-data{display:block}
.side-menu.list-blocks .monitor_block img{width:60px;height:60px;cursor:pointer;display:inline-block;margin-right:10px;border-radius:50%;vertical-align:top;border:0}
.nav-xs.side-menu.list-blocks .monitor_block img{width:40px;height:40px;}
.side-menu.list-blocks .monitor_block .box{width:calc(100% - 70px);display:inline-block}
.nav-xs.side-menu.list-blocks .monitor_block .list-data{display:none}
.side-menu .mdl-menu{z-index: 12}
#monitors_list .monitor_block{transition:none}
.dropdown-menu.scrollable{max-height:300px}
.upload_file input{display:none}
#video_preview .stream-objects{right:0;margin:auto;display:inline-block;position:relative;width:auto}
.stream-block,.stream-objects{overflow: hidden!important}
.stream-objects{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}
.stream-objects .tag{position:absolute;bottom:100%;left:0;background:red;color:#fff;font-family:monospace;font-size:80%;border-radius:5px 5px 0 0 ;padding:3px 5px;}
.stream-objects .stream-detected-object{position:absolute;top:0;left:0;border:3px solid red;background:transparent;border-radius:5px}
.stream-objects .stream-detected-point{position:absolute;top:0;left:0;border:3px solid yellow;background:transparent;border-radius:5px}
.stream-objects .point{position:absolute;top:0;left:0;border:3px solid red;border-radius:50%}
#side_menu_right.nav-xs{width:0!important;overflow:hidden}
.side-menu table{color:#fff;}
#main_canvas{background:#333;color:#fff;padding-top:0}
#main_header{background:#222;color:#fff;}
#logs_modal table tr td:first-child{width:10%}
[class_toggle]{cursor:pointer}
.form-group label{width:100%}
#vis_monitors{overflow:auto;max-height:400px}
#vis_monitors .btn-group-vertical{width:100%}
.table-striped>tbody>tr>td{vertical-align:middle}
.table-striped .thumbnail{width:100px;height:80px;border-radius:5px;margin:0;display:inline-block;}
#motion_list{height:155px;overflow:auto;border-radius:5px;border:1px solid #444;position:relative;background: #222;margin:0}
.dark .list-group-item{border-color: #444;background:#222}
.dark .list-group-item.active{background:#c49a68;border-color:#a7865f}
.novideos{text-transform: uppercase;text-align: center;border-bottom:0!important;padding-top: 55%!important;letter-spacing:2px}
.btn-warning {
color: #fff;
background-color: #c49a68;
border-color: #c49a68;
}
.dark .table-striped>tbody>tr:nth-of-type(even){background:#616161}
.dark .table-striped>tbody>tr>td{border-color:#222;color:#fff}
.dark .table-striped>thead>tr>th{border-color:#222;color:#fff;background:#616161;vertical-align:middle;}
.dark .table-striped>tbody>tr:nth-of-type(odd){background-color: #4c4747;}
.dark .table>tbody>tr.active>td{background:inherit;border:0}
.dark code{color: #c49a68;background-color: #36333d;}
.dark a:not(.btn){color: #c49a68;}
.follow-list ul{padding:0;margin:0;font-family:"Roboto","Helvetica","Arial",sans-serif;}
.follow-list ul a:not(.btn){color:#fff}
.os_bars{width:600px;display:inline-block;padding:5px 0 0 10px}
@media screen and (max-width: 600px){
.os_bars{width:200px;}
.os_bars label{padding:2.5px 0;margin:0;font-size:8pt}
}
.os_bars .display-table .display-table-cell{padding:5px;vertical-align:center;width:33%}
.progress{height:5px;margin:0;}
.os_bars label,.os_bars .percent{padding:2.5px 0;margin:0;font-size:7.5pt}
.ui-pnotify-hide .ui-pnotify{display:none!important}
/*cool dropdown thing*/
ul.msg_list li {
background: #f7f7f7;color:#333;
padding: 5px;
display: list-item;
margin: 6px 6px 0;
width: 96% !important
}
ul.msg_list li div{display:block}
ul.msg_list li:last-child {
margin-bottom: 6px;
padding: 10px
}
ul.msg_list li a {
padding: 3px 5px !important
}
ul.msg_list li .progress {
height:5px;margin:10px 0 0 0;
}
ul.msg_list li .image img {
border-radius: 2px 2px 2px 2px;
-webkit-border-radius: 2px 2px 2px 2px;
float: left;
margin-right: 10px;
width: 11%
}
ul.msg_list li .time {
font-size: 11px;
font-style: italic;
font-weight: bold;
position: absolute;
}
ul.msg_list li .message {
display: block !important;
font-size: 11px
}
.dropdown-menu.msg_list span {
white-space: normal
}
.dropdown-menu {
border: medium none;
box-shadow: none;
display: none;
float: left;
font-size: 12px;
left: 0;
list-style: none outside none;
padding: 0;
position: absolute;
text-shadow: none;
top: 100%;
z-index: 9998;
border: 1px solid #D9DEE4;
border-top-left-radius: 0;
border-top-right-radius: 0
}
.dropdown-menu>li>a {
color: #5A738E
}
.navbar-nav .open .dropdown-menu {
position: absolute;
background: #fff;
margin-top: 0;
border: 1px solid #D9DEE4;
-webkit-box-shadow: none;
right: 0;
left: auto;
width: 220px
}
.is-small-screen .nav>li{display:inline-block}
.navbar-nav .open .dropdown-menu li a{padding:7px 15px}
.navbar-nav .open .dropdown-menu.msg_list {
width: 300px
}
.nav>li>a{color:#fff}
.nav>li>a:focus, .nav>li>a:hover,.nav .open>a, .nav .open>a:focus, .nav .open>a:hover{background:#867560}
.mdl-js-layout.hide-side:not(.is-small-screen){
}
@media screen and (min-width: 1025px){
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__drawer {
width: 0px;transition:0.2s
}
}
.mdl-js-layout.hide-side:not(.is-small-screen) .mdl-layout__header .mdl-layout__drawer-button{
display:none;
}
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__content{
margin-left: 0px;transition:0.2s
}
.mdl-js-layout.hide-side:not(.is-small-screen)>.mdl-layout__header{
margin-left: 0px;width:100%;transition:0.2s
}
.mdl-menu__item>div{display:flex;align-items: center;width:100%}
.mdl-menu__item>div>i{margin-right:5px}
/*Digital Zoom*/
.stream-block{
position: relative;
overflow: auto;
}
.zoomGlass {
overflow: hidden;
transition: none;
width: 175px; height: 175px;
position: absolute;
border-radius: 15px;
border: 3px solid #ddd;
z-index:9999;
}
.zoomGlass iframe,.zoomGlass canvas{position:absolute;transition: none;}
.zoomGlass .hoverShade{position:absolute;width:100%;height:100%}
.dark.form-control,.dark .form-control {
display: block;
width: 100%;
height: 35px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.5;
color: #eee;
background-color: #36333d;
background-image: none;
border: 1px solid #444;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.dark.form-control:focus,.dark .form-control:focus {
color: #ddd;
background-color: #333;
box-shadow: none;
}
/*** custom checkboxes ***/
.checkbox input[type=checkbox] { display:none; } /* to hide the checkbox itself */
.checkbox input[type=checkbox] + label:before {
font-family: FontAwesome;
display: inline-block;
}
.checkbox input[type=checkbox] + label:before { content: "\f096"; } /* unchecked icon */
.checkbox input[type=checkbox] + label:before { letter-spacing: 10px; } /* space between checkbox and label */
.checkbox input[type=checkbox]:checked + label:before { content: "\f046"; } /* checked icon */
.checkbox input[type=checkbox]:checked + label:before { letter-spacing: 5px; } /* allow space for check mark */
/*Clock*/
#time-date {font-size:12px; text-align:center;}
@media screen and (min-width:1025px){
#clock {padding-right:35px}
}
#clock ul { width:150px; margin:0 auto; padding:0px; list-style:none; text-align:center; }
#clock ul li { display:inline; font-size:1.6em; text-align:center;font-family:monospace;}
#clock .point { position:relative; -moz-animation:mymove 1s ease infinite; -webkit-animation:mymove 1s ease infinite; }
/*custom vis.js css*/
.vis-timeline{background:#212121;color:#fff;border-color:#444}
.vis-time-axis .vis-text{color: #dedede}
.vis-item.vis-range .vis-item-content{background:#333;color:#fff}
.vis-time-axis .vis-grid.vis-minor{border-color:#444}
@-moz-document url-prefix() {
.full.modal .modal-body, .medium.modal .modal-body {
height:70%
}
}
/*animations*/
@keyframes blink {
0% { opacity:1 }
50% { opacity:0 }
100% { opacity:1 }
}
@-webkit-keyframes blink {
0% { opacity:1 }
50% { opacity:0 }
100% { opacity:1 }
}
.blink,[mode="Record"] .lamp {
-webkit-animation: blink 1s linear infinite;
-moz-animation: blink 1s linear infinite;
animation: blink 1s linear infinite;
}
/* All-CSS Toggle Switch (Checkbox Hack) by Marcus Burnette - https://codepen.io/mburnette/pen/LxNxNg */
.marc-toggle {
width: 50px;
height: 25px;
}
.marc-toggle.abs-bot-left {
position: absolute;
bottom: 10px;
left: 10px;
}
.marc-toggle.abs-bot-right {
position: absolute;
bottom: 10px;
right: 10px;
}
.marc-toggle input[type=checkbox]{
height: 0;
width: 0;
visibility: hidden;
}
.marc-toggle label {
cursor: pointer;
text-indent: -9999px;
width: 100px;
height: 20px;
background: grey;
display: block;
border-radius: 100px;
margin-bottom: 0;
position: relative;
}
.marc-toggle label:after {
content: '';
position: absolute;
top: 5px;
left: 5px;
width: 10px;
height: 10px;
background: #fff;
border-radius: 90px;
transition: 0.3s;
}
.marc-toggle input:checked + label {
background: #00118c;
}
.marc-toggle input:checked + label:after {
left: calc(100% - 5px);
transform: translateX(-100%);
}
.marc-toggle label:active:after {
width: 10px;
}
/*hexagon pattern*/
.bg-hexagon {
background-color: #054e9f;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%23fdfdfd' fill-opacity='0.4' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}

1
web/libs/css/vis.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 223 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Before After
Before After

5
web/libs/js/bootstrap-slider.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
$(document).ready(function() {
var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
var dayNames= ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
var monthNames = [ lang.January, lang.February, lang.March, lang.April, lang.May, lang.June, lang.July, lang.August, lang.September, lang.October, lang.November, lang.December ];
var dayNames= [lang.Sunday, lang.Monday, lang.Tuesday, lang.Wednesday, lang.Thursday, lang.Friday, lang.Saturday]
var newDate = new Date();
newDate.setDate(newDate.getDate());

View file

@ -12,6 +12,16 @@ $.ccio.permissionCheck = function(toCheck,monitorId){
}
return false
}
$.parseJSON = function(string){
var parsed
try{
parsed = JSON.parse(string)
}catch(err){
}
if(!parsed)parsed = string
return parsed
}
$.ccio.op = function(r,rr,rrr){
if(!rrr){rrr={};};if(typeof rrr === 'string'){rrr={n:rrr}};if(!rrr.n){rrr.n='ShinobiOptions_'+location.host}
ii={o:localStorage.getItem(rrr.n)};try{ii.o=JSON.parse(ii.o)}catch(e){ii.o={}}
@ -113,25 +123,27 @@ $.ccio.base64ArrayBuffer = function(arrayBuffer) {
return base64
}
$.ccio.snapshot=function(e,cb){
var image_data,url;
e.details=JSON.parse(e.mon.details);
$.ccio.snapshot = function(options,cb){
var image_data
var url
var monitor = options.mon || options.monitor || options
var details = $.parseJSON(monitor.details)
if($.ccio.op().jpeg_on!==true){
var extend=function(image_data,width,height){
var len = image_data.length
var arraybuffer = new Uint8Array( len );
var arraybuffer = new Uint8Array( len )
for (var i = 0; i < len; i++) {
arraybuffer[i] = image_data.charCodeAt(i);
arraybuffer[i] = image_data.charCodeAt(i)
}
try {
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'})
} catch (e) {
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder)
bb.append(arraybuffer);
var blob = bb.getBlob('application/octet-stream');
}
url = (window.URL || window.webkitURL).createObjectURL(blob);
finish(url,image_data,width,height);
url = (window.URL || window.webkitURL).createObjectURL(blob)
finish(url,image_data,width,height)
try{
setTimeout(function(){
URL.revokeObjectURL(url)
@ -139,142 +151,191 @@ $.ccio.snapshot=function(e,cb){
}catch(er){}
}
var finish = function(url,image_data,width,height){
cb(url,image_data,width,height);
cb(url,image_data,width,height)
}
switch(JSON.parse(e.mon.details).stream_type){
switch(details.stream_type){
case'hls':case'flv':case'mp4':
$.ccio.snapshotVideo($('[mid='+e.mon.mid+'].monitor_item video')[0],function(base64,video_data,width,height){
$.ccio.snapshotVideo($('[mid='+monitor.mid+'][ke='+monitor.ke+'][auth='+monitor.user.auth_token+'].monitor_item video')[0],function(base64,video_data,width,height){
extend(video_data,width,height)
})
break;
case'mjpeg':
$('#temp').html('<canvas></canvas>')
var c = $('#temp canvas')[0];
var img = $('img',$('[mid='+e.mon.mid+'].monitor_item .stream-element').contents())[0];
c.width = img.width;
c.height = img.height;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0,c.width,c.height);
var c = $('#temp canvas')[0]
var img = $('img',$('[mid='+monitor.mid+'][ke='+monitor.ke+'][auth='+monitor.user.auth_token+'].monitor_item .stream-element').contents())[0]
c.width = img.width
c.height = img.height
var ctx = c.getContext('2d')
ctx.drawImage(img, 0, 0,c.width,c.height)
extend(atob(c.toDataURL('image/jpeg').split(',')[1]),c.width,c.height)
break;
case'h265':
var c = $('[mid='+e.mon.mid+'].monitor_item canvas')[0];
var ctx = c.getContext('2d');
var c = $('[mid='+monitor.mid+'][ke='+monitor.ke+'][auth='+monitor.user.auth_token+'].monitor_item canvas')[0]
var ctx = c.getContext('2d')
extend(atob(c.toDataURL('image/jpeg').split(',')[1]),c.width,c.height)
break;
case'b64':
base64 = e.mon.last_frame.split(',')[1];
var image_data = new Image();
image_data.src = base64;
base64 = monitor.last_frame.split(',')[1]
var image_data = new Image()
image_data.src = base64
extend(atob(base64),image_data.width,image_data.height)
break;
case'jpeg':case'h265':
url=e.p.find('.stream-element').attr('src');
image_data = new Image();
image_data.src = url;
finish(url,image_data,image_data.width,image_data.height);
case'jpeg':
url=e.p.find('.stream-element').attr('src')
image_data = new Image()
image_data.src = url
finish(url,image_data,image_data.width,image_data.height)
break;
}
}else{
url=e.p.find('.stream-element').attr('src');
image_data = new Image();
image_data.src = url;
cb(url,image_data,image_data.width,image_data.height);
url = e.p.find('.stream-element').attr('src')
image_data = new Image()
image_data.src = url
cb(url,image_data,image_data.width,image_data.height)
}
}
$.ccio.snapshotVideo=function(videoElement,cb){
var image_data;
$.ccio.snapshotVideo = function(videoElement,cb){
var image_data
var base64
$('#temp').html('<canvas></canvas>')
var c = $('#temp canvas')[0];
var img = videoElement;
c.width = img.videoWidth;
c.height = img.videoHeight;
var ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0,c.width,c.height);
var c = $('#temp canvas')[0]
var img = videoElement
c.width = img.videoWidth
c.height = img.videoHeight
var ctx = c.getContext('2d')
ctx.drawImage(img, 0, 0,c.width,c.height)
base64=c.toDataURL('image/jpeg')
image_data=atob(base64.split(',')[1]);
var arraybuffer = new ArrayBuffer(image_data.length);
var view = new Uint8Array(arraybuffer);
image_data=atob(base64.split(',')[1])
var arraybuffer = new ArrayBuffer(image_data.length)
var view = new Uint8Array(arraybuffer)
for (var i=0; i<image_data.length; i++) {
view[i] = image_data.charCodeAt(i) & 0xff;
view[i] = image_data.charCodeAt(i) & 0xff
}
try {
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'})
} catch (e) {
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
bb.append(arraybuffer);
var blob = bb.getBlob('application/octet-stream');
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder)
bb.append(arraybuffer)
var blob = bb.getBlob('application/octet-stream')
}
cb(base64,image_data,c.width,c.height);
cb(base64,image_data,c.width,c.height)
}
$.ccio.magnifyStream = function(e){
if(!e.p){
e.e=$(this),
e.p=e.e.parents('[mid]')
$.ccio.magnifyStream = function(options,user){
if(!user)user = $user
if(!options.p && !options.parent){
var el = $(this),
parent = el.parents('[mid]')
}else{
parent = options.p || options.parent
}
if(e.animate === true){
if(!options.attribute){
options.attribute = ''
}
if(options.animate === true){
var zoomGlassAnimate = 'animate'
}else{
var zoomGlassAnimate = 'css'
}
if(e.auto === true){
if(!options.magnifyOffsetElement){
options.magnifyOffsetElement = '.stream-block'
}
if(!options.targetForZoom){
options.targetForZoom = '.stream-element'
}
if(options.auto === true){
var streamBlockOperator = 'position'
}else{
var streamBlockOperator = 'offset'
}
if(e.useCanvas === true){
var magnifiedElement = 'canvas'
var magnifiedElement
if(!options.videoUrl){
if(options.useCanvas === true){
magnifiedElement = 'canvas'
}else{
magnifiedElement = 'iframe'
}
}else{
var magnifiedElement = 'iframe'
magnifiedElement = 'video'
}
e.ke=e.p.attr('ke'),//group key
e.mid=e.p.attr('mid'),//monitor id
e.auth=e.p.attr('auth'),//authkey
e.mon=$.ccio.mon[e.ke+e.mid+e.auth]//monitor configuration
if(e.zoomAmount)e.mon.zoomAmount=3;
if(!e.mon.zoomAmount)e.mon.zoomAmount=3;
e.height=parseFloat(e.p.attr('realHeight')) * e.mon.zoomAmount//height of stream
e.width=parseFloat(e.p.attr('realWidth')) * e.mon.zoomAmount;//width of stream
var targetForZoom = e.p.find('.stream-element');
zoomGlass = e.p.find(".zoomGlass");
if(!options.mon && !options.monitor){
var groupKey = parent.attr('ke')//group key
var monitorId = parent.attr('mid')//monitor id
var sessionKey = parent.attr('auth')//authkey
var monitor = $.ccio.mon[groupKey + monitorId + sessionKey]//monitor configuration
}else{
var monitor = options.mon || options.monitor
var groupKey = monitor.ke//group key
var monitorId = monitor.mid//monitor id
var sessionKey = monitor.auth//authkey
}
if(options.zoomAmount)zoomAmount = 3
if(!zoomAmount)zoomAmount = 3
var realHeight = parent.attr('realHeight')
var realWidth = parent.attr('realWidth')
var height = parseFloat(realHeight) * zoomAmount//height of stream
var width = parseFloat(realWidth) * zoomAmount//width of stream
var targetForZoom = parent.find(options.targetForZoom)
zoomGlass = parent.find(".zoomGlass")
var zoomFrame = function(){
var magnify_offset = e.p.find('.stream-block')[streamBlockOperator]();
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
var rx = Math.round(mx/targetForZoom.width()*e.width - zoomGlass.width()/2)*-1;
var ry = Math.round(my/targetForZoom.height()*e.height - zoomGlass.height()/2)*-1;
var px = mx - zoomGlass.width()/2;
var py = my - zoomGlass.height()/2;
zoomGlass[zoomGlassAnimate]({left: px, top: py}).find(magnifiedElement)[zoomGlassAnimate]({left: rx, top: ry});
var magnify_offset = parent.find(options.magnifyOffsetElement)[streamBlockOperator]()
var mx = options.pageX - magnify_offset.left
var my = options.pageY - magnify_offset.top
var rx = Math.round(mx/targetForZoom.width()*width - zoomGlass.width()/2)*-1
var ry = Math.round(my/targetForZoom.height()*height - zoomGlass.height()/2)*-1
var px = mx - zoomGlass.width()/2
var py = my - zoomGlass.height()/2
zoomGlass[zoomGlassAnimate]({left: px, top: py}).find(magnifiedElement)[zoomGlassAnimate]({left: rx, top: ry})
}
if(!e.height||!e.width||zoomGlass.length===0){
$.ccio.snapshot(e,function(url,buffer,width,height){
e.width = width * e.mon.zoomAmount;
e.height = height * e.mon.zoomAmount;
e.p.attr('realWidth',width)
e.p.attr('realHeight',height)
zoomGlass = e.p.find(".zoomGlass");
if(zoomGlass.length===0){
if(e.useCanvas === true){
e.p.append('<div class="zoomGlass"><canvas class="blenderCanvas"></canvas></div>');
}else{
e.p.append('<div class="zoomGlass"><iframe src="'+e.auth+'/embed/'+e.ke+'/'+e.mid+'/fullscreen|jquery|relative"/><div class="hoverShade"></div></div>');
}
zoomGlass = e.p.find(".zoomGlass");
}
zoomGlass.find(magnifiedElement).css({height:e.height,width:e.width});
zoomFrame()
var commit = function(height,width){
zoomGlass.find(magnifiedElement).css({
height: height,
width: width
})
}else{
zoomGlass.find(magnifiedElement).css({height:e.height,width:e.width});
zoomFrame()
}
if(!height || !width || zoomGlass.length === 0){
zoomGlass = parent.find(".zoomGlass")
var zoomGlassShell = function(contents){return `<div ${options.attribute} class="zoomGlass">${contents}</div>`}
if(!options.videoUrl){
$.ccio.snapshot(monitor,function(url,buffer,w,h){
parent.attr('realWidth',w)
parent.attr('realHeight',h)
if(zoomGlass.length === 0){
if(options.useCanvas === true){
parent.append(zoomGlassShell('<canvas class="blenderCanvas"></canvas>'))
}else{
parent.append(zoomGlassShell('<iframe src="'+$.ccio.init('location',user)+sessionKey+'/embed/'+groupKey+'/'+monitorId+'/fullscreen|jquery|relative"/><div class="hoverShade"></div>'))
}
zoomGlass = parent.find(".zoomGlass")
}
commit(h,w)
})
}else{
if(zoomGlass.length === 0){
parent.append(zoomGlassShell(`<video src="${options.videoUrl}" preload></video>`))
}
if(options.setTime){
var video = zoomGlass.find('video')[0]
video.currentTime = options.setTime
height = video.videoHeight
width = video.videoWidth
parent.attr('realWidth',width)
parent.attr('realHeight',height)
}
commit(height,width)
}
}else{
if(options.setTime){
var video = zoomGlass.find('video')
var src = video.attr('src')
video[0].currentTime = options.setTime
if(options.videoUrl !== src)zoomGlass.html(`<video src="${options.videoUrl}" preload></video>`)
}
commit(height,width)
}
}
$.ccio.destroyStream = function(d,user,killElement){
if(d.mid && !d.id)d.id = d.mid
console.log(d.ke+d.id+user.auth_token)
console.log($.ccio.mon[d.ke+d.id+user.auth_token])
if($.ccio.mon[d.ke+d.id+user.auth_token]){
console.log('destroy')
$.ccio.init('closeVideo',{mid:d.id,ke:d.ke},user);
@ -297,3 +358,59 @@ $.ccio.destroyStream = function(d,user,killElement){
}
}
}
$(document).ready(function(){
$('body')
.on('click', '.table-header-sorter', function () {
var $sort = jQuery(this).find('i');
var currentSort = undefined;
if ($sort.hasClass('fa-sort-asc')) {
currentSort = 'asc';
} else if ($sort.hasClass('fa-sort-desc')) {
currentSort = 'desc';
}
jQuery(this)
.parent()
.find('i.fa')
.removeClass('fa-sort-asc')
.removeClass('fa-sort-desc')
.addClass('fa-sort');
jQuery(this)
.find('i.fa')
.toggleClass('fa-sort', currentSort === 'desc')
.toggleClass('fa-sort-asc', currentSort === undefined)
.toggleClass('fa-sort-desc', currentSort === 'asc');
const field = jQuery(this).data('field');
const $body = jQuery(this)
.closest('.table')
.find('tbody');
const sortedRows = $body
.find('tr')
.detach()
.sort(function(a,b) {
const data1 = jQuery(a).data('sort');
const data2 = jQuery(b).data('sort');
if (currentSort === undefined)
return data1[field] > data2[field] ? 1 : data1[field] < data2[field] ? -1 : 0;
else if (currentSort === 'asc')
return data1[field] > data2[field] ? -1 : data1[field] < data2[field] ? 1 : 0;
else
return data1._no > data2._no ? 1 : data1._no < data2._no ? -1 : 0;
});
$body.append(sortedRows);
})
.on('click','[tab-chooser]',function(){
var el = $(this)
var parent = el.parents('[tab-chooser-parent]')
var tabName = el.attr('tab-chooser')
var allTabsInParent = parent.find('[tab-section]')
var allTabChoosersInParent = parent.find('[tab-chooser]')
allTabsInParent.hide()
allTabChoosersInParent.removeClass('active')
el.addClass('active')
parent.find(`[tab-section="${tabName}"]`).show()
})
})

View file

@ -3,8 +3,7 @@ $.ccio={
mon:{},
useUTC: <%- config.useUTC || false %>,
definitions: <%-JSON.stringify(define)%>,
libURL: '<%-window.libURL%>',
logMemory: []
libURL: '<%-window.libURL%>'
};
<% if(config.DropboxAppKey){ %>
$.ccio.DropboxAppKey = '<%-window.DropboxAppKey%>'
@ -118,7 +117,6 @@ $(document).ready(function(e){
}
})
}
//on window resize
document.addEventListener("fullscreenchange", onFullScreenChange, false);
document.addEventListener("webkitfullscreenchange", onFullScreenChange, false);
document.addEventListener("mozfullscreenchange", onFullScreenChange, false);

View file

@ -0,0 +1,36 @@
$(document).ready(function(){
$.confirm={e:$('#confirm_window')};
$.confirm.title=$.confirm.e.find('.modal-title span')
$.confirm.body=$.confirm.e.find('.modal-body')
$.confirm.footer=$.confirm.e.find('.modal-footer')
$.confirm.click=function(x,e){
$.confirm.footer.find('.confirmaction').remove()
var createButton = function(x,place,callback){
$.confirm.footer.prepend('<button type="button" class="btn '+x.class+' confirmaction confirmaction'+place+'">'+x.title+'</button>')
if(!x.class){x.class='btn-success'}
if(!x.title){x.title='Save changes'}
$.confirm.footer.find('.confirmaction'+place).click(function(){
$.confirm.e.modal('hide')
callback();
})
}
if(x instanceof Array){
$.each(x,function(place,x){
createButton(x,place,x.callback)
})
}else{
createButton(x,0,e)
}
}
$.confirm.create = function(options){
if(options.title && options.body){
$.confirm.e.modal('show')
$.confirm.title.text(options.title)
$.confirm.body.html(options.body)
}
if(options.clickOptions && options.clickCallback)$.confirm.click(options.clickOptions,options.clickCallback)
}
$.confirm.e.on('hidden.bs.modal', function () {
$.confirm.footer.find('.confirmaction').remove()
})
})

View file

@ -0,0 +1,129 @@
$(document).ready(function(){
var downloadFile = function(remoteLink,onProgress,onSuccess){
if(!onProgress)onProgress = function(){}
if(!onSuccess)onSuccess = function(){}
var xhr = new window.XMLHttpRequest();
xhr.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = (evt.loaded / evt.total * 100).toFixed(2);
onProgress(percentComplete)
}
}, false)
xhr.addEventListener('readystatechange', function(e) {
if(xhr.readyState == 2 && xhr.status == 200) {
// Download is being started
}
else if(xhr.readyState == 3) {
// Download is under progress
}
else if(xhr.readyState == 4) {
onSuccess(xhr.response)
// Downloaing has finished
// request.response holds the file data
}
})
xhr.responseType = 'blob'
// Downloading a JPEG file
xhr.open('get', remoteLink)
xhr.send()
}
var downloadBulkVideos = function(videos,onProgress,onSuccess){
var fileBuffers = {}
var numberOfCompletedDownloads = 0
var getVideo = function(video){
var url = video.href
downloadFile(url,function(percent){
if(onProgress)onProgress(video,percent)
},function(buffer){
++numberOfCompletedDownloads
fileBuffers[url] = Object.assign(video,{buffer: buffer})
console.log(fileBuffers[url] )
console.log(videos.length, numberOfCompletedDownloads)
if(videos.length === numberOfCompletedDownloads){
if(onSuccess)onSuccess(fileBuffers)
}else{
getVideo(videos[numberOfCompletedDownloads])
}
})
}
getVideo(videos[numberOfCompletedDownloads])
}
var saveFile = function(blob, filename) {
console.log(blob,filename)
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, filename);
} else {
const a = document.createElement('a');
document.body.appendChild(a);
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 0)
}
}
var zipVideosAndDownload = function(videos,onSuccess){
var zip = new JSZip();
var zipFileName = `ShinobiVideos_${$.ccio.timeObject(new Date()).format('YYYY-MM-DDTHH-mm-ss')}.zip`
var foldersCreated = {}
var downloadBars = {}
var progressBarHtml = []
var videosCopy = Object.assign(videos,{})
$.each(videosCopy,function(n,video){
var fileZipName = `${$.ccio.timeObject(video.time).format('YYYY-MM-DDTHH-mm-ss')}.${video.ext}`
var fileId = video.ke + video.mid + moment(video.time).format('YYYY-MM-DDTHH-mm-ss')
video.fileId = fileId
video.fileZipName = fileZipName
if(!foldersCreated[video.ke]){
foldersCreated[video.ke] = {}
foldersCreated[video.ke]._zipFolder = zip.folder(video.ke)
}
if(!foldersCreated[video.ke][video.mid]){
foldersCreated[video.ke][video.mid] = {}
foldersCreated[video.ke][video.mid]._zipFolder = foldersCreated[video.ke]._zipFolder.folder(video.mid)
}
progressBarHtml.push(`<br><small></small><div id="download-${fileId}" class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div></div>`)
})
new PNotify({
type:'notice',
title: lang['Downloading Videos'],
text: lang['Please Wait for Completion'] + progressBarHtml.join(''),
hide: false,
modules: {
Buttons: {
closer: true,
sticker: false
},
Mobile: {
swipeDismiss: false
}
},
})
$.each(videosCopy,function(n,video){
downloadBars[video.fileId] = $(`#download-${video.fileId} .progress-bar`)
})
downloadBulkVideos(videosCopy,function(video,percent){
downloadBars[video.fileId].width(percent + '%').attr('aria-valuenow', percent)
},function(videosWithBuffers){
new PNotify({
type:'success',
title: lang['Zipping Videos'],
text: lang['Please Wait for Completion']
})
$.each(videosWithBuffers,function(n,video){
foldersCreated[video.ke][video.mid]._zipFolder.file(video.fileZipName, video.buffer)
})
zip.generateAsync({type:"blob"}).then(function(content) {
saveFile(content, zipFileName)
if(onSuccess)onSuccess(content)
});
})
}
$.zipVideosAndDownload = zipVideosAndDownload
})

View file

@ -20,8 +20,13 @@ $.ccio.tm=function(x,d,z,user){
d.per=parseInt(d.hr/24*100);
d.circle='<div title="at '+d.hr+' hours of '+d.startMoment.format('MMMM DD')+'" '+href+' video="launch" class="progress-circle progress-'+d.per+'"><span>'+d.hr+'</span></div>'
tmp+='<li class="video-item glM'+d.mid+user.auth_token+'" auth="'+user.auth_token+'" mid="'+d.mid+'" ke="'+d.ke+'" status="'+d.status+'" status="'+d.status+'" file="'+d.filename+'">'+d.circle+'<div><span title="'+d.endMoment.format()+'" class="livestamp"></span></div><div><div class="small"><b>'+lang.Start+'</b> : '+d.startMoment.format('h:mm:ss , MMMM Do YYYY')+'</div><div class="small"><b>'+lang.End+'</b> : '+d.endMoment.format('h:mm:ss , MMMM Do YYYY')+'</div></div><div><span class="pull-right">'+(parseInt(d.size)/1000000).toFixed(2)+'mb</span><div class="controls btn-group"><a class="btn btn-sm btn-primary" video="launch" '+href+'><i class="fa fa-play-circle"></i></a> <a download="'+d.dlname+'" '+href+' class="btn btn-sm btn-default"><i class="fa fa-download"></i></a>'
if($.ccio.DropboxAppKey){ tmp+='<a video="download" host="dropbox" download="'+d.dlname+'" '+href+' class="btn btn-sm btn-default"><i class="fa fa-dropbox"></i></a>' }
tmp+='<a title="'+lang['Delete Video']+'" video="delete" href="'+$.ccio.init('videoHrefToDelete',url)+'" class="btn btn-sm btn-danger permission_video_delete"><i class="fa fa-trash"></i></a></div></div></li>';
if($.ccio.DropboxAppKey){
tmp+='<a video="download" host="dropbox" download="'+d.dlname+'" '+href+' class="btn btn-sm btn-default"><i class="fa fa-dropbox"></i></a>'
}
if($.ccio.permissionCheck('video_delete',d.mid)){
tmp += '<a title="'+lang['Delete Video']+'" video="delete" href="'+$.ccio.init('videoHrefToDelete',url)+'" class="btn btn-sm btn-danger"><i class="fa fa-trash"></i></a>'
}
tmp += '</div></div></li>';
$(z).each(function(n,v){
v=$(v);
if(v.find('.video-item').length>10){v.find('.video-item:last').remove()}
@ -33,25 +38,25 @@ $.ccio.tm=function(x,d,z,user){
tmp+='<div class="btn-group btn-group-xs">'
var buttons = {
"Pop": {
"label": "Pop",
"label": lang['Pop'],
"attr": "monitor=\"pop\"",
"class": "default",
"icon": "external-link"
},
"Power Viewer": {
"label": "Power Viewer",
"attr": "monitor=\"powerview\"",
"class": "default",
"icon": "map-marker"
},
// "Power Viewer": {
// "label": lang['Power Viewer'],
// "attr": "monitor=\"powerview\"",
// "class": "default",
// "icon": "map-marker"
// },
"Videos List": {
"label": "Videos List",
"label": lang['Videos List'],
"attr": "monitor=\"videos_table\"",
"class": "default",
"icon": "film"
},
"Monitor Settings": {
"label": "Monitor Settings",
"label": lang['Monitor Settings'],
"attr": "monitor=\"edit\"",
"class": "default",
"icon": "wrench"
@ -89,50 +94,56 @@ $.ccio.tm=function(x,d,z,user){
tmp+='<div class="btn-group btn-group-sm">'//start of btn list
var buttons = {
"Snapshot": {
"label": "Snapshot",
"label": lang['Snapshot'],
"attr": "monitor=\"snapshot\"",
"class": "primary",
"icon": "camera"
},
"Show Logs": {
"label": "Show Logs",
"label": lang['Show Logs'],
"attr": "monitor=\"show_data\"",
"class": "warning",
"icon": "exclamation-triangle"
},
"Control": {
"label": "Control",
"label": lang['Control'],
"attr": "monitor=\"control_toggle\"",
"class": "default arrows",
"icon": "arrows"
},
"Status Indicator": {
"label": "Status Indicator",
"Reconnect Stream": {
"label": lang['Reconnect Stream'],
"attr": "monitor=\"watch_on\"",
"class": "success signal",
"icon": "plug"
},
"Pop": {
"label": "Pop",
"label": lang['Pop'],
"attr": "monitor=\"pop\"",
"class": "default",
"icon": "external-link"
},
"Pop": {
"label": lang['Zoom In'],
"attr": "monitor=\"zoomStreamWithMouse\"",
"class": "default",
"icon": "search-plus"
},
"Calendar": {
"label": "Calendar",
"label": lang['Calendar'],
"attr": "monitor=\"calendar\"",
"class": "default ",
"icon": "calendar"
},
"Power Viewer": {
"label": "Power Viewer",
"attr": "monitor=\"powerview\"",
"class": "default",
"icon": "map-marker"
},
// "Power Viewer": {
// "label": lang['Power Viewer'],
// "attr": "monitor=\"powerview\"",
// "class": "default",
// "icon": "map-marker"
// },
"Time-lapse": {
"label": "Time-lapse",
"attr": "monitor=\"timelapse\"",
"label": lang['Time-lapse'],
"attr": "monitor=\"timelapseJpeg\"",
"class": "default",
"icon": "angle-double-right"
},
@ -143,25 +154,25 @@ $.ccio.tm=function(x,d,z,user){
"icon": "th"
},
"Videos List": {
"label": "Videos List",
"label": lang['Videos List'],
"attr": "monitor=\"videos_table\"",
"class": "default",
"icon": "film"
},
"Monitor Settings": {
"label": "Monitor Settings",
"label": lang['Monitor Settings'],
"attr": "monitor=\"edit\"",
"class": "default",
"icon": "wrench"
},
"Fullscreen": {
"label": "Fullscreen",
"label": lang['Fullscreen'],
"attr": "monitor=\"fullscreen\"",
"class": "default",
"icon": "arrows-alt"
},
"Close": {
"label": "Close",
"label": lang['Close'],
"attr": "monitor=\"watch_off\"",
"class": "danger",
"icon": "times"

View file

@ -75,7 +75,7 @@ $(document).ready(function(e){
$.logWriter.floodTimeout = setTimeout(function(){
delete($.logWriter.floodTimeout)
$.logWriter.floodCounter = 0
},1000)
},2000)
$.ccio.tm(4,d,'#logs,'+id+'.monitor_item .logs:visible,'+id+'#add_monitor:visible .logs',user)
}
//open all monitors
@ -320,6 +320,32 @@ $(document).ready(function(e){
user=$user
}
switch(e.a){
case'zoomStreamWithMouse':
var streamWindow = $('.monitor_item[mid="'+e.mid+'"][ke="'+e.ke+'"][auth="'+e.auth+'"]')
if(e.mon.magnifyStreamEnabled){
e.mon.magnifyStreamEnabled = false
streamWindow
.off('mousemove')
.off('touchmove')
.find('.zoomGlass').remove()
}else{
e.mon.magnifyStreamEnabled = true
const magnifyStream = function(e){
$.ccio.magnifyStream({
p: streamWindow,
zoomAmount: 1,
auto: false,
animate: false,
pageX: e.pageX,
pageY: e.pageY,
attribute: 'monitor="zoomStreamWithMouse"'
},user)
}
streamWindow
.on('mousemove', magnifyStream)
.on('touchmove', magnifyStream)
}
break;
case'show_data':
e.p.toggleClass('show_data')
var dataBlocks = e.p.find('.stream-block,.mdl-data_window')
@ -365,31 +391,17 @@ $(document).ready(function(e){
})
}
break;
case'timelapse':
$.timelapse.e.modal('show')
$.timelapse.monitors.find('.monitor').remove()
case'timelapseJpeg':
$.timelapseJpeg.e.modal('show')
$.timelapseJpeg.monitors.find('.monitor').remove()
$.each($.ccio.mon,function(n,v){
$.timelapse.monitors.append('<option class="monitor" value="'+v.mid+'">'+v.name+'</option>')
$.timelapseJpeg.monitors.append('<option class="monitor" value="'+v.mid+'">'+v.name+'</option>')
})
e.e=$.timelapse.monitors.find('.monitor').prop('selected',false)
e.e=$.timelapseJpeg.monitors.find('.monitor').prop('selected',false)
if(e.mid!==''){
e.e=$.timelapse.monitors.find('.monitor[value="'+e.mid+'"]')
e.e=$.timelapseJpeg.monitors.find('.monitor[value="'+e.mid+'"]')
}
e.e.first().prop('selected',true)
$.timelapse.f.submit()
break;
case'powerview':
$.pwrvid.e.modal('show')
$.pwrvid.m.empty()
$.each($.ccio.mon,function(n,v){
$.pwrvid.m.append('<option value="'+v.mid+'">'+v.name+'</option>')
})
e.e=$.pwrvid.m.find('option').prop('selected',false)
if(e.mid!==''){
e.e=$.pwrvid.m.find('[value="'+e.mid+'"]')
}
e.e.first().prop('selected',true)
$.pwrvid.f.submit()
break;
case'region':
if(!e.mon){
@ -508,6 +520,7 @@ $(document).ready(function(e){
right: 'month,agendaWeek,agendaDay,listWeek'
},
defaultDate: $.ccio.timeObject(d.videos[0].time).format('YYYY-MM-DD'),
locale: user.details.lang.substring(0, 2),
navLinks: true,
eventLimit: true,
events:e.ar,
@ -562,21 +575,21 @@ $(document).ready(function(e){
var showThumbnail = $.ccio.op().showThumbnail === '1'
$.vidview.e.removeClass('dark')
e.t.attr('class','fa fa-film')
var tmp = '<table class="table table-striped" style="max-height:500px">';
var tmp = '<table class="table table-striped table-bordered">';
tmp+='<thead>';
tmp+='<tr>';
tmp+='<th><div class="checkbox"><input id="videos_select_all" type="checkbox"><label for="videos_select_all"></label></div></th>';
if(showThumbnail)tmp+='<th data-field="Thumbnail" data-sortable="true">'+lang.Thumbnail+'</th>';
tmp+='<th data-field="Closed" data-sortable="true">'+lang.Closed+'</th>';
tmp+='<th data-field="Ended" data-sortable="true">'+lang.Ended+'</th>';
tmp+='<th data-field="Started" data-sortable="true">'+lang.Started+'</th>';
tmp+='<th data-field="Monitor" data-sortable="true">'+lang.Monitor+'</th>';
tmp+='<th data-field="Filename" data-sortable="true">'+lang.Filename+'</th>';
tmp+='<th data-field="Size" data-sortable="true">'+lang['Size (mb)']+'</th>';
tmp+='<th data-field="Preview" data-sortable="true">'+lang.Preview+'</th>';
tmp+='<th data-field="Watch" data-sortable="true">'+lang.Watch+'</th>';
tmp+='<th data-field="Download" data-sortable="true">'+lang.Download+'</th>';
tmp+='<th class="permission_video_delete" data-field="Delete" data-sortable="true">'+lang.Delete+'</th>';
if(showThumbnail)tmp+='<th>'+lang.Thumbnail+'</th>';
tmp+='<th class="table-header-sorter" data-field="Closed">'+lang.Closed+'<i class="fa fa-sort"></i></th>';
tmp+='<th class="table-header-sorter" data-field="Ended">'+lang.Ended+'<i class="fa fa-sort"></i></th>';
tmp+='<th class="table-header-sorter" data-field="Started">'+lang.Started+'<i class="fa fa-sort"></i></th>';
tmp+='<th class="table-header-sorter" data-field="Monitor">'+lang.Monitor+'<i class="fa fa-sort"></i></th>';
tmp+='<th class="table-header-sorter" data-field="Filename">'+lang.Filename+'<i class="fa fa-sort"></i></th>';
tmp+='<th class="table-header-sorter" data-field="Size">'+lang['Size (mb)']+'<i class="fa fa-sort"></i></th>';
tmp+='<th>'+lang.Preview+'</th>';
tmp+='<th>'+lang.Watch+'</th>';
tmp+='<th>'+lang.Download+'</th>';
tmp+='<th class="permission_video_delete">'+lang.Delete+'</th>';
// tmp+='<th class="permission_video_delete" data-field="Fix" data-sortable="true">'+lang.Fix+'</th>';
tmp+='</tr>';
tmp+='</thead>';
@ -588,10 +601,19 @@ $(document).ready(function(e){
v.mon=$.ccio.mon[v.ke+v.mid+user.auth_token];
v.start=v.time;
// v.filename=$.ccio.init('tf',v.time)+'.'+v.ext;
tmp+='<tr data-ke="'+v.ke+'" data-status="'+v.status+'" data-mid="'+v.mid+'" data-file="'+v.filename+'" data-auth="'+v.mon.user.auth_token+'">';
const sortData = {
_no: n,
Closed: $.ccio.timeObject(v.end).unix(),
Ended: $.ccio.timeObject(v.end).unix(),
Started: $.ccio.timeObject(v.time).unix(),
Monitor: v.mon.name,
Filename: v.filename,
Size: v.size,
};
tmp+='<tr data-sort="' + JSON.stringify(sortData).replace(/"/g, "&#34;") + '" data-ke="'+v.ke+'" data-status="'+v.status+'" data-mid="'+v.mid+'" data-file="'+v.filename+'" data-auth="'+v.mon.user.auth_token+'">';
tmp+='<td><div class="checkbox"><input id="'+v.ke+'_'+v.filename+'" name="'+v.filename+'" value="'+v.mid+'" type="checkbox"><label for="'+v.ke+'_'+v.filename+'"></label></div></td>';
if(showThumbnail)tmp+='<td class="text-center"><img class="thumbnail"></td>';
tmp+='<td><span class="livestamp" title="'+$.ccio.timeObject(v.end).format('YYYY-MM-DD HH:mm:ss')+'"></span></td>';
tmp+='<td>'+$.ccio.timeObject(v.end).fromNow()+'</td>';
tmp+='<td title="'+v.end+'">'+$.ccio.timeObject(v.end).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
tmp+='<td title="'+v.time+'">'+$.ccio.timeObject(v.time).format('h:mm:ss A, MMMM Do YYYY')+'</td>';
tmp+='<td>'+v.mon.name+'</td>';
@ -608,6 +630,10 @@ $(document).ready(function(e){
tmp+='</tbody>';
tmp+='</table>';
e.b.html(tmp)
e.b.css({
overflow: 'auto',
height: '100%',
}).scrollTop(0);
if(showThumbnail){
var i = 0
var getThumbnail = function(){
@ -624,8 +650,6 @@ $(document).ready(function(e){
}
getThumbnail()
}
$.ccio.init('ls');
$.vidview.e.find('table').bootstrapTable();
break;
}
})
@ -796,6 +820,4 @@ $(document).ready(function(e){
.on('dblclick','.stream-hud',function(){
$(this).parents('[mid]').find('[monitor="fullscreen"]').click();
})
//.on('mousemove',".magnifyStream",$.ccio.magnifyStream)
//.on('touchmove',".magnifyStream",$.ccio.magnifyStream);
})

View file

@ -336,11 +336,11 @@ $.ccio.init=function(x,d,user,k){
case'drawMatrices':
d.height=d.stream.height()
d.width=d.stream.width()
if(d.monitorDetails.detector_scale_x===''){d.monitorDetails.detector_scale_x=320}
if(d.monitorDetails.detector_scale_y===''){d.monitorDetails.detector_scale_y=240}
if(!d.details.imgWidth && d.monitorDetails.detector_scale_x===''){d.monitorDetails.detector_scale_x=320}
if(!d.details.imgHeight && d.monitorDetails.detector_scale_y===''){d.monitorDetails.detector_scale_y=240}
d.widthRatio=d.width/d.monitorDetails.detector_scale_x
d.heightRatio=d.height/d.monitorDetails.detector_scale_y
d.widthRatio=d.width/d.details.imgWidth || d.monitorDetails.detector_scale_x
d.heightRatio=d.height/d.details.imgHeight || d.monitorDetails.detector_scale_y
d.streamObjects.find('.stream-detected-object[name="'+d.details.name+'"]').remove()
d.tmp=''

View file

@ -0,0 +1,320 @@
$(document).ready(function(){
$.monitorStates = {
e: $('#monitorStates'),
selector: $('#monitorStatesSelector'),
monitors: $('#monitorStatesMonitors'),
loaded: {}
}
$.monitorStates.f = $.monitorStates.e.find('form')
$.monitorStates.loadPresets = function(callback){
$.get($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke,function(d){
var html = ''
$.each(d.presets,function(n,v){
$.monitorStates.loaded[v.name] = v
html += '<option value="' + v.name + '">' + v.name + '</option>'
})
$.monitorStates.selector.find('optgroup').html(html)
if(callback)callback()
})
}
$.monitorStates.e.on('shown.bs.modal', function (e) {
if($.monitorStates.selector.val() === '')$.monitorStates.loadPresets()
})
var buildOptions = function(field,possiblities,fieldData){
if(!field)console.error('field',field)
var fieldElement = ''
possiblities.forEach(function(option){
if(option.optgroup){
fieldElement += '<optgroup label="' + option.name + '">'
fieldElement += buildOptions(field,option.optgroup,fieldData)
fieldElement += '</optgroup>'
}else{
var selected = ''
if(option.value === fieldData || option.value === field.default){
selected = 'selected'
}
fieldElement += '<option value="' + option.value + '" ' + selected + '>' + option.name + '</option>'
}
})
return fieldElement
}
var drawBlock = function(monitorSettings,preloadedData){
var html = ''
var headerTitle = lang[monitorSettings.name]
// if(monitorSettings.evaluation && !eval(monitorSettings.evaluation)){
// return
// }
if(monitorSettings.blocks){
monitorSettings.blocks.forEach(function(settingsBlock){
html += drawBlock(settingsBlock)
})
}
if(monitorSettings.info){
monitorSettings.info.forEach(function(field){
if(field.isFormGroupGroup === true){
html += drawBlock(field)
}else{
if(field.notForSubAccount === true){
var notForSubAccount = '!details.sub'
if(!field.evaluation){
field.evaluation = notForSubAccount
}else{
field.evaluation += ' && ' + notForSubAccount
}
}
if(!field.name || field.evaluation && !eval(field.evaluation)){
return
}
var attributes = []
var listGroupClass = []
var monitorRowFieldClass = []
if(preloadedData){
var isDetail = false
var name = field.name
var fieldData
if(name.indexOf('detail=') > -1){
isDetail = true
name = name.replace('detail=','')
if(preloadedData.details)fieldData = preloadedData.details[name]
}else{
fieldData = preloadedData[name]
}
if(fieldData){
listGroupClass.push('active')
if(fieldType !== 'select'){
attributes.push(`value="${fieldData}"`)
}
}else{
monitorRowFieldClass.push('display:none')
}
}else{
monitorRowFieldClass.push('display:none')
}
if(field.placeholder || field.default){
attributes.push(`placeholder="${field.placeholder || field.default}"`)
}else if(field.example){
attributes.push(`placeholder="Example : ${field.example}"`)
}
var possiblities = field.possible || []
var fieldType = field.fieldType || 'text'
var fieldElement = ''
switch(fieldType){
case'number':
if(field.numberMin){
attributes.push(`min="${field.numberMin}"`)
}
if(field.numberMax){
attributes.push(`max="${field.numberMax}"`)
}
fieldElement = '<div><input type="number" class="form-control" ' + attributes.join(' ') + '></div>'
break;
case'password':
fieldElement = '<div><input type="password" class="form-control" ' + attributes.join(' ') + '></div>'
break;
case'text':
fieldElement = `<div><input class="form-control" ${attributes.join(' ')}></div>`
break;
case'textarea':
fieldElement = '<div><textarea class="form-control" ' + attributes.join(' ') + '></textarea></div>'
break;
case'select':
fieldElement = '<div><select class="form-control" ' + attributes.join(' ') + '>'
fieldElement += buildOptions(field,possiblities,fieldData)
fieldElement += '</select></div>'
break;
}
if(fieldType === 'ul' || fieldType === 'div' || fieldType === 'btn' || field.name === 'mid'){
}else{
if(headerTitle){
html += `<div class="list-group-item ${listGroupClass.join(' ')}" data-name="${field.name}" data-value="${field.value || ""}">
<h4>${headerTitle} : ${field.field}</h4>
<div><small>${field.description}</small></div>
<div class="state-monitor-row-fields-field mt-4" style="${monitorRowFieldClass.join(' ')}">${fieldElement}</div>
</div>`
}
}
}
})
}
return html
}
$.monitorStates.drawMonitor = function(preloadedData){
var MonitorSettings = $.ccio.definitions['Monitor Settings']
var html = ''
console.log(preloadedData)
Object.keys(MonitorSettings.blocks).forEach(function(blockKey){
var block = MonitorSettings.blocks[blockKey]
html += drawBlock(block,preloadedData)
})
var monitorSelect = `<select class="state-monitor-row-select form-control">`
$.each($.ccio.mon,function(n,monitor){
monitorSelect += `<option value="${monitor.mid}">${monitor.name} (${monitor.mid})</option>`
})
monitorSelect += `</select>`
var fullHtml = `<div class="form-group state-monitor-row">
<div class="input-group state-monitor-row-select-container">
${monitorSelect}
<div class="input-group-btn">
<a class="btn btn-danger delete-monitor">
&nbsp;<i class="fa fa-times"></i>&nbsp;
</a>
</div>
</div>
<div class="list-group state-monitor-row-fields-container" style="height:300px;overflow: auto">
${html}
</div>
</div>`
return fullHtml
}
$.monitorStates.e.on('click','.add-monitor',function(e){
var el = $(this)
var html = $.monitorStates.drawMonitor()
$.monitorStates.monitors.append(html)
})
$.monitorStates.e.on('click','.state-monitor-row-fields-container .list-group-item',function(e){
var el = $(this)
var listGroupParent = el.parents('.list-group')
var fieldContainer = el.find('.state-monitor-row-fields-field')
var name = el.attr('data-name')
var value = el.attr('data-value')
if(el.hasClass('active')){
el.removeClass('active')
fieldContainer.hide()
}else{
el.addClass('active')
fieldContainer.show()
}
})
$.monitorStates.e.on('click','.state-monitor-row-fields-container .form-control',function(e){
e.preventDefault()
return false
})
$.monitorStates.e.on('change','.json',function(e){
var el = $(this)
var val = el.val()
try{
el.css('border-color','green')
var parsed = JSON.parse(val)
el.val(JSON.stringify(parsed,null,3))
}catch(err){
el.css('border-color','red')
return $.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
})
$.monitorStates.e.on('click','.delete',function(e){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor States Preset']);
$.confirm.body.html(lang.deleteMonitorStateText1);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
var form = $.monitorStates.f.serializeObject()
$.post($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke + '/' + form.name + '/delete',function(d){
$.ccio.log(d)
if(d.ok === true){
$.monitorStates.loadPresets()
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
})
})
$.monitorStates.e.on('click','.delete-monitor',function(e){
var el = $(this).parents('.state-monitor-row')
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor State']);
$.confirm.body.html(lang.deleteMonitorStateText2)
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
el.remove()
})
})
$.monitorStates.selector.change(function(e){
var selected = $(this).val()
var loaded = $.monitorStates.loaded[selected]
var namespace = $.monitorStates.e.find('[name="name"]')
var deleteButton = $.monitorStates.e.find('.delete')
if(loaded){
namespace.val(loaded.name)
var html = ''
$.each(loaded.details.monitors,function(n,v){
console.log(v)
html += $.monitorStates.drawMonitor(v)
})
$.monitorStates.monitors.html(html)
deleteButton.show()
}else{
namespace.val('')
$.monitorStates.monitors.empty()
deleteButton.hide()
}
})
$.monitorStates.getFormValuesFromJson = function(){
var rows = $.monitorStates.monitors.find('.state-monitor-row')
var monitors = []
rows.each(function(n,v){
var el = $(v)
var textarea = el.find('textarea')
try{
var json = JSON.parse(el.find('.json').val())
textarea.css('border-color','green')
if(json.mid)monitors.push(json)
}catch(err){
textarea.css('border-color','red')
$.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
})
return monitors
}
$.monitorStates.getFormValues = function(){
var rows = $.monitorStates.monitors.find('.state-monitor-row')
var monitors = []
rows.each(function(n,v){
var monitorJson = {
details: {}
}
var el = $(v)
var fieldsSelcted = el.find('.list-group-item.active')
monitorJson.mid = el.find('.state-monitor-row-select').val()
fieldsSelcted.each(function(nn,element){
var field = $(element)
var name = field.attr('data-name')
var value = field.find('.form-control').val()
var isDetail = false
if(name.indexOf('detail=') > -1){
isDetail = true
name = name.replace('detail=','')
monitorJson.details[name] = value
}else{
monitorJson[name] = value
}
})
if(Object.keys(monitorJson).length > 2 || Object.keys(monitorJson.details).length > 2){
monitors.push(monitorJson)
}
})
return monitors
}
$.monitorStates.f.submit(function(e){
e.preventDefault()
var el = $(this)
var form = el.serializeObject()
var monitors = $.monitorStates.getFormValues()
if(form.name === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Name cannot be empty.'],type:'error'})
}
if(monitors.length === 0){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Must be atleast one row'],type:'error'})
}
var data = {
monitors: monitors
}
$.post($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke + '/' + form.name + '/insert',{data:data},function(d){
$.ccio.log(d)
if(d.ok === true){
$.monitorStates.loadPresets(function(){
$.monitorStates.selector.val(form.name)
})
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
return false;
})
})

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,17 @@
$(document).ready(function(e){
var getUrlPieces = function(url){
var el = document.createElement('a');
el.href = url
return el
// el.host // www.somedomain.com (includes port if there is one[1])
// el.hostname // www.somedomain.com
// el.hash // #top
// el.href // http://www.somedomain.com/account/search?filter=a#top
// el.pathname // /account/search
// el.port // (port if there is one[1])
// el.protocol // http:
// el.search // ?filter=a
}
//multi monitor manager
$.multimon={e:$('#multi_mon')};
$.multimon.table=$.multimon.e.find('.tableData tbody');
@ -17,7 +30,7 @@ $.multimon.e.find('.import_config').click(function(){
var e={};e.e=$(this);e.mid=e.e.parents('[mid]').attr('mid');
$.confirm.e.modal('show');
$.confirm.title.text(lang['Import Monitor Configuration'])
e.html=lang.ImportMultiMonitorConfigurationText+'<div style="margin-top:15px"><div class="form-group"><textarea placeholder="'+lang['Paste JSON here.']+'" class="form-control"></textarea></div><label class="upload_file btn btn-primary btn-block"> Upload File <input class="upload" type=file name="files[]"></label></div>';
e.html=lang.ImportMultiMonitorConfigurationText+'<div style="margin-top:15px"><div class="form-group"><textarea placeholder="'+lang['Paste JSON here.']+'" class="form-control"></textarea></div><label class="upload_file btn btn-primary btn-block">'+lang['Upload File']+'<input class="upload" type=file name="files[]"></label></div>';
$.confirm.body.html(e.html)
$.confirm.e.find('.upload').change(function(e){
var files = e.target.files; // FileList object
@ -28,7 +41,7 @@ $.multimon.e.find('.import_config').click(function(){
}
reader.readAsText(f);
});
$.confirm.click({title:'Import',class:'btn-primary'},function(){
$.confirm.click({title:lang['Import'],class:'btn-primary'},function(){
// setTimeout(function(){
// $.confirm.e.modal('show');
// },1000)
@ -67,7 +80,8 @@ $.multimon.e.find('.import_config').click(function(){
console.log(newMon)
return newMon
}
parsedData=JSON.parse($.confirm.e.find('textarea').val());
var textFieldData = $.confirm.e.find('textarea').val()
var parsedData = JSON.parse(textFieldData)
//zoneminder one monitor
if(parsedData.monitor){
$.aM.import({
@ -95,8 +109,45 @@ $.multimon.e.find('.import_config').click(function(){
})
}
}catch(err){
$.ccio.log(err)
$.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
//#EXTM3U
if(textFieldData.indexOf('#EXTM3U') > -1 && textFieldData.indexOf('{"') === -1){
var m3u8List = textFieldData.replace('#EXTM3U','').trim().split('\n')
var parsedList = {}
var currentName
m3u8List.forEach(function(line){
if(line.indexOf('#EXTINF:-1,') > -1){
currentName = line.replace('#EXTINF:-1,','').trim()
}else{
parsedList[currentName] = line.trim()
}
})
$.each(parsedList,function(name,url){
var link = getUrlPieces(url)
var newMon = $.aM.generateDefaultMonitorSettings()
newMon.details = JSON.parse(newMon.details)
newMon.mid = 'HLS' + name.toLowerCase()
newMon.name = name
newMon.port = link.port
newMon.host = link.hostname
newMon.path = link.pathname
newMon.details.tv_channel = '1'
newMon.details.tv_channel_id = name
newMon.details.auto_host_enable = '1'
newMon.details.auto_host = url
newMon.details.stream_quality = '1'
newMon.details.stream_fps = ''
newMon.details.stream_vcodec = 'libx264'
newMon.details.stream_acodec = 'aac'
newMon.details.stream_type = 'hls'
newMon.details.hls_time = '10'
newMon.type = 'mp4'
newMon.details = JSON.stringify(newMon.details)
postMonitor(newMon)
})
}else{
$.ccio.log(err)
$.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
}
// });
});
@ -116,7 +167,7 @@ $.multimon.getSelectedMonitors = function(unclean){
$.multimon.e.find('.delete').click(function(){
var arr=$.multimon.getSelectedMonitors(true);
if(arr.length===0){
$.ccio.init('note',{title:'No Monitors Selected',text:'Select atleast one monitor to delete.',type:'error'});
$.ccio.init('note',{title:lang['No Monitors Selected'],text:lang['Select atleast one monitor to delete'],type:'error'});
return
}
$.confirm.e.modal('show');
@ -125,7 +176,7 @@ $.multimon.e.find('.delete').click(function(){
$.confirm.body.html(e.html)
$.confirm.click([
{
title:'Delete Monitors',
title:lang['Delete']+' '+lang['Monitors'],
class:'btn-danger',
callback:function(){
$.each(arr,function(n,v){
@ -136,7 +187,7 @@ $.multimon.e.find('.delete').click(function(){
}
},
{
title:'Delete Monitors and Files',
title:lang['Delete Monitors and Files'],
class:'btn-danger',
callback:function(){
$.each(arr,function(n,v){
@ -152,7 +203,7 @@ $.multimon.e.find('.delete').click(function(){
// var arr=$.multimon.getSelectedMonitors();
// var arrObject={}
// if(arr.length===0){
// $.ccio.init('note',{title:'No Monitors Selected',text:'Select atleast one monitor to delete.',type:'error'});
// $.ccio.init('note',{title:lang['No Monitors Selected'],text:lang['Select atleast one monitor to delete'],type:'error'});
// return
// }
// $.multimonedit.selectedList = arr;
@ -162,7 +213,7 @@ $.multimon.e.find('.save_config').click(function(){
var e={};e.e=$(this);
var arr=$.multimon.getSelectedMonitors();
if(arr.length===0){
$.ccio.init('note',{title:'No Monitors Selected',text:'Select atleast one monitor to delete.',type:'error'});
$.ccio.init('note',{title:lang['No Monitors Selected'],text:lang['Select atleast one monitor to delete'],type:'error'});
return
}
e.dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(arr));

View file

@ -0,0 +1,616 @@
$(document).ready(function(e){
var powerVideoWindow = $('#powerVideo')
var powerVideoMonitorsListElement = $('#powerVideoMonitorsList')
var powerVideoMonitorViewsElement = $('#powerVideoMonitorViews')
var powerVideoTimelineStripsContainer = $('#powerVideoTimelineStrips')
var powerVideoDateRangeElement = $('#powerVideoDateRange')
var powerVideoVideoLimitElement = $('#powerVideoVideoLimit')
var powerVideoEventLimitElement = $('#powerVideoEventLimit')
var powerVideoLoadedVideos = {}
var powerVideoLoadedEvents = {}
var powerVideoLoadedChartData = {}
var loadedTableGroupIds = {}
var eventsLabeledByTime = {}
var monitorSlotPlaySpeeds = {}
var currentlyPlayingVideos = {}
var extenders = {
onVideoPlayerTimeUpdateExtensions: [],
onVideoPlayerTimeUpdate: function(extender){
extenders.onVideoPlayerTimeUpdateExtensions.push(extender)
},
onVideoPlayerCreateExtensions: [],
onVideoPlayerCreate: function(extender){
extenders.onVideoPlayerCreateExtensions.push(extender)
},
}
var activeTimeline = null
// fix utc/localtime translation (use timelapseJpeg as guide, it works as expected) >
powerVideoDateRangeElement.daterangepicker({
startDate:$.ccio.timeObject().subtract(moment.duration("24:00:00")),
endDate:$.ccio.timeObject().add(moment.duration("24:00:00")),
timePicker: true,
timePicker24Hour: true,
timePickerSeconds: true,
timePickerIncrement: 30,
locale: {
format: 'MM/DD/YYYY h:mm A'
}
},function(start, end, label){
// $.pwrvid.drawTimeline()
powerVideoDateRangeElement.focus()
getSelectedMonitors().each(function(n,activeElement){
var monitorId = $(activeElement).attr('data-monitor')
requestTableData(monitorId)
})
});
// fix utc/localtime translation (use timelapseJpeg as guide, it works as expected) />
var loadVideosToTimeLineMemory = function(monitorId,videos,events){
powerVideoLoadedVideos[monitorId] = videos
powerVideoLoadedEvents[monitorId] = events
}
var drawMonitorsList = function(){
var html = ''
$.each($.ccio.mon,function(n,monitor){
html += `<div class="list-group-item" data-monitor="${monitor.mid}">${monitor.name}</div>`
})
powerVideoMonitorsListElement.html(html)
}
var requestTableData = function(monitorId,user){
if(!user)user = $user
var dateData = powerVideoDateRangeElement.data('daterangepicker')
$.ccio.cx({
f: 'monitor',
ff: 'get',
fff: 'videos&events',
videoLimit: parseInt(powerVideoVideoLimitElement.val()) || 0,
eventLimit: parseInt(powerVideoEventLimitElement.val()) || 500,
startDate: dateData.startDate.utc().format('YYYY-MM-DDTHH:mm:ss'),
endDate: dateData.endDate.utc().format('YYYY-MM-DDTHH:mm:ss'),
ke: user.ke,
mid: monitorId
})
}
var unloadTableData = function(monitorId,user){
if(!user)user = $user
delete(powerVideoLoadedVideos[monitorId])
delete(powerVideoLoadedEvents[monitorId])
delete(loadedTableGroupIds[monitorId])
delete(loadedTableGroupIds[monitorId + '_events'])
powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid="${monitorId}"]`).remove()
drawLoadedTableData()
}
var checkEventsAgainstVideo = function(video,events){
var videoStartTime = new Date(video.time)
var videoEndTime = new Date(video.end)
var eventsToCheck = events
video.detections = {}
var newSetOfEventsWithoutChecked = {}
$.each(eventsToCheck,function(n,event){
var eventTime = new Date(event.time)
var seekPosition = (eventTime - videoStartTime) / 1000
if (videoStartTime <= eventTime && eventTime <= videoEndTime) {
if(!video.details.confidence)video.details.confidence = 0
video.detections[seekPosition] = event
eventsLabeledByTime[video.mid][video.time][seekPosition] = event
}else{
newSetOfEventsWithoutChecked[n] = video
}
})
eventsToCheck = newSetOfEventsWithoutChecked
}
var prepareVideosAndEventsForTable = function(monitorId,videos,events){
var chartData = []
eventsLabeledByTime[monitorId] = {}
$.each(videos,function(n,video){
eventsLabeledByTime[monitorId][video.time] = {}
if(videos[n - 1])video.videoAfter = videos[n - 1]
if(videos[n + 1])video.videoBefore = videos[n + 1]
checkEventsAgainstVideo(video,events)
chartData.push({
group: loadedTableGroupIds[monitorId],
content: `<div timeline-video-file="${video.mid}${video.time}">
${video.time}
<div class="progress">
<div class="progress-bar progress-bar-danger" role="progressbar" style="width:0%;"><span></span></div>
</div>
</div>`,
start: video.time,
end: video.end,
videoInfo: video
})
})
$.each(events,function(n,event){
var eventReason = event.details.reason.toUpperCase()
var eventSlotTag = eventReason
if(eventReason === 'OBJECT' && event.details.matrices[0]){
eventSlotTag = []
event.details.matrices.forEach(function(matrix){
eventSlotTag.push(matrix.tag)
})
eventSlotTag = eventSlotTag.join(', ')
}
chartData.push({
group: loadedTableGroupIds[monitorId + '_events'],
content: `<div timeline-event="${event.time}">${eventSlotTag}</div>`,
start: event.time,
eventInfo: event
})
})
return chartData
}
var getAllChartDataForLoadedVideos = function(){
var chartData = []
Object.keys(powerVideoLoadedVideos).forEach(function(monitorId,n){
var videos = powerVideoLoadedVideos[monitorId]
var events = powerVideoLoadedEvents[monitorId]
var parsedVideos = prepareVideosAndEventsForTable(monitorId,videos,events)
powerVideoLoadedChartData[monitorId] = parsedVideos
chartData = chartData.concat(parsedVideos)
})
return chartData
}
var visuallySelectItemInRow = function(video){
powerVideoTimelineStripsContainer.find(`[timeline-video-file="${video.mid}${video.time}"]`).parents('.vis-item').addClass('vis-selected')
}
var visuallyDeselectItemInRow = function(video){
powerVideoTimelineStripsContainer.find(`[timeline-video-file="${video.mid}${video.time}"]`).parents('.vis-item').removeClass('vis-selected')
}
var drawTableTimeout = null
var drawLoadedTableData = function(){
// destroy old
try{
if(activeTimeline && activeTimeline.destroy){
activeTimeline.destroy()
}
}catch(err){
}
//
powerVideoTimelineStripsContainer.html(`<div class="loading"><i class="fa fa-spinner fa-pulse"></i><div class="epic-text">${lang['Please Wait...']}</div></div>`)
clearTimeout(drawTableTimeout)
drawTableTimeout = setTimeout(function(){
var container = powerVideoTimelineStripsContainer[0]
var groupsDataSet = new vis.DataSet()
var groups = []
var groupId = 1
Object.keys(powerVideoLoadedVideos).forEach(function(monitorId,n){
groups.push({
id: groupId,
content: monitorId
})
groupId += 1
groups.push({
id: groupId,
content: lang.Events
})
groupId += 1
loadedTableGroupIds[monitorId] = groupId - 2
loadedTableGroupIds[monitorId + '_events'] = groupId - 1
})
groupsDataSet.add(groups)
var chartData = getAllChartDataForLoadedVideos()
if(chartData.length > 0){
var items = new vis.DataSet(chartData)
var options = {
selectable: false,
stack: false,
showCurrentTime: false,
}
// Create a Timeline
var timeline = new vis.Timeline(container, items, groupsDataSet, options)
powerVideoTimelineStripsContainer.find('.loading').remove()
var timeChanging = false
timeline.on('rangechange', function(properties){
timeChanging = true
})
timeline.on('rangechanged', function(properties){
setTimeout(function(){
timeChanging = false
},300)
})
timeline.on('click', function(properties){
if(!timeChanging){
var selectedTime = properties.time
var videosAtSameTime = findAllVideosAtTime(selectedTime)
powerVideoTimelineStripsContainer.find('.vis-item').removeClass('vis-selected')
$.each(videosAtSameTime,function(monitorId,videos){
var selectedVideo = videos[0]
if(selectedVideo){
loadVideoIntoMonitorSlot(selectedVideo,selectedTime)
visuallySelectItemInRow(selectedVideo)
}
})
}
})
activeTimeline = timeline
}else{
powerVideoTimelineStripsContainer.html(`<div class="loading"><i class="fa fa-exclamation-circle"></i><div class="epic-text">${lang['No Data']}</div></div>`)
}
},1000)
}
var drawMatrices = function(event,options){
var streamObjectsContainer = options.streamObjectsContainer
var height = options.height
var width = options.width
var monitorId = options.mid
var widthRatio = width / event.details.imgWidth
var heightRatio = height / event.details.imgHeight
streamObjectsContainer.find('.stream-detected-object[name="'+event.details.name+'"]').remove()
var html = ''
$.each(event.details.matrices,function(n,matrix){
html += `<div class="stream-detected-object" name="${event.details.name}" style="height:${heightRatio * matrix.height}px;width:${widthRatio * matrix.width}px;top:${heightRatio * matrix.y}px;left:${widthRatio * matrix.x}px;">`
if(matrix.tag)html += `<span class="tag">${matrix.tag}</span>`
html += '</div>'
})
streamObjectsContainer.append(html)
}
var attachEventsToVideoActiveElement = function(video){
var monitorId = video.mid
var videoPlayerContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${monitorId}]`)
var videoElement = videoPlayerContainer.find(`video.videoNow`)
var streamObjectsContainer = videoPlayerContainer.find(`.videoPlayer-stream-objects`)
var detectionInfoContainerMotion = videoPlayerContainer.find(`.videoPlayer-detection-info-motion`)
var detectionInfoContainerObject = videoPlayerContainer.find(`.videoPlayer-detection-info-object`)
var detectionInfoContainerRaw = videoPlayerContainer.find(`.videoPlayer-detection-info-raw`)
var motionMeterProgressBar = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar`)
var motionMeterProgressBarTextBox = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar span`)
var videoCurrentTimeProgressBar = powerVideoTimelineStripsContainer.find(`[timeline-video-file="${video.mid}${video.time}"] .progress-bar`)[0]
var preloadedNext = false
var reinitializeStreamObjectsContainer = function(){
height = videoElement.height()
width = videoElement.width()
}
reinitializeStreamObjectsContainer()
$(videoElement)
.resize(reinitializeStreamObjectsContainer)
// .off('loadeddata').on('loadeddata', function() {
// reinitializeStreamObjectsContainer()
// var allLoaded = true
// getAllActiveVideosInSlots().each(function(n,videoElement){
// if(!videoElement.readyState === 4)allLoaded = false
// })
// setTimeout(function(){
// if(allLoaded){
// playAllSlots()
// }
// },1500)
// })
// .off("pause").on("pause",function(){
// console.log(monitorId,'pause')
// })
// .off("play").on("play",function(){
// console.log(monitorId,'play')
// })
.off("timeupdate").on("timeupdate",function(){
var event = eventsLabeledByTime[monitorId][video.time][parseInt(this.currentTime)]
if(event){
if(event.details.matrices){
drawMatrices(event,{
streamObjectsContainer: streamObjectsContainer,
monitorId: monitorId,
height: height,
width: width,
})
detectionInfoContainerObject.html($.ccio.init('jsontoblock',event.details.matrices))
}
if(event.details.confidence){
motionMeterProgressBar.css('width',event.details.confidence+'px')
motionMeterProgressBarTextBox.text(event.details.confidence)
var html = `<div>${lang['Region']} : ${event.details.name}</div>
<div>${lang['Confidence']} : ${event.details.confidence}</div>
<div>${lang['Plugin']} : ${event.details.plug}</div>`
detectionInfoContainerMotion.html(html)
// detectionInfoContainerRaw.html($.ccio.init('jsontoblock',{`${lang['Plug']}`:event.details.plug}))
}
}
var currentTime = this.currentTime;
var watchPoint = Math.floor((currentTime/this.duration) * 100)
if(!preloadedNext && watchPoint >= 75){
preloadedNext = true
var videoAfter = videoPlayerContainer.find(`video.videoAfter`)[0]
videoAfter.setAttribute('preload',true)
}
if(videoCurrentTimeProgressBar)videoCurrentTimeProgressBar.style.width = `${watchPoint}px`
extenders.onVideoPlayerTimeUpdateExtensions.forEach(function(extender){
extender(videoElement,watchPoint)
})
})
var onEnded = function() {
visuallyDeselectItemInRow(video)
if(video.videoAfter){
visuallySelectItemInRow(video.videoAfter)
loadVideoIntoMonitorSlot(video.videoAfter)
}
}
videoElement[0].onended = onEnded
videoElement[0].onerror = onEnded
}
var dettachEventsToVideoActiveElement = function(monitorId){
var videoElement = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${monitorId}] video.videoNow`)
$(videoElement)
// .off('loadeddata')
.off("pause")
.off("play")
.off("timeupdate")
}
var findAllVideosAtTime = function(selectedTime){
var time = new Date(selectedTime)
var parsedVideos = {}
$.each(powerVideoLoadedVideos,function(monitorId,videos){
var videosFilteredByTime = videos.filter(function(video){
return (
(new Date(video.time)) <= time && time < (new Date(video.end))
)
});
parsedVideos[monitorId] = videosFilteredByTime
})
return parsedVideos
}
var resetVisualDetectionDataForMonitorSlot = function(monitorId){
var videoPlayerContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${monitorId}]`)
var streamObjectsContainer = videoPlayerContainer.find(`.videoPlayer-stream-objects`)
var detectionInfoContainerObject = videoPlayerContainer.find(`.videoPlayer-detection-info-object`)
var detectionInfoContainerMotion = videoPlayerContainer.find(`.videoPlayer-detection-info-motion`)
var motionMeterProgressBar = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar`)
var motionMeterProgressBarTextBox = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar span`)
detectionInfoContainerObject.empty()
detectionInfoContainerMotion.empty()
streamObjectsContainer.empty()
motionMeterProgressBar.css('width','0')
motionMeterProgressBarTextBox.text('0')
}
var loadVideoIntoMonitorSlot = function(video,selectedTime){
if(!video)return
resetVisualDetectionDataForMonitorSlot(video.mid)
currentlyPlayingVideos[video.mid] = video
var timeToStartAt = selectedTime - new Date(video.time)
var numberOfMonitors = Object.keys(powerVideoLoadedVideos).length
// if(numberOfMonitors > 3)numberOfMonitors = 3 //start new row after 3
if(numberOfMonitors == 1)numberOfMonitors = 2 //make single monitor not look like a doofus
if(timeToStartAt < 0)timeToStartAt = 0
var widthOfBlock = 100 / numberOfMonitors
var videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}] .videoPlayer-buffers`)
if(videoContainer.length === 0){
if(!monitorSlotPlaySpeeds)monitorSlotPlaySpeeds[video.mid] = {}
powerVideoMonitorViewsElement.append(`<div class="videoPlayer" style="width:${widthOfBlock}%" data-mid="${video.mid}">
<div class="videoPlayer-detection-info">
<div class="videoPlayer-detection-info-raw"></div>
<h5 class="epic-text">${lang.Motion}</h5>
<div class="videoPlayer-detection-info-motion"></div>
<h5 class="epic-text">${lang.Matrices}</h5>
<div class="videoPlayer-detection-info-object"></div>
</div>
<div class="videoPlayer-stream-objects"></div>
<div class="videoPlayer-buffers"></div>
<div class="videoPlayer-motion-meter progress" title="${lang['Motion Meter']}">
<div class="progress-bar progress-bar-danger" role="progressbar" style="width:0%;"><span></span></div>
</div>
</div>`)
videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}] .videoPlayer-buffers`)
}else{
powerVideoMonitorViewsElement.find('.videoPlayer').css('width',`${widthOfBlock}%`)
}
var videoCurrentNow = videoContainer.find('.videoNow')
var videoCurrentAfter = videoContainer.find('.videoAfter')
// var videoCurrentBefore = videoContainer.find('.videoBefore')
dettachEventsToVideoActiveElement(video.mid)
videoContainer.find('video').each(function(n,v){
v.pause()
})
var videoIsSame = (video.href == videoCurrentNow.attr('video'))
var videoIsAfter = (video.href == videoCurrentAfter.attr('video'))
// var videoIsBefore = (video.href == videoCurrentBefore.attr('video'))
var drawVideoHTML = function(position){
var videoData
var exisitingElement = videoContainer.find('.' + position)
if(position){
videoData = video[position]
}else{
position = 'videoNow'
videoData = video
}
if(videoData){
videoContainer.append('<video class="video_video '+position+'" video="'+videoData.href+'" playsinline><source src="'+videoData.href+'" type="video/'+videoData.ext+'"></video>')
}
}
if(
videoIsSame ||
videoIsAfter
// || videoIsBefore
){
switch(true){
case videoIsSame:
var videoNow = videoContainer.find('video.videoNow')[0]
if(!videoNow.paused)videoNow.pause()
videoNow.currentTime = timeToStartAt / 1000
if(videoNow.paused)videoNow.play()
return
break;
case videoIsAfter:
// videoCurrentBefore.remove()
videoCurrentNow.remove()
videoCurrentAfter.removeClass('videoAfter').addClass('videoNow')
// videoCurrentNow.removeClass('videoNow').addClass('videoBefore')
drawVideoHTML('videoAfter')
break;
// case videoIsBefore:
// videoCurrentAfter.remove()
// videoCurrentBefore.removeClass('videoBefore').addClass('videoNow')
// videoCurrentNow.removeClass('videoNow').addClass('videoAfter')
// drawVideoHTML('videoBefore')
// break;
}
}else{
videoContainer.empty()
drawVideoHTML()//videoNow
// drawVideoHTML('videoBefore')
drawVideoHTML('videoAfter')
}
var videoNow = videoContainer.find('video.videoNow')[0]
attachEventsToVideoActiveElement(video)
//
videoNow.setAttribute('preload',true)
videoNow.muted = true
videoNow.playbackRate = monitorSlotPlaySpeeds[video.mid] || 1
videoNow.currentTime = timeToStartAt / 1000
videoNow.play()
extenders.onVideoPlayerCreateExtensions.forEach(function(extender){
extender(videoElement,watchPoint)
})
}
var getSelectedMonitors = function(){
return powerVideoMonitorsListElement.find('.active')
}
var getAllActiveVideosInSlots = function(){
return powerVideoMonitorViewsElement.find('video.videoNow')
}
var pauseAllSlots = function(){
getAllActiveVideosInSlots().each(function(n,video){
if(!video.paused)video.pause()
})
}
var toggleZoomAllSlots = function(){
powerVideoMonitorViewsElement.find(`.videoPlayer`).each(function(n,videoContainer){
var streamWindow = $(videoContainer)
var monitorId = streamWindow.attr('data-mid')
var enabled = streamWindow.attr('zoomEnabled')
if(enabled === '1'){
streamWindow
.attr('zoomEnabled','0')
.off('mouseover')
.off('mouseout')
.off('mousemove')
.off('touchmove')
.find('.zoomGlass').remove()
}else{
const magnifyStream = function(e){
var videoElement = streamWindow.find('video.videoNow')
console.log(videoElement[0].currentTime)
$.ccio.magnifyStream({
p: streamWindow,
videoUrl: streamWindow.find('video.videoNow').find('source').attr('src'),
setTime: videoElement[0].currentTime,
monitor: $.ccio.mon[$user.ke + monitorId + $user.auth_token],
targetForZoom: 'video.videoNow',
magnifyOffsetElement: '.videoPlayer-buffers',
zoomAmount: 1,
auto: false,
animate: false,
pageX: e.pageX,
pageY: e.pageY
},$user)
}
streamWindow
.attr('zoomEnabled','1')
.on('mouseover', function(){
streamWindow.find(".zoomGlass").show()
})
.on('mouseout', function(){
streamWindow.find(".zoomGlass").hide()
})
.on('mousemove', magnifyStream)
.on('touchmove', magnifyStream)
}
})
}
var playAllSlots = function(){
getAllActiveVideosInSlots().each(function(n,video){
if(video.paused)video.play()
})
}
var setPlaySpeedOnAllSlots = function(playSpeed){
Object.keys(powerVideoLoadedVideos).forEach(function(monitorId){
monitorSlotPlaySpeeds[monitorId] = playSpeed
})
getAllActiveVideosInSlots().each(function(n,video){
video.playbackRate = playSpeed
})
}
var nextVideoAllSlots = function(){
Object.keys(currentlyPlayingVideos).forEach(function(monitorId){
var video = currentlyPlayingVideos[monitorId]
visuallyDeselectItemInRow(video)
visuallySelectItemInRow(video.videoAfter)
loadVideoIntoMonitorSlot(video.videoAfter,0)
})
}
var previousVideoAllSlots = function(){
Object.keys(currentlyPlayingVideos).forEach(function(monitorId){
var video = currentlyPlayingVideos[monitorId]
visuallyDeselectItemInRow(video)
visuallySelectItemInRow(video.videoBefore)
loadVideoIntoMonitorSlot(video.videoBefore,0)
})
}
$user.ws.on('f',function (d){
switch(d.f){
case'videos&events':
var videos = d.videos.videos
var events = d.events
loadVideosToTimeLineMemory(d.id,videos,events)
drawLoadedTableData()
break;
}
})
$('body')
.on('dblclick','.videoPlayer',function(){
var el = $(this)
$.ccio.init('fullscreen',this)
})
.on('click','[data-monitor]',function(){
var el = $(this)
var monitorId = el.attr('data-monitor')
el.toggleClass('active')
if(el.hasClass('active')){
requestTableData(monitorId)
}else{
unloadTableData(monitorId)
}
})
.on('click','[powerVideo-control]',function(){
var el = $(this)
var controlType = el.attr('powerVideo-control')
switch(controlType){
case'toggleZoom':
toggleZoomAllSlots()
break;
case'playAll':
playAllSlots()
break;
case'pauseAll':
pauseAllSlots()
break;
case'playSpeedAll':
var playSpeed = el.attr('data-speed')
setPlaySpeedOnAllSlots(playSpeed)
break;
case'previousVideoAll':
playAllSlots()
previousVideoAllSlots()
break;
case'nextVideoAll':
playAllSlots()
nextVideoAllSlots()
break;
}
})
powerVideoWindow.on('shown.bs.modal',function(){
drawMonitorsList()
})
$.powerVideoViewer = {
window: powerVideoWindow,
drawMonitorsList: drawMonitorsList,
activeTimeline: activeTimeline,
monitorListElement: powerVideoMonitorsListElement,
monitorViewsElement: powerVideoMonitorViewsElement,
timelineStripsElement: powerVideoTimelineStripsContainer,
dateRangeElement: powerVideoDateRangeElement,
loadedVideos: powerVideoLoadedVideos,
loadedEvents: powerVideoLoadedEvents,
loadedChartData: powerVideoLoadedChartData,
loadedTableGroupIds: loadedTableGroupIds,
extenders: extenders
}
})

View file

@ -0,0 +1,128 @@
$(document).ready(function(){
$.schedules = {
e: $('#schedules'),
selector: $('#schedulesSelector'),
loadedMonitorStates: {},
loadedSchedules: {}
}
$.schedules.f = $.schedules.e.find('form')
$.schedules.selectedStates = $.schedules.e.find('[name="monitorStates"]')
$.schedules.selectedDays = $.schedules.e.find('[name="days"]')
$.schedules.loadSchedules = function(callback){
$.get($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke,function(d){
console.log(d)
var html = ''
$.each(d.schedules,function(n,v){
$.schedules.loadedSchedules[v.name] = v
html += $.ccio.tm('option',{
id: v.name,
name: v.name
})
})
$.schedules.selector.find('optgroup').html(html)
if(callback)callback()
})
}
$.schedules.loadMonitorStates = function(){
$.get($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke,function(d){
var html = ''
$.each(d.presets,function(n,v){
$.schedules.loadedMonitorStates[v.name] = v
html += $.ccio.tm('option',{
id: v.name,
name: v.name
})
})
$.schedules.selectedStates.html(html)
})
}
$.schedules.e.on('shown.bs.modal', function (e) {
$.schedules.loadMonitorStates()
$.schedules.loadSchedules()
})
$.schedules.e.on('click','.delete',function(e){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor States Preset']);
$.confirm.body.html(lang.deleteMonitorStateText1);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
var form = $.schedules.f.serializeObject()
$.post($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke + '/' + form.name + '/delete',function(d){
$.ccio.log(d)
if(d.ok === true){
$.schedules.loadSchedules()
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
})
})
$.schedules.selector.change(function(e){
var selected = $(this).val()
var loaded = $.schedules.loadedSchedules[selected]
var namespace = $.schedules.e.find('[name="name"]')
var deleteButton = $.schedules.e.find('.delete')
var tzEl = $.schedules.e.find('[name="timezone"]')
$.schedules.selectedStates.find('option:selected').removeAttr('selected')
$.schedules.selectedDays.find('option:selected').removeAttr('selected')
if(loaded){
namespace.val(loaded.name)
var html = ''
$.each(loaded,function(n,v){
$.schedules.f.find('[name="' + n + '"]').val(v)
})
$.each(loaded.details.monitorStates,function(n,v){
$.schedules.selectedStates.find('option[value="' + v + '"]').prop('selected',true)
})
$.each(loaded.details.days,function(n,v){
$.schedules.selectedDays.find('option[value="' + v + '"]').prop('selected',true)
})
tzEl.val(loaded.details.timezone || '+0')
deleteButton.show()
}else{
tzEl.val('+0')
namespace.val('')
deleteButton.hide()
}
})
$.schedules.f.submit(function(e){
e.preventDefault()
var el = $(this)
var form = el.serializeObject()
var monitors = []
var failedToParseAJson = false
var rows = $.monitorStates.monitors.find('.state-monitor-row')
if(form.name === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Name cannot be empty.'],type:'error'})
}
if(form.start === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Start Time cannot be empty.'],type:'error'})
}
if(form.monitorStates instanceof Array === false){
form.monitorStates = [form.monitorStates]
}
if(!form.days || form.days === ''){
form.days = null
}else if(form.days instanceof Array === false){
form.days = [form.days]
}
var data = {
start: form.start,
end: form.end,
enabled: form.enabled,
details: {
monitorStates: form.monitorStates,
days: form.days,
timezone: form.timezone,
}
}
$.post($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke + '/' + form.name + '/insert',{data:data},function(d){
$.ccio.log(d)
if(d.ok === true){
$.schedules.loadSchedules(function(){
$.schedules.selector.val(form.name)
})
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
return false;
})
})

View file

@ -7,6 +7,13 @@ $.ccio.cx=function(x,user){
if(!x.uid){x.uid=user.uid;};
return user.ws.emit('f',x)
}
$.diskUsed = {
main: $('.diskUsed'),
list: {},
}
$.each(addStorage,function(n,storage){
$.diskUsed.list[storage.name] = $(`#diskUsedList [storage="${storage.name}"]`)
})
$.ccio.globalWebsocket=function(d,user){
if(d.f!=='monitor_frame'&&d.f!=='os'&&d.f!=='video_delete'&&d.f!=='detector_trigger'&&d.f!=='detector_record_timeout_start'&&d.f!=='log'){$.ccio.log(d);}
if(!user){
@ -151,12 +158,26 @@ $.ccio.globalWebsocket=function(d,user){
break;
case'diskUsed':
if(!d.limit||d.limit===''){d.limit=10000}
d.percent=parseInt((d.size/d.limit)*100)+'%';
d.human=parseFloat(d.size)
d.percent = parseInt((d.size/d.limit)*100)+'%';
d.human = parseFloat(d.size)
if(d.human>1000){d.human=(d.human/1000).toFixed(2)+' GB'}else{d.human=d.human.toFixed(2)+' MB'}
$('.diskUsed .value').html(d.human)
$('.diskUsed .percent').html(d.percent)
$('.diskUsed .progress-bar').css('width',d.percent)
$.diskUsed.main.find('.value').html(d.human)
$.diskUsed.main.find('.percent').html(d.percent)
$.diskUsed.main.find('.progress-bar').css('width',d.percent)
if(d.addStorage){
$.each(d.addStorage,function(n,storage){
var percent = parseInt((storage.usedSpace/storage.sizeLimit)*100)+'%'
var humanValue = parseFloat(storage.usedSpace)
if(humanValue > 1000){
humanValue = (humanValue/1000).toFixed(2)+' GB'
}else{
humanValue = humanValue.toFixed(2)+' MB'
}
$.diskUsed.list[storage.name].find('.value').html(humanValue)
$.diskUsed.list[storage.name].find('.percent').html(percent)
$.diskUsed.list[storage.name].find('.progress-bar').css('width',percent)
})
}
break;
case'video_fix_success':case'video_fix_start':
switch(d.f){
@ -723,9 +744,14 @@ $.ccio.globalWebsocket=function(d,user){
type: "time",
display: true,
time: {
format: timeFormat,
// round: 'day'
}
// format: timeFormat,
unit: 'minute',
displayFormats: {
minute: 'h:mm a',
},
},
categoryPercentage: 0.6,
barPercentage: .5,
}],
},
}

14
web/libs/js/dash2.tabs.js Normal file
View file

@ -0,0 +1,14 @@
$(document).ready(function(){
$('body')
.on('click','[tab-chooser]',function(){
var el = $(this)
var parent = el.parents('[tab-chooser-parent]')
var tabName = el.attr('[tab-chooser]')
var allTabChoosersInParent = parent.find('[tab-chooser]')
var allTabsInParent = parent.find('[tab-section]')
allTabsInParent.hide()
allTabChoosersInParent.removeClass('active')
el.addClass('active')
parent.find(`[tab-section="${tabName}"]`).show()
})
})

View file

@ -0,0 +1,174 @@
$(document).ready(function(e){
//Timelapse JPEG Window
$.timelapseJpeg = {e:$('#timelapsejpeg')}
$.timelapseJpeg.datepicker = $('#timelapsejpeg_date')
$.timelapseJpeg.timelapseJpegFps = $('#timelapseJpegFps')
$.timelapseJpeg.framesContainer = $.timelapseJpeg.e.find('.frames')
$.timelapseJpeg.frameStrip = $.timelapseJpeg.e.find('.frameStrip')
$.timelapseJpeg.frameIcons = $.timelapseJpeg.e.find('.frameIcons')
$.timelapseJpeg.fieldHolder = $.timelapseJpeg.e.find('.fieldHolder')
$.timelapseJpeg.frameStripPreview = $.timelapseJpeg.e.find('.frameStripPreview')
$.timelapseJpeg.frameStripContainer = $.timelapseJpeg.e.find('.frameStripContainer')
$.timelapseJpeg.playBackViewImg = $.timelapseJpeg.e.find('.playBackView img')
$.timelapseJpeg.liveStreamView = $.timelapseJpeg.e.find('.liveStreamView')
$.timelapseJpeg.monitors=$.timelapseJpeg.e.find('.monitors_list')
$.timelapseJpeg.pointer = $.ccio.init('location',$user)
$.timelapseJpeg.downloadRecheckTimers = {}
$.timelapseJpeg.selectedStartDate = moment().utc().subtract(2, 'days').format('YYYY-MM-DDTHH:mm:ss')
$.timelapseJpeg.selectedEndDate = moment().utc().format('YYYY-MM-DDTHH:mm:ss')
$.timelapseJpeg.datepicker.daterangepicker({
startDate: moment().utc().subtract(2, 'days'),
endDate: moment().utc(),
timePicker: true,
locale: {
format: 'YYYY/MM/DD hh:mm:ss A'
}
}, function(start, end, label) {
console.log(start,end)
var selectedStartDate = moment(start).utc().format('YYYY-MM-DDTHH:mm:ss')
var selectedEndDate = moment(end).utc().format('YYYY-MM-DDTHH:mm:ss')
$.timelapseJpeg.draw(selectedStartDate,selectedEndDate)
$.timelapseJpeg.selectedStartDate = selectedStartDate
$.timelapseJpeg.selectedEndDate = selectedEndDate
})
$.timelapseJpeg.monitors.change(function(){
$.timelapseJpeg.draw()
$.timelapseJpeg.getLiveStream()
})
$.timelapseJpeg.getLiveStream = function(){
var selectedMonitor = $.timelapseJpeg.monitors.val()
$.timelapseJpeg.liveStreamView.html(`<iframe src="${$.timelapseJpeg.pointer+$user.auth_token+'/embed/'+$user.ke+'/'+selectedMonitor+'/jquery|fullscreen'}"></iframe>`)
$.timelapseJpeg.liveStreamView.find('iframe').width($.timelapseJpeg.playBackViewImg.width())
}
$.timelapseJpeg.draw = function(startDate,endDate){
if(!startDate)startDate = $.timelapseJpeg.selectedStartDate
if(!endDate)endDate = $.timelapseJpeg.selectedEndDate
$.timelapseJpeg.frameStripContainerOffset = $.timelapseJpeg.frameStripContainer.offset()
var queryString = ['start=' + startDate,'end=' + endDate]
var frameIconsHtml = ''
var selectedMonitor = $.timelapseJpeg.monitors.val()
var apiURL = $.timelapseJpeg.pointer+$user.auth_token+'/timelapse/'+$user.ke+'/'+selectedMonitor
console.log(apiURL + '?' + queryString.join('&'))
$.getJSON(apiURL + '?' + queryString.join('&'),function(data){
if(data && data[0]){
var firstFilename = data[0].filename
$.timelapseJpeg.frameSelected = firstFilename
$.timelapseJpeg.playlist = {}
$.timelapseJpeg.playlistArray = []
$.each(data.reverse(),function(n,fileInfo){
fileInfo.href = apiURL + '/' + fileInfo.filename.split('T')[0] + '/' + fileInfo.filename
fileInfo.number = n
frameIconsHtml += '<div class="col-md-4"><div class="frame" data-filename="' + fileInfo.filename + '" style="background-image:url(\'' + fileInfo.href + '\')"><div class="shade">' + moment(fileInfo.time).format('YYYY-MM-DD HH:mm:ss') + '</div></div></div>'
$.timelapseJpeg.playlist[fileInfo.filename] = fileInfo
})
$.timelapseJpeg.playlistArray = data
$.timelapseJpeg.frameIcons.html(frameIconsHtml)
$.timelapseJpeg.frameIcons.find(`.frame:first`).click()
$.timelapseJpeg.getLiveStream()
$.timelapseJpeg.resetFilmStripPositions()
}else{
frameIconsHtml = lang['No Data']
$.timelapseJpeg.frameIcons.html(frameIconsHtml)
}
})
}
$.timelapseJpeg.fieldHolderCssHeightModifier = 0
$.timelapseJpeg.resetFilmStripPositions = function(){
var numberOfFrames = Object.keys($.timelapseJpeg.playlist).length
var fieldHolderHeight = $.timelapseJpeg.fieldHolder.height() + $.timelapseJpeg.fieldHolderCssHeightModifier
console.log("calc(100% - " + fieldHolderHeight + "px)")
$.timelapseJpeg.frameIcons.css({height:"calc(100% - " + fieldHolderHeight + "px)"})
}
$.timelapseJpeg.setPlayBackFrame = function(href){
$.timelapseJpeg.playBackViewImg[0].src = href
}
$.timelapseJpeg.playInterval = 1000 / 30
$.timelapseJpeg.play = function(){
var selectedFrame = $.timelapseJpeg.playlist[$.timelapseJpeg.frameSelected]
var selectedFrameNumber = $.timelapseJpeg.playlist[$.timelapseJpeg.frameSelected].number
$.timelapseJpeg.setPlayBackFrame(selectedFrame.href)
$.timelapseJpeg.frameIcons.find(`.frame.selected`).removeClass('selected')
$.timelapseJpeg.frameIcons.find(`.frame[data-filename="${selectedFrame.filename}"]`).addClass('selected')
clearTimeout($.timelapseJpeg.playIntervalTimer)
$.timelapseJpeg.playIntervalTimer = setTimeout(function(){
++selectedFrameNumber
var newSelectedFrame = $.timelapseJpeg.playlistArray[selectedFrameNumber]
if(!newSelectedFrame)return
$.timelapseJpeg.frameSelected = newSelectedFrame.filename
$.timelapseJpeg.play()
},$.timelapseJpeg.playInterval)
}
$.timelapseJpeg.destroy = function(){
$.timelapseJpeg.pause()
$.timelapseJpeg.frameIcons.empty()
$.timelapseJpeg.setPlayBackFrame(null)
}
$.timelapseJpeg.pause = function(){
clearTimeout($.timelapseJpeg.playIntervalTimer)
delete($.timelapseJpeg.playIntervalTimer)
}
$.timelapseJpeg.togglePlayPause = function(){
if($.timelapseJpeg.playIntervalTimer){
$.timelapseJpeg.pause()
}else{
$.timelapseJpeg.play()
}
}
$.timelapseJpeg.e.on('click','.frame',function(){
$.timelapseJpeg.pause()
var selectedFrame = $(this).attr('data-filename')
if(selectedFrame === $.timelapseJpeg.frameSelected){
return $.timelapseJpeg.togglePlayPause()
}
$.timelapseJpeg.frameSelected = selectedFrame
$.timelapseJpeg.frameIcons.find(`.frame.selected`).removeClass('selected')
$.timelapseJpeg.frameIcons.find(`.frame[data-filename="${selectedFrame}"]`).addClass('selected')
var href = $.timelapseJpeg.playlist[selectedFrame].href
$.timelapseJpeg.setPlayBackFrame(href)
})
$.timelapseJpeg.e.on('click','.download_mp4',function(){
var _this = $(this)
var runDownloader = function(){
var startDate = $.timelapseJpeg.selectedStartDate
var endDate = $.timelapseJpeg.selectedEndDate
var queryString = ['fps=' + $.timelapseJpeg.timelapseJpegFps.val(),'start=' + startDate,'end=' + endDate,'mp4=1']
var timerId = queryString.join('&')
var selectedMonitor = $.timelapseJpeg.monitors.val()
var generatorUrl = $.timelapseJpeg.pointer + $user.auth_token + '/timelapse/' + $user.ke + '/' + selectedMonitor
$.getJSON(generatorUrl + '?' + queryString.join('&'),function(response){
if(response.fileExists){
_this.text(lang['Download'])
var downloadName = startDate + '_' + endDate + '_' + selectedMonitor + '.mp4'
var a = document.createElement('a')
a.href = generatorUrl + '?' + queryString.concat(['download="1"']).join('&')
a.download = downloadName
a.click()
}else{
_this.html('&nbsp;<i class="fa fa-spinner fa-pulse"></i>&nbsp;')
clearTimeout($.timelapseJpeg.downloadRecheckTimers[timerId])
$.timelapseJpeg.downloadRecheckTimers[timerId] = setTimeout(function(){
runDownloader()
},5000)
}
})
}
runDownloader()
})
$.timelapseJpeg.e.on('shown.bs.modal', function (e) {
// $.timelapseJpeg.datepicker.val($.timelapseJpeg.baseDate)
// $.timelapseJpeg.draw($.timelapseJpeg.baseDate)
})
$.timelapseJpeg.e.on('hidden.bs.modal', function (e) {
$.timelapseJpeg.destroy()
})
$.timelapseJpeg.timelapseJpegFps
.on('slide',function(ev){
$.timelapseJpeg.playInterval = 1000 / ev.value
})
.slider({
formatter: function(value) {
return 'FPS : ' + value;
}
})
})

View file

@ -3,9 +3,80 @@ $(document).ready(function(e){
$.sM={e:$('#settings')};
$.sM.f=$.sM.e.find('form');
$.sM.links=$('#linkShinobi');
$.sM.addStorageMaxAmounts=$('#add_storage_max_amounts')
$.sM.addStorageMaxAmountsField=$.sM.e.find('[detail="addStorage"]')
$.sM.g=$('#settings_mon_groups');
$.sM.md=$.sM.f.find('[detail]');
$.sM.md.change($.ccio.form.details);
$.sM.e.find('.follow-list ul').affix();
$.sM.sections = {}
var addSection = function(section){
if(!section.id){
var userSettingsId = section.name.replace(/[^a-zA-Z ]/g, '').replace(/[^a-zA-Z ]/g, '').replace(/ /g, '')
section.id = userSettingsId
}
$.sM.sections[section.name] = section.id
if(section.info){
$.each(section.info,function(m,block){
if(block.isFormGroupGroup === true){
addSection(block)
}
})
}
if(section.blocks){
$.each(section.blocks,function(m,block){
addSection(block)
})
}
}
$.each($.ccio.definitions['Account Settings'].blocks,function(n,section){
addSection(section)
})
$.sM.drawList = function(){
var list = $.sM.e.find('.follow-list ul')
var html = ''
$.each($.sM.sections,function(sectionName,sectionId){
var el = $('#' + sectionId)
if(el.length > 0){
html += '<li><a class="scrollTo" href="#' + sectionId + '" scrollToParent="#settings .modal-body">' + sectionName + '</a></li>'
}
})
list.html(html)
}
try{
var addStorageData = JSON.parse($user.details.addStorage || '{}')
var html = ''
$.each(addStorage,function(n,storage){
var limit = ""
if(addStorageData[storage.path] && addStorageData[storage.path].limit){
limit = addStorageData[storage.path].limit
}
html += `<div class="form-group">\
<label><div><span>${lang['Max Storage Amount']} : ${storage.name}</span></div>\
<div><input class="form-control" addStorageLimit="${storage.path}" value="${limit}"></div>\
</label>\
</div>`
})
$.sM.addStorageMaxAmounts.html(html)
$.sM.addStorageMaxAmounts.on('change','[addStorageLimit]',function(){
var json = {}
$.each(addStorage,function(n,storage){
var storageId = storage.path
var el = $.sM.addStorageMaxAmounts.find('[addStorageLimit="' + storageId + '"]')
var value = el.val()
json[storageId] = {
name: storage.name,
path: storage.path,
limit: value
}
})
$.sM.addStorageMaxAmountsField.val(JSON.stringify(json))
})
}catch(err){
console.log(err)
}
$.sM.drawList()
$.sM.f.find('[selector]').change(function(e){
e.v=$(this).val();e.a=$(this).attr('selector')
$.sM.f.find('.'+e.a+'_input').hide()

View file

@ -109,19 +109,15 @@ $.vidview.e.find('.export_selected').click(function(){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Export Selected Videos'])
var html = lang.ExportSelectedVideosMsg+'<div style="margin-bottom:15px"></div>'
var selectedVideos = []
$.each(videos,function(n,v){
html+=v.filename+'<br>';
selectedVideos.push($.vidview.loadedVideos[v.filename])
})
$.confirm.body.html(html)
$.confirm.click({title:'Export Video',class:'btn-danger'},function(){
var queryVariables = []
queryVariables.push('videos='+JSON.stringify(videos))
if($.ccio.useUTC === true){
queryVariables.push('isUTC=true')
}
var downloadZip = $.ccio.init('location',$user)+$user.auth_token+'/zipVideos/'+$user.ke+'?'+queryVariables.join('&')
$('#temp').html('<iframe>a</iframe>').find('iframe').attr('src',downloadZip);
});
$.zipVideosAndDownload(selectedVideos)
})
})
$.vidview.e.find('.merge_selected').click(function(){
e = {}

13
web/libs/js/jszip.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

47
web/libs/js/vis.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -15,34 +15,4 @@
</div>
</div>
</div>
<script>
//confirmwindow
$.confirm={e:$('#confirm_window')};
$.confirm.title=$.confirm.e.find('.modal-title span')
$.confirm.body=$.confirm.e.find('.modal-body')
$.confirm.footer=$.confirm.e.find('.modal-footer')
$.confirm.click=function(x,e){
$.confirm.footer.find('.confirmaction').remove()
var createButton = function(x,place,callback){
$.confirm.footer.prepend('<button type="button" class="btn '+x.class+' confirmaction confirmaction'+place+'">'+x.title+'</button>')
if(!x.class){x.class='btn-success'}
if(!x.title){x.title='Save changes'}
$.confirm.footer.find('.confirmaction'+place).click(function(){
$.confirm.e.modal('hide')
callback();
})
}
if(x instanceof Array){
$.each(x,function(place,x){
createButton(x,place,x.callback)
})
}else{
createButton(x,0,e)
}
}
$(document).ready(function(){
$.confirm.e.on('hidden.bs.modal', function () {
$.confirm.footer.find('.confirmaction').remove()
})
})
</script>
<script src="<%-window.libURL%>libs/js/dash2.confirm.js"></script>

View file

@ -1,11 +1,11 @@
<%
if(!window.libURL)window.libURL = originalURL
%>
<link rel="icon" href="<%-window.libURL%>libs/img/icon/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="<%-window.libURL%>libs/img/icon/favicon.ico" type="image/x-icon" />
<link rel="icon" href="<%-window.libURL%><%-config.webFavicon%>" type="image/x-icon" />
<link rel="shortcut icon" href="<%-window.libURL%><%-config.webFavicon%>" type="image/x-icon" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Shinobi">
<meta name="apple-mobile-web-app-title" content="<%-config.webPageTitle%>">
<link rel="apple-touch-icon" href="<%-window.libURL%>libs/img/icon/apple-touch-icon.png" />
<link rel="apple-touch-icon" sizes="57x57" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="72x72" href="<%-window.libURL%>libs/img/icon/apple-touch-icon-72x72.png" />

View file

@ -2,4 +2,4 @@
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
<meta name="viewport" content="width=device-width, maximum-scale=1, user-scalable=no" />
<meta name="description" content="Shinobi, Open Source CCTV Technology">
<meta name="author" content="Moe Alam, moeiscool on GitHub">
<meta name="author" content="Moe Alam of Shinobi Systems">

View file

@ -0,0 +1 @@
<title><%- config.webPageTitle %></title>

View file

@ -1,5 +1,6 @@
<head>
<title><%-lang.Shinobi%></title>
<!-- Powered by Shinobi, http://shinobi.video -->
<% include header-title.ejs %>
<% if(!window.libURL)window.libURL = originalURL + global.s.checkCorrectPathEnding(config.webPaths.home) %>
<% include header-meta.ejs %>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
@ -8,6 +9,7 @@
<link rel="stylesheet" href="<%-window.libURL%>libs/css/login.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/material.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/material.style.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/roboto.css" type="text/css" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<% include header-favicon.ejs %>

View file

@ -1,45 +1,64 @@
<!--Help Window-->
<!--
<div class="modal fade" id="help_window" tabindex="-1" role="dialog" aria-labelledby="help_windowLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="help_windowLabel"><i class="fa fa-question-circle"></i> &nbsp; <span><%-lang.Help%></span></h4>
</div>
<div class="modal-body">
<a href="http://shinobi.video/docs/donate"><img src="<%-window.libURL%>libs/img/icon/apple-touch-icon-152x152.png" class="pull-right" style="border-radius:50%;margin-left:20px;border: 1px solid #c3996b;"></a>
<p>For information about how to use Shinobi you can check out the <a target="_blank" href="http://shinobi.video/docs">Docs</a>.</p>
<p>If you would like to get professional support please consider ordering a <a href="http://shinobi.video/support">support package</a>. You can find <b>Moe Alam, The Author</b>, on the <a target="_blank" href="https://discord.gg/ehRd8Zz">Discord</a> Community Chat. For general questions and community support you can also try <a href="https://www.reddit.com/r/ShinobiCCTV">Reddit</a>.</p>
<p><strong>Support </strong> <a href="http://shinobi.video/support">from @moeiscool</a></p>
<p><b>Like Shinobi?</b> Please consider donating!</p>
<div><p><strong>Paypal Address :</strong> <a href="https://www.paypal.me/ShinobiCCTV" target="_blank">paypal@m03.ca</a></p>
<% if(!config.userHasSubscribed){ %>
<div class="modal fade" id="help_window" tabindex="-1" role="dialog" aria-labelledby="help_windowLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="help_windowLabel"><i class="fa fa-question-circle"></i> &nbsp; <span><%-lang.Help%></span></h4>
</div>
<div class="modal-body">
<blockquote class="blockquoteInHelp">
<a href="https://licenses.shinobi.video/subscribe" target="_blank"><img src="<%-window.libURL%>libs/img/icon/apple-touch-icon-152x152.png" class="pull-right" style="border-radius:50%;margin-left:20px;border: 1px solid #c3996b;"></a>
<p>For information about how to use Shinobi you can check out the <a target="_blank" href="http://shinobi.video/docs">Docs</a>.</p>
<p><a target="_blank" href="https://discord.gg/ehRd8Zz">Discord</a> Community Chat is great for meeting people and asking questions. For general questions and community support you can also try the <a href="https://www.reddit.com/r/ShinobiCCTV">Reddit forum</a>.</p>
</blockquote>
<blockquote class="blockquoteInHelp" style="margin-bottom:10px">
<b>Support the development by subscribing</b> to any of the following and put your subscription key in the configuration file (conf.json), then restart Shinobi and this annoying popup window won't appear anymore, thanks! <i class="fa fa-smile-o"></i>
<br><br>
<code>"subscriptionId":"sub_XXXXXXXXXXXX",</code>
<br><br>
<p>If you already are supporting the development in a different way, please contact us and we can get this popup to go away for you :) Cheers!</p>
</blockquote>
<div style="margin-bottom:10px;text-align:center">
<a href="https://licenses.shinobi.video/subscribe?planSubscribe=plan_G31AZ9mknNCa6z" target="_blank" class="btn btn-default"><i class="fa fa-share-square-o" aria-hidden="true"></i> Shinobi Mobile License ($5/m)</a>
<a href="https://licenses.shinobi.video/subscribe?planSubscribe=plan_G3LGdNwA8lSmQy" target="_blank" class="btn btn-default"><i class="fa fa-share-square-o" aria-hidden="true"></i> Shinobi Pro License ($75/m)</a> &nbsp;
</div>
<div style="margin-bottom:5px;text-align:center">
<a href="https://licenses.shinobi.video/subscribe?planSubscribe=plan_G42jNgIqXaWmIC" target="_blank" class="btn btn-default"><i class="fa fa-share-square-o" aria-hidden="true"></i> Tiny Support Subscription ($10/m)</a> &nbsp;
</div>
<div>
<!-- <iframe src="https://shinobi.video/ads" style="width:100%;height:250px;border:none;"></iframe> -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger pull-left hide_donate"><%-lang['Close']%></button>
<a target="_blank" href="http://discordapp.com/invite/mdhmvuH/" class="btn btn-primary"><%-lang['Chat on Discord']%></a>
<a target="_blank" href="http://shinobi.video/docs" class="btn btn-success"><%-lang.Documentation%></a>
</div>
</div>
<p><strong>Bitcoin Address :</strong> 1FvC7M8P9wVT1hXwHj8ugxpZj8JGfGyUDu</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger pull-left hide_donate"><%-lang['Don\'t show this anymore']%></button>
<a target="_blank" href="http://discordapp.com/invite/mdhmvuH/" class="btn btn-primary"><%-lang['Chat on Discord']%></a>
<a target="_blank" href="http://shinobi.video/docs" class="btn btn-success"><%-lang.Documentation%></a>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$.help={hide:$('#help_window .hide_donate'),e:$('#help_window')}
if($.ccio.op().hide_donate!==1){
setTimeout(function(){
$.help.e.modal('show')
},1000*60*5)
$.help.hide.click(function(){
$.ccio.op('hide_donate',1);
$.help.e.modal('hide');
})
}else{
$.help.hide.hide()
}
})
</script>-->
<style>
.blockquoteInHelp:before,.blockquoteInHelp:after{
display:none;
}
</style>
<script>
$(document).ready(function(){
$.help={hide:$('#help_window .hide_donate'),e:$('#help_window')}
// if($.ccio.op().hide_donate !== 1){
setTimeout(function(){
$.help.e.modal('show')
},1000*60*0.2)
$.help.hide.click(function(){
// $.ccio.op('hide_donate',1);
$.help.e.modal('hide');
})
// }else{
// $.help.hide.hide()
// }
})
</script>
<% } %>

View file

@ -31,11 +31,10 @@
<div class="form-group-group blue">
<h4><%- lang['Monitors'] %>
<div class="pull-right">
<a class="btn btn-default btn-xs add">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a>
<a class="btn btn-success btn-xs add-monitor">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a>
</div>
</h4>
<div id="monitorStatesMonitors">
</div>
<div id="monitorStatesMonitors"></div>
</div>
</div>
<div class="modal-footer">
@ -46,137 +45,4 @@
</form>
</div>
</div>
<script>
$(document).ready(function(){
$.monitorStates = {
e: $('#monitorStates'),
selector: $('#monitorStatesSelector'),
monitors: $('#monitorStatesMonitors'),
loaded: {}
}
$.monitorStates.f = $.monitorStates.e.find('form')
$.monitorStates.loadPresets = function(callback){
$.get($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke,function(d){
var html = ''
$.each(d.presets,function(n,v){
$.monitorStates.loaded[v.name] = v
html += '<option value="' + v.name + '">' + v.name + '</option>'
})
$.monitorStates.selector.find('optgroup').html(html)
if(callback)callback()
})
}
$.monitorStates.e.on('shown.bs.modal', function (e) {
if($.monitorStates.selector.val() === '')$.monitorStates.loadPresets()
})
$.monitorStates.add = function(loaded,doAppend){
if(!loaded){
json = ''
}else{
json = JSON.stringify(loaded,null,3)
}
var html = '<div class="state-monitor-row"><h4 style="margin-top:7.5px;margin-bottom:7.5px"><small>&nbsp;</small><div class="pull-right"><a class="btn btn-danger btn-xs delete-monitor"><i class="fa fa-trash-o"></i></a></div></h4><textarea class="json form-control" style="width:100%;height:300px">' + json +'</textarea></div>'
if(doAppend)$.monitorStates.monitors.append(html)
return html
}
$.monitorStates.e.find('.add').click(function(e){
$.monitorStates.add(null,true)
})
$.monitorStates.e.on('change','.json',function(e){
var el = $(this)
var val = el.val()
try{
el.css('border-color','green')
var parsed = JSON.parse(val)
el.val(JSON.stringify(parsed,null,3))
}catch(err){
el.css('border-color','red')
return $.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
})
$.monitorStates.e.on('click','.delete',function(e){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor States Preset']);
$.confirm.body.html(lang.deleteMonitorStateText1);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
var form = $.monitorStates.f.serializeObject()
$.post($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke + '/' + form.name + '/delete',function(d){
$.ccio.log(d)
if(d.ok === true){
$.monitorStates.loadPresets()
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
})
})
$.monitorStates.e.on('click','.delete-monitor',function(e){
var el = $(this).parents('.state-monitor-row')
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor State']);
$.confirm.body.html(lang.deleteMonitorStateText2)
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
el.remove()
})
})
$.monitorStates.selector.change(function(e){
var selected = $(this).val()
var loaded = $.monitorStates.loaded[selected]
var namespace = $.monitorStates.e.find('[name="name"]')
var deleteButton = $.monitorStates.e.find('.delete')
if(loaded){
namespace.val(loaded.name)
var html = ''
$.each(loaded.details.monitors,function(n,v){
html += $.monitorStates.add(v)
})
$.monitorStates.monitors.html(html)
deleteButton.show()
}else{
namespace.val('')
$.monitorStates.monitors.empty()
deleteButton.hide()
}
})
$.monitorStates.f.submit(function(e){
e.preventDefault()
var el = $(this)
var form = el.serializeObject()
var monitors = []
var failedToParseAJson = false
var rows = $.monitorStates.monitors.find('.state-monitor-row')
if(form.name === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Name cannot be empty.'],type:'error'})
}
if(rows.length === 0){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Must be atleast one row'],type:'error'})
}
rows.each(function(n,v){
var el = $(v)
try{
console.log(el.find('.json').val())
var json = JSON.parse(el.find('.json').val())
if(json.mid)monitors.push(json)
}catch(err){
console.log(err)
failedToParseAJson = true
}
})
if(failedToParseAJson === true){
return $.ccio.init('note',{title:lang['Invalid JSON'],text:lang.InvalidJSONText,type:'error'})
}
var data = {
monitors: monitors
}
$.post($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke + '/' + form.name + '/insert',{data:data},function(d){
$.ccio.log(d)
if(d.ok === true){
$.monitorStates.loadPresets(function(){
$.monitorStates.selector.val(form.name)
})
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
return false;
})
})
</script>
<script src="<%-window.libURL%>libs/js/dash2.monitorStates.js"></script>

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,10 @@
<thead>
<tr>
<th><div class="checkbox"><input id="multimon_select_all" type="checkbox"><label for="multimon_select_all"></label></div></th>
<th>&nbsp;</th>
<th><%-lang['Name']%></th>
<th><%-lang['Mode']%></th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th><%-lang['Stream']%></th>
<th>&nbsp;</th>
</tr>
</thead>
@ -25,7 +25,7 @@
</table>
</form>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><%-lang.Close%></button>
<div>
<a class="btn btn-danger delete"><%-lang['Delete']%></a>
<a class="btn btn-primary save_config"><%-lang['Export']%></a>

View file

@ -0,0 +1,85 @@
<!--Video File Window-->
<div class="modal full fade dark" id="powerVideo" role="dialog" aria-labelledby="powerVideoLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="powerVideoLabel"><i class="fa fa-map-marker"></i> &nbsp; <%-lang['Power Video Viewer']%><span style="display:none" class="_loading"> &nbsp; <i class="fa fa-pulse fa-spinner"></i></span></h4>
</div>
<div class="modal-body" style="overflow:inherit">
<div class="row">
<div class="col-md-4" id="powerVideoTabs" tab-chooser-parent>
<div class="form-group-group grey text-center">
<h4></h4>
<div class="btn-group" id="powerVideoTabButtons">
<button type="button" class="btn btn-primary btn-sm" tab-chooser="monitors"><%- lang.Monitors %></button>
<button type="button" class="btn btn-primary btn-sm" tab-chooser="settings"><%- lang['Search Settings'] %></button>
</div>
</div>
<div class="form-group-group grey" tab-section="monitors" style="max-height:265px;overflow:auto;">
<h4><%-lang.Monitors%></h4>
<div id="powerVideoMonitorsList" class="list-group"></div>
</div>
<div class="form-group-group grey" tab-section="settings" style="display:none">
<h4><%- lang['Search Settings'] %></h4>
<div class="form-group">
<label><%- lang['Date Range'] %></label>
<input id="powerVideoDateRange" class="form-control"></input>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label><%- lang['Video Limit'] %> <small>(<%- lang['Per Monitor'] %>)</small></label>
<input id="powerVideoVideoLimit" class="form-control" placeholder="0"></input>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label><%- lang['Event Limit'] %> <small>(<%- lang['Per Monitor'] %>)</small></label>
<input id="powerVideoEventLimit" class="form-control" placeholder="500"></input>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-8">
<div id="powerVideoMonitorViews"></div>
<div id="powerVideoMonitorControls" class="text-center">
<div class="btn-group">
<button type="button" powerVideo-control="toggleZoom" class="btn btn-sm btn-default" title="<%- lang['Zoom In'] %>">&nbsp;<i class="fa fa-search-plus"></i>&nbsp;</button>
</div>
<div class="btn-group">
<button type="button" powerVideo-control="previousVideoAll" class="btn btn-sm btn-default" title="<%- lang['Previous Video'] %>">&nbsp;<i class="fa fa-arrow-circle-left"></i>&nbsp;</button>
<button type="button" powerVideo-control="playAll" class="btn btn-sm btn-danger" title="<%- lang.Play %>">&nbsp;<i class="fa fa-play"></i>&nbsp;</button>
<button type="button" powerVideo-control="pauseAll" class="btn btn-sm btn-default" title="<%- lang.Pause %>">&nbsp;<i class="fa fa-pause"></i>&nbsp;</button>
<button type="button" powerVideo-control="nextVideoAll" class="btn btn-sm btn-default" title="<%- lang['Next Video'] %>">&nbsp;<i class="fa fa-arrow-circle-right"></i>&nbsp;</button>
</div>
<div class="btn-group" style="font-family: monospace;">
<button type="button" powerVideo-control="playSpeedAll" data-speed="1" class="btn btn-sm btn-default">1</button>
<button type="button" powerVideo-control="playSpeedAll" data-speed="5" class="btn btn-sm btn-default">5</button>
<button type="button" powerVideo-control="playSpeedAll" data-speed="10" class="btn btn-sm btn-default">10</button>
<button type="button" powerVideo-control="playSpeedAll" data-speed="15" class="btn btn-sm btn-default">15</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12" style="margin-top:10px;">
<div id="powerVideoTimelineStrips">
<div class="loading"><i class="fa fa-hand-pointer-o"></i><div class="epic-text"><%- lang['Select a Monitor'] %></div></div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%-lang['Close']%></button>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/vis.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.powerVideo2.css">
<script src="<%-window.libURL%>libs/js/vis.min.js" async></script>
<script src="<%-window.libURL%>libs/js/dash2.powerVideo2.js" async></script>

View file

@ -69,7 +69,7 @@
</div>
<div class="form-group">
<label><div><span><%-lang['Camera Password']%></span></div>
<div><input class="form-control" name="pass"></div>
<div><input class="form-control" type="password" name="pass"></div>
</label>
</div>
<div class="form-group text-right">

View file

@ -35,16 +35,195 @@
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Timezone Offset']%></span></div>
<div><select class="form-control" name="timezone">
<% [
{
"text": "UTC12:00, Y",
"value": -720
},
{
"text": "UTC11:00, X",
"value": -660
},
{
"text": "UTC10:00, W",
"value": -600
},
{
"text": "UTC09:30, V†",
"value": -570
},
{
"text": "UTC09:00, V",
"value": -540
},
{
"text": "UTC08:00, U",
"value": -480
},
{
"text": "UTC07:00, T",
"value": -420
},
{
"text": "UTC06:00, S",
"value": -360
},
{
"text": "UTC05:00, R",
"value": -300
},
{
"text": "UTC04:00, Q",
"value": -240
},
{
"text": "UTC03:30, P†",
"value": -210
},
{
"text": "UTC03:00, P",
"value": -180
},
{
"text": "UTC02:00, O",
"value": -120
},
{
"text": "UTC01:00, N",
"value": -60
},
{
"text": "UTC±00:00, Z",
"value": 0,
"selected": true
},
{
"text": "UTC+01:00, A",
"value": 60
},
{
"text": "UTC+02:00, B",
"value": 120
},
{
"text": "UTC+03:00, C",
"value": 180
},
{
"text": "UTC+03:30, C†",
"value": 210
},
{
"text": "UTC+04:00, D",
"value": 240
},
{
"text": "UTC+04:30, D†",
"value": 270
},
{
"text": "UTC+05:00, E",
"value": 300
},
{
"text": "UTC+05:30, E†",
"value": 330
},
{
"text": "UTC+05:45, E*",
"value": 345
},
{
"text": "UTC+06:00, F",
"value": 360
},
{
"text": "UTC+06:30, F†",
"value": 390
},
{
"text": "UTC+07:00, G",
"value": 420
},
{
"text": "UTC+08:00, H",
"value": 480
},
{
"text": "UTC+08:45, H*",
"value": 525
},
{
"text": "UTC+09:00, I",
"value": 540
},
{
"text": "UTC+09:30, I†",
"value": 570
},
{
"text": "UTC+10:00, K",
"value": 600
},
{
"text": "UTC+10:30, K†",
"value": 630
},
{
"text": "UTC+11:00, L",
"value": 660
},
{
"text": "UTC+12:00, M",
"value": 720
},
{
"text": "UTC+12:45, M*",
"value": 765
},
{
"text": "UTC+13:00, M†",
"value": 780
},
{
"text": "UTC+14:00, M†",
"value": 840
}
].forEach(function(option){
var selected = ''
if(option.selected)selected = 'selected'
%>
<option value="<%- option.value %>" <%- selected %>><%- option.text %></option>
<% }) %>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Start']%></span></div>
<div><input class="form-control" name="start" placeholder="HH:ss"></div>
<div><input class="form-control" name="start" placeholder="HH:mm"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['End']%></span></div>
<div><input class="form-control" name="end" placeholder="HH:ss"></div>
<div><input class="form-control" name="end" placeholder="HH:mm"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Days']%></span></div>
<div><select class="form-control" style="min-height:100px" multiple name="days">
<option value="0"><%- lang.Sunday %></option>
<option value="1"><%- lang.Monday %></option>
<option value="2"><%- lang.Tuesday %></option>
<option value="3"><%- lang.Wednesday %></option>
<option value="4"><%- lang.Thursday %></option>
<option value="5"><%- lang.Friday %></option>
<option value="6"><%- lang.Saturday %></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Monitor States']%></span></div>
<div><select class="form-control" style="min-height:100px" multiple name="monitorStates">
@ -60,120 +239,4 @@
</form>
</div>
</div>
<script>
$(document).ready(function(){
$.schedules = {
e: $('#schedules'),
selector: $('#schedulesSelector'),
loadedMonitorStates: {},
loadedSchedules: {}
}
$.schedules.f = $.schedules.e.find('form')
$.schedules.selectedStates = $.schedules.e.find('[name="monitorStates"]')
$.schedules.loadSchedules = function(callback){
$.get($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke,function(d){
console.log(d)
var html = ''
$.each(d.schedules,function(n,v){
$.schedules.loadedSchedules[v.name] = v
html += $.ccio.tm('option',{
id: v.name,
name: v.name
})
})
$.schedules.selector.find('optgroup').html(html)
if(callback)callback()
})
}
$.schedules.loadMonitorStates = function(){
$.get($.ccio.init('location',$user) + $user.auth_token + '/monitorStates/' + $user.ke,function(d){
var html = ''
$.each(d.presets,function(n,v){
$.schedules.loadedMonitorStates[v.name] = v
html += $.ccio.tm('option',{
id: v.name,
name: v.name
})
})
$.schedules.selectedStates.html(html)
})
}
$.schedules.e.on('shown.bs.modal', function (e) {
$.schedules.loadMonitorStates()
$.schedules.loadSchedules()
})
$.schedules.e.on('click','.delete',function(e){
$.confirm.e.modal('show');
$.confirm.title.text(lang['Delete Monitor States Preset']);
$.confirm.body.html(lang.deleteMonitorStateText1);
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
var form = $.schedules.f.serializeObject()
$.post($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke + '/' + form.name + '/delete',function(d){
$.ccio.log(d)
if(d.ok === true){
$.schedules.loadSchedules()
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
})
})
$.schedules.selector.change(function(e){
var selected = $(this).val()
var loaded = $.schedules.loadedSchedules[selected]
var namespace = $.schedules.e.find('[name="name"]')
var deleteButton = $.schedules.e.find('.delete')
$.schedules.selectedStates.find('option:selected').removeAttr('selected')
if(loaded){
namespace.val(loaded.name)
var html = ''
$.each(loaded,function(n,v){
$.schedules.f.find('[name="' + n + '"]').val(v)
})
$.each(loaded.details.monitorStates,function(n,v){
$.schedules.selectedStates.find('option[value="' + v + '"]').prop('selected',true)
})
deleteButton.show()
}else{
namespace.val('')
deleteButton.hide()
}
})
$.schedules.f.submit(function(e){
e.preventDefault()
var el = $(this)
var form = el.serializeObject()
var monitors = []
var failedToParseAJson = false
var rows = $.monitorStates.monitors.find('.state-monitor-row')
if(form.name === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Name cannot be empty.'],type:'error'})
}
if(form.start === ''){
return $.ccio.init('note',{title:lang['Invalid Data'],text:lang['Start Time cannot be empty.'],type:'error'})
}
if(form.monitorStates instanceof Array === false){
form.monitorStates = [form.monitorStates]
}
console.log(form.monitorStates)
var data = {
start: form.start,
end: form.end,
enabled: form.enabled,
details:{
monitorStates: form.monitorStates
}
}
$.post($.ccio.init('location',$user) + $user.auth_token + '/schedule/' + $user.ke + '/' + form.name + '/insert',{data:data},function(d){
$.ccio.log(d)
if(d.ok === true){
$.schedules.loadSchedules(function(){
$.schedules.selector.val(form.name)
})
$.ccio.init('note',{title:lang.Success,text:d.msg,type:'success'})
}
})
return false;
})
})
</script>
<script src="<%-window.libURL%>libs/js/dash2.schedules.js"></script>

View file

@ -10,6 +10,11 @@
<h4 class="modal-title" id="settingsLabel"><i class="fa fa-gears"></i> &nbsp; <%-lang.Settings%></h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-2 hidden-xs follow-list">
<ul class="affix"></ul>
</div>
<div class="col-md-10">
<div class="text-center msg"></div>
<div class="form-group-group green">
<h4><%-lang['Account Info']%></h4>
@ -24,597 +29,251 @@
</label>
</div>
</div>
<div class="form-group-group grey">
<h4><%-lang['2-Factor Authentication']%></h4>
<div class="form-group">
<label><div><span><%-lang['Enabled']%></span></div>
<div><select class="form-control" detail="factorAuth">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.Email%></span></div>
<div><select class="form-control" detail="factor_mail">
<option value="1" selected><%-lang.Yes%></option>
<option value="0"><%-lang.No%></option>
</select></div>
</label>
</div>
<div class="form-group u_discord_bot_input u_discord_bot_1">
<label><div><span><%-lang.Discord%></span></div>
<div><select class="form-control" detail="factor_discord">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
</div>
<div class="form-group-group grey">
<h4><%-lang.Profile%></h4>
<div class="form-group">
<label><div><span><%-lang.Email%></span></div>
<div><input class="form-control" type="email" name="mail"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.Password%> <small><%-lang.blankPassword%></small></span></div>
<div><input class="form-control" type="password" name="pass"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.Password%> <%-lang.Again%></span></div>
<div><input class="form-control" type="password" name="password_again"></div>
</label>
</div>
<% if(!details.sub){ %>
<% if(details.edit_size!=='0'){ %>
<div class="form-group">
<label><div><span><%-lang['Max Storage Amount']%></span></div>
<div><input class="form-control" detail="size" placeholder="10000"></div>
</label>
</div>
<% } %>
<% if(details.edit_days!=='0'){ %>
<div class="form-group">
<label><div><span><%-lang['Number of Days to keep']%> <%-lang.Videos%></span></div>
<div><input class="form-control" detail="days" placeholder="5"></div>
</label>
</div>
<% } %>
<% if(details.edit_event_days!=='0'){ %>
<div class="form-group">
<label><div><span><%-lang['Number of Days to keep']%> <%-lang.Events%></span></div>
<div><input class="form-control" detail="event_days" placeholder="10"></div>
</label>
</div>
<% } %>
<% if(details.edit_log_days!=='0'){ %>
<div class="form-group">
<label><div><span><%-lang['Number of Days to keep']%> <%-lang.Logs%></span></div>
<div><input class="form-control" detail="log_days" placeholder="10"></div>
</label>
</div>
<% } %>
<% } %>
<div class="form-group">
<label><div><span><%-lang['Dashboard Language']%></span></div>
<div>
<select class="form-control" detail="lang">
<option value="" selected>Default</option>
<% fs.readdirSync('./languages').forEach(function(v,n){
v=v.replace('.json','') %>
<option value="<%-v%>"><%-v%></option>
<% }) %>
</select>
</div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Notification Sound']%></span></div>
<div>
<select class="form-control" detail="audio_note">
<option value="" selected>No Sound</option>
<% audioFiles.forEach(function(v,n){ %>
<option value="<%-v%>"><%-v%></option>
<%
var buildOptions = function(field,possiblities){
if(!field)console.error('field',field)
var fieldElement = ''
possiblities.forEach(function(option){
if(option.optgroup){
fieldElement += '<optgroup label="' + option.name + '">'
fieldElement += buildOptions(field,option.optgroup)
fieldElement += '</optgroup>'
}else{
var selected = ''
if(option.value === field.default){
selected = 'selected'
}
fieldElement += '<option value="' + option.value + '" ' + selected + '>' + option.name + '</option>'
}
})
return fieldElement
}
var drawBlock = function(userSettings){
if(userSettings.evaluation && !eval(userSettings.evaluation)){
return
}
var attributes = []
var styles = []
var sectionClass = []
var headerTitle = userSettings.headerTitle || lang[userSettings.name] || userSettings.name
if(userSettings.hidden === true){
styles.push('display:none')
}
if(userSettings.style){
styles.push(userSettings.style)
}
if(userSettings.isSection === true){
attributes.push('section')
}
if(userSettings.attribute){
attributes.push(userSettings.attribute)
}
if(userSettings.id){
attributes.push(`id="${userSettings.id}"`)
}else{
var userSettingsId
if(userSettings.name){
userSettingsId = userSettings.name.replace(/[^a-zA-Z ]/g, '').replace(/[^a-zA-Z ]/g, '').replace(/ /g, '')
}else{
userSettingsId = "NO NAME"
}
userSettings.id = userSettingsId
attributes.push(`id="${userSettingsId}"`)
}
if(userSettings.color){
sectionClass.push(userSettings.color)
}
if(userSettings['section-class']){
sectionClass.push(userSettings['section-class'])
}
if(userSettings.isAdvanced){ %>
<div class="h_us_input h_us_advanced">
<% }
if(userSettings['section-pre-pre-class']){ %>
<div class="<%- userSettings['section-pre-pre-class'] %>">
<% }
if(userSettings['section-pre-class']){ %>
<div class="<%- userSettings['section-pre-class'] %>">
<% }
%>
<div <%- attributes.join(' ') %> style="<%- styles.join(';') %>" class="form-group-group <%- sectionClass.join(' ') %>">
<h4 class="<%- userSettings.headerClass %>"><%- headerTitle %>
<% if(userSettings.headerButtons){ %>
<div class="pull-right">
<% userSettings.headerButtons.forEach(function(button){ %>
<a class="btn btn-success btn-xs <%- button.class %>">
<% if(button.icon){ %><i class="fa fa-<%- button.icon %>"></i><% } %>
<% if(button.text){ %><%- button.text %><% } %>
</a>
<% }) %>
</select>
</div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Alert Sound']%></span></div>
<div>
<select class="form-control" detail="audio_alert">
<option value="" selected>No Sound</option>
<% audioFiles.forEach(function(v,n){ %>
<option value="<%-v%>"><%-v%></option>
<% }) %>
</select>
</div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Alert Sound Delay']%></span></div>
<div><input class="form-control" detail="audio_delay" placeholder="1"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Popout Monitor on Event']%></span></div>
<div><select class="form-control" detail="event_mon_pop">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
</div>
<% } %>
</h4>
<% if(userSettings['input-mapping']){ %>
<div class="form-group-group forestgreen" style="display:none" input-mapping="<%- userSettings['input-mapping'] %>">
<h4><%-lang['Input Feed']%>
<div class="pull-right">
<a class="btn btn-success btn-xs add_map_row"><i class="fa fa-plus-square-o"></i></a>
</div>
</h4>
<div class="choices"></div>
</div>
<% } %>
<% if(userSettings.blockquote){ %>
<blockquote class="<%- userSettings.blockquoteClass || '' %>">
<%- userSettings.blockquote %>
</blockquote>
<% } %>
<%
if(userSettings.blocks){
userSettings.blocks.forEach(function(settingsBlock){
drawBlock(settingsBlock)
})
}
if(userSettings.info){
userSettings.info.forEach(function(field){
if(field.isFormGroupGroup === true){
drawBlock(field)
}else{
if(field.notForSubAccount === true){
var notForSubAccount = '!details.sub'
if(!field.evaluation){
field.evaluation = notForSubAccount
}else{
field.evaluation += ' && ' + notForSubAccount
}
}
if(field.evaluation && !eval(field.evaluation)){
return
}
var hidden = ''
if(field.hidden === true){
hidden = 'style="display:none"'
}
var fieldClass = []
var attributes = []
if(field.name && field.name.indexOf('detail=') > -1){
attributes.push(field.name)
}else if(field.name){
attributes.push("name=" + field.name)
}
if(field.placeholder || field.default){
attributes.push(`placeholder="${field.placeholder || field.default}"`)
}else if(field.example){
attributes.push(`placeholder="Example : ${field.example}"`)
}
if(field.attribute){
attributes.push(field.attribute)
}
if(field.selector){
attributes.push(`selector="${field.selector}"`)
}
if(field.id){
attributes.push(`id="${field.id}"`)
}
if(field.class){
fieldClass.push(`${field.class}`)
}
var possiblities = field.possible || []
var fieldType = field.fieldType || 'text'
var fieldElement = ''
var preFill = field.preFill || ''
switch(fieldType){
case'btn':
fieldElement = `<a class="btn btn-block ${fieldClass.join(' ')}" ${attributes.join(' ')}>${field.btnContent}</a>`
break;
case'ul':
fieldElement = `<ul ${attributes.join(' ')} class="${fieldClass.join(' ')}" ></ul>`
break;
case'div':
fieldElement = `<div ${attributes.join(' ')} class="${fieldClass.join(' ')}" ></div>`
break;
case'number':
if(field.numberMin){
attributes.push(`min="${field.numberMin}"`)
}
if(field.numberMax){
attributes.push(`max="${field.numberMax}"`)
}
fieldElement = '<div><input type="number" class="form-control" ' + attributes.join(' ') + '></div>'
break;
case'password':
fieldElement = '<div><input type="password" class="form-control" ' + attributes.join(' ') + '></div>'
break;
case'text':
fieldElement = `<div><input class="form-control" ${attributes.join(' ')} value="${preFill}"></div>`
break;
case'textarea':
fieldElement = '<div><textarea class="form-control" ' + attributes.join(' ') + '></textarea></div>'
break;
case'select':
fieldElement = '<div><select class="form-control" ' + attributes.join(' ') + '>'
fieldElement += buildOptions(field,possiblities)
fieldElement += '</select></div>'
break;
}
if(field.isAdvanced){ %>
<div class="h_us_input h_us_advanced">
<% }
if(field['form-group-class-pre-pre-layer']){ %>
<div class="<%- field['form-group-class-pre-pre-layer'] %>">
<% }
if(field['form-group-class-pre-layer']){ %>
<div class="<%- field['form-group-class-pre-layer'] %>">
<% }
if(fieldType === 'ul' || fieldType === 'div' || fieldType === 'btn'){ %>
<%- fieldElement %>
<% }else{ %>
<div <%- hidden %> class="form-group <%- field['form-group-class'] %>">
<label><div><span><%- field.field %>
<% if(field.description){ %>
<small><%- field.description %></small>
<% } %>
</span></div>
<%- fieldElement %>
</label>
</div>
<% }
}
if(field['form-group-class-pre-layer']){ %>
</div>
<% }
if(field['form-group-class-pre-pre-layer']){ %>
</div>
<% }
if(field.isAdvanced){ %>
</div>
<% }
})
}
%>
</div>
<% if(!details.sub){ %>
<div class="form-group-group blue">
<h4 class="mon_groups">
<%-lang['Monitor Groups']%>
<div class="pull-right">
<a class="btn btn-success btn-xs add"><i class="fa fa-plus"></i></a>
<a class="btn btn-danger btn-xs delete"><i class="fa fa-trash-o"></i></a>
</div>
</h4>
<div class="form-group">
<label><div><span><%-lang['Monitor Groups']%></span></div>
<div><select class="form-control" id="settings_mon_groups"></select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Group Name']%></span></div>
<div><input type="hidden" group="id">
<input class="form-control" group="name"></div>
</label>
</div>
<input type="hidden" detail="mon_groups">
<%
if(userSettings['section-pre-class']){ %>
</div>
<% if(details.use_webdav!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang.WebDAV%></h4>
<div class="form-group">
<label><div><span><%-lang.Autosave%></span></div>
<div><select class="form-control" detail="webdav_save" selector="autosave_webdav">
<option value="0"><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="autosave_webdav_input autosave_webdav_1">
<div class="form-group">
<label><div><span><%-lang.URL%></span></div>
<div><input class="form-control" detail="webdav_url"></div>
</label>
</div>
<div class="row">
<div class="form-group col-md-12">
<label><div><span><%-lang.Username%></span></div>
<div><input class="form-control" detail="webdav_user"></div>
</label>
</div>
<div class="form-group col-md-12">
<label><div><span><%-lang.Password%></span></div>
<div><input class="form-control" type="password" detail="webdav_pass"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Links to Database']%></span></div>
<div><select class="form-control" detail="webdav_log" selector="h_webdavsld">
<option value="0"><%-lang.No%></option>
<option value="1" selected><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="h_webdavsld_input h_webdavsld_1">
<div class="form-group">
<label><div><span><%-lang['Use Max Storage Amount']%></span></div>
<div><select class="form-control" detail="use_webdav_size_limit" selector="h_webdavzl">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group h_webdavzl_input h_webdavzl_1">
<label><div><span><%-lang['Max Storage Amount']%></span></div>
<div><input class="form-control" placeholder="10000" detail="webdav_size_limit"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Directory']%></span></div>
<div><input class="form-control" placeholder="/" detail="webdav_dir"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_aws_s3!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang['Amazon S3']%></h4>
<div class="form-group">
<label><div><span><%-lang.Autosave%></span></div>
<div><select class="form-control" detail="aws_s3_save" selector="autosave_aws_s3">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="autosave_aws_s3_input autosave_aws_s3_1">
<div class="form-group">
<label><div><span><%-lang.Bucket%></span></div>
<div><input class="form-control" detail="aws_s3_bucket" placeholder="Example : slippery-seal"></div>
</label>
</div>
<div class="row">
<div class="form-group col-md-12">
<label><div><span><%-lang.aws_accessKeyId%></span></div>
<div><input class="form-control" detail="aws_accessKeyId"></div>
</label>
</div>
<div class="form-group col-md-12">
<label><div><span><%-lang.aws_secretAccessKey%></span></div>
<div><input class="form-control" type="password" detail="aws_secretAccessKey"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang.Region%></span></div>
<div><select class="form-control" detail="aws_region">
<option value="us-west-1" selected>US West (N. California)</option>
<option value="us-west-2">US West (Oregon)</option>
<option value="us-east-2">US East (Ohio)</option>
<option value="us-east-1">US East (N. Virginia)</option>
<option value="ap-south-1">Asia Pacific (Mumbai)</option>
<option value="ap-northeast-2">Asia Pacific (Seoul)</option>
<option value="ap-northeast-3">Asia Pacific (Osaka-Local)**</option>
<option value="ap-southeast-1">Asia Pacific (Singapore)</option>
<option value="ap-southeast-2">Asia Pacific (Sydney)</option>
<option value="ap-northeast-1">Asia Pacific (Tokyo)</option>
<option value="ca-central-1">Canada (Central)</option>
<option value="cn-north-1">China (Beijing)</option>
<option value="cn-northwest-1">China (Ningxia)</option>
<option value="eu-central-1">EU (Frankfurt)</option>
<option value="eu-west-1">EU (Ireland)</option>
<option value="eu-west-2">EU (London)</option>
<option value="eu-west-3">EU (Paris)</option>
<option value="sa-east-1">South America (São Paulo)</option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Links to Database']%></span></div>
<div><select class="form-control" detail="aws_s3_log" selector="h_s3sld">
<option value="0"><%-lang.No%></option>
<option value="1" selected><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="h_s3sld_input h_s3sld_1">
<div class="form-group">
<label><div><span><%-lang['Use Max Storage Amount']%></span></div>
<div><select class="form-control" detail="use_aws_s3_size_limit" selector="h_s3zl">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group h_s3zl_input h_s3zl_1">
<label><div><span><%-lang['Max Storage Amount']%></span></div>
<div><input class="form-control" placeholder="10000" detail="aws_s3_size_limit"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Directory']%></span></div>
<div><input class="form-control" placeholder="" detail="aws_s3_dir"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_bb_b2!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang['Backblaze B2']%></h4>
<div class="form-group">
<label><div><span><%-lang.Autosave%></span></div>
<div><select class="form-control" detail="bb_b2_save" selector="autosave_bb_b2">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="autosave_bb_b2_input autosave_bb_b2_1">
<div class="form-group">
<label><div><span><%-lang.Bucket%></span></div>
<div><input class="form-control" detail="bb_b2_bucket" placeholder="Example : slippery-seal"></div>
</label>
</div>
<div class="row">
<div class="form-group col-md-12">
<label><div><span><%-lang.accountId%></span></div>
<div><input class="form-control" detail="bb_b2_accountId"></div>
</label>
</div>
<div class="form-group col-md-12">
<label><div><span><%-lang.applicationKey%></span></div>
<div><input class="form-control" type="password" detail="bb_b2_applicationKey"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Links to Database']%></span></div>
<div><select class="form-control" detail="bb_b2_log" selector="h_b2sld">
<option value="0"><%-lang.No%></option>
<option value="1" selected><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="h_b2sld_input h_b2sld_1">
<div class="form-group">
<label><div><span><%-lang['Use Max Storage Amount']%></span></div>
<div><select class="form-control" detail="use_bb_b2_size_limit" selector="h_b2zl">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group h_b2zl_input h_b2zl_1">
<label><div><span><%-lang['Max Storage Amount']%></span></div>
<div><input class="form-control" placeholder="10000" detail="bb_b2_size_limit"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Directory']%></span></div>
<div><input class="form-control" placeholder="" detail="bb_b2_dir"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_whcs!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang['Wasabi Hot Cloud Storage']%></h4>
<div class="form-group">
<label><div><span><%-lang.Autosave%></span></div>
<div><select class="form-control" detail="whcs_save" selector="autosave_whcs">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="autosave_whcs_input autosave_whcs_1">
<div class="form-group">
<label><div><span><%-lang.Bucket%></span></div>
<div><input class="form-control" detail="whcs_bucket" placeholder="Example : slippery-seal"></div>
</label>
</div>
<div class="row">
<div class="form-group col-md-12">
<label><div><span><%-lang.aws_accessKeyId%></span></div>
<div><input class="form-control" detail="whcs_accessKeyId"></div>
</label>
</div>
<div class="form-group col-md-12">
<label><div><span><%-lang.aws_secretAccessKey%></span></div>
<div><input class="form-control" type="password" detail="whcs_secretAccessKey"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang.Region%></span></div>
<div><select class="form-control" detail="whcs_region">
<option value="us-west-1" selected>US West</option>
<option value="us-east-1">US East</option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Links to Database']%></span></div>
<div><select class="form-control" detail="whcs_log" selector="h_whcssld">
<option value="0"><%-lang.No%></option>
<option value="1" selected><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="h_whcssld_input h_whcssld_1">
<div class="form-group">
<label><div><span><%-lang['Use Max Storage Amount']%></span></div>
<div><select class="form-control" detail="use_whcs_size_limit" selector="h_whcszl">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group h_whcszl_input h_whcszl_1">
<label><div><span><%-lang['Max Storage Amount']%></span></div>
<div><input class="form-control" placeholder="10000" detail="whcs_size_limit"></div>
</label>
</div>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Directory']%></span></div>
<div><input class="form-control" placeholder="" detail="whcs_dir"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_sftp!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang['SFTP (SSH File Transfer)']%></h4>
<div class="form-group">
<label><div><span><%-lang.Autosave%></span></div>
<div><select class="form-control" detail="sftp_save" selector="autosave_sftp">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="autosave_sftp_input autosave_sftp_1">
<div class="form-group">
<label><div><span><%-lang.Host%></span></div>
<div><input class="form-control" detail="sftp_host"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.Port%></span></div>
<div><input class="form-control" type="text" detail="sftp_port"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.Username%></span></div>
<div><input class="form-control" type="text" detail="sftp_username"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.Password%></span></div>
<div><input class="form-control" type="password" detail="sftp_password"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang.privateKey%></span></div>
<div><textarea class="form-control" type="password" detail="sftp_privateKey"></textarea></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Save Directory']%></span></div>
<div><input class="form-control" placeholder="" detail="sftp_dir"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_discordbot!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang['Discord Bot']%></h4>
<div class="form-group">
<label><div><span><%-lang.Enabled%></span></div>
<div><select class="form-control" detail="discordbot" selector="u_discord_bot">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="u_discord_bot_input u_discord_bot_1">
<div class="form-group">
<label><div><span><%-lang.Token%></span></div>
<div><input type="password" class="form-control" placeholder="XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXX_XXXXXXXXXXXXXXXXXX" detail="discordbot_token"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Channel ID']%></span></div>
<div><input class="form-control" placeholder="xxxxxxxxxxxxxxxxxx" detail="discordbot_channel"></div>
</label>
</div>
</div>
</div>
<% } %>
<% if(details.use_ldap!=='0'){ %>
<div class="form-group-group forestgreen">
<h4><%-lang.LDAP%></h4>
<div class="form-group">
<label><div><span><%-lang.Enable%></span></div>
<div><select class="form-control" detail="ldap_enable" selector="ldap_i">
<option value="0"><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="ldap_i_input ldap_i_1" style="display:none">
<div class="form-group">
<label><div><span><%-lang.URL%></span></div>
<div><input class="form-control" detail="ldap_url"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['bindDN']%></span></div>
<div><input class="form-control" detail="ldap_bindDN" placeholder="<%-lang.Example%> : cn=admin,dc=test,dc=com"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Bind Credentials']%></span></div>
<div><input class="form-control" detail="ldap_bindCredentials"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Search Filter']%></span></div>
<div><input class="form-control" detail="ldap_searchFilter" placeholder="cn={{username}}"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Search Base']%></span></div>
<div><input class="form-control" detail="ldap_searchBase" placeholder="dc=test,dc=com"></div>
</label>
</div>
</div>
</div>
<% } %>
<% } %>
<div class="form-group-group navy">
<h4><%-lang.Preferences%></h4>
<div class="form-group">
<label><div><span><%-lang.CSS%></span></div>
<div><textarea class="form-control" placeholder="#main_header{background:#b59f00}" detail="css"></textarea></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Force Monitors Per Row']%></span></div>
<div><select class="form-control" localStorage="montage_use" selector="st_force_mon_rows">
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
</select></div>
</label>
</div>
<div class="form-group st_force_mon_rows_input st_force_mon_rows_1">
<label><div><span><%-lang['Monitors per row']%></span></div>
<div><input class="form-control" placeholder="3" localStorage="montage"></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Browser Console Log']%></span></div>
<div><select class="form-control" localStorage="browserLog">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Get Logs to Client']%></span></div>
<div><select class="form-control" detail="get_server_log">
<option value="1" selected><%-lang.Yes%></option>
<option value="0"><%-lang.No%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Show Thumbnails in Video List']%></span></div>
<div><select class="form-control" localStorage="showThumbnail">
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Themes']%></span></div>
<div><select class="form-control" detail="theme">
<option value="" selected>Default</option>
<% fs.readdirSync(__dirname+'/web/libs/themes').forEach(function(v){ %>
<option value="<%-v%>"><%-v%></option>
<% }) %>
</select></div>
</label>
</div>
</div>
<% }
if(userSettings['section-pre-pre-class']){ %>
</div>
<% }
if(userSettings.isAdvanced){ %>
</div>
<% }
}
%>
<% Object.keys(define['Account Settings'].blocks).forEach(function(blockKey){
var accountSettings = define['Account Settings'].blocks[blockKey]
drawBlock(accountSettings)
}) %>
<div class="form-group-group green linkShinobi">
<h4><%-lang['Link Shinobi']%><div class="pull-right"><a class="btn btn-success btn-xs add"><i class="fa fa-plus"></i></a></div></h4>
<div id="linkShinobi"></div>
</div>
<input type="hidden" name="details">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
<button type="submit" class="btn btn-success"><i class="fa fa-check"></i> <%-lang.Save%></button>

View file

@ -15,32 +15,40 @@
<div class="form-group">
<label><div><span><%-lang['All Monitors and Privileges']%></span></div>
<div><select class="form-control" detail="allmonitors">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group permission-view">
<label><div><span><%-lang['Can Create and Delete Monitors']%></span></div>
<div><select class="form-control" detail="monitor_create">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group permission-view">
<label><div><span><%-lang['Can Change User Settings']%></span></div>
<div><select class="form-control" detail="user_change">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Can View Logs']%></span></div>
<div><select class="form-control" detail="view_logs">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Landing Page']%></span></div>
<div><select class="form-control" detail="landing_page">
<option value="" selected><%-lang.Default%></option>
<option value="timelapse"><%-lang.Timelapse %></option>
</select></div>
</label>
</div>
@ -57,8 +65,8 @@
<div class="form-group">
<label><div><span><%- v.name %></span></div>
<div><select class="form-control" monitor="monitors" mid="<%- v.mid %>">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -76,8 +84,8 @@
<div class="form-group">
<label><div><span><%- v.name %></span></div>
<div><select class="form-control" monitor="monitor_edit" mid="<%- v.mid %>">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -95,8 +103,8 @@
<div class="form-group">
<label><div><span><%- v.name %></span></div>
<div><select class="form-control" monitor="video_view" mid="<%- v.mid %>">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -114,8 +122,8 @@
<div class="form-group">
<label><div><span><%- v.name %></span></div>
<div><select class="form-control" monitor="video_delete" mid="<%- v.mid %>">
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
<option value="0" selected><%-lang.No%></option>
<option value="1"><%-lang.Yes%></option>
</select></div>
</label>
</div>
@ -129,4 +137,4 @@
<input type="hidden" name="details">
</form>
</div>
</div>
</div>

View file

@ -1,81 +1,66 @@
<!--Timelapse Window-->
<div class="modal full fade dark" id="timelapse" role="dialog" aria-labelledby="timelapseLabel" aria-hidden="true">
<div class="modal full fade dark" id="timelapsejpeg" role="dialog" aria-labelledby="timelapsejpegLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="timelapseLabel"><i class="fa fa-angle-double-right"></i> &nbsp; <span><%-lang['Time-lapse Tool']%></span></h4>
</div>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="timelapsejpegLabel"><i class="fa fa-angle-double-right"></i> &nbsp; <span><%-lang['Timelapse']%></span></h4>
</div>
<div class="modal-body text-center">
<div class="row">
<div class="col-md-8">
<div class="timelapse_hud">
<div class="timelapse_playRate hover-hide"></div>
<div class="controlBar hover-hide">
<div class="form-group">
<div class="progress" id="timelapse_seekBar">
<div class="progress-bar progress-bar-warning" role="progressbar" style="width:0%"></div>
</div>
</div>
<div>
<div class="form-group monospace">
<div class="btn-group timelapseSpeedUseBasicSwitch">
<a timelapse="stepBackBack" class="active btn btn-primary">&nbsp;<i class="fa fa-backward"></i>&nbsp;</a>
<a timelapse="stepBack" class="btn btn-primary">&nbsp;<i class="fa fa-arrow-circle-o-left"></i>&nbsp;</a>
</div>
<div class="btn-group">
<a timelapse="play" class="btn btn-default">&nbsp;<i class="fa fa-play"></i>&nbsp;</a>
<a timelapse="mute" class="btn btn-default">&nbsp;<i class="fa fa-volume-up"></i>&nbsp;</a>
</div>
<div class="btn-group">
<a timelapse="stepFront" class="btn btn-primary">&nbsp;<i class="fa fa-arrow-circle-o-right"></i>&nbsp;</a>
<a timelapse="stepFrontFront" class="active btn btn-primary">&nbsp;<i class="fa fa-forward"></i>&nbsp;</a>
</div>
<a timelapse="download" class="btn btn-info">&nbsp;<i class="fa fa-download"></i>&nbsp;</a>
<div class="btn-group">
<a timelapse="setPlayBackRate" playRate="1" class="btn btn-default">1</a>
<a timelapse="setPlayBackRate" playRate="5" class="btn btn-default">5</a>
<a timelapse="setPlayBackRate" playRate="15" class="btn btn-default">15</a>
</div>
<div class="btn-group timelapseSpeedUseBasicSwitch">
<a timelapse="setPlayBackRate" playRate="30" class="btn btn-default">30</a>
<a timelapse="setPlayBackRate" playRate="60" class="btn btn-default">60</a>
<a timelapse="setPlayBackRate" playRate="120" class="btn btn-default">120</a>
</div>
</div>
<div class="marc-toggle abs-bot-left">
<input title="<%-lang['Use HTML5 Play Method']%>" type="checkbox" id="timelapseSpeedUseBasic"/><label for="timelapseSpeedUseBasic"><%-lang['Use HTML5 Play Method']%></label>
</div>
</div>
<div class="col-md-4">
<div class="fieldHolder text-left">
<div class="form-group text-center">
<%
var logoImageLink
if(config.logoLocation76x76.indexOf('//') === -1){
logoImageLink = window.libURL + config.logoLocation76x76
}else{
logoImageLink = config.logoLocation76x76
}
%>
<img src="<%- logoImageLink %>" style="<%- config.logoLocation76x76Style %>">
</div>
<div class="form-group">
<label><div><span><%-lang['Monitor']%></span></div>
<div><select class="form-control dark monitors_list"></select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Date']%></span></div>
<div><input type="text" id="timelapsejpeg_date" class="form-control" value="" /></div>
</label>
</div>
<div class="form-group">
<input id="timelapseJpegFps" data-slider-id='timelapseJpegFps' type="text"
data-slider-min="1" data-slider-max="30" data-slider-step="1" data-slider-value="30" value="30"/>
</div>
<div class="form-group">
<!-- <div class="btn-group"> -->
<!-- <a class="btn btn-primary download_mp4"><%-lang['Build']%></a> -->
<a class="btn btn-danger btn-block download_mp4"><%-lang['Download']%></a>
<!-- </div> -->
</div>
<div id="timelapse_video_display"></div>
</div>
<div class="">
</div>
<div class="frameIcons row scroll-style-6"></div>
</div>
<div class="col-md-8 frameStripContainer contained">
<div class="playBackView"><img></div>
<div class="liveStreamView"></div>
</div>
<form class="col-md-4">
<div class="form-group">
<label><div><span><%-lang.Monitor%></span></div>
<div><select class="form-control monitors_list"></select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Date Range']%></span></div>
<div><input type="text" id="timelapse_daterange" class="form-control" value="" /></div>
</label>
</div>
<div class="form-group">
<ul id="timelapse_video_line" class="list-group"></ul>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<div class="btn-group">
<button type="button" class="btn btn-default" data-dismiss="modal"><%-lang.Close%></button>
</div>
</div>
<div class="modal-footer">
<div class="btn-group">
<button type="button" class="btn btn-default" data-dismiss="modal"><%-lang.Close%></button>
</div>
</div>
</div>
</div>
</div>
<script src="<%-window.libURL%>libs/js/dash2.timelapse.js"></script>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.timelapse.jpeg.css">
<script src="<%-window.libURL%>libs/js/dash2.timelapse.jpeg.js"></script>

View file

@ -4,7 +4,7 @@
<% include blocks/header %>
<script>var $user = <%- JSON.stringify($user) %>;</script>
<script>var lang = <%- JSON.stringify(lang) %>;</script>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/roboto.css" type="text/css" />
<script>var addStorage = <%- JSON.stringify(addStorage) %>;</script>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/material-design-iconic-font.min.css" type="text/css" />
<link rel="stylesheet" href="<%-window.libURL%>libs/css/pnotify.custom.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/vbox.css">
@ -16,19 +16,19 @@
<link rel="stylesheet" href="<%-window.libURL%>libs/css/gridstack.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/gridstack-extra.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap-table.min.css">
<!--
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap-slider.min.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.basic.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.misc.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.monitors.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.monitorStates.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.forms.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.modal.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.monitors.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.powervideo.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.ptzcontrols.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.regioneditor.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.rightotleft.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.timelapse.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.css">
-->
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.old.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.righttoleft.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.sidemenu.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.darktheme.css">
<% customAutoLoad.LibsCss.forEach(function(lib){ %>
<link rel="stylesheet" href="<%-window.libURL%>libs/css/<%-lib%>">
<% }) %>
@ -56,7 +56,7 @@
<ul class="nav navbar-nav">
<li title="<%-lang['Toggle Sidebar']%>" class_toggle="hide-side" data-target=".mdl-js-layout"><a>&nbsp;<i class="fa fa-bars"></i>&nbsp;</a></li>
<li title="<%-lang['Add Monitor']%>" mid="" ke="" class="hidden-xs permission_monitor_create"><a monitor="edit">&nbsp;<i class="fa fa-plus"></i>&nbsp;</a></li>
<li title="<%-lang['Power Video Viewer']%>" class="hidden-xs" mid="" ke=""><a monitor="powerview">&nbsp;<i class="fa fa-map-marker"></i>&nbsp;</a></li>
<li title="<%-lang['Power Video Viewer']%>" class="hidden-xs" data-toggle="modal" data-target="#powerVideo"><a>&nbsp;<i class="fa fa-map-marker"></i>&nbsp;</a></li>
<li>
<a title="<%-lang['Monitor Groups']%>" id="group_list_button" class="mdl-js-button">&nbsp;<i class="fa fa-video-camera"></i>&nbsp;</a>
<ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effect" for="group_list_button" id="group_list"></ul>
@ -101,16 +101,31 @@
</ul>
</div>
</li>
<li role="presentation" class="dropdown">
<li role="presentation" class="dropdown hidden-xs">
<a href="javascript:;" class="dropdown-toggle info-number" data-toggle="dropdown" aria-expanded="true">&nbsp;<i class="fa fa-group"></i>&nbsp;</a>
<ul id="users_online" class="dropdown-menu list-unstyled msg_list scrollable" role="menu"></ul>
</li>
<!--
<li role="presentation" class="dropdown">
<a href="javascript:;" class="dropdown-toggle info-number" data-toggle="dropdown" aria-expanded="true">&nbsp;<i class="fa fa-info-circle"></i>&nbsp;</a>
<ul id="notifications" class="dropdown-menu list-unstyled msg_list scrollable" role="menu"></ul>
<a href="javascript:;" class="dropdown-toggle info-number" data-toggle="dropdown" aria-expanded="true">&nbsp;<i class="fa fa-hdd-o"></i>&nbsp;</a>
<ul id="diskUsedList" class="dropdown-menu list-unstyled msg_list scrollable" role="menu">
<% addStorage.forEach(function(storage){ %>
<li class="log-item" storage="<%- storage.name %>">
<span>
<div class="title"><%- storage.name %></div>
<span class="pull-right percent"></span>
<label><span class="value"></span></label>
</span>
<div class="message">
<div class="progress">
<div class="progress-bar progress-bar-warning" role="progressbar"></div>
</div>
</div>
</li>
<% }) %>
</ul>
</li>
-->
<li role="presentation" class="dropdown">
<a href="javascript:;" class="dropdown-toggle info-number" data-toggle="dropdown" aria-expanded="true">&nbsp;<i class="fa fa-exclamation-triangle"></i>&nbsp;</a>
<ul id="logs" class="dropdown-menu list-unstyled msg_list scrollable" role="menu">
@ -125,8 +140,8 @@
<button id="accbtn" style="color:#fff" class="mdl-button mdl-js-button mdl-js-ripple-effect"><i class="fa fa-caret-down"></i> &nbsp;<span class="usermail"></span></button>
<ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effect" for="accbtn">
<li class="mdl-menu__item" data-toggle="modal" data-target="#multi_mon"><div><i class="fa fa-clone"></i><div><%- lang['Monitors'] %></div></div></li>
<li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="powerview"><i class="fa fa-map-marker"></i><div><%- lang['Power Viewer'] %></div></div></li>
<li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="timelapse"><i class="fa fa-angle-double-right"></i><div><%- lang['Time-lapse'] %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#powerVideo"><div><i class="fa fa-map-marker"></i><div><%- lang['Power Viewer'] %></div></div></li>
<li class="mdl-menu__item" mid="" ke=""><div class="flex" monitor="timelapseJpeg"><i class="fa fa-angle-double-right"></i><div><%- lang['Timelapse'] %></div></div></li>
<li class="mdl-menu__item permission_user_change" data-toggle="modal" data-target="#settings"><div><i class="fa fa-gears"></i><div><%- lang.Settings %></div></div></li>
<li class="mdl-menu__item" data-toggle="modal" data-target="#apis"><div><i class="fa fa-code"></i><div><%- lang.API %></div></div></li>
<% if(!details.sub){ %>
@ -154,7 +169,7 @@
</header>
<nav class="demo-navigation mdl-navigation side-menu" id="left_menu">
<div class="form-group col-md-12">
<input class="form-control dark" placeholder="Search Monitors" id="monitors_list_search">
<input class="form-control dark" placeholder="<%- lang.Search %> <%- lang.Monitors %>" id="monitors_list_search">
</div>
<div id="monitors_list" class="display-table"></div>
<div class="mdl-layout-spacer"></div>
@ -173,7 +188,6 @@
<% include blocks/logs.ejs %>
<% include blocks/settings.ejs %>
<% include blocks/filters.ejs %>
<% include blocks/powervideo.ejs %>
<% include blocks/timelapse.ejs %>
<% include blocks/videoview.ejs %>
<% include blocks/monitoredit.ejs %>
@ -183,6 +197,7 @@
<% include blocks/monitorStates.ejs %>
<% include blocks/schedules.ejs %>
<% include blocks/confirm.ejs %>
<% include blocks/help.ejs %>
<% customAutoLoad.PageBlocks.forEach(function(block){ %>
<%- include(block) %>
<% }) %>
@ -200,13 +215,16 @@
<script src="<%-window.libURL%>libs/js/bootstrap-table.min.js"></script>
<script src="<%-window.libURL%>libs/js/socket.io.js"></script>
<script src="<%-window.libURL%>libs/js/fullcalendar.min.js"></script>
<script src="<%-window.libURL%>libs/js/locale-all.js"></script>
<script src="<%-window.libURL%>libs/js/hls.min.js"></script>
<script src="<%-window.libURL%>libs/js/libde265.min.js"></script>
<script src="<%-window.libURL%>libs/js/bootstrap-slider.min.js"></script>
<script type="text/javascript" src="<%-window.libURL%>libs/js/flv.shinobi.js">;</script>
<script src="<%-window.libURL%>libs/js/jszip.min.js"></script>
<script src="<%-window.libURL%>libs/js/dash2.downloadAndZip.js"></script>
<script src="<%-window.libURL%>libs/js/menu.js"></script>
<script src="<%-window.libURL%>libs/js/clock.js"></script>
<script src="<%-window.libURL%>libs/js/poseidon.js"></script>
<script src="<%-window.libURL%>libs/js/Chart.js"></script>
<script src="<%-window.libURL%>libs/js/clusterPoints.js"></script>
<script src="<%-window.libURL%>libs/js/daterangepicker.js"></script>
<script src="<%-window.libURL%>libs/js/jquery.canvasAreaDraw.js"></script>
@ -228,3 +246,4 @@
<script src="<%-window.libURL%>libs/js/<%-lib%>"></script>
<% }) %>
<% include blocks/help.ejs %>
<% include blocks/powerVideo2.ejs %>

View file

@ -6,21 +6,30 @@
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-login">
<div class="panel-heading">
<div class="panel-heading-shade">
<div class="row">
<div class="col-xs-12">
<a href="http://shinobi.video" target="_blank">
<img src="<%-window.libURL%>libs/img/icon/apple-touch-icon-76x76.png" style="border-radius:50%">
</a>
<% if(config.showLoginCardHeader === true){
var logoImageLink
if(config.logoLocation76x76.indexOf('//') === -1){
logoImageLink = window.libURL + config.logoLocation76x76
}else{
logoImageLink = config.logoLocation76x76
}
%>
<div class="panel-heading">
<div class="panel-heading-shade">
<div class="row">
<div class="col-xs-12">
<a href="<%- config.logoLocation76x76Link %>" target="_blank">
<img src="<%- logoImageLink %>" style="<%- config.logoLocation76x76Style %>">
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<% } %>
<div class="panel-body">
<div class="row">
<div class="col-lg-12">
<form id="login-form" method="post" style="display: block;">
<form id="login-form" method="post" style="display: block;margin:0">
<input type="hidden" name="machineID" id="machineID" value="">
<% var message,timeLeft;if(message){ %>
<div class="form-group text-center monospace">
@ -28,48 +37,68 @@
</div>
<% } %>
<div class="form-group">
<input type="text" name="mail" id="email" tabindex="1" class="monospace form-control" placeholder="Email" value="">
<input type="text" name="mail" id="email" tabindex="1" class="monospace form-control" placeholder="<%- lang.Email %>" value="">
</div>
<div class="form-group">
<input type="password" name="pass" id="pass" tabindex="2" class="monospace form-control" placeholder="Password">
<input type="password" name="pass" id="pass" tabindex="2" class="monospace form-control" placeholder="<%- lang.Password %>">
</div>
<div class="form-group f_i_input f_i_ldap" style="display:none">
<input name="key" id="key" tabindex="2" class="monospace form-control" placeholder="Group Key">
</div>
<div class="form-group">
<div class="row">
<div class="col-md-12 monospace" style="width:calc(100% - 48px)">
<select class="form-control" name="function" selector="f_i">
<% switch(screen){
case'super': %>
<option value="super"><%- lang.Superuser %></option>
<% break;
case'admin': %>
<option value="admin"><%- lang.Admin %></option>
<% break;
default: %>
<option value="dash" selected><%- lang.Dashboard %></option>
<% if(config.productType==='Pro'){ %>
<option value="ldap"><%- lang.LDAP %></option>
<% } %>
<option value="streamer"><%- lang.Streamer %></option>
<option value="cam"><%- lang.Dashcam %> (<%- lang.Streamer %> v2)</option>
<% break;
} %>
</select>
</div>
<div class="text-right" title="<%- lang['Remember Me'] %>" style="display:inline-block">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="remember_me">
<input type="checkbox" id="remember_me" value="1" name="remember" class="mdl-switch__input">
<span class="monospace mdl-switch__label"></span>
</label>
</div>
</div>
</div>
<div class="form-group" style="margin:20px"></div>
<div class="form-group">
<% if(config.showLoginSelector === true){ %>
<div class="form-group">
<div class="row">
<div class="col-md-12 monospace" style="width:calc(100% - 48px)">
<select class="form-control" name="function" selector="f_i">
<% switch(screen){
case'super': %>
<option value="super"><%- lang.Superuser %></option>
<% break;
case'admin': %>
<option value="admin"><%- lang.Admin %></option>
<% break;
default: %>
<option value="dash" selected><%- lang.Dashboard %></option>
<% if(config.productType==='Pro'){ %>
<option value="ldap"><%- lang.LDAP %></option>
<% } %>
<option value="streamer"><%- lang.Streamer %></option>
<option value="cam"><%- lang.Dashcam %> (<%- lang.Streamer %> v2)</option>
<% break;
} %>
</select>
</div>
<div class="text-right" title="<%- lang['Remember Me'] %>" style="display:inline-block">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="remember_me">
<input type="checkbox" id="remember_me" value="1" name="remember" class="mdl-switch__input">
<span class="monospace mdl-switch__label"></span>
</label>
</div>
</div>
</div>
<% }else{ %>
<select class="form-control" name="function" style="display:none">
<% switch(screen){
case'super': %>
<option value="super"><%- lang.Superuser %></option>
<% break;
case'admin': %>
<option value="admin"><%- lang.Admin %></option>
<% break;
default: %>
<option value="dash" selected><%- lang.Dashboard %></option>
<% break;
} %>
</select>
<% } %>
<div class="form-group" style="margin:0">
<button type="submit" name="login-submit" id="login-submit" tabindex="4" class="btn btn-success btn-block"><%- lang.Login %></button>
</div>
<% if(config.showPoweredByShinobi){ %>
<p style="<%- config.poweredByShinobiClass %>"><small><%- config.poweredByShinobi %></small></p>
<% }else{ %>
<!-- <%- config.poweredByShinobi %> -->
<% } %>
</form>
</div>
</div>

View file

@ -11,17 +11,22 @@
<link href="<%-window.libURL%>libs/css/montserrat.css" rel="stylesheet" />
<link href="<%-window.libURL%>libs/css/font-awesome.min.css" rel="stylesheet" />
<!-- CSS Files -->
<link href="<%-window.libURL%>libs/css/bootstrap4.min.css" rel="stylesheet" />
<link href="<%-window.libURL%>libs/css/main.dash2.css" rel="stylesheet" />
<link rel="stylesheet" href="<%-window.libURL%>libs/css/bootstrap4.min.css" />
<link rel="stylesheet" href="<%-window.libURL%>libs/css/main.dash2.css" />
<link rel="stylesheet" href="<%-window.libURL%>libs/css/pnotify.custom.min.css">
<link href="<%-window.libURL%>libs/css/now-ui-kit.css?v=1.1.0" rel="stylesheet" />
<link href="<%-window.libURL%>libs/css/super-page.css" rel="stylesheet" />
<link rel="stylesheet" href="<%-window.libURL%>libs/css/now-ui-kit.css?v=1.1.0" />
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.basic.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.modal.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/dash2.forms.css">
<link rel="stylesheet" href="<%-window.libURL%>libs/css/super-page.css" />
<script src="<%-window.libURL%>libs/js/jquery.min.js"></script>
<script src="<%-window.libURL%>libs/js/jquery-ui.min.js"></script>
<script src="<%-window.libURL%>libs/js/basic.js"></script>
<script src="<%-window.libURL%>libs/js/jquery.serialize.js"></script>
<script src="<%-window.libURL%>libs/js/pnotify.custom.min.js"></script>
<script src="<%-window.libURL%>libs/js/popper.min.js" type="text/javascript"></script>
<script src="<%-window.libURL%>libs/js/bootstrap4.min.js" type="text/javascript"></script>
<script src="<%-window.libURL%>libs/js/dash2.confirm.js" type="text/javascript"></script>
<style>
.form-group label>div:first-child{width:40%}
.list-group li .form-group {margin:0}
@ -67,16 +72,16 @@
<div id="main-card" class="card">
<ul class="nav nav-tabs nav-tabs-neutral justify-content-center bg-primary" id="tablist" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#accounts" role="tab">Accounts</a>
<a class="nav-link active" data-toggle="tab" href="#accounts" role="tab"><%-lang['Accounts']%></a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#config" role="tab">Configuration</a>
<a class="nav-link" data-toggle="tab" href="#config" role="tab"><%-lang['Configuration']%></a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#system" role="tab">Controls and Logs</a>
<a class="nav-link" data-toggle="tab" href="#system" role="tab"><%-lang['Controls and Logs']%></a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#changeSuperPreferences" role="tab">Preferences</a>
<a class="nav-link" data-toggle="tab" href="#changeSuperPreferences" role="tab"><%-lang['Preferences']%></a>
</li>
</ul>
<div class="card-body">
@ -89,7 +94,7 @@
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link add">
<p><i class="fa fa-plus-square-o"></i> Add Account</p>
<p><i class="fa fa-plus-square-o"></i> <%-lang['Add']%> <%-lang['Accounts']%></p>
</a>
</li>
</ul>
@ -128,7 +133,7 @@
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" system="deleteLogs">
<p><i class="fa fa-trash-o"></i> Clear Logs</p>
<p><i class="fa fa-trash-o"></i> <%-lang['Delete']%> <%-lang['Logs']%></p>
</a>
</li>
<li class="nav-item">
@ -146,13 +151,7 @@
<p><i class="fa fa-retweet"></i> <%-lang['Flush PM2 Logs']%></p>
</a>
</li>
<!--
<li class="nav-item">
<a class="nav-link" system="update">
<p><i class="fa fa-arrow-up"></i> <%-lang['Update']%></p>
</a>
</li>
-->
</ul>
</div>
</div>
@ -169,6 +168,15 @@
</div>
</div>
</div>
<div class="row text-center">
<div class="col">
<a href="https://gitlab.com/Shinobi-Systems/Shinobi/commit/<%- currentVersion %>" target="_blank">
<small class="epic-text" style="font-weight: 700;color: #fff;letter-spacing: 2pt;">
Current Version : <%- currentVersion %>
</small>
</a>
</div>
</div>
</div>
</div>
</div>
@ -221,10 +229,12 @@ switch($user.lang){
})
break;
}
$.ccio.ws=io(location.origin,{
$.ccio.ws = io(location.origin,{
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
});
$.ccio.cx=function(x){return $.ccio.ws.emit('super',x)}
})
$.ccio.cx = function(x){
return $.ccio.ws.emit('super',x)
}
$.ccio.ws.on('connect',function(d){
$.ccio.cx({f:'init',mail:$user.mail,pass:$user.pass})
})
@ -393,7 +403,7 @@ $.conf.f.submit(function(e){
e.html='<p>This is a change being applied to the configuration file (conf.json). Are you sure you want to do this? You must restart Shinobi for these changes to take effect. <b>The JSON below is what you are about to save.</b></p>'
e.html+='<pre>'+JSON.stringify($.parseJSON($.conf.draw.val()),null,3)+'</pre>'
$.confirm.body.html(e.html)
$.confirm.click({title:'Save',class:'btn-success'},function(){
$.confirm.click({title:lang.Save,class:'btn-success'},function(){
$.post('<%=originalURL%><%=config.webPaths.superApiPrefix%>'+$user.sessionKey+'/system/configure',{
data: $.conf.draw.val()
},function(data){
@ -459,10 +469,10 @@ $.system.e.find('[system]').click(function(e){
switch($(this).attr('system')){
case'deleteLogs':
$.confirm.e.modal('show');
$.confirm.title.html('Delete Logs <small>'+e.u+'</small>')
$.confirm.title.html('<%=lang['Delete Logs']%> <small>'+e.u+'</small>')
e.html='Do you want to delete these logs? User logs will <b>not</b> be deleted.'
$.confirm.body.html(e.html)
$.confirm.click({title:'Delete',class:'btn-danger'},function(){
$.confirm.click({title:lang.Delete,class:'btn-danger'},function(){
// $.ccio.cx({f:'logs',ff:'delete',ke:'$'})
$.get('<%=originalURL%><%=config.webPaths.superApiPrefix%>'+$user.sessionKey+'/logs/delete',function(data){
console.log(data)
@ -472,9 +482,9 @@ $.system.e.find('[system]').click(function(e){
break;
case'update':
$.confirm.e.modal('show')
$.confirm.title.html('Update Shinobi?')
$.confirm.title.html('<%=lang.Update%> Shinobi?')
$.confirm.body.html('Updating Shinobi means overwriting files. If you have modified any files yourself you should update Shinobi manually.')
$.confirm.click({title:'Update',class:'btn-danger'},function(){
$.confirm.click({title:lang.Update,class:'btn-danger'},function(){
// $.ccio.cx({f:'system',ff:'update'})
$.get('<%=originalURL%><%=config.webPaths.superApiPrefix%>'+$user.sessionKey+'/system/update',function(data){
console.log(data)
@ -501,9 +511,9 @@ $.system.e.find('[restart]').click(function(e){
break;
}
})
$.confirm.title.html('Restart?')
$.confirm.title.html('<%=lang.Restart%>?')
$.confirm.body.html(e.html)
$.confirm.click({title:'Restart',class:'btn-danger'},function(){
$.confirm.click({title:lang.Restart,class:'btn-danger'},function(){
// $.ccio.cx({f:'system',ff:'restart',target:e.target})
$.get('<%=originalURL%><%=config.webPaths.superApiPrefix%>'+$user.sessionKey+'/system/restart/'+encodeURIComponent(e.target),function(data){
console.log(data)

118
web/pages/timelapse.ejs Normal file
View file

@ -0,0 +1,118 @@
<%
if(config.ssl&&config.ssl.port&&data.protocol==='https'){
data.port=config.ssl.port
}else{
data.port=config.port
}
data.url = baseUrl
if(data.addon && data.addon.indexOf('relative')>-1){
data.url=''
}
%>
<% include blocks/header-title.ejs %>
<% include blocks/header-meta.ejs %>
<% include blocks/header-favicon.ejs %>
<link rel="stylesheet" href="<%=data.url%>/libs/css/font-awesome.min.css">
<link rel="stylesheet" href="<%=data.url%>/libs/css/bootstrap.min.css">
<link rel="stylesheet" href="<%-data.url%>/libs/css/daterangepicker.css">
<link rel="stylesheet" href="<%-data.url%>/libs/css/dash2.basic.css">
<link rel="stylesheet" href="<%-data.url%>/libs/css/dash2.forms.css">
<link rel="stylesheet" href="<%-data.url%>/libs/css/dash2.darktheme.css">
<link rel="stylesheet" href="<%-data.url%>/libs/css/bootstrap-slider.min.css">
<div id="timelapsejpeg" class="standalone dark">
<div class="modal-body text-center" style="padding-top:0;padding-bottom:0;">
<div class="row">
<div class="col-md-4">
<div class="fieldHolder text-left">
<div class="form-group text-center">
<%
var logoImageLink
if(config.logoLocation76x76.indexOf('//') === -1){
logoImageLink = window.libURL + config.logoLocation76x76
}else{
logoImageLink = config.logoLocation76x76
}
%>
<img src="<%- logoImageLink %>" style="<%- config.logoLocation76x76Style %>">
</div>
<div class="form-group">
<label><div><span><%-lang['Monitor']%></span></div>
<div><select class="form-control dark monitors_list"></select></div>
</label>
</div>
<div class="form-group">
<label><div><span><%-lang['Date']%></span></div>
<div><input type="text" id="timelapsejpeg_date" class="form-control" value="" /></div>
</label>
</div>
<div class="form-group">
<input id="timelapseJpegFps" data-slider-id='timelapseJpegFps' type="text"
data-slider-min="1" data-slider-max="30" data-slider-step="1" data-slider-value="30" value="30"/>
</div>
<div class="form-group">
<!-- <div class="btn-group"> -->
<!-- <a class="btn btn-primary download_mp4"><%-lang['Build']%></a> -->
<a class="btn btn-danger btn-block download_mp4"><%-lang['Download']%></a>
<!-- </div> -->
</div>
</div>
<div class="">
</div>
<div class="frameIcons row scroll-style-6"></div>
</div>
<div class="col-md-8 frameStripContainer contained">
<div class="playBackView"><img></div>
<div class="liveStreamView"></div>
<!-- <div class="frames"></div>
<div class="frameStripPreview"></div>
<div class="frameStrip"></div> -->
</div>
</div>
</div>
</div>
<script src="<%=data.url%>/libs/js/jquery.min.js"></script>
<script src="<%=data.url%>/libs/js/jquery-ui.min.js"></script>
<script>$.ccio = {mon:{}}</script>
<script src="<%-data.url%>/libs/js/moment-with-locales.min.js"></script>
<script src="<%-data.url%>/libs/js/daterangepicker.js"></script>
<script src="<%-data.url%>/libs/js/bootstrap-slider.min.js"></script>
<script src="<%-data.url%>/libs/js/dash2.init.js"></script>
<link rel="stylesheet" href="<%-data.url%>/libs/css/dash2.timelapse.jpeg.css">
<script src="<%-data.url%>/libs/js/dash2.timelapse.jpeg.js"></script>
<script>
var data = <%- JSON.stringify(data) %>
var $user = <%- JSON.stringify($user) %>
var lang = <%- JSON.stringify(lang) %>
var languageChoice = "<%- config.language || 'en' %>".replace('_','-').toLowerCase()
moment.locale(languageChoice)
$user.auth_token = data.auth
$(document).ready(function(){
$.timelapseJpeg.pointer = data.url + '/'
$.timelapseJpeg.fieldHolderCssHeightModifier = 50
$.timelapseJpeg.monitors.find('.monitor').remove()
$.getJSON(data.url+'/'+$user.auth_token+'/monitor/'+$user.ke,function(d){
if(d instanceof Array){
$.each(d,function(n,monitor){
$.ccio.mon[monitor.ke + monitor.mid + $user.auth_token] = monitor
})
}else{
$.ccio.mon[d.ke + d.mid + $user.auth_token] = d
}
$.each($.ccio.mon,function(n,v){
$.timelapseJpeg.monitors.append('<option class="monitor" value="'+v.mid+'">'+v.name+'</option>')
})
$.timelapseJpeg.monitors.find('.monitor').prop('selected',false)
// if(monitor.mid !== ''){
// $.timelapseJpeg.monitors.find('.monitor[value="'+e.mid+'"]')
// }
// $.timelapseJpeg.datepicker.val($.timelapseJpeg.baseDate)
$.timelapseJpeg.selectedStartDate = moment().utc().subtract(2, 'days').format('YYYY-MM-DD')
$.timelapseJpeg.selectedEndDate = moment().utc().add(1, 'days').format('YYYY-MM-DD')
$.timelapseJpeg.draw($.timelapseJpeg.selectedStartDate,$.timelapseJpeg.selectedEndDate)
})
})
</script>