2011-01-30 22 views
27

Estoy creando una extensión que descargará un archivo mp3 de un sitio web. Intento hacer esto creando una nueva pestaña con el enlace al archivo mp3, pero Chrome sigue abriéndolo dentro del reproductor en lugar de descargarlo. ¿Hay alguna manera de que pueda crear una ventana emergente para pedirle al usuario que "guarde como" el archivo?Hacer una extensión de Chrome descargar un archivo

+2

ver http://stackoverflow.com/questions/399486/open- the-save-image-dialog-using-jquery-javascript – serg

Respuesta

64

de avance rápido 3 años, y ahora Google Chrome ofrece chrome.downloads API (desde Chrome 31).

Después de declarar "downloads" permiso en el manifiesto, se puede iniciar una descarga con esta llamada:

chrome.downloads.download({ 
    url: "http://your.url/to/download", 
    filename: "suggested/filename/with/relative.path" // Optional 
}); 

Si desea generar el contenido del archivo en la secuencia de comandos, puede utilizar Blob y URL API, por ejemplo:

var blob = new Blob(["array of", " parts of ", "text file"], {type: "text/plain"}); 
var url = URL.createObjectURL(blob); 
chrome.downloads.download({ 
    url: url // The object URL can be used as download URL 
    //... 
}); 

Para obtener más opciones (es decir, de diálogo Guardar como, sobrescribir archivos existentes, etc.), ver la documentation.

+0

¡Gracias! ¿Es posible que Chrome agregue un archivo a un archivo existente? Quiero descargar un archivo hecho de fragmentos, lo que da como resultado un archivo completo en lugar de múltiples fragmentos. – marlar

+0

@marlar Para eso, sería mejor emplear la [API del sistema de archivos] (http://www.html5rocks.com/en/tutorials/file/filesystem/) (a pesar de la advertencia, es compatible con Chrome) para obtener el trozos, construya el archivo completo, y luego 'descargue' el resultado en la carpeta de Descargas. Pero es una pregunta diferente; si aún necesita ayuda, haga una nueva pregunta. – Xan

+0

"nombre de archivo" se ignora por completo en mi sistema! – jumpjack

5

Lo hice de la siguiente manera en el código Appmator en Github.

El enfoque básico es construir tu Blob, como quieras (Chrome tiene un responseBlob en XmlHttpRequest para que puedas usar eso), crea un iframe (oculto, display:none) y luego asigna el src del iframe para que sea Blob.

Esto iniciará una descarga y la guardará en el sistema de archivos. El único problema es que aún no puedes configurar el nombre de archivo.

var bb = new (window.BlobBuilder || window.WebKitBlobBuilder)(); 

var output = Builder.output({"binary":true}); 
var ui8a = new Uint8Array(output.length); 

for(var i = 0; i< output.length; i++) { 
    ui8a[i] = output.charCodeAt(i); 
} 

bb.append(ui8a.buffer); 

var blob = bb.getBlob("application/octet-stream"); 
var saveas = document.createElement("iframe"); 
saveas.style.display = "none"; 

if(!!window.createObjectURL == false) { 
    saveas.src = window.webkitURL.createObjectURL(blob); 
} 
else { 
    saveas.src = window.createObjectURL(blob); 
} 

document.body.appendChild(saveas); 

Un ejemplo del uso responseBlob de XmlHttpRequest (ver: http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-responseblob)

var xhr = new XmlHttpRequest(); 
xhr.overrideMimeType("application/octet-stream"); // Or what ever mimeType you want. 
xhr.onreadystatechanged = function() { 
if(xhr.readyState == 4 && xhr.status == 200) { 

    var blob = xhr.responseBlob(); 
    var saveas = document.createElement("iframe"); 
    saveas.style.display = "none"; 

    if(!!window.createObjectURL == false) { 
    saveas.src = window.webkitURL.createObjectURL(blob); 
    } 
    else { 
    saveas.src = window.createObjectURL(blob); 
    } 

    document.body.appendChild(saveas); 
} 
+0

¿Cuál es el propósito de la primera línea de ese código? –

+0

Ese es un buen punto ... debidamente observado. – Kinlan

+0

¿Dónde especifico el archivo que intento descargar? –

13

He utilizado una variante de la solución here

var downloadCSS = function() { 
    window.URL = window.webkitURL || window.URL; 
    file = new BlobBuilder(); //we used to need to check for 'WebKitBlobBuilder' here - but no need anymore 
    file.append(someTextVar); //populate the file with whatever text it is that you want 
    var a = document.createElement('a'); 
    a.href = window.URL.createObjectURL(file.getBlob('text/plain')); 
    a.download = 'combined.css'; // set the file name 
    a.style.display = 'none'; 
    document.body.appendChild(a); 
    a.click(); //this is probably the key - simulatating a click on a download link 
    delete a;// we don't need this anymore 
} 

Una cosa que hay que ten en cuenta es que este código debe ejecutarse en la página y no en su extensión; de lo contrario, el usuario no verá la acción de descarga que realiza Chrome. La descarga seguirá ocurriendo y podrá verla en la pestaña de descarga, pero no verán la descarga real.

Editar (idea de último momento de hacer su código de ejecución en la página de contenido):

La forma en que una acción ocurren en la página de contenido en lugar de su extensión es utilizar Chrome "message passing". Básicamente, pasa un mensaje de su extensión (que es casi como una página separada) a la página de contenido con la que está trabajando la extensión. Luego tiene un oyente que su extensión ha inyectado en la página de contenido que reacciona al mensaje y realiza la descarga. Algo como esto:

chrome.extension.onMessage.addListener(
    function (request, sender, sendResponse) { 
     if (request.greeting == "hello") { 
      try{ 
       downloadCSS(); 
      } 
      catch (err) { 
       alert("Error: "+err.message); 
      } 
     } 
    }); 
+1

¡gracias por la solución con 'a.download'! ayuda mucho –

+0

'delete a;' no hace lo que crees que hace aquí, realmente necesitas 'a.parentNode.removeChild (a);'. (Eliminar la referencia a a no es necesario porque como variable local se pierde cuando la función se completa). – ejm

10

Ésta es una versión ligeramente modificada de la respuesta de @Steve Mc que sólo lo hace en una función generalizada que puede ser fácilmente copiado y es usado como:

function exportInputs() { 
    downloadFileFromText('inputs.ini','dummy content!!') 
} 

function downloadFileFromText(filename, content) { 
    var a = document.createElement('a'); 
    var blob = new Blob([ content ], {type : "text/plain;charset=UTF-8"}); 
    a.href = window.URL.createObjectURL(blob); 
    a.download = filename; 
    a.style.display = 'none'; 
    document.body.appendChild(a); 
    a.click(); //this is probably the key - simulating a click on a download link 
    delete a;// we don't need this anymore 
} 
+1

Para las personas actuales: la respuesta de SteveMC ya no funciona, pero esta sí. –

1

Aquí está una manera concisa para descargar un archivo mediante "descargas" permiso en Chrome manifestar usando @Xan y @ solución de AmanicA

function downloadFile(options) { 
    if(!options.url) { 
     var blob = new Blob([ options.content ], {type : "text/plain;charset=UTF-8"}); 
     options.url = window.URL.createObjectURL(blob); 
    } 
    chrome.downloads.download({ 
     url: options.url, 
     filename: options.filename 
    }) 
} 

// Download file with custom content 
downloadFile({ 
    filename: "foo.txt", 
    content: "bar" 
}); 

// Download file from external host 
downloadFile({ 
    filename: "foo.txt", 
    url: "http://your.url/to/download" 
}); 
Cuestiones relacionadas