[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');
}

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

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

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>

[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');
    });
});

[Server] fileDownloader.ts

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

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.

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>

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

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

19