44
55import os
66import shutil
7+ import sys
78import urllib .request
89from dataclasses import dataclass
910from threading import Thread
4344 "te" :"Telugu" ,
4445 "en" :"English" }
4546
47+ # URL suffix for voice files
48+ H2RNG_VOICES_DOWNLOAD_HTTP = "https://hear2read.org/Hear2Read/voices-piper/"
49+ # voice list URL
50+ H2RNG_VOICE_LIST_URL = "https://hear2read.org/nvda-addon/getH2RNGVoiceNames.php"
51+
4652try :
4753 _dir = os .path .dirname (__file__ .decode ("mbcs" ))
4854except AttributeError :
5359OLD_H2RNG_DATA_DIR = os .path .join (os .environ ['ALLUSERSPROFILE' ],
5460 "Hear2Read-ng" )
5561
62+ def copytree_compat (src , dst ):
63+ """Copytree version with overwrite compatible for Python < 3.8. This is
64+ copied from the answer https://stackoverflow.com/a/13814557, and has a
65+ fairly basic functionality not accounting for symlinks, which is sufficient
66+ for our purposes
67+
68+ @param src: path to the source, to be copied from
69+ @type src: string
70+ @param dst: path to the destination, to be copied to
71+ @type dst: string
72+ """
73+ if not os .path .exists (dst ):
74+ os .makedirs (dst )
75+ for item in os .listdir (src ):
76+ s = os .path .join (src , item )
77+ d = os .path .join (dst , item )
78+ if os .path .isdir (s ):
79+ copytree_compat (s , d )
80+ else :
81+ if not os .path .exists (d ) or os .stat (s ).st_mtime - os .stat (d ).st_mtime > 1 :
82+ shutil .copy2 (s , d )
83+
84+ def copytree_overwrite (src , dst ):
85+ """Wrapper to enable consistent behaviour in Python version < 3.8
86+
87+ @param src: path to the source, to be copied from
88+ @type src: string
89+ @param dst: path to the destination, to be copied to
90+ @type dst: string
91+ """
92+ if sys .version_info >= (3 , 8 ):
93+ shutil .copytree (src = src , dst = dst , dirs_exist_ok = True )
94+ else :
95+ copytree_compat (src = src , dst = dst )
96+
97+
5698def check_files ():
5799 """
58100 Checks whether the files and directories vital to Hear2Read Indic are
@@ -74,28 +116,6 @@ def check_files():
74116 if not os .listdir (H2RNG_PHONEME_DIR ):
75117 return False
76118 # phonedir_is_present = True
77-
78- # if os.path.isdir(H2RNG_VOICES_DIR):
79- # file_list = os.listdir(H2RNG_VOICES_DIR)
80-
81- # for file_name in file_list:
82- # parts = file_name.split(".")
83- # if parts[-1] == "onnx" and f"{file_name}.json" in file_list:
84- # return True
85-
86- # return wx.YES == gui.messageBox(
87- # # Translators: message telling the user that no voice is installed
88- # _(
89- # "Hear2Read needs to have an Indic voice to function.\n"
90- # "Please select a Hear2Read voice to download from the manager.\n"
91- # "Do you want to open the voice manager now?"
92- # ),
93- # # Translators: title of a message telling the user that no Hear2Read Indic voice was found
94- # _("Hear2Read Indic Voices"),
95- # wx.YES_NO | wx.ICON_WARNING,)
96-
97- # voice_is_present = True
98- # break
99119
100120 except Exception as e :
101121 log .warn (f"Hear2Read Indic check failed with exception: { e } " )
@@ -105,6 +125,40 @@ def check_files():
105125 # return dll_is_present and phonedir_is_present and voice_is_present
106126
107127
128+ def parse_server_voices (resp_str ):
129+ """Parses the pipe separated file list response from the server
130+
131+ @param resp_str: string of pipe separated voice related files
132+ @type resp_str: string
133+ """
134+ server_voices = {}
135+ server_files = resp_str .split ('|' )
136+ for file in server_files :
137+ if file .startswith ("en" ):
138+ continue
139+ parts = file .split ("." )
140+ if parts [- 1 ] == "onnx" :
141+ if f"{ file } .json" in server_files :
142+ iso_lang = parts [0 ].split ("-" )[0 ].split ("_" )[0 ]
143+ extra = False
144+ if f"{ file } .zip" in server_files :
145+ extra = True
146+ if iso_lang in lang_names .keys ():
147+ server_voices [iso_lang ] = Voice (id = parts [0 ],
148+ lang_iso = iso_lang ,
149+ display_name = lang_names [iso_lang ],
150+ state = "Download" ,
151+ extra = extra )
152+ else :
153+ server_voices [iso_lang ] = Voice (id = parts [0 ],
154+ lang_iso = iso_lang ,
155+ display_name = f"Unknown Lang ({ iso_lang } )" ,
156+ state = "Download" ,
157+ extra = extra )
158+
159+ return server_voices
160+
161+
108162def populateVoices ():
109163 pathName = os .path .join (H2RNG_VOICES_DIR )
110164 voices = dict ()
@@ -164,8 +218,7 @@ def move_old_voices():
164218
165219 if os .path .isdir (old_wavs_dir ):
166220 try :
167- shutil .copytree (src = old_wavs_dir , dst = H2RNG_WAVS_DIR ,
168- dirs_exist_ok = True )
221+ copytree_overwrite (src = old_wavs_dir , dst = H2RNG_WAVS_DIR )
169222 except Exception as e :
170223 log .warn ("Hear2Read Indic unable to copy old wav folders" )
171224
@@ -194,7 +247,8 @@ def move_old_voices():
194247
195248def onInstall ():
196249 """A fallback that tries moving the required data files in case it wasn't
197- done by installTasks.py
250+ done by installTasks.py It is duplicated as importing is not available with
251+ installTasks.py
198252
199253 @raises e: raises any exceptions that can occur while transferring the data
200254 @return: returns True if any voices from an older version (<v1.5) have been
@@ -206,7 +260,7 @@ def onInstall():
206260 src_dir = os .path .join (_dir , "res" )
207261
208262 try :
209- shutil . copytree (src = src_dir , dst = H2RNG_DATA_DIR , dirs_exist_ok = True )
263+ copytree_overwrite (src = src_dir , dst = H2RNG_DATA_DIR )
210264 shutil .rmtree (src_dir )
211265 except Exception as e :
212266 log .warn (f"Error installing Hear2Read Indic data files: { e } " )
0 commit comments