Skip to content
This repository was archived by the owner on Nov 5, 2023. It is now read-only.

Commit 28ba1a7

Browse files
committed
Apply a heuristic when censorship is off to attempt to undo the rest of the censorship that comes from the Web Speech API. Fixed issue where censorship option is not honored.
1 parent 80d30b4 commit 28ba1a7

File tree

8 files changed

+100
-33
lines changed

8 files changed

+100
-33
lines changed

Diff for: app/assets/lang-csv/en-US.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ settings.appearance.xPosition,Use title case,X Position
121121
settings.appearance.yPosition,Use title case,Y Position
122122
settings.censor.censor,Use title case,Censor
123123
settings.censor.censorProfaneLanguage,,Censor profane language.
124-
settings.censor.usEnglishOnly,,(Currently available for US English only.)
124+
settings.censor.usEnglishOnly,,Currently available for US English only.
125125
settings.censor.censorProfaneLanguageDescription.text,"Do not translate {seeThisList} or {useWordReplacement}. The text at the key settings.censor.censorProfaneLanguageDescription.seeThisList and settings.censor.censorProfaneLanguageDescription.useWordReplacements will be placed here, respectively.","What's considered profane? {seeThisList} (note: profanity ahead!) If you need to censor additional words not included in this list, {useWordReplacements}."
126126
settings.censor.censorProfaneLanguageDescription.seeThisList,Will link to https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words,See this list
127127
settings.censor.censorProfaneLanguageDescription.useWordReplacements,,use word replacements

Diff for: app/assets/lang-csv/pt-BR.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ settings.appearance.xPosition,Use title case,Posição X
121121
settings.appearance.yPosition,Use title case,Posição Y
122122
settings.censor.censor,Use title case,Censurar
123123
settings.censor.censorProfaneLanguage,,Censurar linguagem profana.
124-
settings.censor.usEnglishOnly,,(Atualmente disponível apenas para inglês dos EUA)
124+
settings.censor.usEnglishOnly,,Atualmente disponível apenas para inglês dos EUA.
125125
settings.censor.censorProfaneLanguageDescription.text,"Do not translate {seeThisList} or {useWordReplacement}. The text at the key settings.censor.censorProfaneLanguageDescription.seeThisList and settings.censor.censorProfaneLanguageDescription.useWordReplacements will be placed here, respectively.","O que é considerado profano? {seeThisList} (nota: palavrões à frente!) Se você precisar censurar palavras adicionais não incluídas nesta lista, {useWordReplacements}."
126126
settings.censor.censorProfaneLanguageDescription.seeThisList,Will link to https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words,Veja esta lista
127127
settings.censor.censorProfaneLanguageDescription.useWordReplacements,,usar substituições de palavras

Diff for: app/lang/en-US.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export default { common:
135135
censor:
136136
{ censor: 'Censor',
137137
censorProfaneLanguage: 'Censor profane language.',
138-
usEnglishOnly: '(Currently available for US English only.)',
138+
usEnglishOnly: 'Currently available for US English only.',
139139
censorProfaneLanguageDescription:
140140
{ text: 'What\'s considered profane? {seeThisList} (note: profanity ahead!) If you need to censor additional words not included in this list, {useWordReplacements}.',
141141
seeThisList: 'See this list',

Diff for: app/lang/pt-BR.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export default { common:
135135
censor:
136136
{ censor: 'Censurar',
137137
censorProfaneLanguage: 'Censurar linguagem profana.',
138-
usEnglishOnly: '(Atualmente disponível apenas para inglês dos EUA)',
138+
usEnglishOnly: 'Atualmente disponível apenas para inglês dos EUA.',
139139
censorProfaneLanguageDescription:
140140
{ text: 'O que é considerado profano? {seeThisList} (nota: palavrões à frente!) Se você precisar censurar palavras adicionais não incluídas nesta lista, {useWordReplacements}.',
141141
seeThisList: 'Veja esta lista',

Diff for: app/mixins/data/profanity-uncensor-en.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export default [
2+
{
3+
from: 'f***',
4+
to: 'fuck',
5+
},
6+
{
7+
from: 'f******',
8+
to: 'fucking',
9+
},
10+
{
11+
from: 'f*****',
12+
to: 'fucked',
13+
},
14+
{
15+
from: 's***',
16+
to: 'shit', // "slut" conflicts
17+
},
18+
{
19+
from: 'a******',
20+
to: 'asshole',
21+
},
22+
{
23+
from: 'b****',
24+
to: 'bitch',
25+
},
26+
{
27+
from: 'b******',
28+
to: 'bitches',
29+
},
30+
{
31+
from: 'c**********',
32+
to: 'cocksucker',
33+
},
34+
{
35+
from: 'm***',
36+
to: 'milf',
37+
},
38+
];

Diff for: app/pages/captioner/settings/censor/index.vue

+31-17
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,55 @@
11
<template>
2-
<div class="settings-about-view">
2+
<div>
33
<div class="custom-control custom-checkbox mb-2">
44
<input v-model="censor" class="custom-control-input" name="word-replacements-censor-profanity" type="checkbox" id="word-replacements-censor-profanity">
5-
<label class="custom-control-label" for="word-replacements-censor-profanity">{{$t('settings.censor.censorProfaneLanguage')}} {{$t('settings.censor.usEnglishOnly')}}</label>
5+
<label class="custom-control-label" for="word-replacements-censor-profanity">{{$t('settings.censor.censorProfaneLanguage')}}</label>
66
</div>
7-
8-
<i18n path="settings.censor.censorProfaneLanguageDescription.text" tag="p" class="small">
9-
<a place="seeThisList" href="https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words" target="_blank">{{$t('settings.censor.censorProfaneLanguageDescription.seeThisList')}}</a>
10-
<router-link place="useWordReplacements" to="word-replacements">{{$t('settings.censor.censorProfaneLanguageDescription.useWordReplacements')}}</router-link>
11-
</i18n>
12-
<label class="col-form-label">{{$t('settings.censor.replaceCensoredWordsWith')}}</label>
13-
<div class="custom-control custom-radio">
14-
<input type="radio" id="customRadio1" v-model="censorReplaceWith" value="nothing" name="censorReplaceWith" class="custom-control-input">
15-
<label class="custom-control-label" for="customRadio1">{{$t('settings.censor.nothing')}}</label>
7+
<div v-if="censor" class="card card-body">
8+
<p>
9+
{{$t('settings.censor.usEnglishOnly')}}
10+
<i18n path="settings.censor.censorProfaneLanguageDescription.text" tag="span">
11+
<a place="seeThisList" href="https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words" target="_blank">{{$t('settings.censor.censorProfaneLanguageDescription.seeThisList')}}</a>
12+
<router-link place="useWordReplacements" to="word-replacements">{{$t('settings.censor.censorProfaneLanguageDescription.useWordReplacements')}}</router-link>
13+
</i18n>
14+
</p>
15+
<label class="col-form-label pt-0">{{$t('settings.censor.replaceCensoredWordsWith')}}</label>
16+
<div class="custom-control custom-radio">
17+
<input type="radio" id="customRadio1" v-model="censorReplaceWith" value="nothing" name="censorReplaceWith" class="custom-control-input">
18+
<label class="custom-control-label" for="customRadio1">{{$t('settings.censor.nothing')}}</label>
19+
</div>
20+
<div class="custom-control custom-radio">
21+
<input type="radio" id="customRadio2" v-model="censorReplaceWith" value="asterisks" name="censorReplaceWith" class="custom-control-input">
22+
<label class="custom-control-label" for="customRadio2">{{$t('settings.censor.asterisks')}} (*****)</label>
23+
</div>
1624
</div>
17-
<div class="custom-control custom-radio">
18-
<input type="radio" id="customRadio2" v-model="censorReplaceWith" value="asterisks" name="censorReplaceWith" class="custom-control-input">
19-
<label class="custom-control-label" for="customRadio2">{{$t('settings.censor.asterisks')}} (*****)</label>
25+
<div v-else class="card card-body">
26+
<p>Censorship is off. However, the speech-to-text service that Web Captioner runs on currently does not give an option to completely disable censorship. Web Captioner applies a heuristic to uncensor words that are returned from this service that still appear to be censored.</p>
27+
<p class="mb-0">If you are running into issues with words being censored even when censorship is off, <a href="https://feedback.webcaptioner.com/">leave feedback</a> or <a href="https://m.me/webcaptioner">contact Web Captioner</a>.</p>
2028
</div>
2129

22-
<p class="mt-4"></p>
23-
2430
</div>
2531
</template>
2632

2733
<script>
2834
import { mapGetters, mapActions } from 'vuex'
2935
3036
export default {
31-
name: 'settings-censor-view',
3237
transition: 'fade',
3338
middleware: [
3439
'settings-meta',
3540
],
3641
meta: {
3742
settingsPageTitleKey: 'settings.censor.censor',
3843
},
44+
watch: {
45+
censor: function () {
46+
if (this.$store.state.captioner.on) {
47+
this.$nextTick(() => {
48+
this.$store.dispatch('captioner/restartAndReinitializeSpeechRecognizer');
49+
});
50+
}
51+
},
52+
},
3953
computed: {
4054
censor: {
4155
get () {

Diff for: app/store/modules/captioner/RecognitionResultParser.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default class {
1111
return escapeRegExp(stringToCensor);
1212
});
1313

14-
replacement.fromRegex = new RegExp('\\b(' + stringsToCensor.join('|') + ')\\b', 'gi');
14+
replacement.fromRegex = new RegExp('(^|\\b|\\s)(' + stringsToCensor.join('|') + ')(\\b|\\s|$)', 'gi');
1515
return replacement;
1616
});
1717
}
@@ -21,8 +21,10 @@ export default class {
2121
transcriptFinal = '';
2222

2323
const makeReplacements = (text) => {
24+
console.log(this.wordReplacements);
2425
for (let i = 0; i < this.wordReplacements.length; i++) {
25-
text = text.replace(this.wordReplacements[i].fromRegex, this.wordReplacements[i].to);
26+
// $1 and $3 are the leading and trailing whitespace, if any
27+
text = text.replace(this.wordReplacements[i].fromRegex, '$1' + this.wordReplacements[i].to + '$3');
2628
}
2729
return text;
2830
}

Diff for: app/store/modules/captioner/index.js

+23-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Vue from 'vue'
22
import RecognitionResultParser from './RecognitionResultParser.js'
33
import internalWordReplacements from '~/mixins/data/internalWordReplacements'
44
import censoredProfanity from '~/mixins/data/profanity-en'
5+
import profanityUncensor from '~/mixins/data/profanity-uncensor-en'
56

67
const SILENT_RESTART_AFTER_NO_RESULTS_MS = (2 * 1000);
78
const SILENT_RESTART_WAIT_MS_AFTER_STARTING_CAPTIONING = (2.5 * 1000);
@@ -61,19 +62,25 @@ const actions = {
6162
commit('INIT_STORAGE_SESSION_DATE', null, {root:true});
6263
},
6364
start ({commit, state, rootState, getters, dispatch}) {
65+
const CENSOR_ON = rootState.settings.censor.on;
66+
6467
let parser = new RecognitionResultParser({
6568
wordReplacements: [
6669
...rootState.settings.wordReplacements,
6770
...internalWordReplacements,
6871

69-
// Add profanity
70-
{
71-
from: censoredProfanity.join(','),
72-
to: (rootState.settings.censor.replaceWith === 'nothing'
73-
? ''
74-
: '******' // 'asterisks',
75-
)
76-
},
72+
...(CENSOR_ON
73+
// Add profanity censor
74+
? [{
75+
from: censoredProfanity.join(','),
76+
to: (rootState.settings.censor.replaceWith === 'nothing'
77+
? ''
78+
: '******' // 'asterisks',
79+
)
80+
}]
81+
// Apply a heuristic to attempt to fully uncensor speech
82+
: profanityUncensor
83+
),
7784
],
7885
});
7986

@@ -161,8 +168,7 @@ const actions = {
161168

162169
speechRecognizer.onerror = function(error) {
163170
clearTimeout(microphonePermissionNeededTimeout);
164-
// console.log('speechRecognizer error');
165-
// console.log(error);
171+
166172
if (event.error == 'not-allowed') {
167173
commit('SET_CAPTIONER_OFF', {omitFromGoogleAnalytics: true});
168174
commit('SET_SHOULD_BE_ON', { shouldBeOn: false });
@@ -233,6 +239,8 @@ const actions = {
233239
dispatch('donation/SHOW_DONATION_MESSAGE_IF_ELIGIBLE', null, {root:true});
234240
},
235241

242+
243+
// Fast restart if possible
236244
restart ({commit, state, rootState, dispatch}) {
237245
if (state.transcript.interim) {
238246
commit('APPEND_TRANSCRIPT_FINAL', { transcriptFinal: state.transcript.interim });
@@ -255,6 +263,11 @@ const actions = {
255263
}
256264
},
257265

266+
restartAndReinitializeSpeechRecognizer ({commit, state, rootState, dispatch}) {
267+
state.on = false;
268+
dispatch('restart');
269+
},
270+
258271
trackWordCount ({}, {wordCount}) {
259272
if (wordCount > 0) {
260273
Vue.$ga.event({

0 commit comments

Comments
 (0)