279 lines
7.2 KiB
Go
279 lines
7.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/nbd-wtf/go-nostr"
|
|
"github.com/nbd-wtf/go-nostr/nip19"
|
|
)
|
|
|
|
// --- Your FetchNotesHTML() from earlier ---
|
|
func FetchNotesHTML(relayURL, npub string) (string, error) {
|
|
ctx := context.Background()
|
|
|
|
relay, err := nostr.RelayConnect(ctx, relayURL)
|
|
if err != nil {
|
|
return "", fmt.Errorf("relay connection failed: %w", err)
|
|
}
|
|
defer relay.Close()
|
|
|
|
var filters nostr.Filters
|
|
if _, v, err := nip19.Decode(npub); err == nil {
|
|
pub := v.(string)
|
|
filters = []nostr.Filter{{
|
|
Kinds: []int{nostr.KindTextNote},
|
|
Authors: []string{pub},
|
|
Limit: 3,
|
|
}}
|
|
} else {
|
|
return "", fmt.Errorf("npub decode failed: %w", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
defer cancel()
|
|
|
|
sub, err := relay.Subscribe(ctx, filters)
|
|
if err != nil {
|
|
return "", fmt.Errorf("subscribe failed: %w", err)
|
|
}
|
|
|
|
var builder strings.Builder
|
|
for ev := range sub.Events {
|
|
id, _ := nip19.EncodeNote(ev.ID)
|
|
pub, _ := nip19.EncodePublicKey(ev.PubKey)
|
|
t := time.Unix(int64(ev.CreatedAt), 0).UTC()
|
|
rfc3339 := t.Format(time.RFC3339)
|
|
content := ev.Content
|
|
|
|
builder.WriteString("<li>")
|
|
builder.WriteString("<div>")
|
|
builder.WriteString(fmt.Sprintf("<p><strong>ID:</strong> %s</p>", id))
|
|
builder.WriteString(fmt.Sprintf("<p><strong>Author:</strong> %s</p>", pub))
|
|
builder.WriteString(fmt.Sprintf("<p><strong>Created:</strong> %s</p>", rfc3339))
|
|
builder.WriteString(fmt.Sprintf("<p><strong>Content:</strong> %s</p>", content))
|
|
builder.WriteString("</div>")
|
|
builder.WriteString("</li>")
|
|
builder.WriteString("<hr>")
|
|
}
|
|
|
|
return builder.String(), nil
|
|
}
|
|
|
|
// --- Your static HTML template with a placeholder ---
|
|
const htmlTemplate = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>despera.space</title>
|
|
<style>
|
|
html, body {
|
|
margin: 0;
|
|
padding: 0;
|
|
min-height: 100%;
|
|
}
|
|
|
|
body {
|
|
background-color: #000000; /* Black background */
|
|
color: #39ff14; /* Phosphor green text */
|
|
font-family: monospace;
|
|
overflow-y: auto; /* <-- Add this line */
|
|
}
|
|
|
|
a {
|
|
color: #39ff14; /* Match phosphor green */
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
color: #80ff80; /* Slightly lighter green on hover */
|
|
text-decoration: underline;
|
|
}
|
|
|
|
h1 {
|
|
color: #39ff14;
|
|
margin-top: 30px;
|
|
font-size: 1.5em;
|
|
border-bottom: 1px solid #39ff14;
|
|
padding-bottom: 5px;
|
|
}
|
|
|
|
ul {
|
|
list-style-type: none;
|
|
padding-left: 0;
|
|
}
|
|
|
|
li {
|
|
margin-bottom: 10px;
|
|
}
|
|
hr {
|
|
border: 0;
|
|
height: 1px;
|
|
background-color: #39ff14;
|
|
margin: 20px 0;
|
|
}
|
|
/* Navigation Bar */
|
|
nav {
|
|
background-color: #000000;
|
|
border-bottom: 1px solid #39ff14;
|
|
padding: 10px;
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 9999;
|
|
}
|
|
|
|
nav a {
|
|
color: #39ff14;
|
|
font-weight: bold;
|
|
padding: 5px 10px;
|
|
border: 1px solid #39ff14;
|
|
border-radius: 2px;
|
|
transition: background 0.3s, color 0.3s;
|
|
}
|
|
|
|
nav a:hover {
|
|
background-color: #39ff14;
|
|
color: #000000;
|
|
}
|
|
|
|
/* Scanline overlay effect */
|
|
.scanlines {
|
|
position: relative;
|
|
}
|
|
|
|
.scanlines:before {
|
|
content: "";
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100vw;
|
|
height: 2px;
|
|
z-index: 2147483649;
|
|
background: rgba(0, 255, 0, 0.3); /* Subtle green line */
|
|
opacity: 0.75;
|
|
pointer-events: none;
|
|
animation: scanline 2s linear infinite;
|
|
}
|
|
|
|
.scanlines:after {
|
|
content: "";
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
z-index: 2147483648;
|
|
pointer-events: none;
|
|
background: linear-gradient(
|
|
to bottom,
|
|
transparent 50%,
|
|
rgba(0, 255, 0, 0.05) 51%
|
|
);
|
|
background-size: 100% 4px;
|
|
animation: scanlines 1s steps(60) infinite;
|
|
}
|
|
|
|
@keyframes scanline {
|
|
0% {
|
|
transform: translateY(-2px);
|
|
}
|
|
100% {
|
|
transform: translateY(100vh);
|
|
}
|
|
}
|
|
|
|
@keyframes scanlines {
|
|
0% {
|
|
background-position: 0 50%;
|
|
}
|
|
}
|
|
|
|
/* Main content padding */
|
|
.content {
|
|
padding: 20px;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="scanlines">
|
|
<nav>
|
|
<a href="#ids">IDs</a>
|
|
<a href="#notes">Long Form Notes</a>
|
|
<a href="#other">Other Stuff</a>
|
|
<a href="#posts">Posts</a>
|
|
</nav>
|
|
|
|
<div class="content">
|
|
<h1 id="ids">IDs</h1>
|
|
<ul>
|
|
<li>NPUB: npub1nmk2399jazpsup0vsm6dzxw7gydzm5atedj4yhdkn3yx7jh7tzpq842975</li>
|
|
<li>NIP06: iru@ this domain</li>
|
|
<li>LNURL: iru@ this domain</li>
|
|
<li>GPG: 0DE8AAA9F5DA9CCB3F3F3B8E14566DCEC81EF576</li>
|
|
<li>Github: irusensei</li>
|
|
</ul>
|
|
|
|
<h1 id="notes">Long Form Notes</h1>
|
|
<ul>
|
|
<li>
|
|
Running popular AI software on Linux and AMD GPUs:
|
|
<a href="https://habla.news/a/naddr1qqxnzd3ex56rwvfexvurxwfjqgsfam9gjjew3qcwqhkgdax3r80yzx3d6w4uke2jtkmfcjr0ftl93qsrqsqqqa28vfwv5f">note</a>,
|
|
<a href="https://code.despera.space/iru/htdocs/src/branch/main/notes/AMD-AGI.md">local</a>
|
|
</li>
|
|
<li>
|
|
How I put NixOS on my UDM (trashcan model) router:
|
|
<a href="https://habla.news/a/naddr1qvzqqqr4gupzp8hv4z2t96yrpcz7eph56yvausg69hf6hjm92fwmd8zgda90ukyzqqxnzde3xccnyd3sxver2dfk5j9lzf">note</a>,
|
|
<a href="https://code.despera.space/iru/htdocs/src/branch/main/notes/UDM-NIXOS.md">local</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<h1 id="other">Other Stuff</h1>
|
|
<ul>
|
|
<li>
|
|
<a href="https://code.despera.space/mirrors">I keep mirrors of repos I use or feel like having preserved</a>.
|
|
</li>
|
|
</ul>
|
|
|
|
<h1 id="posts">Posts</h1>
|
|
<ul>
|
|
{{POSTS}}
|
|
</ul>
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|
|
`
|
|
|
|
// --- HTTP Handler ---
|
|
func handler(w http.ResponseWriter, r *http.Request) {
|
|
relayURL := "wss://relay.despera.space"
|
|
npub := "npub1nmk2399jazpsup0vsm6dzxw7gydzm5atedj4yhdkn3yx7jh7tzpq842975"
|
|
|
|
notesHTML, err := FetchNotesHTML(relayURL, npub)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("failed to fetch notes: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
page := strings.Replace(htmlTemplate, "{{POSTS}}", notesHTML, 1)
|
|
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
fmt.Fprint(w, page)
|
|
}
|
|
|
|
// --- Main ---
|
|
func main() {
|
|
http.HandleFunc("/", handler)
|
|
|
|
fmt.Println("Serving on http://localhost:8080...")
|
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
}
|