Compare commits

...

12 Commits

Author SHA1 Message Date
lamp 1987330aa7 update for ytdl ejs 2025-12-04 16:43:30 -08:00
lamp 5ba0447644 fix mediainfo 2025-08-31 12:41:47 -07:00
lamp 5b3181669d prefer ipv6 w/o force
can't force ipv6 because some sites like niconico don't have it, change to debian so that ula can be preferred
2025-08-31 01:48:37 -07:00
lamp 710ea0d79f Merge branch 'v2' of ssh.gitea.moe:lamp/ytdl-server into v2 2025-08-04 15:54:13 -07:00
lamp 621a260b88 separate metadata dir 2025-08-04 15:53:26 -07:00
lamp 2f3d0568c9 no flood progress 2025-08-04 14:32:37 -07:00
lamp 555821558f force ipv6 2025-08-02 15:13:57 -07:00
lamp 09f4a1d207 NO PLAYLIST 2025-07-29 21:54:50 -04:00
lamp 50897441fc fix format no duration 2024-09-18 17:37:55 -07:00
lamp 17800acee6 bug 2024-08-03 22:21:19 -07:00
lamp 9d43b79f2e auto update 2024-07-31 00:46:46 -07:00
Lamp bb6a58504b 2024-03-21 00:14:55 -07:00
8 changed files with 136 additions and 47 deletions
+1
View File
@@ -1,3 +1,4 @@
.git
node_modules node_modules
downloads downloads
metadata metadata
+10 -8
View File
@@ -1,13 +1,15 @@
FROM alpine:3.18 FROM node:20-bookworm
RUN adduser -S ytdl ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
RUN apk add --no-cache nodejs npm python3 py3-pip ffmpeg mediainfo make g++ RUN useradd -r -m -s /bin/bash -u 369 ytdl
RUN pip3 install yt-dlp RUN apt update; apt install -y python3-pip ffmpeg mediainfo make g++ iproute2
ADD . /app ADD . /app
WORKDIR /app WORKDIR /app
RUN npm ci RUN npm ci
ENV DOWNLOADS=/downloads ADD ./gai.conf /etc/gai.conf
RUN mkdir -p $DOWNLOADS/metadata; chown -R ytdl $DOWNLOADS ENV DOWNLOADS=/downloads META_DIR=/metadata
RUN mkdir $DOWNLOADS $META_DIR; chown -R ytdl $DOWNLOADS $META_DIR
USER ytdl USER ytdl
VOLUME $DOWNLOADS ENV PATH="/home/ytdl/.local/bin:$PATH"
VOLUME $DOWNLOADS $META_DIR
EXPOSE 8080 EXPOSE 8080
CMD ["node", "."] CMD ["sh", "-c", "pip install --break-system-packages --upgrade yt-dlp[default]; exec node ."]
+67
View File
@@ -0,0 +1,67 @@
# prefer ipv6 ULA over ipv4 because docker uses NATed ULA
# Configuration for getaddrinfo(3).
#
# So far only configuration for the destination address sorting is needed.
# RFC 3484 governs the sorting. But the RFC also says that system
# administrators should be able to overwrite the defaults. This can be
# achieved here.
#
# All lines have an initial identifier specifying the option followed by
# up to two values. Information specified in this file replaces the
# default information. Complete absence of data of one kind causes the
# appropriate default information to be used. The supported commands include:
#
# reload <yes|no>
# If set to yes, each getaddrinfo(3) call will check whether this file
# changed and if necessary reload. This option should not really be
# used. There are possible runtime problems. The default is no.
#
# label <mask> <value>
# Add another rule to the RFC 3484 label table. See section 2.1 in
# RFC 3484. The default is:
#
label ::1/128 0
label ::/0 1
label 2002::/16 2
label ::/96 3
label ::ffff:0:0/96 4
#label fec0::/10 5
#label fc00::/7 6
#label 2001:0::/32 7
#
# This default differs from the tables given in RFC 3484 by handling
# (now obsolete) site-local IPv6 addresses and Unique Local Addresses.
# The reason for this difference is that these addresses are never
# NATed while IPv4 site-local addresses most probably are. Given # *NEVER* NATed huh? You CLUELESS FUCKING RETARDS
# the precedence of IPv6 over IPv4 (see below) on machines having only
# site-local IPv4 and IPv6 addresses a lookup for a global address would
# see the IPv6 be preferred. The result is a long delay because the
# site-local IPv6 addresses cannot be used while the IPv4 address is
# (at least for the foreseeable future) NATed. We also treat Teredo
# tunnels special.
#
# precedence <mask> <value>
# Add another rule to the RFC 3484 precedence table. See section 2.1
# and 10.3 in RFC 3484. The default is:
#
#precedence ::1/128 50
#precedence ::/0 40
#precedence 2002::/16 30
#precedence ::/96 20
#precedence ::ffff:0:0/96 10
#
# For sites which prefer IPv4 connections change the last line to
#
#precedence ::ffff:0:0/96 100
#
# scopev4 <mask> <value>
# Add another rule to the RFC 6724 scope table for IPv4 addresses.
# By default the scope IDs described in section 3.2 in RFC 6724 are
# used. Changing these defaults should hardly ever be necessary.
# The defaults are equivalent to:
#
#scopev4 ::ffff:169.254.0.0/112 2
#scopev4 ::ffff:127.0.0.0/104 2
#scopev4 ::ffff:0.0.0.0/96 14
+3 -2
View File
@@ -1,5 +1,6 @@
process.env.DOWNLOADS ||= "downloads"; process.env.DOWNLOADS ||= "downloads";
process.env.META_DIR ||= "metadata";
process.env.PORT ||= 8080; process.env.PORT ||= 8080;
require("./web.js") require("./web.js");
require("./wss.js") require("./wss.js");
+2 -2
View File
@@ -18,7 +18,7 @@ async function generateList() {
var files = fs.readdirSync(process.env.DOWNLOADS, {withFileTypes: true}).filter(f => f.isFile()).map(f => f.name); var files = fs.readdirSync(process.env.DOWNLOADS, {withFileTypes: true}).filter(f => f.isFile()).map(f => f.name);
var list = await Promise.all(files.map(async name => { var list = await Promise.all(files.map(async name => {
var filepath = path.join(process.env.DOWNLOADS, name); var filepath = path.join(process.env.DOWNLOADS, name);
var metapath = path.join(process.env.DOWNLOADS, "metadata", name) + ".json"; var metapath = path.join(process.env.META_DIR, name) + ".json";
try { try {
var metadata = JSON.parse(fs.readFileSync(metapath, "utf8")); var metadata = JSON.parse(fs.readFileSync(metapath, "utf8"));
@@ -26,7 +26,7 @@ async function generateList() {
var metadata = {}; var metadata = {};
try { try {
metadata.duration = await getVideoLength(filepath); metadata.duration = await getVideoLength(filepath);
} catch(error) {console.error(error.message)}; } catch(error) {console.error(error.stack)};
fs.writeFileSync(metapath, JSON.stringify(metadata)); fs.writeFileSync(metapath, JSON.stringify(metadata));
} }
+2 -1
View File
@@ -97,6 +97,7 @@
loadList(); loadList();
function formatDuration(seconds) { function formatDuration(seconds) {
if (!seconds) return "?";
var d = new Date(0); var d = new Date(0);
d.setSeconds(seconds); d.setSeconds(seconds);
var hms = d.toISOString().substring(11, 19); var hms = d.toISOString().substring(11, 19);
@@ -111,4 +112,4 @@
} }
</script> </script>
</body></html> </body></html>
+3 -1
View File
@@ -1,3 +1,5 @@
docker build -t ytdl-server . docker build -t ytdl-server .
docker run -d --restart=unless-stopped --name ytdls -p 8080:8080 -v "downloads:/downloads" ytdl-server docker run -d --restart=unless-stopped --name ytdl-server -p 8660:8080 -v "/zpool1/ytdls:/downloads" -v "./metadata/:/metadata" ytdl-server
docker ipv6 required
+48 -33
View File
@@ -3,8 +3,9 @@ var qs = require("qs");
var proxyaddr = require("proxy-addr"); var proxyaddr = require("proxy-addr");
var child_process = require("child_process"); var child_process = require("child_process");
var {app, server} = require("./web"); var {app, server} = require("./web");
var {getList, uncacheList} = require("./metalist"); var {uncacheList} = require("./metalist");
var fs = require("fs");
var lastUpdate = Date.now();
var wss = new WebSocketServer({ server }); var wss = new WebSocketServer({ server });
@@ -18,40 +19,54 @@ wss.on("connection", function(ws, req) {
var url = req.query.url; var url = req.query.url;
if (!url) { ws.send(color("red", "missing url")); ws.close(); return } if (!url) { ws.send(color("red", "missing url")); ws.close(); return }
ws.send(color("green", "spawning yt-dlp...")); if (Date.now() - lastUpdate > 8.64e7) {
var cp = child_process.spawn("yt-dlp", ["--no-mtime", url], {cwd: process.env.DOWNLOADS, shell: false}); ws.send("updating yt-dlp...");
var cp = makeCp("pip", ["install", "--break-system-packages", "--upgrade", "yt-dlp"]);
cp.on("close", next);
lastUpdate = Date.now();
} else next();
cp.on("error", error => { function next() {
log(error.message, true); var cp = makeCp("yt-dlp", ["--js-runtimes", "node", "--no-mtime", "--no-playlist", "--progress-delta", "1", url], {cwd: process.env.DOWNLOADS, shell: false});
ws.send(color("red", error.message)); cp.on("close", (code, signal) => {
}); uncacheList();
cp.stdout.on("data", data => { ws.close();
var msg = data.toString().trim(); });
if (msg) { ws.on("close", () => {
log(msg); log("socket closed");
ws.send("yt-dlp: " + color("blue", msg)); });
} }
});
cp.stderr.on("data", data => {
var msg = data.toString().trim();
if (msg) {
log(msg, true);
ws.send(color("orange", "yt-dlp: " + color("blue", msg)));
}
});
cp.on("close", (code, signal) => {
log(`cp exit ${code} (${signal})`);
ws.send(color("green", `yt-dlp exited with code ${code}`));
uncacheList();
ws.close();
});
ws.on("close", () => { function makeCp(command, args, options) {
log("socket closed"); ws.send(color("green", `spawning ${command}...`));
cp.kill(); var cp = child_process.spawn(command, args, options);
});
cp.on("error", error => {
log(error.message, true);
ws.send(color("red", error.message));
});
cp.stdout.on("data", data => {
var msg = data.toString().trim();
if (msg) {
log(msg);
ws.send(command + ": " + color("blue", msg));
}
});
cp.stderr.on("data", data => {
var msg = data.toString().trim();
if (msg) {
log(msg, true);
ws.send(color("orange", command + ": " + color("blue", msg)));
}
});
cp.on("close", (code, signal) => {
log(`${command} exit ${code} (${signal})`);
ws.send(color("green", `${command} exited with code ${code}`));
});
return cp;
}
}); });
function color(color, text) { function color(color, text) {
return `<span style="color: ${color}">${text}</span>`; return `<span style="color: ${color}">${text}</span>`;
} }