Версия: 0.5.2
██╗███╗ ███╗ █████╗ ██╗ ██╗ █████╗ ██║████╗ ████║██╔══██╗██║ ██╔╝██╔══██╗ ██║██╔████╔██║███████║█████╔╝ ███████║ ██ ██║██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══██║ ╚█████╔╝██║ ╚═╝ ██║██║ ██║██║ ██╗██║ ██║ ╚════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
Небольшое веб-приложение на ASP.NET Core (Minimal API) для загрузки и обработки изображений/видео через простой веб-интерфейс.
- Глобальный переключатель языка интерфейса: RU / EN / ES (перевод UI, статусов, подсказок и модалок).
- Загрузка нескольких изображений (до 15 за раз), лимит 75 MB на файл, серверные имена — UUID.
- Все загруженные изображения нормализуются в JPEG + sRGB с embedded ICC профилем.
- Для изображений автоматически создаются миниатюры превью (
/preview/*). - Общая история загрузок (
/history) с сортировкой «новые сверху». - Ресайз по фиксированным ширинам 1280 / 1920 / 2440 по запросу (
/resize), апскейл разрешён. - Кадрирование (Crop) с выбором пропорций (1:1, 2:3, 16:9) от неизменённого исходника (
upload-original/*). - Split: склейка двух изображений в одно 1280×720 с белой полосой 7px по центру (
/split). - Split3: склейка трёх изображений в одно 1280×720 с двумя белыми полосами 7px (
/split3). - OknoFix: генерация вертикальной карточки по PNG-шаблону (портретная «карточка» с рамкой/тенями).
- OknoScale: экспериментальный режим той же карточки с изменяемой шириной окна.
- Image Edit: серверный редактор с параметрами Brightness/Contrast/Saturation/Hue/Exposure/Vibrance (результат сохраняется как новый файл).
- Video Edit: загрузка видео с полным набором инструментов редактирования:
- Trim — тримминг и вырезание сегментов из середины видео
- Timeline Concat — склейка 2+ оригиналов в один результат через добавление клипов кнопкой
+в конце таймлайна - Per-Clip Segments — для каждого добавленного клипа можно задать несколько сегментов (вырезок)
- Per-Mode Vertical Offset Memory — вертикальная позиция видео запоминается отдельно для режимов Vidcov и Episod
- Crop — кадрирование видео (нормализованные координаты 0-1)
- Rotate — поворот на 90°/180°/270°
- Flip — отражение по горизонтали и вертикали
- Speed — изменение скорости воспроизведения (0.25x - 2.0x)
- Mute Audio — отключение звуковой дорожки
- Overlay Templates — загрузка/выбор PNG/WebP/JPEG шаблона поверх видео
- Reset — сброс всех изменений
- фоновые задачи обработки и нормализации с отображением очереди/прогресса в интерфейсе
- 2-pass сжатие в целевой размер, выход 16:9 H.264 с AAC аудио (или без звука)
- Удаление записи из истории и всех связанных файлов (
/delete). - Авто-очистка старых файлов по времени хранения (retention, по умолчанию 48 часов).
- Кнопка-дискета открывает диалог выбора файлов (до 15 штук).
- Можно перетащить файлы мышью на окно (drag & drop).
- Можно вставить изображение из буфера обмена (Ctrl+V).
- В шапке доступен быстрый переключатель языка интерфейса (RU/EN/ES).
- В левой таблице показываются все загруженные изображения.
- В колонке «Оригинал» — миниатюра превью и маленькая кнопка-дискета для скачивания.
- Кнопки размеров 1280 / 1920 / 2440 создают оптимизированные копии по запросу.
- Крестик справа удаляет запись и все связанные файлы.
- Crop — интерактивное кадрирование с выбором пропорций; режется всегда от исходника в
upload-original. - Split — два изображения → один кадр 1280×720 с белой полосой посередине.
- Split3 — три изображения → один кадр 1280×720 с двумя белыми полосами.
- OknoFix — строгий режим вертикальной карточки:
- окно фиксировано по высоте и положению как во встроенном PNG-шаблоне;
- картинка подложки пропорционально масштабируется и двигается под этим окном;
- масштаб меняется колесом мыши или кнопками «−»/«+» внизу справа;
- результат на выходе совпадает с тем, что видно в окне.
- OknoScale — экспериментальный режим той же карточки с изменяемой шириной окна (для проб разных компоновок).
Правая таблица показывает историю результатов Split / Split3 / OknoFix / OknoScale / Edits, каждый результат можно открыть, скачать или удалить.
Image output is always JPEG + sRGB with embedded ICC profile.
Все изображения на выходе гарантированно имеют формат JPEG с встроенным ICC профилем sRGB. Подробности о цветовом менеджменте, ограничениях и best practices см. в docs/COLOR_MANAGEMENT.md.
dotnet run --project src/Jmaka.Api --launch-profile http- открыть
http://localhost:5189/ - bounded smoke check:
powershell -NoProfile -ExecutionPolicy Bypass -File .\tests\smoke-api-version.ps1
POST /upload(multipart/form-data полеfiles, можно несколько)POST /upload-video(multipart/form-data полеfile, один файл)GET /video/upload-jobs/{jobId}(статус нормализации загруженного видео)GET /video/jobs/{jobId}(статус задачи обработки видео)POST /video/jobs/{jobId}/cancel(отмена задачи обработки)POST /video-process(JSON с поддержкой multi-source, например{ storedName, sourceStoredNames, sourceClips, trimStartSec, trimEndSec, outputWidth, targetSizeMb, verticalOffsetPx, segments, cropX, cropY, cropW, cropH, rotateDeg, flipH, flipV, speed, muteAudio, encodingMode, overlayTemplateRelativePath }, гдеsourceClipsможет содержать per-cliptrimStartSec/trimEndSecиsegments[])GET /video-overlay-templates(список доступных overlay-шаблонов)POST /upload-video-overlay-template(multipart/form-data полеfile, шаблон overlay)POST /resize(JSON{ storedName, width })POST /crop(JSON{ storedName, x, y, width, height })POST /split(JSON{ storedNameA, storedNameB, a, b }, результат 1280×720)POST /split3(JSON{ storedNameA, storedNameB, storedNameC, a, b, c }, результат 1280×720)POST /oknofix(JSON{ storedName, x, y, w, h }, вертикальная карточка по PNG-шаблону)POST /oknoscale(JSON{ storedName, x, y, w, h }, вертикальная карточка с изменяемой шириной окна)POST /image-edit-preview(JSON{ storedName, brightness, contrast, saturation, hue, exposure, vibrance })POST /image-edit-apply(JSON{ storedName, brightness, contrast, saturation, hue, exposure, vibrance })GET /historyGET /compositesPOST /delete(JSON{ storedName })POST /delete-composite(JSON{ relativePath })GET /api/version
Нужно: VPS с Ubuntu 24 + установленный nginx (как reverse-proxy). Установщик сам поставит ffmpeg/ffprobe для работы видео.
Мы прикладываем готовые архивы к релизам и будем делать так всегда.
curl -L -o ~/jmaka.tar.gz \
https://github.com/Efidripy/Jmaka/releases/latest/download/jmaka-linux-x64.tar.gz \
&& mkdir -p ~/jmaka_bundle \
&& tar -xzf ~/jmaka.tar.gz -C ~/jmaka_bundle \
&& curl -L -o ~/jmaka-install.sh \
https://raw.githubusercontent.com/Efidripy/Jmaka/main/deploy/ubuntu24/install.sh \
&& bash ~/jmaka-install.sh --interactiveПояснения:
~/jmaka.tar.gz— архив релиза.~/jmaka_bundle/— распакованное содержимое архива (для проверки). Установщик всё равно использует tar.gz и сам раскладывает файлы в/var/www/jmaka/....
Из корня репозитория:
powershell -NoProfile -ExecutionPolicy Bypass -File .\deploy\publish-linux.ps1
Результат: artifacts/jmaka-linux-x64.tar.gz
Если репозиторий уже на сервере, можно запускать напрямую:
bash deploy/ubuntu24/install.sh
Или (рекомендуется для “без git”):
- скачать
install.shв домашнюю папку и запустить:bash ~/jmaka-install.sh
Скрипт сам запросит sudo (если нужно) и по умолчанию возьмёт архив из ~/jmaka.tar.gz.
Скрипт задаст вопросы и:
- разложит файлы в
/var/www/jmaka/<name>/app - создаст storage в
/var/www/jmaka/<name>/storage - создаст systemd сервис
jmaka-<name>на127.0.0.1:<port> - проверит недостающие компоненты (пакеты, runtime)
- покажет занятые порты и предложит первый свободный в диапазоне 5000-5999
- по выбору: распечатает конфиг nginx или создаст файл в
/etc/nginx/...
- Отдельный домен/поддомен целиком под Jmaka (root
/)
- выбирайте path prefix
/ - nginx проксирует
location /на127.0.0.1:<port>
- Подключение к существующему домену в подпапку (например
/jmaka/)
- выбирайте path prefix
/jmaka/ - приложение автоматически включает base-path через
JMAKA_BASE_PATH=/jmaka - nginx должен иметь
location /jmaka/ { proxy_pass http://127.0.0.1:<port>; }(важно: БЕЗ слэша в конце proxy_pass, чтобы префикс /jmaka/ дошёл до приложения)
Статус и логи:
systemctl status jmaka-<name> --no-pagerjournalctl -u jmaka-<name> -n 200 --no-pager
Проверка nginx:
nginx -t && systemctl reload nginx
JMAKA_STORAGE_ROOT— куда писать upload/resized/preview/data (скрипт ставит в/var/www/jmaka/<name>/storage)JMAKA_BASE_PATH— base-path для подпапки (например/jmaka),/= корень
Если Jmaka уже установлен через install.sh и работает как systemd-сервис jmaka-<name>, обновление делается отдельным скриптом:
-
Скопировать новый архив с релиза на сервер, например:
cd ~ curl -L -o jmaka.tar.gz \ https://github.com/Efidripy/Jmaka/releases/latest/download/jmaka-linux-x64.tar.gz
-
Запустить апдейтер из корня репозитория или после скачивания
update-instance.sh:# если репозиторий уже на сервере sudo bash deploy/ubuntu24/update-instance.sh # либо скачать скрипт отдельно и запустить curl -L -o ~/jmaka-update.sh \ https://raw.githubusercontent.com/Efidripy/Jmaka/main/deploy/ubuntu24/update-instance.sh sudo bash ~/jmaka-update.sh
Скрипт сам:
- найдёт все
jmaka-*.serviceи покажет для каждого appDir, порт, base-path и текущую версию; - даст выбрать один инстанс или все сразу;
- спросит путь к архиву (по умолчанию
~/jmaka.tar.gz); - остановит выбранный сервис(ы), сделает бэкап каталога
app→app.bak-YYYYMMDD-HHMMSS; - очистит
app, распакует туда новый архив, выставит права и перезапустит сервис(ы).
dotnet run --project src/Jmaka.Api --launch-profile http- открыть
http://localhost:5189/ - bounded smoke check:
powershell -NoProfile -ExecutionPolicy Bypass -File .\tests\smoke-api-version.ps1
Если dotnet build -c Release падает с ошибкой, что файл Jmaka.Api.exe занят — значит запущен процесс из bin/Release. Остановите его и пересоберите.
- @Efidripy — Efidripy