Compare commits

..

14 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
lamp c6df8df43c Merge branch 'v2' of gitea.moe:lamp/ytdl-server into v2 2023-10-11 14:18:21 -07:00
lamp d2168c1cef fix morgan 2023-10-11 14:18:17 -07:00
9 changed files with 137 additions and 49 deletions
+1
View File
@@ -1,3 +1,4 @@
.git
node_modules
downloads
metadata
+10 -8
View File
@@ -1,13 +1,15 @@
FROM alpine:3.18
RUN adduser -S ytdl
RUN apk add --no-cache nodejs npm python3 py3-pip ffmpeg mediainfo make g++
RUN pip3 install yt-dlp
FROM node:20-bookworm
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
RUN useradd -r -m -s /bin/bash -u 369 ytdl
RUN apt update; apt install -y python3-pip ffmpeg mediainfo make g++ iproute2
ADD . /app
WORKDIR /app
RUN npm ci
ENV DOWNLOADS=/downloads
RUN mkdir -p $DOWNLOADS/metadata; chown -R ytdl $DOWNLOADS
ADD ./gai.conf /etc/gai.conf
ENV DOWNLOADS=/downloads META_DIR=/metadata
RUN mkdir $DOWNLOADS $META_DIR; chown -R ytdl $DOWNLOADS $META_DIR
USER ytdl
VOLUME $DOWNLOADS
ENV PATH="/home/ytdl/.local/bin:$PATH"
VOLUME $DOWNLOADS $META_DIR
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.META_DIR ||= "metadata";
process.env.PORT ||= 8080;
require("./web.js")
require("./wss.js")
require("./web.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 list = await Promise.all(files.map(async 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 {
var metadata = JSON.parse(fs.readFileSync(metapath, "utf8"));
@@ -26,7 +26,7 @@ async function generateList() {
var metadata = {};
try {
metadata.duration = await getVideoLength(filepath);
} catch(error) {console.error(error.message)};
} catch(error) {console.error(error.stack)};
fs.writeFileSync(metapath, JSON.stringify(metadata));
}
+1
View File
@@ -97,6 +97,7 @@
loadList();
function formatDuration(seconds) {
if (!seconds) return "?";
var d = new Date(0);
d.setSeconds(seconds);
var hms = d.toISOString().substring(11, 19);
+3 -1
View File
@@ -1,3 +1,5 @@
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
+1 -2
View File
@@ -3,14 +3,13 @@ require("express-async-errors");
var serveFavicon = require("serve-favicon");
var morgan = require("morgan");
var {getList} = require("./metalist");
var {readFile} = require("fs/promises");
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, process.env.ADDR);
app.use(morgan(`:date[iso] :req[cf-connecting-ip] :method :url ":req[user-agent]" :referrer`));
app.use(morgan(`:date[iso] :remote-addr :method :url ":req[user-agent]" :referrer`));
app.use(serveFavicon("favicon.ico"));
+47 -32
View File
@@ -3,8 +3,9 @@ var qs = require("qs");
var proxyaddr = require("proxy-addr");
var child_process = require("child_process");
var {app, server} = require("./web");
var {getList, uncacheList} = require("./metalist");
var fs = require("fs");
var {uncacheList} = require("./metalist");
var lastUpdate = Date.now();
var wss = new WebSocketServer({ server });
@@ -18,38 +19,52 @@ wss.on("connection", function(ws, req) {
var url = req.query.url;
if (!url) { ws.send(color("red", "missing url")); ws.close(); return }
ws.send(color("green", "spawning yt-dlp..."));
var cp = child_process.spawn("yt-dlp", ["--no-mtime", url], {cwd: process.env.DOWNLOADS, shell: false});
if (Date.now() - lastUpdate > 8.64e7) {
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 => {
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("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();
});
function next() {
var cp = makeCp("yt-dlp", ["--js-runtimes", "node", "--no-mtime", "--no-playlist", "--progress-delta", "1", url], {cwd: process.env.DOWNLOADS, shell: false});
cp.on("close", (code, signal) => {
uncacheList();
ws.close();
});
ws.on("close", () => {
log("socket closed");
});
}
ws.on("close", () => {
log("socket closed");
cp.kill();
});
function makeCp(command, args, options) {
ws.send(color("green", `spawning ${command}...`));
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) {