convert audio source to a "use-once" blob - javascript

So I want to make it a little bit more difficult for users to directly download MP3 files from the server (just from going straight to the URL of the source). I've been looking around and, from what I've gathered, a good way to go about this is to convert an Audio object to a use-once Blob (similar to how YouTube does it).
As an example, something like this:
<!-- directly accessible, unobfuscated url -->
<audio src="www.mywebsite.com/media.mp3"></audio>
Would become:
<!-- visiting the link would lead to a 'your file was not found' page
and the original url is now obfuscated -->
<audio src="blob:http://www.mywebsite.com/6fc4f9d2-035a-4999-b330-96da04c0f6a8"></audio>
At the moment, this is how I'm doing it:
var url = "http://www.mywebsite.com/media.php"; // media.php points to an mp3 file
var audio = null; // just for simplicity sake - i'm not actually doing it like this
if(!audio){
audio = new Audio(url);
} else {
audio.pause();
audio.src = url;
}
Now I was looking at this answer (along with a couple others), but they all either involve using a file selected from an input or, as this one is, using the file as a Base64 string and converting that to a Blob, which I can't figure out how to do and imagine to be a somewhat heavy task to do on the client-side.
Essentially, all I need to do is convert the url to a Blob that can only be used once in that session (cannot be directly accessed in another tab - just that one time it's being played, for example).
NOTE: I Tagged PHP as this may also be a server-side issue, feel free to correct that if necessary.

Related

Can I use javascript to retrieve the content header when setting the src on audio

I'm using the HTML5 audio control to play an mp3 file that is streaming from the server:
<audio id="audio" controls="controls" src="">
</audio>
And I am setting the src of that audio control dynamically, when a user clicks a button:
$('#myBtn').on('click', function (e) {
var audio = document.getElementById('audio');
audio.src = "/api/audio/f56i4gi8lh";
audio.load();
});
The audio is playing fine, but I also want to show the file name in a label when the audio starts streaming. The problem is that before I start streaming the audio from that url, I only know the file id and not the file name. That file name is contained in the header of the response (the response from /api/audio/f56i4gi8lh.
I can see the file name in the header using my F12 tools when I debug:
Is there a way to extract that filename from the header into a javascript variable using javascript or jQuery (while setting the src of the audio control)?
I would think it would be something along these lines:
$('#myBtn').on('click', function (e) {
var audio = document.getElementById('audio');
audio.src = "/api/audio/f56i4gi8lh";
audio.load(function(response) {
var name = response.Header.filename;
});
});
But I cannot find any documentation on anything like this.
You can, but there's unfortunately nothing easy about it.
First off, your server configuration is going to have to properly support CORS for the domain on which your page is.
Next, you'll have to switch to using MediaSource Extensions so that you can request the media yourself with the Fetch API and intercept the response headers. https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
As an alternative, you could look into using Web Workers to handle the fetching. I haven't tried this myself so I don't have any specific advice, but it's my understanding you can do this and continue using the regular audio tag src like you are in your existing code.
Another (albeit less desirable) alternative is to make a separate HEAD request with the Fetch API. This isn't great because this separate request may have a different response than your first request. But, it is a possibility for you.

Receive chunks of video and play them in browser

Base idea: I am creating an app. In which user chooses local file(mp4) in input field(type="file") and then streams the video to other user.
I am thinking to manipulate the file in javascript. And send it chunk by chunk to another user via(datachannels webRTC) then just play it on the other side chunk by chunk.
I understand that i can "assemble" the chunks using - MediaSource API
Questions: How can i split the video in chunks using javascript? I have been googling for a while i can't seem to find a library( maybe i am googling wrong keywords? ).
Thanks!
Use blob#slice to split the video
// simulate a file
blob = new Blob(['ab'])
chunk1 = blob.slice(0, 1)
chunk2 = blob.slice(1, 2)
console.log(blob.size)
console.log(chunk1.size)
console.log(chunk2.size)
Another thing i might think you are interested in is File streaming...
To get a ReadableStream from a blob you could use the hackish why of doing
stream = new Response(blob).body
reader = stream.getReader()
reader.read().then(chunk => spread(chunk))
Another cool library otherwise you can use to stream the blob Is by using Screw-FileReader
What wouldn't be more awesome then using WebTorrent to share the video got everything you need... uses WebRTC...

Use local files with MediaSource

I am trying to build a local video player in nwjs (node-webkit). I was able to play the local files by adding their path as the video element's src attribute, but now I want to make use of MediaSource and ,probably necessary, URL.createObjectUrl().
The problem is I haven't found any documentation that allowed me to achieve this, during my tests I am unable to append a new source to MediaSource as the local file. I tried direct paths and XHR requests, the closest I have been was with the XHR request of the file but I cannot convert the xhr.response into a usable item for my purpose, such as a objecturl.
For some reason just changing the src attribute directly each time a new video is selected causes the memory usage to grow constantly, which is why I would like to try doing this via the MediaSource api.
Since there's a lack of such information I would appreciate if anyone could help.
I was able to discover how this could be done, first there needs to be a mediasource object with which you use URL.createObjectUrl to link to the video.src, and then you create a buffer on it. It is to that buffer that is appended the media which is loaded via XMLHttpRequest with the Content-type set as an arraybuffer.
Careful with big files, if you don't segment them and load everything at once it will eat your ram and even crash your application.

Is it possible to preload and cache video files without adding them to the DOM?

I'm working on a game that involves trigging one of 30 small video files depending on what result you get. As the videos need to play immediately after the user interacts, ideally I'd like to have the videos preloaded and ready to go.
I've added PreloadJS, queued up all of the assets I need.
Looking at the Network tab in inspector, I can see all 20mb of videos transferring on the loading screen.
However, when it comes time to play the clips, it seems to be re-downloading them rather than playing them from memory...
I thought that once the files were downloaded, they'd just stay in the browser cache, and once I tried to load a file with the same src, it would pull it from the pool of downloaded assets, but this doesn't seem to be the case...
Any idea how I can keep the downloaded files in memory without adding 30 video players to the page?
Thanks!
Ger
You could try to load the entire file into memory using Blob and Object-URL. This way the non-attached video element can play directly via the object-URL.
If it's a good strategy in regard to system resources is of course something you need to decide yourself.
Load through XHR as blob
Create Object URL: var url = (URL || webkitURL).createObjectURL(blob);
The video is now in memory, so when you need to play it, set it as source for the video element and you should be ready to go:
var video = document.createElement("video");
video.oncanplay = ...; // attach to DOM, invoke play() etc.
video.src = url; // set the object URL
An object-URL is kept in memory during the life-cycle of a page. You can manually revoke it this way if needed:
(URL || webkitURL).revokeObjectURL(url);

How to save the window.URL.createObjectURL() result for future use?

I'm making an application in HTML5 where you choose a video file, and then the application plays it with the HTML5 video tag and the window.URL.createObjectURL(). The problem is that I want to save the data about this video in localStorage and play it again when the user uses my application, but as Mozilla MDN states about the results of this method:
Browsers will release these automatically when the document is unloaded
So is it possible to do what I'm trying to do? Or do the same thing without the window.URL.createObjectURL() but with something else?
I haven't used createObjectURL(), but if I understand correctly, it's essentially a temporary reference to a file or an in-memory object. If you want to save the actual video, it won't be useful, because the video itself will no longer be referenced by this pointer the next time the user visits the application.
I think you might be able to do this with a data: URL instead, as that URL actually includes the full data from the file. This example demonstrates using a FileReader to generate a data URL. I think you should be able to do this:
var reader = new FileReader();
reader.onload = function(e) {
var myDataUrl = e.target.result;
// do something with the URL in the DOM,
// then save it to local storage
};
reader.readAsDataURL(file);
Update: If you want to go up to 1GB, as you note in your comment, you'd probably be better served by the FileSystem API. This would require you to get the local file, save a copy of the file to persistent filesystem storage, and then use createObjectURL() to get a URL for the file copy. You still have a problem with disk space - you just added 1GB of duplicative file content to the user's filesystem - but I don't think it's possible to keep a persistent reference to a file outside of the browser sandbox otherwise.

Categories