From 23c64aebf57b3a9f9db4c08af001f01af25d732d Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 30 Oct 2022 18:24:09 -0400 Subject: various site updates Signed-off-by: Xe Iaso --- Cargo.lock | 25 +- blog/site-update-mastodon-quoting.markdown | 288 +++++++++++++++++++++ css/shim.css | 1 - ...cb22bdb05c57349b4352beae02be2670da2e6c8590.json | 45 ++++ ...6270918803fd7f085d481aec3ce468332a7511cae8.json | 48 ++++ ...92137727af84d85269b148131c2d87b5c1009f4653.json | 41 +++ ...569c3e568cf57ccf8967da18c8483cf0825812e1fa.json | 58 +++++ ...f913685f6e8479db6096355aa8c217c66c3e120be3.json | 28 -- ...7d019f6ebd33cf39aa11e3d3be3d55c77a8af08b7c.json | 52 ++++ ...c2763e562c3550548beea94f4fbf5cddc05b7840d8.json | 44 ++++ ...f913685f6e8479db6096355aa8c217c66c3e120be3.json | 28 ++ ...44100a5bdc96c302040fe7bd4e83786cd4c5c745a5.json | 28 ++ lib/xesite_markdown/Cargo.toml | 6 +- lib/xesite_markdown/src/lib.rs | 38 +++ lib/xesite_templates/src/lib.rs | 55 ++-- lib/xesite_types/src/mastodon.rs | 3 + src/bin/fetch_mastodon_post.rs | 9 +- src/lib.rs | 8 +- src/main.rs | 8 +- static/cal/xe-iaso-sonic-frontiers-20221108.ics | 23 ++ 20 files changed, 768 insertions(+), 68 deletions(-) create mode 100644 blog/site-update-mastodon-quoting.markdown create mode 100644 data/toots/26a47495344ae9abcc3549cb22bdb05c57349b4352beae02be2670da2e6c8590.json create mode 100644 data/toots/463700a6f44864ee12834d6270918803fd7f085d481aec3ce468332a7511cae8.json create mode 100644 data/toots/67a981a0e102091b1108bb92137727af84d85269b148131c2d87b5c1009f4653.json create mode 100644 data/toots/7fe5a624b9adfd99f1474d569c3e568cf57ccf8967da18c8483cf0825812e1fa.json delete mode 100644 data/toots/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json create mode 100644 data/toots/e92cfe06c03596bbdc2fd67d019f6ebd33cf39aa11e3d3be3d55c77a8af08b7c.json create mode 100644 data/toots/fbd9477545b8e09fea6e81c2763e562c3550548beea94f4fbf5cddc05b7840d8.json create mode 100644 data/users/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json create mode 100644 data/users/e319aa8f1597474805ea0344100a5bdc96c302040fe7bd4e83786cd4c5c745a5.json create mode 100644 static/cal/xe-iaso-sonic-frontiers-20221108.ics diff --git a/Cargo.lock b/Cargo.lock index dadbcee..4e0ea15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -606,7 +606,7 @@ dependencies = [ "reqwest", "serde", "serde_cbor", - "sha2", + "sha2 0.9.9", "url", ] @@ -641,9 +641,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ "block-buffer 0.10.2", "crypto-common", @@ -2498,7 +2498,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -2514,6 +2514,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.5", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -3404,7 +3415,7 @@ dependencies = [ "serde_dhall", "serde_json", "serde_yaml", - "sha2", + "sha2 0.9.9", "sitemap", "thiserror", "tokio", @@ -3429,13 +3440,17 @@ version = "0.1.0" dependencies = [ "color-eyre", "comrak", + "hex", "lazy_static", "lol_html", "maud", + "serde_json", + "sha2 0.10.6", "thiserror", "tracing", "url", "xesite_templates", + "xesite_types", ] [[package]] diff --git a/blog/site-update-mastodon-quoting.markdown b/blog/site-update-mastodon-quoting.markdown new file mode 100644 index 0000000..72bb865 --- /dev/null +++ b/blog/site-update-mastodon-quoting.markdown @@ -0,0 +1,288 @@ +--- +title: "Various site updates" +date: 2022-10-30 +tags: + - mastodon + - stream + - sonicfrontiers + - robocadey + - noxp +--- + + + +Hey all, just some smaller updates on my site and the infrastructure around this +blog. I'm also throwing in some of my smaller project updates that I haven't +gotten to on the blog. + +## Sonic Frontiers stream + +I'm going to be streaming the game [Sonic +Frontiers](https://frontiers.sonicthehedgehog.com/) on +[Twitch](https://twitch.tv/princessxen) on November 8th, 2022 at 10:00 EDT +through at least 12:00 EDT. I may go longer depending on how the game is, but I +took the day off for this so I may as well take advantage of it. + +If you want to add this to your calendar, you can either import [the ICS file +for the +event](https://xeiaso.net/static/cal/xe-iaso-sonic-frontiers-20221108.ics) or +[add it to Google +Calendar](https://www.google.com/calendar/render?action=TEMPLATE&text=Xe%20streams%20Sonic%20Frontiers&dates=20221108T150000Z%2F20221108T170000Z&details=Xe%20Iaso%20streams%20first%20impressions%20and%20gameplay%20of%20Sonic%20Frontiers!%20Grab%20some%20chips%20and%20soda.%20We're%20gonna%20explore%20the%20open%20zone%20and%20see%20if%20it%20lives%20up%20to%20the%20promises%20of%20an%20open%20world%20Sonic%20game.%20It'll%20be%20a%20blast!&location=https%3A%2F%2Ftwitch.tv%2Fprincessxen). +This is my first time pre-announcing a stream like this and I hope that this +will be worth it. + + + +## Mastodon quoting + +One of the big things I've done is add support for embedding mastodon posts in a +more native way. Mastodon normally has an "embed this post" link, which makes +things look like this: + + + +However, I think I can do it better. I wrote some code to serialize the mastodon +post information to JSON on the disk and then I can render out toots like this: + + + +It also works with embedded videos: + + + +I think this looks much cleaner. It also puts a lot less load on the Mastodon +server that I use, which will certainly make Cult Pony happier. + +This works by putting the mastodon data into `.json` files that I ship around +with both my site's git repo and the runtime closure of my website binary. When +the HTML parser sees one of these tags: + +``` + +``` + +It looks up that toot's information on the disk and then renders that into +memory. This allows me to ensure all this information is _not_ fetched from the +target Mastodon server on every page load, which should help with reducing load +on the fediverse servers that I link to. + +## Ads enabled globally + +Previously I only enabled ads for users visiting my blog from [Hacker +News](https://news.ycombinator.com) and [Reddit](https://reddit.com). These ads +are done with [Ethical Ads](https://www.ethicalads.io/), which is done by the +people behind the popular documentation service [Read the +Docs](https://readthedocs.org/). + +I want to stress the following things: + +- The income that I get from the advertisements is being used to fund the + infrastructure for this website and other hilarious projects I have in the + pipeline, just like the Patreon. +- You can use an ad blocker all you want. The only thing that will happen is + that you will see a "nag message" that gently asks you to not as well as + linking to my Patreon. I have no way of tracking who actually blocks ads. +- I have identified a few websites that I think are cool in an attempt to _not_ + show ads when you visit from them, but the main one that I wanted to get + working with this ([Lobsters](https://lobste.rs)) appears to only sometimes + give out referrer information in an effort to discourage content marketing. I + am going to come up with an alternative workaround for Lobsters users to view + my posts without advertising income. +- It turns out hosting video is kinda expensive. + +I am working on an integration with Patreon that allows patrons to bypass ads +from being shown in the blog. I have also been considering having other features +like commenting on posts, but for right now I am focusing on other things. + +## Robocadey 2: Stable Diffusion edition + +Recently I created a project named +[robocadey](https://xeiaso.net/blog/robocadey-2022-04-30). This took all of my +tweets, fed them into GPT-2 and then generated new tweets. This worked for a +while, but then things fell apart due to python catastrophes and I never was +able to get things working again. + +Don't worry, because I have created a _brand new python catastrophe_ using +[Stable Diffusion](https://en.wikipedia.org/wiki/Stable_Diffusion). More +specifically using a variant of the Stable Diffusion model named [Waifu +Diffusion](https://gist.github.com/harubaru/f727cedacae336d1f7877c4bbe2196e1). +Waifu Diffusion is the model that you see in most of my blog's hero images. +Scrying an image out of Waifu Diffusion is similar to searching +[danbooru](https://danbooru.donmai.us/) (warning, NSFW images) for images. + +To use Robocadey 2, all you need to do is mention +[@robocadey@pony.social](https://pony.social/@robocadey) with a set of tags. For +example, this input: + + + +Will get you this output: + + + +Please do feel free to experiment with this. Keep in mind that it can only +process one image at a time (the poor 2060 in `ontos` only has enough vram to do +one image at a time), so depending on load you may have to wait your turn. + +I'm not sure if this is a _bug_ or a _feature_, but if you reply to the bot, +it'll also take that as input to generate new images: + + + +You can find the source code +[here](https://github.com/Xe/x/tree/master/mastodon/robocadey2). This is not in +a state that is ready for other people to use though. I don't expect it to ever +get in such a state. This is an experiment that will some day stop working and +that's okay. + +Be sure to save images that you really like, the bot account is configured to +autodelete generated images after two weeks. This means that the images in my +post are going to eventually go dead too, but that's okay. + +## Mastodon as my main microblogging outlet + +I am really not getting good vibes with the results of Elon Musk purchasing +Twitter. I'm starting to post more on Mastodon at +[@cadey@pony.social](https://pony.social/@cadey) instead. I currently have [a +reposting service](https://moa.party) set up to ferry posts between Mastodon and +Twitter, but there is a significant delay when things get reposted. If you want +things more expediently, I suggest you follow me on Mastodon. + +If you see the `#noxp` hashtag in either +my Twitter or Mastodon posts, the reason it is there is to stop the reposting +service from reposting things. + +## I made a LinkedIn + +I have given in and created a [LinkedIn +account](https://www.linkedin.com/in/xe-iaso-87a883254/). I really don't like +how LinkedIn traps a lot of information about people, and how that information +is used by attackers in order to social engineer people better. But, most of the +industry expects you to have one. If I have to have one, then at least I want to +do it "right". I'll be reposting my blog content there. + +## API endpoints + +I have created a few small API endpoints for the blog. They allow you to get +information about the most recent post on the blog as well as more detailed +information on individual posts. I am considering these endpoints _stable_ and I +am working hard to make sure that the API compatibility will not break in future +releases without proper warning. + +These API calls don't have rate limits currently, but please don't be the person +that makes me have to add them. + +### `/api/new_post` + +This returns information about the most recent post to my blog. This will return +a JSON object that contains at least the following fields: + +- **title** - The title of the post +- **summary** - Either a human-readable summary of the post or the description + of the estimated read time of the post +- **link** - The link to the post + +Here is an example (piped through `jq`): + +```json +{ + "title": "How to make NixOS compile nginx with OpenSSL 1.x", + "summary": "3 minute read", + "link": "https://xeiaso.net/blog/nixos-nginx-openssl-1.x" +} +``` + +### `/api/[blog|talks]/{slug}` + +This returns information on a blog post by URL slug. In the blogpost URL +`https://xeiaso.net/blog/nixos-nginx-openssl-1.x`, the slug is the +`nixos-nginx-openssl-1.x` part. This returns the [JSON Feed +Item](https://www.jsonfeed.org/version/1.1/#items-a-name-items-a) form of the +blogpost or talk summary in question. + +This also includes a custom `_xesite_frontmatter` extension that will contain at +least this information: + +* `about` (required, string) is a link to [the documentation for the extension + in my blog's GitHub + repository](https://github.com/Xe/site/blob/main/docs/jsonfeed_extensions.markdown#_xesite_frontmatter). + It gives readers of the JSON Feed information about what this extension does. + This is for informational purposes only and can safely be ignored by programs. +* `series` (optional, string) is the optional blogpost series name that this + item belongs to. When I post multiple posts about the same topic, I will + usually set the `series` to the same value so that it is more discoverable [on + my series index page](https://xeiaso.net/blog/series). +* `slides_link` (optional, string) is a link to the PDF containing the slides + for a given talk. This is always set on talks, but is technically optional + because not everything I do is a talk. +* `vod` (optional, string) is an object that describes where you can watch the + Video On Demand (vod) for the writing process of a post. When populated, this + is an object that always contains the string fields `twitch` and `youtube`. + These will be URLs to the videos so that you can watch them on demand. + +I reserve the right to add fields to this in the future, but when I do I will +update the documentation accordingly. + +## XeDN video metrics plans + +I'm considering adding some Xeact-powered JavaScript to allow me to track +events on the video I'm hosting on my own infrastructure. My intent is to +create some grafana graphs to track the following events: + +- The video being watched to completion +- The video load being stalled +- The video is able to be played +- If [HTTP Live Streaming](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) + works + +I also plan to surface some of these metrics on the blog itself, namely having +the video being watched to completion function as a proxy for the view count +metric on YouTube. + +## Updates on longer projects + +This is going to have some smaller updates that aren't worth their own sections. + +- I am researching part 2 of [my Bitcoin/Ethereum + article](https://xeiaso.net/blog/cryptocurrency-ownership) that I'll be + writing with Open Skies again. We plan to have this article cover smart + contracts, how to use them, why you would want to use them, and what problems + they have when they intersect with the "real world". At this point I'm almost + certain that calling them "contracts" is a misnomer that is misleading enough + to be observably harmful. +- waifud is still in progress, I am currently stalled on the metadata API. I + can't figure out how to make the libvirt virtual machine connect to the new + metadata service `isekaid` without either the flow being rejected or libvirt + NAT-ing the connection. I am trying to get a direct connection to either + `169.254.169.254` or `fc00::da1a` (data) so that virtual machines can use that + to bootstrap cloud-init. If anyone has ideas, please [contact me](/contact). I + hope to have this usable for other people by the end of the year. Please let + me know if you want to be an early beta tester. +- I have been planning out ideas for a completely AI generated image booru like + danbooru, e621, Derpibooru or Furbooru. I want to create this as a + demonstration of what image generation technology _could be able to do_ if + this technology was a bit more efficient. I don't expect this to be ready any + time soon, and when it is ready I will likely be limiting it heavily. +- [XeDN](https://xeiaso.net/blog/xedn) needs to be rewritten to have a better + caching strategy. Right now it _does_ work but it has a slight habit of + totally falling over at the worst possible times. Browsers retry things, so + it's not realistically as bad as you'd think. +- My blog is built using Nix flakes now. I need to finish migrating my last + cloud server over to flakes. +- My blog is being served with LibreSSL instead of OpenSSL 3.x. I plan to write + about how you can use `system.replaceRuntimeDependencies` to mitigate the + OpenSSL vulnerability with the patched version of OpenSSL on Tuesday, when the + patch is released. I don't know if the OpenSSL bug is going to be super bad, + but if it is then I get to show off a neat trick with NixOS so it's win/win in + my book. + +--- + +And that's what's going on in my world! Hope this was an interesting look into +all of the things that I'm tinkering with and working on for my personal +projects. Hopefully things will settle down once I get someone to [help me do +DevRel at Tailscale](https://boards.greenhouse.io/tailscale/jobs/4093171005). +I've hit a point where I'm not able to do everything on my own anymore and if +you want to help make things happen, please apply to that role. + +Be well! diff --git a/css/shim.css b/css/shim.css index 59ff866..452b8e9 100644 --- a/css/shim.css +++ b/css/shim.css @@ -16,7 +16,6 @@ footer.footer { img { max-width: 100%; - padding: 1em; } .conversation { diff --git a/data/toots/26a47495344ae9abcc3549cb22bdb05c57349b4352beae02be2670da2e6c8590.json b/data/toots/26a47495344ae9abcc3549cb22bdb05c57349b4352beae02be2670da2e6c8590.json new file mode 100644 index 0000000..f7d5fc9 --- /dev/null +++ b/data/toots/26a47495344ae9abcc3549cb22bdb05c57349b4352beae02be2670da2e6c8590.json @@ -0,0 +1,45 @@ +{ + "id": "https://pony.social/users/cadey/statuses/109259252694255124", + "type": "Note", + "inReplyTo": null, + "published": "2022-10-30T21:04:49Z", + "url": "https://pony.social/@cadey/109259252694255124", + "attributedTo": "https://pony.social/users/cadey", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://pony.social/users/cadey/followers" + ], + "sensitive": false, + "atomUri": "https://pony.social/users/cadey/statuses/109259252694255124", + "inReplyToAtomUri": null, + "conversation": "tag:pony.social,2022-10-30:objectId=5765482:objectType=Conversation", + "summary": null, + "content": "

Do you like "video games"? I'm going to be playing Sonic Frontiers on Twitch on its release date! Check it out at https://twitch.tv/princessxen on Tuesday, November 8th at 10:00 Eastern through at least 12:00 Eastern.

", + "contentMap": { + "en": "

Do you like "video games"? I'm going to be playing Sonic Frontiers on Twitch on its release date! Check it out at https://twitch.tv/princessxen on Tuesday, November 8th at 10:00 Eastern through at least 12:00 Eastern.

" + }, + "attachment": [ + { + "type": "Document", + "mediaType": "image/png", + "url": "https://cdn.pony.social/file/tscs37-pony-social/media_attachments/files/109/259/245/365/537/945/original/3c9a9e0a85aed522.png", + "name": "The text \"Xe Iaso Plays Sonic Frontiers, tuesday November 8th 10:00 Eastern time twitch.tv/princessxen\" superimposed over an AI generated landscape with a foxgirl surfing on some shallow waves.", + "blurhash": "UGEp]0oct7M|,[IUxtbc0NMyt6tRtSR-Rjof", + "width": 520, + "height": 292 + } + ], + "tag": [], + "replies": { + "id": "https://pony.social/users/cadey/statuses/109259252694255124/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://pony.social/users/cadey/statuses/109259252694255124/replies?only_other_accounts=true&page=true", + "partOf": "https://pony.social/users/cadey/statuses/109259252694255124/replies", + "items": [] + } + } +} \ No newline at end of file diff --git a/data/toots/463700a6f44864ee12834d6270918803fd7f085d481aec3ce468332a7511cae8.json b/data/toots/463700a6f44864ee12834d6270918803fd7f085d481aec3ce468332a7511cae8.json new file mode 100644 index 0000000..1bf7797 --- /dev/null +++ b/data/toots/463700a6f44864ee12834d6270918803fd7f085d481aec3ce468332a7511cae8.json @@ -0,0 +1,48 @@ +{ + "id": "https://toot.cat/users/dee/statuses/109259172259261888", + "type": "Note", + "inReplyTo": "https://pony.social/users/robocadey/statuses/109259067844671412", + "published": "2022-10-30T20:44:22Z", + "url": "https://toot.cat/@dee/109259172259261888", + "attributedTo": "https://toot.cat/users/dee", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://toot.cat/users/dee/followers", + "https://pony.social/users/robocadey", + "https://pony.social/users/cadey" + ], + "sensitive": true, + "atomUri": "https://toot.cat/users/dee/statuses/109259172259261888", + "inReplyToAtomUri": "https://pony.social/users/robocadey/statuses/109259067844671412", + "conversation": "tag:pony.social,2022-10-30:objectId=5765139:objectType=Conversation", + "summary": "AI generated image (can be NSFW)", + "content": "

@robocadey @cadey that's really well done. Your prompt is a good 'un

", + "contentMap": { + "en": "

@robocadey @cadey that's really well done. Your prompt is a good 'un

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "https://pony.social/users/robocadey", + "name": "@robocadey@pony.social" + }, + { + "type": "Mention", + "href": "https://pony.social/users/cadey", + "name": "@cadey@pony.social" + } + ], + "replies": { + "id": "https://toot.cat/users/dee/statuses/109259172259261888/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://toot.cat/users/dee/statuses/109259172259261888/replies?only_other_accounts=true&page=true", + "partOf": "https://toot.cat/users/dee/statuses/109259172259261888/replies", + "items": [] + } + } +} \ No newline at end of file diff --git a/data/toots/67a981a0e102091b1108bb92137727af84d85269b148131c2d87b5c1009f4653.json b/data/toots/67a981a0e102091b1108bb92137727af84d85269b148131c2d87b5c1009f4653.json new file mode 100644 index 0000000..753870e --- /dev/null +++ b/data/toots/67a981a0e102091b1108bb92137727af84d85269b148131c2d87b5c1009f4653.json @@ -0,0 +1,41 @@ +{ + "id": "https://pony.social/users/cadey/statuses/109259064905977430", + "type": "Note", + "inReplyTo": null, + "published": "2022-10-30T20:17:04Z", + "url": "https://pony.social/@cadey/109259064905977430", + "attributedTo": "https://pony.social/users/cadey", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://pony.social/users/cadey/followers", + "https://pony.social/users/robocadey" + ], + "sensitive": false, + "atomUri": "https://pony.social/users/cadey/statuses/109259064905977430", + "inReplyToAtomUri": null, + "conversation": "tag:pony.social,2022-10-30:objectId=5765139:objectType=Conversation", + "content": "

@robocadey 1girl, cute, solo, portrait, brown hair, brown eyes, long hair, smile, blush, laptop, coffee shop, katana

", + "contentMap": { + "en": "

@robocadey 1girl, cute, solo, portrait, brown hair, brown eyes, long hair, smile, blush, laptop, coffee shop, katana

" + }, + "attachment": [], + "tag": [ + { + "type": "Mention", + "href": "https://pony.social/users/robocadey", + "name": "@robocadey" + } + ], + "replies": { + "id": "https://pony.social/users/cadey/statuses/109259064905977430/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://pony.social/users/cadey/statuses/109259064905977430/replies?only_other_accounts=true&page=true", + "partOf": "https://pony.social/users/cadey/statuses/109259064905977430/replies", + "items": [] + } + } +} \ No newline at end of file diff --git a/data/toots/7fe5a624b9adfd99f1474d569c3e568cf57ccf8967da18c8483cf0825812e1fa.json b/data/toots/7fe5a624b9adfd99f1474d569c3e568cf57ccf8967da18c8483cf0825812e1fa.json new file mode 100644 index 0000000..1ddca15 --- /dev/null +++ b/data/toots/7fe5a624b9adfd99f1474d569c3e568cf57ccf8967da18c8483cf0825812e1fa.json @@ -0,0 +1,58 @@ +{ + "id": "https://pony.social/users/robocadey/statuses/109259173707928134", + "type": "Note", + "inReplyTo": "https://toot.cat/users/dee/statuses/109259172259261888", + "published": "2022-10-30T20:44:44Z", + "url": "https://pony.social/@robocadey/109259173707928134", + "attributedTo": "https://pony.social/users/robocadey", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://pony.social/users/robocadey/followers", + "https://toot.cat/users/dee", + "https://pony.social/users/cadey" + ], + "sensitive": true, + "atomUri": "https://pony.social/users/robocadey/statuses/109259173707928134", + "inReplyToAtomUri": "https://toot.cat/users/dee/statuses/109259172259261888", + "conversation": "tag:pony.social,2022-10-30:objectId=5765139:objectType=Conversation", + "summary": "AI generated image (can be NSFW)", + "content": "

@dee @cadey here is your image:

prompt: that's really well done. Your prompt is a good 'un
seed: 2139947102
Generated with Waifu Diffusion v1.3 (float16)

", + "contentMap": { + "en": "

@dee @cadey here is your image:

prompt: that's really well done. Your prompt is a good 'un
seed: 2139947102
Generated with Waifu Diffusion v1.3 (float16)

" + }, + "attachment": [ + { + "type": "Document", + "mediaType": "image/png", + "url": "https://cdn.pony.social/file/tscs37-pony-social/media_attachments/files/109/259/173/389/855/540/original/c9faa27412aa177a.png", + "name": "Waifu Diffusion v1.3 with the prompt: that's really well done. Your prompt is a good 'un", + "blurhash": "UHK_B_008_9FRi%MM{t7%Lj]WBj@t7ayf7fP", + "width": 512, + "height": 512 + } + ], + "tag": [ + { + "type": "Mention", + "href": "https://toot.cat/users/dee", + "name": "@dee@toot.cat" + }, + { + "type": "Mention", + "href": "https://pony.social/users/cadey", + "name": "@cadey" + } + ], + "replies": { + "id": "https://pony.social/users/robocadey/statuses/109259173707928134/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://pony.social/users/robocadey/statuses/109259173707928134/replies?only_other_accounts=true&page=true", + "partOf": "https://pony.social/users/robocadey/statuses/109259173707928134/replies", + "items": [] + } + } +} \ No newline at end of file diff --git a/data/toots/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json b/data/toots/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json deleted file mode 100644 index 15e8f2a..0000000 --- a/data/toots/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "https://pony.social/users/cadey", - "type": "Person", - "following": "https://pony.social/users/cadey/following", - "followers": "https://pony.social/users/cadey/followers", - "inbox": "https://pony.social/users/cadey/inbox", - "outbox": "https://pony.social/users/cadey/outbox", - "featured": "https://pony.social/users/cadey/collections/featured", - "featuredTags": "https://pony.social/users/cadey/collections/tags", - "preferredUsername": "cadey", - "name": "Xe", - "summary": "

🔞 Minors, please DNI

Any statements are my own, not my employer's

Archmage of Infrastructure at that VPN company that isn't actually a VPN company I guess it's complicated

ΘΔ

zi ai-uh-so /zi ai.É™.soÊŠ/

", - "url": "https://pony.social/@cadey", - "manuallyApprovesFollowers": false, - "discoverable": true, - "published": "2021-06-30T00:00:00Z", - "devices": "https://pony.social/users/cadey/collections/devices", - "icon": { - "type": "Image", - "mediaType": "image/png", - "url": "https://cdn.pony.social/file/tscs37-pony-social/accounts/avatars/106/500/315/995/032/015/original/056011b7379c0ecc.png" - }, - "image": { - "type": "Image", - "mediaType": "image/jpeg", - "url": "https://cdn.pony.social/file/tscs37-pony-social/accounts/headers/106/500/315/995/032/015/original/d32327b86f0038ee.jpeg" - } -} \ No newline at end of file diff --git a/data/toots/e92cfe06c03596bbdc2fd67d019f6ebd33cf39aa11e3d3be3d55c77a8af08b7c.json b/data/toots/e92cfe06c03596bbdc2fd67d019f6ebd33cf39aa11e3d3be3d55c77a8af08b7c.json new file mode 100644 index 0000000..4f418c5 --- /dev/null +++ b/data/toots/e92cfe06c03596bbdc2fd67d019f6ebd33cf39aa11e3d3be3d55c77a8af08b7c.json @@ -0,0 +1,52 @@ +{ + "id": "https://pony.social/users/robocadey/statuses/109259067844671412", + "type": "Note", + "inReplyTo": "https://pony.social/users/cadey/statuses/109259064905977430", + "published": "2022-10-30T20:17:49Z", + "url": "https://pony.social/@robocadey/109259067844671412", + "attributedTo": "https://pony.social/users/robocadey", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://pony.social/users/robocadey/followers", + "https://pony.social/users/cadey" + ], + "sensitive": true, + "atomUri": "https://pony.social/users/robocadey/statuses/109259067844671412", + "inReplyToAtomUri": "https://pony.social/users/cadey/statuses/109259064905977430", + "conversation": "tag:pony.social,2022-10-30:objectId=5765139:objectType=Conversation", + "summary": "AI generated image (can be NSFW)", + "content": "

@cadey here is your image:

prompt: 1girl, cute, solo, portrait, brown hair, brown eyes, long hair, smile, blush, laptop, coffee shop, katana
seed: 1099521048
Generated with Waifu Diffusion v1.3 (float16)

", + "contentMap": { + "en": "

@cadey here is your image:

prompt: 1girl, cute, solo, portrait, brown hair, brown eyes, long hair, smile, blush, laptop, coffee shop, katana
seed: 1099521048
Generated with Waifu Diffusion v1.3 (float16)

" + }, + "attachment": [ + { + "type": "Document", + "mediaType": "image/png", + "url": "https://cdn.pony.social/file/tscs37-pony-social/media_attachments/files/109/259/067/516/262/384/original/b969dbb69fae4f93.png", + "name": "Waifu Diffusion v1.3 with the prompt: 1girl, cute, solo, portrait, brown hair, brown eyes, long hair, smile, blush, laptop, coffee shop, katana", + "blurhash": "UIHUX+%iyCNv%fM|xuaJ0KkCM|xZDiWAITIp", + "width": 512, + "height": 512 + } + ], + "tag": [ + { + "type": "Mention", + "href": "https://pony.social/users/cadey", + "name": "@cadey" + } + ], + "replies": { + "id": "https://pony.social/users/robocadey/statuses/109259067844671412/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://pony.social/users/robocadey/statuses/109259067844671412/replies?only_other_accounts=true&page=true", + "partOf": "https://pony.social/users/robocadey/statuses/109259067844671412/replies", + "items": [] + } + } +} \ No newline at end of file diff --git a/data/toots/fbd9477545b8e09fea6e81c2763e562c3550548beea94f4fbf5cddc05b7840d8.json b/data/toots/fbd9477545b8e09fea6e81c2763e562c3550548beea94f4fbf5cddc05b7840d8.json new file mode 100644 index 0000000..607be43 --- /dev/null +++ b/data/toots/fbd9477545b8e09fea6e81c2763e562c3550548beea94f4fbf5cddc05b7840d8.json @@ -0,0 +1,44 @@ +{ + "id": "https://pony.social/users/cadey/statuses/109242201983408404", + "type": "Note", + "inReplyTo": null, + "published": "2022-10-27T20:48:36Z", + "url": "https://pony.social/@cadey/109242201983408404", + "attributedTo": "https://pony.social/users/cadey", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://pony.social/users/cadey/followers" + ], + "sensitive": false, + "atomUri": "https://pony.social/users/cadey/statuses/109242201983408404", + "inReplyToAtomUri": null, + "conversation": "tag:pony.social,2022-10-27:objectId=5737358:objectType=Conversation", + "content": "

This new watch feels great. I love how the pride edition band looks.

", + "contentMap": { + "en": "

This new watch feels great. I love how the pride edition band looks.

" + }, + "attachment": [ + { + "type": "Document", + "mediaType": "image/jpeg", + "url": "https://cdn.pony.social/file/tscs37-pony-social/media_attachments/files/109/242/197/624/573/230/original/e5a777ad56d3c3b3.jpeg", + "name": "An Apple Watch series 8 with the pride edition band and the time saying \"16:47\"", + "blurhash": "UFEL]Gbwr:V@~qofxtRQ5PMxNMNGMwM{RkNG", + "width": 1247, + "height": 1663 + } + ], + "tag": [], + "replies": { + "id": "https://pony.social/users/cadey/statuses/109242201983408404/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://pony.social/users/cadey/statuses/109242201983408404/replies?only_other_accounts=true&page=true", + "partOf": "https://pony.social/users/cadey/statuses/109242201983408404/replies", + "items": [] + } + } +} \ No newline at end of file diff --git a/data/users/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json b/data/users/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json new file mode 100644 index 0000000..15e8f2a --- /dev/null +++ b/data/users/a83e23736eb81745c08464f913685f6e8479db6096355aa8c217c66c3e120be3.json @@ -0,0 +1,28 @@ +{ + "id": "https://pony.social/users/cadey", + "type": "Person", + "following": "https://pony.social/users/cadey/following", + "followers": "https://pony.social/users/cadey/followers", + "inbox": "https://pony.social/users/cadey/inbox", + "outbox": "https://pony.social/users/cadey/outbox", + "featured": "https://pony.social/users/cadey/collections/featured", + "featuredTags": "https://pony.social/users/cadey/collections/tags", + "preferredUsername": "cadey", + "name": "Xe", + "summary": "

🔞 Minors, please DNI

Any statements are my own, not my employer's

Archmage of Infrastructure at that VPN company that isn't actually a VPN company I guess it's complicated

ΘΔ

zi ai-uh-so /zi ai.É™.soÊŠ/

", + "url": "https://pony.social/@cadey", + "manuallyApprovesFollowers": false, + "discoverable": true, + "published": "2021-06-30T00:00:00Z", + "devices": "https://pony.social/users/cadey/collections/devices", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://cdn.pony.social/file/tscs37-pony-social/accounts/avatars/106/500/315/995/032/015/original/056011b7379c0ecc.png" + }, + "image": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://cdn.pony.social/file/tscs37-pony-social/accounts/headers/106/500/315/995/032/015/original/d32327b86f0038ee.jpeg" + } +} \ No newline at end of file diff --git a/data/users/e319aa8f1597474805ea0344100a5bdc96c302040fe7bd4e83786cd4c5c745a5.json b/data/users/e319aa8f1597474805ea0344100a5bdc96c302040fe7bd4e83786cd4c5c745a5.json new file mode 100644 index 0000000..70a8aef --- /dev/null +++ b/data/users/e319aa8f1597474805ea0344100a5bdc96c302040fe7bd4e83786cd4c5c745a5.json @@ -0,0 +1,28 @@ +{ + "id": "https://pony.social/users/robocadey", + "type": "Service", + "following": "https://pony.social/users/robocadey/following", + "followers": "https://pony.social/users/robocadey/followers", + "inbox": "https://pony.social/users/robocadey/inbox", + "outbox": "https://pony.social/users/robocadey/outbox", + "featured": "https://pony.social/users/robocadey/collections/featured", + "featuredTags": "https://pony.social/users/robocadey/collections/tags", + "preferredUsername": "robocadey", + "name": "Robocadey", + "summary": "

Owned by @cadey.

Toots GPT-2 generated shitposts from @theprincessxena@twitter.com tweets along with images created with Waifu Diffusion v1.3

", + "url": "https://pony.social/@robocadey", + "manuallyApprovesFollowers": false, + "discoverable": false, + "published": "2022-10-08T00:00:00Z", + "devices": "https://pony.social/users/robocadey/collections/devices", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://cdn.pony.social/file/tscs37-pony-social/accounts/avatars/109/133/463/176/529/998/original/7231b4900b06513d.png" + }, + "image": { + "type": "Image", + "mediaType": "image/png", + "url": "https://cdn.pony.social/file/tscs37-pony-social/accounts/headers/109/133/463/176/529/998/original/ece50a6e21c9d773.png" + } +} \ No newline at end of file diff --git a/lib/xesite_markdown/Cargo.toml b/lib/xesite_markdown/Cargo.toml index 62eb817..08e196f 100644 --- a/lib/xesite_markdown/Cargo.toml +++ b/lib/xesite_markdown/Cargo.toml @@ -8,12 +8,16 @@ edition = "2021" [dependencies] color-eyre = "0.6" comrak = "0.14.0" +hex = "0.4" lazy_static = "1.4" lol_html = "0.3" maud = "0.23.0" +sha2 = "0.10" +serde_json = "1" thiserror = "1" tracing = "0.1" url = "2" # local deps -xesite_templates = { path = "../xesite_templates" } \ No newline at end of file +xesite_templates = { path = "../xesite_templates" } +xesite_types = { path = "../xesite_types" } \ No newline at end of file diff --git a/lib/xesite_markdown/src/lib.rs b/lib/xesite_markdown/src/lib.rs index fad2b3a..5bd6dfa 100644 --- a/lib/xesite_markdown/src/lib.rs +++ b/lib/xesite_markdown/src/lib.rs @@ -8,8 +8,16 @@ use comrak::{ use lazy_static::lazy_static; use lol_html::{element, html_content::ContentType, rewrite_str, RewriteStrSettings}; use maud::PreEscaped; +use sha2::{Digest, Sha256}; use std::{cell::RefCell, io::Write}; use url::Url; +use xesite_types::mastodon::{Toot, User}; + +pub fn hash_string(inp: String) -> String { + let mut h = Sha256::new(); + h.update(&inp.as_bytes()); + hex::encode(h.finalize()) +} lazy_static! { static ref SYNTECT_ADAPTER: SyntectAdapter<'static> = SyntectAdapter::new("base16-mocha.dark"); @@ -175,6 +183,36 @@ pub fn render(inp: &str) -> Result { el.replace(&xesite_templates::video(path).0, ContentType::Html); Ok(()) }), + #[cfg(not(target_arch = "wasm32"))] + element!("xeblog-toot", |el| { + use serde_json::from_reader; + use std::fs; + + let mut toot_url = el + .get_attribute("url") + .ok_or(Error::MissingElementAttribute("url".to_string()))?; + + if !toot_url.ends_with(".json") { + toot_url = format!("{toot_url}.json"); + } + + let toot_fname = format!("./data/toots/{}.json", hash_string(toot_url)); + tracing::debug!("opening {toot_fname}"); + let mut fin = fs::File::open(&toot_fname)?; + let t: Toot = from_reader(&mut fin)?; + + let user_fname = format!( + "./data/users/{}.json", + hash_string(format!("{}.json", t.attributed_to.clone())) + ); + tracing::debug!("opening {user_fname}"); + let mut fin = fs::File::open(&user_fname)?; + + let u: User = from_reader(&mut fin)?; + + el.replace(&xesite_templates::toot_embed(u, t).0, ContentType::Html); + Ok(()) + }), ], ..RewriteStrSettings::default() }, diff --git a/lib/xesite_templates/src/lib.rs b/lib/xesite_templates/src/lib.rs index b3298d9..333c847 100644 --- a/lib/xesite_templates/src/lib.rs +++ b/lib/xesite_templates/src/lib.rs @@ -168,33 +168,54 @@ pub fn advertiser_nag() -> Markup { } pub fn toot_embed(u: User, t: Toot) -> Markup { + let content = html! { + (PreEscaped::(t.content)) + + @for att in &t.attachment { + @if att.media_type.starts_with("image/") { + a href=(att.url) { + img height=(if att.height > att.width {"480"} else {"100%"}) src=(att.url) alt=(att.name.clone().unwrap_or("no description provided".into())); + } + } + + @if att.media_type.starts_with("video/") { + video width=({att.width / 2}) height=({att.height / 2}) controls { + source src=(att.url) type=(att.media_type); + "Your browser does not support the video tag, see this URL: " + a href=(att.url) {(att.url)} + } + } + } + @if t.attachment.len() != 0 { + br; + } + + a href=(t.url) { "Link" } + }; html! { .media { .media-left { .avatarholder { - img src=(u.icon.url); + img src=(u.icon.url) alt={"the profile picture for " (u.preferred_username)}; } } .media-body { - .media-heading { (u.name) " @" (u.preferred_username) } + .media-heading { + (u.name) + " " + a href=(u.url) {"@" (u.preferred_username)} + br; + (t.published.format("M%m %d %Y %H:%M (UTC)").to_string()) + } .media-content { - (PreEscaped::(t.content)) - - @for att in &t.attachment { - @if att.media_type.starts_with("image/") { - img src=(att.url) alt=(att.name.clone().unwrap_or("no description provided".into())); - } - - @if att.media_type.starts_with("video/") { - video width=(att.width) height=(att.height) controls { - source src=(att.url) type=(att.media_type); - "Your browser does not support the video tag, see this URL: " - a href=(att.url) {(att.url)} - } + @if let Some(warning) = t.summary { + details { + summary { "Content warning: " (warning) } + (content) } + } @else { + (content) } - - a href=(t.url) { "Link" } } } } diff --git a/lib/xesite_types/src/mastodon.rs b/lib/xesite_types/src/mastodon.rs index 4cf1e96..56567e6 100644 --- a/lib/xesite_types/src/mastodon.rs +++ b/lib/xesite_types/src/mastodon.rs @@ -108,6 +108,9 @@ pub struct Toot { #[serde(rename = "conversation")] pub conversation: String, + #[serde(rename = "summary")] + pub summary: Option, + #[serde(rename = "content")] pub content: String, diff --git a/src/bin/fetch_mastodon_post.rs b/src/bin/fetch_mastodon_post.rs index 06faa57..408d90c 100644 --- a/src/bin/fetch_mastodon_post.rs +++ b/src/bin/fetch_mastodon_post.rs @@ -1,5 +1,4 @@ use color_eyre::Result; -use sha2::{Digest, Sha256}; use std::{env, fs}; use tracing::debug; use xesite_types::mastodon::{Toot, User}; @@ -32,10 +31,13 @@ async fn main() -> Result<()> { let post_hash = xesite::hash_string(post_url); + debug!("wrote post to ./data/toots/{post_hash}.json"); + let mut fout = fs::File::create(&format!("./data/toots/{post_hash}.json"))?; serde_json::to_writer_pretty(&mut fout, &toot)?; let user_url = format!("{}.json", toot.attributed_to); + debug!("fetching {user_url} ..."); let user: User = reqwest::get(&user_url) .await? @@ -45,11 +47,12 @@ async fn main() -> Result<()> { fs::create_dir_all("./data/users")?; - debug!("got user {} ({})", user.name, user.preferred_username); + debug!("got user {} ({})", user.preferred_username, user.name); let user_hash = xesite::hash_string(user_url); - let mut fout = fs::File::create(&format!("./data/toots/{user_hash}.json"))?; + debug!("wrote post to ./data/users/{user_hash}.json"); + let mut fout = fs::File::create(&format!("./data/users/{user_hash}.json"))?; serde_json::to_writer_pretty(&mut fout, &user)?; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 1fc1661..c96e6e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1 @@ -use sha2::{Digest, Sha256}; - -pub fn hash_string(inp: String) -> String { - let mut h = Sha256::new(); - h.update(&inp.as_bytes()); - hex::encode(h.finalize()) -} +pub use xesite_markdown::hash_string; diff --git a/src/main.rs b/src/main.rs index d5b94c0..a35db42 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,10 +4,7 @@ extern crate tracing; use axum::{ body, extract::Extension, - http::{ - header::{self, HeaderValue, CONTENT_TYPE}, - Method, - }, + http::header::{self, HeaderValue, CONTENT_TYPE}, response::{Html, Response}, routing::{get, get_service}, Router, @@ -20,11 +17,10 @@ use std::{ net::{IpAddr, SocketAddr}, str::FromStr, sync::Arc, - time::Duration, }; use tokio::net::UnixListener; use tower_http::{ - cors::{Any, CorsLayer}, + cors::CorsLayer, services::{ServeDir, ServeFile}, set_header::SetResponseHeaderLayer, trace::TraceLayer, diff --git a/static/cal/xe-iaso-sonic-frontiers-20221108.ics b/static/cal/xe-iaso-sonic-frontiers-20221108.ics new file mode 100644 index 0000000..55d0696 --- /dev/null +++ b/static/cal/xe-iaso-sonic-frontiers-20221108.ics @@ -0,0 +1,23 @@ +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +PRODID:ics generator +METHOD:PUBLISH +X-PUBLISHED-TTL:PT1H +BEGIN:VEVENT +UID:0bb304b9-f1e3-4fd0-b0f9-65eee6e8544a +SUMMARY:Xe streams Sonic Frontiers +DTSTAMP:20221030T205030Z +DTSTART:20221108T150000Z +DTEND:20221108T170000Z +DESCRIPTION:Xe Iaso streams first impressions and gameplay of Sonic Frontie + rs! Grab some chips and soda. We're gonna explore the open zone and see if + it lives up to the promises of an open world Sonic game. It'll be a blast + ! +LOCATION:https://twitch.tv/princessxen +BEGIN:VALARM +ACTION:DISPLAY +TRIGGER:-PT60M +END:VALARM +END:VEVENT +END:VCALENDAR -- cgit v1.2.3