Compare commits

...

22 Commits

Author SHA1 Message Date
lamp 881ee4568d Update 'README.md' 2023-02-04 21:44:02 -06:00
lamp 7ac32d6dff update urls 2023-02-05 03:35:33 +00:00
lamp 175a86b490 Merge branch 'proxy' of gitea.moe:lamp/random-miku-server into proxy 2023-02-05 03:29:25 +00:00
lamp 8f1c789c8e remove backup origin 2023-02-05 03:28:29 +00:00
lamp c4d55ec6c7 update url 2022-10-14 02:13:53 -05:00
lamp 3ab1623bed multiple random id 2022-07-31 17:23:18 -07:00
lamp 88a6e5e692 rip 39 commits
update fallback uri
2021-12-08 15:02:21 -06:00
lamp 99f05ea2e0 39 2021-12-04 22:29:27 -08:00
lamp 3ef1d4bdcb draw only id on thumb_mini 2021-11-25 18:16:10 -08:00
lamp 091197e7c7 hmm 2021-11-25 20:08:30 -06:00
lamp 63a9916a03 add option to draw url 2021-11-25 17:56:00 -08:00
lamp 0219cc7f83 Merge branch 'proxy' of gitea.moe:lamp/random-miku-server into proxy 2021-11-25 17:02:05 -08:00
lamp 47a05b243f relocate cache-control 2021-11-25 17:02:02 -08:00
lamp 93017002b9 Update 'README.md' 2021-11-25 18:55:28 -06:00
lamp f5e734a9c9 Update 'README.md' 2021-11-25 18:38:55 -06:00
lamp 42566713cf add r18 only 2021-11-25 16:32:42 -08:00
lamp 9d8d5c078e rewrite readme 2021-11-25 16:12:55 -08:00
lamp 77221513b5 refactor api 2021-11-25 15:36:32 -08:00
lamp 9ecdae240b proxy alternative server if pximg not OK
use status 203
add content-disposition
fix error handler i forgot to un-debug
2021-11-25 14:58:39 -08:00
lamp 8fac3fedcc Merge branch 'proxy' of gitea.moe:lamp/random-miku-server into proxy 2021-11-21 23:31:27 -08:00
lamp 04cbf250b0 add history page and rewrite readme 2021-11-21 23:30:36 -08:00
lamp ebb2071a12 move querystring to left of pixiv url; add auto 2021-11-21 16:12:37 -08:00
6 changed files with 775 additions and 293 deletions
+1
View File
@@ -1,3 +1,4 @@
node_modules node_modules
.env .env
output.log output.log
logs
+16 -15
View File
@@ -1,21 +1,22 @@
Simply go to https://random-miku.owo39.me/ and it will redirect to `https://random-miku.owo39.me/https://www.pixiv.net/en/artworks/<randomid>` which will serve the raw image directly, and the url as such allows you to delete the left half to get to the source. Another request to the same URL from the same IP address will be redirected to a different random image so you can click the reload button in your browser to see different images. A simple no-HTML random Hatsune Miku image server. Example: https://rms.owo69.me/
Some query parameters are available to change the functionality: - Click reload to get a different one. Delete left half of URL to get to source.
- Include pornographic results: https://rms.owo69.me/?allow_r18([=only](https://rms.owo69.me/?allow_r18=only))
- Get different sizes (original, regular, small, or thumb_mini): https://rms.owo69.me/?size=thumb_mini
- Auto-refresh using HTTP Refresh header: https://rms.owo69.me/?auto=3
- kek: https://rms.owo69.me/?allow_r18&size=thumb_mini&auto=0
- See your history: https://rms.owo69.me/log
- Load image by id without redirect thing: https://rms.owo69.me/img/51586149
- Load random image directly without redirect thing: https://rms.owo69.me/img/random
- Draw Pixiv URL onto upper left corner of image: https://rms.owo69.me/img/random?drawsource&size=regular
Here is an HTML site that makes use of it: https://lamp.tk/miku.html
| param | values | description | example | ### Prerequisites
|-------|--------|-------------|---------|
| `size` | `original`, `regular`, `small`, `thumb_mini` | Get a different image size. The default is `original`. | https://random-miku.owo39.me/?size=small |
| `noredirect` | | If used at `/`, server will respond the random image directly to that request instead of redirecting to a URL with the source URL in it (In this case the source id is only recoverable from `X-Pixiv-Id` header.). If used for the other, disables random redirection on reload. | https://random-miku.owo39.me/?noredirect, https://random-miku.owo39.me/https://www.pixiv.net/en/artworks/55814670?noredirect |
| `allow_r18` | | Enables random selection of pornographic illustrations. | https://random-miku.owo39.me/?allow_r18 |
- Node.js
- GraphicsMagick for ?drawsource option
For programatic purposes you can GET `/api` which responds just a random ID in plain text. ### todo
<hr> - Option to limit range to get more higher-ranked illustrations
here's an embedded example.
unfortunately there's no way to get source like this (browsers don't expose redirected urls of embedded resources).
![random miku image](https://random-miku.owo39.me/)
+91 -24
View File
@@ -1,29 +1,43 @@
var express = require("express"); var express = require("express");
var fetch = require("node-fetch"); var fetch = require("node-fetch");
var qs = require("qs");
var serveFavicon = require("serve-favicon");
var gm = require("gm");
var fs = require("fs");
var app = express(); var app = express();
app.set("trust proxy", "127.0.0.1"); app.set("trust proxy", "127.0.0.1");
app.listen(process.env.PORT || 39); app.listen(process.env.PORT || 39, process.env.ADDRESS);
app.use(serveFavicon("ミク.png"));
app.use((req,res,next)=>{req.rawQuery = req.url.includes('?') && req.url.substr(req.url.indexOf('?')+1);next();});
var list = require("./list.json"); var list = require("./list.json");
var list_r18_indices = [], list_safe_indices = [];
for (let i = 0, h = list.length; i < h; i++) if (list[i][2]) list_r18_indices.push(i); else list_safe_indices.push(i);
var ipa_lastload_map = {}; var ipa_lastload_map = {};
function getRandomId(allow_r18) { function getRandomId(allow_r18) {
let x = list[Math.floor(Math.random() * list.length)]; if (allow_r18?.toLowerCase() == "only") {
if (x[2] && !allow_r18) return getRandomId(); return list[list_r18_indices[Math.floor(Math.random() * list_r18_indices.length)]][0];
return x[0]; } else if (allow_r18 != null) {
return list[Math.floor(Math.random() * list.length)][0];
} else {
return list[list_safe_indices[Math.floor(Math.random() * list_safe_indices.length)]][0];
}
}; };
function redirectRandom(req, res) {
res.redirect(`/https://www.pixiv.net/en/artworks/${getRandomId(req.query.allow_r18!=null)}${req.url.includes('?')?req.url.substr(req.url.indexOf('?')):''}`); function getRandomUrl(req) {
var s = req?.params.settings ? `/${req?.params.settings}` : '';
var d = getRandomId(req?.query.allow_r18);
return `${s}/https://www.pixiv.net/en/artworks/${d}`;
} }
async function serveId(id, req, res, next) { async function serveId(id, req, res, next) {
try { try {
if (ipa_lastload_map[req.ip] == req.url && req.query.noredirect == null) console.log(new Date().toLocaleString(), req.ip, req.url);
return redirectRandom(req, res);
else ipa_lastload_map[req.ip] = req.url;
console.log(new Date().toLocaleString(), req.ip, id, Object.keys(req.query).length ? req.query : '', req.headers['referer'] || '');
let pages = list.find(x => x[0] == id)?.[1]; let pages = list.find(x => x[0] == id)?.[1];
if (!pages) { if (!pages) {
@@ -37,35 +51,88 @@ async function serveId(id, req, res, next) {
pages = data.body; pages = data.body;
} }
var url = pages[0].urls[req.query.size ?? "original"]; var size = req.query.size || "original";
var url = pages[0].urls[size];
if (!url) return res.status(400).type("text").send(`size must be one of the following: ${Object.keys(pages[0].urls).join(', ')}`); if (!url) return res.status(400).type("text").send(`size must be one of the following: ${Object.keys(pages[0].urls).join(', ')}`);
var pxreq = await fetch(url, { headers: {"Referer": "https://www.pixiv.net"} }); var pxreq = await fetch(url, { headers: {"Referer": "https://www.pixiv.net"} });
//if (pxreq.status != 200 && size == "original") {
// res.header("X-Using-Backup", '1');
// pxreq = await fetch(`https://39.hmbp.gq/https://www.pixiv.net/en/artworks/${id}?noredirect`);
//}
res.status(pxreq.status);
res.type(pxreq.headers.get("Content-Type")); res.type(pxreq.headers.get("Content-Type"));
res.header("Content-Disposition", `filename=${url.split('/').pop()}`);
res.header("X-Pixiv-Id", id); res.header("X-Pixiv-Id", id);
pxreq.body.pipe(res); if (req.query.auto) res.header("Refresh", `${Number(req.query.auto)}; url=${getRandomUrl(req)}`);
if (req.query.drawsource != null && pxreq.headers.get("Content-Type").startsWith("image")) {
gm(pxreq.body).drawText(2, 12, size == "thumb_mini" ? id : `https://www.pixiv.net/en/artworks/${id}`).stream().pipe(res);
}
else pxreq.body.pipe(res);
fs.appendFileSync(`logs/${req.ip.replace(/[:\/]/g, '-')}.csv`, `${new Date().toISOString()},${id}\n`);
} catch(error) { } catch(error) {
next(error); next(error);
} }
} }
app.get("/https://www.pixiv.net/en/artworks/:id", function (req, res, next) { // original HTML-less site for humans via web browser.
// - click refresh to get different image
// - delete left half of url to get to source
// - hacked querystring so it's before source url
app.get("(/:settings)?/https://www.pixiv.net/en/artworks/:id", function (req, res, next) {
if (req.rawQuery) {
let settings = req.params.settings || '';
if (settings) settings += "&";
settings += req.rawQuery;
return res.redirect(`/${settings}/https://www.pixiv.net/en/artworks/${req.params.id}`);
}
if (req.params.settings) req.query = qs.parse(req.params.settings);
if (ipa_lastload_map[req.ip] == req.url) return res.redirect(getRandomUrl(req));
else ipa_lastload_map[req.ip] = req.url;
serveId(req.params.id, req, res, next); serveId(req.params.id, req, res, next);
}); });
app.get('/', (req, res, next) => { // initial randir
if (req.query.noredirect != null) { app.get('/', (req, res) => {
serveId(getRandomId(req.query.allow_r18!=null), req, res, next) res.redirect((req.rawQuery ? `/${req.rawQuery}` : '') + getRandomUrl(req));
} else {
redirectRandom(req, res);
}
}); });
app.get("/favicon.ico", function (req, res) { // direct random image without redirects
res.sendFile(process.cwd() + "/ミク.png"); app.get("/img/random", (req, res, next) => {
serveId(getRandomId(req.query.allow_r18), req, res, next);
}); });
app.get("/api", function (req, res) { // simple serve id without redirects
res.type("text/plain").send(getRandomId(req.query.allow_r18!=null)); app.get("/img/:id", (req, res, next) => {
res.header("Cache-Control", "max-age=99999999999999");
serveId(req.params.id, req, res, next);
});
// plaintext random id(s) for scripts
app.get("/randomid", function (req, res) {
var count = Number(req.query.count) || 1;
count = Math.min(count, 100);
var ids = [];
for (let i = 0; i < count; i++) ids.push(getRandomId(req.query.allow_r18));
ids = ids.join(',');
res.type("text/plain").send(ids);
});
// log site
app.get("/log", function (req, res) {
res.redirect(`/log/${req.ip}`);
});
var log_html = fs.readFileSync("log.html", "utf8");
app.get("/log/:ipa", function (req, res) {
res.send(log_html);
});
app.get("/log/:ipa/csv", function (req, res) {
res.sendFile(req.params.ipa.replace(/[:\/]/g, '-') + '.csv', {root: process.cwd() + "/logs/"});
}); });
+34
View File
@@ -0,0 +1,34 @@
<title>history</title>
<style>
.i {
width: 128px;
height: 128px;
display: inline-block;
}
</style>
<h1>history for <span id="ipa">???</span></h1>
<p>in reverse-chronological order. hover for dates</p>
<script>
let ipa = location.pathname.split("/").pop().trim();
document.getElementById("ipa").innerText = ipa;
fetch(location.pathname + "/csv").then(r => r.text()).then(csv => {
csv = csv.trim();
csv = csv.split("\n").map(x => x.split(','));
var imgs = [];
for (let row of csv) {
let date = new Date(row[0]).toLocaleString();
let pixiv_id = row[1];
let pixiv_url = `https://www.pixiv.net/en/artworks/${pixiv_id}`;
let thumb_url = `/img/${pixiv_id}?size=thumb_mini`;
//imgs.unshift(`<a href="${pixiv_url}"><img src="${thumb_url}" alt="${pixiv_id}" title="${date}" /></a>`);
imgs.unshift(`<a href="${pixiv_url}"><div class="i" style="background-image: url(${thumb_url})" title="${date}">${pixiv_id}</div></a>`);
}
document.body.innerHTML += imgs.join('');
});
</script>
+630 -253
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -1,6 +1,8 @@
{ {
"dependencies": { "dependencies": {
"express": "^4.17.1", "express": "^4.17.1",
"node-fetch": "^2.6.5" "gm": "^1.23.1",
"node-fetch": "^2.6.5",
"serve-favicon": "^2.5.0"
} }
} }