So erstellen Sie einen wiederaufladbaren Video-Uploader in Node.js

Wenn Sie schon einmal eine beträchtlich große Videodatei hochgeladen haben, kennen Sie dieses Gefühl: Sie sind zu 90% fertig und aktualisieren die Seite aus Versehen - Sie müssen von vorne beginnen.

In diesem Tutorial zeige ich Ihnen, wie Sie einen Video-Uploader für Ihre Website erstellen, der einen unterbrochenen Upload fortsetzen und nach Abschluss ein Miniaturbild generieren kann.


Intro

Damit dieser Uploader wieder aufgenommen werden kann, muss der Server den Status einer bereits hochgeladenen Datei verfolgen und in der Lage sein, an der Stelle fortzufahren, an der sie aufgehört hat. Um diese Aufgabe auszuführen, geben wir dem Node.js-Server die vollständige Kontrolle, um bestimmte Datenblöcke anzufordern. Das HTML-Formular nimmt diese Anforderungen auf und sendet die erforderlichen Informationen an den Server.

Für diese Kommunikation verwenden wir Socket.io. Wenn Sie noch nie etwas von Socket.io gehört haben, handelt es sich hierbei um ein Framework für die Echtzeitkommunikation zwischen Node.js und einer HTML-Webseite.

Dies ist das Grundkonzept. Wir beginnen mit dem HTML-Formular.


Schritt 1: Das HTML

Ich werde den HTML-Code relativ einfach halten. Wir benötigen lediglich eine Eingabe, um eine Datei auszuwählen, ein Textfeld für den Namen und eine Schaltfläche, um den Upload zu starten. Hier ist der notwendige Code:

  

Video-Uploader



Beachten Sie, dass ich den Inhalt in einem Bereich verpackt habe. Wir werden dies später verwenden, um das Layout der Seite mit JavaScript zu aktualisieren. Ich werde das CSS in diesem Tutorial nicht behandeln, aber Sie können den Quellcode herunterladen, wenn Sie meinen verwenden möchten.


Schritt 2: Damit es funktioniert

HTML5 ist noch relativ neu und wird noch nicht in allen Browsern vollständig unterstützt. Bevor Sie fortfahren, müssen Sie zunächst sicherstellen, dass der Browser des Benutzers die HTML5-Datei-API und die FileReader-Klasse unterstützt.

Mit der FileReader-Klasse können wir Teile einer Datei öffnen und lesen und die Daten als Binärzeichenfolge an den Server übergeben. Hier ist das JavaScript für die Featureerkennung:

 window.addEventListener ("load", Ready); function Ready () if (window.File && window.FileReader) // Dies sind die relevanten HTML5-Objekte, die wir verwenden document.getElementById ('UploadButton'). addEventListener ('click', StartUpload); document.getElementById ('FileBox'). addEventListener ('change', FileChosen);  else document.getElementById ('UploadArea'). innerHTML = "Ihr Browser unterstützt die Datei-API nicht. Aktualisieren Sie Ihren Browser."; 

Der obige Code fügt der Schaltfläche und der Dateieingabe im Formular außerdem Ereignisbehandlungsroutinen hinzu. Das FileChosen function setzt einfach eine globale Variable mit der Datei - damit wir später darauf zugreifen können - und füllt das Namensfeld aus, damit der Benutzer beim Benennen der Datei einen Referenzpunkt hat. Hier ist der FileChosen Funktion:

 var SelectedFile; function FileChosen (evnt) SelectedFile = evnt.target.files [0]; document.getElementById ('NameBox'). value = SelectedFile.name; 

Bevor wir das schreiben Upload starten Funktion, müssen wir den Node.js-Server mit socket.io einrichten; Kümmern wir uns jetzt darum.


Schritt 3: Der Socket.io Server

Wie bereits erwähnt, verwende ich Socket.io für die Kommunikation zwischen dem Server und der HTML-Datei. Um Socket.io herunterzuladen, geben Sie Folgendes ein npm install socket.io in ein Terminalfenster (vorausgesetzt, Sie haben Node.js installiert), nachdem Sie zu diesem Projektverzeichnis navigiert haben. So funktioniert socket.io: Entweder "der Server" oder der Client "emittiert" ein Ereignis, und die andere Seite nimmt dieses Ereignis in Form einer Funktion mit der Option auf, JSON-Daten hin und her zu übergeben. Erstellen Sie zunächst eine leere JavaScript-Datei, und fügen Sie den folgenden Code ein.

 var app = required ('http'). createServer (Handler), io = requir ('socket.io'). listen (app), fs = requir ('fs'), exec = requir ('child_process'). exec , util = required ('util') app.listen (8080); Funktionshandler (req, res) fs.readFile (__ dirname + '/index.html'), function (err, data) if (err) res.writeHead (500); return res.end ('Fehler beim Laden des Indexes. html '); res.writeHead (200); res.end (data););  io.sockets.on ('Verbindung', Funktion (Socket) // Ereignisse gehen hier hin);

Die ersten fünf Zeilen enthalten die erforderlichen Bibliotheken, die nächste Zeile weist den Server an, Port 8080 zu überwachen, und die Handlerfunktion übergibt einfach den Inhalt unserer HTML-Datei an den Benutzer, wenn er auf die Site zugreift.

Die letzten beiden Zeilen sind der socket.io-Handler und werden aufgerufen, wenn sich jemand über Socket.io verbindet.

Nun können wir zur HTML-Datei zurückkehren und einige socket.io -Ereignisse definieren.


Schritt 4: Einige Socket.io-Ereignisse

Um Socket.io auf unserer Seite verwenden zu können, müssen Sie zunächst eine Verknüpfung zu seiner JavaScript-Bibliothek herstellen. Sie tun dies auf dieselbe Weise, wie Sie auf eine Bibliothek verweisen würden: referenzieren Sie sie im Kopfbereich. Fügen Sie der Seite vor Ihren Skripts natürlich Folgendes hinzu.

Machen Sie sich keine Sorgen über das Abrufen dieser Datei, da sie zur Laufzeit vom Node.js-Server generiert wird.

Jetzt können wir das schreiben Upload starten Funktion, die wir mit unserer Taste verbunden haben:

 var socket = io.connect ('http: // localhost: 8080'); var FReader; var Name; function StartUpload () if (document.getElementById ('FileBox'). value! = "") FReader = new FileReader (); Name = document.getElementById ('NameBox'). Wert; var Content = ""+ SelectedFile.name +" als "+ Name +" hochladen"; Inhalt + = '
0%'; Inhalt + = " - 0/ "+ Math.round (SelectedFile.size / 1048576) +" MB"; document.getElementById ('UploadArea'). innerHTML = Inhalt; FReader.onload = Funktion (evnt) socket.emit ('Upload', 'Name': Name, Daten: evnt.target.result); socket.emit ('Start', 'Name': Name, 'Size': SelectedFile.size); else alert ("Bitte wählen Sie eine Datei aus");

Die erste Zeile stellt eine Verbindung zum Socket.io-Server her. Als Nächstes haben wir zwei Variablen für den File Reader und den Namen der Datei erstellt, da wir globalen Zugriff auf diese benötigen. Innerhalb der Funktion haben wir zuerst sichergestellt, dass der Benutzer eine Datei ausgewählt hat, und wenn dies der Fall ist, erstellen wir die Datei FileReader, und aktualisieren Sie das DOM mit einem schönen Fortschrittsbalken.

Der FileReader onload Die Methode wird jedes Mal aufgerufen, wenn Daten gelesen werden. wir müssen nur ein emittieren Hochladen Ereignis und senden Sie die Daten an den Server. Zum Schluss geben wir eine Start Geben Sie den Namen und die Größe der Datei an den Node.js-Server weiter.

Kehren wir nun zur Datei Node.js zurück und implementieren Handler für diese beiden Ereignisse.


Schritt 5: Umgang mit den Ereignissen

Sie müssen den Puffer regelmäßig löschen, oder der Server stürzt aufgrund von Speicherüberlastung ab.

Die socket.io -Ereignisse befinden sich innerhalb des Handlers, den wir in der letzten Zeile unserer Node.js-Datei haben. Das erste Ereignis, das wir implementieren, ist das Start Ereignis, das ausgelöst wird, wenn der Benutzer auf die Schaltfläche klickt Hochladen Taste.

Ich habe bereits erwähnt, dass der Server die Kontrolle darüber haben soll, welche Daten er als nächstes erhalten möchte. Dadurch wird es möglich, mit einem vorherigen unvollständigen Upload fortzufahren. Dazu wird zunächst ermittelt, ob es eine Datei mit diesem Namen gab, die den Upload nicht abgeschlossen hat. Wenn ja, wird sie an der Stelle fortgesetzt, an der sie aufgehört hat. Andernfalls beginnt es am Anfang. Wir werden diese Daten in Schritten von einem halben Megabyte übergeben, was 524288 Bytes ergibt.

Um die verschiedenen Uploads gleichzeitig verfolgen zu können, müssen Sie eine Variable hinzufügen, um alles zu speichern. Fügen Sie oben in Ihre Datei ein var Files = ; ' Hier ist der Code für die Start Veranstaltung:

 socket.on ('Start', function (data) // data enthält die Variablen, die wir in der html-Datei durchlaufen haben. var Name = data ['Name']; Files [Name] = // Neuen Eintrag erstellen in Die Dateivariable FileSize: data ['Size'], Data: "", Downloaded: 0 var Place = 0; versuchen Sie var Stat = fs.statSync ('Temp /' + Name); if (Stat.isFile () ) Files [Name] ['Downloaded'] = Stat.size; Place = Stat.size / 524288; catch (er)  // Es ist eine neue Datei fs.open ("Temp /" + Name "") a ", 0755, Funktion (err, fd) if (err) console.log (err); else Files [Name] ['Handler'] = fd; // Wir speichern den File-Handler, damit wir schreiben können dazu später socket.emit ('MoreData', 'Place': Place, Percent: 0);););

Zuerst fügen wir die neue Datei dem hinzu Dateien Array, mit der Größe, den Daten und der Anzahl der bis jetzt heruntergeladenen Bytes. Das Platz Variable speichert, wo in der Datei wir gerade sind - es ist standardmäßig 0, was der Anfang ist. Wir prüfen dann, ob die Datei bereits vorhanden ist (d. H. Sie war in der Mitte und angehalten), und aktualisieren die Variablen entsprechend. Unabhängig davon, ob es sich um einen neuen Upload handelt oder nicht, wir öffnen jetzt die Datei zum Schreiben in die Temp / Ordner und geben Sie die MehrDaten event, um den nächsten Datenabschnitt aus der HTML-Datei anzufordern.

Jetzt müssen wir das hinzufügen Hochladen event, das, wenn Sie sich erinnern, jedes Mal aufgerufen wird, wenn ein neuer Datenblock gelesen wird. Hier ist die Funktion:

 socket.on ('Upload', Funktion (Daten) var Name = Daten ['Name']; Dateien [Name] ['Heruntergeladen'] + = Daten ['Daten']. Länge; Dateien [Name] ['Daten '] + = data [' Data ']; if (Dateien [Name] [' Heruntergeladen '] == Dateien [Name] [' FileSize ']) // Wenn die Datei vollständig hochgeladen ist fs.write (Dateien [Name] ['Handler'], Files [Name] ['Data'], null, 'Binary', Funktion (err, Writen) // Get Thumbnail Here); else if (Files [Name] ['Data']) .length> 10485760) // Wenn der Datenpuffer 10 MB erreicht. fs.write (Dateien [Name] ['Handler']), Dateien [Name] ['Daten'], Null, 'Binär', Funktion (err, Writen) Files [Name] ['Data'] = ""; // Zurücksetzen des Puffers var Place = Files [Name] ['Downloaded'] / 524288; var Percent = (Files [Name] ['Downloaded'] / Files [ Name] ['FileSize']) * 100; socket.emit ('MoreData', 'Place': Place, 'Percent': Percent);); else var Place = Dateien [Name] ['Heruntergeladen '] / 524288; var Percent = (Dateien [Name] [' Heruntergeladene '] / Dateien [Name] [' FileSize ']) * 100; socket.emit (' MoreData ', ' Place ': Place,' Percent ' : Prozent););

Die ersten beiden Zeilen dieses Codes aktualisieren den Puffer mit den neuen Daten und aktualisieren die Gesamtanzahl der heruntergeladenen Bytes. Wir müssen die Daten in einem Puffer speichern und in Inkrementen speichern, damit der Server nicht aufgrund von Speicherüberlastung abstürzt. Alle zehn Megabytes speichern und löschen Sie den Puffer.

Der Erste ob Die Anweisung ermittelt, ob die Datei vollständig hochgeladen wurde, die zweite prüft, ob der Puffer 10 MB erreicht hat, und schließlich werden wir gefragt MehrDaten, Übergeben des fertiggestellten Prozentsatzes und des nächsten zu ladenden Datenblocks.

Nun können wir zur HTML-Datei zurückkehren und die MehrDaten Ereignis und aktualisieren Sie den Fortschritt.


Schritt 6: Den Fortschritt verfolgen

Ich habe eine Funktion zum Aktualisieren der Fortschrittsleiste und der auf der Seite hochgeladenen MB-Menge erstellt. Darüber hinaus die Mehr Daten event liest den Datenblock, den der Server angefordert hat, und leitet ihn an den Server weiter.

Um die Datei in Blöcke aufzuteilen, verwenden wir die File-APIs Scheibe Befehl. Da sich die Datei-API noch in der Entwicklung befindet, müssen wir sie verwenden webkitSlice und mozSlice für Webkit- und Mozilla-Browser.

 socket.on ('MoreData', Funktion (Daten) UpdateBar (Daten ['Prozent'])); var Ort = Daten ['Ort'] * 524288; // Startposition der nächsten Blöcke var NewFile; // Die Variable das wird den neuen Datenblock enthalten, wenn (SelectedFile.webkitSlice) NewFile = SelectedFile.webkitSlice (Place, Place + Math.min (524288, (SelectedFile.size-Place))); else NewFile = SelectedFile.mozSlice (Place, Place +) Math.min (524288, (SelectedFile.size-Place))); FReader.readAsBinaryString (NewFile);); Funktion UpdateBar (Prozent) document.getElementById ('ProgressBar'). style.width = Prozent + '%'; document.getElementById ('percent'). innerHTML = (Math.round (prozent * 100) / 100) + '%'; var MBDone = Math.round (((Prozent / 100.0) * SelectedFile.size) / 1048576); document.getElementById ('MB'). innerHTML = MBDone; 

Mit dieser abschließenden Funktion ist der Uploader abgeschlossen! Wir müssen nur noch die fertige Datei aus dem Ordner verschieben Temp / Ordner und erzeugen Sie die Miniaturansicht.


Schritt 7: Die Miniaturansicht

Bevor wir die Miniaturansicht erstellen, müssen wir die Datei aus dem temporären Ordner verschieben. Wir können dies tun, indem wir Dateistreams und die Pumpe Methode. Das Pumpe Die Methode nimmt einen Lese- und Schreibstrom auf und puffert die Daten zwischen. Sie sollten diesen Code an der Stelle einfügen, an der ich "Generate Thumbnail hier" geschrieben habe Hochladen Veranstaltung:

 var inp = fs.createReadStream ("Temp /" + Name); var out = fs.createWriteStream ("Video /" + Name); util.pump (inp, out, function () fs.unlink ("Temp /" + Name, function () // Dies löscht die temporäre Datei // Moving File Completed););

Wir haben den Unlink-Befehl hinzugefügt. Dadurch wird die temporäre Datei gelöscht, nachdem wir sie kopiert haben. Nun zur Miniaturansicht: Wir verwenden ffmpeg, um die Miniaturansichten zu erstellen, da sie mehrere Formate verarbeiten kann und ein Kinderspiel ist. Zum Zeitpunkt des Schreibens gibt es noch keine guten ffmpeg-Module, also verwenden wir die exec Befehl, der es uns ermöglicht, Terminalbefehle in Node.js auszuführen.

 exec ("ffmpeg -i Video /" + Name + "-ss 01:30 -r 1 -an -vframes 1 -f mjpeg Video /" + Name + ".jpg"), Funktion (err) socket.emit (' Fertig ', ' Image ':' Video / '+ Name +' .jpg '););

Dieser ffmpeg-Befehl erzeugt ein Miniaturbild bei der 1:30-Marke und speichert es in der Video/ Ordner mit einem .jpg Dateityp. Sie können die Zeit der Miniaturansicht ändern, indem Sie die -ss Parameter. Sobald das Thumbnail erstellt wurde, geben wir das aus Erledigt Veranstaltung. Gehen wir nun zurück zur HTML-Seite und implementieren sie.


Schritt 8: Fertigstellen

Das Erledigt Event entfernt die Fortschrittsleiste und ersetzt sie durch das Miniaturbild. Da Node.js nicht als Webserver eingerichtet ist, müssen Sie den Speicherort Ihres Servers (z. B. Apache) im Verzeichnis angeben Pfad Variable, um das Bild zu laden.

 var Path = "http: // localhost /"; socket.on ('Fertig', Funktion (Daten) var Content = "Video erfolgreich hochgeladen !!" Content + = "
"; Inhalt + ="