reference local file in a <video> tag in a bokeh app - html5-video

Minimal example (non-working) to play a video from a local file in a bokeh app is below. The app uses a Div object with an html <video> tag. The expected behavior would be to play the video in the app immediately. The non-working part is the reference to the local video file.
from bokeh.models import Div
from bokeh.io import curdoc
div = Div(text="""
<video width="300px" height="150px" controls autoplay>
<source src="movie.mp4" type="video/mp4"></video>
""")
curdoc().add_root(div)
The app is so.py and video is movie.mp4, both in the same directory.
Running the app from the command line indicates a 404 error when looking for movie.mp4
Screenshot of the app in the browser indicates the video player did load just could not find the video.
Have also tried <source src="file:///C:/so/movie.mp4" type="video/mp4"> which references the full path of the video file, also non-working.

I don't think auto-loading video files from a local directory at page opening is supported in Bokeh. You need to place the video on a web server and load it using HTTP protocol. As #Doug Sillars noted in his post you should replace your src="movie.mp4" with src="http://localhost:5006/so/sample.mp4" and eliminate the need for running external Mongoose web server. So you code would simply become like the code below (it's tested and it's working!) Run it with bokeh serve --show so
main.py
from bokeh.models import Div
from bokeh.io import curdoc
div = Div(text="""
<video width="300px" height="150px" controls autoplay>
<source src="http://localhost:5006/so/static/movie.mp4" type="video/mp4"></video>
""")
curdoc().add_root(div)
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{{ bokeh_css }}
{{ bokeh_js }}
</head>
<body>
{{ plot_div|indent(8) }}
{{ plot_script|indent(8) }}
</body>
</html>
directory structure:
so
|
+---main.py
+---static
+---movie.mp4
+---templates
+---index.html
Another option is to use FileInput widget and give user the possibility to select the file from the local file system like in this example below (tested on Bokeh v2.2.1):
from bokeh.plotting import show
from bokeh.models import Div, Column, FileInput, CustomJS
code = ''' const file = document.getElementsByTagName('input')[0].files[0]
var URL = window.URL || window.webkitURL
var fileURL = URL.createObjectURL(file)
var videoNode = document.querySelector('video')
videoNode.src = fileURL '''
div = Div(text="""<video width="500px" height="250px" controls><source src="" type="video/mp4"></video>""")
fileinput = FileInput(accept=".mp4,.mpg,.mov", visible = True, width = 250, name = 'fileinput')
fileinput.js_on_change('value', CustomJS(args={'fileinput': fileinput}, code = code))
show(Column(div, fileinput))

Your page is at localhost:5006/so, but you are requesting the video at localhost:5006/movie.mp4. I think you want localhost:5006/so/movie.mp4.

Does not seem possible to play a video as a local file because of security issues. Creating a very quick webserver using mongoose.ws worked. The code above then becomes
from bokeh.models import Div
from bokeh.io import curdoc
div = Div(text="""
<video width="300px" height="150px" controls autoplay>
<source src="http://192.168.1.197:8000/movie.mp4" type="video/mp4"></video>
""")
curdoc().add_root(div)
where the URL is created by the mongoose application.

Related

Show video controls in html5 when right click is disabled

I have disabled right click on my website's videos because I want to discourage downloads. To that end I use the following code:
<video oncontextmenu="return false" controls="controls" controlslist="nodownload">
<source src="..."> video
</video>
However, with this users don't have the Controls' functionality. In particular, they cannot move forward or backwards with the keyboard arrows. Normally, to enable this functionality, you have to right click the video and select "Show Controls", as shown below:
Naturally, in my case that is not possible.
How can I enable those controls by default, so I can keep hiding that context menu? I've searched through default <video> attributes but can't find any relevant for me. Any ideas?
To disable right-click on video tag and yet keep video controls, try my example below:
What the codes does:
Gives your video tag an ID (see: id="myVid" )
Uses Javascript's preventDefault(); to block right-click on a specific item by its ID. (Eg: You might still want right-click to work on other [non-video player] parts of the page.)
Testable code example:
<!DOCTYPE html>
<html>
<body>
<video id="myVid" width="640" height="480" controls="controls" controlslist="nodownload">
<source src="filename.mp4" type="video/mp4">
</video>
</body>
</html>
<script>
//# use this line to prevent context menu in Video Element
document.getElementById("myVid").addEventListener('contextmenu', function (e) { e.preventDefault(); }, false);
</script>

Issue playing a video on Jenkins HTML Publisher

I am using Testcafe for my project tests and I am generating a HTML report with screenshot and video in my project.
When I am trying to publish the report using HTML publisher, the video is not playing.
When I open the generated HTML file in the Jenkins agent via browser, the video is playing fine. not sure, why it is not playing on the Jenkins HTML publisher plugin.
MY HTML video code looks like below
<div class="row">
<div class="column">
<img id="myImg" class="errImage" src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAABAAAA" style="width:100%;">
</div>
<div class="column">
<video autoplay muted loop controls id="errorVideo" style="width:99%">
<source src="C:\Program Files (x86)\Jenkins\workspace\Free style node test\e2e\artifacts\videos\Getting Started\My First Test\1.mp4" type="video/mp4">
</video>
</div>
</div>
I tried configuring following content security policy
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "sandbox; default-src '';")
not sure what policy is blocking the video from playing on the Jenkins publisher.
Can someone help to resolve this issue? Thanks in advance.
The policy which blocking your video from playing is media-src == "none", derived from default-src == 'none' (see https://wiki.jenkins.io/display/JENKINS/Configuring+Content+Security+Policy)
Take a look at the solution in https://github.com/jenkinsci/screenrecorder-plugin/blob/master/src/main/java/org/jenkinsci/plugins/screenrecorder/ScreenRecorderBuildWrapper.java, it could work for you:
String curCsp = System.getProperty("hudson.model.DirectoryBrowserSupport.CSP","");
if (!curCsp.contains("media-src"))
{
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", curCsp + ";media-src 'self';");
}

Videojs can't play m3u8 blob URL

I am using Videojs version 7.6.6. It will not play a html5 video if the src is a blob URL. It will load the video time however, but will not play. I get this warning, and then it loads forever:
VIDEOJS: WARN: Problem encountered with the current HLS playlist. Trying again since it is the only playlist.
This is the way my code runs:
<video id="my_video" class="video-js vjs-matrix vjs-default-skin vjs-big-play-centered" controls
preload="none" width="640" height="268" data-setup="{}"></video>
<script type="text/javascript" src="/js/video-766.min.js"></script>
<script>
fetch("https://server/hls/index.m3u8").then(result => result.blob())
.then(blob => {
var blobURL = URL.createObjectURL(blob);
var player = videojs("my_video");
player.src({ src: blobURL, type: "application/x-mpegURL" });
}
);
</script>
If I try it without a blob, just a regular URL to the index.m3u8 file, then it works. So this is a problem with the creation of the blob URL I think. This works, the video starts playing:
<video id="my_video" class="video-js vjs-default-skin" height="360" width="640" controls preload="none">
<source src="https://server/hls/index.m3u8" type="application/x-mpegURL" />
</video>
<script>
var player = videojs('my_video');
</script>
I have searched for this issue and found a lot, but none of it helps me. Am I creating the blob wrong?
The object URL that is generated for the blob will start with file:// protocol if I'm not wrong. Browsers doesn't let you load data with file:// URL. I ran into a similar problem so I created a simple server on my app which returns the requested file over https:// .
The reason why your index.m3u8 is running because it is served over https protocol

How to upload and create multiple file objects with django

I'm new to Django and I'm on the first stages for writing a web app. One of the features of the app requires users to upload multiple pictures to a database.
I have created an 'image' model for storing the pictures and later manipulate them. The user is supposed to upload more than one image at a time using a POST request (don't even know if that is possible).
Each picture uploaded is supposed to be an image object on the database, but for some reason, I'm failing to upload and also create that object. Nothing happens when I make the POST request. I might be failing at some point and in something simple. I'd appreciate some help.
models.py
from django.db import models
class image(models.Model):
image_field = models.FileField(upload_to='images/')
forms.py
from django import forms
from .models import image
class images_form(forms.ModelForm):
class Meta:
model = image
fields = ['image_field']
widgets = {
'image_field' : forms.ClearableFileInput(
attrs={'class': 'upload ','inputtype':'file','name':'images','multiple':True })}
views.py
from django.shortcuts import render
from django.http import HttpResponse
from .forms import images_form
from .models import image
def upload_files(request):
context = {'images_form': images_form}
if request.method == 'POST':
form_images = images_form(request.POST, request.FILES)
files = request.FILES.getlist('images')
if form_images.is_valid():
for file in files:
newimg = image(image_field = file)
print(newimg.name)
newimg.save()
return HttpResponse('images uploaded')
else:
return render(request, 'master_form/desk.html', context=context)
upload_images.html
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<h1>Django Desk</h1>
<div class="container-fluid">
<h1> images</h1>
<form method = "post" enctype = "multipart/form-data">
{% csrf_token %}
{{ images_form.as_p }}
<button type = "submit"> Upload </button>
</form>
</body>
</html>
I found what the problem was.
files = request.FILES.getlist('images')
Was empty or didn't exist.
You have to use the same name you used when defining your model fields, in my case 'image_field', not 'images'.
The new code looks like this (views.py):
for file in request.FILES.getlist('image_field'):
img = image(image_field=file)
img.save()

Play oscillator in left/right channel with Web Audio Api, Ionic and Crosswalk

I want to play an oscillator in left, right or both channel and to achieve this i use the StereoPannerNode from the Web Audio Api.
When i run "ionic serve" on Chrome everything works fine, but when i test the code on Android (i installed the crosswalk plugin) the sound comes from both channels (lower in the channel i don't want the sound to play).
I also tried Merger and Splitter nodes with the same results: works on Chrome, doesn't work on Android.
I tried to use Asus ZenFone with Android 4.4.2 and Huawei p8 with Android 6.0.
This is how i create my audio context and the panner node.
var contextClass = (window.AudioContext);
var audioCtx = new contextClass();
var panNode = audioCtx.createStereoPanner();
I don't know how to fix this, any idea?
On Android 6.0, the following script works. It makes use of the Web Audio API. I have not yet tested it on iOS, but I have a good feeling it will work there (please comment if it does not).
You need an "omg.mp3" file in your root directory to test with. You also should build using Cordova and not worry about the CORS or Same-domain error you might get in your browser
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>StereoPannerNode example</title>
<link rel="stylesheet" href="">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<h1>StereoPannerNode example</h1>
<audio controls>
<source src="omg.mp3" type="audio/mp3">
<p>Browser too old to support HTML5 audio? How depressing!</p>
</audio>
<h2>Set stereo panning</h2>
<input class="panning-control" type="range" min="-1" max="1" step="0.1" value="0">
<span class="panning-value">0</span>
</body>
<script>
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var myAudio = document.querySelector('audio');
var panControl = document.querySelector('.panning-control');
var panValue = document.querySelector('.panning-value');
// Create a MediaElementAudioSourceNode
// Feed the HTMLMediaElement into it
var source = audioCtx.createMediaElementSource(myAudio);
// Create a stereo panner
var panNode = audioCtx.createStereoPanner();
// Event handler function to increase panning to the right and left
// when the slider is moved
panControl.oninput = function() {
panNode.pan.value = panControl.value;
panValue.innerHTML = panControl.value;
}
// connect the AudioBufferSourceNode to the gainNode
// and the gainNode to the destination, so we can play the
// music and adjust the panning using the controls
source.connect(panNode);
panNode.connect(audioCtx.destination);
</script>
</html>