-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathdelete_hellthreads.py
executable file
·139 lines (117 loc) · 3.72 KB
/
delete_hellthreads.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env python3
import argparse
import sys
from datetime import datetime, timezone
from constantine import (
create_session,
require_bluesky_creds_from_env,
fetch_all_hellthread_posts,
post_xrpc,
to_web_url,
)
APP_BSKY_FEED_POST_COLLECTION = "app.bsky.feed.post"
MAX_DELETION_COUNT = 100
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"--before-date",
type=str,
help="Only fetch posts before this date (exclusive),"
" in the local time zone (YYYY-MM-DD)",
)
parser.add_argument(
"--after-date",
type=str,
help="Only fetch posts on or after this date (inclusive),"
" in the local time zone (YYYY-MM-DD)",
)
parser.add_argument(
"handle",
type=str,
help="Handle of the user whose hellthreads to fetch",
)
args = parser.parse_args()
if args.before_date is not None:
# parse YYYY-MM-DD into datetime
try:
args.before_date = parse_local_date(args.before_date)
except ValueError:
print(
f"Invalid date `{args.before_date}`. Must be YYYY-MM-DD",
file=sys.stderr,
)
sys.exit(1)
if args.after_date is not None:
# parse YYYY-MM-DD into datetime
try:
args.after_date = parse_local_date(args.after_date)
except ValueError:
print(
f"Invalid date `{args.after_date}`. Must be YYYY-MM-DD",
file=sys.stderr,
)
sys.exit(1)
if (
args.before_date is not None
and args.after_date is not None
and args.before_date <= args.after_date
):
print(
f"Invalid date range:\n"
f" --after-date: {args.after_date}\n"
f" --before-date: {args.before_date}",
file=sys.stderr,
)
sys.exit(1)
return args
def parse_local_date(date_str):
date = datetime.strptime(date_str, "%Y-%m-%d")
tzlocal = datetime.now(timezone.utc).astimezone().tzinfo
date = date.replace(tzinfo=tzlocal)
return date
def delete_post(session, uri):
words = uri.replace("at://", "").split("/")
if len(words) == 3 and words[1] == APP_BSKY_FEED_POST_COLLECTION:
did = words[0]
rkey = words[2]
json_payload = {
"collection": APP_BSKY_FEED_POST_COLLECTION,
"repo": did,
"rkey": rkey,
}
return post_xrpc(
session, "com.atproto.repo.deleteRecord", json_payload=json_payload
)
return None
def main():
args = parse_args()
handle = args.handle
bluesky_user, bluesky_app_password = require_bluesky_creds_from_env()
session = create_session(bluesky_user, bluesky_app_password)
if session is None:
print(
"Login failed. Please check BLUESKY_USER and BLUESKY_APP_PASSWORD",
file=sys.stderr,
)
sys.exit(1)
hellthread_reply_uris = fetch_all_hellthread_posts(
session, handle, before_date=args.before_date, after_date=args.after_date
)
print(f"{len(hellthread_reply_uris)} hellthread posts total", file=sys.stderr)
total_deleted = 0
failure = False
for uri in hellthread_reply_uris:
if total_deleted >= MAX_DELETION_COUNT:
print(
f"Reached MAX_DELETION_COUNT={MAX_DELETION_COUNT} posts",
file=sys.stderr,
)
break
print(f"Deleting {to_web_url(uri)}", file=sys.stderr)
delete_post(session, uri)
total_deleted += 1
print(f"Deleted {total_deleted} posts", file=sys.stderr)
if failure:
sys.exit(1)
if __name__ == "__main__":
main()