2019-03-20 03:45:23 +08:00
|
|
|
const static = require("node-static");
|
|
|
|
const app = new static.Server("./app");
|
2019-10-29 15:49:04 +08:00
|
|
|
const port = Number(process.argv[2]) || process.env.PORT || 8080;
|
2019-03-20 03:45:23 +08:00
|
|
|
|
2019-04-15 21:13:38 +08:00
|
|
|
let tickets = [];
|
|
|
|
|
2019-04-15 00:09:42 +08:00
|
|
|
const cmd = "youtube-dl";
|
2019-04-15 21:13:38 +08:00
|
|
|
|
2020-03-16 06:14:55 +08:00
|
|
|
function escape(arg) {
|
|
|
|
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
|
|
}
|
|
|
|
|
2020-03-18 05:02:12 +08:00
|
|
|
function searchYoutube(q, limit, response) {
|
2020-03-16 06:14:55 +08:00
|
|
|
response.setHeader("Content-Type", "text/plain"); // necessary for firefox to read by chunks
|
|
|
|
|
2020-03-18 05:02:12 +08:00
|
|
|
console.log("YouTube searching", q, limit);
|
|
|
|
q = escape(`ytsearch${limit}:${q}`);
|
2020-03-16 06:14:55 +08:00
|
|
|
const command = `${cmd} -j ${q} | jq "{id,title}" | jq -s .`;
|
2020-03-17 05:57:13 +08:00
|
|
|
|
2020-03-16 06:14:55 +08:00
|
|
|
require("child_process").exec(command, {}, (error, stdout, stderr) => {
|
|
|
|
if (error) {
|
|
|
|
console.log("error", error);
|
|
|
|
response.writeHead(500);
|
|
|
|
response.end(error.message);
|
|
|
|
} else {
|
|
|
|
response.end(stdout);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-04-15 00:09:42 +08:00
|
|
|
|
2020-03-17 05:57:13 +08:00
|
|
|
function downloadYoutube(id, response) {
|
2019-04-15 00:09:42 +08:00
|
|
|
response.setHeader("Content-Type", "text/plain"); // necessary for firefox to read by chunks
|
|
|
|
|
2020-03-17 05:57:13 +08:00
|
|
|
console.log("YouTube downloading", id);
|
2019-03-29 04:43:18 +08:00
|
|
|
let args = [
|
|
|
|
"-f", "bestaudio",
|
|
|
|
"-o", `${__dirname}/_youtube/%(title)s-%(id)s.%(ext)s`,
|
2020-03-17 05:57:13 +08:00
|
|
|
id
|
2019-03-29 04:43:18 +08:00
|
|
|
]
|
2019-04-15 00:09:42 +08:00
|
|
|
let child = require("child_process").spawn(cmd, args);
|
2019-03-20 03:45:23 +08:00
|
|
|
|
2019-04-15 00:09:42 +08:00
|
|
|
child.stdout.setEncoding("utf8").on("data", chunk => response.write(chunk));
|
|
|
|
child.stderr.setEncoding("utf8").on("data", chunk => response.write(chunk));
|
2019-03-29 04:43:18 +08:00
|
|
|
|
|
|
|
child.on("error", error => {
|
|
|
|
console.log(error);
|
|
|
|
response.writeHead(500);
|
|
|
|
response.end(error.message);
|
|
|
|
});
|
|
|
|
|
|
|
|
child.on("close", code => {
|
2019-04-15 00:09:42 +08:00
|
|
|
if (code != 0) { // fixme
|
2019-03-29 04:43:18 +08:00
|
|
|
}
|
2019-04-15 00:09:42 +08:00
|
|
|
response.end();
|
2019-03-29 04:43:18 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-03-16 06:14:55 +08:00
|
|
|
function handleYoutubeSearch(url, response) {
|
|
|
|
let q = url.searchParams.get("q");
|
2020-03-18 05:02:12 +08:00
|
|
|
let limit = url.searchParams.get("limit") || "";
|
2020-03-16 06:14:55 +08:00
|
|
|
if (q) {
|
2020-03-18 05:02:12 +08:00
|
|
|
searchYoutube(q, limit, response);
|
2020-03-16 06:14:55 +08:00
|
|
|
} else {
|
|
|
|
response.writeHead(404);
|
|
|
|
response.end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleYoutubeDownload(request, response) {
|
2019-03-29 04:43:18 +08:00
|
|
|
let str = "";
|
|
|
|
request.setEncoding("utf8");
|
|
|
|
request.on("data", chunk => str += chunk);
|
|
|
|
request.on("end", () => {
|
2020-03-17 05:57:13 +08:00
|
|
|
let id = require("querystring").parse(str)["id"];
|
|
|
|
if (id) {
|
|
|
|
downloadYoutube(id, response);
|
2019-03-29 04:43:18 +08:00
|
|
|
} else {
|
|
|
|
response.writeHead(404);
|
|
|
|
response.end();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-04-15 21:13:38 +08:00
|
|
|
function handleTicket(request, response) {
|
|
|
|
request.resume().on("end", () => {
|
|
|
|
let ticket = require("crypto").randomBytes(16).toString("hex");
|
|
|
|
tickets.push(ticket);
|
|
|
|
if (tickets.length > 10) { tickets.shift(); }
|
|
|
|
|
|
|
|
let data = {ticket};
|
|
|
|
response.setHeader("Content-Type", "application/json");
|
|
|
|
response.end(JSON.stringify(data));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-03-29 04:43:18 +08:00
|
|
|
function onRequest(request, response) {
|
2020-03-16 06:14:55 +08:00
|
|
|
const url = new URL(request.url, "http://localhost");
|
|
|
|
|
2019-04-15 21:13:38 +08:00
|
|
|
switch (true) {
|
2020-03-16 06:14:55 +08:00
|
|
|
case request.method == "GET" && url.pathname == "/youtube":
|
|
|
|
return handleYoutubeSearch(url, response);
|
|
|
|
|
|
|
|
case request.method == "POST" && url.pathname == "/youtube":
|
|
|
|
return handleYoutubeDownload(request, response);
|
2019-04-15 21:13:38 +08:00
|
|
|
|
2020-03-16 06:14:55 +08:00
|
|
|
case request.method == "POST" && url.pathname == "/ticket":
|
2019-04-15 21:13:38 +08:00
|
|
|
return handleTicket(request, response);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return request.on("end", () => app.serve(request, response)).resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function requestValidator(request) {
|
|
|
|
let ticket = request.resourceURL.query["ticket"];
|
|
|
|
let index = tickets.indexOf(ticket);
|
|
|
|
if (index > -1) {
|
|
|
|
tickets.splice(index, 1);
|
|
|
|
return true;
|
2019-03-29 04:43:18 +08:00
|
|
|
} else {
|
2019-04-15 21:13:38 +08:00
|
|
|
return false;
|
2019-03-29 04:43:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let httpServer = require("http").createServer(onRequest).listen(port);
|
2019-04-15 21:13:38 +08:00
|
|
|
require("ws2mpd").ws2mpd(httpServer, requestValidator);
|
|
|
|
require("ws2mpd").logging(false);
|