upload correct version
Signed-off-by: Sam Therapy <sam@samtherapy.net>
This commit is contained in:
parent
65fbd7ca9e
commit
018afaf0e2
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire, createRequireFromPath} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint/bin/eslint.js
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
}
|
||||
|
||||
// Defer to the real eslint/bin/eslint.js your application uses
|
||||
module.exports = absRequire(`eslint/bin/eslint.js`);
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire, createRequireFromPath} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
|
||||
const relPnpApiPath = "../../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require eslint
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
}
|
||||
|
||||
// Defer to the real eslint your application uses
|
||||
module.exports = absRequire(`eslint`);
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "eslint",
|
||||
"version": "8.22.0-sdk",
|
||||
"main": "./lib/api.js",
|
||||
"type": "commonjs"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {existsSync} = require(`fs`);
|
||||
const {createRequire, createRequireFromPath} = require(`module`);
|
||||
const {resolve} = require(`path`);
|
||||
|
||||
const relPnpApiPath = "../../../.pnp.cjs";
|
||||
|
||||
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
|
||||
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
|
||||
|
||||
if (existsSync(absPnpApiPath)) {
|
||||
if (!process.versions.pnp) {
|
||||
// Setup the environment to be able to require prettier/index.js
|
||||
require(absPnpApiPath).setup();
|
||||
}
|
||||
}
|
||||
|
||||
// Defer to the real prettier/index.js your application uses
|
||||
module.exports = absRequire(`prettier/index.js`);
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "prettier",
|
||||
"version": "2.7.1-sdk",
|
||||
"main": "./index.js",
|
||||
"type": "commonjs"
|
||||
}
|
|
@ -12,11 +12,11 @@ https://waifurudor.de/?tags=tohsaka_rin,-feet,-underwear,rating:safe
|
|||
|
||||
Clone the repo to where ever you will be hosting this and run the following command to install the dependencies.
|
||||
|
||||
```sh
|
||||
yarn
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
Now that the dependencies are taken care of you can verify it runs with `yarn build && yarn start` in the root directory of the project. If it tells you it is listening on a port you're probably good to go.
|
||||
Now that the dependencies are taken care of you can verify it runs with `npm start` in the root directory of the project. If it tells you it is listening on a port you're probably good to go.
|
||||
|
||||
## Running as a service
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
},
|
||||
"name": "waifurudor.de",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build": "tsc --build",
|
||||
"clean": "tsc --build --clean",
|
||||
"start": "node ./dist/index.js"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -20,10 +20,10 @@
|
|||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/express": "4.17.13",
|
||||
"@types/morgan": "1",
|
||||
"@types/morgan": "1.9.3",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import express, { NextFunction, Request, Response } from "express";
|
||||
import helmet from "helmet";
|
||||
import morgan from "morgan";
|
||||
|
||||
import { ParseGet, ParsePost } from "./helpers/parse.js";
|
||||
import Search from "./helpers/search.js";
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(helmet());
|
||||
app.use(morgan("combined"));
|
||||
// app.use(morgan(process.env.NODE_ENV === "production" ? "tiny" : "dev"));
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
// Errors
|
||||
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
||||
console.error(err.stack);
|
||||
res.status(500).json({ msg: "Wife machine broke", error: err });
|
||||
});
|
||||
|
||||
app
|
||||
.route("/")
|
||||
.get(ParseGet, Search)
|
||||
.post(ParsePost, Search)
|
||||
// Also have a fallback for anyone who tries to be silly :)
|
||||
.all((_req, res) => {
|
||||
res.set("ALLOW", "GET, POST");
|
||||
res.status(405).json({ msg: "Method not allowed." });
|
||||
});
|
||||
|
||||
// Politely tell all crawlers to go away since there's nothing here.
|
||||
app.get("/robots.txt", (_req, res) => {
|
||||
res.setHeader("content-type", "text/plain");
|
||||
res.status(200).send(`User-agent: *
|
||||
Disallow: /`);
|
||||
});
|
||||
|
||||
app.get("/source", (_req, res) => {
|
||||
res.redirect(301, "https://git.freecumextremist.com/grumbulon/waifurudor.de");
|
||||
});
|
||||
|
||||
// For 404s
|
||||
app.use((_req, res) => {
|
||||
res.setHeader("content-type", "text/plain");
|
||||
res.status(404).send("Nothing beside remains.");
|
||||
});
|
||||
|
||||
export default app;
|
|
@ -0,0 +1,108 @@
|
|||
// TODO: many of these are probably redundant and should be removed.
|
||||
/**
|
||||
* Helper function to allow adding content types because XSS bad.
|
||||
* Hopefully this works as it should.
|
||||
* @param extension File extension, without any additional faff
|
||||
* @returns Content type that should be used
|
||||
*/
|
||||
export default function ContentType(extension: string): string {
|
||||
switch (
|
||||
extension.toLowerCase()?.replace("jpg", "jpeg").replace("svg", "svg+xml")
|
||||
) {
|
||||
case "aces":
|
||||
case "avci":
|
||||
case "avcs":
|
||||
case "avif":
|
||||
case "bmp":
|
||||
case "cgm":
|
||||
case "dpx":
|
||||
case "emf":
|
||||
case "fits":
|
||||
case "g3fax":
|
||||
case "gif":
|
||||
case "heic":
|
||||
case "heif":
|
||||
case "hej2k":
|
||||
case "hsj2":
|
||||
case "ief":
|
||||
case "jls":
|
||||
case "jp2":
|
||||
case "jpeg":
|
||||
case "jph":
|
||||
case "jphc":
|
||||
case "jpm":
|
||||
case "jpx":
|
||||
case "jxr":
|
||||
case "jxra":
|
||||
case "jxrs":
|
||||
case "jxs":
|
||||
case "jxsc":
|
||||
case "jxsi":
|
||||
case "jxss":
|
||||
case "ktx":
|
||||
case "ktx2":
|
||||
case "naplps":
|
||||
case "png":
|
||||
case "prs.btif":
|
||||
case "prs.pti":
|
||||
case "pwg-raster":
|
||||
case "t38":
|
||||
case "tiff":
|
||||
case "tiff-fx":
|
||||
case "wmf":
|
||||
return `image/${extension}`;
|
||||
|
||||
case "1d-interleaved-parityfec":
|
||||
case "3gpp":
|
||||
case "3gpp2":
|
||||
case "3gpp-tt":
|
||||
case "av1":
|
||||
case "bmpeg":
|
||||
case "bt656":
|
||||
case "celb":
|
||||
case "dv":
|
||||
case "encaprtp":
|
||||
case "ffv1":
|
||||
case "flexfec":
|
||||
case "h261":
|
||||
case "h263":
|
||||
case "h263-1998":
|
||||
case "h263-2000":
|
||||
case "h264":
|
||||
case "h264-rcdo":
|
||||
case "h264-svc":
|
||||
case "h265":
|
||||
case "iso.segment":
|
||||
case "jxsv":
|
||||
case "mj2":
|
||||
case "mp1s":
|
||||
case "mp2p":
|
||||
case "mp2t":
|
||||
case "mp4":
|
||||
case "mp4v-es":
|
||||
case "mpv":
|
||||
case "mpeg":
|
||||
case "mpeg4-generic":
|
||||
case "nv":
|
||||
case "ogg":
|
||||
case "parityfec":
|
||||
case "pointer":
|
||||
case "quicktime":
|
||||
case "raptorfec":
|
||||
case "raw":
|
||||
case "rtp-enc-aescm128":
|
||||
case "rtploopback":
|
||||
case "rtx":
|
||||
case "scip":
|
||||
case "smpte291":
|
||||
case "smpte292m":
|
||||
case "ulpfec":
|
||||
case "vc1":
|
||||
case "vc2":
|
||||
case "vp8":
|
||||
case "vp9":
|
||||
return `video/${extension}`;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import { Request, Response, NextFunction } from "express";
|
||||
|
||||
/**
|
||||
* Middleware for extracting the options from a GET.
|
||||
*
|
||||
* Why not just support JSON for both GET and POST requests?
|
||||
* Don't wanna.
|
||||
*/
|
||||
export function ParseGet(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): void {
|
||||
if (req.query.tags && typeof req.query.tags === "string") {
|
||||
res.locals.tags = req.query.tags.split(",");
|
||||
}
|
||||
res.locals.booru = (req.query.booru as string) ?? "sb";
|
||||
next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware for extracting the options from a POST.
|
||||
*
|
||||
* Accepts from the body only because.
|
||||
*/
|
||||
export function ParsePost(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): void {
|
||||
res.locals.tags = req.body.tags;
|
||||
res.locals.booru = (req.body.booru as string) ?? "sb";
|
||||
next();
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { Request, Response } from "express";
|
||||
import booru from "booru";
|
||||
import ContentType from "./contentType.js";
|
||||
|
||||
/**
|
||||
* Searches the booru for an image to return.
|
||||
* @param _req Express request (not used)
|
||||
* @param res Node Response
|
||||
*/
|
||||
export default function Search(_req: Request, res: Response) {
|
||||
booru
|
||||
.search(res.locals.booru, res.locals.tags, { random: true, limit: 1 })
|
||||
.then(async (post) => {
|
||||
const imageURL = post[0]?.fileUrl as string;
|
||||
|
||||
const type = imageURL.split(".").pop() as string;
|
||||
res.setHeader("content-type", ContentType(type));
|
||||
|
||||
const img = await fetch(imageURL)
|
||||
// Turn the image into an ArrayBuffer (which is also a Promise)
|
||||
.then(async (fetchRes) => {
|
||||
return fetchRes?.arrayBuffer();
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
console.error(err);
|
||||
res.status(500).json({ msg: "Wife machine broke", error: err });
|
||||
});
|
||||
|
||||
// deepcode ignore XSS: nmp
|
||||
res.status(200).end(Buffer.from(img as ArrayBuffer), "binary");
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
res.status(400).json({ msg: "WaaS Error", error: err });
|
||||
console.error(err);
|
||||
});
|
||||
}
|
40
src/index.ts
40
src/index.ts
|
@ -1,45 +1,7 @@
|
|||
import express, { NextFunction, Request, Response } from "express";
|
||||
import helmet from "helmet";
|
||||
import morgan from "morgan";
|
||||
import app from "./app.js";
|
||||
|
||||
import { ParseGet, ParsePost, Search } from "./helpers/booruSearch.js";
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
app.use(helmet());
|
||||
app.use(morgan(process.env.NODE_ENV === "production" ? "tiny" : "dev"));
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
||||
console.error(err.stack);
|
||||
res.status(500).json({ msg: "Wife machine broke", error: err });
|
||||
});
|
||||
|
||||
app
|
||||
.route("/")
|
||||
.get(ParseGet, Search)
|
||||
.post(ParsePost, Search)
|
||||
// Also have a fallback for anyone who tries to be silly :)
|
||||
.all((_req, res) => {
|
||||
res.set("ALLOW", "GET, POST");
|
||||
res.status(405).json({ msg: "Method not allowed." });
|
||||
});
|
||||
|
||||
// Politely tell all crawlers to go away since there's nothing here.
|
||||
app.get("/robots.txt", (_req, res) => {
|
||||
res.setHeader("content-type", "text/plain");
|
||||
res.status(200).send(`User-agent: *
|
||||
Disallow: /`);
|
||||
});
|
||||
|
||||
// For 404s
|
||||
app.use((_req, res) => {
|
||||
res.setHeader("content-type", "text/plain");
|
||||
res.status(404).send("Nothing beside remains.");
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`listening on port ${port}`);
|
||||
});
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
[Unit]
|
||||
Description=waifurudor.de
|
||||
Description=waifurudor.de - Anime as a Service (AaaS)
|
||||
|
||||
[Service]
|
||||
ExecStart=npm start
|
||||
ExecStart=yarn start
|
||||
Restart=always
|
||||
User=none
|
||||
Group=nogroup
|
||||
Environment=PATH=/usr/bin:/usr/local/bin
|
||||
Environment=NODE_ENV=production
|
||||
WorkingDirectory=/whatever/user/waifurudor.de/src/
|
||||
WorkingDirectory=/whatever/user/waifurudor.de/
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -54,7 +54,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/morgan@npm:1":
|
||||
"@types/morgan@npm:1.9.3":
|
||||
version: 1.9.3
|
||||
resolution: "@types/morgan@npm:1.9.3"
|
||||
dependencies:
|
||||
|
@ -677,7 +677,7 @@ __metadata:
|
|||
resolution: "waifurudor.de@workspace:."
|
||||
dependencies:
|
||||
"@types/express": 4.17.13
|
||||
"@types/morgan": 1
|
||||
"@types/morgan": 1.9.3
|
||||
booru: 2.6.2
|
||||
express: ">=5.0.0-beta.1"
|
||||
helmet: 5.1.1
|
||||
|
|
Loading…
Reference in New Issue