⭐ Moe-Counter Compatible Website Hit Counter Written in Gleam mayu.due.moe
hit-counter svg moe
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Pre-cache themes in memory

Fuwn 397f7ea9 08b2212c

+86 -31
+65
src/cache.gleam
··· 1 + import gleam/dict.{type Dict} 2 + import gleam/int 3 + import gleam/list 4 + import gleam/option.{type Option} 5 + import gleam/result 6 + import image 7 + import simplifile 8 + 9 + pub type CachedImage { 10 + CachedImage(data: BitArray, info: image.ImageInformation) 11 + } 12 + 13 + pub type ThemeCache = 14 + Dict(String, Dict(Int, CachedImage)) 15 + 16 + pub fn load_themes() { 17 + list.fold( 18 + case simplifile.read_directory("./themes") { 19 + Ok(files) -> files 20 + Error(_) -> [] 21 + }, 22 + dict.new(), 23 + fn(accumulated_themes, theme) { 24 + dict.insert( 25 + accumulated_themes, 26 + theme, 27 + list.range(0, 9) 28 + |> list.fold(dict.new(), fn(accumulated_digits, digit) { 29 + case 30 + simplifile.read_bits( 31 + from: "./themes/" 32 + <> theme 33 + <> "/" 34 + <> int.to_string(digit) 35 + <> "." 36 + <> case theme { 37 + "gelbooru-h" | "moebooru-h" | "lain" | "garukura" -> "png" 38 + _ -> "gif" 39 + }, 40 + ) 41 + { 42 + Ok(image_data) -> { 43 + case image.get_image_information(image_data) { 44 + Ok(info) -> 45 + dict.insert( 46 + accumulated_digits, 47 + digit, 48 + CachedImage(data: image_data, info: info), 49 + ) 50 + Error(_) -> accumulated_digits 51 + } 52 + } 53 + Error(_) -> accumulated_digits 54 + } 55 + }), 56 + ) 57 + }, 58 + ) 59 + } 60 + 61 + pub fn get_image(cache, theme, digit) -> Option(CachedImage) { 62 + dict.get(cache, theme) 63 + |> result.then(fn(theme_images) { dict.get(theme_images, digit) }) 64 + |> option.from_result 65 + }
+3 -1
src/mayu.gleam
··· 1 + import cache 1 2 import database 2 3 import gleam/erlang/process 3 4 import mist ··· 10 11 wisp.configure_logger() 11 12 12 13 let _ = simplifile.create_directory("./data") 14 + let image_cache = cache.load_themes() 13 15 14 16 use connection <- sqlight.with_connection("./data/count.db") 15 17 ··· 18 20 let secret_key_base = wisp.random_string(64) 19 21 let assert Ok(_) = 20 22 wisp.mist_handler( 21 - fn(request) { request.handle(request, connection) }, 23 + fn(request) { request.handle(request, connection, image_cache) }, 22 24 secret_key_base, 23 25 ) 24 26 |> mist.new
+2 -1
src/request.gleam
··· 19 19 handle(request) 20 20 } 21 21 22 - pub fn handle(request, connection) { 22 + pub fn handle(request, connection, image_cache) { 23 23 use _ <- middleware(request) 24 24 25 25 case wisp.path_segments(request) { ··· 50 50 |> wisp.set_header("Content-Type", "image/svg+xml") 51 51 |> wisp.string_body( 52 52 svg.xml( 53 + image_cache, 53 54 case list.key_find(wisp.get_query(request), "theme") { 54 55 Ok(theme) -> theme 55 56 _ -> "asoul"
+16 -29
src/svg.gleam
··· 1 + import cache 1 2 import gleam/bit_array 2 3 import gleam/int 3 4 import gleam/list 5 + import gleam/option.{Some} 4 6 import gleam/string_builder 5 7 import image 6 - import simplifile 7 8 8 9 type XmlImages { 9 10 XmlImages(xml: String, width: Int, height: Int) ··· 21 22 ) <> "\"/>" 22 23 } 23 24 24 - fn images(theme, digits, width, height, svgs) { 25 + fn images(image_cache, theme, digits, width, height, svgs) { 25 26 case digits { 26 27 [] -> XmlImages(string_builder.to_string(svgs), width, height) 27 28 [digit, ..rest] -> 28 - case 29 - simplifile.read_bits( 30 - from: "./themes/" 31 - <> theme 32 - <> "/" 33 - <> int.to_string(digit) 34 - <> "." 35 - <> case theme { 36 - "gelbooru-h" | "moebooru-h" | "lain" | "garukura" -> "png" 37 - _ -> "gif" 38 - }, 39 - ) 40 - { 41 - Ok(data) -> 42 - case image.get_image_information(data) { 43 - Ok(information) -> 44 - images( 45 - theme, 46 - rest, 47 - width + information.width, 48 - int.max(height, information.height), 49 - string_builder.append(svgs, image(data, information, width)), 50 - ) 51 - Error(_) -> XmlImages(string_builder.to_string(svgs), width, height) 52 - } 53 - Error(_) -> XmlImages(string_builder.to_string(svgs), width, height) 29 + case cache.get_image(image_cache, theme, digit) { 30 + Some(cached) -> 31 + images( 32 + image_cache, 33 + theme, 34 + rest, 35 + width + cached.info.width, 36 + int.max(height, cached.info.height), 37 + string_builder.append(svgs, image(cached.data, cached.info, width)), 38 + ) 39 + _ -> images(image_cache, theme, rest, width, height, svgs) 54 40 } 55 41 } 56 42 } 57 43 58 - pub fn xml(theme, number, padding) { 44 + pub fn xml(image_cache, theme, number, padding) { 59 45 let xml = 60 46 images( 47 + image_cache, 61 48 theme, 62 49 { 63 50 let assert Ok(digits) = int.digits(number, 10)