Compare commits
29 Commits
1b616bb6d9
...
proxy
| Author | SHA1 | Date | |
|---|---|---|---|
| 881ee4568d | |||
| 7ac32d6dff | |||
| 175a86b490 | |||
| 8f1c789c8e | |||
| c4d55ec6c7 | |||
| 3ab1623bed | |||
| 88a6e5e692 | |||
| 99f05ea2e0 | |||
| 3ef1d4bdcb | |||
| 091197e7c7 | |||
| 63a9916a03 | |||
| 0219cc7f83 | |||
| 47a05b243f | |||
| 93017002b9 | |||
| f5e734a9c9 | |||
| 42566713cf | |||
| 9d8d5c078e | |||
| 77221513b5 | |||
| 9ecdae240b | |||
| 8fac3fedcc | |||
| 04cbf250b0 | |||
| ebb2071a12 | |||
| c018ca12de | |||
| 66ab01429a | |||
| 9fee2a7852 | |||
| 4c8ee7b20a | |||
| a75c37731f | |||
| ebf6a8ffc4 | |||
| 6ed02a4740 |
@@ -1,3 +1,4 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
output.log
|
output.log
|
||||||
|
logs
|
||||||
@@ -1,19 +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.
|
A simple no-HTML random Hatsune Miku image server. Example: https://rms.owo69.me/
|
||||||
|
|
||||||
Your address and last requested URL are remembered so that when you click reload in your browser, you're redirected to a different one. You can add `?noredirect` query param to disable this.
|
- 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
|
||||||
|
|
||||||
You can add the `size` query parameter with one of `original`, `regular`, `small`, or `thumb_mini` (or whatever pixiv api has) to get a different size. The default is `original`.
|
Here is an HTML site that makes use of it: https://lamp.tk/miku.html
|
||||||
|
|
||||||
For programatic purposes you can GET `/api` which responds just a random ID in plain text.
|
### Prerequisites
|
||||||
|
|
||||||
<hr>
|
- Node.js
|
||||||
|
- GraphicsMagick for ?drawsource option
|
||||||
|
|
||||||
The original version served already-downloaded images from a MongoDB database, containing ~90,000 of the top 初音ミク illustrations on pixiv, but the system went down so now it only has the list of ids from said database and it proxies the images from pixiv. (might revert later when I get back and resurrect said system...)
|
### 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).
|
|
||||||
|
|
||||||

|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,29 +1,47 @@
|
|||||||
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, 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 idlist = require("./idlist.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 = {};
|
||||||
var page_cache = {};
|
|
||||||
|
|
||||||
let randomId = () => idlist[Math.floor(Math.random() * idlist.length)];
|
|
||||||
let redirectRandom = (req, res) => res.redirect(`/https://www.pixiv.net/en/artworks/${randomId()}`);
|
|
||||||
|
|
||||||
app.get('/', redirectRandom);
|
function getRandomId(allow_r18) {
|
||||||
app.get("/favicon.ico", (req, res) => res.sendFile(process.cwd() + "/ミク.png"));
|
if (allow_r18?.toLowerCase() == "only") {
|
||||||
app.get("/api", (req, res) => res.type("text/plain").send(randomId()));
|
return list[list_r18_indices[Math.floor(Math.random() * list_r18_indices.length)]][0];
|
||||||
app.get("/https://www.pixiv.net/en/artworks/:id", async function (req, res, next) {
|
} 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 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) {
|
||||||
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, req.params.id, req.query);
|
let pages = list.find(x => x[0] == id)?.[1];
|
||||||
|
|
||||||
let pages = page_cache[req.params.id];
|
|
||||||
if (!pages) {
|
if (!pages) {
|
||||||
let data = await (await fetch(`https://pixiv.net/ajax/illust/${req.params.id}/pages`, {
|
let data = await (await fetch(`https://pixiv.net/ajax/illust/${id}/pages`, {
|
||||||
headers: { "Host": "www.pixiv.net" }
|
headers: { "Host": "www.pixiv.net" }
|
||||||
})).json();
|
})).json();
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
@@ -31,21 +49,90 @@ app.get("/https://www.pixiv.net/en/artworks/:id", async function (req, res, next
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pages = data.body;
|
pages = data.body;
|
||||||
page_cache[req.params.id] = pages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(', ')}`);
|
||||||
|
|
||||||
res.type(url.split('.').pop());
|
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`);
|
||||||
|
//}
|
||||||
|
|
||||||
(await fetch(url, {
|
res.status(pxreq.status);
|
||||||
headers: {"Referer": "https://www.pixiv.net"}
|
res.type(pxreq.headers.get("Content-Type"));
|
||||||
})).body.pipe(res);
|
res.header("Content-Disposition", `filename=${url.split('/').pop()}`);
|
||||||
|
res.header("X-Pixiv-Id", id);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(8039);
|
// initial randir
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.redirect((req.rawQuery ? `/${req.rawQuery}` : '') + getRandomUrl(req));
|
||||||
|
});
|
||||||
|
|
||||||
|
// direct random image without redirects
|
||||||
|
app.get("/img/random", (req, res, next) => {
|
||||||
|
serveId(getRandomId(req.query.allow_r18), req, res, next);
|
||||||
|
});
|
||||||
|
|
||||||
|
// simple serve id without redirects
|
||||||
|
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/"});
|
||||||
|
});
|
||||||
|
|||||||
@@ -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>
|
||||||
Generated
+630
-253
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user