DEV Community

Masui Masanori
Masui Masanori

Posted on

[Express][TypeScript] Downloading files

Intro

This time, I will try downloading files.

Download files by Stream

I can download files by fs like below.

fileDonwloader.ts

import fs from 'fs';

export function loadFile(): fs.ReadStream {
    return fs.createReadStream('tmp/region.png');
}
Enter fullscreen mode Exit fullscreen mode

index.ts

import express from 'express';
...
import * as downloader from './files/fileDownloader';

const port = 3000;
const app = express();
...
app.get('/files/download', (req, res) => {
    const stream = downloader.loadFile();
    // download file as "hello.png"
    res.writeHead(200, {
        "Content-Type": "image/png",
        "Content-Disposition": "attachment; filename=hello.png",
    });
    stream.on('open', () => {
        console.log('Opened');
        stream.pipe(res);
    });
    stream.on('close', () => {
        console.log('Closed');
    });
});
app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
});
Enter fullscreen mode Exit fullscreen mode

It's very simple.
After opening the stream, downloading the file is started.
After finishing the downloading, the stream is closed.

Alt Text

Play videos

How about playing videos?

First, I try setting the url as "src" of a video element.

[Client] index.html

<!DOCTYPE html>
<html lang='en'>
    <head>
        <title>Hello</title>
        <meta charset="utf8">
    </head>
    <body>
...
        <video muted controls autoplay src="/files/video"></video>
        <script src="./js/main.page.js"></script>
        <script>Page.init()</script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

[Server] index.ts

app.get('/files/video', (req, res) => {
    const stream = downloader.loadVideo();
    stream.on('open', () => {
        console.log('Opened');

        stream.pipe(res);
    });
    stream.on('close', () => {
        console.log('Closed');
    });
});
Enter fullscreen mode Exit fullscreen mode

[Server] fileDownloader.ts

import fs from 'fs';
...
export function loadVideo(): fs.ReadStream {
    return fs.createReadStream('tmp/sample.mp4');
}
Enter fullscreen mode Exit fullscreen mode

I can play the video.
But I have a problem.

After loading the page, before starting the video, I must wait for downloading data first.
After donwloading, the video start playing.
But the data isn't the first one.

Alt Text

I think it's for getting the video information to prepare playing.
Can I avoid the first downloading or finish more quickly?

Download videos by TypeScript

How about donwload the video and set it into the video element by TypeScript?

[Client] index.html

...
        <video id="video_sample"></video>
        <script src="./js/main.page.js"></script>
        <script>Page.init()</script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

[Client] main.page.ts

...
export function init() {
    const targetVideo = document.getElementById('video_sample') as HTMLVideoElement;
    targetVideo.muted = true;
    targetVideo.controls = true;
    targetVideo.autoplay = true;

    fetch('files/video', {
        method: 'GET',
        mode: 'cors'
    })
    .then(res => res.blob())
    .then(data => {
        targetVideo.src = URL.createObjectURL(data);
    })
    .catch(err => console.error(err));
}
Enter fullscreen mode Exit fullscreen mode

Most of the result was same as first example.
Because it also waits for downloading all of the video data first.

The difference is caching the video data, so though I replay the video after finishing the first playing, it won't download the data again.

Can I set Stream API as the source of the video element?
I couldn't find how to do that :(

If I can generate "MediaStream" or "MediaSource" from ReadableStream, I can set as "srcObject" of the video element...

Shall I use WebSocket or WebRTC?

Resources

Top comments (0)