Skip to content
This repository was archived by the owner on Aug 10, 2024. It is now read-only.

Commit b20d8b0

Browse files
authored
Merge pull request #6 from jcsalterego/pinned-posts
Pinned Posts
2 parents 62f9d9f + b8c110f commit b20d8b0

File tree

7 files changed

+108
-11
lines changed

7 files changed

+108
-11
lines changed

CONFIG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ Cute animals feed
1919

2020
# searchTerms
2121

22-
> Maximum of five search terms. Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
22+
> Search Terms are now more powerful. There are two types:
23+
>
24+
> - Pinned posts: links such as `https://bsky.app/profile/saddymayo.bsky.social/post/3jxju2wwap22e` will pin at the top of the feed. One link per line, please.
25+
> - Keywords (maximum 5 terms): Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
26+
>
2327
28+
- https://bsky.app/profile/saddymayo.bsky.social/post/3jxju2wwap22e
2429
- cats
2530
- dogs
2631
- penguins

cloudflare-worker/worker.js

+35-3
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,34 @@ function jsonResponse(obj) {
3535
return response;
3636
}
3737

38+
function bucketTerms(allTerms, opts={}) {
39+
let maxSearchTerms = opts["maxSearchTerms"] || MAX_SEARCH_TERMS;
40+
let pinnedPosts = [];
41+
let searchTerms = [];
42+
43+
for (let term of allTerms) {
44+
if (term.startsWith("at://")) {
45+
pinnedPosts.push(term);
46+
} else {
47+
searchTerms.push(term);
48+
}
49+
}
50+
51+
return {
52+
pinnedPosts: pinnedPosts,
53+
searchTerms: searchTerms.slice(0, maxSearchTerms),
54+
}
55+
}
56+
3857
async function getFeedSkeleton(request) {
39-
let url = new URL(request.url);
40-
let feedAtUrl = url.searchParams.get("feed");
58+
const url = new URL(request.url);
59+
const feedAtUrl = url.searchParams.get("feed");
4160
if (feedAtUrl === null) {
4261
console.warn(`feed parameter missing from query string`);
4362
return feedJsonResponse([]);
4463
}
64+
const cursorParam = url.searchParams.get("cursor");
65+
const showPins = cursorParam === null;
4566
let words = feedAtUrl.split("/");
4667
let feedId = words[words.length - 1];
4768
let config = CONFIGS[feedId];
@@ -56,7 +77,14 @@ async function getFeedSkeleton(request) {
5677
limit = DEFAULT_LIMIT;
5778
}
5879

59-
let searchTerms = config.searchTerms.slice(0, MAX_SEARCH_TERMS);
80+
let allTerms = bucketTerms(config.searchTerms, {
81+
maxSearchTerms: MAX_SEARCH_TERMS,
82+
});
83+
let searchTerms = allTerms.searchTerms;
84+
let pinnedPosts = allTerms.pinnedPosts;
85+
if (!showPins) {
86+
pinnedPosts = [];
87+
}
6088
let responsePromises = [];
6189

6290
for (let searchTerm of searchTerms) {
@@ -88,6 +116,9 @@ async function getFeedSkeleton(request) {
88116
a === b ? 0 : a < b ? -1 : 1
89117
);
90118
var feed = [];
119+
for (let pinnedPost of pinnedPosts) {
120+
feed.push({ post: pinnedPost });
121+
}
91122
for (let timestampUrl of timestampURLs) {
92123
let atUrl = timestampUrl[1];
93124
feed.push({ post: atUrl });
@@ -124,6 +155,7 @@ const CONFIGS = {
124155
"description": "Cute animals feed",
125156
"searchTerms": [
126157
"cats",
158+
"at://did:plc:ozppa2bsq6bdnajyweoir2i2/app.bsky.feed.post/3jxju2wwap22e",
127159
"dogs",
128160
"penguins",
129161
"red pandas",

configs/BASKETBALL_EMOJIS.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ Posts with 🏀
2525

2626
# searchTerms
2727

28-
> Maximum of five search terms. Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
28+
> Search Terms are now more powerful. There are two types:
29+
>
30+
> - Pinned posts: links such as `https://bsky.app/profile/saddymayo.bsky.social/post/3jxju2wwap22e` will pin at the top of the feed. One link per line, please.
31+
> - Keywords (maximum 5 terms): Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
2932
3033
- 🏀
3134

configs/GAMING_EMOJIS.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ Posts with 👾🎮🕹️
2525

2626
# searchTerms
2727

28-
> Maximum of five search terms. Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
28+
> Search Terms are now more powerful. There are two types:
29+
>
30+
> - Pinned posts: links such as `https://bsky.app/profile/saddymayo.bsky.social/post/3jxju2wwap22e` will pin at the top of the feed. One link per line, please.
31+
> - Keywords (maximum 5 terms): Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
2932
3033
- 👾
3134
- 🎮

configs/SCIENCE_EMOJIS.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ Posts with 🧪🥼🔭
2525

2626
# searchTerms
2727

28-
> Maximum of five search terms. Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
28+
> Search Terms are now more powerful. There are two types:
29+
>
30+
> - Pinned posts: links such as `https://bsky.app/profile/saddymayo.bsky.social/post/3jxju2wwap22e` will pin at the top of the feed. One link per line, please.
31+
> - Keywords (maximum 5 terms): Test these in [https://bsky.app/search](https://bsky.app/search). `AND` is implicit, so `cat dog` on one line will require both `cat` and `dog`. You can use quotes as well `"hot dog"`.
2932
3033
- 🧪
3134
- 🥼

feed-generator/configs.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"description": "Cute animals feed",
66
"searchTerms": [
77
"cats",
8+
"at://did:plc:ozppa2bsq6bdnajyweoir2i2/app.bsky.feed.post/3jxju2wwap22e",
89
"dogs",
910
"penguins",
1011
"red pandas",

render-configs.py

+54-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,59 @@
33
import json
44
import os
55
import re
6+
import sys
7+
8+
import requests
69

710
WORKER_SENTINEL = "\n\n// CONFIGS\n\n"
11+
LIST_ITEM_REGEX = re.compile(r"^- ")
12+
POST_REGEX = re.compile(r"^.*[\./]bsky\.app/profile/(.+?)/post/([a-z0-9]+)")
13+
14+
15+
def resolve_handles(handles):
16+
dids = {}
17+
for handle in handles:
18+
url = f"https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle={handle}"
19+
response = requests.get(url)
20+
if response.status_code == 200:
21+
did = response.json()["did"]
22+
dids[handle] = did
23+
return dids
24+
25+
26+
def render_search_terms(search_terms):
27+
handles = set()
28+
rendered_terms = []
29+
30+
# strip out list item markers
31+
terms = [re.compile(LIST_ITEM_REGEX).sub("", term) for term in search_terms]
32+
33+
# collect handles and pins
34+
for term in terms:
35+
post_matches = POST_REGEX.match(term)
36+
if post_matches:
37+
handle = post_matches.group(1)
38+
handles.add(handle)
39+
40+
# resolve handles
41+
dids = resolve_handles(handles)
42+
43+
# replace handles with DIDs
44+
for term in terms:
45+
post_matches = POST_REGEX.match(term)
46+
if post_matches:
47+
handle = post_matches.group(1)
48+
rkey = post_matches.group(2)
49+
did = dids[handle]
50+
if did:
51+
at_url = f"at://{did}/app.bsky.feed.post/{rkey}"
52+
rendered_terms.append(at_url)
53+
else:
54+
print(f"WARN: Failed to resolve handle {handle}", file=sys.stderr)
55+
else:
56+
rendered_terms.append(term)
57+
58+
return rendered_terms
859

960

1061
def parse_config(dirname, markdown_contents):
@@ -28,9 +79,7 @@ def parse_config(dirname, markdown_contents):
2879
for key in flat_keys:
2980
config[key] = " ".join(config[key])
3081
if "searchTerms" in config:
31-
config["searchTerms"] = [
32-
re.compile(r"^- ").sub("", term) for term in config["searchTerms"]
33-
]
82+
config["searchTerms"] = render_search_terms(config["searchTerms"])
3483
if "avatar" in config:
3584
matches = re.compile("^.*\((.+)\)$").match(config["avatar"])
3685
if matches:
@@ -46,7 +95,7 @@ def parse_config(dirname, markdown_contents):
4695
config["displayName"] = display_name
4796

4897
if "isEnabled" in config:
49-
config["isEnabled"] = (config["isEnabled"].lower() == "true")
98+
config["isEnabled"] = config["isEnabled"].lower() == "true"
5099
else:
51100
# for legacy support, if the section is missing, set to True
52101
config["isEnabled"] = True
@@ -91,4 +140,5 @@ def main():
91140
save_json_configs("feed-generator/configs.json", configs)
92141
replace_json_configs("cloudflare-worker/worker.js", configs)
93142

143+
94144
main()

0 commit comments

Comments
 (0)