Publish bytecode release package
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
.venv/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
build/
|
||||
|
||||
tmp/
|
||||
generated/
|
||||
|
||||
vendor/ffmpeg/*.exe
|
||||
vendor/ffmpeg/*.zip
|
||||
vendor/ffmpeg/_extract/
|
||||
|
||||
vendor/gifsicle/gifsicle.exe
|
||||
vendor/gifsicle/node_modules/
|
||||
vendor/gifsicle/package.json
|
||||
vendor/gifsicle/package-lock.json
|
||||
|
||||
streamdeck/**/node_modules/
|
||||
streamdeck/**/logs/
|
||||
|
||||
*.log
|
||||
89
README.md
Normal file
@ -0,0 +1,89 @@
|
||||
# rimpac_gif_creator
|
||||
|
||||
Локальная Windows-утилита для записи выделенной области экрана в маленький GIF через вложенный `ffmpeg.exe`.
|
||||
|
||||
## Запуск
|
||||
|
||||
1. Один раз установите локальный FFmpeg, если `vendor/ffmpeg/ffmpeg.exe` отсутствует:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\tools\install_ffmpeg.ps1
|
||||
```
|
||||
|
||||
2. Установите локальный Gifsicle для дополнительного сжатия, если `vendor/gifsicle/gifsicle.exe` отсутствует:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\tools\install_gifsicle.ps1
|
||||
```
|
||||
|
||||
3. Запустите приложение двойным кликом по `rimpac_gif_creator.vbs`.
|
||||
|
||||
`run.bat` оставлен как технический запуск с консолью, если нужно увидеть ошибки.
|
||||
|
||||
## Тесты
|
||||
|
||||
Быстрый набор unit/integrity-тестов запускается без дополнительных зависимостей:
|
||||
|
||||
```powershell
|
||||
python -m unittest discover -s tests -v
|
||||
```
|
||||
|
||||
Тесты проверяют логику версий и обновлений, утилиты сборки GIF, кастомный установщик, Stream Deck-плагин, тёмный логотип, а также то, что публичный release-payload не содержит исходники приложения и установщика.
|
||||
|
||||
## Установка и обновления
|
||||
|
||||
Для продуктовой сборки используется кастомный русский GUI-инсталлятор:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\tools\build_custom_installer.ps1 -PublicRepoUrl "https://git.safe-cap.com/RIMPAC/Gif_Generator_Releases.git"
|
||||
```
|
||||
|
||||
Скрипт готовит приватную промежуточную папку `build/package/rimpac_gif_creator`, компилирует `app.py` и `updater.py` в `app.pyc` / `updater.pyc`, собирает публичный `build/release_repo` без `.py` исходников приложения, а затем упаковывает этот payload внутрь одного `build/installer/RIMPAC_GIF_Creator_Setup.exe` через PyInstaller.
|
||||
|
||||
Инсталлятор на русском языке, по умолчанию ставит программу в `C:\RIMPAC\GIF Creator`, создаёт ярлык `RIMPAC GIF Creator` на рабочем столе и использует иконку из `assets/rimpac_gif_creator.ico`. Это один `RIMPAC_GIF_Creator_Setup.exe`: `ffmpeg.exe`, `ffprobe.exe`, `gifsicle.exe` и release-payload кладутся внутрь установщика заранее, без видимых командных строк, UAC-запросов и загрузок после установки. В главном окне установщика есть явная галка Stream Deck с объяснением: если у пользователя есть Stream Deck, инсталлятор дополнительно ставит плагин в `%APPDATA%\Elgato\StreamDeck\Plugins`; если галочку не ставить, устанавливается только программа и ярлык.
|
||||
|
||||
В папку установки также кладётся `Uninstall.exe`. Установщик регистрирует удаление в Windows для текущего пользователя, поэтому программу можно удалить через `Приложения и компоненты` или прямым запуском `C:\RIMPAC\GIF Creator\Uninstall.exe`. Удалятор убирает папку программы, ярлык с рабочего стола, запись удаления Windows и, по галочке, Stream Deck-плагин.
|
||||
|
||||
Текущая версия release-пакета: `beta 0.1`. Версия хранится в `version.json` и поднимается только вручную перед выпуском новой версии.
|
||||
|
||||
Кнопка `Проверить обновления` запускает `updater.pyc`: он делает `git fetch`, читает `version.json` из установленной программы и из `origin/main`, а затем обновляется только если в публичном релизном репозитории версия новее и канал совпадает. Если версия такая же, новый коммит в релизном git не будет устанавливаться автоматически. При наличии новой версии updater закрывает программу, выполняет `git pull --ff-only`, обновляет зависимости из `requirements.txt` и запускает программу снова. За счёт git скачиваются только изменившиеся объекты, а не весь проект архивом.
|
||||
|
||||
Публичный URL обновлений хранится в `update_config.json`: `https://git.safe-cap.com/RIMPAC/Gif_Generator_Releases.git`. В этом репозитории должны лежать только release-файлы (`*.pyc`, конфиги, иконки, launcher-скрипты), без `app.py` и `updater.py`.
|
||||
|
||||
## Управление
|
||||
|
||||
- Зажмите левую кнопку мыши и выделите прямоугольник.
|
||||
- До начала записи можно тянуть рамку за края/углы, чтобы изменить размер, или за центр, чтобы перенести всю область.
|
||||
- На панели рамки кнопка `Папка` открывает `generated`, кнопка `Очист.` удаляет все GIF из этой папки.
|
||||
- Нажмите красный круг, чтобы начать запись.
|
||||
- Во время записи красный круг становится квадратом, а рамка светится красным.
|
||||
- Во время записи большой оверлей скрывается: остаются только тонкая красная рамка и маленькая панель, а клики за их пределами проходят в игру/систему.
|
||||
- Нажмите красный квадрат, чтобы остановить запись.
|
||||
- Нажмите крестик на панели, чтобы отменить и закрыть приложение.
|
||||
- После записи у выбранной рамки появится предпросмотр: двумя ползунками можно обрезать начало и конец.
|
||||
- При движении конечного ползунка предпросмотр сразу показывает последний кадр выбранного диапазона.
|
||||
- На экране предпросмотра или прогресса `Escape` отменяет операцию и удаляет временные файлы.
|
||||
- Нажмите `Создать GIF`.
|
||||
- После нажатия `Создать GIF` окно предпросмотра заменяется экраном прогресса там, где была выбранная рамка.
|
||||
- После сборки в этом же окне показывается итоговый размер GIF и статус копирования в буфер.
|
||||
- После успешной сборки это же окно остается открытым, пока вы не закроете его крестиком или `Escape`.
|
||||
- После галочки GIF уже лежит в буфере обмена как файл и сохраняется в `generated`.
|
||||
- Кнопки `Папка GIF` / `Папка` открывают `generated`, кнопки `Очистить` / `Очист.` удаляют все GIF из этой папки.
|
||||
|
||||
GIF создается с частотой 12 кадров/с, шириной до 640 px, ограниченной палитрой и финальной оптимизацией через локальный `gifsicle`.
|
||||
|
||||
Бинарники `ffmpeg.exe`, `ffprobe.exe` и `gifsicle.exe` не хранятся в git, чтобы репозиторий не раздувался. Их можно восстановить скриптами из `tools`.
|
||||
|
||||
При запуске приложение автоматически открывает оверлей на том мониторе, где сейчас находится курсор. Захват кадров выполняется через `mss`, чтобы корректно работать с несколькими мониторами.
|
||||
|
||||
## Stream Deck
|
||||
|
||||
Плагин лежит в `streamdeck/com.rimpac.gif-creator.sdPlugin` и установлен в:
|
||||
|
||||
```text
|
||||
C:\Users\User\AppData\Roaming\Elgato\StreamDeck\Plugins\com.rimpac.gif-creator.sdPlugin
|
||||
```
|
||||
|
||||
В Stream Deck ищите категорию `RIMPAC` и кнопку `GIF Creator`.
|
||||
|
||||
Если кнопка не появилась сразу, перезапустите приложение Stream Deck.
|
||||
BIN
Uninstall.exe
Normal file
BIN
assets/installer_small.bmp
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
assets/installer_wizard.bmp
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
assets/rimpac_gif_creator.ico
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/rimpac_logo.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/rimpac_logo_dark.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
pillow>=11.0.0
|
||||
mss>=10.0.0
|
||||
3
rimpac_gif_creator.vbs
Normal file
@ -0,0 +1,3 @@
|
||||
Set shell = CreateObject("WScript.Shell")
|
||||
root = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
|
||||
shell.Run """" & root & "\run.bat" & """", 0, False
|
||||
15
run.bat
Normal file
@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
setlocal
|
||||
cd /d "%~dp0"
|
||||
|
||||
if not exist ".venv\Scripts\python.exe" (
|
||||
py -m venv .venv
|
||||
".venv\Scripts\python.exe" -m pip install --upgrade pip
|
||||
".venv\Scripts\python.exe" -m pip install -r requirements.txt
|
||||
)
|
||||
|
||||
if exist "app.py" (
|
||||
".venv\Scripts\python.exe" app.py
|
||||
) else (
|
||||
".venv\Scripts\python.exe" app.pyc
|
||||
)
|
||||
45
streamdeck/com.rimpac.gif-creator.sdPlugin/bin/plugin.js
Normal file
@ -0,0 +1,45 @@
|
||||
import streamDeck, { SingletonAction } from "@elgato/streamdeck";
|
||||
import { spawn } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const pluginDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
const launcherConfig = join(pluginDir, "launcher.json");
|
||||
const fallbackLauncher = "F:\\AI\\TopSecretProjects\\ffmpeg-projects\\rimpac_gif_creator\\rimpac_gif_creator.vbs";
|
||||
|
||||
function getAppLauncher() {
|
||||
if (!existsSync(launcherConfig)) {
|
||||
return fallbackLauncher;
|
||||
}
|
||||
try {
|
||||
const config = JSON.parse(readFileSync(launcherConfig, "utf8"));
|
||||
return config.appLauncher || fallbackLauncher;
|
||||
} catch {
|
||||
return fallbackLauncher;
|
||||
}
|
||||
}
|
||||
|
||||
class LaunchGifCreatorAction extends SingletonAction {
|
||||
manifestId = "com.rimpac.gif-creator.launch";
|
||||
|
||||
async onKeyDown(ev) {
|
||||
const appLauncher = getAppLauncher();
|
||||
if (!existsSync(appLauncher)) {
|
||||
streamDeck.logger.error(`Launcher not found: ${appLauncher}`);
|
||||
await ev.action.showAlert();
|
||||
return;
|
||||
}
|
||||
|
||||
const child = spawn("wscript.exe", [appLauncher], {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
});
|
||||
child.unref();
|
||||
await ev.action.showOk();
|
||||
}
|
||||
}
|
||||
|
||||
streamDeck.actions.registerAction(new LaunchGifCreatorAction());
|
||||
streamDeck.connect();
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
39
streamdeck/com.rimpac.gif-creator.sdPlugin/manifest.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://schemas.elgato.com/streamdeck/plugins/manifest.json",
|
||||
"UUID": "com.rimpac.gif-creator",
|
||||
"Name": "RIMPAC GIF Creator",
|
||||
"Description": "Launches the local rimpac_gif_creator screen GIF recorder.",
|
||||
"Author": "RIMPAC",
|
||||
"Version": "1.0.0.0",
|
||||
"SDKVersion": 2,
|
||||
"Software": {
|
||||
"MinimumVersion": "7.1"
|
||||
},
|
||||
"Nodejs": {
|
||||
"Version": "24"
|
||||
},
|
||||
"OS": [
|
||||
{
|
||||
"Platform": "windows",
|
||||
"MinimumVersion": "10"
|
||||
}
|
||||
],
|
||||
"CodePath": "bin/plugin.js",
|
||||
"Category": "RIMPAC ffmpeg",
|
||||
"CategoryIcon": "imgs/actions/launch/icon",
|
||||
"Icon": "imgs/actions/launch/icon",
|
||||
"Actions": [
|
||||
{
|
||||
"UUID": "com.rimpac.gif-creator.launch",
|
||||
"Name": "GIF Creator",
|
||||
"Tooltip": "Start rimpac_gif_creator.",
|
||||
"Icon": "imgs/actions/launch/icon",
|
||||
"States": [
|
||||
{
|
||||
"Image": "imgs/actions/launch/key",
|
||||
"Title": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
74
streamdeck/com.rimpac.gif-creator.sdPlugin/package-lock.json
generated
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "com.rimpac.gif-creator.sdplugin",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "com.rimpac.gif-creator.sdplugin",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@elgato/streamdeck": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@elgato/schemas": {
|
||||
"version": "0.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@elgato/schemas/-/schemas-0.4.15.tgz",
|
||||
"integrity": "sha512-UpELAqazf52PFer+hqg/hvEhYoPHCH3R0af6P7Ih3Hk6xCCJENn7cA5TIpXAIGEWe6dIteHuo/e/iPGLUP7yXA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@elgato/streamdeck": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@elgato/streamdeck/-/streamdeck-2.1.0.tgz",
|
||||
"integrity": "sha512-d6wgSe93NbKAW0yT6/rabGCYUWic6nAoQoSLAXVadqTIUVmt+5Tfu7OaIGKnGER6AOn6dOpX6havRLFFFcUmOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@elgato/schemas": "^0.4.14",
|
||||
"@elgato/utils": "^0.4.4",
|
||||
"ws": "^8.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@elgato/utils": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@elgato/utils/-/utils-0.4.5.tgz",
|
||||
"integrity": "sha512-kBoqM8LEhhVLv7lNftYqaecNna3T/L85QQWU56yR1iFCvqlyyD22WmBljRcQkw5ZNvib55Br3cnrsxX3ajp+dQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"zod": "^3.25.24"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
|
||||
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
streamdeck/com.rimpac.gif-creator.sdPlugin/package.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "com.rimpac.gif-creator.sdplugin",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@elgato/streamdeck": "^2.0.4"
|
||||
}
|
||||
}
|
||||
5
update_config.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"branch": "main",
|
||||
"repo_url": "https://git.safe-cap.com/RIMPAC/Gif_Generator_Releases.git",
|
||||
"remote": "origin"
|
||||
}
|
||||
BIN
updater.pyc
Normal file
BIN
vendor/ffmpeg/ffmpeg.exe
vendored
Normal file
BIN
vendor/ffmpeg/ffprobe.exe
vendored
Normal file
BIN
vendor/gifsicle/gifsicle.exe
vendored
Normal file
4
version.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"channel": "beta",
|
||||
"version": "0.1"
|
||||
}
|
||||