Upyou.it The Blog Tech News Blog

8set/09Off

Scaricare il contenuto di una cartella SkyDrive con Firefox e MozRepl

Come prosecuzione naturale di questo post voglio mostrarvi con un piccolo esempio come sia possibile creare degli script per istruire Firefox e fargli fare quello che vogliamo, senza necessariamente arrivare a scrivere un'estensione apposita. E allora, con la testa ancora piena di acronimi come XPCOM, XPConnect, XUL e chi più ne ha più ne metta, alcuni dei quali ancora poco chiari, mi sono posto l'obbiettivo di realizzare un modesto script per scaricare attraverso il browser i file presenti in un disco "sulle nuvole" SkyDrive, in modo del tutto automatico.

skydrive

SkyDrive può essere molto utile per riporre file che volete condividere con i vostri amici o anche soltanto se volete avere a portata di mano certi file anche quando siete distanti dal vostro PC. Sfortunatamente non è possibile, a parte per le foto, scaricare in modo automatico tutti i file presenti in una cartella. Lo script che ho programmato è in grado di fare questo, in maniera ricorsiva, andando cioè a esplorare le sottocartelle che dovesse trovare nella cartella di partenza. Ovviamente, come potete vedere voi stessi guardando il codice, non voglio dire che ci troviamo allo stesso livello di semplicità d'uso di iMacros, ma in questo caso le possibilità sono praticamente infinite e i limite veramente pochi. Abbiamo infatti a disposizione la stessa potenza disponibile alle estensioni del browser e possiamo perciò sbizzarrirci.

Ecco di seguito il codice. Non è ciò che si può considerare codice pulito ma anzi è uno spezzatino che ho messo assieme dopo qualche ora di ricerca frenetica in internet ( la documentazione su XPCOM e XPConnect è, ahime, un po' scarna ) e un po' di collage stile Javascript. Un breve commento: la variabile __destDir in testa al codice rappresenta la cartella di destinazione dei file scaricati e potete modificarla a vostro piacimento.

var __destDir = "c:\\temp\\";
function getSkyDriveDir(dirUrl){
 skyDriveDownload(dirUrl, '');
}

function skyDriveDownload(url, subpath){
 var req = new XMLHttpRequest();
 req.open('GET',url,false);
 req.overrideMimeType('text/xml');
 req.send(null);

 if(req.status != 200){
 repl.print('Error: status code ' + req.status);
 return;
 }

 var resText = req.responseText;
 // questo serve per trasformare quello che riceviamo in un documento "attraversabile" con i metodi DOM
 var div = content.document.createElement('DIV');
 div.innerHTML = resText;

 var dirContent = getElementsByClass('tvLink',div,'A');
 for(var i=0;i<dirContent.length;i++){
 var contentUrl = dirContent[i].href;
 var itemName = dirContent[i].title;
 var isDirectory = itemName.indexOf('.') == -1;

 if(isDirectory){
 // leggo ricorsivamente il contenuto della cartella
 repl.print("Reading content of directory " + itemName);
 subpath += '\\' + itemName;
 skyDriveDownload(contentUrl, subpath);
 subpath = subpath.substring(0,subpath.lastIndexOf('\\')-1);
 repl.print("Exiting directory " + itemName);
 } else {
 req.open('GET',contentUrl,false);
 req.overrideMimeType('text/xml');
 req.send(null);

 if(req.status != 200){
 repl.print('Error: status code ' + req.status);
 return;
 }

 var text = req.responseText;
 var pos1 = text.indexOf("var _download = ") + 17;

 var pos2 = text.indexOf("'",pos1);
 var finalUrl = text.substring(pos1, pos2);
 // unescape della stringa
 eval("finalUrl = '"+finalUrl+"';");
 pos1 = finalUrl.lastIndexOf('?');
 if(pos1 >= 0){
 finalUrl = finalUrl.substring(0,pos1);
 }

 downloadFile(finalUrl, subpath);
 }
 }
}

var skyDriveProgressListener =
 {
 QueryInterface: function(aIID)
 {
 if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
 aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
 aIID.equals(Components.interfaces.nsISupports))
 return this;
 throw Components.results.NS_NOINTERFACE;
 },

 onStateChange: function(aWebProgress, aRequest, aFlag, aStatus)
 {
 fileName = unescape(aRequest.name.substring(aRequest.name.lastIndexOf('/')+1));
 if(aFlag & Components.interfaces.nsIWebProgressListener.STATE_START)
 {
 repl.print('Download started: ' + fileName);
 }
 else if(aFlag & Components.interfaces.nsIWebProgressListener.STATE_STOP)
 {
 repl.print('Download finished: ' + fileName);
 }
 },

 onLocationChange: function(aProgress, aRequest, aURI){},

 // For definitions of the remaining functions see XULPlanet.com
 onProgressChange: function(a, b, c, d, e, f) { },
 onStatusChange: function(a, b, c, d) { },
 onSecurityChange: function(a, b, c) { }
 }

function downloadFile(httpLoc, subpath) {
 try {
 //new obj_URI object
 var obj_URI = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(httpLoc, null, null);

 //new file object
 var obj_TargetFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);

 //set file with path

 var str_FileName = unescape(httpLoc.substring(httpLoc.lastIndexOf('/') + 1));
 var str_Path = __destDir + subpath + '\\' + str_FileName;

 obj_TargetFile.initWithPath(str_Path);
 //if file doesn't exist, create
 if(!obj_TargetFile.exists()) {
 obj_TargetFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,0644);
 }

 //new persitence object
 var obj_Persist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);

 // with persist flags if desired
 const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
 const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
 obj_Persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;

 obj_Persist.progressListener = skyDriveProgressListener;

 //save file to target
 obj_Persist.saveURI(obj_URI,null,null,null,null,obj_TargetFile);
 } catch (e) {
 repl.print(e);
 }
}

function getElementsByClass(searchClass,node,tag) {
 var classElements = new Array();
 if ( node == null )
 node = document;
 if ( tag == null )
 tag = '*';
 var els = node.getElementsByTagName(tag);
 var elsLen = els.length;
 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
 for (i = 0, j = 0; i < elsLen; i++) {
 if ( pattern.test(els[i].className) ) {
 classElements[j] = els[i];
 j++;
 }
 }
 return classElements;
}

Qualcuno potrebbe dire che si tratta di una soluzione un po' overkill e avrebbe sicuramente ragione :-) Il codice è quasi eccessivamente strutturato per essere un semplice hack con poche pretese. Ma è un po' il mio stile di fare le cose, quando mi metto cerco di fare le cose con cura e di trarne qualche insegnamento; in questo caso XPCOM e XPConnect erano mondi a me estranei ( e nemmeno con Javascript sono un mago ) e quindi ho cercato di, come si dice in questi casi, unire l'utile al dilettevole.

Per usare questo script in MozRepl salvatelo da qualche parte nel vostro disco fisso e dal prompt di MozRepl date il comando

repl.load('file:///c:/percorso/del/file.js');

utilizzando il percorso e il nome che gli avete assegnato. Fatto questo date il comando

getSkyDriveDir('url_della_cartella_skydrive_che_volete_scaricare');

ricordando di mettere le virgolette e di effettuare il login al servizio prima. Una volta dato il comando il software inizierà a scaricare i file che troverà nella cartella indicata esplorando le sottocartelle. Un problema di questo script è che non vi avviserà quando avrà completato tutti i download ma soltanto di volta in volta che un file sarà stato scaricato, ma ehi, non si può avere sempre tutto :-D

Spero che possa tornare utile a qualcuno ;-)

Be Sociable, Share!
Commenti (4) Trackback (0)
  1. Innanzotutto grazie per aver condiviso questa trovata geniale!! Purtroppo per me è un pò che ci sto provando, ma dopo aver risolto gli inevitabili problemi con il telnet ( purtroppo sono windows…grrrrrrr) e scaricato Putty per avere un telnet compatibile con mozrepl non riesco ad avere alcuna risposta “vitale” da mozrepl.
    dopo averlo avviato con il comando telnet localhost 4242 e aver avuto la risposta repl> qualsiasi comando, compreso il repl.whereAmI(), non restiuisce nulla.
    Potresti darmi qualche aiuto?! Grazie mille e ancora complimenti!!!!

  2. Una domanda: se volessi scrivere un programma in Java o in C++ in grado di effettuare la stessa operazione, cosa dovrei fare?

  3. @Neo: hai attivato l’opzione Implicit CR in every LF in Putty?

    @vincenzo: è una domanda un po’ complessa per risponderti in un commento. Ipotizzando che tu conosca ad esempio Java dovresti leggerti la documentazione di qualche classe Java contenuta nel SDK che sia in grado di recuperare contenuti attraverso HTTP. Ovviamente potresti anche usare direttamente i socket ma sarebbe più complicato. Una volta recuperato il contenuto delle pagine come viene fatto dallo script dovresti fare un “parsing” e trovare il testo che corrisponde ai link ai vari file o alle cartelle. Nel mio script la cosa è semplificata dal fatto di usare il DOM di Javascript che mi permette di navigare tra gli elementi della pagina senza ricorrere a espressioni regolari o ricerche di sottostringhe. E’ comunque possibile che esista qualche classe Java che implementa DOM, in tal caso faresti bene ad usarla.

  4. Grazie Stefano!
    Si, io conosco il Java ma non Ajax/Javascript… Anche in Java esiste un parser DOM, quindi dovrei riuscire a navigare tra i vari elementi così come tu hai fatto con Javascript!
    Quindi in teoria dovrebbe essere possibile interagire completamente con SkyDrive gestendo cartelle, upload/download di file, ecc..


I trackback sono disattivati.