yt backend

This commit is contained in:
Lamp 2023-10-14 17:40:42 -07:00
parent e9e798ebae
commit bfc7956f8c
6 changed files with 42 additions and 94 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
node_modules
metadata
videos
videos
videos.json

8
getvideos.py Normal file
View File

@ -0,0 +1,8 @@
from yt_dlp import YoutubeDL
from json import dump
with YoutubeDL() as ydl:
info = ydl.extract_info("ytsearch500:mmd", download=False, process=False)
info["entries"] = list(info["entries"])
with open("videos.json", "w") as f:
dump(info, f)

View File

@ -2,7 +2,6 @@ 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");
@ -11,8 +10,6 @@ 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());
});
@ -35,22 +32,12 @@ async function getPlaylist() {
}
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)
});
}
var videos = JSON.parse(await fs.readFile("videos.json", "utf8")).entries;
videos = videos.map(v => ({
id: v.id,
duration: v.duration,
title: v.title
}));
shuffle(videos);
@ -61,37 +48,6 @@ async function generatePlaylist() {
}
}
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--) {

11
package-lock.json generated
View File

@ -8,7 +8,6 @@
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
"morgan": "^1.10.0",
"video-length": "^2.0.6",
"ws": "^8.14.2"
}
},
@ -655,11 +654,6 @@
"node": ">= 0.8"
}
},
"node_modules/video-length": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/video-length/-/video-length-2.0.6.tgz",
"integrity": "sha512-vPh0n39/3q2Gdzv93w745bjfNg+DFvhpKCr0GH2ZVYuPCXXYUGmy0fgmJOpk9btiZmAZsBrX/xhwb2tmyEoyBw=="
},
"node_modules/ws": {
"version": "8.14.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
@ -1157,11 +1151,6 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
},
"video-length": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/video-length/-/video-length-2.0.6.tgz",
"integrity": "sha512-vPh0n39/3q2Gdzv93w745bjfNg+DFvhpKCr0GH2ZVYuPCXXYUGmy0fgmJOpk9btiZmAZsBrX/xhwb2tmyEoyBw=="
},
"ws": {
"version": "8.14.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",

View File

@ -3,7 +3,6 @@
"express": "^4.18.2",
"express-async-errors": "^3.1.1",
"morgan": "^1.10.0",
"video-length": "^2.0.6",
"ws": "^8.14.2"
}
}

View File

@ -53,30 +53,19 @@
<div id="ytplayer"></div>
<script>
(onload = onresize = () => {
ytplayer.width = Math.min(innerWidth, 16/9 * innerHeight);
ytplayer.height = Math.min(innerHeight, 9/16 * innerWidth);
ytplayer.style.width = Math.min(innerWidth, 16/9 * innerHeight) + "px";
ytplayer.style.height = Math.min(innerHeight, 9/16 * innerWidth) + "px";
})();
</script>
<template id="mousie_template">
<div class="mousie">
<div class="mousie_pointer">🮰</div>
<div class="mousie_talk"></div>
</div>
</template>
<script>
var player;
function initializePlayer(ytid, position) {
function initializePlayer(id, position) {
initializePlayer = () => console.warn("player already initialized");
return new Promise(function (resolve, reject) {
player = new YT.Player('ytplayer', {
videoId: ytid,
width: ytplayer.width,
height: ytplayer.height,
videoId: id,
width: "1920",
height: "1080",
playerVars: {
'playsinline': 1,
"autoplay": 1,
@ -109,15 +98,15 @@
}
async function sync(force) {
var {ytid, position} = await nowPlaying();
var {id, position} = await nowPlaying();
if (!player) {
await initializePlayer(ytid, position);
await initializePlayer(id, position);
}
if (player.getVideoData().video_id != ytid) {
if (player.getVideoData().video_id != id) {
console.debug("change video");
player.loadVideoById(ytid, position);
player.loadVideoById(id, position);
player.playVideo();
}
@ -139,9 +128,6 @@
if (!playlist || Date.now() > playlist.timestamp + playlist.totalDuration*1000) {
playlist = await fetch("playlist").then(res => res.json());
}
playlist.videos = playlist.videos.filter(v => v.source.includes('youtube'));//tmp
for (var i = 0, pastDurations = 0; i < playlist.videos.length; i++) {
var video = playlist.videos[i];
var videoDurationMs = video.duration * 1000;
@ -152,8 +138,7 @@
}
return {
position: (Date.now() - pastDurations - playlist.timestamp) / 1000,
source: video.source,
ytid: video.source.split('?v=')[1]
id: video.id
};
}
@ -161,7 +146,17 @@
</script>
<script> // mousies
<template id="mousie_template">
<div class="mousie">
<div class="mousie_pointer">🮰</div>
<div class="mousie_talk"></div>
</div>
</template>
<script>
var ws;
(function createWs() {
ws = new WebSocket(location.href.replace('http','ws'));
@ -204,11 +199,11 @@
};
})();
onmousemove = evt => {
onmousemove = ({pageX, pageY}) => {
if (ws.readyState != WebSocket.OPEN) return;
var {left, top, width, height} = ytplayer.getBoundingClientRect();
var x = (4096 * evt.pageX / width) - (4096 * left / width);
var y = (4096 * evt.pageY / height) - (4096 * top / height);
var x = (4096 * pageX / width) - (4096 * left / width);
var y = (4096 * pageY / height) - (4096 * top / height);
var b = new ArrayBuffer(4);
var dv = new DataView(b);
dv.setInt16(0, x, false);
@ -268,7 +263,7 @@
oncontextmenu = evt => {
evt.preventDefault();
nowPlaying().then(v => {
if (v.source) open(v.source, "_blank");
open(`https://www.youtube.com/watch?v=${v.id}`, "_blank");
});
};