有道ai写作,突破免费限制,无限制使用
预览效果
文末提供源码包及apk下载地址有道ai写作python版
import hashlib import time import json import ssl import base64 import uuid from urllib.parse import quote import requests from requests_toolbelt.multipart.encoder import MultipartEncoder from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from sseclient import SSEClient # 生成唯一的用户id yduuid=str(uuid.uuid4()).replace('-','') session = requests.session() lastModified = requests.get('https://fanyi.youdao.com/index.html').headers['last-Modified'] _nlmf = int(time.mktime(time.strptime(lastModified, "%a, %d %b %Y %H:%M:%S GMT"))) session.headers = { 'Referer': 'https://fanyi.youdao.com/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36', } session.get(f'https://rlogs.youdao.com/rlog.php?_npid=fanyiweb&_ncat=pageview&_ncoo=935962676.0432019&_nssn=NULL&_nver=1.2.0&_ntms={time.time()}&_nref=&_nurl=https%3A%2F%2Ffanyi.youdao.com%2Findex.html%23%2F&_nres=1920x1080&_nlmf={_nlmf}&_njve=0&_nchr=utf-8&_nfrg=%2F&/=NULL&screen=1920*1080') # 获取md5加密结果 def get_md5(s,is_hex=True): md5=hashlib.md5() md5.update(s.encode()) if is_hex: return md5.hexdigest() return md5.digest() # AES-128-CBC解密 def decrypt(encrypted_data, key, iv): cipher = AES.new(key, AES.MODE_CBC, iv) decrypted_data = cipher.decrypt(base64.b64decode(encrypted_data)) return decrypted_data.decode('utf-8') def get_token_and_key(): params = { 'product': 'webdict', 'appVersion': '1.0', 'client': 'web', 'mid': '1', 'vendor': 'web', 'screen': '1', 'model': '1', 'imei': '1', 'network': 'wired', 'keyfrom': 'webdict', 'keyid': 'ai-write', 'mysticTime': str(int(time.time()*1000)), 'yduuid': yduuid, } # 参数排序 sorted_params = sorted(params.items(), key=lambda x: x[0]) sorted_params.append(("key","xuiC95RuooxC8Q51UJtdod1plLUhdAmt")) encoded_params = '&'.join([f"{key}={value}" for key, value in sorted_params]) print("encoded_params:::::"+encoded_params) # 获取sign签名 sign=get_md5(encoded_params) params.update({"sign":sign}) params.update({"pointParam":"appVersion,client,imei,keyfrom,keyid,mid,model,mysticTime,network,product,screen,vendor,yduuid,key"}) response = session.get('https://luna-ai.youdao.com/write/ai/web/ktf', params=params, verify=False) print(response.text) #============解密数据=============================== e=response.text.replace("-","+").replace("_","/") key=get_md5("IIS0fzL@zGv1^zO2%NcZiTcM=98WYxdun$CJE1KUKFfEhz&zpEC0fdXfvGqy*N!r",is_hex=False) iv=get_md5("kG_oSxAXx#xjbiOKAkf9915Ko-XclOBP-GSgfo6E9ZB%9WvgcY6Y7dmje!+m5g#d",is_hex=False) s=decrypt(e,key,iv).replace('\x02', '') print("解密数据::::"+s) decode_data=json.loads(json.loads(s)) return decode_data def get_result(query): decode_data=get_token_and_key() params = { 'product': 'webdict', 'appVersion': '1.0', 'client': 'web', 'mid': '1', 'vendor': 'web', 'screen': '1', 'model': '1', 'imei': '1', 'network': 'wired', 'keyfrom': 'webdict', 'keyid': 'ai-write-web', 'mysticTime': str(int(time.time()*1000)), 'yduuid': yduuid, 'functionId':'1', 'query':quote(query), 'userCustomize':quote(query), 'token':decode_data["token"] } # 参数排序 sorted_params = sorted(params.items(), key=lambda x: x[0]) sorted_params.append(("key",decode_data['sk'])) encoded_params = '&'.join([f"{key}={value}" for key, value in sorted_params]) print("encoded_params:::::"+encoded_params) # 获取签名字符串 sign=get_md5(encoded_params) params.update({"sign":sign}) print("签名字符串:"+sign) params.update({"pointParam":"appVersion,client,functionId,imei,keyfrom,keyid,mid,model,mysticTime,network,product,query,screen,token,userCustomize,vendor,yduuid,key"}) # 数据为multipart/form-data格式 multipart_data = MultipartEncoder(fields=params) # 修改请求头中的Content-Type session.headers['Content-Type']= multipart_data.content_type # 发送请求 response = session.post('https://luna-ai.youdao.com/write/ai/template/sse', data=multipart_data, stream=True,verify=False) # 处理SSE流数据 client=SSEClient(response) for event in client.events(): # 判断事件类型 if event.event=='message': # 不换行输出 print(json.loads(event.data)['content'],end='') if __name__=='__main__': keyword=input('请输入关键词:') get_result(keyword) 有道ai写作lua版
使用Aide lua打包为apk
require "import" --import "androidx" --import "androidx.appcompat.app.*" --import "androidx.appcompat.view.*" --import "androidx.appcompat.widget.*" --import "android.app.*" import "android.os.*" import "android.widget.*" import "android.view.*" import "androidx.coordinatorlayout.widget.CoordinatorLayout" local layout={ CoordinatorLayout; layout_height="fill"; layout_width="match_parent"; { LinearLayout; layout_width="match_parent"; orientation="vertical"; layout_height="match_parent"; { LinearLayout; layout_width="match_parent"; orientation="horizontal"; layout_height="wrap_content"; { EditText; layout_marginTop="10"; id="inputText"; hint="请输入关键词"; layout_weight=19; layout_marginLeft="5"; }; { Button; layout_marginTop="10"; id="translateBtn"; text="ai写作"; layout_weight=1; layout_marginRight="5"; }; }; { LinearLayout; layout_width="fill"; layout_height="fill"; { ScrollView; layout_width="fill"; id="1"; layout_height="fill"; { TextView; layout_margin="10"; layout_width="fill"; id="resultView"; layout_height="wrap_content"; }; }; }; }; }; --ui结束 activity.setContentView(loadlayout(layout)) -- 生成时间戳 function getTimestamp() local Date = luajava.bindClass "java.util.Date" return Date().getTime() end -- 字符串url编码 function urlEncode(s) -- url编码 local s = string.gsub(s, "([^%w%.%- ])", function(c) return string.format("%%%02X", string.byte(c)) end) -- 逗号不编码 return s:gsub(" ", "+"):gsub("%%2C",","):gsub("%%25","%%") end -- 字符串序列化 function tableToStr(tbl,sep) local str = '' local sep= sep or '&' for key, value in pairs(tbl) do str = str .. key .. '=' .. urlEncode(value) .. sep end return string.sub(str, 1, -2) end -- 拼接排序后的表为字符串 function tableToStr1(tbl) local str = '' for key, value in ipairs(tbl) do str = str .. value[1] .. '=' .. urlEncode(value[2]) .. '&' end return string.sub(str, 1, -2) end -- md5加密 function md5Encrypt(data,isHex) local MessageDigest = luajava.bindClass "java.security.MessageDigest" local md = MessageDigest.getInstance("MD5") local bytes = md.digest(String(data).getBytes()) local isHex= (isHex==nil) and true or false if isHex ==false then return bytes end local result = "" for i = 0, #bytes - 1 do local temp = string.format("%02x", (bytes[i] & 0xff)) result = result .. temp end return result end -- AES解密 function decrypt(encryptStr, key, iv) local String = luajava.bindClass "java.lang.String" local SecretKeySpec = luajava.bindClass "javax.crypto.spec.SecretKeySpec" local IvParameterSpec = luajava.bindClass "javax.crypto.spec.IvParameterSpec" local Cipher = luajava.bindClass "javax.crypto.Cipher" local Base64 = luajava.bindClass "android.util.Base64" local algorithm = "AES" local mode = "AES/CBC/PKCS5Padding" local raw=SecretKeySpec(key,algorithm) local ivBytes = IvParameterSpec(iv) local cipher = Cipher.getInstance(mode) cipher.init(Cipher.DECRYPT_MODE, raw, ivBytes) local encode_content = Base64.decode(encryptStr, Base64.DEFAULT) local byte_content = cipher.doFinal(encode_content) return String(byte_content, "utf-8") end -- 公共请求参数定义 local base = { Cookies = { ['OUTFOX_SEARCH_USER_ID_NCOO'] = '1536815481.8081024', ['OUTFOX_SEARCH_USER_ID'] = '1773118125@192.168.0.1', }, Headers = { ['Accept'] = 'application/json, text/plain, */*', ['Accept-Language'] = 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', ['Connection'] = 'keep-alive', ['Origin'] = 'https://fanyi.youdao.com', ['Referer'] = 'https://fanyi.youdao.com/', ['Sec-Fetch-Dest'] = 'empty', ['Sec-Fetch-Mode'] = 'cors', ['Sec-Fetch-Site'] = 'same-site', ['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0', ['sec-ch-ua'] = '"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"', ['sec-ch-ua-mobile'] = '?0', ['sec-ch-ua-platform'] = '"Windows"', }, Params = { ['product'] = 'webdict', ['appVersion'] = '1.0', ['client'] = 'web', ['mid'] = '1', ['vendor'] = 'web', ['screen'] = '1', ['model'] = '1', ['imei'] = '1', ['network'] = 'wired', ['keyfrom'] = 'webdict', ['keyid'] = 'ai-write', ['mysticTime'] = '', ['yduuid'] = '', } } -- 生成全局唯一用户id,同一id只有10次免费机会,每次生成不同id即可跳过免费限制 function genUUID() local UUID=luajava.bindClass 'java.util.UUID' return string.gsub(tostring(UUID.randomUUID()),'-','') end --复制表 function copyTable(original) local copy = {} for key, value in pairs(original) do if type(value) == "table" then copy[key] = copyTable(value) -- 递归复制子表 else copy[key] = value end end return copy end -- 获得按键排序后的参数table function getSortedParams(params) local function compare(a, b) return a[1] < b[1] end local sorted_params = {} for key, value in pairs(params) do table.insert(sorted_params, { key, value }) end table.sort(sorted_params, compare) return sorted_params end -- 获取token和key function getTokenAndKey() local JSON=require 'cjson' local url = 'https://luna-ai.youdao.com/write/ai/web/ktf' -- 复制公共表头和参数 local headers = copyTable(base.Headers) local params = copyTable(base.Params) local cookies = tableToStr(base.Cookies,";") -- 设置参数 params['mysticTime']=getTimestamp() -- 生成yduuid base.yduuid=genUUID() params['yduuid']=base.yduuid -- 按照table中键进行排序,并指定排序函数 local sorted_params=getSortedParams(params) local encoded_params = tableToStr1(sorted_params) encoded_params = encoded_params .. "&key=xuiC95RuooxC8Q51UJtdod1plLUhdAmt" print("获取签名字符串"..encoded_params) local sign = md5Encrypt(encoded_params) print("获取签名的sign:"..sign) params['sign'] = sign params['pointParam'] = "appVersion,client,imei,keyfrom,keyid,mid,model,mysticTime,network,product,screen,vendor,yduuid,key" local finalUrl=url..'?'..tableToStr(params) print("请求地址"..finalUrl) -- 发送请求 local httpTask=Http.get(finalUrl,cookies,nil,headers,function () end) local result=httpTask.get() local code,content,cookie,header=result[0],result[1],result[2],result[3] -- 解密数据 local b64str=content:gsub(' ','+'):gsub('-','+'):gsub('_','/') -- des解密 local key=md5Encrypt('IIS0fzL@zGv1^zO2%NcZiTcM=98WYxdun$CJE1KUKFfEhz&zpEC0fdXfvGqy*N!r',false) local iv=md5Encrypt('kG_oSxAXx#xjbiOKAkf9915Ko-XclOBP-GSgfo6E9ZB%9WvgcY6Y7dmje!+m5g#d',false) local s=tostring(decrypt(b64str,key,iv)) s=string.gsub(s,'\x02','') print("token和sign"..s) local decodeData=JSON.decode(JSON.decode(s)) return decodeData['sk'],decodeData['token'] end -- 获取翻译结果 function getResult(query) local JSON=require 'cjson' local url = 'https://luna-ai.youdao.com/write/ai/template/sse' -- 复制公共表头和参数 local headers = copyTable(base.Headers) local params = copyTable(base.Params) -- 获取token和key local key,token=getTokenAndKey() -- 设置参数 params['mysticTime']=getTimestamp() params['yduuid']=base.yduuid params['keyid']='ai-write-web' params['functionId']='1' params['query']=urlEncode(query) params['userCustomize']=urlEncode(query) params['token']=token -- 设置头部 local boundary="jeb3u3g5vh5v3hh2h2hg5g6v7vh4hehdjd" headers['Content-Type']='multipart/form-data;boundary='..boundary headers['Accept']='*/*, text/event-stream' headers["Referer"]="https://fanyi.youdao.com/aiwrite/document" -- 按照table中键进行排序,并指定排序函数 local sorted_params=getSortedParams(params) local encoded_params=tableToStr1(sorted_params) encoded_params = encoded_params .. "&key="..key print('生成签名的参数字符串:::'..encoded_params) local sign = md5Encrypt(encoded_params) params['sign'] = sign print("签名结果:::"..sign) params['pointParam'] = 'appVersion,client,functionId,imei,keyfrom,keyid,mid,model,mysticTime,network,product,query,screen,token,userCustomize,vendor,yduuid,key' -- 处理sse事件流数据 local OkHttpClient=luajava.bindClass 'okhttp3.OkHttpClient' local MultipartBody=luajava.bindClass 'okhttp3.MultipartBody' local Request=luajava.bindClass 'okhttp3.Request' local RealEventSource=luajava.bindClass 'okhttp3.internal.sse.RealEventSource' local EventSource=luajava.bindClass 'okhttp3.sse.EventSource' local EventSourceListener=luajava.bindClass 'okhttp3.sse.EventSourceListener' local TimeUnit=luajava.bindClass 'java.util.concurrent.TimeUnit' local client =OkHttpClient.Builder().connectTimeout(20,TimeUnit.SECONDS).readTimeout(20,TimeUnit.SECONDS).build() local requestBodyBuilder=MultipartBody.Builder().setType(MultipartBody.FORM) --添加请求参数 for k,v in pairs(params) do requestBodyBuilder.addFormDataPart(String(k),String(tostring(v))) end local requestBody=requestBodyBuilder.build() local requestBuilder = Request.Builder().url(url) -- 添加请求头 for k,v in pairs(headers) do requestBuilder.header(String(k),String(tostring(v))) end local request=requestBuilder.post(requestBody).build() -- 事件监听器 local listener=EventSourceListener({ onOpen=function(eventSource,response) print("建立sse链接") print(response) end, onEvent=function(eventSource,id,_type,data) -- 判断事件类型 if _type=="message" then -- 更新ui activity.runOnUiThread(Runnable{ run=function() local result=JSON.decode(data) resultView.append(result["content"]) end }) end end, onFailure=function(eventSource,t,response) print("打开链接失败") end, onClose=function(eventSource) print("连接关闭") end }) local eventSource=RealEventSource(request,listener) --开启事件源连接 eventSource.connect(client) end -- 测试 translateBtn.onClick=function() -- 清空上一次的结果 resultView.setText("") local inputStr=tostring(inputText.getText()) getResult(inputStr) end