250 lines
7.1 KiB
JavaScript
250 lines
7.1 KiB
JavaScript
import { iterateAtpRepo } from "@atcute/car";
|
|
import * as fs from "fs";
|
|
|
|
var did = "did:plc:u4gngygg2w5egsigxu5g7byu";
|
|
var pds = "https://pds.owo69.me";
|
|
var identifier = "lamp.bsky.social";
|
|
var password = "";
|
|
|
|
|
|
async function fetch(url, options) {
|
|
console.debug("fetch", url);
|
|
var res = await global.fetch(url, options);
|
|
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText} ${await res.text()}`);
|
|
return res;
|
|
}
|
|
|
|
|
|
//try {
|
|
//var repo = fs.readFileSync("repo");
|
|
//} catch (e) {
|
|
var repo = await fetch(`${pds}/xrpc/com.atproto.sync.getRepo?did=${did}`).then(res => res.arrayBuffer());
|
|
repo = new Uint8Array(repo);
|
|
fs.writeFileSync("repo", repo);
|
|
//}
|
|
|
|
var [likes, posts, reposts] = [[],[],[]];
|
|
|
|
for (let {collection, rkey, record} of iterateAtpRepo(repo)) {
|
|
switch (collection) {
|
|
case "app.bsky.feed.like":
|
|
likes.push([rkey,record]);
|
|
break;
|
|
case "app.bsky.feed.post":
|
|
posts.push([rkey,record]);
|
|
break;
|
|
case "app.bsky.feed.repost":
|
|
reposts.push([rkey,record]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
console.log(`repo: ${likes.length} likes ${posts.length} posts ${reposts.length} reposts`);
|
|
|
|
|
|
|
|
var res = await fetch(pds+"/xrpc/com.atproto.server.createSession", {
|
|
method: "POST",
|
|
headers: {"Content-Type": "application/json"},
|
|
body: JSON.stringify({identifier, password})
|
|
});
|
|
var {accessJwt} = await res.json();
|
|
console.log(accessJwt);
|
|
|
|
|
|
|
|
console.log("getting likes");
|
|
|
|
var applikes = [];
|
|
var cursor = undefined;
|
|
do {
|
|
let res = await fetch(`${pds}/xrpc/app.bsky.feed.getActorLikes?actor=${did}&limit=100${cursor?`&cursor=${cursor}`:''}`, {
|
|
headers: {"Authorization": `Bearer ${accessJwt}`}
|
|
});
|
|
let j = await res.json();
|
|
for (let post of j.feed) {
|
|
//fs.appendFileSync("likes.txt", JSON.stringify(post) + ",\n");
|
|
applikes.push(post.post.viewer.like);
|
|
}
|
|
if (cursor == j.cursor) break;
|
|
cursor = j.cursor;
|
|
} while (cursor);
|
|
|
|
|
|
|
|
|
|
/*var appposts = [];
|
|
var posturis = posts.map(([rkey]) => `at://${did}/app.bsky.feed.post/${rkey}`);
|
|
for (let i = 0; i < posturis.length; i += 25) {
|
|
let s = posturis.slice(i, i + 25);
|
|
let q = posturis.map(u => `uris=${encodeURIComponent(u)}`).join('&');
|
|
let res = await fetch(`${pds}/xrpc/app.bsky.feed.getPosts?${q}`, {
|
|
headers: {"Authorization": `Bearer ${accessJwt}`}
|
|
});
|
|
console.log(res.status);
|
|
let j = await res.json();
|
|
for (let post of j.posts) {
|
|
appposts.push(post.uri);
|
|
fs.appendFileSync("posts.txt", JSON.stringify(post) + ",\n");
|
|
}
|
|
}*/
|
|
|
|
|
|
console.log("getting posts");
|
|
|
|
var appposts = [];
|
|
var appreposts = [];
|
|
var cursor = undefined;
|
|
do {
|
|
// posts_with_replies gets everything??
|
|
let res = await fetch(`${pds}/xrpc/app.bsky.feed.getAuthorFeed?actor=${did}&limit=100&filter=posts_with_replies${cursor?`&cursor=${cursor}`:''}`, {
|
|
headers: {"Authorization": `Bearer ${accessJwt}`}
|
|
});
|
|
let j = await res.json();
|
|
for (let post of j.feed) {
|
|
let isRepost = post.reason?.$type == "app.bsky.feed.defs#reasonRepost";
|
|
if (isRepost) {
|
|
//fs.appendFileSync("reposts.txt", JSON.stringify(post) + ",\n");
|
|
appreposts.push(post.post.viewer.repost);
|
|
} else {
|
|
//fs.appendFileSync("posts.txt", JSON.stringify(post) + ",\n");
|
|
appposts.push(post.post.uri);
|
|
}
|
|
}
|
|
if (cursor == j.cursor) break;
|
|
cursor = j.cursor;
|
|
} while (cursor);
|
|
|
|
console.log(`app: ${applikes.length} likes, ${appposts.length} posts, ${appreposts.length} reposts`);
|
|
|
|
|
|
var applikes = applikes.map(x => x.split('/').at(-1));
|
|
var appposts = appposts.map(x => x.split('/').at(-1));
|
|
var appreposts = appreposts.map(x => x.split('/').at(-1));
|
|
|
|
var missing = {likes: [], posts: [], reposts: []};
|
|
|
|
|
|
for (let [rkey, record] of likes) {
|
|
if (!applikes.includes(rkey)) {
|
|
missing.likes.push([rkey, record]);
|
|
}
|
|
}
|
|
for (let [rkey, record] of posts) {
|
|
if (!appposts.includes(rkey)) {
|
|
missing.posts.push([rkey, record]);
|
|
}
|
|
}
|
|
for (let [rkey, record] of reposts) {
|
|
if (!appreposts.includes(rkey)) {
|
|
missing.reposts.push([rkey, record]);
|
|
}
|
|
}
|
|
|
|
console.log(`There are ${missing.likes.length} missing likes, ${missing.posts.length} missing posts, ${missing.reposts.length} missing reposts`);
|
|
|
|
|
|
let missing_post_references = [...missing.likes, ...missing.reposts].filter(([rkey, record]) => record.subject.uri.includes("app.bsky.feed.post"));
|
|
let referenced_posts_that_still_exist = [];
|
|
|
|
for (let i = 0; i < missing_post_references.length; i += 25) {
|
|
let uris = missing_post_references.slice(i, i + 25).map(x => x[1].subject.uri);
|
|
let q = uris.map(u => `uris=${encodeURIComponent(u)}`).join('&');
|
|
let res = await fetch(`${pds}/xrpc/app.bsky.feed.getPosts?${q}`, {
|
|
headers: {"Authorization": `Bearer ${accessJwt}`}
|
|
});
|
|
let j = await res.json();
|
|
console.debug(j.posts);
|
|
referenced_posts_that_still_exist.push(...j.posts.map(p => p.uri));
|
|
}
|
|
|
|
missing.likes = missing.likes.filter(([rkey, record]) => referenced_posts_that_still_exist.includes(record.subject.uri));
|
|
missing.reposts = missing.reposts.filter(([rkey, record]) => referenced_posts_that_still_exist.includes(record.subject.uri));
|
|
|
|
console.log(`${missing.likes.length} missing liked posts still exist, ${missing.reposts.length} missing reposts still exist`);
|
|
|
|
fs.writeFileSync("missing.json", JSON.stringify(missing));
|
|
|
|
|
|
var writes = [];
|
|
for (let [records, collection] of [[missing.likes, "app.bsky.feed.like"], [missing.posts, "app.bsky.feed.post"], [missing.reposts, "app.bsky.feed.repost"]]) {
|
|
for (let [rkey, record] of records) {
|
|
writes.push({
|
|
collection,
|
|
rkey,
|
|
action: "delete",
|
|
$type: "com.atproto.repo.applyWrites#delete"
|
|
});
|
|
writes.push({
|
|
collection,
|
|
rkey,
|
|
action: "create",
|
|
$type: "com.atproto.repo.applyWrites#create",
|
|
value: record
|
|
});
|
|
}
|
|
}
|
|
|
|
let allresults = [];
|
|
for (let i = 0; i < writes.length; i += 100) {
|
|
let subwrites = writes.slice(i, i + 100);
|
|
let res = await fetch(`${pds}/xrpc/com.atproto.repo.applyWrites`, {
|
|
method: "POST",
|
|
headers: {"Authorization": `Bearer ${accessJwt}`, "Content-Type": "application/json"},
|
|
body: JSON.stringify({
|
|
repo: did,
|
|
writes: subwrites,
|
|
validate: true
|
|
})
|
|
});
|
|
console.log(res.status);
|
|
let {results} = await res.json();
|
|
allresults.push(...results);
|
|
}
|
|
|
|
fs.writeFileSync("allresults.json", JSON.stringify(allresults));
|
|
|
|
|
|
|
|
// wont show in appview idk how generate proper rkey but it's not important
|
|
/*var x = 0;
|
|
var writes = [];
|
|
for (let {$type, uri, cid} of allresults) {
|
|
if ($type == "com.atproto.repo.applyWrites#createResult" && uri.includes("app.bsky.feed.post")) {
|
|
writes.push({
|
|
collection: "app.bsky.feed.post",
|
|
rkey: `aaaaa${x++}`,
|
|
action: "create",
|
|
$type: "com.atproto.repo.applyWrites#create",
|
|
value: {
|
|
$type: "app.bsky.feed.post",
|
|
createdAt: new Date().toISOString(),
|
|
langs: ["en"],
|
|
embed: {
|
|
$type: "app.bsky.embed.record",
|
|
record: {
|
|
uri,
|
|
cid
|
|
}
|
|
},
|
|
text: "post missing from appview restored with script"
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < writes.length; i += 100) {
|
|
let subwrites = writes.slice(i, i + 100);
|
|
let res = await fetch(`${pds}/xrpc/com.atproto.repo.applyWrites`, {
|
|
method: "POST",
|
|
headers: {"Authorization": `Bearer ${accessJwt}`, "Content-Type": "application/json"},
|
|
body: JSON.stringify({
|
|
repo: did,
|
|
writes: subwrites,
|
|
validate: true
|
|
})
|
|
});
|
|
console.log(res.status, await res.text());
|
|
}*/
|
|
|
|
debugger; |