--- --- 快速打开翻译,支持百度和有道翻译API --- 有道API需要用户自行申请。 --- Created by sugood(https://github.com/sugood). --- DateTime: 2020/10/23 11:12 --- local chooser = require("hs.chooser") local menubar = hs.menubar.new() local dictHistoryPath= "~/.hammerspoon/data/dictHistory.json" local ydUrl = 'https://openapi.youdao.com/api' local bdUrl = 'https://fanyi-api.baidu.com/api/trans/vip/translate' local bdWeburl = 'https://fanyi.baidu.com/#' local ydWeburl = 'http://youdao.com/w/' local mChooser local searchResult = {} local isFirst = true function truncate(q) if q == nil or q == '' then return '' end local len = SubStringGetTotalIndex(q) if (len <= 20) then return q else return SubStringUTF8(q,1,10)..len..SubStringUTF8(q,len-9) end end function newWebview() local cscreen = hs.screen.mainScreen() local cres = cscreen:fullFrame() sheetView = hs.webview.newBrowser({ x = cres.x+cres.w*0.15/2, y = cres.y+cres.h*0.25/2, w = cres.w*0.85, h = cres.h*0.75 }) sheetView:windowTitle("CheatSheets") sheetView:windowStyle("utility") sheetView:titleVisibility("hidden") sheetView:allowGestures(true) sheetView:allowNewWindows(false) sheetView:allowTextEntry(true) sheetView:closeOnEscape(true) sheetView:bringToFront(false) sheetView:darkMode(true) sheetView:reload(false) sheetView:level(hs.drawing.windowLevels.mainMenu) end -- 右键弹出菜单 local rightClickCallbackFn = function(index) if index and index > 0 then local selectResult = mChooser:selectedRowContents(index) if selectResult == nil or stringIsEmpty(selectResult.text) then return end menubar = hs.menubar.new(false) menubar:setTitle("Hidden Menu") menubar:setMenu( { { title = "查看详情", fn = function() hs.dialog.blockAlert(selectResult.text, selectResult.subText,"确定","","informational") end }, { title = "查看网页", fn = function() sheetView:url(selectResult.webUrl):show() end }, { title = "-" }, { title = "朗读译文", fn = function() speak(selectResult.text) end }, { title = "朗读原文", fn = function() speak(selectResult.subText) end }, }) menubar:popupMenu(hs.mouse.getAbsolutePosition(), true) end end -- 系统发音 function speak(str) speaker = hs.speech.new() speaker:speak(str) end function getBaiduApi(q) headers = {ContentType = "application/x-www-form-urlencoded;charset=utf-8"} salt = tostring(hs.timer.secondsSinceEpoch()*1000) curtime = tostring(os.time()) geturl = "q="..q.."&from=auto&to=auto&appid=".. config[1].baiduAppid .."&salt="..salt.."&sign="..hs.hash.MD5(config[1].baiduAppid ..q..salt..config[1].baiduAppSecret) --print('geturl:'..geturl) hs.http.doAsyncRequest(bdUrl,'POST',geturl,headers,function(code, body, htable) if code ~= 200 then print('get weather error:'..code) return else searchResult = {} results = hs.json.decode(body) print('results:'..hs.inspect(results)) if(results['trans_result']) then item = {} item.text = results['trans_result'][1].dst item.subText = q item.webUrl = bdWeburl..results['from'].."/"..results['to'].."/"..decodeURI(q) table.insert(searchResult,1,item) end mChooser:choices(searchResult) hs.json.write(searchResult,dictHistoryPath, true, true) end end) end function getYoudaoApi(q) headers = {ContentType = "application/x-www-form-urlencoded;charset=utf-8"} salt = tostring(hs.timer.secondsSinceEpoch()*1000) curtime = tostring(os.time()) geturl = "q="..q.."&from=auto&to=auto&signType=v3&curtime="..curtime.."&appKey="..config[1].youdaoAppid.. "&salt="..salt.."&sign="..hs.hash.SHA256(config[1].youdaoAppid..truncate(q)..salt..curtime..config[1].youdaoAppSecret) --print('geturl:'..geturl) hs.http.doAsyncRequest(ydUrl,'POST',geturl,headers,function(code, body, htable) if code ~= 200 then print('get weather error:'..code) return else searchResult = {} results = hs.json.decode(body) --print('results:'..hs.inspect(results)) if(results['web']) then --逆序插入 for i=#results['web'],1,-1 do item = {} item.text = table.concat(results['web'][i].value,", ") item.subText = results['web'][i].key item.webUrl = ydWeburl..decodeURI(item.subText) table.insert(searchResult,1,item) end end if(results['basic']) then if (results['basic']['exam_type']) then item = {} item.text = table.concat(results['basic']['exam_type'],', ') item.subText = q item.webUrl = ydWeburl..decodeURI(item.subText) table.insert(searchResult,1,item) end if (results['basic']['explains']) then for i=#results['basic']['explains'],1,-1 do item = {} item.text = results['basic']['explains'][i] item.subText = q item.webUrl = ydWeburl..decodeURI(item.subText) table.insert(searchResult,1,item) end end end if(results['translation']) then item = {} item.text = table.concat(results['translation']) item.subText = q item.webUrl = ydWeburl..decodeURI(item.subText) table.insert(searchResult,1,item) end mChooser:choices(searchResult) hs.json.write(searchResult,dictHistoryPath, true, true) end end) end -- 粘贴选中的片段 local completionFn = function(result) if result then hs.pasteboard.setContents(result.text) --hs.eventtap.keyStroke({ "cmd" }, "V") print("keywords:"..result.text) end end -- 监听输入框 local queryChangedCallbackFn = function(result) print("changekeywords:"..result) if result and #result > 0 then if config[1].dictEngine == '百度' then getBaiduApi(result) else getYoudaoApi(result) end else if(isFirst) then isFirst = false else searchResult = {} mChooser:choices(searchResult) hs.json.write(searchResult,dictHistoryPath, true, true) end end end function initData() newWebview() -- 选取片段内容(按下快捷键时显示片段列表,点击选中的快捷键将自动粘贴) hs.hotkey.bind(hyperCmd, "F", function () isFirst = true if hs.json.read(dictHistoryPath) ~= nil then searchResult = hs.json.read(dictHistoryPath) end local num = hs.pasteboard.changeCount() hs.eventtap.keyStroke({ "cmd" }, "C") mChooser = chooser.new(completionFn) :choices(searchResult) :queryChangedCallback(queryChangedCallbackFn) :rightClickCallback(rightClickCallbackFn) :searchSubText(true) :show() local numAfter = hs.pasteboard.changeCount() --如果复制成功则自动查询复制的内容,否者只打开翻译界面 if(numAfter > num) then --粘贴选中的文本进行查询 hs.eventtap.keyStroke({ "cmd" }, "V") end end) end initData()