Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions se5/ArteCheck.Tests/TwoLinePositionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,20 @@ [Fact] public void IndependentWholeFileShiftRuleRemains()
var f=Assert.Single(ArteChecker.Analyze(new[]{P("A\nB","19",0)},null,Options()),f=>f.Kind==ArteFixKind.TeletextLinePosition);
Assert.Equal("20",f.After);Assert.Contains("whole file",f.Reason);
}
[Fact] public void Mnr11HeaderMovesBottomRowsTo23RowPage()
{
var header=GsiHeader.CreateDefault();header.MaxRows="11";
var rows=new[]{P("Eins","11",0),P("Eins\nZwei","10",4000),P("Titel","1",8000),P("Mitte","6",12000)};var o=Options();
var fixes=ArteChecker.Analyze(rows,header.ToString(),o);
Assert.Equal("23",GsiHeader.Parse(Assert.Single(fixes,f=>f.Kind==ArteFixKind.Header).ProposedHeader!).MaxRows);
var positions=fixes.Where(f=>f.Kind==ArteFixKind.TeletextLinePosition).ToArray();
Assert.Equal(new[]{1,2},positions.Select(f=>f.Index));
var result=ArteChecker.Apply(rows,header.ToString(),fixes,o);
Assert.Equal(new[]{"22","20","1","6"},result.Paragraphs.Select(p=>p.MarginV));
}
[Fact] public void Mnr23HeaderKeepsRow11()
{
var rows=new[]{P("Anker","22",0),P("Eins","11",4000)};
Assert.DoesNotContain(ArteChecker.Analyze(rows,GsiHeader.CreateDefault().ToString(),Options()),f=>f.Kind==ArteFixKind.TeletextLinePosition);
}
}
39 changes: 37 additions & 2 deletions se5/ArteCheck/ArteChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public sealed class ArteChecker

private readonly ArteOptions _options;
private readonly List<ArteFix> _fixes = new();
private int? _sourceMaxRows;

private ArteChecker(ArteOptions options) => _options = options;

Expand Down Expand Up @@ -162,6 +163,11 @@ private void AnalyzeHeader(string? headerText)
var hasStlHeader = GsiHeader.IsStlHeader(headerText);
var header = hasStlHeader ? GsiHeader.Parse(headerText!) : GsiHeader.CreateDefault();
var original = header.Clone();
if (hasStlHeader && int.TryParse(original.MaxRows, out var sourceRows) && sourceRows > 1 && sourceRows < BottomRow)
{
_sourceMaxRows = sourceRows;
}

header.CodePage = "850";
header.DiskFormatCode = "STL25.01";
header.DisplayStandardCode = "2";
Expand Down Expand Up @@ -381,11 +387,28 @@ private void AnalyzeLinePositions(List<PluginParagraph> subtitle)
{
// Double height: the stored row is the first physical row, so one line belongs on 22 (22+23)
// and two lines on 20 (20+21, 22+23).
// A header with fewer rows (e.g. MNR 11) becomes MNR 23, so subtitles on the bottom of the
// small page (one line on 11, two lines on 10) move to the bottom of the teletext page.
var bottomOfSourcePage = new HashSet<int>();
if (_sourceMaxRows is { } sourceRows)
{
for (var i = 0; i < subtitle.Count; i++)
{
var p = subtitle[i];
var lines = TeletextText.LineCount(p.Text);
if (!string.IsNullOrWhiteSpace(p.Text) && lines <= 2 && int.TryParse(p.MarginV, out var row) && row + lines - 1 >= sourceRows)
{
bottomOfSourcePage.Add(i);
}
}
}

var correctBottom = 0;
var oneRowHigh = 0;
foreach (var p in subtitle)
for (var i = 0; i < subtitle.Count; i++)
{
if (string.IsNullOrWhiteSpace(p.Text) || !int.TryParse(p.MarginV, out var row))
var p = subtitle[i];
if (string.IsNullOrWhiteSpace(p.Text) || !int.TryParse(p.MarginV, out var row) || bottomOfSourcePage.Contains(i))
{
continue;
}
Expand Down Expand Up @@ -430,6 +453,18 @@ private void AnalyzeLinePositions(List<PluginParagraph> subtitle)

var expectedRow = lineCount == 1 ? 22 : 20;
var hasRow = int.TryParse(p.MarginV, out var currentRow);
if (bottomOfSourcePage.Contains(i))
{
if (currentRow != expectedRow)
{
Add(new ArteFix(GroupPosition, true, i + 1, currentRow.ToString(), expectedRow.ToString(),
$"Header had {_sourceMaxRows} rows (now 23) - move the bottom subtitle to row {expectedRow}.",
ArteFixKind.TeletextLinePosition));
}

continue;
}

if (shiftWholeFile && hasRow)
{
Add(new ArteFix(GroupPosition, true, i + 1, currentRow.ToString(), (currentRow + 1).ToString(),
Expand Down
2 changes: 1 addition & 1 deletion se5/ArteCheck/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Needs a Subtitle Edit build whose plugin contract includes `subtitle.header` and
| Frame-accurate time codes | Rounds in and out times to whole 25 fps frames. |
| Display duration | Checks reading time (Subtitle Edit's minimum duration and max CPS, minus the reading tolerance), plus the maximum duration. Corrections are offered but not pre-selected. |
| Maximum two lines / characters per row | Rebalances the line break, or splits the subtitle into several inside the original time range. Each color change uses a teletext cell. |
| Teletext row | Double height: one line on row 22, two lines on row 20. Moves a whole file down one row if it sits one row too high. Rows higher up the screen are left alone. |
| Teletext row | Double height: one line on row 22, two lines on row 20. Moves a whole file down one row if it sits one row too high. When the header had MNR 11, bottom subtitles (one line on 11, two lines on 10) move to 22 and 20. Rows higher up the screen are left alone. |
| Teletext colors | Normal subtitles are all yellow or uncolored, with no boxing. SDH colors map to the eight teletext colors. |
| No italics, unneeded spaces | Teletext has no italics; leading and trailing spaces use cells. |
| Minimum gaps | Shares the missing frames between the previous out time and the next in time (an odd frame comes off the previous out time), without going under the minimum durations. |
Expand Down
Loading