|  | @@ -1,105 +1,72 @@
 | 
	
		
			
				|  |  | -import hashlib
 | 
	
		
			
				|  |  |  import os
 | 
	
		
			
				|  |  | -import shutil
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import pygame
 | 
	
		
			
				|  |  |  import requests
 | 
	
		
			
				|  |  |  import logging
 | 
	
		
			
				|  |  |  import sys
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  from core import AudioPlayer
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -VOXYGEN_LANGUAGES = dict(
 | 
	
		
			
				|  |  | -    fr=dict(electra="Electra", emma="Emma", becool="Becool", agnes="Agnes", loic="Loic", fabienne="Fabienne", helene="Helene", marion="Marion", matteo="Matteo",
 | 
	
		
			
				|  |  | -            melodine="Melodine", mendoo="Mendoo", michel="Michel", moussa="Moussa", philippe="Philippe", sorciere="Sorciere"),
 | 
	
		
			
				|  |  | -    ar=dict(adel="Adel"),
 | 
	
		
			
				|  |  | -    de=dict(matthias="Matthias", jylvia="Sylvia"),
 | 
	
		
			
				|  |  | -    uk=dict(bronwen="Bronwen", elizabeth="elizabeth", judith="Judith", paul="Paul", witch="Witch"),
 | 
	
		
			
				|  |  | -    us=dict(bruce="Bruce", jenny="Jenny"),
 | 
	
		
			
				|  |  | -    es=dict(martha="Martha"),
 | 
	
		
			
				|  |  | -    it=dict(sonia="Sonia"))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -VOXYGEN_VOICE_DEFAULT = "Michel"
 | 
	
		
			
				|  |  | -VOXYGEN_LANGUAGES_DEFAULT = "default"
 | 
	
		
			
				|  |  | -VOXYGEN_URL = "https://www.voxygen.fr/sites/all/modules/voxygen_voices/assets/proxy/index.php"
 | 
	
		
			
				|  |  | -VOXYGEN_CONTENT_TYPE = "audio/mpeg"
 | 
	
		
			
				|  |  | -VOXYGEN_TIMEOUT_SEC = 30
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -CACHE_PATH = "/tmp/jarvis/tts/voxygen"
 | 
	
		
			
				|  |  | -CACHE_EXTENSION = ".tts"
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def say(words=None, voice=None, language=VOXYGEN_LANGUAGES_DEFAULT, cache=True):
 | 
	
		
			
				|  |  | -    voice = get_voice(voice, language)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    file_path = get_file_path(words, voice, language)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if get_audio(voice, words, file_path, cache):
 | 
	
		
			
				|  |  | -        AudioPlayer.play_audio(file_path, keep_file=cache)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def get_file_path(words, voice, language):
 | 
	
		
			
				|  |  | -    md5 = hashlib.md5(words).hexdigest()
 | 
	
		
			
				|  |  | -    filename = voice + "." + md5 + CACHE_EXTENSION
 | 
	
		
			
				|  |  | -    cache_directory = os.path.join(CACHE_PATH, language)
 | 
	
		
			
				|  |  | -    file_path = os.path.join(cache_directory, filename)
 | 
	
		
			
				|  |  | -    create_directory(cache_directory)
 | 
	
		
			
				|  |  | -    logging.debug("Cache directory %s exists and File path for audio is: %s", cache_directory, file_path)
 | 
	
		
			
				|  |  | -    return file_path
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def get_voice(voice, language):
 | 
	
		
			
				|  |  | -    if language in VOXYGEN_LANGUAGES and voice in VOXYGEN_LANGUAGES[language]:
 | 
	
		
			
				|  |  | -        return VOXYGEN_LANGUAGES[language][voice]
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    logging.warn("Cannot find language matching language: %s voice: %s replace by default voice: %s", language, voice, VOXYGEN_VOICE_DEFAULT)
 | 
	
		
			
				|  |  | -    return VOXYGEN_VOICE_DEFAULT
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def get_audio(voice, text, file_path, cache):
 | 
	
		
			
				|  |  | -    if not cache or not os.path.exists(file_path) or file_is_empty(file_path):
 | 
	
		
			
				|  |  | -        payload = {
 | 
	
		
			
				|  |  | -            "method": "redirect",
 | 
	
		
			
				|  |  | -            "text": text.encode('utf8'),
 | 
	
		
			
				|  |  | -            "voice": voice
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        r = requests.get(VOXYGEN_URL, params=payload, stream=True, timeout=VOXYGEN_TIMEOUT_SEC)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        content_type = r.headers['Content-Type']
 | 
	
		
			
				|  |  | -        logging.debug("Trying to get url: %s response code: %s and content-type: %s", r.url, r.status_code, content_type)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | -            if r.status_code == requests.codes.ok and content_type == VOXYGEN_CONTENT_TYPE:
 | 
	
		
			
				|  |  | -                return write_in_file(file_path, r.content)
 | 
	
		
			
				|  |  | -            else:
 | 
	
		
			
				|  |  | -                return False
 | 
	
		
			
				|  |  | -        except IOError as e:
 | 
	
		
			
				|  |  | -            logging.error("I/O error(%s): %s", e.errno, e.strerror)
 | 
	
		
			
				|  |  | -        except ValueError:
 | 
	
		
			
				|  |  | -            logging.error("Could not convert data to an integer.")
 | 
	
		
			
				|  |  | -        except:
 | 
	
		
			
				|  |  | -            logging.error("Unexpected error: %s", sys.exc_info()[0])
 | 
	
		
			
				|  |  | -    else:
 | 
	
		
			
				|  |  | -        return True
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def write_in_file(file_path, content):
 | 
	
		
			
				|  |  | -    with open(file_path, "wb") as file_open:
 | 
	
		
			
				|  |  | -        file_open.write(content)
 | 
	
		
			
				|  |  | -        file_open.close()
 | 
	
		
			
				|  |  | -    return not file_is_empty(file_path)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def file_is_empty(file_path):
 | 
	
		
			
				|  |  | -    return os.path.getsize(file_path) == 0
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def create_directory(cache_path):
 | 
	
		
			
				|  |  | -    if not os.path.exists(cache_path):
 | 
	
		
			
				|  |  | -        os.makedirs(cache_path)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -def wipe_cache():
 | 
	
		
			
				|  |  | -    shutil.rmtree(CACHE_PATH)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +from tts import TTS
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Voxygen(TTS):
 | 
	
		
			
				|  |  | +    VOXYGEN_LANGUAGES = dict(
 | 
	
		
			
				|  |  | +        fr=dict(electra="Electra", emma="Emma", becool="Becool", agnes="Agnes", loic="Loic", fabienne="Fabienne", helene="Helene", marion="Marion",
 | 
	
		
			
				|  |  | +                matteo="Matteo",
 | 
	
		
			
				|  |  | +                melodine="Melodine", mendoo="Mendoo", michel="Michel", moussa="Moussa", philippe="Philippe", sorciere="Sorciere"),
 | 
	
		
			
				|  |  | +        ar=dict(adel="Adel"),
 | 
	
		
			
				|  |  | +        de=dict(matthias="Matthias", jylvia="Sylvia"),
 | 
	
		
			
				|  |  | +        uk=dict(bronwen="Bronwen", elizabeth="elizabeth", judith="Judith", paul="Paul", witch="Witch"),
 | 
	
		
			
				|  |  | +        us=dict(bruce="Bruce", jenny="Jenny"),
 | 
	
		
			
				|  |  | +        es=dict(martha="Martha"),
 | 
	
		
			
				|  |  | +        it=dict(sonia="Sonia"))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    VOXYGEN_VOICE_DEFAULT = "Michel"
 | 
	
		
			
				|  |  | +    VOXYGEN_LANGUAGES_DEFAULT = "default"
 | 
	
		
			
				|  |  | +    VOXYGEN_URL = "https://www.voxygen.fr/sites/all/modules/voxygen_voices/assets/proxy/index.php"
 | 
	
		
			
				|  |  | +    VOXYGEN_CONTENT_TYPE = "audio/mpeg"
 | 
	
		
			
				|  |  | +    VOXYGEN_TIMEOUT_SEC = 30
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self):
 | 
	
		
			
				|  |  | +        TTS.__init__(self)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def say(self, words=None, voice=None, language=VOXYGEN_LANGUAGES_DEFAULT, cache=True):
 | 
	
		
			
				|  |  | +        voice = self.get_voice(voice, language)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        file_path = self.cache.get_audio_file_cache_path(words, voice, language)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if self.get_audio(voice, words, file_path, cache):
 | 
	
		
			
				|  |  | +            AudioPlayer.play_audio(file_path, keep_file=cache)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def get_voice(self, voice, language):
 | 
	
		
			
				|  |  | +        if language in self.VOXYGEN_LANGUAGES and voice in self.VOXYGEN_LANGUAGES[language]:
 | 
	
		
			
				|  |  | +            return self.VOXYGEN_LANGUAGES[language][voice]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        logging.warn("Cannot find language matching language: %s voice: %s replace by default voice: %s", language, voice, self.VOXYGEN_VOICE_DEFAULT)
 | 
	
		
			
				|  |  | +        return self.VOXYGEN_VOICE_DEFAULT
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def get_audio(self, voice, text, file_path, cache):
 | 
	
		
			
				|  |  | +        if not cache or not os.path.exists(file_path) or self.cache.file_is_empty(file_path):
 | 
	
		
			
				|  |  | +            payload = {
 | 
	
		
			
				|  |  | +                "method": "redirect",
 | 
	
		
			
				|  |  | +                "text": text.encode('utf8'),
 | 
	
		
			
				|  |  | +                "voice": voice
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            r = requests.get(self.VOXYGEN_URL, params=payload, stream=True, timeout=self.VOXYGEN_TIMEOUT_SEC)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            content_type = r.headers['Content-Type']
 | 
	
		
			
				|  |  | +            logging.debug("Trying to get url: %s response code: %s and content-type: %s", r.url, r.status_code, content_type)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            try:
 | 
	
		
			
				|  |  | +                if r.status_code == requests.codes.ok and content_type == self.VOXYGEN_CONTENT_TYPE:
 | 
	
		
			
				|  |  | +                    return self.cache.write_in_file(file_path, r.content)
 | 
	
		
			
				|  |  | +                else:
 | 
	
		
			
				|  |  | +                    return False
 | 
	
		
			
				|  |  | +            except IOError as e:
 | 
	
		
			
				|  |  | +                logging.error("I/O error(%s): %s", e.errno, e.strerror)
 | 
	
		
			
				|  |  | +            except ValueError:
 | 
	
		
			
				|  |  | +                logging.error("Could not convert data to an integer.")
 | 
	
		
			
				|  |  | +            except:
 | 
	
		
			
				|  |  | +                logging.error("Unexpected error: %s", sys.exc_info()[0])
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            return True
 |