+1
.gitignore
+1
.gitignore
···
1
+
.env
+23
.vscode/settings.json
+23
.vscode/settings.json
···
1
+
{
2
+
"workbench.colorCustomizations": {
3
+
"activityBar.activeBackground": "#08beda",
4
+
"activityBar.background": "#08beda",
5
+
"activityBar.foreground": "#15202b",
6
+
"activityBar.inactiveForeground": "#15202b99",
7
+
"activityBarBadge.background": "#d708bc",
8
+
"activityBarBadge.foreground": "#e7e7e7",
9
+
"commandCenter.border": "#e7e7e799",
10
+
"sash.hoverBorder": "#08beda",
11
+
"statusBar.background": "#0693a9",
12
+
"statusBar.foreground": "#e7e7e7",
13
+
"statusBarItem.hoverBackground": "#08beda",
14
+
"statusBarItem.remoteBackground": "#0693a9",
15
+
"statusBarItem.remoteForeground": "#e7e7e7",
16
+
"titleBar.activeBackground": "#0693a9",
17
+
"titleBar.activeForeground": "#e7e7e7",
18
+
"titleBar.inactiveBackground": "#0693a999",
19
+
"titleBar.inactiveForeground": "#e7e7e799"
20
+
},
21
+
"peacock.color": "#0693a9",
22
+
"deno.enable": true
23
+
}
+3
README.md
+3
README.md
+20
appeals.ts
+20
appeals.ts
···
1
+
import { AtpAgent } from "@atproto/api";
2
+
export const getAllAppeals = async (agent: AtpAgent) => {
3
+
let appeals: any[] = []; // Y U NO LET ME IMPORT TYPEDEF DENO????
4
+
let cursor;
5
+
do {
6
+
const { data } = await agent.tools.ozone.moderation.queryStatuses({
7
+
limit: 100,
8
+
includeMuted: false,
9
+
appealed: true,
10
+
sortField: "lastReportedAt",
11
+
sortDirection: "desc",
12
+
cursor,
13
+
});
14
+
if (!data.subjectStatuses.length) break;
15
+
cursor = data.cursor;
16
+
appeals = appeals.concat(data.subjectStatuses);
17
+
} while (cursor);
18
+
19
+
return appeals;
20
+
};
+11
deno.json
+11
deno.json
+156
deno.lock
+156
deno.lock
···
1
+
{
2
+
"version": "5",
3
+
"specifiers": {
4
+
"jsr:@std/assert@1": "1.0.15",
5
+
"jsr:@std/cli@^1.0.23": "1.0.23",
6
+
"jsr:@std/dotenv@~0.225.5": "0.225.5",
7
+
"jsr:@std/internal@^1.0.12": "1.0.12",
8
+
"npm:@atproto/api@~0.17.3": "0.17.3"
9
+
},
10
+
"jsr": {
11
+
"@std/assert@1.0.15": {
12
+
"integrity": "d64018e951dbdfab9777335ecdb000c0b4e3df036984083be219ce5941e4703b",
13
+
"dependencies": [
14
+
"jsr:@std/internal"
15
+
]
16
+
},
17
+
"@std/cli@1.0.23": {
18
+
"integrity": "bf95b7a9425ba2af1ae5a6359daf58c508f2decf711a76ed2993cd352498ccca",
19
+
"dependencies": [
20
+
"jsr:@std/internal"
21
+
]
22
+
},
23
+
"@std/dotenv@0.225.5": {
24
+
"integrity": "9ce6f9d0ec3311f74a32535aa1b8c62ed88b1ab91b7f0815797d77a6f60c922f"
25
+
},
26
+
"@std/internal@1.0.12": {
27
+
"integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027"
28
+
}
29
+
},
30
+
"npm": {
31
+
"@atproto/api@0.17.3": {
32
+
"integrity": "sha512-pdQXhUAapNPdmN00W0vX5ta/aMkHqfgBHATt20X02XwxQpY2AnrPm2Iog4FyjsZqoHooAtCNV/NWJ4xfddJzsg==",
33
+
"dependencies": [
34
+
"@atproto/common-web",
35
+
"@atproto/lexicon",
36
+
"@atproto/syntax",
37
+
"@atproto/xrpc",
38
+
"await-lock",
39
+
"multiformats",
40
+
"tlds",
41
+
"zod"
42
+
]
43
+
},
44
+
"@atproto/common-web@0.4.3": {
45
+
"integrity": "sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg==",
46
+
"dependencies": [
47
+
"graphemer",
48
+
"multiformats",
49
+
"uint8arrays",
50
+
"zod"
51
+
]
52
+
},
53
+
"@atproto/lexicon@0.5.1": {
54
+
"integrity": "sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==",
55
+
"dependencies": [
56
+
"@atproto/common-web",
57
+
"@atproto/syntax",
58
+
"iso-datestring-validator",
59
+
"multiformats",
60
+
"zod"
61
+
]
62
+
},
63
+
"@atproto/syntax@0.4.1": {
64
+
"integrity": "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw=="
65
+
},
66
+
"@atproto/xrpc@0.7.5": {
67
+
"integrity": "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA==",
68
+
"dependencies": [
69
+
"@atproto/lexicon",
70
+
"zod"
71
+
]
72
+
},
73
+
"await-lock@2.2.2": {
74
+
"integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="
75
+
},
76
+
"graphemer@1.4.0": {
77
+
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="
78
+
},
79
+
"iso-datestring-validator@2.2.2": {
80
+
"integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA=="
81
+
},
82
+
"multiformats@9.9.0": {
83
+
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="
84
+
},
85
+
"tlds@1.260.0": {
86
+
"integrity": "sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ==",
87
+
"bin": true
88
+
},
89
+
"uint8arrays@3.0.0": {
90
+
"integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==",
91
+
"dependencies": [
92
+
"multiformats"
93
+
]
94
+
},
95
+
"zod@3.25.76": {
96
+
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="
97
+
}
98
+
},
99
+
"remote": {
100
+
"https://deno.land/x/crayon@3.3.3/mod.ts": "82ad225583a483c4837577971629cddaa22614093af8353da6426b9366de9780",
101
+
"https://deno.land/x/crayon@3.3.3/src/conversions.ts": "9bfd3b1fbe412bcba092890ac558b6beaad4c3aa399cd99d45fadb324d28afd6",
102
+
"https://deno.land/x/crayon@3.3.3/src/crayon.ts": "6b237baa08a31c903436e040afd2228a7fffaa5d11dddc58e3c402f79b3c1d04",
103
+
"https://deno.land/x/crayon@3.3.3/src/styles.ts": "aa588b57b2c0482dc5c6f53109b4287831a9827c0aeef9a88129beae1172c1ee",
104
+
"https://deno.land/x/crayon@3.3.3/src/util.ts": "af8884a917488de76ac0c2b92482093ade74514ece77a4c64e5eb5b0f6ed68e6",
105
+
"https://deno.land/x/tui@2.1.11/mod.ts": "b32347385f2efc7dd90a9e5f6386fded9bde505e3f1c4b07b8509c77206d15a6",
106
+
"https://deno.land/x/tui@2.1.11/src/canvas/box.ts": "3f6a41af65942b069795d895c2a73d039a83ba35c01b5236ea88d1de65ba3ebf",
107
+
"https://deno.land/x/tui@2.1.11/src/canvas/canvas.ts": "31daa080882956f19f5bf8a6b52f7a946ebc34bdba103b007ce4e73c2b922409",
108
+
"https://deno.land/x/tui@2.1.11/src/canvas/draw_object.ts": "2b8a48f10c343aee61d9dc7f00ea7917119ea41374a994e1db7b5b1ee188f0f8",
109
+
"https://deno.land/x/tui@2.1.11/src/canvas/mod.ts": "9da429bfb1d4f53eed661c3e2a2ae4b610380526597aa5f35a6604b810a83ac7",
110
+
"https://deno.land/x/tui@2.1.11/src/canvas/text.ts": "e6c0f5ecb985a037e55397810bc212bae206240acd3e2b15fb786ae2746abdea",
111
+
"https://deno.land/x/tui@2.1.11/src/component.ts": "d7a35cd1a4bc8a6177b047595c86e1df3418b340701e343ee83a08ac7a8005de",
112
+
"https://deno.land/x/tui@2.1.11/src/controls.ts": "e0e91f61a8a73fb044ce980fd3d070407c2f950635cbce73d97f060ef19a780e",
113
+
"https://deno.land/x/tui@2.1.11/src/event_emitter.ts": "e4ee1de2037c89952c5c4c54dc336b7992024f0cb41c9e49229944e773386824",
114
+
"https://deno.land/x/tui@2.1.11/src/input.ts": "4ddc4049718847b2f76c2d022b740694ed50f958c2c42bb3a2eacfe0b0d83b0d",
115
+
"https://deno.land/x/tui@2.1.11/src/input_reader/decoders/keyboard.ts": "70d4f54605a650612601e654bc28a5d4260374a893e27b8a86fe7181cb626377",
116
+
"https://deno.land/x/tui@2.1.11/src/input_reader/decoders/mouse.ts": "a119c6261a27fb9b5e1711ba3d5161c45eac5615ea0aa739e4e6bca759434e6e",
117
+
"https://deno.land/x/tui@2.1.11/src/input_reader/mod.ts": "4213a920c69fd51badd1091fe7c61eff1bd1ead32659785c16f976ae377491cc",
118
+
"https://deno.land/x/tui@2.1.11/src/input_reader/types.ts": "c940a6d656b2fbdc051c2e0508f8eeefa322dd16e60fc6a3bac8d1e9337f7d6c",
119
+
"https://deno.land/x/tui@2.1.11/src/layout/errors.ts": "3df98a8f7747657fd252f602b26e9b5ee130dbfb236bcb4b2d2c912d7ae1eef9",
120
+
"https://deno.land/x/tui@2.1.11/src/layout/grid_layout.ts": "7b2fca94d1a074c61d838c36800dca47f518f720c6539a33d0ad674081a29a76",
121
+
"https://deno.land/x/tui@2.1.11/src/layout/horizontal_layout.ts": "e2ea27519c44c124cb228f19d4b14aa314e7db2cc92ef83fccfa146ced29d4e4",
122
+
"https://deno.land/x/tui@2.1.11/src/layout/mod.ts": "65381a8dd7e8f6287742ebeffef866ae98932d16daf3ea3325f0180b37e327b8",
123
+
"https://deno.land/x/tui@2.1.11/src/layout/types.ts": "ebc78ef4adbf802a49f5319474d81183a2b9edc2947443d9f40f23c4730e16f3",
124
+
"https://deno.land/x/tui@2.1.11/src/layout/vertical_layout.ts": "41f1ec4b897a0f45478b6392f0c74d0c010a74693b99f36f532c85d5525dfca0",
125
+
"https://deno.land/x/tui@2.1.11/src/signals/computed.ts": "824428cfda7c9e4a6aed8caee32a9aa62cd257fac9e7ca64d54c99a15ea56019",
126
+
"https://deno.land/x/tui@2.1.11/src/signals/dependency_tracking.ts": "b89e933a912e8c32881e13ba1555201ec22cc0be69600862ff824f72f1bd6d55",
127
+
"https://deno.land/x/tui@2.1.11/src/signals/effect.ts": "b478ca6469a151e93970679108e01a786b6e121023294d15b7293476161ec049",
128
+
"https://deno.land/x/tui@2.1.11/src/signals/flusher.ts": "b47eeca9547a39487bef56ab82272f050883474995d5e92191296aec936180cb",
129
+
"https://deno.land/x/tui@2.1.11/src/signals/lazy_computed.ts": "b4653efd855ce920657510b4cd086c58a8c72be6511465e3234f4e0b134bb9c6",
130
+
"https://deno.land/x/tui@2.1.11/src/signals/lazy_effect.ts": "b8bdebf29d4b5ae204bc8c0300f03d9c60ff097aef28e0df6515665497b919f0",
131
+
"https://deno.land/x/tui@2.1.11/src/signals/mod.ts": "e76b1303c74c257956d29f9169f3f12af410a0e8540c7a467e5405ba839cc431",
132
+
"https://deno.land/x/tui@2.1.11/src/signals/reactivity.ts": "8520655a0b948d979b1b3450139695726c1dfeb46b46d49b8e4159fe4651368d",
133
+
"https://deno.land/x/tui@2.1.11/src/signals/signal.ts": "5f351000a3316196ac3836fd9f3ef2a708aec85713df720a01c853d4859060be",
134
+
"https://deno.land/x/tui@2.1.11/src/signals/types.ts": "e04d088a849a58d184c30420fec9ab3726985e3bcbe2cdc1b4bbc218fb299dbe",
135
+
"https://deno.land/x/tui@2.1.11/src/theme.ts": "87f3da7e6a5bbbeb04c3c5384069225c244bcce0bac833a87828c5208af07cfc",
136
+
"https://deno.land/x/tui@2.1.11/src/tui.ts": "9b9bb4da296e96aadbe846520446d76570cf6105dcbc3c59e26a4301b4c6d2f4",
137
+
"https://deno.land/x/tui@2.1.11/src/types.ts": "7e39e8c59a1d28e379e54455dd7d7bb1a349191970d9af8d47a74b590e0de401",
138
+
"https://deno.land/x/tui@2.1.11/src/utils/ansi_codes.ts": "be83f249ab09d33b64540adda5191c58580d386cc7627b8d10ea3363c9a6d23d",
139
+
"https://deno.land/x/tui@2.1.11/src/utils/async.ts": "3f3bfe526c05467313237c434bc951a02344935dba61fe7b4e14d818d03ba1ca",
140
+
"https://deno.land/x/tui@2.1.11/src/utils/component.ts": "a7f5396b480c7ed437c5e08ec56c3e5c85a55963ee8520c2e5cc7a185577f1a3",
141
+
"https://deno.land/x/tui@2.1.11/src/utils/mod.ts": "4daef102e2406625f32faf08d238b702a26b3dc87232c35e97a215b9dbf9e781",
142
+
"https://deno.land/x/tui@2.1.11/src/utils/numbers.ts": "9d4322b7a184e111184f37507ccdf0d4a29ee7eb8f2ce8f942f078bd165f8941",
143
+
"https://deno.land/x/tui@2.1.11/src/utils/signals.ts": "a78893aa2e379468df65045a4d1f45e0111237b24e18c19bf5a92b6ee9074c4a",
144
+
"https://deno.land/x/tui@2.1.11/src/utils/sorted_array.ts": "d7b55e9c6489102fbee46d632040449f960f2ed3ae0d6bc3326e6d6ec1450d97",
145
+
"https://deno.land/x/tui@2.1.11/src/utils/strings.ts": "0f7d24072e3d2ed4993f0f2692f148b0af4d9b7a665193dec835101af4dabf7b",
146
+
"https://deno.land/x/tui@2.1.11/src/view.ts": "77c9dfdb3632f95c2456036c5e30f90cfbbad62cbb4f370cba48b992523aa619"
147
+
},
148
+
"workspace": {
149
+
"dependencies": [
150
+
"jsr:@std/assert@1",
151
+
"jsr:@std/cli@^1.0.23",
152
+
"jsr:@std/dotenv@~0.225.5",
153
+
"npm:@atproto/api@~0.17.3"
154
+
]
155
+
}
156
+
}
+39
login.ts
+39
login.ts
···
1
+
import { AtpAgent } from "@atproto/api";
2
+
import { parseArgs } from "@std/cli";
3
+
4
+
export const loginToService = async () => {
5
+
const {
6
+
username = Deno.env.get("ATP_USERNAME"),
7
+
password = Deno.env.get("ATP_PASSWORD"),
8
+
service = Deno.env.get("SERVICE_URI") ?? "https://bsky.social",
9
+
} = parseArgs(Deno.args);
10
+
11
+
const agent = new AtpAgent({ service });
12
+
agent.configureProxy("did:plc:newitj5jo3uel7o4mnf3vj2o#atproto_labeler");
13
+
14
+
try {
15
+
await agent.login({ identifier: username, password });
16
+
} catch (e) {
17
+
console.dir(e);
18
+
if (e instanceof Error && e.name === "AuthFactorTokenRequiredError") {
19
+
let authFactorToken;
20
+
21
+
do {
22
+
authFactorToken = prompt(
23
+
`Check your email for a login token and enter it below:`
24
+
);
25
+
} while (!authFactorToken);
26
+
27
+
try {
28
+
await agent.login({
29
+
identifier: username,
30
+
password,
31
+
authFactorToken,
32
+
});
33
+
} catch (e) {
34
+
console.error(e);
35
+
}
36
+
}
37
+
}
38
+
return agent;
39
+
};
+65
main.ts
+65
main.ts
···
1
+
import { loginToService } from "./login.ts";
2
+
import "@std/dotenv/load";
3
+
import { parseArgs } from "@std/cli";
4
+
import { getAllAppeals } from "./appeals.ts";
5
+
6
+
if (import.meta.main) {
7
+
const {
8
+
_: [command],
9
+
} = parseArgs(Deno.args);
10
+
switch (command) {
11
+
case "autoappeal": {
12
+
const agent = await loginToService();
13
+
const appeals = await getAllAppeals(agent);
14
+
const {
15
+
data: { records },
16
+
} = await agent.tools.ozone.moderation.getRecords({
17
+
uris: appeals.map((d) => d.subject.uri),
18
+
});
19
+
20
+
for (const record of records) {
21
+
const evt = {
22
+
subject: {
23
+
$type: "com.atproto.repo.strongRef",
24
+
uri: record.uri,
25
+
cid: record.cid,
26
+
},
27
+
createdBy: agent.did!,
28
+
subjectBlobCids: record.blobCids,
29
+
modTool: { name: "ozone-cli/autoappeal" },
30
+
};
31
+
32
+
// Remove ALL labels from each post
33
+
// @TODO add some sort of NLP to determine what action to take (i.e., replace label X with label Y)
34
+
await agent.tools.ozone.moderation.emitEvent({
35
+
...evt,
36
+
event: {
37
+
$type: "tools.ozone.moderation.defs#modEventLabel",
38
+
createLabelVals: [],
39
+
negateLabelVals: record.labels,
40
+
comment: `Labels removed by ozone-cli at ${new Date().toISOString()}`,
41
+
},
42
+
});
43
+
44
+
// Acknowledge appeal
45
+
await agent.tools.ozone.moderation.emitEvent({
46
+
...evt,
47
+
event: {
48
+
$type: "tools.ozone.moderation.defs#modEventAcknowledge",
49
+
comment: "",
50
+
acknowledgeAccountSubjects: false,
51
+
},
52
+
});
53
+
54
+
// Resolve appeal
55
+
await agent.tools.ozone.moderation.emitEvent({
56
+
...evt,
57
+
event: {
58
+
$type: "tools.ozone.moderation.defs#modEventResolveAppeal",
59
+
comment: "Resolving",
60
+
},
61
+
});
62
+
}
63
+
}
64
+
}
65
+
}