View video file in ui

Hi I am trying to display a mp4 video from a file which is in my httpStatic folder, on the dashboard, my code is below, whilst this works I want to add some code in say a function or a template node to inject the file name instead of specifying it in the dashboard template node but I just cannot get my head around it

Thought it would just be a case of sending a msg.payload containing the address into the dashboard template node and replacing the existing address with {{msg,.payload}} but I cannot get it to work ... also I think I may need to refresh the dashboard template node once the new address is injected but nothing I have tried comes close to working, any help would be appreciated

'''{"id":"a63c1856.975b38","type":"ui_template","z":"4e3c808b.59652","group":"7e6c67d9.c87798","name":"template2","order":27,"width":0,"height":0,"format":"<div id="video">\n <video width="300" height="200" controls>\n <source src= "/video/tl_27_11_2018_07_59.mp4">\n \n\n \n\n\n\n\n\n\n","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":630,"y":1700,"wires":[["6fae8f9e.2cd19"]]},{"id":"7e6c67d9.c87798","type":"ui_group","z":"","name":"G_1","tab":"4e11b05c.70bfc","order":1,"disp":false,"width":"18","collapse":false},{"id":"4e11b05c.70bfc","type":"ui_tab","z":"","name":"Drivecamlrgscreen","icon":"dashboard","order":5}]'''

Hi Dave,

When the above HTML is inside a template node, I 'think' you should add something like this in the same template node:

<script> 
    (function(scope) {
        // Watch for messages being send to this template node
        scope.$watch('msg', function (msg) {      
            if (msg) {
                  var document.getElementById().src = msg.payload;
            }       
         }); 
    })(scope); 
</script>

P.S. I haven't tested this code ...

Bart

If you define your video html elements in a ui_template node, replace the src="/video/xxxx" with the angular ng-src directive instead:

<div id="video">
    <video width="300" height="200" controls>
    <source ng-src="{{msg.payload}}">
</div>

Then whenever you pass a new msg.payload containing a video url, it should switch to that video source.

3 Likes

Thanks Steve, slightly modding your code I got it working, however to make it work currently I have to switch to a different tab and back again the results of that loads the new url into the video screen.

[{"id":"10cda3f5.3f63cc","type":"inject","z":"37539945.991916","name":"test","topic":"","payload":"/video/tl_27_11_2018_13_40.mp4","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1180,"y":1300,"wires":[["a93393a2.28198"]]},{"id":"a93393a2.28198","type":"ui_template","z":"37539945.991916","group":"a4019b6f.6ea158","name":"Vid_screen","order":28,"width":"6","height":"4","format":"<div id=\"video\">\n    <video width=\"300\" height=\"200\"  controls>\n    <source ng-src={{msg.payload}}>\n  </video>    \n</div>\n\n\n\n\n","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":1380,"y":1300,"wires":[["802a1edd.a3e54"]]},{"id":"8a54008c.02bf4","type":"ui_ui_control","z":"37539945.991916","name":"","x":1730,"y":1300,"wires":[[]]},{"id":"802a1edd.a3e54","type":"trigger","z":"37539945.991916","op1":"3","op2":"4","op1type":"str","op2type":"str","duration":"10","extend":false,"units":"ms","reset":"","bytopic":"all","name":"","x":1560,"y":1300,"wires":[["8a54008c.02bf4"]]},{"id":"a4019b6f.6ea158","type":"ui_group","z":"","name":"G_2","tab":"4e11b05c.70bfc","order":4,"disp":false,"width":"6","collapse":false},{"id":"4e11b05c.70bfc","type":"ui_tab","z":"","name":"Drivecamlrgscreen","icon":"dashboard","order":5}]

I guess something like Bart's code that detects when a new msg arrives could just update this specific template node which I would really like to do, but I just cannot get it to work.

Hi Dave,

Finally some (few) 'me-time' at my pc.
When I use this (updated) code snippet in a template node:

<div>
     <video id="video" width="100%" heigth="100%"></video>
</div>

<script> 
    (function(scope) {
        // Watch for messages being send to this template node
        scope.$watch('msg', function (msg) {      
            if (msg) {

                var video = document.getElementById('video');
                video.src = msg.payload;
                video.play();
            }       
         }); 
    })(scope); 
</script>

Then I can switch (in Chrome) dynamically between movies, by injecting URLs referring to different mp4 files:

Here is the example flow:

[{"id":"34ebe5b1.ffe0ca","type":"inject","z":"18e47039.88483","name":"Show first stream","topic":"","payload":"https://storage.googleapis.com/coverr-main/mp4/The-Slow-Dock.mp4","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":620,"y":1140,"wires":[["d4643763.1e4478"]]},{"id":"d4643763.1e4478","type":"ui_template","z":"18e47039.88483","group":"b389df50.19473","name":"Vid_screen","order":28,"width":"6","height":"4","format":"<div>\n     <video id=\"video\" width=\"100%\" heigth=\"100%\"></video>\n</div>\n\n<script> \n    (function(scope) {\n        // Watch for messages being send to this template node\n        scope.$watch('msg', function (msg) {      \n            if (msg) {\n\n                var video = document.getElementById('video');\n                video.src = msg.payload;\n                video.play();\n            }       \n         }); \n    })(scope); \n</script>\n\n\n\n","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":830,"y":1140,"wires":[[]]},{"id":"1cd37387.83b0bc","type":"inject","z":"18e47039.88483","name":"Show first stream","topic":"","payload":"https://storage.googleapis.com/coverr-main/mp4/Night-Traffic.mp4","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":620,"y":1180,"wires":[["d4643763.1e4478"]]},{"id":"b389df50.19473","type":"ui_group","z":"","name":"G_2","tab":"12ba52b2.c0ce3d","order":4,"disp":false,"width":"6","collapse":false},{"id":"12ba52b2.c0ce3d","type":"ui_tab","z":"","name":"Drivecamlrgscreen","icon":"dashboard","order":5}]

Note that recently Google has changed its autoplay policy. So you cannot use the autoplay attribute anymore, and you will get an exception when you do video.play() in Javascript. Reason is that they want to avoid that websites start automatically playing unwanted video/audio, which is annoying for users and wastes bandwith. However for your use case, I had to change the policy allow manually back to the old status (which means the user doesn't have to press something before playing):
image

Is there anybody around who knows how we can solve this automatically??

Bart

2 Likes

I had to modify it a bit as my browser was complaining for something else

Maybe it'll solve your autoplay as well

<div>
     <video id="video" width="100%" heigth="100%"></video>
</div>

<script> 
    (function(scope) {
        // Watch for messages being send to this template node
        scope.$watch('msg', function (msg) {      
            if (msg) {

                var video = document.getElementById('video');
                video.src = msg.payload;
                var playPromise = video.play();

                if (playPromise !== undefined) {
                    playPromise.then(_ => {
                      // Automatic playback started!
                      // Show playing UI.
                    })
                    .catch(error => {
                      // Auto-play was prevented
                      // Show paused UI.
                    });
                }
            }       
         }); 
    })(scope); 
</script>

Hi @hugobox,

Thanks for the tip!!!
I tried something similar yesterday, but then I also arrived in the catch part...

To be sure, I have reset again my autoplay policy to the default:
image

Then both your and mine version still work fine. Very weird!

Afterwards I have asked Chrome to make sure that a user gesture is required, before start playing:
image

Then both versions still work fine. I don't get it anymore :woozy_face:

Other nodes are also being fixed for the policy changes (see discussion and corresponding pull request), but I don't get how they can get around the user gestures that way ...

P.S. But your version is anyway better than mine ...
Bart

Thanks guys, I didn't get a lot of time over the last few days ('me-time' haha) to test and I now have to go out again, but the code is working great on my pc using Chrome, at the moment it doesn't appear to work on my ipad or iphone in safari I will down load & check google browser app later, cheers.