7 Commits

Author SHA1 Message Date
fde16de0c6 License update 2026-05-06 14:51:22 +03:00
418f12ca4a Финальное исправление иконок в оформлении 2026-05-06 14:21:09 +03:00
7001aeb070 Иправления 2026-05-06 12:58:29 +03:00
b793571681 Исправленны иконки 2026-05-06 12:47:46 +03:00
74412ad368 Не большие изменения 2026-05-06 12:31:42 +03:00
855bdcc3f9 небольшие правки 2026-04-18 11:21:11 +03:00
4646dd2b70 fix: исправлены роуты веб-сервера и обновлён Makefile
- Убран дублирующийся роут /favicon.ico
- Добавлен импорт ServeDir
- Makefile: поддержка ImageMagick 6 и 7
- Добавлена цель favicon
2026-04-18 11:12:54 +03:00
19 changed files with 159 additions and 32 deletions

19
Cargo.lock generated
View File

@@ -33,6 +33,7 @@ dependencies = [
"tower", "tower",
"tower-http", "tower-http",
"urlencoding", "urlencoding",
"winres",
] ]
[[package]] [[package]]
@@ -1768,6 +1769,15 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "tower" name = "tower"
version = "0.5.3" version = "0.5.3"
@@ -2167,6 +2177,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winres"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
dependencies = [
"toml",
]
[[package]] [[package]]
name = "wit-bindgen" name = "wit-bindgen"
version = "0.51.0" version = "0.51.0"

View File

@@ -48,3 +48,6 @@ opt-level = "z"
lto = true lto = true
codegen-units = 1 codegen-units = 1
strip = true strip = true
[build-dependencies]
winres = "0.1"

View File

@@ -1,7 +1,5 @@
# MIT License # MIT License
Copyright (c) 2026 [Your Name or Company]
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

Binary file not shown.

BIN
assets/logo.icns Normal file

Binary file not shown.

BIN
assets/logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

11
build.rs Normal file
View File

@@ -0,0 +1,11 @@
fn main() {
#[cfg(windows)]
{
if let Err(e) = winres::WindowsResource::new()
.set_icon("assets/logo.ico")
.compile()
{
eprintln!("warning: не удалось встроить иконку: {e}");
}
}
}

View File

@@ -1,4 +1,4 @@
.PHONY: all clean build-mac build-windows build-linux build-linux-musl package help quick package-single .PHONY: all clean build-mac build-windows build-linux build-linux-musl package help quick package-single icons
# Название проекта # Название проекта
PROJECT_NAME := ae_anons PROJECT_NAME := ae_anons
@@ -18,11 +18,14 @@ BLUE := \033[0;34m
CYAN := \033[0;36m CYAN := \033[0;36m
MAGENTA := \033[0;35m MAGENTA := \033[0;35m
BOLD := \033[1m BOLD := \033[1m
NC := \033[0m # No Color NC := \033[0m
# Файл для хранения времени сборки # Файл для хранения времени сборки
TIMING_FILE := .build_timing TIMING_FILE := .build_timing
# Определение команды ImageMagick (v6 = convert, v7 = magick)
IMAGEMAGICK := $(shell command -v magick 2>/dev/null || command -v convert 2>/dev/null || echo "false")
help: help:
@echo "$(BOLD)$(CYAN)AE Anons - Makefile команды$(NC)" @echo "$(BOLD)$(CYAN)AE Anons - Makefile команды$(NC)"
@echo "" @echo ""
@@ -41,6 +44,10 @@ help:
@echo " make package - Создать пакеты для всех платформ" @echo " make package - Создать пакеты для всех платформ"
@echo " make package-single - Создать пакет для текущей платформы" @echo " make package-single - Создать пакет для текущей платформы"
@echo "" @echo ""
@echo "$(GREEN)Подготовка ресурсов:$(NC)"
@echo " make setup - Подготовить иконки (логотипы, favicon)"
@echo " make setup-fontawesome-manual - Скачать и исправить all.min.css (если удалён)"
@echo ""
@echo "$(GREEN)Очистка:$(NC)" @echo "$(GREEN)Очистка:$(NC)"
@echo " make clean - Очистить все сборки" @echo " make clean - Очистить все сборки"
@echo " make clean-timing - Очистить файл с временами сборки" @echo " make clean-timing - Очистить файл с временами сборки"
@@ -49,24 +56,27 @@ help:
# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ # ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
# ============================================ # ============================================
# Копирование общих файлов в пакет
define copy_common_files define copy_common_files
@cp .env.example $(1)/ 2>/dev/null || true @cp .env.example $(1)/ 2>/dev/null || true
@cp README.md $(1)/ 2>/dev/null || true @cp README.md $(1)/ 2>/dev/null || true
@if [ -f LICENSE ]; then cp LICENSE $(1)/; else echo "$(YELLOW)⚠️ LICENSE не найден, пропускаем$(NC)"; fi @if [ -f LICENSE ]; then cp LICENSE $(1)/; else echo "$(YELLOW)⚠️ LICENSE не найден, пропускаем$(NC)"; fi
endef endef
# Функция для замера времени
define measure_time define measure_time
@start=$$(date +%s); \ @start=$$(date +%s); \
$(2); \ $(2); \
end=$$(date +%s); \ end=$$(date +%s); \
duration=$$((end - start)); \ duration=$$((end - start)); \
echo "$(1): $$duration сек" >> $(TIMING_FILE); \ echo "$(1): $$duration сек" >> $(TIMING_FILE); \
echo "$(GREEN)$(1) завершён за $$duration сек$(NC)" if [ $$duration -ge 60 ]; then \
min=$$((duration / 60)); \
sec=$$((duration % 60)); \
echo "$(GREEN)$(1) завершён за $${min}m $${sec}s$(NC)"; \
else \
echo "$(GREEN)$(1) завершён за $${duration}s$(NC)"; \
fi
endef endef
# Функция для вывода итоговой таблицы
define print_timing_summary define print_timing_summary
@echo "" @echo ""
@echo "$(BOLD)$(CYAN)═══════════════════════════════════════════════════════════════$(NC)" @echo "$(BOLD)$(CYAN)═══════════════════════════════════════════════════════════════$(NC)"
@@ -88,6 +98,58 @@ define print_timing_summary
@rm -f $(TIMING_FILE) @rm -f $(TIMING_FILE)
endef endef
# ============================================
# ПОДГОТОВКА РЕСУРСОВ
# ============================================
setup: icons
@echo "$(GREEN)Все статические ресурсы подготовлены$(NC)"
# Генерация иконок (favicon, .ico, .icns) из логотипа
icons:
@echo "$(GREEN)🎨 Генерация иконок...$(NC)"
@if [ "$(IMAGEMAGICK)" = "false" ]; then \
echo "$(RED)❌ ImageMagick не установлен. Установите: brew install imagemagick$(NC)"; \
exit 1; \
fi
# favicon.ico
@$(IMAGEMAGICK) assets/logo.png -define icon:auto-resize=48,32,16 src/static/favicon.ico
@echo "$(GREEN) ✓ src/static/favicon.ico$(NC)"
# Windows .ico
@$(IMAGEMAGICK) assets/logo.png -define icon:auto-resize=256,128,64,48,32,16 assets/logo.ico
@echo "$(GREEN) ✓ assets/logo.ico$(NC)"
# macOS .icns
@mkdir -p assets/icon.iconset
@sips -z 16 16 assets/logo.png --out assets/icon.iconset/icon_16x16.png 2>/dev/null || true
@sips -z 32 32 assets/logo.png --out assets/icon.iconset/icon_16x16@2x.png 2>/dev/null || true
@sips -z 32 32 assets/logo.png --out assets/icon.iconset/icon_32x32.png 2>/dev/null || true
@sips -z 64 64 assets/logo.png --out assets/icon.iconset/icon_32x32@2x.png 2>/dev/null || true
@sips -z 128 128 assets/logo.png --out assets/icon.iconset/icon_128x128.png 2>/dev/null || true
@sips -z 256 256 assets/logo.png --out assets/icon.iconset/icon_128x128@2x.png 2>/dev/null || true
@sips -z 256 256 assets/logo.png --out assets/icon.iconset/icon_256x256.png 2>/dev/null || true
@sips -z 512 512 assets/logo.png --out assets/icon.iconset/icon_256x256@2x.png 2>/dev/null || true
@sips -z 512 512 assets/logo.png --out assets/icon.iconset/icon_512x512.png 2>/dev/null || true
@iconutil -c icns assets/icon.iconset -o assets/logo.icns 2>/dev/null || true
@rm -rf assets/icon.iconset
@echo "$(GREEN) ✓ assets/logo.icns$(NC)"
# Восстановить CSS Font Awesome вручную (если файл удалён)
setup-fontawesome-manual:
@echo "$(GREEN)📥 Скачивание Font Awesome CSS...$(NC)"
@curl -sL -o src/static/fontawesome/all.min.css $(FONTAWESOME_CSS_URL)
@sed -i '' -E 's|(\.\./)*webfonts/|/static/fontawesome/webfonts/|g' \
src/static/fontawesome/all.min.css
@echo "$(GREEN)✓ CSS восстановлен и пути исправлены$(NC)"
# ============================================
# ИКОНКА ДЛЯ WINDOWS .EXE
# ============================================
windows-icon:
@if [ ! -f assets/logo.ico ]; then \
echo "$(YELLOW)logo.ico не найден, запускаю генерацию иконок...$(NC)"; \
$(MAKE) icons; \
fi
# ============================================ # ============================================
# ОПРЕДЕЛЕНИЕ ПЛАТФОРМЫ # ОПРЕДЕЛЕНИЕ ПЛАТФОРМЫ
# ============================================ # ============================================
@@ -113,7 +175,6 @@ endif
quick: detect-platform quick: detect-platform
# Быстрая сборка без упаковки (только бинарник)
quick-release: quick-release:
ifeq ($(UNAME_S),Darwin) ifeq ($(UNAME_S),Darwin)
@echo "$(GREEN)🍎 Сборка для macOS...$(NC)" @echo "$(GREEN)🍎 Сборка для macOS...$(NC)"
@@ -147,7 +208,7 @@ quick-linux:
@echo "$(GREEN)✅ Пакет: $(BINARIES_DIR)/$(PROJECT_NAME)-v$(VERSION)-linux-$(UNAME_M)/$(NC)" @echo "$(GREEN)✅ Пакет: $(BINARIES_DIR)/$(PROJECT_NAME)-v$(VERSION)-linux-$(UNAME_M)/$(NC)"
@$(call print_timing_summary) @$(call print_timing_summary)
quick-windows: quick-windows: windows-icon
@rm -f $(TIMING_FILE) @rm -f $(TIMING_FILE)
@if command -v x86_64-w64-mingw32-gcc >/dev/null 2>&1; then \ @if command -v x86_64-w64-mingw32-gcc >/dev/null 2>&1; then \
$(call measure_time,"🪟 Windows x64",cargo build --target x86_64-pc-windows-gnu --release); \ $(call measure_time,"🪟 Windows x64",cargo build --target x86_64-pc-windows-gnu --release); \
@@ -170,7 +231,7 @@ build-mac:
@echo "$(GREEN)🍎 Сборка для macOS...$(NC)" @echo "$(GREEN)🍎 Сборка для macOS...$(NC)"
@time cargo build --release @time cargo build --release
build-windows: build-windows: windows-icon
@echo "$(GREEN)🪟 Сборка для Windows x86_64...$(NC)" @echo "$(GREEN)🪟 Сборка для Windows x86_64...$(NC)"
@time cargo build --target x86_64-pc-windows-gnu --release @time cargo build --target x86_64-pc-windows-gnu --release

View File

@@ -1,7 +1,5 @@
# MIT License # MIT License
Copyright (c) 2026 [Your Name or Company]
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

View File

@@ -1,7 +1,5 @@
# MIT License # MIT License
Copyright (c) 2026 [Your Name or Company]
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

View File

@@ -1,7 +1,5 @@
# MIT License # MIT License
Copyright (c) 2026 [Your Name or Company]
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

View File

@@ -1,7 +1,5 @@
# MIT License # MIT License
Copyright (c) 2026 [Your Name or Company]
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights

BIN
src/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -4,12 +4,13 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AE Anons - Nexrender Job Manager</title> <title>AE Anons</title>
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/png" href="/favicon.ico"> <link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/favicon.ico"> <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/assets/logo.png">
<!-- CSS -->
<link rel="stylesheet" href="/static/fontawesome/all.min.css"> <link rel="stylesheet" href="/static/fontawesome/all.min.css">
<link rel="stylesheet" href="/static/style.css"> <link rel="stylesheet" href="/static/style.css">
</head> </head>
@@ -26,7 +27,7 @@
<i class="fas fa-bolt"></i> <i class="fas fa-bolt"></i>
</div> </div>
</div> </div>
<h1>AE Anons - Nexrender Job Manager</h1> <h1>AE Anons</h1>
</div> </div>
<div class="header-controls"> <div class="header-controls">
<button class="theme-toggle" onclick="toggleTheme()"> <button class="theme-toggle" onclick="toggleTheme()">

View File

@@ -11,7 +11,6 @@ use serde::Serialize;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
#[derive(Clone)] #[derive(Clone)]
@@ -89,7 +88,18 @@ pub async fn run_web_server(config: Config) -> anyhow::Result<()> {
.route("/favicon.ico", get(favicon)) .route("/favicon.ico", get(favicon))
.route("/static/style.css", get(style_css)) .route("/static/style.css", get(style_css))
.route("/static/fontawesome/all.min.css", get(fontawesome_css)) .route("/static/fontawesome/all.min.css", get(fontawesome_css))
.nest_service("/static/fontawesome/webfonts", ServeDir::new("src/static/fontawesome/webfonts")) .route(
"/static/fontawesome/webfonts/fa-solid-900.woff2",
get(fa_solid_woff2),
)
.route(
"/static/fontawesome/webfonts/fa-regular-400.woff2",
get(fa_regular_woff2),
)
.route(
"/static/fontawesome/webfonts/fa-brands-400.woff2",
get(fa_brands_woff2),
)
.route("/assets/logo.png", get(logo_png)) .route("/assets/logo.png", get(logo_png))
.route("/api/jobs", get(list_jobs)) .route("/api/jobs", get(list_jobs))
.route("/api/generate", post(generate_jobs)) .route("/api/generate", post(generate_jobs))
@@ -98,7 +108,6 @@ pub async fn run_web_server(config: Config) -> anyhow::Result<()> {
.route("/api/jobs/stop-all", post(stop_all_jobs)) .route("/api/jobs/stop-all", post(stop_all_jobs))
.layer(TraceLayer::new_for_http()) .layer(TraceLayer::new_for_http())
.with_state(state); .with_state(state);
let addr: SocketAddr = format!("0.0.0.0:{}", web_port).parse()?; let addr: SocketAddr = format!("0.0.0.0:{}", web_port).parse()?;
log::info!("Web server listening on http://{}", addr); log::info!("Web server listening on http://{}", addr);
@@ -112,19 +121,31 @@ async fn index_page() -> Html<&'static str> {
} }
async fn style_css() -> impl IntoResponse { async fn style_css() -> impl IntoResponse {
([(CONTENT_TYPE, "text/css")], include_str!("static/style.css")) (
[(CONTENT_TYPE, "text/css")],
include_str!("static/style.css"),
)
} }
async fn fontawesome_css() -> impl IntoResponse { async fn fontawesome_css() -> impl IntoResponse {
([(CONTENT_TYPE, "text/css")], include_str!("static/fontawesome/all.min.css")) (
[(CONTENT_TYPE, "text/css")],
include_str!("static/fontawesome/all.min.css"),
)
} }
async fn logo_png() -> impl IntoResponse { async fn logo_png() -> impl IntoResponse {
([(CONTENT_TYPE, "image/png")], include_bytes!("../assets/logo.png").as_slice()) (
[(CONTENT_TYPE, "image/png")],
include_bytes!("../assets/logo.png").as_slice(),
)
} }
async fn favicon() -> impl IntoResponse { async fn favicon() -> impl IntoResponse {
([(CONTENT_TYPE, "image/png")], include_bytes!("../assets/logo.png").as_slice()) (
[(CONTENT_TYPE, "image/x-icon")],
include_bytes!("static/favicon.ico").as_slice(),
)
} }
async fn list_jobs(State(state): State<AppState>) -> Result<Json<Vec<JobInfo>>, AppError> { async fn list_jobs(State(state): State<AppState>) -> Result<Json<Vec<JobInfo>>, AppError> {
@@ -214,6 +235,27 @@ async fn stop_all_jobs(State(state): State<AppState>) -> Result<impl IntoRespons
Ok((StatusCode::OK, format!("Stopped {} jobs", stopped))) Ok((StatusCode::OK, format!("Stopped {} jobs", stopped)))
} }
async fn fa_solid_woff2() -> impl IntoResponse {
(
[(CONTENT_TYPE, "font/woff2")],
include_bytes!("static/fontawesome/webfonts/fa-solid-900.woff2").as_slice(),
)
}
async fn fa_regular_woff2() -> impl IntoResponse {
(
[(CONTENT_TYPE, "font/woff2")],
include_bytes!("static/fontawesome/webfonts/fa-regular-400.woff2").as_slice(),
)
}
async fn fa_brands_woff2() -> impl IntoResponse {
(
[(CONTENT_TYPE, "font/woff2")],
include_bytes!("static/fontawesome/webfonts/fa-brands-400.woff2").as_slice(),
)
}
struct AppError(StatusCode, String); struct AppError(StatusCode, String);
impl IntoResponse for AppError { impl IntoResponse for AppError {