liuyuqi-dellpc 4 years ago
commit
2b16b4fe75

+ 276 - 0
baidu/SubtitleTranslate - baidu.as

@@ -0,0 +1,276 @@
+/*
+	real time subtitle translate for PotPlayer using Bai Du API
+*/
+
+// string GetTitle() 														-> get title for UI
+// string GetVersion														-> get version for manage
+// string GetDesc()															-> get detail information
+// string GetLoginTitle()													-> get title for login dialog
+// string GetLoginDesc()													-> get desc for login dialog
+// string ServerLogin(string User, string Pass)								-> login
+// string ServerLogout()													-> logout
+// array<string> GetSrcLangs() 												-> get source language
+// array<string> GetDstLangs() 												-> get target language
+// string Translate(string Text, string &in SrcLang, string &in DstLang) 	-> do translate !!
+
+
+//必须配置的部分,不过现在已经移交到“实时字幕翻译”中了
+//它的位置是: 打开任意视频或者点击左上角的PolPlayer -> 字幕 -> 实时字幕翻译 -> 实时字幕翻译设置 -> 选中百度翻译 -> 点右边的 “账户设置”
+string appId = "";//appid
+string toKey = "";//密钥
+
+//可选配置,一般而言是不用修改的!
+int coolTime = 1000;//冷却时间,这里的单位是毫秒,1秒钟=1000毫秒,如果提示 error:54003, 那么就加大这个数字,建议一次加100
+string userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";//这个是可选配置,一般不用修改!
+
+//执行环境,请不要修改!
+int NULL = 0;
+int executeThreadId = NULL;//这个变量的命名是我的目标,不过,暂时没能实现!只是做了个还有小bug的临时替代方案
+int nextExecuteTime = 0;//下次执行代码的时间
+
+
+string GetVersion(){
+	return "1";
+}
+
+string GetTitle(){
+	return "{$CP950=Bai Du 翻譯$}{$CP0=Bai Du translate$}";
+}
+
+
+string GetDesc(){
+	return "https://fanyi.baidu.com/";
+}
+
+string GetLoginTitle(){
+	return "请输入配置";
+}
+
+string GetLoginDesc(){
+	return "请输入AppId和密钥!";
+}
+
+
+string GetUserText(){
+	return "App ID:";
+}
+
+string GetPasswordText(){
+	return "密钥:";
+}
+
+
+array<string> GetSrcLangs(){
+	array<string> ret = GetLangTable();
+	
+	ret.insertAt(0, ""); // empty is auto
+	return ret;
+}
+
+array<string> GetDstLangs(){
+	return GetLangTable();
+}
+
+string ServerLogin(string appIdStr, string toKeyStr){
+	if (appIdStr.empty() || toKeyStr.empty()) return "fail";
+	appId = appIdStr;
+	toKey = toKeyStr;
+	return "200 ok";
+}
+
+
+string Translate(string text, string &in srcLang, string &in dstLang){
+	string ret = "";
+	if(!text.empty()){//确实有内容需要翻译才有必要继续
+		//开发文档。需要App id 等信息
+		//http://api.fanyi.baidu.com/api/trans/product/apidoc
+		// HostOpenConsole();	// for debug
+		
+		//语言选择
+		srcLang = GetLang(srcLang);
+		dstLang = GetLang(dstLang);
+		
+		
+	//	API.. Always UTF-8
+		string q = HostUrlEncode(text);
+		
+		string salt = "" + HostGetTickCount();//随机数
+		string sign = HostHashMD5(appId + text + salt + toKey);//签名 appid+q+salt+密钥
+		string parames = "from=" + srcLang + "&to=" + dstLang + "&appid=" + appId + "&sign=" + sign  + "&salt=" + salt + "&q=" + q;
+		string url = "http://api.fanyi.baidu.com/api/trans/vip/translate?" + parames;
+
+		//线程同步 - 独占锁
+		acquireExclusiveLock();
+
+		//计算冷却时间,应百度翻译新版API要求,加入频率设定
+		int tickCount = HostGetTickCount();
+		int sleepTime = nextExecuteTime - tickCount;
+
+		// HostPrintUTF8("tickCount == " + tickCount + " sleepTime == " + sleepTime);// for debug
+
+		if(sleepTime > 0){//如果冷却时间还没到,有需要休息的部分
+			HostSleep(sleepTime);//那么就休息这些时间
+		}
+
+		
+		// HostPrintUTF8("url == " + url);// for debug
+		string html = HostUrlGetString(url, userAgent);
+
+		//更新下次执行任务的时间
+		nextExecuteTime = coolTime + HostGetTickCount();//上面 HostUrlGetString 需要时间执行,所以需要重新获取 TickCount
+
+		//线程同步 - 释放独占锁
+		releaseExclusiveLock();
+
+		if(!html.empty()){//如果成功取得 Html 内容
+			ret = JsonParse(html);//那么解析这个 HTML 里面的 json 内容
+		}
+
+		if (ret.length() > 0){//如果有翻译结果
+			srcLang = "UTF8";
+			dstLang = "UTF8";
+		}	
+
+		if(text == ret){//如果翻译后的译文,跟原文一致
+			ret = "";//那么忽略这个字幕
+		}
+	}
+	return ret;
+}
+
+//获取语言
+string GetLang(string &in lang){
+	string result = lang;
+
+	if(result.empty()){//空字符串
+		result = "auto";
+	} else if(result == "zh-CN"){//简体中文
+		result = "zh";
+	} else if(result == "zh-TW"){//繁体中文
+		result = "cht";
+	} else if(result == "ja"){//日语
+		result = "jp";
+	} else if(result == "ro"){//罗马尼亚语
+		result = "rom";
+	}
+
+	return result;
+}
+
+
+array<string> langTable = {
+	"zh-CN",//->zh
+	"zh-TW",//->cht
+	"en",
+	"ja",//->jp
+	"kor",
+	"fra",
+	"spa",
+	"th",
+	"ara",
+	"ru",
+	"pt",
+	"de",
+	"it",
+	"el",
+	"nl",
+	"pl",
+	"bul",
+	"est",
+	"dan",
+	"fin",
+	"cs",
+	"ro",//->rom
+	"slo",
+	"swe",
+	"hu",
+	"vie"
+	"yue",//粤语
+	"wyw",//文言文
+};
+
+//获取支持语言
+array<string>  GetLangTable(){
+	return langTable;
+}
+
+//解析Json数据
+string JsonParse(string json){
+	string ret = "";//返回值
+	JsonReader reader;
+	JsonValue root;
+	
+	if (reader.parse(json, root)){//如果成功解析了json内容
+		if(root.isObject()){//要求是对象模式
+			bool hasError = false;
+			array<string> keys = root.getKeys();//获取json root对象中所有的key
+
+			//查找是否存在错误
+			for(uint i = 0; i < keys.size(); i++){
+				if("error_code" == keys[i]){
+					hasError = true;
+					break;
+				}
+			}
+
+			if(hasError){//如果发生了错误
+				JsonValue errorCode = root["error_code"];//错误编号
+				JsonValue errorMsg = root["error_msg"];//错误信息描述
+				ret = "error: " + errorCode.asString() + ", error_msg=" + errorMsg.asString();
+			}else{//如果没发生错误
+				JsonValue transResult = root["trans_result"];//取得翻译结果
+				if(transResult.isArray()){//如果有翻译结果-必须是数组形式
+					for(int i = 0; i < transResult.size(); i++){
+						JsonValue item = transResult[i];//取得翻译结果
+						JsonValue dst = item["dst"];//获取翻译结果的目标
+						if(i > 0){//如果需要处理多行的情况
+							ret += "\n";//第二行开始的开头位置,加上换行符
+						}
+						ret += dst.asString();//拼接翻译结果,可能存在多行
+					}
+				}
+			}
+		}
+	} 
+	return ret;
+}
+
+/**
+上独占锁 - 当前仅仅只是模拟版,还有 bug ,不过暂时可临时使用
+*/
+void acquireExclusiveLock(){
+	int tickCount1 = HostGetTickCount();//取得第一个时刻
+	HostSleep(1);
+	int tickCount2 = HostGetTickCount();//取得第二个时刻
+	/**
+	注意:
+	1、这是一个临时的方案
+	2、因为我本地尝试:HostLoadLibrary("Kernel32.dll") 没能正常工作,所以才采用当前这个临时方案
+	3、key 原本应该是唯一的,不然可能存在多个线程得到的是同一个tickCount。会导致多个线程同时执行,意味着这多个线程只能成功一个翻译,虽然已经做了部分防御,但是不能确保万一!
+	4、当然,上方的触发的概率不高,不过确实存在这个bug。
+	5、所以当前只能作为临时方案,有更好的方案时,必须替换掉
+	*/
+	int key = tickCount1 << 16 + (tickCount2 & 0xFFFF);//两个时刻合并,使得多线程重复相同数字的概率下降,但还是有可能重复,当前这个算法,仅仅能作为临时的解决方案而已!
+
+	while(executeThreadId != key){
+		if(executeThreadId == NULL){//如果没其他任务在执行了
+			executeThreadId = key;//尝试注册当前任务为执行任务
+		}
+
+		HostSleep(1);//休息下,看看有没有抢着注册的其他线程任务,或者等待正在执行的任务解除锁
+
+		if(executeThreadId == key){//如果没被其他线程抢注册了
+			HostSleep(1);//再次休息下
+			if(executeThreadId == key){//二次确认,确保原子性
+				break;//成功抢到执行权限,不必再等待了
+			}
+		}
+	}
+}
+
+/**
+释放独占锁 - 当前仅仅只是模拟版,还有 bug ,不过暂时可临时使用
+*/
+void releaseExclusiveLock(){
+	executeThreadId = NULL;//解除锁
+}

BIN
baidu/SubtitleTranslate - baidu.ico


+ 91 - 0
baidu/readme.md

@@ -0,0 +1,91 @@
+# 声明:
+
+>1、这个是机器翻译。所以翻译效果肯定不是太好,不要抱太高的期望!
+
+>2、百度翻译在2百万字符,就要收费,所以没法用我个人的AppId和密钥,需要您自己注册一个。
+
+>3、如果是一个人用,个人使用一个月看视频的字幕翻译而已,不至于到2百万字符吧。。。。嗯。大概。建议您可以自己每隔几天去百度翻译后台看看。
+
+>4、我个人使用的环境是:不带字幕的视频+ass外挂字幕+在线翻译这样的结构。推荐也是用这个模式,内嵌字幕可能是硬绘制在视频帧图片里面,那种情况的视频暂时没法翻译。建议先找一个这种格式的,测试集成效果!
+
+>5、我只是源码开源者,只为技术交流,拒绝承担任何责任!
+
+## 第一步:必须开通百度翻译的开发者,并注册一个应用
+
+>1、前往网址:http://api.fanyi.baidu.com/api/trans/product/prodinfo
+
+>2、登录你自己的百度账号
+
+>3、第1的网址打开后点“产品服务”,拉到下面,有个“立即使用”
+
+>4、填写百度翻译要求的必要信息,并完成应用注册,不要填写IP地址,其他的填写啥看你个人喜好咯!
+
+
+## 第二步:安装翻译插件
+
+>1、将SubtitleTranslate - baidu.as、SubtitleTranslate - baidu.ico这两个文件选中,Ctrl+C复制
+
+>2、打开PotPlayer播放器的安装路径(方法不会的请百度、谷歌等等方式搜索)
+
+>3、再进入Extention文件夹,接着又进入Subtitle文件夹、最后进入Translate文件夹
+
+>4、Ctrl+V,把刚才选择的两个文件粘贴到这个文件夹
+
+
+## 第三步:获取和配置翻译插件的 appId 与 密钥
+
+>1、第一步中的1,网址,点击“管理控制台”
+
+>2、我的服务下面一点,如果有“此服务已停用 开启(这两个字蓝色)”的提示,点击“开启”
+
+>3、拉到底部,会有“申请信息”,里面包含 “APP ID” 和 “密钥”
+
+>4、随便打开一个带外挂字幕的视频,例如外挂ass字幕文件的视频!
+
+>5、右键点击视频->字幕->在线字幕翻译->实时字幕翻译设置->选中百度翻译-> 点右边的 “账户设置”,会弹出一个对话框。
+
+>6、将上面第 3 步得到的“APP ID” 和 “密钥”分别填写进去,然后点确定,会再次弹出对话框,点击关闭就行了。
+
+
+## 第四步:测试
+
+>1、随便打开一个带中文字幕的视频(如果上方打开的视频没关闭,不必重新打开)
+
+>2、右键点击视频->字幕->在线字幕翻译->Bai Du translate
+
+>3、右键点击视频->字幕->在线字幕翻译->总是使用(注:这个看个人需求)
+
+>4、右键点击视频->字幕->在线字幕翻译->下面显示翻译(注:这个看个人需求)
+
+>5、右键点击视频->字幕->在线字幕翻译->目标语言->之后在语言列表选择你要的,例如英语,日语、汉语等等任意一个,看个人需求。
+
+>6、畅玩吧
+
+
+## 可选的配置 - 翻译请求的频率
+
+>1、这个配置是可选的,一般不用配置的
+
+>2、原因:百度翻译有默认翻译冷却时间,短时间内多次传输翻译请求,那么很可能会被拦截,如果翻译结果会提示 error:54003……那么就是被拦截了。如果出现这个,那么才有必要做这个配置,否则就不需要这个配置的!
+
+>3、用记事本等文本编辑器打开刚才安装后的SubtitleTranslate - baidu.as这个文件(不是当前这个文本的同一个文件夹里的文件哦,是配置到PolPlayer里面的那个文件!)
+
+>4、修改大概23行位置的 int coolTime = 1000; 数字1000,将它加大一些,然后保存好文件再试试,如果不够就再加大一些,1000是指1秒钟,1000毫秒=1秒,是指一条字幕翻译后,下一条字幕最少需要等多久才开始翻译的意思。请注意不要删除掉这行的最后一个英文的分号
+
+>5、保存文件
+
+>6、如果开着PotPlayer则关闭再重新打开,没开的直接打开就行了,然后就可以试试效果了。
+
+
+## 常见错误
+>如果集成后,翻译结果出现:error: 数字,error_msg:英语,那么根据数字,在下方截图查找原因:
+![QQ20190703-085634](https://user-images.githubusercontent.com/31087168/61015667-2a950100-a3bf-11e9-8d21-4f111260c5fe.png)
+
+
+## 最后:参与扩展
+
+>欢迎广大网友们继续扩展优化,欢迎任何有益的合并请求!
+
+>github发布地址:https://github.com/fjqingyou/PotPlayer_Subtitle_Translate_Baidu
+    
+

+ 4 - 0
baidu/使用方法.txt

@@ -0,0 +1,4 @@
+1、首先,请在跟当前文件的同一个文件夹下,找到 readme.md 文件。
+2、用鼠标点着它不放,然后拖动鼠标到现在您看到文字的这里。接着松开鼠标
+3、之后你会发现,当前这里的内容发生了变化。直接看变化后的内容就好了!
+4、如果之后关闭文件提示保存,点否,如果没提示直接无视本行说明!

+ 18 - 0
tencent/README.md

@@ -0,0 +1,18 @@
+# subtitle-translate-tmt
+
+使用[腾讯机器翻译](https://cloud.tencent.com/product/tmt) API 为 PotPlayer 翻译实时字幕.
+
+## 必要条件
+
+* PotPlayer 版本 >= 1.7.20977
+* [开通腾讯云 机器翻译API](https://console.cloud.tencent.com/tmt)(需实名认证)
+* [创建腾讯云 SecretId & SecretKey](https://console.cloud.tencent.com/cam/capi)
+
+## 安装
+
+1. [下载](https://github.com/BlackGlory/subtitle-translate-tmt/archive/master.zip)
+2. 解压缩
+3. 复制文件 `SubtitleTranslate - tmt.as` 和 `SubtitleTranslate - tmt.ico` 到 `C:\Program Files\DAUM\PotPlayer\Extention\Subtitle\Translate` 文件夹
+4. 运行/重启 PotPlayer
+5. 菜单->字幕->实时字幕翻译->实时字幕翻译设置->腾讯机器翻译->帐户设置, 填写你的 SecretId 和 SecretKey
+6. 配置 PotPlayer 关于实时字幕翻译设置的其他选项, 播放带有字幕文本的视频, 测试效果

+ 277 - 0
tencent/SubtitleTranslate - tmt.as

@@ -0,0 +1,277 @@
+/*
+  real time subtitle translate for PotPlayer using Tencent Machine Translation API
+  https://github.com/BlackGlory/subtitle-translate-tmt
+  https://cloud.tencent.com/product/tmt
+*/
+
+// string GetTitle()                             -> get title for UI
+// string GetVersion                            -> get version for manage
+// string GetDesc()                              -> get detail information
+// string GetLoginTitle()                          -> get title for login dialog
+// string GetLoginDesc()                          -> get desc for login dialog
+// string GetUserText()                            -> get user text for login dialog
+// string GetPasswordText()                          -> get password text for login dialog
+// string ServerLogin(string User, string Pass)                -> login
+// string ServerLogout()                          -> logout
+// array<string> GetSrcLangs()                         -> get source language
+// array<string> GetDstLangs()                         -> get target language
+// string Translate(string Text, string &in SrcLang, string &in DstLang)   -> do translate !!
+
+bool debug = false;
+
+string secretId = '';
+string secretKey = '';
+
+uint secondsOfMinute = 60;
+uint secondsOfHour = 3600;
+uint secondsOfDay = 86400;
+
+// https://cloud.tencent.com/document/api/551/15619
+dictionary DstLangTable = {
+  {'zh', 'zh'} // 中文
+, {'zh-CN', 'zh'} // 简体中文
+, {'zh-TW', 'zh'} // 繁体中文
+, {'en', 'en'} // 英文
+, {'ja', 'jp'} // 日语
+, {'ko', 'kr'} // 韩语
+, {'de', 'de'} // 德语
+, {'fr', 'fr'} // 法语
+, {'es', 'es'} // 西班牙文
+, {'it', 'it'} // 意大利文
+, {'tr', 'tr'} // 土耳其文
+, {'ru', 'ru'} // 俄文
+, {'pt', 'pt'} // 葡萄牙文
+, {'vi', 'vi'} // 越南文
+, {'id', 'id'} // 印度尼西亚文
+, {'ms', 'ms'} // 马来西亚文
+, {'th', 'th' } // 泰文
+};
+
+dictionary SrcLangTable = {
+  {'', 'auto'} // 自动检测
+, {'zh', 'zh'} // 中文
+, {'zh-CN', 'zh'} // 简体中文
+, {'zh-TW', 'zh'} // 繁体中文
+, {'en', 'en'} // 英文
+, {'ja', 'jp'} // 日语
+, {'ko', 'kr'} // 韩语
+, {'de', 'de'} // 德语
+, {'fr', 'fr'} // 法语
+, {'es', 'es'} // 西班牙文
+, {'it', 'it'} // 意大利文
+, {'tr', 'tr'} // 土耳其文
+, {'ru', 'ru'} // 俄文
+, {'pt', 'pt'} // 葡萄牙文
+, {'vi', 'vi'} // 越南文
+, {'id', 'id'} // 印度尼西亚文
+, {'ms', 'ms'} // 马来西亚文
+, {'th', 'th' } // 泰文
+};
+
+uint getTimestamp() {
+  datetime fakeUnix = datetime(1970, 1, 2, 0, 0, 0); // datetime(1970, 1, 1) may an invalid value.
+  datetime now = datetime();
+  uint timestamp = now - fakeUnix;
+  timestamp += secondsOfDay; // patch for fakeUnix.
+  return timestamp;
+}
+
+string createQuerystring(dictionary query) {
+  array<string> keys = query.getKeys();
+  keys.sortAsc();
+  uint length = keys.length();
+  array<string> pairs(length);
+  for (uint i = 0; i < length; i++) {
+    string key = keys[i];
+    string value = string(query[key]);
+    pairs[i] = key + '=' + value;
+  }
+  string querystring = join(pairs, '&');
+  return querystring;
+}
+
+// for debug
+/*
+void printHex(string str) {
+  string hexStr = '';
+  for (uint i = 0; i < str.length(); i++) {
+    hexStr += formatInt(str[i], 'H') + ' ';
+  }
+  HostPrintUTF8(hexStr);
+}
+*/
+
+string createChar(uint bytechar) {
+  string result = '';
+  result.resize(1);
+  result[0] = bytechar;
+  return result;
+}
+
+string repeat(string str, uint times) {
+  string result = '';
+  for (uint i = 0; i < times; i++) {
+    result += str;
+  }
+  return result;
+}
+
+string xorStr(string leftStr, string rightStr) {
+  string result = '';
+  result.resize(leftStr.length());
+  for (uint i = 0, length = leftStr.length(); i < length; i++) {
+    result[i] = leftStr[i] ^ rightStr[i];
+  }
+  return result;
+}
+
+string hex2bin(string hexStr) {
+  uint resultLength = hexStr.length() / 2;
+  string result = '';
+  result.resize(resultLength);
+  for (uint i = 0; i < resultLength; i++) {
+    result[i] = parseInt(hexStr.substr(i * 2, 2), 16);
+  }
+  return result;
+}
+
+string hmacSHA1(string key, string message) {
+  uint blockSize = 64;
+
+  if (key.length() > blockSize) {
+    key = HostHashSHA1(key);
+  }
+
+  if (key.length() < blockSize) {
+    key += repeat(createChar(0x00), blockSize - key.length());
+  }
+
+  string ipadKey = xorStr(repeat(createChar(0x36), blockSize), key);
+  string opadKey = xorStr(repeat(createChar(0x5c), blockSize), key);
+
+  return HostHashSHA1(opadKey + hex2bin(HostHashSHA1(ipadKey + message)));
+}
+
+// https://cloud.tencent.com/document/api/213/15693
+string createSignature(string querystring, string host, string method = 'GET', string path = '/') {
+  return HostBase64Enc(hex2bin(hmacSHA1(secretKey, method + host + path + '?' + querystring)));
+}
+
+JsonValue parseJSON(string json) {
+  JsonReader reader;
+  JsonValue data;
+  reader.parse(json, data);
+  return data;
+}
+
+string replace(string str, string substr, string newSubstr) {
+  array<string> arr = str.split(substr);
+  string result = join(arr, newSubstr);
+  return result;
+}
+
+string GetTitle() {
+  return
+    '{$CP936=腾讯机器翻译$}'
+    '{$CP0=Tencent Machine Translate$}';
+}
+
+string GetVersion() {
+  return '1';
+}
+
+string GetDesc() {
+  return
+    '<a href="https://github.com/BlackGlory/subtitle-translate-tmt">'
+      'Extension Source Code'
+    '</a>'
+    ' '
+    '<a href="https://cloud.tencent.com/product/tmt">'
+      'About TMT'
+    '</a>';
+}
+
+string GetLoginTitle() {
+  return
+    '{$CP936=填写 API 密钥$}'
+    '{$CP0=Input Tencent Cloud API key$}';
+}
+
+string GetLoginDesc() {
+  return 'https://console.cloud.tencent.com/cam/capi';
+}
+
+string GetUserText() {
+  return 'SecretId:';
+}
+
+string GetPasswordText() {
+  return 'SecretKey:';
+}
+
+string ServerLogin(string user, string pass) {
+  if (user.empty() || pass.empty()) {
+    return 'fail';
+  }
+
+  secretId = user;
+  secretKey = pass;
+  return '200 ok';
+}
+
+void ServerLogout() {
+  secretKey = '';
+  secretId = '';
+}
+
+array<string> GetSrcLangs() {
+  array<string> ret = SrcLangTable.getKeys();
+  return ret;
+}
+
+array<string> GetDstLangs() {
+  array<string> ret = DstLangTable.getKeys();
+  return ret;
+}
+
+string Translate(string text, string &in srcLang, string &in dstLang) {
+  if (debug) HostOpenConsole();
+
+  dictionary query = {
+    {'Action', 'TextTranslate'}
+  , {'Version', '2018-03-21'}
+  , {'Region', 'ap-shanghai'}
+  , {'Timestamp', formatInt(getTimestamp())}
+  , {'Nonce', formatInt(HostGetTickCount())}
+  , {'SecretId', secretId}
+  , {'SourceText', text}
+  , {'Source', string(SrcLangTable[srcLang])}
+  , {'Target', string(DstLangTable[dstLang])}
+  , {'ProjectId', formatInt(0)}
+  };
+
+  string signature = createSignature(createQuerystring(query), 'tmt.tencentcloudapi.com');
+  query['SourceText'] = HostUrlEncode(string(query['SourceText']));
+  string querystring = createQuerystring(query);
+  string url = 'https://tmt.tencentcloudapi.com/?' + querystring + '&Signature=' + HostUrlEncode(signature);
+  string json = HostUrlGetString(url);
+  JsonValue data = parseJSON(json);
+
+  if (data.isObject()) {
+    JsonValue response = data['Response'];
+    if (response.isObject()) {
+      JsonValue targetText = response['TargetText'];
+      if (targetText.isString()) {
+        string translatedText = replace(targetText.asString(), '*', '\n');
+        if (debug) HostPrintUTF8(string(SrcLangTable[srcLang]) + '=>' + string(DstLangTable[dstLang]));
+        if (debug) HostPrintUTF8(text + '\n=>\n' + translatedText);
+        srcLang = 'UTF8';
+        dstLang = 'UTF8';
+        return translatedText;
+      }
+      if (debug) HostPrintUTF8(json);
+    }
+  }
+
+  return '';
+}

BIN
tencent/SubtitleTranslate - tmt.ico