2011-01-30 22 views
27

Tworzę rozszerzenie, które spowoduje pobranie pliku mp3 ze strony internetowej. Próbuję to zrobić, tworząc nową zakładkę z linkiem do pliku mp3, ale Chrome nadal otwiera ją w odtwarzaczu zamiast go pobierać. Czy jest jakiś sposób, aby utworzyć okienko pop-up, aby poprosić użytkownika o "zapisanie jako" pliku?Tworzenie rozszerzenia Chrome pobierz plik

+2

zobaczyć http://stackoverflow.com/questions/399486/open- a-save-image-dialog-using-jquery-javascript – serg

Odpowiedz

64

Przewijanie do przodu 3 lata, a teraz Google Chrome oferuje chrome.downloads API (od Chrome 31).

Po zadeklarowaniu "downloads" pozwolenie w manifeście, można zainicjować pobieranie z tej rozmowy:

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

Jeśli chcesz wygenerować zawartość pliku w skrypcie, można użyć Blob i URL API, np:

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 
    //... 
}); 

Aby uzyskać więcej opcji (tj dialogowym Zapisz jako, zastępując istniejące pliki, etc.), zobacz documentation.

+0

Dzięki! Czy Chrome może dodać plik do istniejącego pliku? Chcę pobrać plik złożony z fragmentów, w wyniku czego powstanie jeden kompletny plik zamiast wielu fragmentów. – marlar

+0

@marlar W tym celu najlepiej byłoby użyć [interfejsu API systemu plików] (http://www.html5rocks.com/en/tutorials/file/filesystem/) (pomimo ostrzeżenia, jest on obsługiwany w Chrome), aby uzyskać porcje, skompiluj kompletny plik, a następnie "pobierz" wynik do folderu Downloads. Ale to inne pytanie; jeśli nadal potrzebujesz pomocy, zadaj nowe pytanie. – Xan

+0

"filename" jest całkowicie ignorowany w moim systemie! – jumpjack

5

Zrobiłem to w następujący sposób w Appmator kod na Github.

Podstawowym podejściem jest zbudowanie swojego Bloba, jakkolwiek chcesz (Chrome ma element ResponseBlob na XmlHttpRequest, więc możesz go użyć), utwórz element iframe (ukryty, display:none), a następnie przypisz src elementu iframe jako Blob.

Spowoduje to pobranie pliku i zapisanie go w systemie plików. Jedynym problemem jest to, że nie możesz jeszcze ustawić nazwy pliku.

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); 

przykład użycia responseBlob XMLHttpRequest (patrz: 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

jaki jest cel pierwszej linii tego kodu? –

+0

To jest dobry punkt ... bardzo zauważony. – Kinlan

+0

Gdzie mogę określić plik, który próbuję pobrać? –

13

użyłem wariację na rozwiązanie 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 
} 

Jedno trzeba mieć na uwadze to, że ten kod musi zostać wykonany na stronie, a nie na twoim rozszerzeniu - w przeciwnym razie użytkownik nie zobaczy akcji pobierania, którą robi chrome. Pobieranie nadal będzie możliwe i będzie można je zobaczyć na karcie pobierania, ale nie będą one widoczne.

Edit (refleksja na temat tworzenia kodu wykonać na stronie treści):

Sposób dokonania czynności wystąpić na stronie zawartości zamiast numer wewnętrzny jest używać Chrome "message passing". Zasadniczo przekazujesz wiadomość z twojego rozszerzenia (która jest prawie jak oddzielna strona) do strony treści, z którą współpracuje rozszerzenie. Następnie masz słuchacza, który twój wstrzyknął na stronę treści, która zareaguje na wiadomość i pobiera ją. Coś takiego:

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

dziękuję za obejście problemu z 'a.download'! bardzo pomaga –

+0

'delete a;' nie robi tego, co myślisz, że robi tutaj, faktycznie potrzebujesz 'a.parentNode.removeChild (a);'. (Usunięcie odniesienia do a nie jest konieczne, ponieważ jako zmienna lokalna jest tracona po zakończeniu funkcji). – ejm

10

Jest to nieco zmodyfikowana wersja odpowiedzi @Steve MC, które po prostu sprawia, że ​​do uogólnionej funkcji, które mogą być łatwo kopiowane i używane jak:

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

Dla aktualnych osób: odpowiedź SteveMC już nie działa, ale ta robi. –

1

Oto zwięzły sposób, aby pobrać plik za pomocą „Pliki” zezwolenie w Chrome manifestować używając @Xan i @ rozwiązania AmanicA za

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" 
});