diff --git a/Cargo.lock b/Cargo.lock index 5228108..d4d33d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2746,7 +2746,6 @@ dependencies = [ "showbits-assets", "showbits-common", "showbits-typst", - "taffy", "tokio", ] diff --git a/showbits-thermal-printer/Cargo.toml b/showbits-thermal-printer/Cargo.toml index 4988ffa..689c188 100644 --- a/showbits-thermal-printer/Cargo.toml +++ b/showbits-thermal-printer/Cargo.toml @@ -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] diff --git a/showbits-thermal-printer/scripts/euph_feed.py b/showbits-thermal-printer/scripts/euph_feed.py index 41e3630..1c1e073 100644 --- a/showbits-thermal-printer/scripts/euph_feed.py +++ b/showbits-thermal-printer/scripts/euph_feed.py @@ -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) diff --git a/showbits-thermal-printer/scripts/twitch_feed.py b/showbits-thermal-printer/scripts/twitch_feed.py index 31a1f18..0b56be5 100644 --- a/showbits-thermal-printer/scripts/twitch_feed.py +++ b/showbits-thermal-printer/scripts/twitch_feed.py @@ -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) diff --git a/showbits-thermal-printer/src/documents.rs b/showbits-thermal-printer/src/documents.rs index 36c445a..7da622b 100644 --- a/showbits-thermal-printer/src/documents.rs +++ b/showbits-thermal-printer/src/documents.rs @@ -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; diff --git a/showbits-thermal-printer/src/documents/chat/data.json b/showbits-thermal-printer/src/documents/chat/data.json new file mode 100644 index 0000000..2c520ea --- /dev/null +++ b/showbits-thermal-printer/src/documents/chat/data.json @@ -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 +} diff --git a/showbits-thermal-printer/src/documents/chat/lib b/showbits-thermal-printer/src/documents/chat/lib new file mode 120000 index 0000000..dc598c5 --- /dev/null +++ b/showbits-thermal-printer/src/documents/chat/lib @@ -0,0 +1 @@ +../lib \ No newline at end of file diff --git a/showbits-thermal-printer/src/documents/chat/main.typ b/showbits-thermal-printer/src/documents/chat/main.typ new file mode 100644 index 0000000..713c7f7 --- /dev/null +++ b/showbits-thermal-printer/src/documents/chat/main.typ @@ -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 +} diff --git a/showbits-thermal-printer/src/documents/chat/mod.rs b/showbits-thermal-printer/src/documents/chat/mod.rs new file mode 100644 index 0000000..bf989e3 --- /dev/null +++ b/showbits-thermal-printer/src/documents/chat/mod.rs @@ -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, +} + +pub async fn post(server: State, Form(form): Form) { + 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; +} diff --git a/showbits-thermal-printer/src/drawer.rs b/showbits-thermal-printer/src/drawer.rs index 3fa4798..c6203cd 100644 --- a/showbits-thermal-printer/src/drawer.rs +++ b/showbits-thermal-printer/src/drawer.rs @@ -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 { diff --git a/showbits-thermal-printer/src/drawer/chat_message.rs b/showbits-thermal-printer/src/drawer/chat_message.rs deleted file mode 100644 index af2d96b..0000000 --- a/showbits-thermal-printer/src/drawer/chat_message.rs +++ /dev/null @@ -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::::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(()) - } -} diff --git a/showbits-thermal-printer/src/persistent_printer.rs b/showbits-thermal-printer/src/persistent_printer.rs index cdfaaa6..395f04e 100644 --- a/showbits-thermal-printer/src/persistent_printer.rs +++ b/showbits-thermal-printer/src/persistent_printer.rs @@ -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( - tree: &mut Tree, - ctx: &mut C, - root: NodeId, - ) -> anyhow::Result { - 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( - &mut self, - tree: &mut Tree, - 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 { diff --git a/showbits-thermal-printer/src/server.rs b/showbits-thermal-printer/src/server.rs index c06bea7..91ea28f 100644 --- a/showbits-thermal-printer/src/server.rs +++ b/showbits-thermal-printer/src/server.rs @@ -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, 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, 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, request: Form) { - let _ = server - .tx - .send(Command::draw(ChatMessageDrawing { - username: request.0.username, - content: request.0.content, - })) - .await; -}