make propertys work inital for genericSpeechDriver, add settings
This commit is contained in:
parent
9ba8c627df
commit
b5ec64bb13
@ -31,8 +31,9 @@ genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine
|
|||||||
# Turn speech on or off:
|
# Turn speech on or off:
|
||||||
enabled=True
|
enabled=True
|
||||||
|
|
||||||
# Select speech driver, options are speechd (default) or espeak:
|
# Select speech driver, options are speechdDriver (default), genericDriver or espeakDriver:
|
||||||
#driver=speechdDriver
|
#driver=speechdDriver
|
||||||
|
#driver=genericDriver
|
||||||
driver=espeakDriver
|
driver=espeakDriver
|
||||||
|
|
||||||
|
|
||||||
@ -62,6 +63,27 @@ language=en_US
|
|||||||
# Read new text as it happens?
|
# Read new text as it happens?
|
||||||
autoReadIncoming=True
|
autoReadIncoming=True
|
||||||
|
|
||||||
|
# genericSpeechCommand is the command that is executed for talking
|
||||||
|
# the following variables are replaced with values
|
||||||
|
# fenrirText = is the text that should be spoken
|
||||||
|
# fenrirModule = may be the speech module like used in speech-dispatcher, not every TTY need this
|
||||||
|
# fenrirLanguage = the language
|
||||||
|
# fenrirVoice = is the current voice that should be used
|
||||||
|
# the current volume, pitch and rate is calculated like this
|
||||||
|
# value = min + settingValue * (min - max )
|
||||||
|
# fenrirVolume = is replaced with the current volume
|
||||||
|
# fenrirPitch = is replaced with the current pitch
|
||||||
|
# fenrirRate = is replaced with the current speed (speech rate)
|
||||||
|
genericSpeechCommand=espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"
|
||||||
|
|
||||||
|
# those are the min and max values of the TTS system that is used in genericSpeechCommand
|
||||||
|
fenrirMinVolume=0
|
||||||
|
fenrirMaxVolume=200
|
||||||
|
fenrirMinPitch=0
|
||||||
|
fenrirMaxPitch=99
|
||||||
|
fenrirMinRate=80
|
||||||
|
fenrirMaxRate=450
|
||||||
|
|
||||||
[braille]
|
[braille]
|
||||||
enabled=False
|
enabled=False
|
||||||
driver=brlapiDriver
|
driver=brlapiDriver
|
||||||
|
@ -32,9 +32,10 @@ genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine
|
|||||||
# Turn speech on or off:
|
# Turn speech on or off:
|
||||||
enabled=True
|
enabled=True
|
||||||
|
|
||||||
# Select speech driver, options are speechd (default) or espeak:
|
# Select speech driver, options are speechdDriver (default), genericDriver or espeakDriver:
|
||||||
driver=speechdDriver
|
driver=speechdDriver
|
||||||
#driver=espeakDriver
|
#driver=espeakDriver
|
||||||
|
#driver=genericDriver
|
||||||
|
|
||||||
|
|
||||||
# The rate selects how fast Fenrir will speak. Options range from 0, slowest, to 1.0, fastest.
|
# The rate selects how fast Fenrir will speak. Options range from 0, slowest, to 1.0, fastest.
|
||||||
@ -63,6 +64,27 @@ language=english-us
|
|||||||
# Read new text as it happens?
|
# Read new text as it happens?
|
||||||
autoReadIncoming=True
|
autoReadIncoming=True
|
||||||
|
|
||||||
|
# genericSpeechCommand is the command that is executed for talking
|
||||||
|
# the following variables are replaced with values
|
||||||
|
# fenrirText = is the text that should be spoken
|
||||||
|
# fenrirModule = may be the speech module like used in speech-dispatcher, not every TTY need this
|
||||||
|
# fenrirLanguage = the language
|
||||||
|
# fenrirVoice = is the current voice that should be used
|
||||||
|
# the current volume, pitch and rate is calculated like this
|
||||||
|
# value = min + settingValue * (min - max )
|
||||||
|
# fenrirVolume = is replaced with the current volume
|
||||||
|
# fenrirPitch = is replaced with the current pitch
|
||||||
|
# fenrirRate = is replaced with the current speed (speech rate)
|
||||||
|
genericSpeechCommand=espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"
|
||||||
|
|
||||||
|
# those are the min and max values of the TTS system that is used in genericSpeechCommand
|
||||||
|
fenrirMinVolume=0
|
||||||
|
fenrirMaxVolume=200
|
||||||
|
fenrirMinPitch=0
|
||||||
|
fenrirMaxPitch=99
|
||||||
|
fenrirMinRate=80
|
||||||
|
fenrirMaxRate=450
|
||||||
|
|
||||||
[braille]
|
[braille]
|
||||||
enabled=False
|
enabled=False
|
||||||
driver=brlapiDriver
|
driver=brlapiDriver
|
||||||
|
@ -1,178 +0,0 @@
|
|||||||
[sound]
|
|
||||||
# Turn sound on or off:
|
|
||||||
enabled=True
|
|
||||||
|
|
||||||
# Select the driver used to play sounds, choices are generic and gstreamer.
|
|
||||||
# Sox is the default.
|
|
||||||
driver=genericDriver
|
|
||||||
|
|
||||||
# Sound themes. This is the pack of sounds used for sound alerts.
|
|
||||||
# Sound packs may be located at /usr/share/sounds
|
|
||||||
# For system wide availability, or ~/.local/share/fenrir/sounds
|
|
||||||
# For the current user.
|
|
||||||
theme=default
|
|
||||||
|
|
||||||
# Sound volume controls how loud the sounds for your chosen soundpack are.
|
|
||||||
# 0 is quietest, 1.0 is loudest.
|
|
||||||
volume=1.0
|
|
||||||
|
|
||||||
# shell commands for generic sound driver
|
|
||||||
# the folowing variable are substituded
|
|
||||||
# fenrirVolume = the current volume setting
|
|
||||||
# fenrirSoundFile = the soundfile for an soundicon
|
|
||||||
# fenrirFrequence = the frequence to play
|
|
||||||
# fenrirDuration = the duration of the frequence
|
|
||||||
# the following command is used for play a soundfile
|
|
||||||
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
|
|
||||||
#the following command is used for generating a frequence beep
|
|
||||||
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
|
|
||||||
|
|
||||||
[speech]
|
|
||||||
# Turn speech on or off:
|
|
||||||
enabled=True
|
|
||||||
|
|
||||||
# Select speech driver, options are speechd (default) or espeak:
|
|
||||||
driver=speechdDriver
|
|
||||||
#driver=espeakDriver
|
|
||||||
|
|
||||||
|
|
||||||
# The rate selects how fast fenrir will speak. Options range from 0, slowest, to 1.0, fastest.
|
|
||||||
rate=0.65
|
|
||||||
|
|
||||||
# Pitch controls the pitch of the voice, select from 0, lowest, to 1.0, highest.
|
|
||||||
pitch=0.5
|
|
||||||
# Pitch for capital letters
|
|
||||||
capitalPitch=0.9
|
|
||||||
|
|
||||||
# Volume controls the loudness of the voice, select from 0, quietest, to 1.0, loudest.
|
|
||||||
volume=1.0
|
|
||||||
|
|
||||||
# Module is used for speech-dispatcher, to select the speech module you want to use.
|
|
||||||
# Consult speech-dispatcher's configuration and help ti find out which modules are available.
|
|
||||||
# The default is espeak.
|
|
||||||
module=espeak
|
|
||||||
|
|
||||||
# Voice selects the varient you want to use, for example, f5 will use the female voice #5 in espeak,
|
|
||||||
# or if using the espeak module in speech-dispatcher. To find out which voices are available, consult the documentation provided with your chosen synthesizer.
|
|
||||||
voice=
|
|
||||||
|
|
||||||
# Select the language you want fenrir to use.
|
|
||||||
language=de
|
|
||||||
|
|
||||||
# Read new text as it happens?
|
|
||||||
autoReadIncoming=True
|
|
||||||
|
|
||||||
[braille]
|
|
||||||
enabled=False
|
|
||||||
driver=brlapiDriver
|
|
||||||
layout=en
|
|
||||||
# to what should the flush timeout relate to
|
|
||||||
# word = flush after (number of words to display) * seconds
|
|
||||||
# char = flush after (number of chars to display) * seconds
|
|
||||||
# fix = flush after X seconds
|
|
||||||
# none = no automatic flush (manual via shortcut)
|
|
||||||
flushMode=word
|
|
||||||
# seconds to flush or
|
|
||||||
# -1 = no automatic flush (manual via shortcut)
|
|
||||||
flushTimeout=3
|
|
||||||
# how should the cursor be focused?
|
|
||||||
# page = if cursor cross the border move to next page and start at beginn
|
|
||||||
# fixCell = ajust the cursor on an special cell where it is always placed. the display scroll here more smooth.
|
|
||||||
cursorFocusMode=page
|
|
||||||
# define the cell on the Braille device where fenrir should scroll and keep the cursor
|
|
||||||
# 0 = first cell on device
|
|
||||||
# -1 = last cell on device
|
|
||||||
# >0 = fix cell number
|
|
||||||
fixCursorOnCell=-1
|
|
||||||
#How should the braille follow the focus
|
|
||||||
# none = no automatic toggle command used
|
|
||||||
# review = priority to review
|
|
||||||
# last = follow last used cursor
|
|
||||||
cursorFollowMode=review
|
|
||||||
# number of cells in panning (horizontal)
|
|
||||||
# 0 = display size, >0 number of cells
|
|
||||||
panSizeHorizontal=0
|
|
||||||
|
|
||||||
[screen]
|
|
||||||
driver=vcsaDriver
|
|
||||||
encoding=cp850
|
|
||||||
screenUpdateDelay=0.05
|
|
||||||
suspendingScreen=
|
|
||||||
autodetectSuspendingScreen=True
|
|
||||||
|
|
||||||
[keyboard]
|
|
||||||
driver=evdevDriver
|
|
||||||
# filter input devices NOMICE, ALL or a DEVICE NAME
|
|
||||||
device=ALL
|
|
||||||
# gives fenrir exclusive access to the keyboard and let consume keystrokes. just disable on problems.
|
|
||||||
grabDevices=True
|
|
||||||
ignoreShortcuts=False
|
|
||||||
# the current shortcut layout located in /etc/fenrir/keyboard
|
|
||||||
keyboardLayout=test
|
|
||||||
# echo chars while typing.
|
|
||||||
charEcho=False
|
|
||||||
# echo deleted chars
|
|
||||||
charDeleteEcho=True
|
|
||||||
# echo word after pressing space
|
|
||||||
wordEcho=False
|
|
||||||
# interrupt speech on any keypress
|
|
||||||
interruptOnKeyPress=False
|
|
||||||
# you can filter the keys on that the speech should interrupt (empty = all keys, otherwhise the given keys)
|
|
||||||
interruptOnKeyPressFilter=
|
|
||||||
# timeout for double tap in sec
|
|
||||||
doubleTapTimeout=0.2
|
|
||||||
|
|
||||||
[general]
|
|
||||||
debugLevel=2
|
|
||||||
punctuationProfile=default
|
|
||||||
punctuationLevel=some
|
|
||||||
respectPunctuationPause=True
|
|
||||||
newLinePause=True
|
|
||||||
numberOfClipboards=10
|
|
||||||
emoticons=True
|
|
||||||
# define the current fenrir key
|
|
||||||
fenrirKeys=KEY_KP0,KEY_META
|
|
||||||
scriptKey=KEY_COMPOSE
|
|
||||||
timeFormat=%H:%M:%P
|
|
||||||
dateFormat=%A, %B %d, %Y
|
|
||||||
autoSpellCheck=True
|
|
||||||
spellCheckLanguage=en_US
|
|
||||||
scriptPath=/usr/share/fenrir/scripts
|
|
||||||
# overload commands, and create new one without changing Fenrir default
|
|
||||||
commandPath=/usr/share/fenrir/commands
|
|
||||||
|
|
||||||
[focus]
|
|
||||||
#follow the text cursor
|
|
||||||
cursor=True
|
|
||||||
#follow highlighted text changes
|
|
||||||
highlight=False
|
|
||||||
|
|
||||||
[review]
|
|
||||||
lineBreak=True
|
|
||||||
endOfScreen=True
|
|
||||||
# leave the review when pressing a key
|
|
||||||
leaveReviewOnKeypress=False
|
|
||||||
# leave the review when changing the screen
|
|
||||||
leaveReviewOnScreenChange=True
|
|
||||||
|
|
||||||
[promote]
|
|
||||||
enabled=True
|
|
||||||
inactiveTimeoutSec=120
|
|
||||||
list=
|
|
||||||
|
|
||||||
[time]
|
|
||||||
# automatic time anouncement
|
|
||||||
enabled=False
|
|
||||||
# present time
|
|
||||||
presentTime=True
|
|
||||||
# present date (on change)
|
|
||||||
presentDate=True
|
|
||||||
# present time after x seconds
|
|
||||||
delaySec=0
|
|
||||||
# present time after to given minutes example every 15 minutes: 00,15,30,45
|
|
||||||
# if delaySec is >0 onMinutes is ignored
|
|
||||||
onMinutes=00,30
|
|
||||||
# announce via soundicon
|
|
||||||
announce=True
|
|
||||||
# interrupt current speech for time announcement
|
|
||||||
interrupt=False
|
|
@ -20,6 +20,28 @@ language=english-us
|
|||||||
volume=1.0
|
volume=1.0
|
||||||
autoReadIncoming=True
|
autoReadIncoming=True
|
||||||
|
|
||||||
|
# genericSpeechCommand is the command that is executed for talking
|
||||||
|
# the following variables are replaced with values
|
||||||
|
# fenrirText = is the text that should be spoken
|
||||||
|
# fenrirModule = may be the speech module like used in speech-dispatcher, not every TTY need this
|
||||||
|
# fenrirLanguage = the language
|
||||||
|
# fenrirVoice = is the current voice that should be used
|
||||||
|
# the current volume, pitch and rate is calculated like this
|
||||||
|
# value = min + settingValue * (min - max )
|
||||||
|
# fenrirVolume = is replaced with the current volume
|
||||||
|
# fenrirPitch = is replaced with the current pitch
|
||||||
|
# fenrirRate = is replaced with the current speed (speech rate)
|
||||||
|
genericSpeechCommand=espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"
|
||||||
|
|
||||||
|
# those are the min and max values of the TTS system that is used in genericSpeechCommand
|
||||||
|
fenrirMinVolume=0
|
||||||
|
fenrirMaxVolume=200
|
||||||
|
fenrirMinPitch=0
|
||||||
|
fenrirMaxPitch=99
|
||||||
|
fenrirMinRate=80
|
||||||
|
fenrirMaxRate=450
|
||||||
|
|
||||||
|
|
||||||
[braille]
|
[braille]
|
||||||
enabled=False
|
enabled=False
|
||||||
driver=brlapiDriver
|
driver=brlapiDriver
|
||||||
|
@ -26,6 +26,13 @@ settings = {
|
|||||||
'voice': '',
|
'voice': '',
|
||||||
'language': 'english-us',
|
'language': 'english-us',
|
||||||
'autoReadIncoming': True,
|
'autoReadIncoming': True,
|
||||||
|
'genericSpeechCommand':'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"',
|
||||||
|
'fenrirMinVolume':0,
|
||||||
|
'fenrirMaxVolume':200,
|
||||||
|
'fenrirMinPitch':0,
|
||||||
|
'fenrirMaxPitch':99,
|
||||||
|
'fenrirMinRate':80,
|
||||||
|
'fenrirMaxRate':450,
|
||||||
},
|
},
|
||||||
'braille':{
|
'braille':{
|
||||||
'enabled': False,
|
'enabled': False,
|
||||||
|
@ -31,13 +31,21 @@ class driver():
|
|||||||
self.language = None
|
self.language = None
|
||||||
self.voice = None
|
self.voice = None
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self._isInitialized = True
|
|
||||||
self.env = environment
|
self.env = environment
|
||||||
self.speechCommand = ''
|
self.minVolume = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMinVolume')
|
||||||
#self.speechCommand = self.env['runtime']['settingsManager'].getSetting('speech', 'genericSpeechCommand')
|
self.maxVolume = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMaxVolume')
|
||||||
|
self.minPitch = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMinPitch')
|
||||||
|
self.maxPitch = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMaxPitch')
|
||||||
|
self.minRate = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMinRate')
|
||||||
|
self.maxRate = self.env['runtime']['settingsManager'].getSettingAsInt('speech', 'fenrirMaxRate')
|
||||||
|
|
||||||
|
self.speechCommand = self.env['runtime']['settingsManager'].getSetting('speech', 'genericSpeechCommand')
|
||||||
if self.speechCommand == '':
|
if self.speechCommand == '':
|
||||||
self.speechCommand = 'spd-say "fenrirText"'
|
self.speechCommand = 'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"'
|
||||||
#'espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"'
|
if False: #for debugging overwrite here
|
||||||
|
self.speechCommand = 'spd-say --wait "fenrirText"'
|
||||||
|
|
||||||
|
self._isInitialized = True
|
||||||
if self._isInitialized:
|
if self._isInitialized:
|
||||||
self.speechThread.start()
|
self.speechThread.start()
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
@ -51,12 +59,6 @@ class driver():
|
|||||||
return
|
return
|
||||||
if not queueable:
|
if not queueable:
|
||||||
self.cancel()
|
self.cancel()
|
||||||
self.volume = '200'
|
|
||||||
self.rate = '200'
|
|
||||||
self.pitch = '200'
|
|
||||||
self.module = ''
|
|
||||||
self.language = ''
|
|
||||||
self.voice = 'de'
|
|
||||||
utterance = {
|
utterance = {
|
||||||
'text': text,
|
'text': text,
|
||||||
'volume': self.volume,
|
'volume': self.volume,
|
||||||
@ -86,32 +88,32 @@ class driver():
|
|||||||
def setVoice(self, voice):
|
def setVoice(self, voice):
|
||||||
if not self._isInitialized:
|
if not self._isInitialized:
|
||||||
return
|
return
|
||||||
print('SpeechDummyDriver: setVoice:' + str(voice))
|
self.voice = str(voice)
|
||||||
|
|
||||||
def setPitch(self, pitch):
|
def setPitch(self, pitch):
|
||||||
if not self._isInitialized:
|
if not self._isInitialized:
|
||||||
return
|
return
|
||||||
print('SpeechDummyDriver: setPitch:' + str(pitch))
|
self.pitch = self.minPitch + pitch * (self.maxPitch - self.minPitch )
|
||||||
|
|
||||||
def setRate(self, rate):
|
def setRate(self, rate):
|
||||||
if not self._isInitialized:
|
if not self._isInitialized:
|
||||||
return
|
return
|
||||||
print('SpeechDummyDriver: setRate:' + str(rate))
|
self.rate = self.minRate + rate * (self.maxRate - self.minRate )
|
||||||
|
|
||||||
def setModule(self, module):
|
def setModule(self, module):
|
||||||
if not self._isInitialized:
|
if not self._isInitialized:
|
||||||
return
|
return
|
||||||
print('SpeechDummyDriver: setModule:' + str(module))
|
self.module = str(module)
|
||||||
|
|
||||||
def setLanguage(self, language):
|
def setLanguage(self, language):
|
||||||
if not self._isInitialized:
|
if not self._isInitialized:
|
||||||
return
|
return
|
||||||
print('SpeechDummyDriver: setLanguage:' + str(language))
|
self.language = str(language)
|
||||||
|
|
||||||
def setVolume(self, volume):
|
def setVolume(self, volume):
|
||||||
if not self._isInitialized:
|
if not self._isInitialized:
|
||||||
return
|
return
|
||||||
print('SpeechDummyDriver: setVolume:' + str(volume))
|
self.volume = self.minVolume + volume * (self.maxVolume - self.minVolume )
|
||||||
|
|
||||||
def worker(self):
|
def worker(self):
|
||||||
while True:
|
while True:
|
||||||
@ -121,24 +123,25 @@ class driver():
|
|||||||
return
|
return
|
||||||
elif not isinstance(utterance, dict):
|
elif not isinstance(utterance, dict):
|
||||||
continue
|
continue
|
||||||
print(utterance)
|
|
||||||
for key, item in utterance.items():
|
for key in ['volume','module','language','voice','pitch','rate','text']:
|
||||||
|
if not key in utterance:
|
||||||
|
utterance[key] = ''
|
||||||
if not utterance[key]:
|
if not utterance[key]:
|
||||||
utterance[key] = ''
|
utterance[key] = ''
|
||||||
|
print(utterance)
|
||||||
popenSpeechCommand = self.speechCommand
|
popenSpeechCommand = self.speechCommand
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirVolume', str(utterance['volume'] ))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirVolume', str(utterance['volume'] ).replace('"',''))
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirModule', str(utterance['module']))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirModule', str(utterance['module']).replace('"',''))
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirLanguage', str(utterance['language']))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirLanguage', str(utterance['language']).replace('"',''))
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirVoice', str(utterance['voice']))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirVoice', str(utterance['voice']).replace('"',''))
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirPitch', str(utterance['pitch']))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirPitch', str(utterance['pitch']).replace('"',''))
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirRate', str(utterance['rate'] ))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirRate', str(utterance['rate']).replace('"',''))
|
||||||
popenSpeechCommand = popenSpeechCommand.replace('fenrirText', str(utterance['text'] ))
|
popenSpeechCommand = popenSpeechCommand.replace('fenrirText', str(utterance['text']).replace('"','').replace('\n',''))
|
||||||
|
|
||||||
self.proc = Popen(popenSpeechCommand, shell=True)
|
|
||||||
try:
|
try:
|
||||||
self.proc = Popen(popenSpeechCommand , stdout=PIPE, stderr=PIPE, shell=True)
|
self.proc = Popen(popenSpeechCommand , stdout=PIPE, stderr=PIPE, shell=True)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = self.proc.communicate()
|
||||||
screenEncoding = self.env['runtime']['settingsManager'].getSetting('screen', 'encoding')
|
screenEncoding = self.env['runtime']['settingsManager'].getSetting('screen', 'encoding')
|
||||||
stderr = stderr.decode(screenEncoding, "replace").encode('utf-8').decode('utf-8')
|
stderr = stderr.decode(screenEncoding, "replace").encode('utf-8').decode('utf-8')
|
||||||
stdout = stdout.decode(screenEncoding, "replace").encode('utf-8').decode('utf-8')
|
stdout = stdout.decode(screenEncoding, "replace").encode('utf-8').decode('utf-8')
|
||||||
|
Loading…
Reference in New Issue
Block a user