101 lines
2.8 KiB
JavaScript
101 lines
2.8 KiB
JavaScript
var express = require("express");
|
|
require("express-async-errors");
|
|
var morgan = require("morgan");
|
|
var fs = require("fs/promises");
|
|
var getVideoLength = v => require('video-length')(v, {bin: "mediainfo"});
|
|
|
|
var app = module.exports.app = express();
|
|
app.set("env", process.env.NODE_ENV || "production");
|
|
app.set("trust proxy", ["loopback","linklocal","uniquelocal","173.245.48.0/20","103.21.244.0/22","103.22.200.0/22","103.31.4.0/22","141.101.64.0/18","108.162.192.0/18","190.93.240.0/20","188.114.96.0/20","197.234.240.0/22","198.41.128.0/17","162.158.0.0/15","104.16.0.0/13","104.24.0.0/14","172.64.0.0/13","131.0.72.0/22","2400:cb00::/32","2606:4700::/32","2803:f800::/32","2405:b500::/32","2405:8100::/32","2a06:98c0::/29","2c0f:f248::/32"]);
|
|
module.exports.server = app.listen(process.env.PORT || 8080, process.env.ADDR);
|
|
|
|
app.use(morgan(`:date[iso] :remote-addr :method :url ":req[user-agent]" :referrer`));
|
|
|
|
app.use("/videos/", express.static("videos"));
|
|
|
|
app.get("/playlist", async (req, res) => {
|
|
res.send(await getPlaylist());
|
|
});
|
|
|
|
app.use(express.static("public"));
|
|
|
|
require("./mousie-server");
|
|
|
|
|
|
|
|
|
|
|
|
var currentPlaylist;
|
|
|
|
async function getPlaylist() {
|
|
if (!currentPlaylist || Date.now() > currentPlaylist.timestamp + currentPlaylist.totalDuration*1000) {
|
|
currentPlaylist = await generatePlaylist();
|
|
}
|
|
return currentPlaylist;
|
|
}
|
|
|
|
async function generatePlaylist() {
|
|
var videofiles = await fs.readdir("videos");
|
|
|
|
var videos = [];
|
|
|
|
for (let name of videofiles) {
|
|
let metadata = await getMetadata(name);
|
|
if (!metadata.duration) {
|
|
console.warn("missing duration:", name);
|
|
continue;
|
|
};
|
|
videos.push({
|
|
name,
|
|
duration: metadata.duration,
|
|
source: metadata.source || inferSource(name)
|
|
});
|
|
}
|
|
|
|
shuffle(videos);
|
|
|
|
return {
|
|
videos,
|
|
timestamp: Date.now(),
|
|
totalDuration: videos.reduce((td, v) => td + v.duration, 0)
|
|
}
|
|
}
|
|
|
|
async function getMetadata(video) {
|
|
var videopath = `videos/${video}`;
|
|
var metadatapath = `metadata/${video}.json`;
|
|
try {
|
|
var metadata = JSON.parse(await fs.readFile(metadatapath, "utf8"));
|
|
} catch (error) {
|
|
var metadata = {
|
|
duration: null
|
|
};
|
|
try {
|
|
metadata.duration = await getVideoLength(videopath);
|
|
} catch(error) {
|
|
console.error("get video length:", error.message);
|
|
};
|
|
await fs.writeFile(metadatapath, JSON.stringify(metadata));
|
|
}
|
|
return metadata;
|
|
}
|
|
|
|
function inferSource(name) {
|
|
var youtube_id = name.match(/\[([A-Za-z0-9_-]{11})\]/);
|
|
if (youtube_id)
|
|
return `https://www.youtube.com/watch?v=${youtube_id[1]}`;
|
|
|
|
var niconico_id = name.match(/\[(sm\d+)\]/);
|
|
if (niconico_id)
|
|
return `https://www.nicovideo.jp/watch/${niconico_id[1]}`;
|
|
}
|
|
|
|
|
|
|
|
|
|
function shuffle(array) {
|
|
for (let i = array.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[array[i], array[j]] = [array[j], array[i]];
|
|
}
|
|
} |