@@ -87,6 +87,33 @@ export default class WebAudio {
87
87
}
88
88
}
89
89
90
+ apfCaptionLine ( rule : AudioRule , text : string ) : HTMLSpanElement {
91
+ const line = document . createElement ( 'span' ) ;
92
+ line . classList . add ( 'APF-subtitle-line' ) ;
93
+ line . style . background = 'black' ;
94
+ line . style . color = 'white' ;
95
+ line . style . fontSize = '3.5vw' ;
96
+ line . style . paddingLeft = '4px' ;
97
+ line . style . paddingRight = '4px' ;
98
+ line . style . height = '18px' ;
99
+ line . textContent = text ;
100
+ return line ;
101
+ }
102
+
103
+ apfCaptionLines ( rule : AudioRule , lines : HTMLSpanElement [ ] ) : HTMLDivElement {
104
+ const apfLines = document . createElement ( 'div' ) ;
105
+ apfLines . classList . add ( 'APF-subtitles' ) ;
106
+ apfLines . style . bottom = '10px' ;
107
+ apfLines . style . position = 'absolute' ;
108
+ apfLines . style . textAlign = 'center' ;
109
+ apfLines . style . width = '100%' ;
110
+ lines . forEach ( ( line ) => {
111
+ apfLines . appendChild ( line ) ;
112
+ apfLines . appendChild ( document . createElement ( 'br' ) ) ;
113
+ } ) ;
114
+ return apfLines ;
115
+ }
116
+
90
117
clean ( subtitleContainer , ruleIndex = 0 ) : void {
91
118
const rule = this . rules [ ruleIndex ] ;
92
119
if ( rule . mode === 'watcher' ) { return ; } // If this is for a watcher rule, leave the text alone
@@ -128,11 +155,8 @@ export default class WebAudio {
128
155
}
129
156
} ) ;
130
157
131
- switch ( rule . showSubtitles ) {
132
- case Constants . ShowSubtitles . Filtered : if ( filtered ) { this . showSubtitles ( rule , subtitles ) ; } else { this . hideSubtitles ( rule , subtitles ) ; } break ;
133
- case Constants . ShowSubtitles . Unfiltered : if ( filtered ) { this . hideSubtitles ( rule , subtitles ) ; } else { this . showSubtitles ( rule , subtitles ) ; } break ;
134
- case Constants . ShowSubtitles . None : this . hideSubtitles ( rule , subtitles ) ; break ;
135
- }
158
+ const shouldBeShown = this . subtitlesShouldBeShown ( rule , filtered ) ;
159
+ shouldBeShown ? this . showSubtitles ( rule ) : this . hideSubtitles ( rule ) ;
136
160
}
137
161
138
162
cleanYouTubeAutoSubs ( node ) : void {
@@ -236,15 +260,9 @@ export default class WebAudio {
236
260
// Some sites ignore textTrack.mode = 'hidden' and will still show captions
237
261
// This is a fallback (not preferred) method that can be used for hiding the cues
238
262
hideCue ( rule : AudioRule , cue : FilteredVTTCue ) {
239
- if (
240
- ( rule . showSubtitles === Constants . ShowSubtitles . Filtered && ! cue . filtered )
241
- || ( rule . showSubtitles === Constants . ShowSubtitles . Unfiltered && cue . filtered )
242
- || rule . showSubtitles === Constants . ShowSubtitles . None
243
- ) {
244
- cue . text = '' ;
245
- cue . position = 100 ;
246
- cue . size = 0 ;
247
- }
263
+ cue . text = '' ;
264
+ cue . position = 100 ;
265
+ cue . size = 0 ;
248
266
}
249
267
250
268
hideSubtitles ( rule : AudioRule , subtitles ?) {
@@ -280,9 +298,11 @@ export default class WebAudio {
280
298
}
281
299
282
300
initCueRule ( rule : AudioRule ) {
301
+ if ( rule . apfCaptions === true ) { rule . videoCueHideCues = true ; }
283
302
if ( rule . videoSelector === undefined ) { rule . videoSelector = WebAudio . DefaultVideoSelector ; }
284
303
if ( rule . videoCueRequireShowing === undefined ) { rule . videoCueRequireShowing = this . filter . cfg . muteCueRequireShowing ; }
285
304
if ( rule . externalSub ) {
305
+ if ( rule . externalSubTrackMode === undefined ) { rule . externalSubTrackMode = 'showing' ; }
286
306
if ( rule . externalSubURLKey === undefined ) { rule . externalSubURLKey = 'url' ; }
287
307
if ( rule . externalSubFormatKey === undefined ) { rule . externalSubFormatKey = 'format' ; }
288
308
if ( rule . externalSubTrackLabel === undefined ) { rule . externalSubTrackLabel = 'APF' ; }
@@ -446,7 +466,7 @@ export default class WebAudio {
446
466
newTextTrack ( rule : AudioRule , video : HTMLVideoElement , cues : VTTCue [ ] ) : TextTrack {
447
467
if ( video . textTracks ) {
448
468
const track = video . addTextTrack ( 'captions' , rule . externalSubTrackLabel , rule . videoCueLanguage ) as TextTrack ;
449
- track . mode = 'showing' ;
469
+ track . mode = rule . externalSubTrackMode ;
450
470
for ( let i = 0 ; i < cues . length ; i ++ ) {
451
471
track . addCue ( cues [ i ] ) ;
452
472
}
@@ -603,15 +623,13 @@ export default class WebAudio {
603
623
}
604
624
605
625
const result = this . replaceTextResult ( cue . text ) ;
626
+ cue . originalText = cue . text ;
606
627
if ( result . modified ) {
607
628
cue . filtered = true ;
608
- cue . originalText = cue . text ;
609
629
cue . text = result . filtered ;
610
630
} else {
611
631
cue . filtered = false ;
612
632
}
613
-
614
- if ( rule . videoCueHideCues ) { this . hideCue ( rule , cue ) ; }
615
633
}
616
634
}
617
635
@@ -748,6 +766,15 @@ export default class WebAudio {
748
766
this . fillerAudio . currentTime = 0 ;
749
767
}
750
768
769
+ subtitlesShouldBeShown ( rule , filtered : boolean = false ) : boolean {
770
+ switch ( rule . showSubtitles ) {
771
+ case Constants . ShowSubtitles . All : return true ;
772
+ case Constants . ShowSubtitles . Filtered : return filtered ;
773
+ case Constants . ShowSubtitles . Unfiltered : return ! filtered ;
774
+ case Constants . ShowSubtitles . None : return false ;
775
+ }
776
+ }
777
+
751
778
// Checks if a node is a supported audio node.
752
779
// Returns rule id upon first match, otherwise returns false
753
780
supportedNode ( node ) {
@@ -883,12 +910,8 @@ export default class WebAudio {
883
910
}
884
911
885
912
if ( data . skipped ) { return false ; }
886
- // Hide/show captions/subtitles
887
- switch ( rule . showSubtitles ) {
888
- case Constants . ShowSubtitles . Filtered : if ( data . filtered ) { instance . showSubtitles ( rule ) ; } else { instance . hideSubtitles ( rule ) ; } break ;
889
- case Constants . ShowSubtitles . Unfiltered : if ( data . filtered ) { instance . hideSubtitles ( rule ) ; } else { instance . showSubtitles ( rule ) ; } break ;
890
- case Constants . ShowSubtitles . None : instance . hideSubtitles ( rule ) ; break ;
891
- }
913
+ const shouldBeShown = instance . subtitlesShouldBeShown ( rule , data . filtered ) ;
914
+ shouldBeShown ? instance . showSubtitles ( rule ) : instance . hideSubtitles ( rule ) ;
892
915
if ( data . filtered ) { instance . filter . updateCounterBadge ( ) ; }
893
916
} else {
894
917
if ( rule . ignoreMutations ) { instance . filter . startObserving ( ) ; } // Start observing when video is not playing
@@ -908,49 +931,38 @@ export default class WebAudio {
908
931
909
932
textTrack . oncuechange = ( ) => {
910
933
if ( textTrack . activeCues && textTrack . activeCues . length > 0 ) {
911
- let filtered = false ;
912
-
913
- for ( let i = 0 ; i < textTrack . activeCues . length ; i ++ ) {
914
- const activeCue = textTrack . activeCues [ i ] as FilteredVTTCue ;
915
- if ( ! activeCue . hasOwnProperty ( 'filtered' ) ) {
916
- const cues = textTrack . cues as any as FilteredVTTCue [ ] ;
917
- instance . processCues ( cues , rule ) ;
918
- }
919
-
920
- if ( activeCue . filtered ) {
921
- filtered = true ;
922
- instance . mute ( rule , video ) ;
934
+ const activeCues = Array . from ( textTrack . activeCues as any as FilteredVTTCue [ ] ) ;
935
+ const apfLines = [ ] ;
936
+
937
+ const processed = activeCues . some ( ( activeCue ) => activeCue . hasOwnProperty ( 'filtered' ) ) ;
938
+ if ( ! processed ) { instance . processCues ( activeCues , rule ) ; }
939
+ const filtered = activeCues . some ( ( activeCue ) => activeCue . filtered ) ;
940
+ filtered ? instance . mute ( rule , video ) : instance . unmute ( rule , video ) ;
941
+ const shouldBeShown = instance . subtitlesShouldBeShown ( rule , filtered ) ;
942
+
943
+ for ( let i = 0 ; i < activeCues . length ; i ++ ) {
944
+ const activeCue = activeCues [ i ] ;
945
+ if ( ! shouldBeShown && rule . videoCueHideCues ) { instance . hideCue ( rule , activeCue ) ; }
946
+ if ( rule . apfCaptions ) {
947
+ const text = filtered ? activeCue . text : activeCue . originalText ;
948
+ const line = instance . apfCaptionLine ( rule , text ) ;
949
+ apfLines . unshift ( line ) ; // Cues seem to show up in reverse order
923
950
}
924
951
}
925
952
926
- if ( ! filtered ) { instance . unmute ( rule , video ) ; }
927
-
928
- if ( ! rule . videoCueHideCues ) {
929
- if ( filtered ) {
930
- switch ( rule . showSubtitles ) {
931
- case Constants . ShowSubtitles . Filtered : textTrack . mode = 'showing' ; break ;
932
- case Constants . ShowSubtitles . Unfiltered : textTrack . mode = 'hidden' ; break ;
933
- }
934
- } else {
935
- switch ( rule . showSubtitles ) {
936
- case Constants . ShowSubtitles . Filtered : textTrack . mode = 'hidden' ; break ;
937
- case Constants . ShowSubtitles . Unfiltered : textTrack . mode = 'showing' ; break ;
938
- }
953
+ if ( apfLines . length ) {
954
+ const container = document . getElementById ( rule . apfCaptionsSelector ) ;
955
+ const oldLines = container . querySelector ( 'div.APF-subtitles' ) ;
956
+ if ( oldLines ) { oldLines . remove ( ) ; }
957
+ if ( shouldBeShown ) {
958
+ const apfCaptions = instance . apfCaptionLines ( rule , apfLines ) ;
959
+ container . appendChild ( apfCaptions ) ;
939
960
}
940
961
}
941
962
942
- if ( rule . displaySelector ) {
943
- if ( filtered ) {
944
- switch ( rule . showSubtitles ) {
945
- case Constants . ShowSubtitles . Filtered : instance . showSubtitles ( rule ) ; break ;
946
- case Constants . ShowSubtitles . Unfiltered : instance . hideSubtitles ( rule ) ; break ;
947
- }
948
- } else {
949
- switch ( rule . showSubtitles ) {
950
- case Constants . ShowSubtitles . Filtered : instance . hideSubtitles ( rule ) ; break ;
951
- case Constants . ShowSubtitles . Unfiltered : instance . showSubtitles ( rule ) ; break ;
952
- }
953
- }
963
+ if ( ! rule . videoCueHideCues ) { textTrack . mode = shouldBeShown ? 'showing' : 'hidden' ; }
964
+ if ( rule . displaySelector ) { // Hide original subtitles if using apfCaptions
965
+ apfLines . length || ! shouldBeShown ? instance . hideSubtitles ( rule ) : instance . showSubtitles ( rule ) ;
954
966
}
955
967
} else { // No active cues
956
968
instance . unmute ( rule , video ) ;
0 commit comments