Пример #1
0
def preInstalledFirstRun():
    if not SystemQueries.isPreInstalled(
    ):  # Do as little as possible if there is no pre-install
        if SystemQueries.wasPreInstalled():
            module_logger.info('PRE INSTALL: REMOVED')
            # Set version to 0.0.0 so normal first run will execute and fix the
            # keymap
            Settings.setSetting('version', '0.0.0')
            enabler.markPreOrPost()  # Update the install status
        return False

    lastVersion = Settings.getSetting('version')

    if not enabler.isPostInstalled() and SystemQueries.wasPostInstalled():
        module_logger.info('POST INSTALL: UN-INSTALLED OR REMOVED')
        # Add-on was removed. Assume un-installed and treat this as a
        # pre-installed first run to disable the addon
    elif lastVersion:
        enabler.markPreOrPost()  # Update the install status
        return False

    # Set version to 0.0.0 so normal first run will execute on first enable
    Settings.setSetting('version', '0.0.0')

    module_logger.info('PRE-INSTALLED FIRST RUN')
    module_logger.info('Installing basic keymap')

    # Install keymap with just F12 enabling included
    from utils import keymapeditor
    keymapeditor.installBasicKeymap()

    module_logger.info('Pre-installed - DISABLING')

    enabler.disableAddon()
    return True
Пример #2
0
    def available():
        try:
            subprocess.call(['flite', '--help'],
                            stdout=(open(os.path.devnull, 'w')),
                            universal_newlines=True,
                            stderr=subprocess.STDOUT)
        except (OSError, IOError):
            return SystemQueries.isATV2() and SystemQueries.commandIsAvailable(
                'flite')
        return True


#class FliteTTSBackend(TTSBackendBase):
#    provider = 'Flite':q:q
#    def __init__(self):
#        import ctypes
#        self.flite = ctypes.CDLL('libflite.so.1',mode=ctypes.RTLD_GLOBAL)
#        flite_usenglish = ctypes.CDLL('libflite_usenglish.so.1',mode=ctypes.RTLD_GLOBAL) #analysis:ignore
#        flite_cmulex = ctypes.CDLL('libflite_cmulex.so.1',mode=ctypes.RTLD_GLOBAL) #analysis:ignore
#        flite_cmu_us_slt = ctypes.CDLL('libflite_cmu_us_slt.so.1')
#        self.flite.flite_init()
#        self.voice = flite_cmu_us_slt.register_cmu_us_slt()
#
#    def say(self,text,interrupt=False):
#        if not text: return
#        self.flite.flite_text_to_speech(text,self.voice,'play')
#
#
#    @staticmethod
#    def available():
#        try:
#            import ctypes
#            ctypes.CDLL('libflite.so.1')
#        except (OSError, IOError):
#            return False
#        return True

#class FliteTTSBackend(TTSBackendBase):
#    provider = 'Flite'
#
#    def say(self,text,interrupt=False):
#        if not text: return
#        voice = self.currentVoice() or 'kal16'
#        subprocess.call(['flite', '-voice', voice, '-t', text], universal_newlines=True)
#
#    def voices(self):
#        return subprocess.check_output(['flite','-lv'], universal_newlines=True).split(': ',1)[-1].strip().split(' ')
#
#    @staticmethod
#    def available():
#        try:
#            subprocess.call(['flite', '--help'], stdout=(open(os.path.devnull, 'w')),
#            stderr=subprocess.STDOUT, universal_newlines=True)
#        except (OSError, IOError):
#            return False
#        return True
Пример #3
0
def getBackendFallback():
    if SystemQueries.isATV2():
        return FliteTTSBackend
    elif SystemQueries.isWindows():
        return SAPITTSBackend
    elif SystemQueries.isOSX():
        return OSXSayTTSBackend
    elif SystemQueries.isOpenElec():
        return ESpeakTTSBackend
    for b in backendsByPriority:
        if b._available(): return b
    return None
Пример #4
0
def buildKeymap(defaults=False):  # TODO: Build XML with ElementTree?
    xml = None
    with open(_keymapSource(), 'r') as f:
        xml = f.read()
    if not xml:
        return
    if defaults:
        defs = {}
    else:
        defs = loadCustomKeymapDefs()
    for action, default in ACTIONS:
        key = defs.get('key.{0}'.format(action))
        if key:
            xml = xml.replace('<{0}>'.format(action),
                              '<key id="{0}">'.format(key)).replace(
                                  '</{0}>'.format(action), '</key>')
        else:
            xml = xml.replace('<{0}>'.format(action),
                              '<{0}>'.format(default)).replace(
                                  '</{0}>'.format(action),
                                  '</{0}>'.format(default.split(' ', 1)[0]))

    xml = xml.format(
        SPECIAL=SystemQueries.isPreInstalled() and 'xbmc' or 'home')

    saveKeymapXML(xml)
Пример #5
0
    def available():
        return sys.platform == 'darwin' and not SystemQueries.isATV2()


#on isVoiceOverRunning()
#	set isRunning to false
#	tell application "System Events"
#		set isRunning to (name of processes) contains "VoiceOver"
#	end tell
#	return isRunning
#end isVoiceOverRunning
#
#on isVoiceOverRunningWithAppleScript()
#	if isVoiceOverRunning() then
#		set isRunningWithAppleScript to true
#
#		-- is AppleScript enabled on VoiceOver --
#		tell application "VoiceOver"
#			try
#				set x to bounds of vo cursor
#			on error
#				set isRunningWithAppleScript to false
#			end try
#		end tell
#		return isRunningWithAppleScript
#	end if
#	return false
#end isVoiceOverRunningWithAppleScript
Пример #6
0
 def update(self):
     self.voice = self.setting('voice')
     self.rate = self.setting('speed')
     self.useAOSS = self.setting('use_aoss')
     if self.useAOSS and not SystemQueries.commandIsAvailable('aoss'):
         self._logger.info(
             'Cepstral: Use aoss is enabled, but aoss is not found. Disabling.'
         )
         self.useAOSS = False
     volume = self.setting('volume')
     self.volume = int(round(
         100 * (10**(volume / 20.0))))  #convert from dB to percent
     pitch = self.setting('pitch')
     self.pitch = 0.4 + (
         (pitch + 6) /
         20.0) * 2  #Convert from (-6 to +14) value to (0.4 to 2.4)
Пример #7
0
 def isSupportedOnPlatform():
     return (SystemQueries.isLinux() or SystemQueries.isWindows()
             or SystemQueries.isOSX())
Пример #8
0
 def available():
     return SystemQueries.isWindows()
Пример #9
0
 def isSupportedOnPlatform():
     return SystemQueries.isWindows()
Пример #10
0
 def isSupportedOnPlatform():
     return SystemQueries.isLinux()
Пример #11
0
class FliteTTSBackend(base.SimpleTTSBackendBase):
    provider = Backends.FLITE_ID
    displayName = 'Flite'
    speedConstraints = (20, 100, 200, True)

    settings = {
        Settings.PIPE: False,
        Settings.PLAYER: Players.INTERNAL,
        Settings.SPEED: 100,
        Settings.VOICE: 'kal16',
        Settings.VOLUME: 0
    }
    onATV2 = SystemQueries.isATV2()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._logger = module_logger.getChild(
            self.__class__.__name__)  # type: LazyLogger
        self.process = None

    def init(self):
        self.process = None
        self.update()

    @staticmethod
    def isSupportedOnPlatform():
        return SystemQueries.isLinux()

    @staticmethod
    def isInstalled():
        installed = False
        if FliteTTSBackend.isSupportedOnPlatform():
            installed = True
        return installed

    def runCommand(self, text_to_voice, dummy):
        wave_file, exists = self.get_path_to_voice_file(text_to_voice,
                                                        use_cache=False)

        if self.onATV2:
            os.system('flite -t "{0}" -o "{1}"'.format(text_to_voice,
                                                       wave_file))
        else:
            voice = type(self).getVoice()
            subprocess.call([
                'flite', '-voice', voice, '-t', text_to_voice, '-o', wave_file
            ],
                            universal_newlines=True)
        return True

    def runCommandAndSpeak(self, text_to_voice):

        voice = type(self).getVoice()
        self.process = subprocess.Popen(
            ['flite', '-voice', voice, '-t', text_to_voice],
            universal_newlines=True)
        while self.process.poll() is None and self.active:
            xbmc.sleep(10)

    def update(self):
        pass

    def getMode(self):
        if not self.onATV2 and self.setting('output_via_flite'):
            return base.SimpleTTSBackendBase.ENGINESPEAK
        else:
            return base.SimpleTTSBackendBase.WAVOUT

    def stop(self):
        if not self.process: return
        try:
            self.process.terminate()
        except:
            pass

    @classmethod
    def settingList(cls, setting, *args):
        if cls.onATV2:
            return None

        elif setting == Settings.PLAYER:
            # Get list of player ids. Id is same as is stored in settings.xml

            players = cls.get_players(include_builtin=False)
            default_player = cls.get_setting_default(Settings.PLAYER)

            return players, default_player

        elif setting == 'voice':
            return [(v, v)
                    for v in subprocess.check_output(
                        ['flite', '-lv'], universal_newlines=True).split(
                            ': ', 1)[-1].strip().split(' ')]

    @staticmethod
    def available():
        try:
            subprocess.call(['flite', '--help'],
                            stdout=(open(os.path.devnull, 'w')),
                            universal_newlines=True,
                            stderr=subprocess.STDOUT)
        except (OSError, IOError):
            return SystemQueries.isATV2() and SystemQueries.commandIsAvailable(
                'flite')
        return True


#class FliteTTSBackend(TTSBackendBase):
#    provider = 'Flite':q:q
#    def __init__(self):
#        import ctypes
#        self.flite = ctypes.CDLL('libflite.so.1',mode=ctypes.RTLD_GLOBAL)
#        flite_usenglish = ctypes.CDLL('libflite_usenglish.so.1',mode=ctypes.RTLD_GLOBAL) #analysis:ignore
#        flite_cmulex = ctypes.CDLL('libflite_cmulex.so.1',mode=ctypes.RTLD_GLOBAL) #analysis:ignore
#        flite_cmu_us_slt = ctypes.CDLL('libflite_cmu_us_slt.so.1')
#        self.flite.flite_init()
#        self.voice = flite_cmu_us_slt.register_cmu_us_slt()
#
#    def say(self,text,interrupt=False):
#        if not text: return
#        self.flite.flite_text_to_speech(text,self.voice,'play')
#
#
#    @staticmethod
#    def available():
#        try:
#            import ctypes
#            ctypes.CDLL('libflite.so.1')
#        except (OSError, IOError):
#            return False
#        return True

#class FliteTTSBackend(TTSBackendBase):
#    provider = 'Flite'
#
#    def say(self,text,interrupt=False):
#        if not text: return
#        voice = self.currentVoice() or 'kal16'
#        subprocess.call(['flite', '-voice', voice, '-t', text], universal_newlines=True)
#
#    def voices(self):
#        return subprocess.check_output(['flite','-lv'], universal_newlines=True).split(': ',1)[-1].strip().split(' ')
#
#    @staticmethod
#    def available():
#        try:
#            subprocess.call(['flite', '--help'], stdout=(open(os.path.devnull, 'w')),
#            stderr=subprocess.STDOUT, universal_newlines=True)
#        except (OSError, IOError):
#            return False
#        return True
Пример #12
0
 def available():
     return sys.platform == 'darwin' and not SystemQueries.isATV2()
Пример #13
0
 def isSupportedOnPlatform():
     return SystemQueries.isOSX()
Пример #14
0
class FestivalTTSBackend(SimpleTTSBackendBase):
    provider = Backends.FESTIVAL_ID
    displayName = 'Festival'
    canStreamWav = SystemQueries.commandIsAvailable('mpg123')
    speedConstraints = (-16, 0, 12, True)
    pitchConstraints = (50, 105, 500, True)
    volumeConstraints = (-12, 0, 12, True)
    player_handler_class: Type[BasePlayerHandler] = WavAudioPlayerHandler

    settings = {
        Settings.PIPE: False,
        Settings.PITCH: 105,
        Settings.PLAYER: Players.MPLAYER,
        Settings.SPEED: 0,    # Undoubtedly settable, also supported by some players
        Settings.VOICE: '',
        Settings.VOLUME: 0
    }
    _logger = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if type(self)._logger is None:
            type(self)._logger = module_logger.getChild(self.__class__.__name__)  # type: LazyLogger
        self.festivalProcess = None

    def init(self):
        self.festivalProcess = None
        self.update()

    @staticmethod
    def isSupportedOnPlatform():
        return SystemQueries.isLinux()

    @staticmethod
    def isInstalled():
        installed = False
        if FestivalTTSBackend.isSupportedOnPlatform():
            installed = True
        return installed

    def getMode(self):
        player = type(self).getSetting(Settings.PLAYER)

        if type(self).getSetting(Settings.PIPE):
            return SimpleTTSBackendBase.PIPE
        else:
            return SimpleTTSBackendBase.WAVOUT

    def runCommand(self, text_to_voice, dummy):

        wave_file, exists = self.get_path_to_voice_file(text_to_voice, use_cache=False)

        wave_pipe = None
        return self.generate_speech(text_to_voice, wave_file)

    def runCommandAndPipe(self, text_to_voice):

        wave_file, exists = self.get_path_to_voice_file(text_to_voice, use_cache=False)

        wave_pipe = None
        if self.generate_speech(text_to_voice, wave_file):
            wave_pipe = io.BytesIO(wave_file)

        return wave_pipe

    def generate_speech(self, text_to_voice: str, wave_file: str):
        # In addition to festival, see the text2wave command

        if not text_to_voice:
            return None
        text_to_voice = text_to_voice.strip()
        if len(text_to_voice) == 0:
            return None

        volume = type(self).getVolume()
        volume = 1 * (10 ** (volume / 20.0))  # convert from dB to percent/100

        voice = type(self).getVoice()
        voice = voice and '(voice_{0})'.format(voice) or ''

        speed = type(self).getSpeed()
        durationMultiplier = 1.8 - (((speed + 16) / 28.0) * 1.4)  #
        # Convert from (-16 to +12) value to (1.8 to 0.4)
        durMult = durationMultiplier and "(Parameter.set 'Duration_Stretch {0})".format(
            durationMultiplier) or ''

        pitch = type(self).getPitch()
        pitch = pitch != 105 and "(require 'prosody-param)(set-pitch {0})".format(
            pitch) or ''

        # Assumption is to only adjust speech settings in engine, not player

        player_volume = 0.0  # '{:.2f}'.format(0.0)  # Don't alter volume (db)
        player_speed =  100.0  # '{:.2f}'.format(100.0)  # Don't alter speed/tempo (percent)
        # Changing pitch without impacting tempo (speed) is
        player_pitch = 100.0  # '{:.2f}'.format(100.0)  # Percent
        # not easy. One suggestion is to use lib LADSPA

        self.setPlayer(type(self).getSetting(Settings.PLAYER))
        self.player_handler.setVolume(player_volume)  # In db -12 .. 12
        self.player_handler.setSpeed(player_speed)
        self.player_handler.setPitch(player_pitch)

        self.festivalProcess = subprocess.Popen(['festival', '--pipe'],
                                                stdin=subprocess.PIPE,
                                                universal_newlines=True)
        text_to_voice = text_to_voice.replace('"', '\\"').strip()
        out = '(audio_mode \'async){0}{1}{2}(utt.save.wave (utt.wave.rescale (SynthText ' \
              '' \
              '"{3}") {4:.2f} nil)"{5}")\n'.format(
                     voice, durMult, pitch, text_to_voice, volume, wave_file)
        self.festivalProcess.communicate(out)
        return True

    def stop(self):
        try:
            self.festivalProcess.terminate()
        except:
            return

    @classmethod
    def settingList(cls, setting, *args):
        if setting == Settings.LANGUAGE:
            return [], None

        elif setting == Settings.VOICE:
            p = subprocess.Popen(['festival', '-i'], stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                 universal_newlines=True)
            d = p.communicate('(voice.list)')
            voices = list(
                map(str.strip, d[0].rsplit('> (', 1)[-1].rsplit(')', 1)[0].split(' ')))
            if voices:
                return [(v, v) for v in voices]  # name, id

        elif setting == Settings.PLAYER:
            # Get list of player ids. Id is same as is stored in settings.xml

            players = cls.get_players(include_builtin=False)
            default_player = cls.get_setting_default(Settings.PLAYER)

            return players, default_player

        return None

    @staticmethod
    def available():
        try:
            subprocess.call(['festival', '--help'], stdout=(open(os.path.devnull, 'w')),
                            stderr=subprocess.STDOUT, universal_newlines=True)
        except (OSError, IOError):
            return False
        return True
Пример #15
0
class GoogleTTSBackend(base.SimpleTTSBackendBase):
    provider = 'Google'
    displayName = 'Google'
    # ttsURL = 'http://translate.google.com/translate_tts?client=t&tl={0}&q={1}'
    ttsURL = 'https://translate.google.com/translate_tts?&q={1}&tl={0}&client=tw-ob'
    canStreamWav = SystemQueries.commandIsAvailable('mpg123')
    playerClass = audio.MP3AudioPlayerHandler
    settings = {
        'language': 'en',
        'pipe': False,
        'player': 'mpg123',
        'volume': 0
    }

    def init(self):
        self.process = None
        self.update()

    @staticmethod
    def isSupportedOnPlatform():
        return (SystemQueries.isLinux() or SystemQueries.isWindows()
                or SystemQueries.isOSX())

    @staticmethod
    def isInstalled():
        installed = False
        if GoogleTTSBackend.isSupportedOnPlatform():
            installed = True
        return installed

    def threadedSay(self, text):
        if not text: return
        sections = textwrap.wrap(text, 100)
        if self.mode == self.PIPE:
            for text in sections:
                source = self.runCommandAndPipe(text)
                if not source: continue
                self.player_handler.pipeAudio(source)
        else:
            for text in sections:
                outFile = self.player_handler.getOutFile(text, use_cache=False)
                if not self.runCommand(text, outFile): return
                self.player_handler.play()

    def runCommand(self, text, outFile):
        url = self.ttsURL.format(self.language, urllib.parse.quote(text))
        LazyLogger.debug_verbose('Google url: ' + url)
        #

        # local IFS = +; /usr/bin/mplayer -ao alsa -really -quiet -noconsolecontrols "http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=$*&tl=en";
        headers = {
            'Referer': 'http://translate.google.com',
            'User-Agent': 'stagefright/1.2 (Linux;Android 5.0)'
        }
        req = urllib.request.Request(url, headers=headers)
        try:
            resp = urllib.request.urlopen(req)
        except:
            OldLogger.ERROR('Failed to open Google TTS URL', hide_tb=True)
            return False

        with open(outFile, 'wb') as out:
            shutil.copyfileobj(resp, out)
        return True

    def runCommandAndPipe(self, text):
        url = self.ttsURL.format(self.language, urllib.parse.quote(text))
        LazyLogger.debug_verbose('Google url: ' + url)
        #req = urllib.request.Request(url) #, headers={ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36' })
        headers = {
            'Referer': 'http://translate.google.com/',
            'User-Agent': 'stagefright/1.2 (Linux;Android 5.0)'
        }
        req = urllib.request.Request(url, headers=headers)
        try:
            resp = urllib.request.urlopen(req)
            LazyLogger.debug_verbose('url: ' + req.get_full_url())
            LazyLogger.debug_verbose('headers: ' + str(req.header_items()))
        except:
            OldLogger.ERROR('Failed to open Google TTS URL', hide_tb=True)
            return None
        return resp

    def getWavStream(self, text):

        wav_path = os.path.join(utils.getTmpfs(), 'speech.wav')
        mp3_path = os.path.join(utils.getTmpfs(), 'speech.mp3')
        self.runCommand(text, mp3_path)
        self.process = subprocess.Popen(['mpg123', '-w', wav_path, mp3_path],
                                        stdout=(open(os.path.devnull, 'w')),
                                        stderr=subprocess.STDOUT,
                                        universal_newlines=True)
        while self.process.poll() is None and self.active:
            xbmc.sleep(10)
        os.remove(mp3_path)
        return open(wav_path, 'rb')

    def update(self):
        self.language = self.setting('language')
        self.setPlayer(self.setting('player'))
        self.setVolume(self.setting('volume'))
        self.setMode(self.getMode())

    def getMode(self):
        if self.setting('pipe'):
            return base.SimpleTTSBackendBase.PIPE
        else:
            return base.SimpleTTSBackendBase.WAVOUT

    def stop(self):
        if not self.process: return
        try:
            self.process.terminate()
        except:
            pass

    @classmethod
    def settingList(cls, setting, *args):
        if setting == 'language':
            return LANGUAGES
        return None

    @staticmethod
    def available():
        return audio.MP3AudioPlayerHandler.canPlay()
Пример #16
0
 def isSupportedOnPlatform(cls):
     return SystemQueries.isLinux() or SystemQueries.isAndroid()