Compare commits

..

4 Commits

Author SHA1 Message Date
lamp fad66e6945 handle payload error 2024-05-20 14:14:55 -07:00
lamp e3f39e37a1 add warnings 2024-05-20 14:06:46 -07:00
lamp d2ec6b2861 support mobile site 2024-05-15 15:22:43 -07:00
lamp 071165c13e commit 2024-05-14 23:24:35 -07:00
5 changed files with 170 additions and 113 deletions
+2
View File
@@ -0,0 +1,2 @@
credentials.json
past_bookmarks.json
Vendored Executable
+4
View File
@@ -0,0 +1,4 @@
{
"deno.enable": true,
"deno.lint": false
}
+111 -84
View File
@@ -1,113 +1,140 @@
import ky from 'https://esm.sh/ky';
import credentials from "./credentials.json" with { type: "json" }; import credentials from "./credentials.json" with { type: "json" };
var {matrix_token, pixiv_cookie, pixiv_user_id} = credentials; var {client_id, client_secret, username, password, pixiv_cookie} = credentials;
var ke = ky.create({ var access_token;
hooks: {
beforeRequest: [request => console.log(`${request.method} ${request.url}`)],
afterResponse: [(_request, _options, response) => console.log(response.status)]
},
retry: {
limit: 100,
delay: attemptCount => (2 ** (attemptCount - 1)) * 1000
},
timeout: false
});
await (async function login() {
var form = new FormData();
form.append("client_id", client_id);
form.append("client_secret", client_secret);
form.append("grant_type", "password");
form.append("username", username);
form.append("password", password);
var data = await fetch("https://pleroma.lamp.wtf/oauth/token", {
method: "POST",
body: form
}).then(res => res.json());
console.log ("logged in", data);
access_token = data.access_token;
})();
var matrix = { async function uploadFile({data, name}) {
ky: ke.extend({headers: {"Authorization": `Bearer ${credentials.matrix_token}`}}), var form = new FormData();
rooms: { form.append("file", data, name);
default: "!mxhaBcBiEmnGxrffll:matrix.org", var res = await fetch("https://pleroma.lamp.wtf/api/v1/media", {
pixiv_sfw: "!zStOGJAGxEaQgwxGYI:matrix.org", method: "POST",
pixiv_nsfw: "!HtXDHeAhEKBFGfAJTi:matrix.org" body: form,
}, headers: {"Authorization": `Bearer ${access_token}`}
async sendMessage({room = this.rooms.default, type = "m.text", body, filename, info, url}) { });
return await this.ky.put(`https://matrix-client.matrix.org/_matrix/client/v3/rooms/${encodeURIComponent(room)}/send/m.room.message/${Math.random().toString()}`, { var json = await res.json();
json: {msgtype: type, body, filename, info, url} console.log("uploaded file", res.status, json.url);
}).json(); return json;
},
async uploadFile(filename, data) {
var {content_uri} = await this.ky.post(`https://matrix-client.matrix.org/_matrix/media/v3/upload?filename=${encodeURIComponent(filename)}`, {body: data}).json();
return content_uri;
},
async sendImage({room = this.rooms.default, body, filename, data, info}) {
var content_uri = await this.uploadFile(filename, data);
return await this.sendMessage({room, type: "m.image", body: body || filename, filename, url: content_uri, info});
}
} }
async function postStatus({status, visibility = "unlisted", content_type = "text/plain", media_ids = [], sensitive, files}) {
if (files) {
media_ids = (await Promise.all(files.map(file => uploadFile(file)))).map(d => d.id);
}
var form = new FormData();
form.append("status", status);
form.append("visibility", visibility);
form.append("source", "bot");
form.append("content_type", content_type);
for (let media_id of media_ids) {
form.append("media_ids[]", media_id);
}
if (sensitive) form.append("sensitive", "true");
var res = await fetch("https://pleroma.lamp.wtf/api/v1/statuses", {
method: "POST",
body: form,
headers: {"Authorization": `Bearer ${access_token}`}
});
var json = await res.json();
console.log("posted", res.status, json.uri || json);
return json;
}
async function downloadPixivIllust(illust_id) { async function downloadPixivIllust(illust_id) {
var html = await ke.get(`https://www.pixiv.net/en/artworks/${illust_id}`, {headers: {"Cookie": credentials.pixiv_cookie}}).text(); var url = `https://www.pixiv.net/en/artworks/${illust_id}`;
console.log("fetch", url);
var html = await fetch(url, {headers: {"Cookie": pixiv_cookie}}).then(res => res.text());
var illust = Object.values(JSON.parse(html.match(/<meta name="preload-data" id="meta-preload-data" content='(.*)'>/)[1]).illust)[0]; var illust = Object.values(JSON.parse(html.match(/<meta name="preload-data" id="meta-preload-data" content='(.*)'>/)[1]).illust)[0];
var images = []; var images = [];
for (let i = 0; i < illust.pageCount; i++) { for (let i = 0; i < illust.pageCount; i++) {
let url = illust.urls.original.replace('p0', 'p'+i); let url = illust.urls.original.replace('p0', 'p'+i);
let data = await ke.get(url, {headers: {"Referer": "https://www.pixiv.net/"}}).then(res => res.blob()); console.log("fetch", url);
let data = await fetch(url, {headers: {"Referer": "https://www.pixiv.net/"}}).then(res => res.blob());
images.push({url, name: url.split('/').pop(), data}); images.push({url, name: url.split('/').pop(), data});
}; };
return {illust, images}; return {illust, images};
} }
export async function pixivToMatrix(illust_id) { export async function pixivToPleroma(illust_id) {
try { try {
var {illust, images} = await downloadPixivIllust(illust_id); var {illust, images} = await downloadPixivIllust(illust_id);
var room = illust.xRestrict ? matrix.rooms.pixiv_nsfw : matrix.rooms.pixiv_sfw; await postStatus({
await matrix.sendMessage({room, body: `https://www.pixiv.net/en/artworks/${illust_id}`}); status: `https://www.pixiv.net/en/artworks/${illust_id}`
for (var image of images) { + ((images.length > 4) ? '\n⚠ >4 img' : '')
try { + ((illust.illustType == 2) ? '\n⚠ ugoira conversion not implemented' : ''),
await matrix.sendImage({ files: images,
room, visibility: "unlisted",
filename: image.name, sensitive: Boolean(illust.xRestrict)
data: image.data, });
info: {
mimetype: image.data.type,
size: image.data.size
}
});
} catch (error) {
onError(error);
}
}
} catch (error) { } catch (error) {
onError(error);
}
function onError(error) {
console.error(error.stack); console.error(error.stack);
matrix.sendMessage({room: room || matrix.rooms.pixiv_sfw, body: error.stack}).catch(error => { postStatus({
console.error(error.stack); status: `https://www.pixiv.net/en/artworks/${illust_id}` +
`\n#error:\n${error.stack}`
}); });
} }
} }
if (import.meta.main) Deno.serve({
port: 18024,
hostname: "127.0.0.1"
}, async (req, info) => {
var {pathname} = new URL(req.url);
console.log(info.remoteAddr.hostname, req.headers.get('x-forwarded-for'), pathname);
try {
var new_ids = []; switch (pathname) {
top: for (var offset = 0;;) { case "/ajax/illusts/bookmarks/add":
let url = `https://www.pixiv.net/ajax/user/${pixiv_user_id}/illusts/bookmarks?tag=&offset=${offset}&limit=100&rest=show&lang=en&version=5dc84ab282403a049abea4e2f2214b6a69d31da6`; var payload = await req.clone().json();
console.log("get", url); console.log(payload);
let data = await fetch(url, {headers: {Cookie: pixiv_cookie}}).then(res => res.json()); var {comment, illust_id, restrict, tags} = payload;
let ids = data.body.works.map(x => x.id); pixivToPleroma(illust_id);
if (!ids.length) break; break;
for (let id of ids) { case "/ajax/illusts/bookmarks/delete":
if (["119320087", "119534122"].includes(id)) break top; var payload = await req.clone().formData();
new_ids.push(id); console.log(payload);
// todo
break;
case "/touch/ajax_api/ajax_api.php":
var payload = await req.clone().formData();
console.log(payload);
var mode = payload.get("mode");
if (mode == "add_bookmark_illust") {
var restrict = payload.get("restrict");
var tag = payload.get("tag");
var id = payload.get("id");
var comment = payload.get("comment");
pixivToPleroma(id);
} else if (mode == "delete_bookmark_illust") {
var id = payload.get("id");
// todo
}
break;
}
} catch (error) {
console.error("payload error:", error.stack);
} }
offset += ids.length;
}
console.log("new ids", new_ids); return fetch("https://www.pixiv.net"+pathname, {
method: req.method,
for (let id of new_ids.reverse()) { headers: req.headers,
await pixivToMatrix(id); body: req.body,
} redirect: "manual"
});
});
+18
View File
@@ -0,0 +1,18 @@
import credentials from "./credentials.json" with { type: "json" };
var {pixiv_cookie, pixiv_user_id} = credentials;
var all_ids = [];
var offset = 0;
while (true) {
let url = `https://www.pixiv.net/ajax/user/${pixiv_user_id}/illusts/bookmarks?tag=&offset=${offset}&limit=100&rest=show&lang=en&version=5dc84ab282403a049abea4e2f2214b6a69d31da6`;
console.log("get", url);
let data = await fetch(url, {headers: {Cookie: pixiv_cookie}}).then(res => res.json());
let ids = data.body.works.map(x => x.id);
if (!ids.length) break;
for (let id of ids) {
all_ids.push(id);
}
offset += ids.length;
}
Deno.writeTextFileSync("past_bookmarks.json", JSON.stringify(all_ids));
+6
View File
@@ -0,0 +1,6 @@
import past_bookmarks from "./past_bookmarks.json" with { type: "json" };
import { pixivToPleroma } from "./app.deno.js";
for (let id of past_bookmarks.reverse()) {
await pixivToPleroma(id);
}