+2
-39
caddy/Caddyfile
+2
-39
caddy/Caddyfile
···
80
80
on_demand
81
81
}
82
82
83
-
handle / {
84
-
header Content-Type text/plain; charset=utf-8
85
-
header Access-Control-Allow-Origin *
86
-
respond <<BODY
87
-
| |
88
-
| |
89
-
| |
90
-
+---#---------------------#---+
91
-
| [Used Car Salesman voice] |
92
-
| Open Your |
93
-
| __ ___ _ _ ___ |
94
-
| | \ / \| \| |/ __| |
95
-
| _ | - || - || || | | |
96
-
| |_||__/ \___/|_|\_|\___| |
97
-
| ___ _ _ ___ |
98
-
| | __|| || | | __| |
99
-
| | _| | || |_ | _| |
100
-
| |_| |_||___||___| |
101
-
| |
102
-
| At dong.vielle.dev TODAY |
103
-
| for a chance to win £50 off |
104
-
| a purchase of 3 |
105
-
| or more potatoes!! |
106
-
+-----------------------------+
107
-
108
-
Welcome to my PDS!
109
-
It's running off a pi on my floor
110
-
and isnt always online at the time of writing.
111
-
112
-
Invite codes are required
113
-
DM me if you somehow trust this enough
114
-
115
-
PDS Source: https://github.com/bluesky-social/atproto
116
-
Setup Guide: https://vielle.dev/blog/pds-on-a-pi
117
-
Protocol: https://atproto.com
118
-
119
-
120
-
BODY 200
121
-
}
83
+
@landing path / /css
84
+
reverse_proxy @landing landing:8000
122
85
123
86
# secure due to tailscale wireguard stuff
124
87
# i cant configure https on the pi???
+4
compose.yaml
+4
compose.yaml
+7
landing/Dockerfile
+7
landing/Dockerfile
+173
landing/landing.ts
+173
landing/landing.ts
···
1
+
const css = `
2
+
@property --gradient-offset {
3
+
syntax: "<length>";
4
+
inherits: false;
5
+
initial-value: 0px;
6
+
}
7
+
8
+
@keyframes scroll {
9
+
from {
10
+
--gradient-offset: 0px;
11
+
}
12
+
13
+
to {
14
+
--gradient-offset: var(--gradient-gap);
15
+
}
16
+
}
17
+
18
+
html {
19
+
background:
20
+
repeating-linear-gradient(
21
+
#fff1,
22
+
#0000 5px,
23
+
#fff1 10px
24
+
),
25
+
black;
26
+
min-height: 100%;
27
+
font-family: 'Monaspace neon var', monospace;
28
+
font-weight: bold;
29
+
}
30
+
31
+
html, body {
32
+
margin: 0;
33
+
}
34
+
35
+
pre {
36
+
/* config */
37
+
--light: lime;
38
+
--dark: green;
39
+
--gradient-gap: 10px;
40
+
--gradient-size: 5px;
41
+
--gradient-offset: 0px;
42
+
--gradient-max: calc(var(--gradient-gap) * 2 + var(--gradient-size));
43
+
44
+
/* override some resource://content-accessible/plaintext.css styles in ff */
45
+
white-space: pre !important;
46
+
width: max-content;
47
+
padding: 1em;
48
+
margin-block: 0;
49
+
padding-block-start: 0;
50
+
51
+
text-shadow: 0 0 5px lime;
52
+
color: lime;
53
+
@supports (background-clip: text) {
54
+
color: transparent;
55
+
background: repeating-linear-gradient(
56
+
var(--light),
57
+
var(--light) calc(var(--gradient-gap) - var(--gradient-offset)),
58
+
var(--dark) calc(var(--gradient-gap) - var(--gradient-offset)),
59
+
var(--dark) calc(var(--gradient-gap) - var(--gradient-offset) + var(--gradient-size)),
60
+
var(--light) calc(var(--gradient-gap) - var(--gradient-offset) + var(--gradient-size)),
61
+
var(--light) var(--gradient-max)
62
+
) text;
63
+
animation: 10s infinite scroll linear;
64
+
}
65
+
}
66
+
`;
67
+
68
+
const starter = ` | |
69
+
| |
70
+
| |
71
+
+---#---------------------#---+
72
+
| [Used Car Salesman voice] |
73
+
| Open Your |
74
+
| __ ___ _ _ ___ |
75
+
| | \\ / \\| \\| |/ __| |
76
+
| _ | - || - || || | | |
77
+
| |_||__/ \\___/|_|\\_|\\___| |
78
+
| ___ _ _ ___ |
79
+
| | __|| || | | __| |
80
+
| | _| | || |_ | _| |
81
+
| |_| |_||___||___| |
82
+
| |
83
+
| At dong.vielle.dev TODAY |
84
+
| for a chance to win £50 off |
85
+
| a purchase of 3 |
86
+
| or more potatoes!! |
87
+
+-----------------------------+
88
+
89
+
90
+
Welcome to my PDS!
91
+
It's running off a pi on my floor
92
+
and isnt always online at the time of writing.
93
+
94
+
Invite codes are required
95
+
DM me if you somehow trust this enough
96
+
97
+
PDS Source: https://github.com/bluesky-social/atproto
98
+
Setup Guide: https://vielle.dev/blog/pds-on-a-pi
99
+
Protocol: https://atproto.com
100
+
`;
101
+
102
+
Deno.serve({ port: 8000 }, (req) => {
103
+
switch (new URL(req.url).pathname) {
104
+
case "/css":
105
+
return new Response(css, {
106
+
headers: {
107
+
"Content-Type": "text/css; charset=utf-8",
108
+
"Access-Control-Allow-Origin": "*",
109
+
},
110
+
});
111
+
case "/": {
112
+
const body = new ReadableStream({
113
+
async start(controller) {
114
+
const users = fetch("http://pi:8000/xrpc/com.atproto.sync.listRepos")
115
+
.then((res) => res.json() as Promise<{ repos: { did: string }[] }>)
116
+
.then((res) => res.repos)
117
+
.then((res) =>
118
+
res.map((repo) => ({
119
+
display: fetch(
120
+
`http://pi:8000/xrpc/com.atproto.repo.getRecord?repo=${repo.did}&collection=app.bsky.actor.profile&rkey=self`
121
+
)
122
+
.then((res) => res.json())
123
+
.then((profile) => profile.value.displayName),
124
+
handle: fetch(
125
+
repo.did.startsWith("did:plc")
126
+
? "https://plc.directory/" + repo.did
127
+
: `https://${repo.did.replace("did:web:", "")}/.well-known/did.json`
128
+
)
129
+
.then((res) => res.json())
130
+
.then((doc) => doc.alsoKnownAs[0].replace("at://", "")),
131
+
did: repo.did,
132
+
}))
133
+
)
134
+
.then(async (users) =>
135
+
(
136
+
await Promise.all(
137
+
users.map(
138
+
async (x) =>
139
+
`\n- ${x.did}@${await x.handle}: ${await x.display}`
140
+
)
141
+
)
142
+
).join("\n")
143
+
);
144
+
145
+
for (const line of starter) {
146
+
await new Promise((res) => setTimeout(res, 10));
147
+
controller.enqueue(line);
148
+
}
149
+
150
+
controller.enqueue("");
151
+
for (const user of "\n\nAccounts:" + (await users)) {
152
+
await new Promise((res) => setTimeout(res, 10));
153
+
controller.enqueue(user);
154
+
}
155
+
156
+
controller.close();
157
+
},
158
+
});
159
+
160
+
return new Response(body.pipeThrough(new TextEncoderStream()), {
161
+
headers: {
162
+
"Content-Type": "text/text; charset=utf-8",
163
+
"Access-Control-Allow-Origin": "*",
164
+
Link: "</css>; rel=stylesheet",
165
+
},
166
+
});
167
+
}
168
+
}
169
+
170
+
return new Response("404", {
171
+
status: 404,
172
+
});
173
+
});