Convert blob URL to normal URL - javascript

My page generates a URL like this: "blob:http%3A//localhost%3A8383/568233a1-8b13-48b3-84d5-cca045ae384f" How can I convert it to a normal address?
I'm using it as an <img>'s src attribute.

A URL that was created from a JavaScript Blob can not be converted to a "normal" URL.
A blob: URL does not refer to data the exists on the server, it refers to data that your browser currently has in memory, for the current page. It will not be available on other pages, it will not be available in other browsers, and it will not be available from other computers.
Therefore it does not make sense, in general, to convert a Blob URL to a "normal" URL. If you wanted an ordinary URL, you would have to send the data from the browser to a server and have the server make it available like an ordinary file.
It is possible convert a blob: URL into a data: URL, at least in Chrome. You can use an AJAX request to "fetch" the data from the blob: URL (even though it's really just pulling it out of your browser's memory, not making an HTTP request).
Here's an example:
var blob = new Blob(["Hello, world!"], { type: 'text/plain' });
var blobUrl = URL.createObjectURL(blob);
var xhr = new XMLHttpRequest;
xhr.responseType = 'blob';
xhr.onload = function() {
var recoveredBlob = xhr.response;
var reader = new FileReader;
reader.onload = function() {
var blobAsDataUrl = reader.result;
window.location = blobAsDataUrl;
};
reader.readAsDataURL(recoveredBlob);
};
xhr.open('GET', blobUrl);
xhr.send();
data: URLs are probably not what you mean by "normal" and can be problematically large. However they do work like normal URLs in that they can be shared; they're not specific to the current browser or session.

another way to create a data url from blob url may be using canvas.
var canvas = document.createElement("canvas")
var context = canvas.getContext("2d")
context.drawImage(img, 0, 0) // i assume that img.src is your blob url
var dataurl = canvas.toDataURL("your prefer type", your prefer quality)
as what i saw in mdn, canvas.toDataURL is supported well by browsers. (except ie<9, always ie<9)

For those who came here looking for a way to download a blob url video / audio, this answer worked for me. In short, you would need to find an *.m3u8 file on the desired web page through Chrome -> Network tab and paste it into a VLC player.
Another guide shows you how to save a stream with the VLC Player.
UPDATE:
An alternative way of downloading the videos from a blob url is by using the mass downloader and joining the files together.
Download Videos Part
Open network tab in chrome dev tools
Reload the webpage
Filter .m3u8 files
Look through all filtered files and find the playlist of the '.ts' files. It should look something like this:
You need to extract those links somehow. Either download and edit the file manually OR use any other method you like. As you can see, those links are very similar, the only thing that differs is the serial number of the video: 's-0-v1-a1.ts', 's-1-v1-a1.ts' etc.
https://some-website.net/del/8cf.m3u8/s-0-v1-a1.ts
https://some-website.net/del/8cf.m3u8/s-1-v1-a1.ts
https://some-website.net/del/8cf.m3u8/s-2-v1-a1.ts
and so on up to the last link in the .m3u8 playlist file. These .ts files are actually your video. You need to download all of them.
For bulk downloading I prefer using the Simple Mass Downloader extension for Chrome (https://chrome.google.com/webstore/detail/simple-mass-downloader/abdkkegmcbiomijcbdaodaflgehfffed)
If you opt in for the Simple Mass Downloader, you need to:
a. Select a Pattern URL
b. Enter your link in the address field with only one modification: that part of the link that is changing for each next video needs to be replaced with the pattern in square brackets [0:400] where 0 is the first file name and 400 is the last one. So your link should look something like this https://some-website.net/del/8cf.m3u8/s-[0:400]-v1-a1.ts.
Afterwards hit the Import button to add these links into the Download List of Mass Downloader.
c. The next action may ask you for the destination folder for EACH video you download. So it is highly recommended to specify the default download folder in Chrome Settings and disable the Select Destination option in Chrome Settings as well. This will save you a lot of time! Additionally you may want you specify the folder where these files will go to:
c1. Click on Select All checkbox to select all files from the Download List.
c2. Click on the Download button in the bottom right corner of the SMD extension window. It will take you to next tab to start downloading
c3. Hit Start selected. This will download all vids automatically into the download folder.
That is it! Simply wait till all files are downloaded and you can watch them via the VLC Player or any other player that supports the .ts format. However, if you want to have one video instead of those you have downloaded, you need to join all these mini-videos together
Joining Videos Part
Since I am working on Mac, I am not aware of how you would do this on Windows. If you are the Windows user and you want to merge the videos, feel free to google for the windows solution. The next steps are applicable for Mac only.
Open Terminal in the folder you want the new video to be saved in
Type: cat and hit space
Open the folder where you downloaded your .ts video. Select all .ts videos that you want to join (use your mouse or cmd+A)
Drag and drop them into the terminal
Hit space
Hit >
Hit Space
Type the name of the new video, e.g. my_new_video.ts. Please note that the format has to be the same as in the original videos, otherwise it will take long time to convert and even may fail!
Hit Enter. Wait for the terminal to finish the joining process and enjoy watching your video!

Found this answer here and wanted to reference it as it appear much cleaner than the accepted answer:
function blobToDataURL(blob, callback) {
var fileReader = new FileReader();
fileReader.onload = function(e) {callback(e.target.result);}
fileReader.readAsDataURL(blob);
}

I'm very late to the party.
If you want to download the content you can simply use fetch now
fetch(blobURL)
.then(res => res.blob())
.then(blob => /*do what you want with the blob here*/)

Here the solution:
let blob = new Blob(chunks, { 'type' : 'video/mp4;' });
let videoURL = window.URL.createObjectURL(blob);
const blobF = await fetch(videoURL).then(res => res.blob())

As the previous answer have said, there is no way to decode it back to url, even when you try to see it from the chrome devtools panel, the url may be still encoded as blob.
However, it's possible to get the data, another way to obtain the data is to put it into an anchor and directly download it.
<a href="blob:http://example.com/xxxx-xxxx-xxxx-xxxx" download>download</a>
Insert this to the page containing blob url and click the button, you get the content.
Another way is to intercept the ajax call via a proxy server, then you could view the true image url.

Related

File download - How can I control the filename AND respect the users preferences?

I have a blob url and a button on my site. The user can click on that button and the blob opens in a new tab.
<a class="downloadlink" id="downloadlink" target="_blank" href="[[_blobUrl]]"></a>
This works.
If the user has the setting for the file type behind this blob (e.g. pdf) to save the file instead of previewing it in the browser, the file gets downloaded of course. But firefox creates a random filename of the format
[a-zA-Z0-9]{8}\.pdf
Chrome uses the blob uuid and appends pdf.
How can I control the filename AND respect the users preferences?
When I add the download attribute the file gets always downloaded, also when the user has the setting "Preview" for the specified file type. I want the behavior the user prefers (preview or download) but still control the filename in case the user prefers downloading the file.
Update for firefox:
I got a solution for firefox but it is not working in chrome. Instead of
this._blobUrl = URL.createObjectURL(blob);
I do
let file = new File([blob], this.downloadname, {type: 'application/pdf'});
this._blobUrl = URL.createObjectURL(file);
Chrome does expose this preference through the navigator.plugins dictionary. If this object contains a PDF Reader, then you know the user wants to see it displayed in their browser.
const opensInBrowser = [...navigator.plugins].some(plug => [...plug].some(mime => mime.type === 'application/pdf'))
console.log(opensInBrowser);
But this does only work for Chrome. Firefox doesn't expose this information here (IIRC they don't technically use a Plugin to display the pdf). So this means that we can't use only this; Firefox will always be marked as not opening in browser, while it may very well be.
So I think the only way is still a very long one... exposed in details here..
Using a Service Worker, we can fake a request to a named file, that Chrome will use to set the name, both of the downloaded file and of the pdf read by the plugin.
That is until they follow Firefox in forwarding correctly File objects names through the Blob URIs that point to them.
Simpliest solution (that should also work with IE10) is to create an a element, attach it to body, set it's name, let user download it and remove after, something like this:
function save(){
const file = new File(['this is where BLOB should go'], {type: 'application/pdf'}); // edit this line to have access to source blob
const link = document.createElement('a');
link.href = URL.createObjectURL(file);
link.download = 'this is the name.pdf';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
window.save = save;
and for HTML:
<a class="downloadlink" id="downloadlink" target="_blank" onclick='save()'>here is your link</a>
working example can be found here
take notice of:
you should edit the onclick function to pass the blob you're
expecting to be as an output of the file
in example i created a pdf only, however you can extend this
functionality pretty easily to any kind of document you need (and is
recognizable by given browser)

Set the default save as name for a an <embed> or <iframe> that uses a Blob [duplicate]

This question already has answers here:
Can I set the filename of a PDF object displayed in Chrome?
(4 answers)
Closed 1 year ago.
I am generating a PDF in the browser using PDFKit (without node) and displaying it an iframe or an embed tag via the src attribute. The generated blob URL is some kind of UUID. So the overall page looks like:
<embed src="blob:http://localhost/eeaabb..."/>
The PDF appears fine, but when I click the Download link in Chrome, the default file name is the UUID. In FireFox, it is just "document.pdf".
If this were a server-generated PDF I would use Content-Disposition and/or manipulate the URL so the last part of it is the name I want, but that doesn't seem possible with a client-generated object.
Things I have tried:
Setting the PDF title via the metadata. This works but doesn't affect the filename.
Manipulating the embed tag title attribute. Doesn't seem to do anything.
Change the page title. Doesn't affect the file.
Try to append something to the data url. Just prevents the PDF from displaying.
Upload the PDF via POST, then download it via a page where I can control the URL. Could work, but seems crazy to generate a client-side PDF only to have to upload it to the server.
Is there any way around this so that I can control the default/suggested file name?
Note:
This answer is outdated.
The behavior described below did change since it was posted, and it may still change in the future.
Since this question has been asked elsewhere, with better responses, I invite you to read these instead: Can I set the filename of a PDF object displayed in Chrome?
I didn't find, yet, for chrome's default plugin.
I've got something that works for Firefox though, and which will default to download.pdf in chrome, for some odd reason...
By passing a dataURI in the form of
'data:application/pdf;headers=filename%3D' + FILE_NAME + ';base64,...'
Firefox accepts FILE_NAME as the name of your file, but chrome doesn't...
A plnkr to show a better download.pdf in chrome, which doesn't like nested iframes...
And an snippet which will only work in FF :
const FILE_NAME = 'myCoolFileName.pdf';
const file_header = ';headers=filename%3D';
fetch('https://dl.dropboxusercontent.com/s/rtktu1zwurgd43q/simplePDF.pdf?dl=0').then(r => r.blob())
.then(blob=>{
const f = new FileReader();
f.onload = () => myPdfViewer.src = f.result.replace(';', file_header + encodeURIComponent(FILE_NAME) + ';');
f.readAsDataURL(blob);
});
<iframe id="myPdfViewer" width="500" height="500"></iframe>
But note that if it is really important to you, you could of course not rely on browser's own plugins, and use e.g Mozilla's PDF.js over which you'll get an extended control.
Is there any way around this so that I can control the name?
No. You cannot control the name of a file stored at user local filesystem.
You can use <a> element with download attribute set to suggested file name. If user selects to download offered file user can change the file name at any time before or after downloading file.
window.onload = () => {
let blob = new Blob(["file"], {
type: "text/plain"
});
let url = URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "file.txt";
document.body.appendChild(a);
console.log(url);
a.click();
}
At chrome, chromium browsers you can use requestFileSystem to store Blob, File or Directory at LocalFileSystem, which writes file to browser configuration directory, or other directories within user operating system. See
How to Write in file (user directory) using JavaScript?
jQuery File Upload Plugin: Is possible to preserve the structure of uploaded folders?
Where is Blob binary data stored?

Youtube Blob urls don't work in browsers but in src

I know that there are no blob urls only objects.
I made my own blob object for a video buffer and then I used it in a src of video tag which is something like blob://website.com/blablobbla . I opened this url in the browser it worked
when I opened the url of youtube video src (blob url) into a new tab it did't work but mine video src (blob url) worked
I want to know how can I do the same with my blob urls so that they only work in the src of the html video tag and give error or don't work in the external tab/window of the browsers.I just want to know the technology behind this and blob objects and their url properties.
The question seems somewhat vague to me, so here is what I interpret (also from the code in the fiddle-images in your question):
you receive a Blob (image's binary data) through a XMLHttpRequest() GET-request (responseType = 'blob')
you create a Blob URL with URL.createObjectURL() in the URL Store for XMLHttpRequest() response-object (the Blob holding the binary data)
you set the resulting Blob URL-string as src for a image (and append the image to the document, thereby showing the image you just downloaded)
You "don't want it to work in new tab" ("it" being the Blob URL-string I assume).
In your comments you say:
In fiddle I inspected the image and copied the src and then pasted it in new tab and it worked and showed the image I don't want the image to be shown directly with the blob url.
If you go to youtube and open the src of video in new tab : It will not work,, I want this to happen
It appears to me that you do not want the user to be able to view/download the blob when they copy the Blob URL-string (by examining the live source or simply right-click-on-image>>Copy Imagelocation) and paste it into a new tab/window (for which you give youtube as an example).
But you are also talking about video's.
TL;DR: It seems your question/bounty might be mixing up 2 different types of URL returned by window.URL.createObjectURL();:
Blob URL referencing (objects that represent) 'raw local data' (like (Local-)File, Blob, etc.)
For these you want to automatically (or programmatically) revoke the Blob URL from the browser's URL Store (which you could consider a simplified local webserver inside the browser, only available to that browser).
var myBlobURL=window.URL.createObjectURL(object, flag_oneTimeOnly);
returns a re-usable Blob URL which can be revoked with: window.URL.revokeObjectURL(myBlobURL) (adds the Blob URL string to the Revocation List).
Note: there used to be a second argument flag_oneTimeOnly which used to revoke the Blob URL automatically after it's first use, but that is currently no longer part of the spec! Also this flag often didn't work anyway (at least in firefox).
var myBlobURL=window.URL.createFor(object);
returns a Blob URL that is automatically revoked after it's first use.
Note: quite some browsers were 'late' to implement this one.
MediaSource object URL referencing a special MediaSource Object
These URL's are
only intended to link src of a HTMLMediaElement (think <audo> & <video> elements) to the special MediaSource Object
Note: a new tab/window is not an HTMLMediaElement
already automatically revoked
Note: even though they are created through window.URL.createObjectURL();
Here's what's happening for the fiddle in your question's image and similar code that downloaded a video as Blob (where you downloaded the whole video-file's data/binary on the server using an xhr) or any other 'local' data:
You are essentially using the 'bare' 'un-enhanced' File-API.
The URL Store is only maintained during a session (so it will survive a page-refresh, since it is still the same session) and lost when the document is unloaded.
So, if your fiddle is still open, then fiddle-document (the document that created the Blob URL) is obviously not yet unloaded, and therefore it's Blob URLs are available to the browser (any tab/window) as long as it is not revoked!
This is a relevant feature: you can build/download/modify a Blob in the browser, create a Blob URL and set it as href to a file-download link (which the user can right-click and open in a new tab/window!!)
Close the fiddle or revoke the Blob URL from the URL Store and the Blob URL is no longer accessible (also not in a different tab/window).
Try yourself with your modified fiddle: https://jsfiddle.net/7cyoozwv/
In this fiddle it should now no longer be possible to load your sample image into a different tab/window after you copied the image url (once the image is displayed in your page).
Here I revoked the URL manually (revokeObjectURL()) as it is currently the best cross-browser method (partially due to the api not yet fully being stabilized).
Also note: an element's onload event can be an elegant place to revoke your Blob URL.
Here is what's happening to an <audio> or <video> source linked to an MediaSource Object using an MediaSource object URL returned by window.URL.createObjectURL(MediaSource):
The Media Source Extensions (MSE) also extend the File-API's window.URL.createObjectURL() to accept a MediaSource Object. The (current draft of the) URL Object Extension specifies that:
This algorithm is intended to mirror the behavior of the createObjectURL()[FILE-API] method with autoRevoke set to true.
Note that the current spec of the File API's window.URL.createObjectURL() no longer has an autoRevoke (or flag_oneTimeOnly) boolean flag accessible to the programmer who should be using window.URL.createFor() for this purpose instead. I wonder when the Media-Source spec will mimic that (and for backward compatibility alias their createObjectURL() to a new createFor() extension (seems more appropriate as that is how it seems to be intended to work currently)).
These resulting automatically revoked URL-strings are only intended to link the src of a HTMLMediaElement (think <audo> & <video> elements) to the special MediaSource Object.
I don't think that an empty Document (from a new tab/window) is a <audo> or <video> element.
Perhaps "A quick tutorial on MSE"(source: MSDN) might help clarify the difference and basic use:
To use the MSE API, follow these steps:
Define an HTML5 video element in the HTML section of a page.
Create a MediaSource object in JavaScript.
Create a virtual URL using createObjectURL with the MediaSource object as the source.
Assign the virtual URL to the video element's src property.
Create a SourceBuffer using addSourceBuffer, with the mime type of the video you're adding.
Get the video initialization segment from the media file online and add it to the SourceBuffer with appendBuffer.
Get the segments of video data from the media file, append them to the SourceBuffer with appendBuffer.
Call the play method on the video element.
Repeat step 7 until done.
Clean up.
You (or a big-time player like youtube who will dynamically select supported technologies for playback on the client's platform (so there is no way to tell for sure what kind of youtube video URL's you are talking about)) could be using the new special MediaSource Object to play video's (or audio).
This adds buffer-based source options to HTML5 video for streaming support (compared to to downloading a complete video file before playing or use an add-on like Silverlight or Adobe Flash to stream media).
Hope this is what you were after!
Actually, the URL that you're referring is just a "string" reference to the BLOB itself (which is created using the function window.URL.createObjectURL); So, that you can use it like a normal URL. And, the scope is also only until the document is unloaded.
So, I don't think it is possible for you to open the URL just using browser. And also I tried to re-create what you're saying but with no avail (in my own website, create a blob and put the URL into browser).
Below is the code
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://kurrik.github.io/hackathons/static/img/sample-128.png");
xhr.responseType = "blob";
xhr.onload = function response(e) {
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(this.response);
console.log(imageUrl);
var imgDOM = document.createElement("img");
imgDOM.src = imageUrl;
document.getElementById("divImage").appendChild(imgDOM);
};
xhr.send();
The fiddle here
Update :
Ok, after I looked at it. seems like youtube is using media-source to stream the video.
I haven't updated the fiddle (cannot found a video that I can use). But, basically, It still using the same function (createObjectURL) to create the blob URL. But, instead of using the source (image, video, etc) to pass to the function. You should pass the MediaSource object into the function.
And then, you use the blob URL and pass it into the video.src. Therefore, when you try to open the blob link. You should not be able to see the video again.

Is It Possibly to Access Firefox Save As Command Using JS?

I'm trying to figure out how to call the File Save As Command in Firefox
(the one you get when you right click an image and save it) to save an image using JS (or if there is something else I can use, I would be grateful if you pointed me in that direction). I am looking for an example of how to open the Save As menu and pre-fill the file name field ... I've been searching furiously and have come up with zip. In my search I saw that you cannot directly save a file to disk, but is it impossible to call the save as function? Any suggestions would be greatly appreciated!
Edit:
I'm not looking to make this code available to everyone, and the java script is client side, I'm just writing a small script to make saving photos a little easier in terms of naming them.
-Will
No you can't do this, and really you are trying to find a solution in a way that does not embrace the internet and the way people interact with content. What you are trying to do is call on Operating System operation from Javascript. If there were anyway this would be possible, I don't think it is at all, it would be a very poor solution. Think about all the different Operating Systems Firefox is being used on. If you found a solution for Windows 7, what about an Apple Mac running Firefox?
What you should consider is that a User decides whether to Save something to their computer, not the programmer of the application. Provide a link to the file, most users know how to right click a link and select Save As. Add help tip explaining what to do as well.
To give a File a specific name or even start an automatic download when a User clicks or takes some kind of action, you can create a response from your server that is a PDF,Excel,Jpeg,Doc,Docx or many other files types. The server can load the file in memory and sent it as a response with the proper header information in the response.
For example to set a specific name for the file when the user downloads you can set your Response header with something like:
header('Content-Disposition: attachment; filename="downloaded.pdf"');
You can use the anchor element's download attribute to specify that a link is to be downloaded. Note that this is not implemented in all browsers, Chrome, Firefox, and Opera currently support it
https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
HTMLAnchorElement.download
Is a DOMString indicating that the linked
resource is intended to be downloaded rather than displayed in the
browser. The value represent the proposed name of the file. If the
name is not a valid filename of the underlying OS, browser will adapt
it. The value is a URL with a scheme like http:, file:, data: or even
blob: (created with URL.createObjectURL).
Demo
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillRect(25,25,100,100);
ctx.clearRect(45,45,60,60);
ctx.strokeRect(50,50,50,50);
var link = document.getElementById("link");
//Set href to the data url that you want downloaded
link.href = "http://placehold.it/350x350";
//set download to the default filename you want to use
link.download = "image.png";
<canvas id="canvas" width="150" height="150"></canvas>
Click to download
You can also specify a regular url to a file, but note that if the server sends a filename header: Content-Disposition ... filename... that it will overwrite whatever you have in the download attribute.

How do I change a filename on-download with javascript?

The script adds a download link for videos (on a specific site). How do I change the filename to something else while downloading?
Example URL:
"http://website.com/video.mp4"
Example of what I want the filename to be saved as during download:
"The_title_renamed_with_javascript.mp4"
This actually is possible with JavaScript, though browser support would be spotty. You can use XHR2 to download the file from the server to the browser as a Blob, create a URL to the Blob, create an anchor with its href property set to that URL, set the download property to whatever you want the filename to be, and then click the link. This works in Google Chrome, but I haven't verified support in other browsers.
window.URL = window.URL || window.webkitURL;
var xhr = new XMLHttpRequest(),
a = document.createElement('a'), file;
xhr.open('GET', 'someFile', true);
xhr.responseType = 'blob';
xhr.onload = function () {
file = new Blob([xhr.response], { type : 'application/octet-stream' });
a.href = window.URL.createObjectURL(file);
a.download = 'someName.gif'; // Set to whatever file name you want
// Now just click the link you created
// Note that you may have to append the a element to the body somewhere
// for this to work in Firefox
a.click();
};
xhr.send();
You can't do this with client-side JavaScript, you need to set the response header...
.NET
Response.AddHeader("Content-Disposition", "inline;filename=myname.txt")
Or PHP
header('Content-Disposition: inline;filename=myname.txt')
Also available in other server-side languages of your choice.
The filename for downloading is set in the header (take a look at "Content-Disposition"), wich is created on server-side.
There's no way you could change that with pure javascript on a file you're linking to unless you have access to the server-side (that way you could pass an additional parameter giving the filename and change the server-side behaviour to set the header to match that... but that would also be possible with pure html, no need for javascript). Conclusion: Javascript is absolute useless to achive what you want.
You can probably do this with a Chrome userscript, but it cannot be done (yet) with Greasemonkey (Firefox) javascript.
Workaround methods (easiest to hardest):
Add the links with Greasemonkey but use the excellent DownThemAll! add-on to download and rename the videos.
Download the videos as-is and use a batch file, shell-script, Python program, etc. to rename them.
Use Greasemonkey's GM_xmlhttpRequest()Doc function to send the files to your own web application on a server you control.
This server could be your own PC running XAMPP (or similar).
Write your own Firefox add-on, instead of a Greasemonkey script. Add-ons have the required privileges, Greasemonkey does not.
AFAIK, you will not be able to do this right from the client itself. You could first upload the file onto the server with the desired name, and then serve it back up to the end user (in which case your file name would be used).
Just in case you are looking for such a solution for your nasty downloading chrome extension, you should look into chrome.downloads API, it needs additional permission ('downloads') and allows you to specify filename. https://developer.chrome.com/extensions/downloads
However there is a problem I'm facing right now. The chrome extension I'm refactoring has 600k+ user base and adding a new permission would disable the extension for all of them. So it is no-go solution for me, but if you are developing a new extension you definitely should use it.

Categories

Resources