Compare commits

..

No commits in common. "c12b9b360a086d5459db35f9c17932060dc0efcc" and "6726cafff4839871be1e489a047127c1d1c3284e" have entirely different histories.

10 changed files with 38 additions and 154 deletions

View File

@ -1,45 +0,0 @@
#!/usr/bin/env zx
import { glob } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { chunk } from 'es-toolkit/array';
const dataDir = path.join(import.meta.dirname, '../../../data')
/**
* @type {string[]}
*/
const images = [];
for await (const image of glob('**/*.{jpg,jpeg,png,gif,svg}', {
cwd: dataDir,
})) {
images.push(image)
}
const cpus = os.cpus().length - 1;
const chunkSize = Math.ceil(images.length / cpus);
const chunks = chunk(images, chunkSize);
/**
* @param {string[]} images
*/
async function convertImages(images) {
for await (const image of images) {
const imagePath = path.resolve(dataDir, image)
const webp = imagePath.replace(path.extname(imagePath), '.webp')
const avif = imagePath.replace(path.extname(imagePath), '.avif')
console.log(`Converting ${imagePath} to ${webp}...`);
await $`ffmpeg -i "${imagePath}" -c:v libwebp -lossless 1 "${webp}"`;
console.log(`Converting ${imagePath} to ${avif}...`);
await $`ffmpeg -i "${imagePath}" -c:v libaom-av1 -still-picture 1 -pix_fmt yuv420p10le -crf 0 -strict experimental "${avif}"`;
}
}
await Promise.all(
chunks.map(convertImages)
)

View File

@ -26,18 +26,18 @@ host = '{{ get_env(name="HOST", default="localhost") }}'
enable = true enable = true
# Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details.
[server.middlewares.request_id] [server.middleware.request_id]
enable = true enable = true
[server.middlewares.logger] [server.middleware.logger]
enable = true enable = true
# when your code is panicked, the request still returns 500 status code. # when your code is panicked, the request still returns 500 status code.
[server.middlewares.catch_panic] [server.middleware.catch_panic]
enable = true enable = true
# Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned.
[server.middlewares.timeout_request] [server.middleware.timeout_request]
enable = false enable = false
# Duration time in milliseconds. # Duration time in milliseconds.
timeout = 5000 timeout = 5000
@ -53,10 +53,7 @@ timeout = 5000
# - POST # - POST
# Set the value of the [`Access-Control-Max-Age`][mdn] header in seconds # Set the value of the [`Access-Control-Max-Age`][mdn] header in seconds
# max_age: 3600 # max_age: 3600
[server.middlewares.cors] [server.middleware.cors]
enable = true
[server.middlewares.compression]
enable = true enable = true
# Database Configuration # Database Configuration

View File

@ -6,7 +6,6 @@ use tracing::instrument;
use super::{builder::AppBuilder, context::AppContextTrait}; use super::{builder::AppBuilder, context::AppContextTrait};
use crate::{ use crate::{
app::Environment,
errors::{RecorderError, RecorderResult}, errors::{RecorderError, RecorderResult},
web::{ web::{
controller::{self, core::ControllerTrait}, controller::{self, core::ControllerTrait},
@ -65,11 +64,9 @@ impl App {
let middlewares = default_middleware_stack(context.clone()); let middlewares = default_middleware_stack(context.clone());
for mid in middlewares { for mid in middlewares {
if mid.is_enabled() {
router = mid.apply(router)?; router = mid.apply(router)?;
tracing::info!(name = mid.name(), "+middleware"); tracing::info!(name = mid.name(), "+middleware");
} }
}
let router = router let router = router
.with_state(context.clone()) .with_state(context.clone())
@ -89,9 +86,6 @@ impl App {
async { async {
{ {
let monitor = task.setup_monitor().await?; let monitor = task.setup_monitor().await?;
if matches!(context.environment(), Environment::Development) {
monitor.run().await?;
} else {
monitor monitor
.run_with_signal(async move { .run_with_signal(async move {
Self::shutdown_signal().await; Self::shutdown_signal().await;
@ -100,7 +94,6 @@ impl App {
}) })
.await?; .await?;
} }
}
Ok::<(), RecorderError>(()) Ok::<(), RecorderError>(())
}, },

View File

@ -1,4 +1,4 @@
use std::{borrow::Cow, fmt}; use std::fmt;
use async_stream::try_stream; use async_stream::try_stream;
use axum::{body::Body, response::Response}; use axum::{body::Body, response::Response};
@ -206,12 +206,6 @@ impl StorageService {
let mime_type = mime_guess::from_path(storage_path.as_ref()).first_or_octet_stream(); let mime_type = mime_guess::from_path(storage_path.as_ref()).first_or_octet_stream();
let content_type = HeaderValue::from_str(mime_type.as_ref())?; let content_type = HeaderValue::from_str(mime_type.as_ref())?;
let etag = metadata.etag().map(Cow::Borrowed).or_else(|| {
let len = metadata.content_length();
let lm = metadata.last_modified()?.timestamp();
Some(Cow::Owned(format!("\"{lm:x}-{len:x}\"")))
});
let last_modified = metadata.last_modified().map(|lm| lm.to_rfc2822());
let response = if let Some(TypedHeader(range)) = range { let response = if let Some(TypedHeader(range)) = range {
let ranges = range let ranges = range
@ -246,7 +240,7 @@ impl StorageService {
}; };
let body = Body::from_stream(stream); let body = Body::from_stream(stream);
let mut builder = Response::builder() Response::builder()
.status(StatusCode::PARTIAL_CONTENT) .status(StatusCode::PARTIAL_CONTENT)
.header( .header(
header::CONTENT_TYPE, header::CONTENT_TYPE,
@ -254,34 +248,17 @@ impl StorageService {
format!("multipart/byteranges; boundary={boundary}").as_str(), format!("multipart/byteranges; boundary={boundary}").as_str(),
) )
.unwrap(), .unwrap(),
); )
.body(body)?
if let Some(etag) = etag {
builder = builder.header(header::ETAG, etag.to_string());
}
if let Some(last_modified) = last_modified {
builder = builder.header(header::LAST_MODIFIED, last_modified);
}
builder.body(body)?
} else if let Some((r, content_range)) = ranges.pop() { } else if let Some((r, content_range)) = ranges.pop() {
let reader = self.reader(storage_path.as_ref()).await?; let reader = self.reader(storage_path.as_ref()).await?;
let stream = reader.into_bytes_stream(r).await?; let stream = reader.into_bytes_stream(r).await?;
let mut builder = Response::builder() Response::builder()
.status(StatusCode::PARTIAL_CONTENT) .status(StatusCode::PARTIAL_CONTENT)
.header(header::CONTENT_TYPE, content_type.clone()) .header(header::CONTENT_TYPE, content_type.clone())
.header(header::CONTENT_RANGE, content_range); .header(header::CONTENT_RANGE, content_range)
.body(Body::from_stream(stream))?
if let Some(etag) = metadata.etag() {
builder = builder.header(header::ETAG, etag);
}
if let Some(last_modified) = last_modified {
builder = builder.header(header::LAST_MODIFIED, last_modified);
}
builder.body(Body::from_stream(stream))?
} else { } else {
unreachable!("ranges length should be greater than 0") unreachable!("ranges length should be greater than 0")
} }
@ -299,19 +276,10 @@ impl StorageService {
let reader = self.reader(storage_path.as_ref()).await?; let reader = self.reader(storage_path.as_ref()).await?;
let stream = reader.into_bytes_stream(..).await?; let stream = reader.into_bytes_stream(..).await?;
let mut builder = Response::builder() Response::builder()
.status(StatusCode::OK) .status(StatusCode::OK)
.header(header::CONTENT_TYPE, content_type); .header(header::CONTENT_TYPE, content_type)
.body(Body::from_stream(stream))?
if let Some(etag) = etag {
builder = builder.header(header::ETAG, etag.to_string());
}
if let Some(last_modified) = last_modified {
builder = builder.header(header::LAST_MODIFIED, last_modified);
}
builder.body(Body::from_stream(stream))?
}; };
Ok(response) Ok(response)

View File

@ -0,0 +1,6 @@
---
source: apps/recorder/src/web/middleware/request_id.rs
assertion_line: 126
expression: id
---
"foo-barbaz"

View File

@ -77,6 +77,7 @@
"tw-animate-css": "^1.3.4", "tw-animate-css": "^1.3.4",
"type-fest": "^4.41.0", "type-fest": "^4.41.0",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"es-toolkit": "^1.39.3",
"@tanstack/react-router": "^1.121.2" "@tanstack/react-router": "^1.121.2"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,38 +1,9 @@
import { type ComponentProps, useMemo, useState } from "react"; import type { ComponentProps } from "react";
export type ImgProps = Omit<ComponentProps<"img">, "alt"> & export type ImgProps = Omit<ComponentProps<"img">, "alt"> &
Required<Pick<ComponentProps<"img">, "alt">> & { Required<Pick<ComponentProps<"img">, "alt">>;
optimize?: boolean;
};
const LEGACY_IMAGE_REGEX = /\.(jpg|jpeg|png|gif|svg)$/;
export const Img = (props: ImgProps) => { export const Img = (props: ImgProps) => {
const src = props.src;
const isLegacy = useMemo(() => src?.match(LEGACY_IMAGE_REGEX), [src]);
const [isError, setIsError] = useState(false);
if (!src) {
// biome-ignore lint/nursery/noImgElement: <explanation> // biome-ignore lint/nursery/noImgElement: <explanation>
return <img {...props} alt={props.alt} />; return <img {...props} alt={props.alt} />;
}
return (
<picture {...props}>
{isLegacy && !isError && (
<>
<source
srcSet={src.replace(LEGACY_IMAGE_REGEX, ".webp")}
type="image/webp"
/>
<source
srcSet={src.replace(LEGACY_IMAGE_REGEX, ".avif")}
type="image/avif"
/>
</>
)}
<img {...props} alt={props.alt} onError={() => setIsError(true)} />
</picture>
);
}; };

View File

@ -11,9 +11,6 @@ prepare-dev-testcontainers:
docker pull ghcr.io/dumtruck/konobangu-testing-torrents:latest docker pull ghcr.io/dumtruck/konobangu-testing-torrents:latest
docker pull postgres:17-alpine docker pull postgres:17-alpine
dev-optimize-images:
npx -y zx apps/recorder/examples/optimize_image.mjs
dev-webui: dev-webui:
pnpm run --filter=webui dev pnpm run --filter=webui dev

View File

@ -19,9 +19,6 @@
"engines": { "engines": {
"node": ">=22" "node": ">=22"
}, },
"dependencies": {
"es-toolkit": "^1.39.3"
},
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.4", "@biomejs/biome": "1.9.4",
"@types/node": "^24.0.1", "@types/node": "^24.0.1",

7
pnpm-lock.yaml generated
View File

@ -10,10 +10,6 @@ overrides:
importers: importers:
.: .:
dependencies:
es-toolkit:
specifier: ^1.39.3
version: 1.39.3
devDependencies: devDependencies:
'@biomejs/biome': '@biomejs/biome':
specifier: 1.9.4 specifier: 1.9.4
@ -213,6 +209,9 @@ importers:
embla-carousel-react: embla-carousel-react:
specifier: ^8.6.0 specifier: ^8.6.0
version: 8.6.0(react@19.1.0) version: 8.6.0(react@19.1.0)
es-toolkit:
specifier: ^1.39.3
version: 1.39.3
graphiql: graphiql:
specifier: ^4.1.2 specifier: ^4.1.2
version: 4.1.2(@codemirror/language@6.11.1)(@emotion/is-prop-valid@0.8.8)(@types/node@24.0.1)(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) version: 4.1.2(@codemirror/language@6.11.1)(@emotion/is-prop-valid@0.8.8)(@types/node@24.0.1)(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))