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]]; } }