Typstify /chat_message to /chat

This commit is contained in:
Joscha 2025-03-01 23:11:49 +01:00
parent 8bece23baf
commit de7ae63a5e
13 changed files with 93 additions and 153 deletions

1
Cargo.lock generated
View file

@ -2746,7 +2746,6 @@ dependencies = [
"showbits-assets",
"showbits-common",
"showbits-typst",
"taffy",
"tokio",
]

View file

@ -17,7 +17,6 @@ serde = { workspace = true }
showbits-assets = { workspace = true }
showbits-common = { workspace = true }
showbits-typst = { workspace = true }
taffy = { workspace = true }
tokio = { workspace = true, features = ["full"] }
[lints]

View file

@ -1,6 +1,5 @@
import argparse
import json
import re
import time
import requests
@ -93,7 +92,7 @@ class Room:
print("Posting", data)
try:
requests.post(f"http://{self.addr}/chat_message", data=data)
requests.post(f"http://{self.addr}/chat", data=data)
except Exception as e:
print("Oop:", e)

View file

@ -99,7 +99,7 @@ class Room:
time.sleep(10)
def join(self):
nick = f"justinfan{ random.randint(1, 99999)}"
nick = f"justinfan{random.randint(1, 99999)}"
print(f"Joining #{self.channel} as {nick}")
self.ws.send("CAP REQ :twitch.tv/tags twitch.tv/commands")
self.ws.send("PASS SCHMOOPIIE") # What the web ui does
@ -120,7 +120,7 @@ class Room:
print("Posting", data)
try:
requests.post(f"http://{self.addr}/chat_message", data=data)
requests.post(f"http://{self.addr}/chat", data=data)
except Exception as e:
print("Oop:", e)

View file

@ -2,6 +2,7 @@ use showbits_typst::Typst;
pub mod calendar;
pub mod cells;
pub mod chat;
pub mod egg;
pub mod image;
pub mod text;

View file

@ -0,0 +1,5 @@
{
"username": "John Argbuckle aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"feed": false
}

View file

@ -0,0 +1 @@
../lib

View file

@ -0,0 +1,37 @@
#import "lib/main.typ" as lib;
#show: it => lib.init(it)
#let data = json("data.json")
#let max_width = 32 * 8pt + 4pt
#let limit_width(body) = context {
let width = measure(body).width
if width > max_width { box(body, width: max_width) } else { body }
}
// This way, the top line of the username box looks better.
#v(4pt)
#par(hanging-indent: 32pt)[
#limit_width(
box(
height: 10pt,
clip: true,
stroke: 1pt + black,
inset: (x: 2pt),
outset: (y: 3pt + .5pt, x: -.5pt),
{
// Ensure all characters that fit on the line are displayed on the line.
// We don't want a half-empty box.
show regex("."): it => it + sym.zws
data.username
},
),
)
#h(-4pt)
#data.content
]
#if data.feed {
lib.feed
}

View file

@ -0,0 +1,38 @@
use axum::{Form, extract::State};
use serde::{Deserialize, Serialize};
use crate::{
drawer::{Command, NewTypstDrawing},
server::Server,
};
#[derive(Serialize)]
struct Data {
username: String,
content: String,
feed: bool,
}
#[derive(Deserialize)]
pub struct FormData {
pub username: String,
pub content: String,
pub feed: Option<bool>,
}
pub async fn post(server: State<Server>, Form(form): Form<FormData>) {
let data = Data {
username: form.username,
content: form.content,
feed: form.feed.unwrap_or(false),
};
let typst = super::typst_with_lib()
.with_json("/data.json", &data)
.with_main_file(include_str!("main.typ"));
let _ = server
.tx
.send(Command::draw(NewTypstDrawing::new(typst)))
.await;
}

View file

@ -1,5 +1,4 @@
mod backlog;
mod chat_message;
mod new_typst;
use showbits_common::widgets::{FontStuff, HasFontStuff};
@ -7,9 +6,7 @@ use tokio::sync::mpsc;
use crate::persistent_printer::PersistentPrinter;
pub use self::{
backlog::BacklogDrawing, chat_message::ChatMessageDrawing, new_typst::NewTypstDrawing,
};
pub use self::{backlog::BacklogDrawing, new_typst::NewTypstDrawing};
#[derive(Default)]
pub struct Context {

View file

@ -1,90 +0,0 @@
use showbits_common::{
Node, Tree, WidgetExt,
color::{BLACK, WHITE},
widgets::{Block, Text},
};
use taffy::{
AlignItems, Display, FlexDirection,
style_helpers::{length, percent},
};
use crate::persistent_printer::PersistentPrinter;
use super::{Context, Drawing};
pub struct ChatMessageDrawing {
pub username: String,
pub content: String,
}
impl Drawing for ChatMessageDrawing {
fn draw(&self, printer: &mut PersistentPrinter, ctx: &mut Context) -> anyhow::Result<()> {
let mut tree = Tree::<Context>::new(WHITE);
let max_username_width_in_chars = 32.0;
let max_username_height_in_lines = 3.0;
let max_content_height_in_lines = 16.0;
let username = Text::new()
.and_plain(&self.username)
.widget(&mut ctx.font_stuff)
.node()
.with_max_size_width(length(max_username_width_in_chars * 8.0))
.with_max_size_height(length(max_username_height_in_lines * 16.0))
.register(&mut tree)?;
let username = Block::new()
.with_border(BLACK)
.node()
.with_border_all(length(1.0))
.with_padding_horiz(length(1.0))
.with_flex_shrink(0.0) // Avoid wrapping
.and_child(username)
.register(&mut tree)?;
let content = if let Some(content) = self.content.strip_prefix("/me") {
let content = content.trim_start();
let content = Text::new()
.and_plain(content)
.widget(&mut ctx.font_stuff)
.node()
.with_max_size_height(length(max_content_height_in_lines * 16.0))
.register(&mut tree)?;
Block::new()
.with_border(BLACK)
.node()
.with_border_all(length(1.0))
.with_padding_horiz(length(1.0))
.and_child(content)
.register(&mut tree)?
} else {
let content = Text::new()
.and_plain(&self.content)
.widget(&mut ctx.font_stuff)
.node()
.with_max_size_height(length(max_content_height_in_lines * 16.0))
.register(&mut tree)?;
Node::empty()
.with_padding_vert(length(1.0))
.and_child(content)
.register(&mut tree)?
};
let root = Node::empty()
.with_size_width(percent(1.0))
.with_padding_all(length(1.0))
.with_display(Display::Flex)
.with_flex_direction(FlexDirection::Row)
.with_align_items(Some(AlignItems::Start))
.with_gap_width(length(2.0))
.and_child(username)
.and_child(content)
.register(&mut tree)?;
printer.print_tree(&mut tree, ctx, root)?;
Ok(())
}
}

View file

@ -3,8 +3,6 @@ use std::{fs, io::ErrorKind, path::PathBuf};
use anyhow::{Context, bail};
use image::RgbaImage;
use jiff::Timestamp;
use showbits_common::Tree;
use taffy::{AvailableSpace, NodeId, Size};
use crate::printer::Printer;
@ -30,20 +28,6 @@ impl PersistentPrinter {
}
}
fn render_tree_to_image<C>(
tree: &mut Tree<C>,
ctx: &mut C,
root: NodeId,
) -> anyhow::Result<RgbaImage> {
let available = Size {
width: AvailableSpace::Definite(Printer::WIDTH as f32),
// TODO Maybe MinContent? If not, why not?
height: AvailableSpace::MaxContent,
};
tree.render(ctx, root, available)
}
fn print_image_immediately(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
let Some(printer) = &mut self.printer else {
bail!("no printer found");
@ -93,17 +77,6 @@ impl PersistentPrinter {
Ok(())
}
pub fn print_tree<C>(
&mut self,
tree: &mut Tree<C>,
ctx: &mut C,
root: NodeId,
) -> anyhow::Result<()> {
let image = Self::render_tree_to_image(tree, ctx, root)?;
self.print_image(&image)?;
Ok(())
}
pub fn print_backlog(&mut self) -> anyhow::Result<()> {
// Don't try to print if the chances of success are zero.
if let Some(file) = &self.printer_file {

View file

@ -3,17 +3,13 @@ mod r#static;
pub mod statuscode;
use axum::{
Form, Router,
extract::{DefaultBodyLimit, State},
Router,
extract::DefaultBodyLimit,
routing::{get, post},
};
use serde::Deserialize;
use tokio::{net::TcpListener, sync::mpsc};
use crate::{
documents,
drawer::{ChatMessageDrawing, Command},
};
use crate::{documents, drawer::Command};
use self::r#static::get_static_file;
@ -32,7 +28,10 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
"/cells",
post(documents::cells::post).fallback(get_static_file),
)
.route("/chat_message", post(post_chat_message))
.route(
"/chat",
post(documents::chat::post).fallback(get_static_file),
)
.route("/egg", post(documents::egg::post).fallback(get_static_file))
.route(
"/image",
@ -54,21 +53,3 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
axum::serve(listener, app).await?;
Ok(())
}
// /chat_message
#[derive(Deserialize)]
struct PostChatMessageForm {
username: String,
content: String,
}
async fn post_chat_message(server: State<Server>, request: Form<PostChatMessageForm>) {
let _ = server
.tx
.send(Command::draw(ChatMessageDrawing {
username: request.0.username,
content: request.0.content,
}))
.await;
}