diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 612b769..63ae9a1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ Describe the change and why it is needed. ## Validation -- [ ] `dotnet build .\InstantReplay.sln -c Release` +- [ ] `dotnet build .\Captail.sln -c Release` - [ ] Real Windows UI checked when applicable - [ ] Existing replay, hotkey, tray, and recovery behavior preserved - [ ] New user-facing text added to both EN and RU resources diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b604b5e..d69b9be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: with: dotnet-version: 9.0.x cache: true - cache-dependency-path: src/InstantReplay/InstantReplay.csproj + cache-dependency-path: src/Captail/Captail.csproj - name: Cache OBS runtime uses: actions/cache@v6 @@ -43,13 +43,13 @@ jobs: - name: Build Release shell: pwsh - run: dotnet build ./InstantReplay.sln -c Release -p:ContinuousIntegrationBuild=true + run: dotnet build ./Captail.sln -c Release -p:ContinuousIntegrationBuild=true - name: Validate localization dictionaries shell: pwsh run: | - [xml]$en = Get-Content ./src/InstantReplay/Languages/Strings.en.xaml - [xml]$ru = Get-Content ./src/InstantReplay/Languages/Strings.ru.xaml + [xml]$en = Get-Content ./src/Captail/Languages/Strings.en.xaml + [xml]$ru = Get-Content ./src/Captail/Languages/Strings.ru.xaml $enKeys = @($en.ResourceDictionary.String | ForEach-Object { $_.Key }) $ruKeys = @($ru.ResourceDictionary.String | ForEach-Object { $_.Key }) $differences = @(Compare-Object $enKeys $ruKeys) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dab6b3e..a265108 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: with: dotnet-version: 9.0.x cache: true - cache-dependency-path: src/InstantReplay/InstantReplay.csproj + cache-dependency-path: src/Captail/Captail.csproj - name: Cache OBS runtime uses: actions/cache@v6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d40e8a..b079505 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable user-facing changes are documented here. +## [Unreleased] + +### Changed + +- Renamed remaining solution, project, namespace, icon, and native bridge identifiers to Captail. +- Added a real interface screenshot and an OBS Replay Buffer comparison to the README. +- Standardized repository comments and diagnostic messages in English. + ## [0.1.0] - 2026-07-20 First public preview. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dbd7173..058815e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ Requirements: ```powershell .\tools\AcquireObsRuntime.ps1 -dotnet build .\InstantReplay.sln -c Debug +dotnet build .\Captail.sln -c Debug ``` ## Pull requests @@ -43,6 +43,8 @@ dotnet build .\InstantReplay.sln -c Debug ## Code style - Follow existing C# and XAML conventions. +- Use English for GitHub issues, pull requests, documentation, code comments, and diagnostic messages. +- Keep Russian text only in the Russian localization dictionary. - Prefer clear behavior over abstraction. - Keep user-facing text in EN/RU localization dictionaries. - Do not present unavailable hardware functionality as enabled. diff --git a/InstantReplay.sln b/Captail.sln similarity index 92% rename from InstantReplay.sln rename to Captail.sln index 2f84d49..94217cf 100644 --- a/InstantReplay.sln +++ b/Captail.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstantReplay", "src\InstantReplay\InstantReplay.csproj", "{FB66E8EA-3BE5-4E9C-8533-1C1B10A06151}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Captail", "src\Captail\Captail.csproj", "{FB66E8EA-3BE5-4E9C-8533-1C1B10A06151}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/README.md b/README.md index 3131c61..281653c 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ Captail is designed around one rule: **Instant Replay should stay on.** A game crash, game-to-desktop switch, temporary capture failure, protected surface, or recoverable graphics-driver interruption should not silently leave you without a replay. A watchdog monitors the recording pipeline and restarts it when recovery is possible. +

+ Captail main window showing replay status, audio sources, recording format, disk space, and save hotkey +

+ > [!WARNING] > Captail `v0.1.x` is an early public preview. Core recording works, but bugs and hardware-specific problems are expected. Please report anything that does not work. @@ -27,6 +31,16 @@ Captail is designed around one rule: **Instant Replay should stay on.** A game c - **Flexible audio** — system/game audio and microphone, volume controls, microphone boost, mixed or separate tracks. - **Local and private** — no account, cloud upload, analytics, or telemetry. Replays stay on your PC. +## How Captail differs from OBS Replay Buffer + +Captail uses libobs for capture and encoding, but it is not an OBS Studio frontend. + +- Starts directly in the system tray with Windows. +- Requires no scenes, sources, or streaming configuration. +- Monitors capture health and automatically recovers the recording pipeline. +- Switches between focused game capture and desktop capture. +- Stays focused on one job: reliable instant replay. + ## Download Download the latest version from [GitHub Releases](https://github.com/FaulMit/captail/releases). @@ -147,7 +161,7 @@ Requirements: git clone https://github.com/FaulMit/captail.git cd captail .\tools\AcquireObsRuntime.ps1 -dotnet build .\InstantReplay.sln -c Release +dotnet build .\Captail.sln -c Release ``` Create local release packages: diff --git a/docs/captail-main.jpg b/docs/captail-main.jpg new file mode 100644 index 0000000..c43d7d8 Binary files /dev/null and b/docs/captail-main.jpg differ diff --git a/installer/Captail.iss b/installer/Captail.iss index 4fa631b..14bad31 100644 --- a/installer/Captail.iss +++ b/installer/Captail.iss @@ -35,7 +35,7 @@ ArchitecturesInstallIn64BitMode=x64compatible MinVersion=10.0.19041 OutputDir={#OutputDir} OutputBaseFilename=Captail-{#MyAppVersion}-Setup-win-x64 -SetupIconFile=..\src\InstantReplay\Assets\Everloop.ico +SetupIconFile=..\src\Captail\Assets\Captail.ico UninstallDisplayIcon={app}\{#MyAppExeName} UninstallDisplayName={#MyAppName} Uninstallable=yes diff --git a/native/ObsBridge/CMakeLists.txt b/native/ObsBridge/CMakeLists.txt index 95c2c4b..3c560f8 100644 --- a/native/ObsBridge/CMakeLists.txt +++ b/native/ObsBridge/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) -project(EverloopObsBridge LANGUAGES CXX) +project(CaptailObsBridge LANGUAGES CXX) -add_library(EverloopObsBridge SHARED EverloopObsBridge.cpp) -target_compile_features(EverloopObsBridge PRIVATE cxx_std_20) -target_compile_definitions(EverloopObsBridge PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) +add_library(CaptailObsBridge SHARED CaptailObsBridge.cpp) +target_compile_features(CaptailObsBridge PRIVATE cxx_std_20) +target_compile_definitions(CaptailObsBridge PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) diff --git a/native/ObsBridge/EverloopObsBridge.cpp b/native/ObsBridge/CaptailObsBridge.cpp similarity index 100% rename from native/ObsBridge/EverloopObsBridge.cpp rename to native/ObsBridge/CaptailObsBridge.cpp diff --git a/native/ObsCaptureFixture/ObsCaptureFixture.cpp b/native/ObsCaptureFixture/ObsCaptureFixture.cpp index f2a5c42..ba00b66 100644 --- a/native/ObsCaptureFixture/ObsCaptureFixture.cpp +++ b/native/ObsCaptureFixture/ObsCaptureFixture.cpp @@ -22,7 +22,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show) WNDCLASSW window_class{}; window_class.hInstance = instance; window_class.lpfnWndProc = window_proc; - window_class.lpszClassName = L"EverloopObsCaptureFixture"; + window_class.lpszClassName = L"CaptailObsCaptureFixture"; window_class.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512)); if (!RegisterClassW(&window_class)) return 1; @@ -30,7 +30,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show) HWND window = CreateWindowExW( 0, window_class.lpszClassName, - L"Everloop OBS Capture Fixture", + L"Captail OBS Capture Fixture", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, diff --git a/src/InstantReplay/App.xaml b/src/Captail/App.xaml similarity index 93% rename from src/InstantReplay/App.xaml rename to src/Captail/App.xaml index d3e16a4..54408a1 100644 --- a/src/InstantReplay/App.xaml +++ b/src/Captail/App.xaml @@ -1,4 +1,4 @@ - diff --git a/src/InstantReplay/App.xaml.cs b/src/Captail/App.xaml.cs similarity index 97% rename from src/InstantReplay/App.xaml.cs rename to src/Captail/App.xaml.cs index e16d769..2072ef9 100644 --- a/src/InstantReplay/App.xaml.cs +++ b/src/Captail/App.xaml.cs @@ -9,7 +9,7 @@ using System.Windows.Threading; using H.NotifyIcon; -namespace InstantReplay; +namespace Captail; public partial class App : Application { @@ -355,7 +355,7 @@ private async void RunGameCaptureTest(string[] args) OutputDirectory = root, }; if (!TryStartPipeline(showError: false)) - throw new InvalidOperationException("OBS Game Capture не запустился."); + throw new InvalidOperationException("OBS Game Capture did not start."); await Task.Delay(TimeSpan.FromSeconds(8)); string path = await _obs!.SaveReplayAsync(); @@ -397,11 +397,11 @@ private async void RunFaultRecoveryTest() }; StartHealthMonitor(); if (!TryStartPipeline(showError: false)) - throw new InvalidOperationException("Исходный OBS pipeline не запустился."); + throw new InvalidOperationException("The initial OBS pipeline did not start."); DateTime originalStart = _pipelineStartedUtc; await Task.Delay(TimeSpan.FromSeconds(3)); - RecoverPipeline("QA: искусственный перезапуск OBS."); + RecoverPipeline("QA: simulated OBS restart."); await Task.Delay(TimeSpan.FromSeconds(6)); bool restarted = IsReplayRunning && _pipelineStartedUtc > originalStart; string path = restarted @@ -471,8 +471,8 @@ private bool AcquireSingleInstance(bool backgroundLaunch, bool isolatedUiTest) Environment.UserName; string suffix = userId.Replace('\\', '.') + (isolatedUiTest ? ".UiOnly" : ""); - string mutexName = $@"Local\Everloop.SingleInstance.{suffix}"; - _activationPipeName = $"Everloop.Activate.{suffix}"; + string mutexName = $@"Local\Captail.SingleInstance.{suffix}"; + _activationPipeName = $"Captail.Activate.{suffix}"; _singleInstanceMutex = new Mutex( initiallyOwned: true, mutexName, @@ -503,11 +503,11 @@ private void SendActivationCommand(string command) } catch (TimeoutException) { - // Первый экземпляр ещё запускается. + // The first instance may still be starting. } catch (IOException) { - // Pipe между попытками пересоздаётся. + // The pipe is recreated between attempts. } } } @@ -550,7 +550,7 @@ private async Task ActivationServerLoopAsync(CancellationToken cancellationToken private static void TerminateLegacyInstances() { int currentId = Environment.ProcessId; - foreach (Process process in Process.GetProcessesByName("InstantReplay")) + foreach (Process process in Process.GetProcessesByName("Captail")) { using (process) { @@ -568,7 +568,7 @@ private static void TerminateLegacyInstances() catch (Exception exception) { Log.Write( - $"Не удалось закрыть старый экземпляр PID {process.Id}: " + + $"Failed to close the previous instance PID {process.Id}: " + exception.Message); } } @@ -588,7 +588,7 @@ private void BindHotkeyAtStartup() } catch (Exception exception) { - Log.Write($"Глобальный хоткей недоступен: {exception.Message}"); + Log.Write($"Global hotkey unavailable: {exception.Message}"); _pendingUiError = exception.Message; ShowOverlayNotification( "!", @@ -639,7 +639,7 @@ private bool TryStartPipeline(bool showError) if (engine is not null) _capabilities = engine.Capabilities; StopPipeline(); - Log.Write($"Запуск OBS pipeline не удался: {exception}"); + Log.Write($"OBS pipeline startup failed: {exception}"); if (showError) { ShowOverlayNotification( @@ -667,7 +667,7 @@ private void StopPipeline() } catch (Exception exception) { - Log.Write($"Остановка OBS pipeline: {exception}"); + Log.Write($"OBS pipeline shutdown failed: {exception}"); } } @@ -1119,7 +1119,7 @@ private async Task SaveReplayCoreAsync(ObsReplayEngine engine) } catch (Exception exception) { - Log.Write($"Сохранение повтора упало: {exception}"); + Log.Write($"Replay save failed: {exception}"); ShowOverlayNotification( "!", Localization.Text("L.Notify.SaveError"), @@ -1161,7 +1161,7 @@ private static string FormatDuration(int seconds) => private static Icon CreateIcon() { using Stream stream = GetResourceStream( - new Uri("Assets/Everloop.ico", UriKind.Relative)).Stream; + new Uri("Assets/Captail.ico", UriKind.Relative)).Stream; using var icon = new Icon(stream); return (Icon)icon.Clone(); } @@ -1185,7 +1185,7 @@ protected override void OnExit(ExitEventArgs e) } catch { - // Уже освобождён во время аварийного завершения. + // Already released during emergency shutdown. } _singleInstanceMutex.Dispose(); } diff --git a/src/InstantReplay/AssemblyInfo.cs b/src/Captail/AssemblyInfo.cs similarity index 100% rename from src/InstantReplay/AssemblyInfo.cs rename to src/Captail/AssemblyInfo.cs diff --git a/src/InstantReplay/Assets/Everloop.ico b/src/Captail/Assets/Captail.ico similarity index 100% rename from src/InstantReplay/Assets/Everloop.ico rename to src/Captail/Assets/Captail.ico diff --git a/src/InstantReplay/AudioDevices.cs b/src/Captail/AudioDevices.cs similarity index 96% rename from src/InstantReplay/AudioDevices.cs rename to src/Captail/AudioDevices.cs index 6e31134..63b950f 100644 --- a/src/InstantReplay/AudioDevices.cs +++ b/src/Captail/AudioDevices.cs @@ -1,6 +1,6 @@ using NAudio.CoreAudioApi; -namespace InstantReplay; +namespace Captail; internal static class AudioDevices { diff --git a/src/InstantReplay/Autostart.cs b/src/Captail/Autostart.cs similarity index 73% rename from src/InstantReplay/Autostart.cs rename to src/Captail/Autostart.cs index 62b0ce1..d9da7b7 100644 --- a/src/InstantReplay/Autostart.cs +++ b/src/Captail/Autostart.cs @@ -1,18 +1,17 @@ using Microsoft.Win32; -namespace InstantReplay; +namespace Captail; -/// Автозапуск через HKCU\...\Run — без прав администратора. +/// Per-user startup through HKCU\...\Run; administrator rights are not required. public static class Autostart { private const string RunKey = @"Software\Microsoft\Windows\CurrentVersion\Run"; private const string ValueName = "Captail"; - private const string LegacyValueName = "InstantReplay"; public static bool IsEnabled() { using var key = Registry.CurrentUser.OpenSubKey(RunKey); - return HasCommand(key, ValueName) || HasCommand(key, LegacyValueName); + return HasCommand(key, ValueName); } public static void SetEnabled(bool enabled) @@ -27,12 +26,10 @@ public static void SetEnabled(bool enabled) ValueName, $"\"{executablePath}\" --background", RegistryValueKind.String); - key.DeleteValue(LegacyValueName, throwOnMissingValue: false); } else { key.DeleteValue(ValueName, throwOnMissingValue: false); - key.DeleteValue(LegacyValueName, throwOnMissingValue: false); } } diff --git a/src/InstantReplay/InstantReplay.csproj b/src/Captail/Captail.csproj similarity index 90% rename from src/InstantReplay/InstantReplay.csproj rename to src/Captail/Captail.csproj index 96a75a7..084a7d9 100644 --- a/src/InstantReplay/InstantReplay.csproj +++ b/src/Captail/Captail.csproj @@ -12,7 +12,8 @@ Captail Captail Captail - Assets\Everloop.ico + Captail + Assets\Captail.ico 0.1.0 @@ -23,7 +24,7 @@ - + PreserveNewest PreserveNewest @@ -51,13 +52,13 @@ - - + - @@ -65,7 +66,7 @@ AfterTargets="Publish" DependsOnTargets="BuildObsBridge" Condition="'$(PublishDir)' != ''"> - diff --git a/src/InstantReplay/Config.cs b/src/Captail/Config.cs similarity index 57% rename from src/InstantReplay/Config.cs rename to src/Captail/Config.cs index 149af7a..28081ff 100644 --- a/src/InstantReplay/Config.cs +++ b/src/Captail/Config.cs @@ -2,47 +2,47 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace InstantReplay; +namespace Captail; public sealed class Config { public string Language { get; set; } = "en"; public int BufferSeconds { get; set; } = 300; - /// 0 = ограничение только по длительности. + /// 0 = duration-only limit. public int MaxReplaySizeMb { get; set; } public int FrameRate { get; set; } = 60; - /// 0 = адаптивный битрейт по кодеку и нагрузке. + /// 0 = adaptive bitrate based on codec and load. public int BitrateMbps { get; set; } public string Hotkey { get; set; } = "Ctrl+Shift+F10"; public string ToggleReplayHotkey { get; set; } = "Ctrl+Shift+F9"; public bool ReplayEnabled { get; set; } = true; - /// "av1", "hevc" или "h264". OBS выбирает доступный encoder нужного формата. + /// "av1", "hevc", or "h264". OBS selects an available encoder for the requested format. public string Codec { get; set; } = "h264"; public int MonitorIndex { get; set; } - /// "source", "720p", "1080p", "1440p" или "2160p". + /// "source", "720p", "1080p", "1440p", or "2160p". public string RecordingResolution { get; set; } = "source"; - /// "desktop" или "game". + /// "desktop" or "game". public string CaptureSource { get; set; } = "desktop"; - /// Полный путь к EXE выбранной игры; PID определяется при запуске pipeline. + /// Full path to the selected game executable; PID is resolved when the pipeline starts. public string GameExecutablePath { get; set; } = ""; public bool CaptureSystemAudio { get; set; } = true; public int SystemAudioVolume { get; set; } = 100; - /// ID render-устройства для loopback; пусто — дефолтное устройство Windows. + /// Render-device ID used for loopback; empty selects the Windows default device. public string SystemAudioDeviceId { get; set; } = ""; public bool CaptureMicrophone { get; set; } public int MicrophoneVolume { get; set; } = 100; public int MicrophoneBoostDb { get; set; } - /// ID устройства микрофона; пусто — дефолтный микрофон Windows. + /// Microphone device ID; empty selects the Windows default microphone. public string MicrophoneDeviceId { get; set; } = ""; public int AudioBitrateKbps { get; set; } = 192; - /// "aac" для fragmented MP4 или "opus" для MKV. + /// "aac" for fragmented MP4 or "opus" for MKV. public string AudioCodec { get; set; } = "aac"; /// - /// true — звук системы и микрофон сохраняются отдельными аудиодорожками; - /// false — источники сводятся в одну дорожку. + /// true stores system audio and microphone on separate tracks; + /// false mixes both sources into one track. /// public bool SeparateAudioTracks { get; set; } @@ -51,31 +51,22 @@ public sealed class Config [JsonIgnore] public static string ConfigPath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Captail", "config.json"); - [JsonIgnore] - private static string LegacyConfigPath => - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "InstantReplay", "config.json"); - public static Config Load() { - foreach (string path in new[] { ConfigPath, LegacyConfigPath }) + try { - try + if (File.Exists(ConfigPath)) { - if (!File.Exists(path)) - continue; - Config config = - JsonSerializer.Deserialize(File.ReadAllText(path)) ?? + JsonSerializer.Deserialize(File.ReadAllText(ConfigPath)) ?? new Config(); config.Language = NormalizeLanguage(config.Language); - if (!string.Equals(path, ConfigPath, StringComparison.OrdinalIgnoreCase)) - config.Save(); return config; } - catch - { - // Пробуем следующий путь; повреждённый конфиг не роняет запуск. - } + } + catch + { + // A damaged config must not prevent startup. } var defaultConfig = new Config(); diff --git a/src/InstantReplay/EncoderCapabilities.cs b/src/Captail/EncoderCapabilities.cs similarity index 99% rename from src/InstantReplay/EncoderCapabilities.cs rename to src/Captail/EncoderCapabilities.cs index 331305c..8193e1a 100644 --- a/src/InstantReplay/EncoderCapabilities.cs +++ b/src/Captail/EncoderCapabilities.cs @@ -1,4 +1,4 @@ -namespace InstantReplay; +namespace Captail; public sealed record CodecCapability( string Codec, diff --git a/src/InstantReplay/HotkeyManager.cs b/src/Captail/HotkeyManager.cs similarity index 96% rename from src/InstantReplay/HotkeyManager.cs rename to src/Captail/HotkeyManager.cs index 587b8df..7e1f2ca 100644 --- a/src/InstantReplay/HotkeyManager.cs +++ b/src/Captail/HotkeyManager.cs @@ -2,9 +2,9 @@ using System.Windows.Input; using System.Windows.Interop; -namespace InstantReplay; +namespace Captail; -/// Два глобальных хоткея: сохранение повтора и включение/выключение буфера. +/// Global hotkeys for saving a replay and toggling the replay buffer. public sealed class HotkeyManager : IDisposable { [DllImport("user32.dll")] diff --git a/src/InstantReplay/Interop/CaptureInterop.cs b/src/Captail/Interop/CaptureInterop.cs similarity index 96% rename from src/InstantReplay/Interop/CaptureInterop.cs rename to src/Captail/Interop/CaptureInterop.cs index ec5132c..cc9a37e 100644 --- a/src/InstantReplay/Interop/CaptureInterop.cs +++ b/src/Captail/Interop/CaptureInterop.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; using System.Text; -namespace InstantReplay.Interop; +namespace Captail.Interop; internal static class CaptureInterop { @@ -153,7 +153,7 @@ public static bool IsProcessRunning(string executablePath) } catch { - // Защищённые системные процессы не являются выбранной игрой. + // Protected system processes cannot be the selected game. } process.Dispose(); diff --git a/src/InstantReplay/Languages/Strings.en.xaml b/src/Captail/Languages/Strings.en.xaml similarity index 100% rename from src/InstantReplay/Languages/Strings.en.xaml rename to src/Captail/Languages/Strings.en.xaml diff --git a/src/InstantReplay/Languages/Strings.ru.xaml b/src/Captail/Languages/Strings.ru.xaml similarity index 100% rename from src/InstantReplay/Languages/Strings.ru.xaml rename to src/Captail/Languages/Strings.ru.xaml diff --git a/src/InstantReplay/Localization.cs b/src/Captail/Localization.cs similarity index 98% rename from src/InstantReplay/Localization.cs rename to src/Captail/Localization.cs index b0c84e4..8ea36ca 100644 --- a/src/InstantReplay/Localization.cs +++ b/src/Captail/Localization.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Windows; -namespace InstantReplay; +namespace Captail; public static class Localization { diff --git a/src/InstantReplay/Log.cs b/src/Captail/Log.cs similarity index 95% rename from src/InstantReplay/Log.cs rename to src/Captail/Log.cs index 734e8e9..fe477c5 100644 --- a/src/InstantReplay/Log.cs +++ b/src/Captail/Log.cs @@ -1,6 +1,6 @@ using System.IO; -namespace InstantReplay; +namespace Captail; public static class Log { diff --git a/src/InstantReplay/ObsLogBridge.cs b/src/Captail/ObsLogBridge.cs similarity index 76% rename from src/InstantReplay/ObsLogBridge.cs rename to src/Captail/ObsLogBridge.cs index 9a34551..5ef1a5d 100644 --- a/src/InstantReplay/ObsLogBridge.cs +++ b/src/Captail/ObsLogBridge.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace InstantReplay; +namespace Captail; internal static class ObsLogBridge { @@ -11,18 +11,18 @@ private delegate void LogCallback( private static readonly LogCallback Callback = Write; - [DllImport("EverloopObsBridge.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("CaptailObsBridge.dll", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private static extern bool everloop_install_obs_log_handler(LogCallback callback); - [DllImport("EverloopObsBridge.dll", CallingConvention = CallingConvention.Cdecl)] + [DllImport("CaptailObsBridge.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void everloop_remove_obs_log_handler(); internal static bool Install() { bool installed = everloop_install_obs_log_handler(Callback); if (!installed) - Log.Write("OBS log bridge не установился."); + Log.Write("OBS log bridge could not be installed."); return installed; } diff --git a/src/InstantReplay/ObsNative.cs b/src/Captail/ObsNative.cs similarity index 99% rename from src/InstantReplay/ObsNative.cs rename to src/Captail/ObsNative.cs index 172ca30..bef1587 100644 --- a/src/InstantReplay/ObsNative.cs +++ b/src/Captail/ObsNative.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace InstantReplay; +namespace Captail; internal static class ObsNative { diff --git a/src/InstantReplay/ObsReplayEngine.cs b/src/Captail/ObsReplayEngine.cs similarity index 98% rename from src/InstantReplay/ObsReplayEngine.cs rename to src/Captail/ObsReplayEngine.cs index fb2d46c..0baf990 100644 --- a/src/InstantReplay/ObsReplayEngine.cs +++ b/src/Captail/ObsReplayEngine.cs @@ -1,8 +1,8 @@ using System.IO; using System.Runtime.InteropServices; -using InstantReplay.Interop; +using Captail.Interop; -namespace InstantReplay; +namespace Captail; public sealed class ObsReplayEngine : IDisposable { @@ -163,7 +163,7 @@ public static EncoderCapabilities ProbeCapabilities(Config config) } catch (Exception exception) { - Log.Write($"Проверка возможностей GPU не удалась: {exception}"); + Log.Write($"GPU capability detection failed: {exception}"); return EncoderCapabilities.Failed(exception.Message); } finally @@ -479,8 +479,8 @@ private void CreateSources() } else { - // WGC переживает secure/DRM-поверхности и сбросы DXGI стабильнее; - // защищённые участки становятся чёрными, сам источник не останавливается. + // WGC handles secure/DRM surfaces and DXGI resets more reliably; + // protected regions become black without stopping the source. ObsNative.obs_data_set_int(videoSettings, "method", 2); ObsNative.obs_data_set_string( videoSettings, @@ -628,8 +628,8 @@ private void CreateEncoders() if (_videoEncoder == 0) { Log.Write( - $"Кодировщик {candidate.EncoderId} отклонил профиль " + - $"{loadProfile}; пробуем следующий."); + $"Encoder {candidate.EncoderId} rejected profile " + + $"{loadProfile}; trying the next candidate."); continue; } @@ -922,7 +922,7 @@ private int AudioTrackCount() int enabled = (_config.CaptureSystemAudio ? 1 : 0) + (_config.CaptureMicrophone ? 1 : 0); if (enabled == 0) - return 1; // Replay Buffer требует аудиокодировщик; дорожка остаётся тихой. + return 1; // Replay Buffer requires an audio encoder; this track remains silent. return _config.SeparateAudioTracks && enabled > 1 ? 2 : 1; } diff --git a/src/InstantReplay/OverlayNotificationWindow.xaml b/src/Captail/OverlayNotificationWindow.xaml similarity index 97% rename from src/InstantReplay/OverlayNotificationWindow.xaml rename to src/Captail/OverlayNotificationWindow.xaml index 457c8d7..7bd6d34 100644 --- a/src/InstantReplay/OverlayNotificationWindow.xaml +++ b/src/Captail/OverlayNotificationWindow.xaml @@ -1,4 +1,4 @@ - + @@ -155,7 +155,7 @@ - + - + - + - + - +