8 Commits

Author SHA1 Message Date
Kareem Horstink 1c6848bb9e ci: add architecture suffix to binary names 2026-07-01 08:27:11 +00:00
Kareem Horstink ad7860161a chore: explicitly set Core project as Library output type 2026-07-01 08:17:32 +00:00
Kareem Horstink fa679e441e ci: add rolling draft release workflow 2026-07-01 08:07:35 +00:00
Kareem Horstink 8bd53587d1 add publish scripts (PowerShell + bash) for single-command cross-platform builds 2026-07-01 06:05:16 +00:00
Imrayya 817b476c5f Update known issues in README
Remove mention of Plex Transcoder subtitle issues.
2026-06-26 00:32:35 +07:00
Imrayya 02176d0d7e Revise instructions in README
Updated CLI and GUI publishing instructions for self-contained builds on various platforms
Updated the CLI and GUI usage guide
2026-06-26 00:28:03 +07:00
Kareem Horstink 1c5d2e3934 fix: wire up Convert button Click handler (was never attached) 2026-06-25 17:04:40 +00:00
Kareem Horstink 9b7b8df874 fix: wire up GUI browse buttons, make text boxes editable, pause CLI on error, register codepage provider
GUI:
- Attach Click event handlers to browse input/output buttons (were defined but never wired up)
- Remove ReadOnly=true from input/output text boxes so users can type or copy paths

CLI:
- Make Cli.Run return bool to signal errors
- Only pause with Console.ReadLine() when an error occurs (not on success)
- Fix default case to return true

Core:
- Add System.Text.Encoding.CodePages package for CP1252 SRT file support
- Call Encoding.RegisterProvider(CodePagesEncodingProvider.Instance) before reading files
2026-06-25 16:46:05 +00:00
10 changed files with 213 additions and 30 deletions
+78
View File
@@ -0,0 +1,78 @@
name: Build and Draft
on:
push:
branches: [main]
permissions:
contents: write
jobs:
build-and-draft:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
# ---- Build all 5 binaries (no version in filenames needed) ----
- name: Build CLI - Linux x64
run: |
dotnet publish ConvertSRTto3DASS.Cli \
-c Release -r linux-x64 --self-contained false \
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true \
-o publish/linux-x64/
mv publish/linux-x64/ConvertSRTto3DASS publish/linux-x64/ConvertSRTto3DASS-cli-linux-x64
- name: Build CLI - macOS x64
run: |
dotnet publish ConvertSRTto3DASS.Cli \
-c Release -r osx-x64 --self-contained false \
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true \
-o publish/osx-x64/
mv publish/osx-x64/ConvertSRTto3DASS publish/osx-x64/ConvertSRTto3DASS-cli-osx-x64
- name: Build CLI - macOS arm64
run: |
dotnet publish ConvertSRTto3DASS.Cli \
-c Release -r osx-arm64 --self-contained false \
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true \
-o publish/osx-arm64/
mv publish/osx-arm64/ConvertSRTto3DASS publish/osx-arm64/ConvertSRTto3DASS-cli-osx-arm64
- name: Build CLI - Windows x64
run: |
dotnet publish ConvertSRTto3DASS.Cli \
-c Release -r win-x64 --self-contained false \
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true \
-o publish/win-x64/
mv publish/win-x64/ConvertSRTto3DASS.exe publish/win-x64/ConvertSRTto3DASS-cli-win-x64.exe
- name: Build GUI - Windows x64
run: |
dotnet publish ConvertSRTto3DASS.Gui \
-c Release -r win-x64 --self-contained false \
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true \
-p:EnableWindowsTargeting=true \
-o publish/gui-win-x64/
mv publish/gui-win-x64/ConvertSRTto3DASS.exe publish/gui-win-x64/ConvertSRTto3DASS-gui-win-x64.exe
# ---- Update (or create) the rolling draft release ----
- name: Update Rolling Draft Release
uses: ncipollo/release-action@v1
with:
allowUpdates: true
draft: true
tag: rolling-draft
name: "Draft (latest build)"
body: "Latest binaries from commit ${{ github.sha }}. Edit tag, name, and notes before publishing."
artifacts: |
publish/linux-x64/ConvertSRTto3DASS-cli-linux-x64
publish/osx-x64/ConvertSRTto3DASS-cli-osx-x64
publish/osx-arm64/ConvertSRTto3DASS-cli-osx-arm64
publish/win-x64/ConvertSRTto3DASS-cli-win-x64.exe
publish/gui-win-x64/ConvertSRTto3DASS-gui-win-x64.exe
+6 -4
View File
@@ -4,19 +4,19 @@ namespace ConvertSRTto3DASS;
internal static class Cli internal static class Cli
{ {
public static void Run(string[] args) public static bool Run(string[] args)
{ {
if (args.Length == 0 || args[0] is "--help" or "-h" or "/?") if (args.Length == 0 || args[0] is "--help" or "-h" or "/?")
{ {
PrintUsage(); PrintUsage();
return; return false;
} }
var inputPath = args[0]; var inputPath = args[0];
if (!File.Exists(inputPath)) if (!File.Exists(inputPath))
{ {
Console.Error.WriteLine($"Input file not found: {inputPath}"); Console.Error.WriteLine($"Input file not found: {inputPath}");
return; return true;
} }
// Parse options // Parse options
@@ -80,7 +80,7 @@ internal static class Cli
break; break;
default: default:
Console.Error.WriteLine($"Unknown argument: {args[i]}"); Console.Error.WriteLine($"Unknown argument: {args[i]}");
return; return true;
} }
i++; i++;
} }
@@ -106,11 +106,13 @@ internal static class Cli
var result = SrtConverter.Convert(options); var result = SrtConverter.Convert(options);
Console.WriteLine($"Parsed: {result.SubtitleCount} subtitle blocks"); Console.WriteLine($"Parsed: {result.SubtitleCount} subtitle blocks");
Console.WriteLine("Conversion complete."); Console.WriteLine("Conversion complete.");
return false;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.Error.WriteLine($"ERROR: {ex.Message}"); Console.Error.WriteLine($"ERROR: {ex.Message}");
Console.Error.WriteLine(ex.ToString()); Console.Error.WriteLine(ex.ToString());
return true;
} }
string GetNextArg(int index) => index + 1 < args.Length ? args[index + 1] : throw new ArgumentException($"Missing value for {args[index]}"); string GetNextArg(int index) => index + 1 < args.Length ? args[index + 1] : throw new ArgumentException($"Missing value for {args[index]}");
@@ -13,6 +13,9 @@
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <PropertyGroup Condition="'$(Configuration)' == 'Release'">
<Optimize>true</Optimize> <Optimize>true</Optimize>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>false</PublishReadyToRun>
<StripSymbols>true</StripSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
+6 -1
View File
@@ -2,5 +2,10 @@ namespace ConvertSRTto3DASS;
internal static class Program internal static class Program
{ {
static void Main(string[] args) => Cli.Run(args); static void Main(string[] args)
{
var hadError = Cli.Run(args);
if (hadError)
Console.ReadLine();
}
} }
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -9,6 +10,10 @@
<RootNamespace>ConvertSRTto3DASS</RootNamespace> <RootNamespace>ConvertSRTto3DASS</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <PropertyGroup Condition="'$(Configuration)' == 'Release'">
<Optimize>true</Optimize> <Optimize>true</Optimize>
</PropertyGroup> </PropertyGroup>
+3
View File
@@ -16,6 +16,9 @@ public static class SrtConverter
public static ConversionResult Convert(ConversionOptions options) public static ConversionResult Convert(ConversionOptions options)
{ {
// Register legacy codepage support (needed for CP1252, etc.)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var srtText = ReadSrt(options.InputPath); var srtText = ReadSrt(options.InputPath);
var subtitles = ParseSrt(srtText); var subtitles = ParseSrt(srtText);
var header = CreateHeader(options); var header = CreateHeader(options);
+6 -2
View File
@@ -71,11 +71,13 @@ partial class Form1
Size = new Size(1040, 80) Size = new Size(1040, 80)
}; };
label_InputFile = new Label { Text = "Input SRT:", Font = segoe, Location = new Point(15, 25), AutoSize = true }; label_InputFile = new Label { Text = "Input SRT:", Font = segoe, Location = new Point(15, 25), AutoSize = true };
textBox_InputFile = new TextBox { Location = new Point(100, 22), Size = new Size(780, 23), ReadOnly = true }; textBox_InputFile = new TextBox { Location = new Point(100, 22), Size = new Size(780, 23) };
button_BrowseInput = new Button { Text = "Browse...", Location = new Point(890, 20), Size = new Size(90, 25), Font = segoe, FlatStyle = FlatStyle.Flat }; button_BrowseInput = new Button { Text = "Browse...", Location = new Point(890, 20), Size = new Size(90, 25), Font = segoe, FlatStyle = FlatStyle.Flat };
button_BrowseInput.Click += button_BrowseInput_Click;
label_OutputFile = new Label { Text = "Output ASS:", Font = segoe, Location = new Point(15, 55), AutoSize = true }; label_OutputFile = new Label { Text = "Output ASS:", Font = segoe, Location = new Point(15, 55), AutoSize = true };
textBox_OutputFile = new TextBox { Location = new Point(100, 52), Size = new Size(780, 23), ReadOnly = true }; textBox_OutputFile = new TextBox { Location = new Point(100, 52), Size = new Size(780, 23) };
button_BrowseOutput = new Button { Text = "Browse...", Location = new Point(890, 50), Size = new Size(90, 25), Font = segoe, FlatStyle = FlatStyle.Flat }; button_BrowseOutput = new Button { Text = "Browse...", Location = new Point(890, 50), Size = new Size(90, 25), Font = segoe, FlatStyle = FlatStyle.Flat };
button_BrowseOutput.Click += button_BrowseOutput_Click;
groupBox_File.Controls.AddRange([label_InputFile, textBox_InputFile, button_BrowseInput, label_OutputFile, textBox_OutputFile, button_BrowseOutput]); groupBox_File.Controls.AddRange([label_InputFile, textBox_InputFile, button_BrowseInput, label_OutputFile, textBox_OutputFile, button_BrowseOutput]);
// ---- Mode section ---- // ---- Mode section ----
@@ -95,6 +97,7 @@ partial class Form1
DropDownStyle = ComboBoxStyle.DropDownList DropDownStyle = ComboBoxStyle.DropDownList
}; };
comboBox_Mode.Items.AddRange(["SBS (Side-by-Side)", "OU (Over-Under)", "RG (Red-Green)"]); comboBox_Mode.Items.AddRange(["SBS (Side-by-Side)", "OU (Over-Under)", "RG (Red-Green)"]);
comboBox_Mode.SelectedIndexChanged += comboBox_Mode_SelectedIndexChanged;
groupBox_Mode.Controls.AddRange([label_Mode, comboBox_Mode]); groupBox_Mode.Controls.AddRange([label_Mode, comboBox_Mode]);
// ---- Resolution section ---- // ---- Resolution section ----
@@ -165,6 +168,7 @@ partial class Form1
ForeColor = Color.White, ForeColor = Color.White,
FlatAppearance = { BorderSize = 0 } FlatAppearance = { BorderSize = 0 }
}; };
button_Convert.Click += button_Convert_Click;
// ---- Status ---- // ---- Status ----
textBox_Status = new TextBox textBox_Status = new TextBox
+37 -23
View File
@@ -28,19 +28,27 @@ The application runs in two modes — **GUI** (no arguments) and **CLI** (with a
4. Adjust settings as needed 4. Adjust settings as needed
5. Click **Convert** 5. Click **Convert**
> **Note:** The GUI is experimental. Feedback and bug reports are welcome!
### Command Line ### Command Line
Pass any argument to trigger CLI mode: The CLI runs on **Windows, Linux, and macOS**.
``` #### Drag and drop:
ConvertSRTto3DASS.exe input.srt [options] 1. Drag and drop an `.srt` file onto `ConvertSRTto3DASS`
``` - Uses default settings (SBS mode, 1280x720)
2. The resulting `.ass` file will be saved in the same directory as the `.srt`
Or drag and drop an `.srt` file onto the executable. #### Command line:
```
Available options: ConvertSRTto3DASS.exe input.srt [options]
```
##### Available options:
```
```
--mode sbs|ou|rg 3D mode (default: sbs) --mode sbs|ou|rg 3D mode (default: sbs)
--resx <number> Output width --resx <number> Output width
--resy <number> Output height --resy <number> Output height
@@ -54,21 +62,20 @@ Available options:
--verticalmargin <number> General vertical margin --verticalmargin <number> General vertical margin
--output <path> Output file path --output <path> Output file path
--help, -h, /? Show help --help, -h, /? Show help
```
Examples: ```
##### Examples:
```
``` ConvertSRTto3DASS.exe movie.srt --mode sbs
ConvertSRTto3DASS.exe movie.srt --mode sbs ConvertSRTto3DASS.exe movie.srt --mode ou --resx 1920 --resy 1080
ConvertSRTto3DASS.exe movie.srt --mode ou --resx 1920 --resy 1080 ConvertSRTto3DASS.exe movie.srt --mode rg --offsetx 6 --bottomoffset 24
ConvertSRTto3DASS.exe movie.srt --mode rg --offsetx 6 --bottomoffset 24
```
> **Note:** The GUI is experimental. Feedback and bug reports are welcome! ```
## Known Issues ## Known Issues
- Plex Transcoder has issues with the converted subtitles. VLC works correctly.
- Subtitle positional data from `.srt` files is stripped during conversion. - Subtitle positional data from `.srt` files is stripped during conversion.
## Requirements ## Requirements
@@ -83,14 +90,21 @@ ConvertSRTto3DASS.exe movie.srt --mode rg --offsetx 6 --bottomoffset 24
# Build all projects # Build all projects
dotnet build dotnet build
# Publish CLI (cross-platform) # Publish CLI (self-contained)
dotnet publish ConvertSRTto3DASS.Cli -c Release -r linux-x64 --self-contained false -p:PublishSingleFile=true ## Linux x64
dotnet publish ConvertSRTto3DASS.Cli -c Release -r osx-x64 --self-contained false -p:PublishSingleFile=true dotnet publish ConvertSRTto3DASS.Cli -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish ConvertSRTto3DASS.Cli -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true ## OSX x64
dotnet publish ConvertSRTto3DASS.Cli -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
## OSX arm64
dotnet publish ConvertSRTto3DASS.Cli -c Release -r osx-arm64 --self-contained false -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
## Windows x64
dotnet publish ConvertSRTto3DASS.Cli -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
# Publish GUI (Windows only) # Publish GUI (Windows x64 only, self-contained)
dotnet publish ConvertSRTto3DASS.Gui -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true dotnet publish ConvertSRTto3DASS.Gui -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
``` ```
_Each publish produces a single .exe with no .dll sidecars._
## License ## License
+31
View File
@@ -0,0 +1,31 @@
# Publish all targets for SRTto3Dsubtitles
# Usage: ./publish.ps1
$ErrorActionPreference = "Stop"
$targets = @(
@{ Project = "ConvertSRTto3DASS.Cli"; Runtime = "linux-x64"; Name = "ConvertSRTto3DASS-linux-x64" },
@{ Project = "ConvertSRTto3DASS.Cli"; Runtime = "win-x64"; Name = "ConvertSRTto3DASS-win-x64.exe" },
@{ Project = "ConvertSRTto3DASS.Cli"; Runtime = "osx-x64"; Name = "ConvertSRTto3DASS-osx-x64" },
@{ Project = "ConvertSRTto3DASS.Cli"; Runtime = "osx-arm64"; Name = "ConvertSRTto3DASS-osx-arm64" },
@{ Project = "ConvertSRTto3DASS.Gui"; Runtime = "win-x64"; Name = "ConvertSRTto3DASS-GUI-Win-x64.exe" }
)
foreach ($t in $targets) {
Write-Host "Publishing $($t.Name)..." -ForegroundColor Cyan
dotnet publish $t.Project -c Release -r $t.Runtime `
--self-contained false `
-p:PublishSingleFile=true `
-p:IncludeNativeLibrariesForSelfExtract=true `
-p:OutputType=Exe `
-p:OutputPath="publish\$($t.Runtime)\"
$src = "publish\$($t.Runtime)\$($t.Project).exe"
$dst = "publish\$($t.Name)"
if (Test-Path $src) {
Move-Item $src $dst -Force
Write-Host " -> $dst" -ForegroundColor Green
}
}
Write-Host "`nDone! Published files in publish/`n" -ForegroundColor Green
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
# Publish all targets for SRTto3Dsubtitles
# Usage: ./publish.sh
set -e
declare -a targets=(
"ConvertSRTto3DASS.Cli:linux-x64:ConvertSRTto3DASS-linux-x64"
"ConvertSRTto3DASS.Cli:win-x64:ConvertSRTto3DASS-win-x64.exe"
"ConvertSRTto3DASS.Cli:osx-x64:ConvertSRTto3DASS-osx-x64"
"ConvertSRTto3DASS.Cli:osx-arm64:ConvertSRTto3DASS-osx-arm64"
"ConvertSRTto3DASS.Gui:win-x64:ConvertSRTto3DASS-GUI-Win-x64.exe"
)
rm -rf publish
mkdir -p publish
for entry in "${targets[@]}"; do
IFS=':' read -r project runtime name <<< "$entry"
echo "Publishing $name..."
dotnet publish "$project" -c Release -r "$runtime" \
--self-contained false \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:OutputType=Exe \
-p:OutputPath="publish/$runtime/"
src="publish/$runtime/$project.exe"
dst="publish/$name"
if [ -f "$src" ]; then
mv "$src" "$dst"
echo " -> $dst"
fi
done
echo ""
echo "Done! Published files in publish/"