Skip to content

Commit 47f0516

Browse files
cfsmp3claude
andcommitted
feat: Add remaining CCExtractor CLI options to GUI
Add support for the following CLI options: Medium priority: - --hcc: Hybrid closed captions (HardSubX) - --psm: Tesseract page segmentation mode (14 modes) - --ttxtforcelatin: Force Latin charset for Teletext - --font/--italics: SPUPNG font paths - --forceflush: Flush file buffer on write Low priority: - --screenfuls: Stop after N screenfuls - --unixts: Unix timestamp reference - --ucla: UCLA transcript format - --no-spupngocr: Disable SPUPNG OCR - -L/--list-tracks: List all tracks - --output-field: Select caption field (1/2/both) - --cc2: Process channel 2 - --tverbose: Teletext verbose mode - --customtxt: Custom transcript format 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6408e5d commit 47f0516

7 files changed

Lines changed: 418 additions & 11 deletions

File tree

lib/bloc/process_bloc/process_bloc.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ class ProcessBloc extends Bloc<ProcessEvent, ProcessState> {
6262
_extractor
6363
.extractFile(
6464
file,
65-
listenProgress: (progress) =>
66-
add(ProcessFileExtractorProgress(progress)),
65+
listenProgress: (progress) => add(ProcessFileExtractorProgress(progress)),
6766
listenOutput: (line) => add(ProcessFileExtractorOutput(line)),
6867
listenVideoDetails: (videoDetails) =>
6968
add(ProcessFileVideoDetails(videoDetails)),
@@ -86,8 +85,7 @@ class ProcessBloc extends Bloc<ProcessEvent, ProcessState> {
8685
location: location,
8786
tcpdesc: tcpdesc,
8887
tcppasswrd: tcppassword,
89-
listenProgress: (progress) =>
90-
add(ProcessFileExtractorProgress(progress)),
88+
listenProgress: (progress) => add(ProcessFileExtractorProgress(progress)),
9189
listenOutput: (line) => add(ProcessFileExtractorOutput(line)),
9290
listenVideoDetails: (videoDetails) =>
9391
add(ProcessFileVideoDetails(videoDetails)),
@@ -105,8 +103,7 @@ class ProcessBloc extends Bloc<ProcessEvent, ProcessState> {
105103
_extractor
106104
.extractFilesInSplitMode(
107105
state.orignalList,
108-
listenProgress: (progress) =>
109-
add(ProcessFileExtractorProgress(progress)),
106+
listenProgress: (progress) => add(ProcessFileExtractorProgress(progress)),
110107
listenOutput: (line) => add(ProcessFileExtractorOutput(line)),
111108
listenVideoDetails: (videoDetails) =>
112109
add(ProcessFileVideoDetails(videoDetails)),

lib/bloc/updater_bloc/updater_bloc.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ class UpdaterBloc extends Bloc<UpdaterEvent, UpdaterState> {
2525
http.Response response = await http.get(url);
2626
var data = jsonDecode(response.body);
2727
for (var i = 0; i < data.length; i++) {
28-
if (event.currentVersion ==
29-
data[i]['tag_name'].toString().substring(1)) {
28+
if (event.currentVersion == data[i]['tag_name'].toString().substring(1)) {
3029
currentVersionIndex = i;
3130
}
3231
}

lib/models/settings_model.dart

Lines changed: 144 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,27 @@ class SettingsModel {
122122
String confThresh;
123123
String whiteThresh;
124124
bool splitMode;
125+
bool hcc;
126+
String psm;
127+
128+
// SPUPNG font options
129+
String spupngFont;
130+
String spupngItalicsFont;
131+
132+
// Buffering
133+
bool forceflush;
134+
135+
// Additional options
136+
String screenfuls;
137+
String unixts;
138+
bool ucla;
139+
bool nospupngocr;
140+
bool listTracks;
141+
String outputField;
142+
bool cc2;
143+
bool tverbose;
144+
String customtxt;
145+
bool ttxtforcelatin;
125146
SettingsModel({
126147
this.out = 'auto/default',
127148
this.inp = 'auto/default',
@@ -219,6 +240,21 @@ class SettingsModel {
219240
this.confThresh = '',
220241
this.whiteThresh = '',
221242
this.splitMode = false,
243+
this.hcc = false,
244+
this.psm = 'auto/default',
245+
this.spupngFont = '',
246+
this.spupngItalicsFont = '',
247+
this.forceflush = false,
248+
this.screenfuls = '',
249+
this.unixts = '',
250+
this.ucla = false,
251+
this.nospupngocr = false,
252+
this.listTracks = false,
253+
this.outputField = 'auto/default',
254+
this.cc2 = false,
255+
this.tverbose = false,
256+
this.customtxt = '',
257+
this.ttxtforcelatin = false,
222258
});
223259

224260
static Map<String, String> get paramsLookUpMap {
@@ -317,6 +353,21 @@ class SettingsModel {
317353
'confThresh': '--conf-thresh',
318354
'whiteThresh': '--whiteness-thresh',
319355
'splitMode': '', // splitMode is not a ccx setting
356+
'hcc': '--hcc',
357+
'psm': '--psm',
358+
'spupngFont': '--font',
359+
'spupngItalicsFont': '--italics',
360+
'forceflush': '--forceflush',
361+
'screenfuls': '--screenfuls',
362+
'unixts': '--unixts',
363+
'ucla': '--ucla',
364+
'nospupngocr': '--no-spupngocr',
365+
'listTracks': '-L',
366+
'outputField': '--output-field',
367+
'cc2': '--cc2',
368+
'tverbose': '--tverbose',
369+
'customtxt': '--customtxt',
370+
'ttxtforcelatin': '--ttxtforcelatin',
320371
};
321372
}
322373

@@ -443,6 +494,21 @@ class SettingsModel {
443494
String? confThresh,
444495
String? whiteThresh,
445496
bool? splitMode,
497+
bool? hcc,
498+
String? psm,
499+
String? spupngFont,
500+
String? spupngItalicsFont,
501+
bool? forceflush,
502+
String? screenfuls,
503+
String? unixts,
504+
bool? ucla,
505+
bool? nospupngocr,
506+
bool? listTracks,
507+
String? outputField,
508+
bool? cc2,
509+
bool? tverbose,
510+
String? customtxt,
511+
bool? ttxtforcelatin,
446512
}) {
447513
return SettingsModel(
448514
out: out ?? this.out,
@@ -544,6 +610,21 @@ class SettingsModel {
544610
confThresh: confThresh ?? this.confThresh,
545611
whiteThresh: whiteThresh ?? this.whiteThresh,
546612
splitMode: splitMode ?? this.splitMode,
613+
hcc: hcc ?? this.hcc,
614+
psm: psm ?? this.psm,
615+
spupngFont: spupngFont ?? this.spupngFont,
616+
spupngItalicsFont: spupngItalicsFont ?? this.spupngItalicsFont,
617+
forceflush: forceflush ?? this.forceflush,
618+
screenfuls: screenfuls ?? this.screenfuls,
619+
unixts: unixts ?? this.unixts,
620+
ucla: ucla ?? this.ucla,
621+
nospupngocr: nospupngocr ?? this.nospupngocr,
622+
listTracks: listTracks ?? this.listTracks,
623+
outputField: outputField ?? this.outputField,
624+
cc2: cc2 ?? this.cc2,
625+
tverbose: tverbose ?? this.tverbose,
626+
customtxt: customtxt ?? this.customtxt,
627+
ttxtforcelatin: ttxtforcelatin ?? this.ttxtforcelatin,
547628
);
548629
}
549630

@@ -645,6 +726,21 @@ class SettingsModel {
645726
'confThresh': confThresh,
646727
'whiteThresh': whiteThresh,
647728
'splitMode': splitMode,
729+
'hcc': hcc,
730+
'psm': psm,
731+
'spupngFont': spupngFont,
732+
'spupngItalicsFont': spupngItalicsFont,
733+
'forceflush': forceflush,
734+
'screenfuls': screenfuls,
735+
'unixts': unixts,
736+
'ucla': ucla,
737+
'nospupngocr': nospupngocr,
738+
'listTracks': listTracks,
739+
'outputField': outputField,
740+
'cc2': cc2,
741+
'tverbose': tverbose,
742+
'customtxt': customtxt,
743+
'ttxtforcelatin': ttxtforcelatin,
648744
};
649745
}
650746

@@ -746,12 +842,27 @@ class SettingsModel {
746842
confThresh: map['confThresh'],
747843
whiteThresh: map['whiteThresh'],
748844
splitMode: map['splitMode'],
845+
hcc: map['hcc'] ?? false,
846+
psm: map['psm'] ?? 'auto/default',
847+
spupngFont: map['spupngFont'] ?? '',
848+
spupngItalicsFont: map['spupngItalicsFont'] ?? '',
849+
forceflush: map['forceflush'] ?? false,
850+
screenfuls: map['screenfuls'] ?? '',
851+
unixts: map['unixts'] ?? '',
852+
ucla: map['ucla'] ?? false,
853+
nospupngocr: map['nospupngocr'] ?? false,
854+
listTracks: map['listTracks'] ?? false,
855+
outputField: map['outputField'] ?? 'auto/default',
856+
cc2: map['cc2'] ?? false,
857+
tverbose: map['tverbose'] ?? false,
858+
customtxt: map['customtxt'] ?? '',
859+
ttxtforcelatin: map['ttxtforcelatin'] ?? false,
749860
);
750861
}
751862

752863
@override
753864
String toString() {
754-
return 'SettingsModel(out: $out, inp: $inp, outputfilename: $outputfilename, fixptsjumps: $fixptsjumps, append: $append, service: $service, outInterval: $outInterval, segmentonkeyonly: $segmentonkeyonly, goptime: $goptime, nogoptime: $nogoptime, fixpadding: $fixpadding, freqEs15: $freqEs15, stream: $stream, videoedited: $videoedited, usepicorder: $usepicorder, myth: $myth, nomyth: $nomyth, wtvconvertfix: $wtvconvertfix, wtvmpeg2: $wtvmpeg2, program_number: $program_number, autoprogram: $autoprogram, multiprogram: $multiprogram, streamtype: $streamtype, hauppauge: $hauppauge, mp4vidtrack: $mp4vidtrack, noautotimeref: $noautotimeref, noscte20: $noscte20, webvttcss: $webvttcss, analyzevideo: $analyzevideo, timestampMap: $timestampMap, nolevdist: $nolevdist, minlevdist: $minlevdist, maxlevdist: $maxlevdist, chapters: $chapters, bom: $bom, nobom: $nobom, encoder: $encoder, nofontcolor: $nofontcolor, nohtmlescape: $nohtmlescape, notypesetting: $notypesetting, trim: $trim, defaultcolor: $defaultcolor, sentencecap: $sentencecap, capFile: $capFile, kf: $kf, profanityFile: $profanityFile, splitbysentence: $splitbysentence, datets: $datets, sects: $sects, latrusmap: $latrusmap, xds: $xds, lf: $lf, df: $df, autodash: $autodash, xmltv: $xmltv, xmltvliveinterval: $xmltvliveinterval, xmltvoutputinterval: $xmltvoutputinterval, xmltvonlycurrent: $xmltvonlycurrent, sem: $sem, dvblang: $dvblang, mkvlang: $mkvlang, ocrlang: $ocrlang, quant: $quant, oem: $oem, bufferinput: $bufferinput, nobufferinput: $nobufferinput, buffersize: $buffersize, koc: $koc, dru: $dru, norollup: $norollup, rollUp: $rollUp, delay: $delay, startat: $startat, endat: $endat, codec: $codec, nocodec: $nocodec, startcreditstext: $startcreditstext, startcreditsnotbefore: $startcreditsnotbefore, startcreditsnotafter: $startcreditsnotafter, startcreditsforatleast: $startcreditsforatleast, startcreditsforatmost: $startcreditsforatmost, endcreditstext: $endcreditstext, endcreditsforatleast: $endcreditsforatleast, endcreditsforatmost: $endcreditsforatmost, tpage: $tpage, teletext: $teletext, noteletext: $noteletext, hardsubx: $hardsubx, tickertext: $tickertext, ocrMode: $ocrMode, subcolor: $subcolor, minSubDuration: $minSubDuration, detectItalics: $detectItalics, confThresh: $confThresh, whiteThresh: $whiteThresh, splitMode: $splitMode)';
865+
return 'SettingsModel(out: $out, inp: $inp, outputfilename: $outputfilename, fixptsjumps: $fixptsjumps, append: $append, service: $service, outInterval: $outInterval, segmentonkeyonly: $segmentonkeyonly, goptime: $goptime, nogoptime: $nogoptime, fixpadding: $fixpadding, freqEs15: $freqEs15, stream: $stream, videoedited: $videoedited, usepicorder: $usepicorder, myth: $myth, nomyth: $nomyth, wtvconvertfix: $wtvconvertfix, wtvmpeg2: $wtvmpeg2, program_number: $program_number, autoprogram: $autoprogram, multiprogram: $multiprogram, streamtype: $streamtype, hauppauge: $hauppauge, mp4vidtrack: $mp4vidtrack, noautotimeref: $noautotimeref, noscte20: $noscte20, webvttcss: $webvttcss, analyzevideo: $analyzevideo, timestampMap: $timestampMap, nolevdist: $nolevdist, minlevdist: $minlevdist, maxlevdist: $maxlevdist, chapters: $chapters, bom: $bom, nobom: $nobom, encoder: $encoder, nofontcolor: $nofontcolor, nohtmlescape: $nohtmlescape, notypesetting: $notypesetting, trim: $trim, defaultcolor: $defaultcolor, sentencecap: $sentencecap, capFile: $capFile, kf: $kf, profanityFile: $profanityFile, splitbysentence: $splitbysentence, datets: $datets, sects: $sects, latrusmap: $latrusmap, xds: $xds, lf: $lf, df: $df, autodash: $autodash, xmltv: $xmltv, xmltvliveinterval: $xmltvliveinterval, xmltvoutputinterval: $xmltvoutputinterval, xmltvonlycurrent: $xmltvonlycurrent, sem: $sem, dvblang: $dvblang, mkvlang: $mkvlang, ocrlang: $ocrlang, quant: $quant, oem: $oem, bufferinput: $bufferinput, nobufferinput: $nobufferinput, buffersize: $buffersize, koc: $koc, dru: $dru, norollup: $norollup, rollUp: $rollUp, delay: $delay, startat: $startat, endat: $endat, codec: $codec, nocodec: $nocodec, startcreditstext: $startcreditstext, startcreditsnotbefore: $startcreditsnotbefore, startcreditsnotafter: $startcreditsnotafter, startcreditsforatleast: $startcreditsforatleast, startcreditsforatmost: $startcreditsforatmost, endcreditstext: $endcreditstext, endcreditsforatleast: $endcreditsforatleast, endcreditsforatmost: $endcreditsforatmost, tpage: $tpage, teletext: $teletext, noteletext: $noteletext, hardsubx: $hardsubx, tickertext: $tickertext, ocrMode: $ocrMode, subcolor: $subcolor, minSubDuration: $minSubDuration, detectItalics: $detectItalics, confThresh: $confThresh, whiteThresh: $whiteThresh, splitMode: $splitMode, hcc: $hcc, psm: $psm, spupngFont: $spupngFont, spupngItalicsFont: $spupngItalicsFont, forceflush: $forceflush, screenfuls: $screenfuls, unixts: $unixts, ucla: $ucla, nospupngocr: $nospupngocr, listTracks: $listTracks, outputField: $outputField, cc2: $cc2, tverbose: $tverbose, customtxt: $customtxt, ttxtforcelatin: $ttxtforcelatin)';
755866
}
756867

757868
@override
@@ -854,7 +965,22 @@ class SettingsModel {
854965
other.detectItalics == detectItalics &&
855966
other.confThresh == confThresh &&
856967
other.whiteThresh == whiteThresh &&
857-
other.splitMode == splitMode;
968+
other.splitMode == splitMode &&
969+
other.hcc == hcc &&
970+
other.psm == psm &&
971+
other.spupngFont == spupngFont &&
972+
other.spupngItalicsFont == spupngItalicsFont &&
973+
other.forceflush == forceflush &&
974+
other.screenfuls == screenfuls &&
975+
other.unixts == unixts &&
976+
other.ucla == ucla &&
977+
other.nospupngocr == nospupngocr &&
978+
other.listTracks == listTracks &&
979+
other.outputField == outputField &&
980+
other.cc2 == cc2 &&
981+
other.tverbose == tverbose &&
982+
other.customtxt == customtxt &&
983+
other.ttxtforcelatin == ttxtforcelatin;
858984
}
859985

860986
@override
@@ -954,6 +1080,21 @@ class SettingsModel {
9541080
detectItalics.hashCode ^
9551081
confThresh.hashCode ^
9561082
whiteThresh.hashCode ^
957-
splitMode.hashCode;
1083+
splitMode.hashCode ^
1084+
hcc.hashCode ^
1085+
psm.hashCode ^
1086+
spupngFont.hashCode ^
1087+
spupngItalicsFont.hashCode ^
1088+
forceflush.hashCode ^
1089+
screenfuls.hashCode ^
1090+
unixts.hashCode ^
1091+
ucla.hashCode ^
1092+
nospupngocr.hashCode ^
1093+
listTracks.hashCode ^
1094+
outputField.hashCode ^
1095+
cc2.hashCode ^
1096+
tverbose.hashCode ^
1097+
customtxt.hashCode ^
1098+
ttxtforcelatin.hashCode;
9581099
}
9591100
}

lib/screens/settings/hardsubx_settings.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ class HardSubxSettingsScreen extends StatelessWidget {
8989
);
9090
},
9191
),
92+
CustomSwitchListTile(
93+
title: 'HCC (Hybrid Closed Captions)',
94+
subtitle:
95+
'Use when file has both closed captions and burned-in subtitles',
96+
value: state.settingsModel.hcc,
97+
onTap: (value) {
98+
context.read<SettingsBloc>().add(
99+
SettingsUpdatedEvent(
100+
state.settingsModel.copyWith(
101+
hcc: value,
102+
),
103+
),
104+
);
105+
},
106+
),
92107
CustomDropDown(
93108
title: 'OCR mode',
94109
subtitle:
@@ -228,6 +243,22 @@ class HardSubxSettingsScreen extends StatelessWidget {
228243
);
229244
},
230245
),
246+
CustomDropDown(
247+
title: 'PSM (Page Segmentation Mode)',
248+
subtitle:
249+
'Select the page segmentation mode for Tesseract.',
250+
value: state.settingsModel.psm,
251+
items: dropdownListMap['psm']!.keys.toList(),
252+
onChanged: (String newValue) {
253+
context.read<SettingsBloc>().add(
254+
SettingsUpdatedEvent(
255+
state.settingsModel.copyWith(
256+
psm: newValue,
257+
),
258+
),
259+
);
260+
},
261+
),
231262
CustomTextField(
232263
title: 'DVB lang',
233264
subtitle:

lib/screens/settings/input_settings.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,35 @@ class InputSettingsScreen extends StatelessWidget {
378378
);
379379
},
380380
),
381+
CustomSwitchListTile(
382+
title: 'Force Latin charset',
383+
subtitle:
384+
'Force Latin G0 charset for Teletext, ignoring any Cyrillic designation in the stream.',
385+
value: state.settingsModel.ttxtforcelatin,
386+
onTap: (value) {
387+
context.read<SettingsBloc>().add(
388+
SettingsUpdatedEvent(
389+
state.settingsModel.copyWith(
390+
ttxtforcelatin: value,
391+
),
392+
),
393+
);
394+
},
395+
),
396+
CustomSwitchListTile(
397+
title: 'Teletext verbose',
398+
subtitle: 'Enable teletext verbose mode for debugging.',
399+
value: state.settingsModel.tverbose,
400+
onTap: (value) {
401+
context.read<SettingsBloc>().add(
402+
SettingsUpdatedEvent(
403+
state.settingsModel.copyWith(
404+
tverbose: value,
405+
),
406+
),
407+
);
408+
},
409+
),
381410
],
382411
),
383412
),

0 commit comments

Comments
 (0)