diff options
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/asbestos/html.templ | 114 | ||||
| -rw-r--r-- | cmd/asbestos/html_templ.go | 403 | ||||
| -rw-r--r-- | cmd/asbestos/main.go | 100 | ||||
| -rw-r--r-- | cmd/mastodon2atproto/main.go | 245 | ||||
| -rw-r--r-- | cmd/stickers/data/error.avif | bin | 0 -> 6509 bytes | |||
| -rw-r--r-- | cmd/stickers/data/error.jxl | bin | 0 -> 15104 bytes | |||
| -rw-r--r-- | cmd/stickers/data/error.png | bin | 0 -> 30864 bytes | |||
| -rw-r--r-- | cmd/stickers/data/error.webp | bin | 0 -> 10548 bytes | |||
| -rw-r--r-- | cmd/stickers/data/not_found.avif | bin | 0 -> 6225 bytes | |||
| -rw-r--r-- | cmd/stickers/data/not_found.jxl | bin | 0 -> 14346 bytes | |||
| -rw-r--r-- | cmd/stickers/data/not_found.png | bin | 0 -> 29457 bytes | |||
| -rw-r--r-- | cmd/stickers/data/not_found.webp | bin | 0 -> 9824 bytes | |||
| -rw-r--r-- | cmd/stickers/main.go | 160 | ||||
| -rw-r--r-- | cmd/stickers/main.templ | 52 | ||||
| -rw-r--r-- | cmd/stickers/main_templ.go | 168 |
15 files changed, 1242 insertions, 0 deletions
diff --git a/cmd/asbestos/html.templ b/cmd/asbestos/html.templ new file mode 100644 index 0000000..ae57782 --- /dev/null +++ b/cmd/asbestos/html.templ @@ -0,0 +1,114 @@ +package main + +import ( + "within.website/x/htmx" + "within.website/x/xess" +) + +templ NotFound() { + <p>The URL you requested could not be found. Please check your URL and hang up to try your call again.</p> +} + +templ allClear() { + <p>Your data was not found in the dataset. No action is required on your part.</p> +} + +templ Error(why string) { + <p>Oopsie whoopsie uwu we made a fucky-wucky! A widdle fucko boingo! The code monkeys at our headquarters are working VEWY HARD to fix this!</p> + <p>Reason: { why }</p> +} + +templ Index() { + <p>TODO placeholder</p> + <input + style="display: block" + class="form-control" + type="search" + name="search" + placeholder="Begin Typing To Search Users..." + hx-post="/search" + hx-trigger="input changed delay:500ms, search" + hx-target="#search-results" + hx-indicator=".htmx-indicator" + hx-swap="innerHTML" + /> + <br/> + <div id="search-results"></div> +} + +templ headArea() { + @htmx.Use() + <style> + .no-copy { + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently supported by Chrome, Opera and Edge */ + } + </style> +} + +templ footer() { + <p> + A product of <a href="https://techaro.lol">Techaro</a> + <a href="https://bsky.app/profile/techaro.lol"> + { "@techaro.lol" } + </a>, the only ethical AI company + </p> +} + +templ Layout(title string, body templ.Component) { + @xess.Base( + title, + headArea(), + nil, + body, + footer(), + ) +} + +templ searchPage(authorDID string, posts []Post) { + <table> + <thead> + <tr> + <th>Created at</th> + <th>Text</th> + <th>Link</th> + </tr> + </thead> + <tbody> + for _, post := range posts { + <tr> + <td>{ post.CreatedAt }</td> + <td>{ post.Text }</td> + <td><a href={ templ.SafeURL(post.BlueskyURL) }>🔗</a></td> + </tr> + } + </tbody> + </table> + <div id="dmca-notice"> + <p>Since your data is in this dataset, here's what you can do about it:</p> + <p>Compose an email to <code>dmca@huggingface.co</code> with the subject line <code>DMCA Takedown Request</code> and something like the following body (rephrase this in your own words):</p> + <blockquote class="no-copy"> + Hello, + <br/> + <br/> + I am writing to you to inform you that my data is present in the dataset <a href="https://huggingface.co/datasets/bluesky-community/one-million-bluesky-posts">bluesky-community/one-million-bluesky-posts</a> and I did not consent to it being included. I would like to request that you remove my data from the dataset. + <br/> + <br/> + You can identify my data by searching for the following DID in the <code>author_did</code> column: <code>{ authorDID }</code> + <br/> + <br/> + Thank you for your attention and patience in this matter. + <br/> + <br/> + Sincerely, + <br/> + <br/> + { "(Your Name here)" }, { "(Your Email here)" } + <br/> + { "(identified as" } { authorDID }{ ")" } + </blockquote> + <p>For more information, please refer to the <a href="https://huggingface.co/datasets/bluesky-community/one-million-bluesky-posts/discussions/12">dataset page</a>.</p> + </div> +} diff --git a/cmd/asbestos/html_templ.go b/cmd/asbestos/html_templ.go new file mode 100644 index 0000000..7ac5c03 --- /dev/null +++ b/cmd/asbestos/html_templ.go @@ -0,0 +1,403 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.793 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "within.website/x/htmx" + "within.website/x/xess" +) + +func NotFound() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p>The URL you requested could not be found. Please check your URL and hang up to try your call again.</p>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func allClear() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p>Your data was not found in the dataset. No action is required on your part.</p>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func Error(why string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p>Oopsie whoopsie uwu we made a fucky-wucky! A widdle fucko boingo! The code monkeys at our headquarters are working VEWY HARD to fix this!</p><p>Reason: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(why) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 18, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func Index() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p>TODO placeholder</p><input style=\"display: block\" class=\"form-control\" type=\"search\" name=\"search\" placeholder=\"Begin Typing To Search Users...\" hx-post=\"/search\" hx-trigger=\"input changed delay:500ms, search\" hx-target=\"#search-results\" hx-indicator=\".htmx-indicator\" hx-swap=\"innerHTML\"><br><div id=\"search-results\"></div>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func headArea() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = htmx.Use().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<style>\n .no-copy {\n -webkit-user-select: none; /* Safari */\n -moz-user-select: none; /* Firefox */\n -ms-user-select: none; /* Internet Explorer/Edge */\n user-select: none; /* Non-prefixed version, currently supported by Chrome, Opera and Edge */\n }\n </style>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func footer() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p>A product of <a href=\"https://techaro.lol\">Techaro</a> <a href=\"https://bsky.app/profile/techaro.lol\">") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("@techaro.lol") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 55, Col: 19} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>, the only ethical AI company</p>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func Layout(title string, body templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = xess.Base( + title, + headArea(), + nil, + body, + footer(), + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +func searchPage(authorDID string, posts []Post) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<table><thead><tr><th>Created at</th><th>Text</th><th>Link</th></tr></thead> <tbody>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, post := range posts { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<tr><td>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(post.CreatedAt) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 82, Col: 25} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(post.Text) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 83, Col: 20} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td><a href=\"") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 templ.SafeURL = templ.SafeURL(post.BlueskyURL) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var13))) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">🔗</a></td></tr>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</tbody></table><div id=\"dmca-notice\"><p>Since your data is in this dataset, here's what you can do about it:</p><p>Compose an email to <code>dmca@huggingface.co</code> with the subject line <code>DMCA Takedown Request</code> and something like the following body (rephrase this in your own words):</p><blockquote class=\"no-copy\">Hello,<br><br>I am writing to you to inform you that my data is present in the dataset <a href=\"https://huggingface.co/datasets/bluesky-community/one-million-bluesky-posts\">bluesky-community/one-million-bluesky-posts</a> and I did not consent to it being included. I would like to request that you remove my data from the dataset.<br><br>You can identify my data by searching for the following DID in the <code>author_did</code> column: <code>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(authorDID) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 99, Col: 119} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code><br><br>Thank you for your attention and patience in this matter.<br><br>Sincerely,<br><br>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs("(Your Name here)") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 108, Col: 23} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(", ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs("(Your Email here)") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 108, Col: 48} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<br>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var17 string + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs("(identified as") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 110, Col: 21} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var18 string + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(authorDID) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 110, Col: 35} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(")") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `html.templ`, Line: 110, Col: 42} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</blockquote><p>For more information, please refer to the <a href=\"https://huggingface.co/datasets/bluesky-community/one-million-bluesky-posts/discussions/12\">dataset page</a>.</p></div>") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/cmd/asbestos/main.go b/cmd/asbestos/main.go new file mode 100644 index 0000000..9ab1f8e --- /dev/null +++ b/cmd/asbestos/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "database/sql" + "flag" + "fmt" + "log" + "log/slog" + "net/http" + + "github.com/a-h/templ" + _ "github.com/mattn/go-sqlite3" + "within.website/x/htmx" + "within.website/x/internal" + "within.website/x/xess" +) + +//go:generate go run github.com/a-h/templ/cmd/templ@latest generate + +var ( + bind = flag.String("bind", ":8069", "http port to bind on") + dbURL = flag.String("database-url", "", "path to sqlite database") +) + +func main() { + internal.HandleStartup() + + slog.Info("opening database", "database_url", *dbURL) + db, err := sql.Open("sqlite3", *dbURL) + if err != nil { + log.Fatal(err) + } + defer db.Close() + + s := &Server{db: db} + + mux := http.NewServeMux() + xess.Mount(mux) + htmx.Mount(mux) + + mux.Handle("/{$}", templ.Handler( + Layout("Asbestos", Index()), + )) + + mux.HandleFunc("POST /search", s.searchHTMXPage) + + fmt.Printf("http://localhost%s\n", *bind) + log.Fatal(http.ListenAndServe(*bind, mux)) +} + +type Server struct { + db *sql.DB +} + +type Post struct { + ID int + Text string + CreatedAt string + Author string + URI string + HasImages bool + ReplyTo sql.NullString + BlueskyURL string +} + +func (s *Server) getPostsByAuthor(author string) ([]Post, error) { + rows, err := s.db.Query("SELECT id, text, created_at, author, uri, has_images, reply_to, bluesky_url FROM posts WHERE author = ?", author) + if err != nil { + return nil, err + } + defer rows.Close() + + var posts []Post + for rows.Next() { + var post Post + if err := rows.Scan(&post.ID, &post.Text, &post.CreatedAt, &post.Author, &post.URI, &post.HasImages, &post.ReplyTo, &post.BlueskyURL); err != nil { + return nil, err + } + posts = append(posts, post) + } + return posts, nil +} + +func (s *Server) searchHTMXPage(w http.ResponseWriter, r *http.Request) { + query := r.FormValue("search") + + posts, err := s.getPostsByAuthor(query) + if err != nil { + slog.Error("can't find posts", "author", query, "err", err) + templ.Handler(Error(err.Error())).ServeHTTP(w, r) + return + } + + if len(posts) == 0 { + templ.Handler(allClear()).ServeHTTP(w, r) + return + } + + templ.Handler(searchPage(query, posts)).ServeHTTPStreamed(w, r) +} diff --git a/cmd/mastodon2atproto/main.go b/cmd/mastodon2atproto/main.go new file mode 100644 index 0000000..a8957a8 --- /dev/null +++ b/cmd/mastodon2atproto/main.go @@ -0,0 +1,245 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "image" + "image/jpeg" + _ "image/png" + "log" + "log/slog" + "os" + "path/filepath" + "strings" + "time" + + "github.com/bluesky-social/indigo/api/atproto" + lexutil "github.com/bluesky-social/indigo/lex/util" + "github.com/rivo/uniseg" + "within.website/x/internal" + "within.website/x/web/bskybot" + "within.website/x/web/mastosan" +) + +var ( + bskyAuthkey = flag.String("bsky-authkey", "", "Bluesky authkey") + bskyHandle = flag.String("bsky-handle", "", "Bluesky handle/email") + bskyPDS = flag.String("bsky-pds", "https://bsky.social", "Bluesky PDS") + + afterStr = flag.String("after", "2017-04-22T04:59:14Z", "only consider posts after this point") +) + +func main() { + internal.HandleStartup() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + agent := bskybot.NewAgent(ctx, *bskyPDS, *bskyHandle, *bskyAuthkey) + if err := agent.Connect(ctx); err != nil { + log.Fatal(err) + } + + if flag.NArg() != 1 { + fmt.Println("Usage: mastodon2atproto [flags] <data dir>") + } + + dir := flag.Arg(0) + + fin, err := os.Open(filepath.Join(dir, "outbox.json")) + if err != nil { + log.Fatal(err) + } + defer fin.Close() + + after, err := time.Parse(time.RFC3339, *afterStr) + if err != nil { + log.Fatalf("can't parse after time: %v", err) + } + + var oc OrderedCollection + if err := json.NewDecoder(fin).Decode(&oc); err != nil { + log.Fatal(err) + } + + slog.Info("found items", "count", oc.TotalItems) + + var out []Object + + for _, item := range oc.OrderedItems { + slog.Debug("found item", "type", item.Type) + + if item.Type == "Announce" { + continue + } + + var obj Object + if err := json.Unmarshal(item.Object, &obj); err != nil { + log.Fatal(err) + } + + if obj.InReplyTo != nil { + continue + } + + text, err := mastosan.Text(ctx, obj.Content) + if err != nil { + log.Fatal(err) + } + + if strings.HasPrefix(text, "@") { + continue + } + + if uniseg.GraphemeClusterCount(text) > 300 { + continue + } + + if obj.Published.Before(after) { + continue + } + + skip := false + for _, att := range obj.Attachment { + if !strings.HasPrefix(att.URL, "image/") { + skip = true + } + } + + if skip { + continue + } + + obj.Content = text + + slog.Debug("found post", "text", text, "published", obj.Published) + + out = append(out, obj) + } + + slog.Info("found candidate posts for migration", "len", len(out)) + + t := time.NewTicker(5 * time.Second) + defer t.Stop() + + for _, obj := range out { + <-t.C + + slog.Info("migrating post", "post", obj) + + pb := bskybot.NewPostBuilder(obj.Content). + AtTime(obj.Published) + + if len(obj.Attachment) != 0 { + var blobs []lexutil.LexBlob + var images []bskybot.Image + for _, att := range obj.Attachment { + att.URL = strings.TrimPrefix(att.URL, "/interlinked-mst3k") + fname := filepath.Join(dir, att.URL) + + st, err := os.Stat(fname) + if err != nil { + log.Fatalf("can't stat file: %v", err) + } + if st.Size() >= 976560 { + fname, err = convertToJPG(fname) + if err != nil { + log.Fatalf("can't convert to jpeg: %v", err) + } + } + + fin, err := os.Open(fname) + if err != nil { + log.Fatalf("can't open file: %v", err) + } + + resp, err := atproto.RepoUploadBlob(ctx, agent.Client(), fin) + if err != nil { + log.Fatalf("can't upload blob: %v", err) + } + + blobs = append(blobs, lexutil.LexBlob{ + Ref: resp.Blob.Ref, + MimeType: resp.Blob.MimeType, + Size: resp.Blob.Size, + }) + images = append(images, bskybot.Image{}) + } + + pb = pb.WithImages(blobs, images) + } + + post, err := pb.Build() + if err != nil { + log.Fatalf("can't build post: %v", err) + } + + cid, uri, err := agent.PostToFeed(ctx, post) + if err != nil { + log.Fatalf("can't post to feed: %v", err) + } + + pathSp := strings.Split(uri, "/") + id := pathSp[len(pathSp)-1] + + postURL := fmt.Sprintf("https://bsky.app/profile/%s/post/%s", *bskyHandle, id) + + slog.Info("reposted old post", "at", obj.Published, "cid", cid, "uri", uri, "url", postURL) + } +} + +type OrderedCollection struct { + TotalItems int `json:"totalItems"` + OrderedItems []Item `json:"orderedItems"` +} + +type Item struct { + Type string `json:"type"` + Object json.RawMessage `json:"object"` +} + +type Object struct { + ID string `json:"id"` + To []string `json:"to"` + CC []string `json:"cc"` + InReplyTo *string `json:"inReplyTo"` + Published time.Time `json:"published"` + Content string `json:"content"` + Attachment []Attachment `json:"attachment"` + DirectMessage bool `json:"directMessage"` +} + +type Attachment struct { + MediaType string `json:"mediaType"` + URL string `json:"url"` + Name string `json:"name"` +} + +func convertToJPG(fname string) (string, error) { + fin, err := os.Open(fname) + if err != nil { + return "", fmt.Errorf("failed to open %s: %w", fname, err) + } + defer fin.Close() + + img, _, err := image.Decode(fin) + if err != nil { + return "", fmt.Errorf("failed to decode PNG file: %w", err) + } + + outFileName := fname[:len(fname)-len(filepath.Ext(fname))] + ".jpeg" + outFile, err := os.Create(outFileName) + if err != nil { + return "", fmt.Errorf("failed to create JPEG file: %w", err) + } + defer outFile.Close() + + options := jpeg.Options{Quality: 85} + if err := jpeg.Encode(outFile, img, &options); err != nil { + return "", fmt.Errorf("failed to encode JPEG file: %w", err) + } + + return outFileName, nil +} diff --git a/cmd/stickers/data/error.avif b/cmd/stickers/data/error.avif Binary files differnew file mode 100644 index 0000000..505da03 --- /dev/null +++ b/cmd/stickers/data/error.avif diff --git a/cmd/stickers/data/error.jxl b/cmd/stickers/data/error.jxl Binary files differnew file mode 100644 index 0000000..cb6cf89 --- /dev/null +++ b/cmd/stickers/data/error.jxl diff --git a/cmd/stickers/data/error.png b/cmd/stickers/data/error.png Binary files differnew file mode 100644 index 0000000..3143cdf --- /dev/null +++ b/cmd/stickers/data/error.png diff --git a/cmd/stickers/data/error.webp b/cmd/stickers/data/error.webp Binary files differnew file mode 100644 index 0000000..ebd4604 --- /dev/null +++ b/cmd/stickers/data/error.webp diff --git a/cmd/stickers/data/not_found.avif b/cmd/stickers/data/not_found.avif Binary files differnew file mode 100644 index 0000000..fa2e6de --- /dev/null +++ b/cmd/stickers/data/not_found.avif diff --git a/cmd/stickers/data/not_found.jxl b/cmd/stickers/data/not_found.jxl Binary files differnew file mode 100644 index 0000000..f7cc7df --- /dev/null +++ b/cmd/stickers/data/not_found.jxl diff --git a/cmd/stickers/data/not_found.png b/cmd/stickers/data/not_found.png Binary files differnew file mode 100644 index 0000000..043e0d0 --- /dev/null +++ b/cmd/stickers/data/not_found.png diff --git a/cmd/stickers/data/not_found.webp b/cmd/stickers/data/not_found.webp Binary files differnew file mode 100644 index 0000000..42188fb --- /dev/null +++ b/cmd/stickers/data/not_found.webp diff --git a/cmd/stickers/main.go b/cmd/stickers/main.go new file mode 100644 index 0000000..67f1e83 --- /dev/null +++ b/cmd/stickers/main.go @@ -0,0 +1,160 @@ +package main + +import ( + "context" + "embed" + "flag" + "fmt" + "log" + "log/slog" + "net/http" + "strings" + "sync" + "time" + + "github.com/a-h/templ" + "github.com/aws/aws-sdk-go-v2/aws" + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + awsConfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/s3" + "within.website/x/htmx" + "within.website/x/internal" + "within.website/x/xess" +) + +//go:generate go run github.com/a-h/templ/cmd/templ@latest generate + +var ( + bind = flag.String("bind", ":3923", "TCP address to bind to") + bucketName = flag.String("bucket-name", "xedn", "Bucket to pull from") + folderName = flag.String("folder-name", "stickers", "Folder name for stickers") + + //go:embed data/* + static embed.FS + + cache = map[string]struct{}{} + cacheLock = sync.RWMutex{} +) + +func main() { + internal.HandleStartup() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + cfg, err := awsConfig.LoadDefaultConfig(ctx) + if err != nil { + log.Fatal(err) + } + + s3c := s3.NewFromConfig(cfg, func(o *s3.Options) { + o.UsePathStyle = true + }) + + presigner := Presigner{s3.NewPresignClient(s3c)} + _ = presigner + + mux := http.NewServeMux() + htmx.Mount(mux) + xess.Mount(mux) + + mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { + character := r.FormValue("character") + mood := r.FormValue("mood") + + templ.Handler( + xess.Simple("Sticker Tester", index(character, mood)), + ).ServeHTTP(w, r) + }) + + mux.HandleFunc("GET /sticker/{name}/{mood}", func(w http.ResponseWriter, r *http.R |
