I am writing an extension to download videos from a website. That web site has mp4 files and m3u8 files. I have already implemented the part to download direct mp4 files. I stuck at converting the m3u8 file to mp4. I tried lot of js packages but there are a lot of dependencies and failed even after using browserfy.
Current popup.js file
function loadvideoList(callback){
chrome.storage.sync.get(['courseID'], function(result) {
if(result.courseID != 'undefined'){
$.ajax({
type: 'GET',
url: "http://localhost:80/get_videos_list/"+result.courseID,
crossDomain: true,
success: function(response) {
document.getElementById("loading_icon").style.display='none';
document.getElementById("videos_list").style.display='block';
document.getElementById("videos_list").style.padding='10px';
for(var i = 0; i < response.video_list.length; i++){
if(response.video_list[i].type == 'mp4'){
handleDownloadButton(response.video_list[i]);
}else{
// ************ HERE ***************
handleDownloadButton-m3u8Tomp4(response.video_list[i].video_url)
}
}
},
error: function (err) {
alert("unexpected error occured: "+err.code);
console.log(err);
}
});
}else{
document.getElementById("videos_list").style.display='none';
document.getElementById("videos_list").style.padding='0';
}
});
}
function handleDownloadButton(json_vid){
var node = document.createElement("DIV");
// node.style.marginBottom = "5px"
var t = document.createElement('p');
t.textContent = json_vid.file_name;
t.style.width ="240px";
node.appendChild(t);
node.style.padding = "5px";
var downloadBtn = document.createElement("BUTTON");
downloadBtn.style.cssFloat = "right";
downloadBtn.className = "btn btn-primary btn-sm download_btn";
downloadBtn.innerHTML = "Download";
// downloadBtn.value = json_vid.video_url;
node.appendChild(downloadBtn);
downloadBtn.id = json_vid.video_id;
document.getElementById("videos_list").appendChild(node);
var progress_bar = document.createElement("DIV");
progress_bar.className = "progress_container";
node.appendChild(progress_bar);
var moving_bar = document.createElement("DIV");
moving_bar.className = "progress_bar";
progress_bar.appendChild(moving_bar);
moving_bar.id = json_vid.video_id+"bar";
$(function(){
$(`#${json_vid.video_id}`).click(function(){
$(`#${json_vid.video_id}`).attr("disabled", true);
// alert(json_vid.video_url);
var that = this;
var page_url = json_vid.video_url;
var req = new XMLHttpRequest();
req.open("GET", page_url, true);
// req.withCredentials = true;
req.addEventListener("progress", function (evt) {
if(evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
// document.getElementById("download_stat").innerHTML = percentComplete;
// console.log(percentComplete);
document.getElementById(json_vid.video_id+"bar").style.width = `${percentComplete*100}%`;
document.getElementById(json_vid.video_id).textContent = `${(percentComplete*100).toFixed(2)}%`;
}
}, false);
req.responseType = "blob";
req.onreadystatechange = function () {
if (req.readyState === 4 && req.status === 200) {
var filename = $(that).data('filename');
if (typeof window.chrome !== 'undefined') {
// Chrome version
$(`#${json_vid.video_id}`).attr("disabled", false);
$(`#${json_vid.video_id}`).attr("onclick", "").unbind("click");
document.getElementById(json_vid.video_id).textContent = 'Save';
$(function(){
$(`#${json_vid.video_id}`).click(function(){
// alert("download is ready");
var link = document.createElement('a');
// link.text = "download is ready";
// document.getElementById("videos_list").appendChild(link);
link.href = window.URL.createObjectURL(req.response);
link.download = json_vid.file_name;
link.click();
});
});
} else if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE version
var blob = new Blob([req.response], { type: 'application/force-download' });
window.navigator.msSaveBlob(blob, filename);
} else {
// Firefox version
var file = new File([req.response], filename, { type: 'application/force-download' });
window.open(URL.createObjectURL(file));
}
}
};
req.send();
});
});
}
handleDownloadButton function create the button to download the direct mp4 files. I need to implement a similar function called handleDownloadButton-m3u8Tomp4(see the code sample) that should first convert the http://...file.m3u8 to a mp4 and make it also downloadable. I seek for a script in similar repos like https://github.com/puemos/hls-downloader-chrome-extension, but I was unable to do so. It would be great, If anyone could help me, Thanks in advance!
You can try to use ffmpeg.wasm to convert the .m3u8 file to a .mp4 file. ffmpeg.wasm is a pure WebAssembly / JavaScript port of FFmpeg. They even have an example repository for a Chrome extension. I haven't tested it myself though.
There are other questions here on StackOverflow that deal with how to convert a m3u8 file with FFmpeg, like this one for example.
Related
Hello Developers,
I'm trying to download the list of files getting form XMLHttpRequest() request method and store it in the array of files. I wanted to zip all the files in an array using javascript without using any 3rd party library.
I have tried to achieve this by URL.createObjectURL(url) and URL.revokeObjectURL(url) method but the file I'm getting is corrupted.
I'm Sharing my code snippet please help me out
const URLS = [
'https://vr.josh.earth/assets/2dimages/saturnv.jpg',
'https://vr.josh.earth/assets/360images/hotel_small.jpg',
'https://vr.josh.earth/assets/360images/redwoods.jpg'
];
$(document).ready(function () {
debugger
$("#downloadAll").click(function () {
var blob = new Array();
var files = new Array();
URLS.forEach(function (url, i) {
getRawData(url, function (err, data) {
debugger
var mydata = data;
// mydata = btoa(encodeURIComponent(data));
// var blobData = b64toBlob(mydata , 'image/jpg');
var blobData = new Blob([mydata], { type: 'image/jpg' });
blob.push(blobData);
var filename = "testFiles" + i + ".jpg";
var file = blobToFile(blobData, filename);
files.push(file);
debugger
if (files.length == URLS.length) {
// saveData(blob, "fileName.zip");
var AllBlobData = new Blob([blob], { type: 'application/zip' });
saveData(AllBlobData, "Test.zip");
// saveFile("DownloadFiles.zip", "application/zip", files)
}
});
});
});
});
//Retriving record using XMLHttpRequest() method.
function getRawData(urlPath, callback, progress) {
var request = new XMLHttpRequest();
request.open("GET", urlPath, true);
request.setRequestHeader('Accept', '');
if ('responseType' in request)
request.responseType = "arraybuffer"
if (request.overrideMimeType)
request.overrideMimeType('text/plain; charset=x-user-defined');
request.send();
var file, err;
request.onreadystatechange = function () {
if (this.readyState === 4) {
request.onreadystatechange = null;
if (this.status === 200) {
try {
debugger
var file = request.response || request.responseText;
} catch (error) {
throw error;
}
callback(err, file);
} else {
debugger
callback(new Error("Ajax Error!!"))
}
} else {
debugger
}
}
}
//For Saving the file into zip
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
// var AllBlobs = new Blob([data], { type: "" });//application/zip //octet/stream
// var url = window.URL.createObjectURL(AllBlobs);
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
//Downloaded Zip File
enter image description here
I'm working on Google drive integration with salesforce. Currently I'm facing file corruption when I tried to download file using java script. My code is as followed
function downloadGDriveFile() {
var id = '0B3EI0BFOUwSydHZNZXdIZ3lDZzg';
var downloadUrl = 'https://www.googleapis.com/drive/v2/files/'+ id+'?alt=media';
var accessToken = MY ACCESS TOKEN;
var mType = 'image/jpeg';
var name = 'Internet_of_Things.jpg';
if (downloadUrl) {
var xhr = new XMLHttpRequest();
xhr.open('GET', downloadUrl);
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.onload = function() {
onDownload(xhr.response);
};
xhr.onerror = function() {
//downloadFile(null);
};
xhr.send();
}
else {
alert("Unable to download file.");
}
}
function onDownload(data) {
var filename = 'Internet_of_Things.jpg';
var blob = new Blob([data], { type: "image/jpeg" });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
//window.location = downloadUrl;
}
alert(11);
//URL.revokeObjectURL(downloadUrl);
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 1); // cleanup
}
}
when file is downloaded file is corrupted.File content shown as follow
���� JFIF �� hExif MM * > F( 1 N Paint.NET v3.5.11 �� C �� C�� ��" ��
Dose any one can help me to sort this out. Do I need to encode or decode the Response from Google REST API?
I'm using angular 1.2.27, and I'm trying to download a file. It works perfect on chrome but on FF nothing happens, the request returns 200/ok and the success code runs, but that's it, no file is downloaded:
var fileLoaded = $q.defer();
$http.get(url, { responseType: 'arraybuffer' })
.success(function (data,status,hdr) {
var cd = hdr('Content-Disposition').split(';');
var fileName = '';
_.forEach(cd,function(d){
if(d.trim().indexOf('filename') >= 0){
fileName = d.split('=')[1].replace(/[\"]/g,'');
return false;
}
});
var file = new Blob([data]);
var wurl = $window.URL || $window.webkitURL;
var fileURL = wurl.createObjectURL(file);
console.log( 'fileURL:' , fileURL );
var a = document.createElement("a");
a.href = fileURL;
a.download = fileName;
a.target = "_self";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
wurl.revokeObjectURL(fileURL);
fileLoaded.resolve(true);
}).error(function (data) {
// console.error(data);
fileLoaded.reject(data);
});
return fileLoaded.promise;
}
The only difference i see is when i log the fileURL. on chrome it appears like this:
blob:http%3A//localhost%3A9000/e869aa88-8190-4d9d-a379-9ad977a09613
And on FF like this:
blob:http://localhost:9000/f36b7773-00bb-4ade-87be-8f197c41ccf8
But I assume this is just a console thing.
any idea what I'm doing wrong?
Putting an answer here for reference. Using FileSaver from #Satpal comment, i was able to solve it easily:
var fileLoaded = $q.defer();
$http.get(url, { responseType: 'arraybuffer' })
.success(function (data,status,hdr) {
var cd = hdr('Content-Disposition').split(';');
var fileName = '';
_.forEach(cd,function(d){
if(d.trim().indexOf('filename') >= 0){
fileName = d.split('=')[1].replace(/[\"]/g,'');
return false;
}
});
var file = new Blob([data]);
saveAs(file, fileName);
fileLoaded.resolve(true);
}).error(function (data) {
// console.error(data);
fileLoaded.reject(data);
});
return fileLoaded.promise;
}
I want to build a voice recorder using HTML5 same as one found in gitHub JSSoundecorder, but what I want is for the user to be able to choose the file format before recording the voice.I can do this using ffmpeg. In other words the user must be able to select the audio format by check box (mp3,wma,pcm) and in the background code, the .wav file usually created by the program instead of displaying it, it should be converted by the format selected then displayed in the new format.this is the ffmpeg code we can use ,but I don't know how to get the .wav audio file to convert it and show it.please if someone have ideas,or if can find demos I have been looking for weeks.this is the ffmpeg code:
var fileName;
var fileBuffer;
function timeToSeconds(time) {
var parts = time.split(":");
return parseFloat(parts[0]) * 60 * 60 + parseFloat(parts[1]) * 60 + parseFloat(parts[2]) + parseFloat("0." + parts[3]);
}
// create ffmpeg worker
function getFFMPEGWorker() {
// regexps for extracting time from ffmpeg logs
var durationRegexp = /Duration: (.*?), /
var timeRegexp = /time=(.*?) /;
var duration;
var ffmpegWorker = new Worker('worker.js');
var durationLine;
ffmpegWorker.addEventListener('message', function(event) {
var message = event.data;
console.log(message.type);
if (message.type === "ready" && window.File && window.FileList && window.FileReader) {
// script loaded, hide loader
$('#loading').hide();
} else if (message.type == "stdout") {
console.log(message.data);
} else if (message.type == "stderr") {
console.log(message.data);
// try to extract duration
if (durationRegexp.exec(message.data)) {
duration = timeToSeconds(durationRegexp.exec(message.data)[1]);
}
// try to extract time
if (timeRegexp.exec(message.data)) {
var time = timeToSeconds(timeRegexp.exec(message.data)[1]);
if (duration) {
$("#progress").text("Progress: " + Math.floor(time / duration * 100) + "%");
$("#progress").show();
}
}
} else if (message.type == "done") {
var code = message.data.code;
console.log(message.data);
var outFileNames = Object.keys(message.data.outputFiles);
console.log(outFileNames);
if (code == 0 && outFileNames.length) {
var outFileName = outFileNames[0];
var outFileBuffer = message.data.outputFiles[outFileName];
var src = window.URL.createObjectURL(new Blob([outFileBuffer]));
$("#downloadLink").attr('href', src);
$("#download").show();
} else {
$("#error").show();
}
$("#converting").hide();
$("#progress").hide();
}
}, false);
return ffmpegWorker;
}
// create ffmpeg worker
var ffmpegWorker = getFFMPEGWorker();
var ffmpegRunning = false;
$('#convert').click(function() {
// terminate existing worker
if (ffmpegRunning) {
ffmpegWorker.terminate();
ffmpegWorker = getFFMPEGWorker();
}
ffmpegRunning = true;
// display converting animation
$("#converting").show();
$("#error").hide();
// hide download div
$("#download").hide();
// change download file name
var fileNameExt = fileName.substr(fileName.lastIndexOf('.') + 1);
var outFileName = fileName.substr(0, fileName.lastIndexOf('.')) + "." + getOutFormat();
$("#downloadLink").attr("download", outFileName);
$("#downloadLink").text(outFileName);
var arguments = [];
arguments.push("-i");
arguments.push(fileName);
arguments.push("-b:a");
arguments.push(getBitrate());
switch (getOutFormat()) {
case "mp3":
arguments.push("-acodec");
arguments.push("libmp3lame");
arguments.push("out.mp3");
break;
case "wma":
arguments.push("-acodec");
arguments.push("wmav1");
arguments.push("out.asf");
break;
case "pcm":
arguments.push("-f");
arguments.push("s16le");
arguments.push("-acodec");
arguments.push("pcm_s16le");
arguments.push("out.pcm");
}
ffmpegWorker.postMessage({
type: "command",
arguments: arguments,
files: [
{
"name": fileName,
"buffer": fileBuffer
}
]
});
});
function getOutFormat() {
return $('input[name=format]:checked').val();
}
function getBitrate() {
return $('input[name=bitrate]:checked').val();
}
// disable conversion at start
$('#convert').attr('disabled', 'true');
function readInputFile(file) {
// disable conversion for the time of file loading
$('#convert').attr('disabled', 'true');
// load file content
var reader = new FileReader();
reader.onload = function(e) {
$('#convert').removeAttr('disabled');
fileName = file.name;
console.log(fileName);
fileBuffer = e.target.result;
}
reader.readAsArrayBuffer(file);
}
// reset file selector at start
function resetInputFile() {
$("#inFile").wrap('<form>').closest('form').get(0).reset();
$("#inFile").unwrap();
}
resetInputFile();
function handleFileSelect(event) {
var files = event.target.files; // FileList object
console.log(files);
// files is a FileList of File objects. display first file name
file = files[0];
console.log(file);
if (file) {
$("#drop").text("Drop file here");
readInputFile(file);
}
}
// setup input file listeners
document.getElementById('inFile').addEventListener('change', handleFileSelect, false);
Hi i am downloading selected links using chrome extension but I can't set downloads location. All the urls downloaded to default location of chrome. i know we can't do it because of security reason. can we prompt directory chooser dialog in chrome extension popup from here user can select the Download path.Need any information from my side let me know.
Is this possible at all? Any suggestions on how to go about it?
Thanks in advance
My code
function downloadFile(url, onSuccess,arrayOfUrl,zip) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (onSuccess)
{
onDownloadComplete(xhr.response, arrayOfUrl,zip)
}
}
}
xhr.send("null");
}
function onDownloadComplete(blobData,urls,zip ){
if (count < urls.length) {
blobToBase64(blobData, function(binaryData){
var fileName = urls[count].substring(urls[count].lastIndexOf('/')+1);
zip.file(fileName+".docx", binaryData, {base64: true});
if (count < urls.length -1){
count++;
downloadFile(urls[count], onDownloadComplete, urls,zip);
}
else {
var content = zip.generate();
var zipName = 'download.zip';
var a = document.createElement('a');
a.href = "data:application/zip;base64," + content;
a.download = zipName;
a.click();
count = 0;
}
});
}
}
popup.js
function onDownloadComplete(blobData,urls,zip ){
if (count < urls.length) {
blobToBase64(blobData, function(binaryData){
// add downloaded file to zip:
var fileName = urls[count].substring(urls[count].lastIndexOf('/')+1);
// zip.file(fileName, binaryData, {base64: true});
zip.file(fileName+".docx", binaryData, {base64: true}); //file"+count+".docx"
if (count < urls.length -1){
count++;
downloadFile(urls[count], onDownloadComplete, urls,zip);
}
else {
chrome.runtime.getBackgroundPage(function () {
zipAndSaveFiles(zip);});
}
});
}
}
**background.js**
function zipAndSaveFiles(zip)
{
var content = zip.generate(zip);
var zipName = 'download.zip';
var dataURL = 'data:application/zip;base64,' + content;
chrome.downloads.download({
url: dataURL,
filename: zipName,
saveAs: true
});
}
Since you are generating and downloading just one ZIP file, you can use the chrome.downloads.download() method. E.g.:
var content = zip.generate();
var zipName = 'download.zip';
var dataURL = 'data:application/zip;base64,' + content;
chrome.downloads.download({
url: dataURL,
filename: zipName,
saveAs: true
});
count = 0;
If you omit the display of a SaveAs dialog, then you can only specify a file name that is inside the user-defined download folder or in a subfolder of it.
Regarding the issue with the popup (see comment below):
You should call the function from your background-page, not the popup. E.g. you could use chrome.runtime.sendMessage/onMessage to pass a message to your background-page:
In background.js:
...
function zipAndSaveFiles(...) { ... }
chrome.runtime.onMessage.addListener(function(msg, sender) {
if ((msg.action === 'zipAndSave')
&& (msg.params !== undefined)) {
zipAndSaveFiles(msg.params);
}
});
In popup.js:
...
chrome.runtime.sendMessage({
action: 'zipAndSave',
params: ['url1', 'url2', 'url3']
});