Skip to content

Instantly share code, notes, and snippets.

@DingGGu
Last active March 26, 2024 06:13
Show Gist options
  • Star 39 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save DingGGu/8144a2b96075deaf1bac to your computer and use it in GitHub Desktop.
Save DingGGu/8144a2b96075deaf1bac to your computer and use it in GitHub Desktop.
NodeJS Mp3 Streaming ExpressJS
var express = require('express');
var app = express();
var fs = require('fs');
app.listen(3000, function() {
console.log("[NodeJS] Application Listening on Port 3000");
});
app.get('/api/play/:key', function(req, res) {
var key = req.params.key;
var music = 'music/' + key + '.mp3';
var stat = fs.statSync(music);
range = req.headers.range;
var readStream;
if (range !== undefined) {
var parts = range.replace(/bytes=/, "").split("-");
var partial_start = parts[0];
var partial_end = parts[1];
if ((isNaN(partial_start) && partial_start.length > 1) || (isNaN(partial_end) && partial_end.length > 1)) {
return res.sendStatus(500); //ERR_INCOMPLETE_CHUNKED_ENCODING
}
var start = parseInt(partial_start, 10);
var end = partial_end ? parseInt(partial_end, 10) : stat.size - 1;
var content_length = (end - start) + 1;
res.status(206).header({
'Content-Type': 'audio/mpeg',
'Content-Length': content_length,
'Content-Range': "bytes " + start + "-" + end + "/" + stat.size
});
readStream = fs.createReadStream(music, {start: start, end: end});
} else {
res.header({
'Content-Type': 'audio/mpeg',
'Content-Length': stat.size
});
readStream = fs.createReadStream(music);
}
readStream.pipe(res);
});
@DingGGu
Copy link
Author

DingGGu commented Apr 8, 2015

Mobile does not support 'Content-Range' header when user request play.

var express     = require('express');
var app         = express();
var fs          = require('fs');

app.listen(3000, function() {
    console.log("[NodeJS] Application Listening on Port 3000");
});

app.get('/api/play/:key', function(req, res) {
    var key = req.params.key;

    var music = 'music/' + key + '.mp3';

    var stat = fs.statSync(music);
    range = req.headers.range;
    var readStream;

    if (range !== undefined) {
        var parts = range.replace(/bytes=/, "").split("-");

        var partial_start = parts[0];
        var partial_end = parts[1];

        var start = parseInt(partial_start, 10);
        var end = partial_end ? parseInt(partial_end, 10) : stat.size - 1;
        var content_length = (end - start) + 1;

        res.status(206).header({
            'Content-Type': 'audio/mpeg',
            'Content-Length': content_length,
            'Content-Range': "bytes " + start + "-" + end + "/" + stat.size
        });

        readStream = fs.createReadStream(music, {start: start, end: end});
    } else {
        res.header({
            'Content-Type': 'audio/mpeg',
            'Content-Length': stat.size
        });
        readStream = fs.createReadStream(music);
    }
    readStream.pipe(res);
});

@DingGGu
Copy link
Author

DingGGu commented May 7, 2016

createReadStream contained portential server crush.
NGINX PROXY showed
upstream prematurely closed connection while reading upstream
CHROME showed
ERR_INCOMPLETE_CHUNKED_ERROR

readStream = fs.createReadStream(music, {start: start, end: end});
start and end parameter just only accept numeric.

var express     = require('express');
var app         = express();
var fs          = require('fs');

app.listen(3000, function() {
    console.log("[NodeJS] Application Listening on Port 3000");
});

app.get('/api/play/:key', function(req, res) {
    var key = req.params.key;

    var music = 'music/' + key + '.mp3';

    var stat = fs.statSync(music);
    range = req.headers.range;
    var readStream;

    if (range !== undefined) {
        var parts = range.replace(/bytes=/, "").split("-");

        var partial_start = parts[0];
        var partial_end = parts[1];

        if ((isNaN(partial_start) && partial_start.length > 1) || (isNaN(partial_end) && partial_end.length > 1)) {
            return res.sendStatus(500); //ERR_INCOMPLETE_CHUNKED_ENCODING
        }

        var start = parseInt(partial_start, 10);
        var end = partial_end ? parseInt(partial_end, 10) : stat.size - 1;
        var content_length = (end - start) + 1;

        res.status(206).header({
            'Content-Type': 'audio/mpeg',
            'Content-Length': content_length,
            'Content-Range': "bytes " + start + "-" + end + "/" + stat.size
        });

        readStream = fs.createReadStream(music, {start: start, end: end});
    } else {
        res.header({
            'Content-Type': 'audio/mpeg',
            'Content-Length': stat.size
        });
        readStream = fs.createReadStream(music);
    }
    readStream.pipe(res);
});

@edinsoncs
Copy link

Great

@loretoparisi
Copy link

👍 💯 🥇

@bentooth
Copy link

bentooth commented Jan 1, 2019

Thank you for this! <3 <3 <3

@enif-lee
Copy link

enif-lee commented Jan 6, 2019

GREAT!

@jezequiel
Copy link

genial!

@alainib
Copy link

alainib commented Feb 24, 2020

i got

TypeError: fs.statSync is not a function
at /app/app.js:42:17
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
at next (/app/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
at /app/node_modules/express/lib/router/index.js:281:22
at param (/app/node_modules/express/lib/router/index.js:354:14)
at param (/app/node_modules/express/lib/router/index.js:365:14)
at Function.process_params (/app/node_modules/express/lib/router/index.js:410:3)
at next (/app/node_modules/express/lib/router/index.js:275:10)

@DingGGu
Copy link
Author

DingGGu commented Feb 25, 2020

i got

TypeError: fs.statSync is not a function
at /app/app.js:42:17
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
at next (/app/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
at /app/node_modules/express/lib/router/index.js:281:22
at param (/app/node_modules/express/lib/router/index.js:354:14)
at param (/app/node_modules/express/lib/router/index.js:365:14)
at Function.process_params (/app/node_modules/express/lib/router/index.js:410:3)
at next (/app/node_modules/express/lib/router/index.js:275:10)

@alainib Please make sure declare at the top of your code.

const fs = require('fs')

@StupidRepo
Copy link

This is amazing, thanks for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment