---
allow_origins:
- '*'
allow_xss: false
alt_top_banner: ''
auto_reload: false
auto_reload_interval: 5.0
code: ''
mimetype: text/html
no_header: false
no_navheader: false
require_method:
- GET
require_permissions:
- view_nvr
resource_timestamp: 1675750898769122
resource_type: page
setupcode: from kaithem.api.devices import all_devices
streaming_response: false
template_engine: mako
theme_css_url: ''

---
<%!
#Code Here runs once when page is first rendered. Good place for import statements.
import json
import datetime
%>

    <%
__doc__= "#Python Code here runs every page load"
%>

        <style>
      iframe{
        width: 100%;
        height: 70vh;
      }
        </style>

        <script src="/static/js/thirdparty/vue3.js"></script>
        <script src="/static/js/thirdparty/luxon.min.js"></script>

        <h2><i class="mdi mdi-castle"></i>Beholder NVR</h2>
        <title>Beholder NVR</title>

            <div id="app" class="window" style="max-width: 100vw;">
              <datalist id="cameras">
                  <option v-for="v,i of cameraUrls">{{i}}</option>
              </datalist>


              <div class="tool-bar" style="width:100%">
                <button v-on:click="tab='playback'" :class="{'highlight': tab=='playback'}"><i class="mdi mdi-files-stack"></i>Recordings</button>
                <button v-on:click="tab='cameras'" :class="{'highlight': tab=='cameras'}"><i class="mdi mdi-cctv"></i>Cameras</button>
                <button v-on:click="tab='multiview'" :class="{'highlight': tab=='multiview'}"><i class="mdi mdi-table"></i>Wall Builder</button>

                <button v-on:click="goFS()"><i class="mdi mdi-arrow-expand-all"></i>Fullscreen</button>

              </div>
              <div style="display: flex; flex-wrap: wrap;">
                <div v-if="tab=='multiview'"  style="">

                  <div class="tool-bar" style="width:100%">

                    <button v-on:click="goFSWall()"><i class="mdi mdi-arrow-expand-all"></i>Fullscreen</button>

                  </div>

                  <div style="display: flex; flex-wrap: wrap;">
                    <div style="max-height: 25em; overflow: scroll">
                        <details><summary>Help</summary>
                        Take up to 4 URLs or wall builder codes and assemble them into a display.
                        Note that this does not get saved anywhere, instead, the you just bookmark the generated link to get back.
                        You can embed *any* page into a wall so long as it fits in the quarter-screen size.
                        </details>

                      <table>
                        <tr>
                          <th>View Slots</th>
                        </tr>

                        <tr v-for="v,i in viewSlots">
                          <td><input v-model="viewSlots[i]"></td>
                        </tr>

                      </table>

                      <h4>Link to this wall</h4>
                      <a :href="'?viewslots='+encodeURIComponent(JSON.stringify(viewSlots))">This editor page</a>
                      <a :href="'fswall?viewslots='+encodeURIComponent(JSON.stringify(viewSlots))">Just the wall</a>

                    </div>

                    <div  id="videowall" style="display: flex; flex-wrap: wrap;min-height:80vh;">
                    <template v-for="v,i in viewSlots">
                    <div v-if="viewSlots[i]" style="min-width:49%; max-width:99%; max-height:49%; flex-grow: 2; background-color: black;">
                        <iframe :src="viewSlots[i]" style="overflow: auto; width: 100%; height:100%;">
                        </iframe>
                    </div>
                    </template>
                    </div>
                  </div>
                </div>




                <div v-if="tab=='cameras'"  style="display: flex; flex-wrap: wrap;">
                    <div style="max-height: 25em; overflow: scroll">
                      <ul>
                          <li v-for="v,i of cameraUrls"><a v-on:click="setRTPlayback(cameraUrls[i],i)">{{i}}</a></li>
                      </ul>

                      <h3>Live View</h3>


                      <h4>Embeddable Viewer Code for wall builder</h4>

                      <details><summary>Help</summary>
                        Copy and paste this into a wall builder slot, or anywhere else you'd like to to embed a camera feed.
                        </details>
                        <pre>/pages/Beholder/{{makeFullRtPlaybackUrl() }}</pre>

                      <h4>Fullscreen Link</h4>
                      <p><a :href="makeFullRtPlaybackUrl()+'&fs=1'">Link</a></p>

                      <h3>JPEG Snapshot</h3>
                      <p><a :href="'serve_jpg?device='+selectedRTCam">Link</a></p>

                    </div>

                    <div style="min-width:30vw; flex-grow: 2; background-color: black;" v-if="rtPlaybackUrl">

                        <iframe :src="makeFullRtPlaybackUrl()+'&controls=1'" id="playback-iframe" style="overflow: auto">
                        </iframe>

                    </div>
                </div>



                <div v-if="tab=='playback'"  style="display: flex; flex-wrap: wrap;">
                  <div>
                  <div class="tool-bar">
                        <p>Starting:</p><input v-model="searchtime" type="date">
                        <input v-model="searchcam" list="cameras" placeholder="All Cameras">
                        <button v-on:click="getFiles(searchcam, searchtime)"><i class="mdi mdi-binoculars"></i>Search</button>
                        <button :class="{'highlight': showClipThumbnails}" v-on:click="showClipThumbnails=!showClipThumbnails">Previews</button>
                  </div>
                    <div style="min-width:12vw; max-height: 25em; overflow-y: scroll;">
                      <dl>
                          <template v-for="i,v of fileSet">
                          <dt><a v-on:click="setPlayback('player/'+i[1]+'/playlist.m3u8',i)">{{new Date(Date.parse(i[0])).toLocaleString()}} @ {{i[2]}}</a>
                          {{i[3]}}
                          </dt>
                          <dd>
                            <img :src="'serve/' + i[1]+'/thumbnail.jpg'" v-if="showClipThumbnails"></img>
                          </dd>
                          </template>
                      </dl>
                    </div>
                    <div v-if="playbackClipInfo">
                      <h3>Selected: {{new Date(Date.parse(playbackClipInfo[0])).toLocaleString()}} @ {{playbackClipInfo[2]}}</h3>
                      <h4>Download</h4>
                      <a :href="'serve_mp4/' + playbackClipInfo[1]+'/playlist.m3u8'">Download as MP4</a>
                    </div>
                  </div>

                <div style="min-width:30vw; flex-grow: 2;">

                    <iframe :src="playbackURL" scrolling="no" id="playback-iframe" style="overflow: auto">
                    </iframe>

                </div>
                </div>
              </div>

            </div>




        <script>
            appData=
  {
        message: 'Hello Vue!',
        tab: "${'multiview' if 'viewslots' in kwargs else 'playback'}",

        searchcam:'',
        searchtime: "${datetime.datetime.now().strftime('%Y-%m-%d')}",
        fileSet: [],
        playbackURL: '',
        rtPlaybackUrl: '',
        selectedRTCam:'',
        showClipThumbnails: false,
        viewSlots: ${json.loads(kwargs.get('viewslots', '["", "", "", ""]')) },
        playbackClipInfo: 0,


        makeFullRtPlaybackUrl : function()
        {
          return (appData.rtPlaybackUrl)
        },

        goFS : function(){
            document.getElementById("app").requestFullscreen()
        },



        goFSWall : function(){
            document.getElementById("videowall").requestFullscreen()
        },


        setPlayback: function(x,i){
          app.playbackURL=x
          app.playbackClipInfo = i
        },


        setRTPlayback: function(x,name){
          app.rtPlaybackUrl=x
          app.selectedRTCam=name
          app.tab='cameras'
        },

        getFiles: function(filter, date){

          var sp =  new URLSearchParams({
                filter: app.searchcam,
                starttime: luxon.DateTime.fromISO(app.searchtime).toISO()
            })
          fetch('filesearch?'+sp)
          .then(function(r){
            r.json().then(
              function(r){
                app.fileSet = r
              }
            )
          })
        },

        cameraUrls:{
          %for i in all_devices:
          %if all_devices[i].device_type_name =='NVRChannel':
          '${i}': "rtplayer?play=${i|u}",
          %endif
          %endfor
          "None": ''
        }



      }


  app= Vue.createApp({
    data() {
      return appData
    }
  }).mount('#app')

        </script>