Cum se creează un uploader video reînnoibil în Node.js

Dacă ați încărcat vreodată un fișier video considerabil mare, atunci știți acest sentiment: sunteți 90% făcut și reîncărcați accidental pagina - trebuie să începeți din nou.

În acest tutorial, voi demonstra cum să faceți o încărcare video pentru site-ul dvs. care să reia o încărcare întreruptă și să generați o miniatură la finalizarea.


introducere

Pentru ca acest uploader să poată fi resuscitat, serverul trebuie să urmărească cât de mult a fost încărcat un fișier și să poată continua de unde a rămas. Pentru a îndeplini această sarcină, vom oferi un control complet serverului Node.js pentru a solicita blocuri de date specifice, iar formularul HTML va prelua aceste cereri și va trimite informațiile necesare serverului.

Pentru a face față acestei comunicări, vom folosi Socket.io. Dacă nu ați auzit niciodată de Socket.io, acesta este un cadru pentru comunicarea în timp real între Node.js și o pagină web HTML - să vă grăbiți mai mult în acest scurt.

Acesta este conceptul de bază; vom începe cu formularul HTML.


Pasul 1: HTML-ul

Voi păstra HTML destul de simplu; tot ce avem nevoie este o intrare pentru a alege un fișier, o casetă de text pentru nume și un buton pentru a începe încărcarea. Iată codul necesar:

  

Încărcător video



Observați că am împachetat conținutul într-o perioadă; vom folosi acest lucru mai târziu pentru a actualiza aspectul paginii cu JavaScript. Nu voi acoperi CSS în acest tutorial, dar puteți descărca codul sursă, dacă doriți să folosiți a mea.


Pasul 2: Îmbunătățirea funcționării

HTML5 este încă relativ nou și încă nu este complet acceptat în toate browserele. Primul lucru pe care trebuie să-l facem, înainte de a merge mai departe, este să vă asigurați că browserul utilizatorului acceptă clasa API HTML5 și clasa FileReader.

Clasa FileReader ne permite să deschidem și să citim părți ale unui fișier și să transmitem datele ca un șir binar la server. Aici este JavaScript pentru detectarea caracteristicilor:

 window.addEventListener ("încărcare", gata); funcția Ready () if (window.File && window.FileReader) // Acestea sunt obiectele HTML5 relevante pe care le vom folosi document.getElementById ('UploadButton'). addEventListener ('click', StartUpload); document.getElementById ('FileBox'). addEventListener ('schimbare', FileChosen);  else document.getElementById ('UploadArea') innerHTML = "Browserul dvs. nu suportă fișierul API Actualizați-vă browserul"; 

De asemenea, codul de mai sus adaugă gestionarea evenimentelor la butonul și introducerea fișierului în formular. FileChosen funcția stabilește pur și simplu o variabilă globală cu fișierul - astfel încât să putem accesa ulterior - și umple câmpul de nume, astfel încât utilizatorul să aibă un punct de referință atunci când numește fișierul. Aici este FileChosen funcţie:

 var SelectedFile; funcția FileChosen (evnt) SelectedFile = evnt.target.files [0]; document.getElementById ('NumeBox'). valoare = SelectedFile.name; 

Înainte de a scrie StartUpload funcția, trebuie să configuram serverul Node.js cu socket.io; hai să avem grijă de asta acum.


Pasul 3: Serverul Socket.io

După cum am menționat mai devreme, voi folosi Socket.io pentru comunicarea dintre server și fișierul HTML. Pentru a descărca Socket.io, tastați npm instalare socket.io într-o fereastră Terminal (presupunând că ați instalat Node.js), după ce ați navigat la acest director de proiecte. Modul în care funcționează socket.io este: fie serverul, fie clientul "emite" un eveniment, iar cealaltă parte va prelua acest eveniment sub forma unei funcții cu opțiunea de a transmite date JSON înainte și înapoi. Pentru a începe, creați un fișier JavaScript gol și plasați în el codul următor.

 var app = solicita ('http') createServer (handler), io = necesita ('socket.io'). , util = necesită ('util') app.listen (8080); funcția (err, data) if (err) res.writeHead (500); retur res.end ("Eroare la încărcarea indexului. html '); res.writeHead (200); res.end (date););  io.sockets.on ("conexiune", funcție (socket) // Evenimentele vor merge aici);

Primele cinci linii includ bibliotecile necesare, următorul rând instruiește serverul să asculte pe portul 8080, iar funcția handler trece pur și simplu conținutul fișierului nostru HTML către utilizator, atunci când accesează site-ul.

Ultimele două linii sunt handlerul socket.io și vor fi apelate când cineva se conectează, prin Socket.io.

Acum, ne putem întoarce la fișierul HTML și putem defini câteva evenimente socket.io.


Pasul 4: Unele evenimente Socket.io

Pentru a începe să utilizați Socket.io în pagina noastră, trebuie să vă conectați mai întâi la biblioteca JavaScript. Faceți acest lucru în același mod în care vă referiți la orice bibliotecă: trimiteți-o în zona capului. Adăugați următoarele la pagină, înainte de scenariile dvs., evident.

Nu vă faceți griji cu privire la obținerea acestui fișier, deoarece acesta este generat la runtime de către serverul Node.js.

Acum, putem scrie StartUpload funcția pe care am conectat-o ​​la butonul nostru:

 var socket = io.connect ("http: // localhost: 8080"); var FReader; Numele var; funcția StartUpload () if (document.getElementById ('FileBox') valoare! = "") FReader = fișierul de fișiere nou (); Nume = document.getElementById ('NumeBox'). Valoare; var Conținut = "Încărcarea "+ SelectedFile.name +" ca "+ Nume +""; Conținut + = '
0%„; Conținut + = " - 0/ "+ Math.round (SelectedFile.size / 1048576) +" MB"document.getElementById ('UploadArea') innerHTML = Conținut; FReader.onload = funcția (evnt) socket.emit ('Încărcare', Nume: Nume, Date: evnt.target.result); socket.emit ('Start', 'Nume': Nume, 'Dimensiune': SelectedFile.size); alt alert ("Selectați un fișier");

Prima linie se conectează la serverul Socket.io; în continuare, am creat două variabile pentru fișierul Reader și numele fișierului, deoarece vom avea nevoie de acces global la acestea. În interiorul funcției, am asigurat mai întâi că utilizatorul a selectat un fișier și, dacă au făcut-o, am creat FileReader, și actualizați DOM cu o bara de progres frumos.

Aplicația FileReader onload metoda se numește de fiecare dată când citește unele date; tot ce trebuie să facem este să emităm Încărcați eveniment și trimiteți datele către server. În cele din urmă, emitem a start eveniment, trecând numele și dimensiunea fișierului la serverul Node.js.

Acum, să revenim la fișierul Node.js și să implementăm gestionarea acestor două evenimente.


Pasul 5: Manipularea evenimentelor

Trebuie să ștergeți tamponul de fiecare dată atât de des sau serverul se va prăbuși, din cauza supraîncărcării memoriei.

Evenimentele socket.io intră în interiorul handler-ului pe care îl avem pe ultima linie a fișierului nostru Node.js. Primul eveniment pe care îl vom implementa este start eveniment, care este declanșat atunci când utilizatorul face clic pe Încărcați buton.

Am menționat anterior că serverul ar trebui să aibă controlul asupra datelor pe care dorește să le primească în continuare; acest lucru îi va permite să continue de la o încărcare anterioară care a fost incompletă. Ea face acest lucru prin determinarea mai întâi dacă există un fișier de acest nume care nu a terminat încărcarea și, dacă da, va continua de unde a rămas; în caz contrar, va începe de la început. Vom transmite aceste date în incremente de jumătate de megabyte, care vor ajunge la 524288 octeți.

Pentru a urmări încărcarea diferită în același timp, trebuie să adăugăm o variabilă pentru a stoca totul. În partea de sus a fișierului, adăugați var Files = ; Iată codul pentru start eveniment:

 socket.on ('Start', funcția (date) // datele conțin variabilele pe care le-am trecut în fișierul html var Name = data ['Name']; Fișierul Variable FileSize: data ['Size'], Data: "", Descărcat: 0 var Place = 0; ) Fisiere [Nume] ['Descarcat'] = Stat.size; Loc = Stat.size / 524288; captura (er)  a, 0755, funcția (err, fd) if (err) console.log (err); altceva Files [Name] ['Handler'] = fd; la acesta mai târziu socket.emit ('MoreData', 'Place': Loc, Procent: 0);););

Mai întâi, adăugăm noul fișier la Fișiere array, cu dimensiunea, datele și cantitatea de octeți descărcate până acum. Loc unde variază în fișierul în care ne aflăm - este implicit 0, care este începutul. Apoi, verificăm dacă fișierul există deja (adică a fost în mijloc și oprit) și actualizați variabilele în consecință. Fie că este o încărcare nouă sau nu, acum deschidem fișierul pentru a scrie la Temp / folder, și emite MoreData eveniment pentru a solicita următoarea secțiune de date din fișierul HTML.

Acum, trebuie să adăugăm Încărcați eveniment, care, dacă vă amintiți, se numește de fiecare dată când se citește un nou bloc de date. Iată funcția:

 socket.on ("Încărcare", funcție (date) var Nume = date ['Nume']; '] = data ' Data ']; if (Files [Name] [' Downloaded '] == Fișiere [Name] [FileSize' ['Handler'], Fișiere [Name] ['Data'], null, 'Binary', funcția (err, Writen) // Get Thumbnail Here .bg> 10485760) // Dacă Bufferul de Date ajunge la 10MB fs.write (Files [Name] ['Handler'], funcțiile (err, Writen) Fișiere [nume] ['date'] = ""; // Resetați Bufferul var Place = fișiere [nume] ['descărcat'] / 524288; var Percent = Nume] ['FileSize']) * 100; socket.emit ('MoreData', 'Place': Place, 'Percent': Percent); '] / / 524288; var Percent = (Fișiere [Nume] [' Descărcate '] / Fișiere [Name] [' FileSize ']) * 100; socket.emit (' : Procent););

Primele două linii ale acestui cod actualizează tamponul cu datele noi și actualizează variabila descărcată totală de octeți. Trebuie să stocăm datele într-un buffer și să le salvăm în incremente, astfel încât să nu se prăbușească serverul datorită supraîncărcării memoriei; fiecare zece megaocteți, vom salva și elimina tamponul.

Primul dacă instrucțiunea determină dacă fișierul este complet încărcat, cel de-al doilea verifică dacă tamponul a ajuns la 10 MB și, în final, solicităm MoreData, trecând procentul făcut și următorul bloc de date pentru preluare.

Acum, putem reveni la fișierul HTML și putem implementa MoreData și actualizați progresul.


Pasul 6: Urmărirea progresului

Am creat o funcție pentru a actualiza bara de progres și cantitatea de MB încărcată pe pagină. Pe lângă aceasta, Mai multe date evenimentul citește blocul de date solicitat de server și îl transmite pe server.

Pentru a împărți fișierul în blocuri, folosim fișierele API pentru fișiere Felie comanda. Întrucât fișierul API este în curs de dezvoltare, trebuie să îl folosim webkitSlice și mozSlice pentru browserele Webkit și Mozilla, respectiv.

 socket.on ('MoreData', functie (data) UpdateBar (data ['Percent']) var Place = date [Place] * 524288; va păstra noul bloc de date dacă (SelectedFile.webkitSlice) NewFile = SelectedFile.webkitSlice (Place, Place + Math.min (524288, (SelectedFile.size-Place))) altfel NewFile = SelectedFile.mozSlice (Place, Math.min (524288, (SelectedFile.size-Place))); FReader.readAsBinaryString (NewFile);); funcția UpdateBar (procente) document.getElementById ('ProgressBar') style.width =% + '%'; document.getElementById ('procente') innerHTML = (Math.round (% * 100) / 100) + '%'; var MBDone = Math.round (((procente / 100.0) * SelectedFile.size) / 1048576); document.getElementById ('MB') interiorHTML = MBDone; 

Cu această funcție finală, încărcătorul este finalizat! Tot ce trebuie să facem este să mutați fișierul complet din Temp / folder și generați miniaturile.


Pasul 7: Miniatură

Înainte de a genera miniatura, trebuie să mutăm fișierul din dosarul temporar. Putem face acest lucru prin utilizarea fluxurilor de fișiere și a pompa metodă. pompa metoda ia într-un flux de citire și scriere și tamponază datele între ele. Ar trebui să adăugați acest cod acolo unde am scris "Generați miniatură aici" în Încărcați eveniment:

 var inp = fs.createReadStream ("Temp /" + Nume); var out = fs.createWriteStream ("Video /" + Nume); util.pump (inp, out, function () fs.unlink ("Temp /" + Nume, functie () // Aceasta sterge fisierul temporar // Mutarea fișierului finalizat);

Am adăugat comanda de deconectare; acest lucru va șterge fișierul temporar, după ce terminăm copierea acestuia. Acum, pe thumbnail: vom folosi ffmpeg pentru a genera miniaturile, deoarece se poate ocupa de mai multe formate, și este un cinch pentru a instala. La momentul acestei scrieri, nu există module ffmpeg bune, așa că vom folosi Exec care ne permite să executăm comenzi Terminal din cadrul Node.js.

 exec ("ffmpeg -i Video /" + Nume + "-ss 01:30 -r 1 -in -vframe 1 -f mjpeg Video /" + Nume + ".jpg", functie (err) socket.emit (' Efectuat ', ' Imagine ':' Video / '+ Nume +' .jpg '););

Această comandă ffmpeg va genera o miniatură la marcajul 1:30 și va salva pe Video/ dosar cu .jpg tip fișier. Puteți modifica ora miniaturii modificând -ss parametru. Odată ce miniatura a fost generată, emitem Terminat eveniment. Acum, să revenim la pagina HTML și să o implementăm.


Pasul 8: Finalizarea

Terminat evenimentul va elimina bara de progres și îl va înlocui cu imaginea miniaturală. Deoarece Node.js nu este setat ca server web, trebuie să plasați locația serverului (de ex. Apache) în cale pentru a încărca imaginea.

 cale var = "http: // localhost /"; socket.on ('Done', funcția (data) var Content = "Video încărcat cu succes!" Conținut + = "
"Conținut + ="