├── 2020-10-25_18-49-20_chrome.png ├── LICENSE ├── README.md ├── img ├── 2020-10-26_11-38-26_chrome.png └── readme.md ├── legacy ├── randomsentencegenerator_v0.6.user.js ├── randomsentencegenerator_v0.7.1.user.js └── randomsentencegenerator_v0.7.user.js └── randomsentencegenerator.user.js /2020-10-25_18-49-20_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c4d0/Dulunche_RandomSentenceGenerator/3f476637911c17d0db03d2412f95f97e1c7a8bd2/2020-10-25_18-49-20_chrome.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 c4d0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dulunche_RandomSentenceGenerator 2 | 3 | 油猴脚本,配合[独轮车](https://greasyfork.org/zh-CN/scripts/412464-youtube%E7%8B%AC%E8%BD%AE%E8%BD%A6-auto-youtube-chat-sender)用 4 | 5 | 随机生成弹药,可以一定程度避免对面sj弹药库 6 | 7 | **根据反馈,有时候窗口加载不出来,可能是因为梯子开了全局导致百度翻译api无法访问,请调整梯子的设置** 8 | 9 | # 安装 10 | 11 | **注意:从0.7版本开始使用了新版独轮车提供的接口,更新时请确保独轮车版本大于等于2.20** 12 | 13 | 从openuserjs.org安装 14 | 15 | - [RandomSentenceGenerator](https://openuserjs.org/scripts/sqrl/RandomSentenceGenerator) 16 | 17 | 或直接从github下载 18 | 19 | - [当前版本 0.7.1](https://github.com/c4d0/Dulunche_RandomSentenceGenerator/raw/main/randomsentencegenerator.user.js) 20 | - [0.7](https://github.com/c4d0/Dulunche_RandomSentenceGenerator/raw/main/legacy/randomsentencegenerator_v0.7.user.js) 21 | - [0.6](https://github.com/c4d0/Dulunche_RandomSentenceGenerator/raw/main/legacy/randomsentencegenerator_v0.6.user.js) 22 | 23 | # 原理 24 | 25 | 从一个[中文词库](https://gist.github.com/c4d0/47b712b20ac1f85724048d500909d1cc)里面随机选出词语组合成句子,再白嫖百度翻译的api反复翻译,就能把语法理顺。 26 | 27 | 通过随机插入给定词语,可以让生成的结果和给定的主题相关,乍一看很有道理但是实际上狗屁不通(手动ac娘表情) 28 | 29 | # 使用方法 30 | 31 | 打开youtube,等加载完词库即可看到界面,shift+r可以切换界面显示 32 | 33 | - 主题:会随机插入到生成的文本中。多个词用空格隔开 34 | - 翻译顺序:百度翻译的语言代码。例如:zh=简中 jp=日语 de=德语 ru=俄语 fra=法语 kor=韩语。空格隔开,生成时会从原文开始,按照这个顺序依次翻译得出结果 35 | - 敏感词:翻译完成后会从文本里删去这些词,避免触发敏感词封禁。正则表达式,忽略大小写 36 | - 一次生成条数、每条长度:不解释 37 | - 语气增强:随机插入问号和感叹号 38 | - 逻辑增强:随机插入逻辑连接词 39 | - 自动装填:生成后自动填入独轮车(如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中) 40 | - 动态装填:开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药(适合长时间全自动挂机,如果用手动穿甲的话则没必要开) 41 | 42 | 43 | ![scr1](https://github.com/c4d0/Dulunche_RandomSentenceGenerator/raw/main/img/2020-10-26_11-38-26_chrome.png) 44 | 45 | 放一张增强全开的生成结果图 46 | 47 | ![scr1](https://github.com/c4d0/Dulunche_RandomSentenceGenerator/raw/main/2020-10-25_18-49-20_chrome.png) 48 | 49 | # 二次开发 50 | 51 | 一些操作已经注入到了全局变量中,可以直接控制台调用。 52 | ``` js 53 | //异步函数要拿返回值的话记得用await 54 | laji_GenerateAndTranslate() //相当于点击生成按钮 55 | laji_OpenDeepl() //相当于点击打开deepl按钮 56 | laji_baiduFanyiTranslateAsync(text, from, to) //百度翻译文字 57 | laji_baiduFanyiDetectLangAsync(text) //百度检测文字语言 58 | laji_cxhrAsync(url, method, dataString) //跨域请求 59 | ``` 60 | 61 | 示例:定时每60秒重新生成 62 | ``` js 63 | var id = setInterval(() => laji_GenerateAndTranslate(), 60 * 1000); 64 | //如果要停止定时器,输入 clearInterval(id); 65 | ``` 66 | 67 | # Changelog 68 | 69 | ## v0.7.1 70 | - 更改快捷键为alt+shift+R,防止误触 71 | 72 | ## v0.7 73 | - 优化ui 74 | - 增加了动态装填,可以全自动挂机 75 | - 优化了语气增强的插入位置,避免打破句子的连续性 76 | 77 | ## v0.6 78 | - 优化ui 79 | - 增加了语气增强和逻辑增强 80 | 81 | -------------------------------------------------------------------------------- /img/2020-10-26_11-38-26_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c4d0/Dulunche_RandomSentenceGenerator/3f476637911c17d0db03d2412f95f97e1c7a8bd2/img/2020-10-26_11-38-26_chrome.png -------------------------------------------------------------------------------- /img/readme.md: -------------------------------------------------------------------------------- 1 | 放图片 2 | -------------------------------------------------------------------------------- /legacy/randomsentencegenerator_v0.6.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RandomSentenceGenerator 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.6 5 | // @description generates random sentence, helps you come up with good ideas. 6 | // @author sqrl 7 | // @license MIT 8 | // @match *://www.youtube.com/* 9 | // @grant GM_xmlhttpRequest 10 | // @grant GM_setValue 11 | // @grant GM_getValue 12 | // ==/UserScript== 13 | 14 | (async function() { 15 | 'use strict'; 16 | if (window.top !== window.self) throw new Error('非顶层框架'); 17 | 18 | let isBusy = false; 19 | let wordsChinese = []; 20 | let wordsTone = ['!', '?']; 21 | let wordsLogic = ['虽然', '但是', '因为', '所以', '如果']; 22 | 23 | let ui = { 24 | saveInput : function (){ 25 | for (var i = 0; i < this.config.length; i++){ 26 | var cfg = this.config[i]; 27 | if (cfg.name != null && cfg.tag == 'input'){ 28 | switch (cfg.properties.type){ 29 | case 'checkbox': 30 | GM_setValue(cfg.storage, this.elem[cfg.name].checked); 31 | break; 32 | default: 33 | GM_setValue(cfg.storage, this.elem[cfg.name].value); 34 | break; 35 | } 36 | } 37 | } 38 | }, 39 | loadInput : function (){ 40 | for (var i = 0; i < this.config.length; i++){ 41 | var cfg = this.config[i]; 42 | if (cfg.name != null && cfg.tag == 'input'){ 43 | var loaded = null; 44 | switch (cfg.properties.type){ 45 | case 'checkbox': 46 | loaded = GM_getValue(cfg.storage); 47 | this.elem[cfg.name].checked = loaded == null ? cfg.def : loaded; 48 | break; 49 | default: 50 | loaded = GM_getValue(cfg.storage); 51 | this.elem[cfg.name].value = loaded == null ? cfg.def : loaded; 52 | break; 53 | } 54 | } 55 | } 56 | }, 57 | initialize : function(root, config){ 58 | this.config = config; 59 | for (var i = 0; i < config.length; i++){ 60 | var cfg = config[i]; 61 | var ele = document.createElement(cfg.tag); 62 | if (cfg.name != null) this.elem[cfg.name] = ele; 63 | if (cfg.properties != null){ 64 | for (var k in cfg.properties){ 65 | switch(k){ 66 | case 'style': 67 | for (var styleKey in cfg.properties.style){ 68 | ele.style[styleKey] = cfg.properties.style[styleKey]; 69 | } 70 | break; 71 | default: 72 | ele[k] = cfg.properties[k]; 73 | break; 74 | } 75 | } 76 | } 77 | root.appendChild(ele); 78 | } 79 | }, 80 | elem : { } 81 | }; 82 | let uiConfig = [ 83 | { 84 | tag : 'span', 85 | properties : { 86 | innerHTML : '垃圾话生成器(shift+R隐藏/显示界面)' 87 | } 88 | }, 89 | { tag : 'br' }, 90 | { 91 | tag : 'span', 92 | properties : { 93 | innerHTML : '鼠标悬停可以查看输入提示 ' 94 | } 95 | }, 96 | { 97 | tag : 'a', 98 | properties : { 99 | href : 'https://github.com/c4d0/Dulunche_RandomSentenceGenerator', 100 | target : '_blank', 101 | innerHTML : '打开github' 102 | } 103 | }, 104 | { tag : 'br' }, 105 | { 106 | tag : 'span', 107 | properties : { 108 | innerHTML : '主题:' 109 | } 110 | }, 111 | { 112 | tag : 'input', 113 | name : 'insertWordBox', 114 | storage : 'insertWordBox', 115 | def : '垃圾 coco', 116 | properties : { 117 | type : 'text', 118 | id : 'laji_insertWordBox', 119 | title : '会随机插入到生成的文本中。多个词用空格隔开' 120 | } 121 | }, 122 | { tag : 'br' }, 123 | { 124 | tag : 'span', 125 | properties : { 126 | innerHTML : '翻译顺序:' 127 | } 128 | }, 129 | { 130 | tag : 'input', 131 | name : 'translationOrderBox', 132 | storage : 'translationOrderBox', 133 | def : 'zh jp zh jp en', 134 | properties : { 135 | type : 'text', 136 | id : 'laji_translationOrderBox', 137 | title : '百度翻译的语言代码。例如:zh=简中 jp=日语 de=德语 ru=俄语 fra=法语 kor=韩语。\n空格隔开,生成时会从原文开始,按照这个顺序依次翻译得出结果' 138 | } 139 | }, 140 | { tag : 'br' }, 141 | { 142 | tag : 'span', 143 | properties : { 144 | innerHTML : '敏感词:' 145 | } 146 | }, 147 | { 148 | tag : 'input', 149 | name : 'banWordBox', 150 | storage : 'banWordBox', 151 | def : 'bot report taiwan pizza', 152 | properties : { 153 | type : 'text', 154 | id : 'laji_banWordBox', 155 | title : '翻译完成后会从文本里删去这些词,避免触发敏感词封禁。正则表达式,忽略大小写' 156 | } 157 | }, 158 | { tag : 'br' }, 159 | { 160 | tag : 'span', 161 | properties : { 162 | innerHTML : '一次生成条数:' 163 | } 164 | }, 165 | { 166 | tag : 'input', 167 | name : 'lineNumBox', 168 | storage : 'lineNumBox', 169 | def : '20', 170 | properties : { 171 | type : 'text', 172 | id : 'laji_lineNumBox', 173 | style : { 174 | 'width' : '50px' 175 | } 176 | } 177 | }, 178 | { tag : 'br' }, 179 | { 180 | tag : 'span', 181 | properties : { 182 | innerHTML : '每条中文词数:' 183 | } 184 | }, 185 | { 186 | tag : 'input', 187 | name : 'wordNumBox', 188 | storage : 'wordNumBox', 189 | def : '10', 190 | properties : { 191 | type : 'text', 192 | id : 'laji_wordNumBox', 193 | style : { 194 | 'width' : '50px' 195 | } 196 | } 197 | }, 198 | { tag : 'br' }, 199 | { 200 | tag : 'span', 201 | properties : { 202 | innerHTML : '语气增强', 203 | title : '随机插入问号和感叹号' 204 | } 205 | }, 206 | { 207 | tag : 'input', 208 | name : 'enhanceTone', 209 | storage : 'enhanceTone', 210 | def : false, 211 | properties : { 212 | type : 'checkbox', 213 | id : 'laji_enhanceTone', 214 | title : '随机插入问号和感叹号' 215 | } 216 | }, 217 | { tag : 'br' }, 218 | { 219 | tag : 'span', 220 | properties : { 221 | innerHTML : '逻辑增强', 222 | title : '随机插入逻辑连接词' 223 | } 224 | }, 225 | { 226 | tag : 'input', 227 | name : 'enhanceLogic', 228 | storage : 'enhanceLogic', 229 | def : false, 230 | properties : { 231 | type : 'checkbox', 232 | id : 'laji_enhanceLogic', 233 | title : '随机插入逻辑连接词' 234 | } 235 | }, 236 | { tag : 'br' }, 237 | { 238 | tag : 'span', 239 | properties : { 240 | innerHTML : '自动装填', 241 | title : '生成后自动填入独轮车' 242 | } 243 | }, 244 | { 245 | tag : 'input', 246 | name : 'autoDLC', 247 | storage : 'autoDLC', 248 | def : false, 249 | properties : { 250 | type : 'checkbox', 251 | id : 'laji_banWordBox', 252 | title : '生成后自动填入独轮车' 253 | } 254 | }, 255 | { tag : 'br' }, 256 | { 257 | tag : 'button', 258 | name : 'generateButton', 259 | properties : { 260 | innerHTML : '开始生成', 261 | id : 'laji_generateButton', 262 | title : '生成随机中文+多次翻译', 263 | onclick : async e=>{ 264 | if (isBusy) return; 265 | isBusy = true; 266 | ui.saveInput(); 267 | var original = ui.elem.generateButton.innerHTML; 268 | ui.elem.generateButton.innerHTML = '...'; 269 | var numLines = Number(ui.elem.lineNumBox.value); 270 | var numWords = Number(ui.elem.wordNumBox.value); 271 | if (isNaN(numLines)) numLines = 20; 272 | if (isNaN(numWords)) numLines = 10; 273 | await asyncGenerate(numLines, numWords); 274 | await asyncTranslate(); 275 | //fill DLC 276 | if (ui.elem.autoDLC.checked) { 277 | if (document.getElementsByClassName('dlc-cmd')[0] != null){ 278 | var dlcTextbox = document.getElementsByClassName('dlc-cmd')[0].lastElementChild.firstElementChild.firstElementChild.firstElementChild; 279 | dlcTextbox.value = ui.elem.resultText.value; 280 | dlcTextbox.dispatchEvent(new InputEvent('change')); 281 | } 282 | } 283 | ui.elem.generateButton.innerHTML = original; 284 | isBusy = false; 285 | } 286 | } 287 | }, 288 | { 289 | tag : 'button', 290 | name : 'deeplButton', 291 | properties : { 292 | innerHTML : '用deepl打开', 293 | id : 'laji_deeplButton', 294 | title : '在新窗口中用deepl打开当前文本框的内容', 295 | onclick : async e=>{ 296 | openDeepl(ui.elem.resultText.value); 297 | } 298 | } 299 | }, 300 | { tag : 'br' }, 301 | { 302 | tag : 'textarea', 303 | name : 'resultText', 304 | properties : { 305 | id : 'laji_resultText', 306 | cols : 40, 307 | rows : 8, 308 | style : { 309 | 'min-width' : '180px', 310 | 'min-height' : '50px' 311 | } 312 | } 313 | } 314 | ]; 315 | 316 | function cxhrAsync(url, method, dataStr){ 317 | return new Promise(resolve => { 318 | GM_xmlhttpRequest({ 319 | method: method, 320 | url: url, 321 | data: dataStr, 322 | headers: { 323 | "Content-Type": "application/x-www-form-urlencoded" 324 | }, 325 | onload: function(res){ 326 | if(res.status === 200){ 327 | //console.log(res.responseText); 328 | resolve(res.responseText); 329 | }else{ 330 | console.log('error'); 331 | console.log(res); 332 | resolve(null); 333 | } 334 | }, 335 | onerror : function(err){ 336 | console.log('error'); 337 | console.log(err); 338 | resolve(null); 339 | } 340 | }); 341 | }); 342 | } 343 | 344 | let tokenReg = new RegExp("token:\\s'(\\S{32})'"); 345 | let gtkReg = new RegExp("window.gtk\\s=\\s'(\\d{6}.\\d{9})';"); 346 | let baiduFanyi = { 347 | currentToken : null, 348 | currentGtk : null, 349 | initialize : async function(){ 350 | let page = await cxhrAsync('https://fanyi.baidu.com/', 'get', ''); 351 | this.currentToken = tokenReg.exec(page)[1]; 352 | this.currentGtk = gtkReg.exec(page)[1]; 353 | }, 354 | getSign : function(content){ 355 | function a(r, o) { 356 | for (var t = 0; t < o.length - 2; t += 3) { 357 | var a = o.charAt(t + 2); 358 | a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a), 359 | a = "+" === o.charAt(t + 1) ? r >>> a: r << a, 360 | r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a 361 | } 362 | return r 363 | } 364 | var C = null; 365 | var token = function(r, _gtk) { 366 | var o = r.length; 367 | o > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(o / 2) - 5, 10) + r.substring(r.length, r.length - 10)); 368 | var t; 369 | t = void 0, 370 | t = null !== C ? C: (C = _gtk || "") || ""; 371 | for (var e = t.split("."), h = Number(e[0]) || 0, i = Number(e[1]) || 0, d = [], f = 0, g = 0; g < r.length; g++) { 372 | var m = r.charCodeAt(g); 373 | 128 > m ? d[f++] = m: (2048 > m ? d[f++] = m >> 6 | 192 : (55296 === (64512 & m) && g + 1 < r.length && 56320 === (64512 & r.charCodeAt(g + 1)) ? (m = 65536 + ((1023 & m) << 10) + (1023 & r.charCodeAt(++g)), d[f++] = m >> 18 | 240, d[f++] = m >> 12 & 63 | 128) : d[f++] = m >> 12 | 224, d[f++] = m >> 6 & 63 | 128), d[f++] = 63 & m | 128) 374 | } 375 | for (var S = h, 376 | u = "+-a^+6", 377 | l = "+-3^+b+-f", 378 | s = 0; s < d.length; s++) S += d[s], 379 | S = a(S, u); 380 | 381 | return S = a(S, l), 382 | S ^= i, 383 | 0 > S && (S = (2147483647 & S) + 2147483648), 384 | S %= 1e6, 385 | S.toString() + "." + (S ^ h) 386 | } 387 | return token(content, this.currentGtk); 388 | }, 389 | translate : async function (content, from, to){ 390 | let sign = this.getSign(content); 391 | var textres = await cxhrAsync(`https://fanyi.baidu.com/v2transapi?from=${from}&to=${to}`, 392 | 'post', `from=${from}&to=${to}&query=${encodeURIComponent(content)}&transtype=realtime&simple_means_flag=3&sign=${sign}&token=${this.currentToken}&domain=common`); 393 | //console.log(textres); 394 | var obj = eval(`(${textres})`); 395 | //console.log(obj); 396 | var resstr = ''; 397 | obj.trans_result.data.forEach(line => resstr += line.dst + '\n'); 398 | return resstr; 399 | }, 400 | getLang : async function (content){ 401 | var textres = await cxhrAsync('https://fanyi.baidu.com/langdetect', 'post', 'query=' + encodeURIComponent(content)); 402 | var obj = eval(`(${textres})`); 403 | return obj.lan; 404 | }, 405 | } 406 | 407 | let asyncGenerate = async (numLines, numWords) => { 408 | var insertWords = ui.elem.insertWordBox.value.split(' '); 409 | ui.elem.resultText.value = ''; 410 | for (var i = 0; i < numLines; i++){ 411 | var trashArr = randomFromWordList(wordsChinese, numWords); 412 | var j; 413 | for (j = 0; j < insertWords.length; j++){ 414 | if (Math.random() > 1 - 0.02**(1.0 / insertWords.length)) continue; 415 | var insertPosition = randomInt(0, trashArr.length + 1); 416 | trashArr.splice(insertPosition, 0, insertWords[j]); 417 | } 418 | if (ui.elem.enhanceTone.checked){ 419 | var toneArr = randomFromWordList(wordsTone, randomInt(1, 3)); 420 | for (j = 0; j < toneArr.length; j++){ 421 | var insertPosition = randomInt(trashArr.length / 2, trashArr.length + 1); 422 | trashArr.splice(insertPosition, 0, toneArr[j]); 423 | } 424 | } 425 | if (ui.elem.enhanceLogic.checked){ 426 | var logicArr = randomFromWordList(wordsLogic, randomInt(1, 3)); 427 | for (j = 0; j < logicArr.length; j++){ 428 | var insertPosition = randomInt(0, trashArr.length / 2); 429 | trashArr.splice(insertPosition, 0, logicArr[j]); 430 | } 431 | } 432 | trashArr.forEach(trash => ui.elem.resultText.value += trash); 433 | ui.elem.resultText.value += '\n'; 434 | } 435 | console.log(ui.elem.resultText.value); 436 | } 437 | 438 | let asyncTranslate = async () => { 439 | var translations = ui.elem.translationOrderBox.value.split(' '); 440 | while (translations.length > 0) { 441 | var thisLang = await baiduFanyi.getLang(ui.elem.resultText.value); 442 | var nextLang = translations.shift(); 443 | if (thisLang == nextLang) continue; 444 | console.log(`translating: ${thisLang} to ${nextLang}`); 445 | var translated = await baiduFanyi.translate(ui.elem.resultText.value, thisLang, nextLang); 446 | console.log(translated); 447 | ui.elem.resultText.value = translated; 448 | } 449 | var banWords = ui.elem.banWordBox.value.split(' '); 450 | for (var i = 0; i < banWords.length; i++){ 451 | //去除不允许的词 暂且这么处理 452 | ui.elem.resultText.value = ui.elem.resultText.value.replaceAll(new RegExp(banWords[i], 'gi'), ''); 453 | } 454 | } 455 | 456 | 457 | //jump to deepl 458 | function openDeepl(content){ 459 | window.open('https://www.deepl.com/en/translator#zh/en/' + encodeURIComponent(content)); 460 | } 461 | 462 | async function getWordList(url){ 463 | let raw = await cxhrAsync(url, 'get', ''); 464 | return raw.split('\n'); 465 | } 466 | 467 | function randomInt(from, to){ 468 | return Math.floor(Math.random() * (to - from) + from); 469 | } 470 | 471 | function randomFromWordList(wordList, numWords){ 472 | var res = []; 473 | for (var i = 0; i < numWords; i++){ 474 | res.push(wordList[Math.floor(Math.random()**2 * wordList.length)]); 475 | } 476 | return res; 477 | } 478 | 479 | let insertScript = function(script){ 480 | //console.log(script); 481 | var scriptElem = document.createElement('script'); 482 | scriptElem.innerHTML = script; 483 | document.body.appendChild(scriptElem); 484 | } 485 | 486 | let insertFunction = function(globalName, params, func){ 487 | var eventName = globalName + '_userevent'; 488 | document.addEventListener(eventName, async e => { 489 | //console.log(e); 490 | var promise = func.apply(window, e.params); 491 | e.resolve(await promise); 492 | }); 493 | insertScript(` 494 | var ${globalName} = function(${params}){ 495 | return new Promise(resolve =>{ 496 | var event = document.createEvent('HTMLEvents'); 497 | event.initEvent('${eventName}', true, true); 498 | event.params = Array.from(arguments); 499 | event.resolve = resolve; 500 | document.dispatchEvent(event); 501 | }); 502 | } 503 | `); 504 | } 505 | 506 | insertFunction('laji_baiduFanyiTranslateAsync', 'text, from, to', async(content, from, to) => await baiduFanyi.translate(content, from, to)); 507 | insertFunction('laji_baiduFanyiDetectLangAsync', 'text', async(content) => await baiduFanyi.getLang(content)); 508 | insertFunction('laji_cxhrAsync', 'url, method, dataString', cxhrAsync) 509 | insertFunction('laji_GenerateAndTranslate', '', () => ui.elem.generateButton.click()); 510 | insertFunction('laji_OpenDeepl', '', () => ui.elem.deeplButton.click()); 511 | 512 | 513 | //load wordlist 514 | console.log('get wordlist'); 515 | //wordsEnglish = await getWordList('https://github.com/first20hours/google-10000-english/raw/master/google-10000-english-no-swears.txt'); 516 | wordsChinese = await getWordList('https://gist.github.com/c4d0/47b712b20ac1f85724048d500909d1cc/raw/904236c3c1fecf348b9757b7d705ac9ba40bf655/chinese_10000words'); 517 | 518 | //badduFanyi 519 | console.log('get fanyi token'); 520 | await baiduFanyi.initialize(); 521 | setInterval(() => baiduFanyi.initialize(), 600 * 1000);//10分钟重新获取token 522 | //test fanyi functionality 523 | var testres2 = await baiduFanyi.translate('啊这', 'zh', 'en'); 524 | console.log('翻译测试 啊这->' + testres2); 525 | 526 | 527 | //setup ui 528 | console.log('setup ui'); 529 | let smallWindow = document.createElement('div'); 530 | smallWindow.id = 'laji_root'; 531 | smallWindow.style['position'] = 'fixed'; 532 | smallWindow.style['left'] = '0'; 533 | smallWindow.style['top'] = '0'; 534 | //smallWindow.style['width'] = '200px'; 535 | //smallWindow.style['height'] = '100px'; 536 | smallWindow.style['background-color'] = '#fff'; 537 | smallWindow.style['border-width'] = '2px'; 538 | smallWindow.style['border-style'] = 'solid'; 539 | smallWindow.style['border-color'] = '#888'; 540 | smallWindow.style['z-index'] = '100000'; 541 | smallWindow.style['display'] = 'none'; 542 | smallWindow.style['user-select'] = 'none'; 543 | ui.initialize(smallWindow, uiConfig); 544 | ui.loadInput(); 545 | document.body.appendChild(smallWindow); 546 | console.log('ui loaded'); 547 | console.log(ui); 548 | 549 | 550 | 551 | //drag window 552 | var startX = 0, startY = 0; 553 | var currentX = 0, currentY = 0; 554 | var isMouseDown = false; 555 | smallWindow.addEventListener('mousedown', e =>{ 556 | if (e.target.tagName == "TEXTAREA" || e.target.tagName == "BUTTON" || e.target.tagName == "INPUT") return; 557 | startX = e.pageX; 558 | startY = e.pageY; 559 | isMouseDown = true; 560 | }); 561 | document.addEventListener('mousemove', e =>{ 562 | if (!isMouseDown) return; 563 | currentX += e.pageX - startX; 564 | currentY += e.pageY - startY; 565 | startX = e.pageX; 566 | startY = e.pageY; 567 | smallWindow.style['left'] = currentX + 'px'; 568 | smallWindow.style['top'] = currentY + 'px'; 569 | 570 | }); 571 | document.addEventListener('mouseup', e =>{ 572 | isMouseDown = false; 573 | }); 574 | 575 | //hotkey 576 | document.addEventListener('keydown', e =>{ 577 | if (e.key == 'R'){ 578 | smallWindow.style['display'] = smallWindow.style['display'] == 'none' ? '' : 'none'; 579 | } 580 | }); 581 | 582 | smallWindow.style['display'] = ''; 583 | 584 | })(); 585 | -------------------------------------------------------------------------------- /legacy/randomsentencegenerator_v0.7.1.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RandomSentenceGenerator 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.7.1 5 | // @description generates random sentence, helps you come up with good ideas. 6 | // @author sqrl 7 | // @license MIT 8 | // @match *://www.youtube.com/* 9 | // @grant GM_xmlhttpRequest 10 | // @grant GM_setValue 11 | // @grant GM_getValue 12 | // ==/UserScript== 13 | 14 | 15 | //要求独轮车版本 >= 2.20 16 | 17 | (async function() { 18 | 19 | if (window.top !== window.self) throw new Error('非顶层框架'); 20 | 21 | let isBusy = false; 22 | let wordsChinese = []; 23 | let wordsTone = ['!', '?']; 24 | let wordsLogic = ['虽然', '但是', '因为', '所以', '如果']; 25 | let dlcIsRunning = false; 26 | let dulunche = null; 27 | let translators = {}; //字典,key为标识符,value为translator对象 28 | 29 | let ui = { 30 | saveInput : function (){ 31 | for (let i = 0; i < this.config.length; i++){ 32 | let cfg = this.config[i]; 33 | if (cfg.name != null && cfg.tag == 'input'){ 34 | switch (cfg.properties.type){ 35 | case 'checkbox': 36 | GM_setValue(cfg.storage, this.elem[cfg.name].checked); 37 | break; 38 | default: 39 | GM_setValue(cfg.storage, this.elem[cfg.name].value); 40 | break; 41 | } 42 | } 43 | } 44 | }, 45 | loadInput : function (){ 46 | for (let i = 0; i < this.config.length; i++){ 47 | let cfg = this.config[i]; 48 | if (cfg.name != null && cfg.tag == 'input'){ 49 | let loaded = null; 50 | switch (cfg.properties.type){ 51 | case 'checkbox': 52 | loaded = GM_getValue(cfg.storage); 53 | this.elem[cfg.name].checked = loaded == null ? cfg.def : loaded; 54 | break; 55 | default: 56 | loaded = GM_getValue(cfg.storage); 57 | this.elem[cfg.name].value = loaded == null ? cfg.def : loaded; 58 | break; 59 | } 60 | this.elem[cfg.name].dispatchEvent(new InputEvent('change')); 61 | } 62 | } 63 | }, 64 | initialize : function(root, config){ 65 | this.config = config; 66 | for (let i = 0; i < config.length; i++){ 67 | let cfg = config[i]; 68 | let ele = document.createElement(cfg.tag); 69 | if (cfg.name != null) this.elem[cfg.name] = ele; 70 | if (cfg.properties != null){ 71 | for (let k in cfg.properties){ 72 | switch(k){ 73 | case 'style': 74 | for (let styleKey in cfg.properties.style){ 75 | ele.style[styleKey] = cfg.properties.style[styleKey]; 76 | } 77 | break; 78 | default: 79 | ele[k] = cfg.properties[k]; 80 | break; 81 | } 82 | } 83 | } 84 | root.appendChild(ele); 85 | } 86 | }, 87 | elem : { } 88 | }; 89 | let uiConfig = [ 90 | { 91 | tag : 'span', 92 | properties : { 93 | innerHTML : '垃圾话生成器 0.7.1(alt+shift+R隐藏/显示界面)' 94 | } 95 | }, 96 | { tag : 'br' }, 97 | { 98 | tag : 'span', 99 | properties : { 100 | innerHTML : '鼠标悬停可以查看输入提示 ' 101 | } 102 | }, 103 | { 104 | tag : 'a', 105 | properties : { 106 | href : 'https://github.com/c4d0/Dulunche_RandomSentenceGenerator', 107 | target : '_blank', 108 | innerHTML : '打开github' 109 | } 110 | }, 111 | { tag : 'br' }, 112 | { 113 | tag : 'span', 114 | properties : { 115 | innerHTML : '主题:' 116 | } 117 | }, 118 | { 119 | tag : 'input', 120 | name : 'insertWordBox', 121 | storage : 'insertWordBox', 122 | def : '垃圾 coco', 123 | properties : { 124 | type : 'text', 125 | id : 'laji_insertWordBox', 126 | title : '会随机插入到生成的文本中。多个词用空格隔开' 127 | } 128 | }, 129 | { tag : 'br' }, 130 | { 131 | tag : 'span', 132 | properties : { 133 | innerHTML : '翻译顺序:' 134 | } 135 | }, 136 | { 137 | tag : 'input', 138 | name : 'translationOrderBox', 139 | storage : 'translationOrderBox', 140 | def : 'zh jp zh jp en', 141 | properties : { 142 | type : 'text', 143 | id : 'laji_translationOrderBox', 144 | title : '百度翻译的语言代码。例如:zh=简中 jp=日语 de=德语 ru=俄语 fra=法语 kor=韩语。\n空格隔开,生成时会从原文开始,按照这个顺序依次翻译得出结果' 145 | } 146 | }, 147 | { tag : 'br' }, 148 | { 149 | tag : 'span', 150 | properties : { 151 | innerHTML : '敏感词:' 152 | } 153 | }, 154 | { 155 | tag : 'input', 156 | name : 'banWordBox', 157 | storage : 'banWordBox', 158 | def : 'bot report taiwan pizza', 159 | properties : { 160 | type : 'text', 161 | id : 'laji_banWordBox', 162 | title : '翻译完成后会从文本里删去这些词,避免触发敏感词封禁。正则表达式,忽略大小写' 163 | } 164 | }, 165 | { tag : 'br' }, 166 | { 167 | tag : 'span', 168 | properties : { 169 | innerHTML : '一次生成条数:' 170 | } 171 | }, 172 | { 173 | tag : 'input', 174 | name : 'lineNumBox', 175 | storage : 'lineNumBox', 176 | def : '20', 177 | properties : { 178 | type : 'text', 179 | id : 'laji_lineNumBox', 180 | style : { 181 | 'width' : '50px' 182 | } 183 | } 184 | }, 185 | { tag : 'br' }, 186 | { 187 | tag : 'span', 188 | properties : { 189 | innerHTML : '每条中文词数:' 190 | } 191 | }, 192 | { 193 | tag : 'input', 194 | name : 'wordNumBox', 195 | storage : 'wordNumBox', 196 | def : '10', 197 | properties : { 198 | type : 'text', 199 | id : 'laji_wordNumBox', 200 | style : { 201 | 'width' : '50px' 202 | } 203 | } 204 | }, 205 | { tag : 'br' }, 206 | { 207 | tag : 'span', 208 | properties : { 209 | innerHTML : '语气增强', 210 | title : '随机插入问号和感叹号' 211 | } 212 | }, 213 | { 214 | tag : 'input', 215 | name : 'enhanceTone', 216 | storage : 'enhanceTone', 217 | def : false, 218 | properties : { 219 | type : 'checkbox', 220 | id : 'laji_enhanceTone', 221 | title : '随机插入问号和感叹号' 222 | } 223 | }, 224 | { 225 | tag : 'span', 226 | properties : { 227 | innerHTML : '  ' 228 | } 229 | }, 230 | { 231 | tag : 'span', 232 | properties : { 233 | innerHTML : '逻辑增强', 234 | title : '随机插入逻辑连接词' 235 | } 236 | }, 237 | { 238 | tag : 'input', 239 | name : 'enhanceLogic', 240 | storage : 'enhanceLogic', 241 | def : false, 242 | properties : { 243 | type : 'checkbox', 244 | id : 'laji_enhanceLogic', 245 | title : '随机插入逻辑连接词' 246 | } 247 | }, 248 | { 249 | tag : 'span', 250 | properties : { 251 | innerHTML : '  ' 252 | } 253 | }, 254 | { 255 | tag : 'span', 256 | properties : { 257 | innerHTML : '强制小写', 258 | title : '强制转换成小写字母' 259 | } 260 | }, 261 | { 262 | tag : 'input', 263 | name : 'forceLower', 264 | storage : 'forceLower', 265 | def : false, 266 | properties : { 267 | type : 'checkbox', 268 | id : 'laji_forceLower', 269 | title : '强制转换成小写字母' 270 | } 271 | }, 272 | { tag : 'br' }, 273 | { 274 | tag : 'span', 275 | properties : { 276 | innerHTML : '自动装填', 277 | title : '生成后自动填入独轮车\n【如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中】' 278 | } 279 | }, 280 | { 281 | tag : 'input', 282 | name : 'autoDLC', 283 | storage : 'autoDLC', 284 | def : false, 285 | properties : { 286 | type : 'checkbox', 287 | id : 'laji_autoDLC', 288 | title : '生成后自动填入独轮车\n【如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中】', 289 | onchange : function (e){ 290 | ui.elem.dynamicReload.disabled = !ui.elem.autoDLC.checked; 291 | } 292 | } 293 | }, 294 | { 295 | tag : 'span', 296 | properties : { 297 | innerHTML : '  ' 298 | } 299 | }, 300 | { 301 | tag : 'span', 302 | properties : { 303 | innerHTML : '动态装填', 304 | title : '【适合长时间全自动挂机,如果用手动穿甲的话则没必要开】\n开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药' 305 | } 306 | }, 307 | { 308 | tag : 'input', 309 | name : 'dynamicReload', 310 | storage : 'dynamicReload', 311 | def : false, 312 | properties : { 313 | type : 'checkbox', 314 | id : 'laji_dynamicReload', 315 | title : '【适合长时间全自动挂机,如果用手动穿甲的话则没必要开】\n开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药' 316 | } 317 | }, 318 | { tag : 'br' }, 319 | { 320 | tag : 'button', 321 | name : 'generateButton', 322 | properties : { 323 | innerHTML : '开始生成', 324 | id : 'laji_generateButton', 325 | title : '生成随机中文+多次翻译', 326 | onclick : async e=>{ 327 | if (isBusy) return; 328 | isBusy = true; 329 | ui.saveInput(); 330 | let original = ui.elem.generateButton.innerHTML; 331 | ui.elem.generateButton.innerHTML = '...'; 332 | let numLines = Number(ui.elem.lineNumBox.value); 333 | let numWords = Number(ui.elem.wordNumBox.value); 334 | if (isNaN(numLines)) numLines = 20; 335 | if (isNaN(numWords)) numLines = 10; 336 | await asyncGenerate(numLines, numWords); 337 | await asyncTranslate(); 338 | //fill DLC 339 | if (ui.elem.autoDLC.checked) { 340 | sendToDlc(ui.elem.resultText.value); 341 | } 342 | ui.elem.generateButton.innerHTML = original; 343 | isBusy = false; 344 | } 345 | } 346 | }, 347 | { 348 | tag : 'button', 349 | name : 'deeplButton', 350 | properties : { 351 | innerHTML : '用deepl打开', 352 | id : 'laji_deeplButton', 353 | title : '在新窗口中用deepl打开当前文本框的内容', 354 | onclick : async e=>{ 355 | openDeepl(ui.elem.resultText.value); 356 | } 357 | } 358 | }, 359 | { tag : 'br' }, 360 | { 361 | tag : 'textarea', 362 | name : 'resultText', 363 | properties : { 364 | id : 'laji_resultText', 365 | cols : 40, 366 | rows : 8, 367 | style : { 368 | 'min-width' : '180px', 369 | 'min-height' : '50px' 370 | } 371 | } 372 | } 373 | ]; 374 | 375 | function cxhrAsync(url, method, dataStr){ 376 | return new Promise(resolve => { 377 | GM_xmlhttpRequest({ 378 | method: method, 379 | url: url, 380 | data: dataStr, 381 | headers: { 382 | "Content-Type": "application/x-www-form-urlencoded" 383 | }, 384 | onload: function(res){ 385 | if(res.status === 200){ 386 | //console.log(res.responseText); 387 | resolve(res.responseText); 388 | }else{ 389 | console.log('error'); 390 | console.log(res); 391 | resolve(null); 392 | } 393 | }, 394 | onerror : function(err){ 395 | console.log('error'); 396 | console.log(err); 397 | resolve(null); 398 | } 399 | }); 400 | }); 401 | } 402 | 403 | //翻译器:百度翻译 404 | //必要的异步函数:initialize()和translate(content, from, to) 405 | //每当有东西需要翻译时就依次调用initialize和translate 406 | //为了统一格式,from和to就用百度翻译的语言代号,如果实现别的api可能需要做一个转换 407 | //可以照此实现别的翻译api 408 | let tokenReg = new RegExp("token:\\s'(\\S{32})'"); 409 | let gtkReg = new RegExp("window.gtk\\s=\\s'(\\d{6}.\\d{9})';"); 410 | let baiduFanyi = { 411 | initialized : false, 412 | currentToken : null, 413 | currentGtk : null, 414 | initialize : async function(){ //异步,当需要此翻译的时候被调用 415 | if (this.initialized) return;//只初始化一次 416 | console.log('initializing baiduFanyi'); 417 | await this.fetchToken(); 418 | setInterval(() => this.fetchToken(), 600 * 1000);//10分钟重新获取token 419 | this.initialized = true; 420 | }, 421 | fetchToken : async function(){ 422 | let page = await cxhrAsync('https://fanyi.baidu.com/', 'get', ''); 423 | this.currentToken = tokenReg.exec(page)[1]; 424 | this.currentGtk = gtkReg.exec(page)[1]; 425 | }, 426 | getSign : function(content){ 427 | function a(r, o) { 428 | for (var t = 0; t < o.length - 2; t += 3) { 429 | var a = o.charAt(t + 2); 430 | a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a), 431 | a = "+" === o.charAt(t + 1) ? r >>> a: r << a, 432 | r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a 433 | } 434 | return r 435 | } 436 | var C = null; 437 | var token = function(r, _gtk) { 438 | var o = r.length; 439 | o > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(o / 2) - 5, 10) + r.substring(r.length, r.length - 10)); 440 | var t; 441 | t = void 0, 442 | t = null !== C ? C: (C = _gtk || "") || ""; 443 | for (var e = t.split("."), h = Number(e[0]) || 0, i = Number(e[1]) || 0, d = [], f = 0, g = 0; g < r.length; g++) { 444 | var m = r.charCodeAt(g); 445 | 128 > m ? d[f++] = m: (2048 > m ? d[f++] = m >> 6 | 192 : (55296 === (64512 & m) && g + 1 < r.length && 56320 === (64512 & r.charCodeAt(g + 1)) ? (m = 65536 + ((1023 & m) << 10) + (1023 & r.charCodeAt(++g)), d[f++] = m >> 18 | 240, d[f++] = m >> 12 & 63 | 128) : d[f++] = m >> 12 | 224, d[f++] = m >> 6 & 63 | 128), d[f++] = 63 & m | 128) 446 | } 447 | for (var S = h, 448 | u = "+-a^+6", 449 | l = "+-3^+b+-f", 450 | s = 0; s < d.length; s++) S += d[s], 451 | S = a(S, u); 452 | 453 | return S = a(S, l), 454 | S ^= i, 455 | 0 > S && (S = (2147483647 & S) + 2147483648), 456 | S %= 1e6, 457 | S.toString() + "." + (S ^ h) 458 | } 459 | return token(content, this.currentGtk); 460 | }, 461 | translate : async function (content, from, to){ 462 | let sign = this.getSign(content); 463 | let textres = await cxhrAsync(`https://fanyi.baidu.com/v2transapi?from=${from}&to=${to}`, 464 | 'post', `from=${from}&to=${to}&query=${encodeURIComponent(content)}&transtype=realtime&simple_means_flag=3&sign=${sign}&token=${this.currentToken}&domain=common`); 465 | if (textres == null) return null; 466 | let obj = eval(`(${textres})`); 467 | //console.log(obj); 468 | let resstr = ''; 469 | obj.trans_result.data.forEach(line => resstr += line.dst + '\n'); 470 | return resstr; 471 | }, 472 | getLang : async function (content){ 473 | let textres = await cxhrAsync('https://fanyi.baidu.com/langdetect', 'post', 'query=' + encodeURIComponent(content)); 474 | let obj = eval(`(${textres})`); 475 | return obj.lan; 476 | }, 477 | } 478 | 479 | //生成随机中文 480 | let asyncGenerate = async (numLines, numWords) => {//其实没有async... 481 | let insertWords = ui.elem.insertWordBox.value.split(' '); 482 | ui.elem.resultText.value = ''; 483 | for (let i = 0; i < numLines; i++){ 484 | let trashArr = randomFromWordList(wordsChinese, numWords); 485 | let j, insertPosition; 486 | for (j = 0; j < insertWords.length; j++){ 487 | if (Math.random() > 1 - 0.02**(1.0 / insertWords.length)) continue; 488 | insertPosition = randomInt(0, trashArr.length + 1); 489 | trashArr.splice(insertPosition, 0, insertWords[j]); 490 | } 491 | if (ui.elem.enhanceTone.checked){ 492 | let toneArr = randomFromWordList(wordsTone, randomInt(1, 3)); 493 | for (j = 0; j < toneArr.length; j++){ 494 | insertPosition = [Math.floor(trashArr.length / 2), Math.floor(trashArr.length * 2 / 3), trashArr.length][randomInt(0, 3)]; 495 | trashArr.splice(insertPosition, 0, toneArr[j]); 496 | } 497 | } 498 | if (ui.elem.enhanceLogic.checked){ 499 | let logicArr = randomFromWordList(wordsLogic, randomInt(1, 3)); 500 | for (j = 0; j < logicArr.length; j++){ 501 | insertPosition = randomInt(0, trashArr.length / 2); 502 | trashArr.splice(insertPosition, 0, logicArr[j]); 503 | } 504 | } 505 | trashArr.forEach(trash => ui.elem.resultText.value += trash); 506 | ui.elem.resultText.value += '\n'; 507 | } 508 | //console.log(ui.elem.resultText.value); 509 | } 510 | 511 | //翻译 512 | let asyncTranslate = async () => { 513 | let translations = ui.elem.translationOrderBox.value.split(' '); 514 | while (translations.length > 0) { 515 | let thisLang = await baiduFanyi.getLang(ui.elem.resultText.value); 516 | let nextLang = translations.shift(); 517 | if (thisLang == nextLang) continue; 518 | //console.log(`translating: ${thisLang} to ${nextLang}`); 519 | let translated = await baiduFanyi.translate(ui.elem.resultText.value, thisLang, nextLang); 520 | if (translated == null){ 521 | console.log(`error translating: ${thisLang} to ${nextLang}`); 522 | break; 523 | } 524 | //console.log(translated); 525 | ui.elem.resultText.value = translated; 526 | } 527 | let banWords = ui.elem.banWordBox.value.split(' '); 528 | for (let i = 0; i < banWords.length; i++){ 529 | //去除不允许的词 暂且这么处理 530 | ui.elem.resultText.value = ui.elem.resultText.value.replaceAll(new RegExp(banWords[i], 'gi'), ''); 531 | } 532 | if (ui.elem.forceLower.checked){ 533 | ui.elem.resultText.value = ui.elem.resultText.value.toLowerCase(); 534 | } 535 | 536 | } 537 | 538 | 539 | //jump to deepl 540 | function openDeepl(content){ 541 | window.open('https://www.deepl.com/en/translator#zh/en/' + encodeURIComponent(content)); 542 | } 543 | 544 | function sendToDlc(text){ 545 | if (dulunche != null){ 546 | try{ 547 | dulunche.config.text = text; 548 | }catch(e){ 549 | console.log(e); 550 | } 551 | if (dlcIsRunning && ui.elem.dynamicReload.checked){ 552 | //动态装填,覆盖独轮车的danmakuGener 553 | console.log('randomsentencegenerator: overriding danmakuGener'); 554 | let splitText = text.split('\n'); 555 | let splitFiltered = []; 556 | let currentIndex = 0; 557 | let sentCount = 0; 558 | splitText.forEach(i => { 559 | if (i.length > 0){ 560 | splitFiltered.push(i); 561 | } 562 | }); 563 | //覆盖danmakuGener 564 | dulunche.refs.danmakuGener = (function*(){ 565 | while(true){ 566 | if (splitFiltered.length == 0) { 567 | ui.elem.generateButton.click(); 568 | yield ''; 569 | } 570 | else{ 571 | if (dulunche.config.randomDanmaku){ 572 | sentCount++; 573 | yield splitFiltered[randomInt(0, splitFiltered.length)]; 574 | } 575 | else{ 576 | currentIndex++; 577 | sentCount++; 578 | if (currentIndex >= splitFiltered.length) currentIndex = 0; 579 | yield splitFiltered[currentIndex]; 580 | } 581 | if (sentCount > splitFiltered.length / 2 && sentCount > 1){ 582 | ui.elem.generateButton.click(); 583 | } 584 | } 585 | } 586 | })(); 587 | } 588 | } 589 | } 590 | 591 | //下载词库 592 | async function getWordList(url){ 593 | let raw = await cxhrAsync(url, 'get', ''); 594 | return raw.split('\n'); 595 | } 596 | 597 | function randomInt(from, to){ 598 | return Math.floor(Math.random() * (to - from) + from); 599 | } 600 | 601 | function randomFromWordList(wordList, numWords){ 602 | let res = []; 603 | for (let i = 0; i < numWords; i++){ 604 | res.push(wordList[Math.floor(Math.random()**2 * wordList.length)]); 605 | } 606 | return res; 607 | } 608 | 609 | //注入代码 610 | let insertScript = function(script){ 611 | //console.log(script); 612 | let scriptElem = document.createElement('script'); 613 | scriptElem.innerHTML = script; 614 | document.body.appendChild(scriptElem); 615 | } 616 | 617 | //注入函数 618 | let insertFunction = function(globalName, params, func){ 619 | let eventName = globalName + '_userevent' + randomInt(10000000, 99999999); 620 | document.addEventListener(eventName, async e => { 621 | //console.log(e); 622 | let promise = func.apply(window, e.params); 623 | e.resolve(await promise); 624 | }); 625 | insertScript(` 626 | window.${globalName} = function(${params}){ 627 | return new Promise(resolve =>{ 628 | let event = document.createEvent('HTMLEvents'); 629 | event.initEvent('${eventName}', true, true); 630 | event.params = Array.from(arguments); 631 | event.resolve = resolve; 632 | document.dispatchEvent(event); 633 | }); 634 | } 635 | `); 636 | } 637 | 638 | //异步,从外面取值 639 | let globalEval = function(code){ 640 | return new Promise(resolve => { 641 | insertFunction('laji_passObject', 'obj', o => { 642 | resolve(o); 643 | }); 644 | insertScript(` 645 | (() => { 646 | try{ 647 | laji_passObject(eval("${code}")); 648 | } 649 | catch(e){ 650 | console.log(e); 651 | laji_passObject(null); 652 | } 653 | finally{ 654 | window.laji_passObject = undefined; 655 | } 656 | })() 657 | `); 658 | }); 659 | } 660 | 661 | insertFunction('laji_baiduFanyiTranslateAsync', 'text, from, to', async(content, from, to) => await baiduFanyi.translate(content, from, to)); 662 | insertFunction('laji_baiduFanyiDetectLangAsync', 'text', async(content) => await baiduFanyi.getLang(content)); 663 | insertFunction('laji_cxhrAsync', 'url, method, dataString', cxhrAsync) 664 | insertFunction('laji_GenerateAndTranslate', '', () => ui.elem.generateButton.click()); 665 | insertFunction('laji_OpenDeepl', '', () => ui.elem.deeplButton.click()); 666 | 667 | 668 | //load wordlist 669 | console.log('get wordlist'); 670 | //wordsEnglish = await getWordList('https://github.com/first20hours/google-10000-english/raw/master/google-10000-english-no-swears.txt'); 671 | wordsChinese = await getWordList('https://gist.github.com/c4d0/47b712b20ac1f85724048d500909d1cc/raw/904236c3c1fecf348b9757b7d705ac9ba40bf655/chinese_10000words'); 672 | 673 | 674 | baiduFanyi.initialize(); 675 | 676 | 677 | //setup ui 678 | let smallWindow = document.createElement('div'); 679 | smallWindow.id = 'laji_root'; 680 | smallWindow.style['position'] = 'fixed'; 681 | smallWindow.style['left'] = '0'; 682 | smallWindow.style['top'] = '0'; 683 | //smallWindow.style['width'] = '200px'; 684 | //smallWindow.style['height'] = '100px'; 685 | smallWindow.style['background-color'] = '#fff'; 686 | smallWindow.style['border-width'] = '2px'; 687 | smallWindow.style['border-style'] = 'solid'; 688 | smallWindow.style['border-color'] = '#888'; 689 | smallWindow.style['border-radius'] = '5px'; 690 | smallWindow.style['padding'] = '4px'; 691 | smallWindow.style['z-index'] = '100000'; 692 | smallWindow.style['display'] = 'none'; 693 | smallWindow.style['user-select'] = 'none'; 694 | ui.initialize(smallWindow, uiConfig); 695 | ui.loadInput(); 696 | document.body.appendChild(smallWindow); 697 | console.log(ui); 698 | 699 | 700 | 701 | //drag window 702 | let startX = 0, startY = 0; 703 | let currentX = 0, currentY = 0; 704 | let isMouseDown = false; 705 | smallWindow.addEventListener('mousedown', e =>{ 706 | if (e.target.tagName == "TEXTAREA" || e.target.tagName == "BUTTON" || e.target.tagName == "INPUT") return; 707 | startX = e.pageX; 708 | startY = e.pageY; 709 | isMouseDown = true; 710 | }); 711 | document.addEventListener('mousemove', e =>{ 712 | if (!isMouseDown) return; 713 | currentX += e.pageX - startX; 714 | currentY += e.pageY - startY; 715 | startX = e.pageX; 716 | startY = e.pageY; 717 | smallWindow.style['left'] = currentX + 'px'; 718 | smallWindow.style['top'] = currentY + 'px'; 719 | 720 | }); 721 | document.addEventListener('mouseup', e =>{ 722 | isMouseDown = false; 723 | }); 724 | 725 | //hotkey 726 | document.addEventListener('keydown', e =>{ 727 | if (e.keyCode == 82 && e.altKey && e.shiftKey){ 728 | smallWindow.style['display'] = smallWindow.style['display'] == 'none' ? '' : 'none'; 729 | } 730 | }); 731 | 732 | smallWindow.style['display'] = ''; 733 | 734 | //获取独轮车接口 735 | dulunche = await globalEval('window.dulunche'); 736 | if (dulunche != null){ 737 | dulunche.eventBus.on('dlc.run', ()=>{ 738 | dlcIsRunning = true; 739 | if (ui.elem.autoDLC.checked && ui.elem.dynamicReload.checked) { 740 | sendToDlc(ui.elem.resultText.value); 741 | } 742 | }); 743 | dulunche.eventBus.on('dlc.stop', ()=>{ 744 | dlcIsRunning = false; 745 | }); 746 | } 747 | else{ 748 | console.log('randomsentencegenerator: 未找到独轮车'); 749 | } 750 | 751 | 752 | })(); 753 | -------------------------------------------------------------------------------- /legacy/randomsentencegenerator_v0.7.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RandomSentenceGenerator 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.7 5 | // @description generates random sentence, helps you come up with good ideas. 6 | // @author sqrl 7 | // @license MIT 8 | // @match *://www.youtube.com/* 9 | // @grant GM_xmlhttpRequest 10 | // @grant GM_setValue 11 | // @grant GM_getValue 12 | // ==/UserScript== 13 | 14 | 15 | //要求独轮车版本 >= 2.20 16 | 17 | (async function() { 18 | 19 | if (window.top !== window.self) throw new Error('非顶层框架'); 20 | 21 | let isBusy = false; 22 | let wordsChinese = []; 23 | let wordsTone = ['!', '?']; 24 | let wordsLogic = ['虽然', '但是', '因为', '所以', '如果']; 25 | let dlcIsRunning = false; 26 | let dulunche = null; 27 | 28 | let ui = { 29 | saveInput : function (){ 30 | for (let i = 0; i < this.config.length; i++){ 31 | let cfg = this.config[i]; 32 | if (cfg.name != null && cfg.tag == 'input'){ 33 | switch (cfg.properties.type){ 34 | case 'checkbox': 35 | GM_setValue(cfg.storage, this.elem[cfg.name].checked); 36 | break; 37 | default: 38 | GM_setValue(cfg.storage, this.elem[cfg.name].value); 39 | break; 40 | } 41 | } 42 | } 43 | }, 44 | loadInput : function (){ 45 | for (let i = 0; i < this.config.length; i++){ 46 | let cfg = this.config[i]; 47 | if (cfg.name != null && cfg.tag == 'input'){ 48 | let loaded = null; 49 | switch (cfg.properties.type){ 50 | case 'checkbox': 51 | loaded = GM_getValue(cfg.storage); 52 | this.elem[cfg.name].checked = loaded == null ? cfg.def : loaded; 53 | break; 54 | default: 55 | loaded = GM_getValue(cfg.storage); 56 | this.elem[cfg.name].value = loaded == null ? cfg.def : loaded; 57 | break; 58 | } 59 | this.elem[cfg.name].dispatchEvent(new InputEvent('change')); 60 | } 61 | } 62 | }, 63 | initialize : function(root, config){ 64 | this.config = config; 65 | for (let i = 0; i < config.length; i++){ 66 | let cfg = config[i]; 67 | let ele = document.createElement(cfg.tag); 68 | if (cfg.name != null) this.elem[cfg.name] = ele; 69 | if (cfg.properties != null){ 70 | for (let k in cfg.properties){ 71 | switch(k){ 72 | case 'style': 73 | for (let styleKey in cfg.properties.style){ 74 | ele.style[styleKey] = cfg.properties.style[styleKey]; 75 | } 76 | break; 77 | default: 78 | ele[k] = cfg.properties[k]; 79 | break; 80 | } 81 | } 82 | } 83 | root.appendChild(ele); 84 | } 85 | }, 86 | elem : { } 87 | }; 88 | let uiConfig = [ 89 | { 90 | tag : 'span', 91 | properties : { 92 | innerHTML : '垃圾话生成器 0.7(shift+R隐藏/显示界面)' 93 | } 94 | }, 95 | { tag : 'br' }, 96 | { 97 | tag : 'span', 98 | properties : { 99 | innerHTML : '鼠标悬停可以查看输入提示 ' 100 | } 101 | }, 102 | { 103 | tag : 'a', 104 | properties : { 105 | href : 'https://github.com/c4d0/Dulunche_RandomSentenceGenerator', 106 | target : '_blank', 107 | innerHTML : '打开github' 108 | } 109 | }, 110 | { tag : 'br' }, 111 | { 112 | tag : 'span', 113 | properties : { 114 | innerHTML : '主题:' 115 | } 116 | }, 117 | { 118 | tag : 'input', 119 | name : 'insertWordBox', 120 | storage : 'insertWordBox', 121 | def : '垃圾 coco', 122 | properties : { 123 | type : 'text', 124 | id : 'laji_insertWordBox', 125 | title : '会随机插入到生成的文本中。多个词用空格隔开' 126 | } 127 | }, 128 | { tag : 'br' }, 129 | { 130 | tag : 'span', 131 | properties : { 132 | innerHTML : '翻译顺序:' 133 | } 134 | }, 135 | { 136 | tag : 'input', 137 | name : 'translationOrderBox', 138 | storage : 'translationOrderBox', 139 | def : 'zh jp zh jp en', 140 | properties : { 141 | type : 'text', 142 | id : 'laji_translationOrderBox', 143 | title : '百度翻译的语言代码。例如:zh=简中 jp=日语 de=德语 ru=俄语 fra=法语 kor=韩语。\n空格隔开,生成时会从原文开始,按照这个顺序依次翻译得出结果' 144 | } 145 | }, 146 | { tag : 'br' }, 147 | { 148 | tag : 'span', 149 | properties : { 150 | innerHTML : '敏感词:' 151 | } 152 | }, 153 | { 154 | tag : 'input', 155 | name : 'banWordBox', 156 | storage : 'banWordBox', 157 | def : 'bot report taiwan pizza', 158 | properties : { 159 | type : 'text', 160 | id : 'laji_banWordBox', 161 | title : '翻译完成后会从文本里删去这些词,避免触发敏感词封禁。正则表达式,忽略大小写' 162 | } 163 | }, 164 | { tag : 'br' }, 165 | { 166 | tag : 'span', 167 | properties : { 168 | innerHTML : '一次生成条数:' 169 | } 170 | }, 171 | { 172 | tag : 'input', 173 | name : 'lineNumBox', 174 | storage : 'lineNumBox', 175 | def : '20', 176 | properties : { 177 | type : 'text', 178 | id : 'laji_lineNumBox', 179 | style : { 180 | 'width' : '50px' 181 | } 182 | } 183 | }, 184 | { tag : 'br' }, 185 | { 186 | tag : 'span', 187 | properties : { 188 | innerHTML : '每条中文词数:' 189 | } 190 | }, 191 | { 192 | tag : 'input', 193 | name : 'wordNumBox', 194 | storage : 'wordNumBox', 195 | def : '10', 196 | properties : { 197 | type : 'text', 198 | id : 'laji_wordNumBox', 199 | style : { 200 | 'width' : '50px' 201 | } 202 | } 203 | }, 204 | { tag : 'br' }, 205 | { 206 | tag : 'span', 207 | properties : { 208 | innerHTML : '语气增强', 209 | title : '随机插入问号和感叹号' 210 | } 211 | }, 212 | { 213 | tag : 'input', 214 | name : 'enhanceTone', 215 | storage : 'enhanceTone', 216 | def : false, 217 | properties : { 218 | type : 'checkbox', 219 | id : 'laji_enhanceTone', 220 | title : '随机插入问号和感叹号' 221 | } 222 | }, 223 | { 224 | tag : 'span', 225 | properties : { 226 | innerHTML : '  ' 227 | } 228 | }, 229 | { 230 | tag : 'span', 231 | properties : { 232 | innerHTML : '逻辑增强', 233 | title : '随机插入逻辑连接词' 234 | } 235 | }, 236 | { 237 | tag : 'input', 238 | name : 'enhanceLogic', 239 | storage : 'enhanceLogic', 240 | def : false, 241 | properties : { 242 | type : 'checkbox', 243 | id : 'laji_enhanceLogic', 244 | title : '随机插入逻辑连接词' 245 | } 246 | }, 247 | { 248 | tag : 'span', 249 | properties : { 250 | innerHTML : '  ' 251 | } 252 | }, 253 | { 254 | tag : 'span', 255 | properties : { 256 | innerHTML : '强制小写', 257 | title : '强制转换成小写字母' 258 | } 259 | }, 260 | { 261 | tag : 'input', 262 | name : 'forceLower', 263 | storage : 'forceLower', 264 | def : false, 265 | properties : { 266 | type : 'checkbox', 267 | id : 'laji_forceLower', 268 | title : '强制转换成小写字母' 269 | } 270 | }, 271 | { tag : 'br' }, 272 | { 273 | tag : 'span', 274 | properties : { 275 | innerHTML : '自动装填', 276 | title : '生成后自动填入独轮车\n【如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中】' 277 | } 278 | }, 279 | { 280 | tag : 'input', 281 | name : 'autoDLC', 282 | storage : 'autoDLC', 283 | def : false, 284 | properties : { 285 | type : 'checkbox', 286 | id : 'laji_autoDLC', 287 | title : '生成后自动填入独轮车\n【如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中】', 288 | onchange : function (e){ 289 | ui.elem.dynamicReload.disabled = !ui.elem.autoDLC.checked; 290 | } 291 | } 292 | }, 293 | { 294 | tag : 'span', 295 | properties : { 296 | innerHTML : '  ' 297 | } 298 | }, 299 | { 300 | tag : 'span', 301 | properties : { 302 | innerHTML : '动态装填', 303 | title : '【适合长时间全自动挂机,如果用手动穿甲的话则没必要开】\n开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药' 304 | } 305 | }, 306 | { 307 | tag : 'input', 308 | name : 'dynamicReload', 309 | storage : 'dynamicReload', 310 | def : false, 311 | properties : { 312 | type : 'checkbox', 313 | id : 'laji_dynamicReload', 314 | title : '【适合长时间全自动挂机,如果用手动穿甲的话则没必要开】\n开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药' 315 | } 316 | }, 317 | { tag : 'br' }, 318 | { 319 | tag : 'button', 320 | name : 'generateButton', 321 | properties : { 322 | innerHTML : '开始生成', 323 | id : 'laji_generateButton', 324 | title : '生成随机中文+多次翻译', 325 | onclick : async e=>{ 326 | if (isBusy) return; 327 | isBusy = true; 328 | ui.saveInput(); 329 | let original = ui.elem.generateButton.innerHTML; 330 | ui.elem.generateButton.innerHTML = '...'; 331 | let numLines = Number(ui.elem.lineNumBox.value); 332 | let numWords = Number(ui.elem.wordNumBox.value); 333 | if (isNaN(numLines)) numLines = 20; 334 | if (isNaN(numWords)) numLines = 10; 335 | await asyncGenerate(numLines, numWords); 336 | await asyncTranslate(); 337 | //fill DLC 338 | if (ui.elem.autoDLC.checked) { 339 | sendToDlc(ui.elem.resultText.value); 340 | } 341 | ui.elem.generateButton.innerHTML = original; 342 | isBusy = false; 343 | } 344 | } 345 | }, 346 | { 347 | tag : 'button', 348 | name : 'deeplButton', 349 | properties : { 350 | innerHTML : '用deepl打开', 351 | id : 'laji_deeplButton', 352 | title : '在新窗口中用deepl打开当前文本框的内容', 353 | onclick : async e=>{ 354 | openDeepl(ui.elem.resultText.value); 355 | } 356 | } 357 | }, 358 | { tag : 'br' }, 359 | { 360 | tag : 'textarea', 361 | name : 'resultText', 362 | properties : { 363 | id : 'laji_resultText', 364 | cols : 40, 365 | rows : 8, 366 | style : { 367 | 'min-width' : '180px', 368 | 'min-height' : '50px' 369 | } 370 | } 371 | } 372 | ]; 373 | 374 | function cxhrAsync(url, method, dataStr){ 375 | return new Promise(resolve => { 376 | GM_xmlhttpRequest({ 377 | method: method, 378 | url: url, 379 | data: dataStr, 380 | headers: { 381 | "Content-Type": "application/x-www-form-urlencoded" 382 | }, 383 | onload: function(res){ 384 | if(res.status === 200){ 385 | //console.log(res.responseText); 386 | resolve(res.responseText); 387 | }else{ 388 | console.log('error'); 389 | console.log(res); 390 | resolve(null); 391 | } 392 | }, 393 | onerror : function(err){ 394 | console.log('error'); 395 | console.log(err); 396 | resolve(null); 397 | } 398 | }); 399 | }); 400 | } 401 | 402 | let tokenReg = new RegExp("token:\\s'(\\S{32})'"); 403 | let gtkReg = new RegExp("window.gtk\\s=\\s'(\\d{6}.\\d{9})';"); 404 | let baiduFanyi = { 405 | currentToken : null, 406 | currentGtk : null, 407 | initialize : async function(){ 408 | let page = await cxhrAsync('https://fanyi.baidu.com/', 'get', ''); 409 | this.currentToken = tokenReg.exec(page)[1]; 410 | this.currentGtk = gtkReg.exec(page)[1]; 411 | }, 412 | getSign : function(content){ 413 | function a(r, o) { 414 | for (var t = 0; t < o.length - 2; t += 3) { 415 | var a = o.charAt(t + 2); 416 | a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a), 417 | a = "+" === o.charAt(t + 1) ? r >>> a: r << a, 418 | r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a 419 | } 420 | return r 421 | } 422 | var C = null; 423 | var token = function(r, _gtk) { 424 | var o = r.length; 425 | o > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(o / 2) - 5, 10) + r.substring(r.length, r.length - 10)); 426 | var t; 427 | t = void 0, 428 | t = null !== C ? C: (C = _gtk || "") || ""; 429 | for (var e = t.split("."), h = Number(e[0]) || 0, i = Number(e[1]) || 0, d = [], f = 0, g = 0; g < r.length; g++) { 430 | var m = r.charCodeAt(g); 431 | 128 > m ? d[f++] = m: (2048 > m ? d[f++] = m >> 6 | 192 : (55296 === (64512 & m) && g + 1 < r.length && 56320 === (64512 & r.charCodeAt(g + 1)) ? (m = 65536 + ((1023 & m) << 10) + (1023 & r.charCodeAt(++g)), d[f++] = m >> 18 | 240, d[f++] = m >> 12 & 63 | 128) : d[f++] = m >> 12 | 224, d[f++] = m >> 6 & 63 | 128), d[f++] = 63 & m | 128) 432 | } 433 | for (var S = h, 434 | u = "+-a^+6", 435 | l = "+-3^+b+-f", 436 | s = 0; s < d.length; s++) S += d[s], 437 | S = a(S, u); 438 | 439 | return S = a(S, l), 440 | S ^= i, 441 | 0 > S && (S = (2147483647 & S) + 2147483648), 442 | S %= 1e6, 443 | S.toString() + "." + (S ^ h) 444 | } 445 | return token(content, this.currentGtk); 446 | }, 447 | translate : async function (content, from, to){ 448 | let sign = this.getSign(content); 449 | let textres = await cxhrAsync(`https://fanyi.baidu.com/v2transapi?from=${from}&to=${to}`, 450 | 'post', `from=${from}&to=${to}&query=${encodeURIComponent(content)}&transtype=realtime&simple_means_flag=3&sign=${sign}&token=${this.currentToken}&domain=common`); 451 | //console.log(textres); 452 | let obj = eval(`(${textres})`); 453 | //console.log(obj); 454 | let resstr = ''; 455 | obj.trans_result.data.forEach(line => resstr += line.dst + '\n'); 456 | return resstr; 457 | }, 458 | getLang : async function (content){ 459 | let textres = await cxhrAsync('https://fanyi.baidu.com/langdetect', 'post', 'query=' + encodeURIComponent(content)); 460 | let obj = eval(`(${textres})`); 461 | return obj.lan; 462 | }, 463 | } 464 | 465 | let asyncGenerate = async (numLines, numWords) => { 466 | let insertWords = ui.elem.insertWordBox.value.split(' '); 467 | ui.elem.resultText.value = ''; 468 | for (let i = 0; i < numLines; i++){ 469 | let trashArr = randomFromWordList(wordsChinese, numWords); 470 | let j, insertPosition; 471 | for (j = 0; j < insertWords.length; j++){ 472 | if (Math.random() > 1 - 0.02**(1.0 / insertWords.length)) continue; 473 | insertPosition = randomInt(0, trashArr.length + 1); 474 | trashArr.splice(insertPosition, 0, insertWords[j]); 475 | } 476 | if (ui.elem.enhanceTone.checked){ 477 | let toneArr = randomFromWordList(wordsTone, randomInt(1, 3)); 478 | for (j = 0; j < toneArr.length; j++){ 479 | insertPosition = [Math.floor(trashArr.length / 2), Math.floor(trashArr.length * 2 / 3), trashArr.length][randomInt(0, 3)]; 480 | trashArr.splice(insertPosition, 0, toneArr[j]); 481 | } 482 | } 483 | if (ui.elem.enhanceLogic.checked){ 484 | let logicArr = randomFromWordList(wordsLogic, randomInt(1, 3)); 485 | for (j = 0; j < logicArr.length; j++){ 486 | insertPosition = randomInt(0, trashArr.length / 2); 487 | trashArr.splice(insertPosition, 0, logicArr[j]); 488 | } 489 | } 490 | trashArr.forEach(trash => ui.elem.resultText.value += trash); 491 | ui.elem.resultText.value += '\n'; 492 | } 493 | console.log(ui.elem.resultText.value); 494 | } 495 | 496 | let asyncTranslate = async () => { 497 | let translations = ui.elem.translationOrderBox.value.split(' '); 498 | while (translations.length > 0) { 499 | let thisLang = await baiduFanyi.getLang(ui.elem.resultText.value); 500 | let nextLang = translations.shift(); 501 | if (thisLang == nextLang) continue; 502 | //console.log(`translating: ${thisLang} to ${nextLang}`); 503 | let translated = await baiduFanyi.translate(ui.elem.resultText.value, thisLang, nextLang); 504 | //console.log(translated); 505 | ui.elem.resultText.value = translated; 506 | } 507 | let banWords = ui.elem.banWordBox.value.split(' '); 508 | for (let i = 0; i < banWords.length; i++){ 509 | //去除不允许的词 暂且这么处理 510 | ui.elem.resultText.value = ui.elem.resultText.value.replaceAll(new RegExp(banWords[i], 'gi'), ''); 511 | } 512 | if (ui.elem.forceLower.checked){ 513 | ui.elem.resultText.value = ui.elem.resultText.value.toLowerCase(); 514 | } 515 | 516 | } 517 | 518 | 519 | //jump to deepl 520 | function openDeepl(content){ 521 | window.open('https://www.deepl.com/en/translator#zh/en/' + encodeURIComponent(content)); 522 | } 523 | 524 | function sendToDlc(text){ 525 | if (dulunche != null){ 526 | try{ 527 | dulunche.config.text = text; 528 | }catch(e){ 529 | console.log(e); 530 | } 531 | if (dlcIsRunning && ui.elem.dynamicReload.checked){ 532 | console.log('randomsentencegenerator: overriding danmakuGener'); 533 | let splitText = text.split('\n'); 534 | let splitFiltered = []; 535 | let currentIndex = 0; 536 | let sentCount = 0; 537 | splitText.forEach(i => { 538 | if (i.length > 0){ 539 | splitFiltered.push(i); 540 | } 541 | }); 542 | //覆盖danmakuGener 543 | dulunche.refs.danmakuGener = (function*(){ 544 | while(true){ 545 | if (splitFiltered.length == 0) { 546 | ui.elem.generateButton.click(); 547 | yield ''; 548 | } 549 | else{ 550 | if (dulunche.config.randomDanmaku){ 551 | sentCount++; 552 | yield splitFiltered[randomInt(0, splitFiltered.length)]; 553 | } 554 | else{ 555 | currentIndex++; 556 | sentCount++; 557 | if (currentIndex >= splitFiltered.length) currentIndex = 0; 558 | yield splitFiltered[currentIndex]; 559 | } 560 | if (sentCount > splitFiltered.length / 2 && sentCount > 1){ 561 | ui.elem.generateButton.click(); 562 | } 563 | } 564 | } 565 | })(); 566 | } 567 | } 568 | } 569 | 570 | async function getWordList(url){ 571 | let raw = await cxhrAsync(url, 'get', ''); 572 | return raw.split('\n'); 573 | } 574 | 575 | function randomInt(from, to){ 576 | return Math.floor(Math.random() * (to - from) + from); 577 | } 578 | 579 | function randomFromWordList(wordList, numWords){ 580 | let res = []; 581 | for (let i = 0; i < numWords; i++){ 582 | res.push(wordList[Math.floor(Math.random()**2 * wordList.length)]); 583 | } 584 | return res; 585 | } 586 | 587 | let insertScript = function(script){ 588 | //console.log(script); 589 | let scriptElem = document.createElement('script'); 590 | scriptElem.innerHTML = script; 591 | document.body.appendChild(scriptElem); 592 | } 593 | 594 | let insertFunction = function(globalName, params, func){ 595 | let eventName = globalName + '_userevent' + randomInt(10000000, 99999999); 596 | document.addEventListener(eventName, async e => { 597 | //console.log(e); 598 | let promise = func.apply(window, e.params); 599 | e.resolve(await promise); 600 | }); 601 | insertScript(` 602 | window.${globalName} = function(${params}){ 603 | return new Promise(resolve =>{ 604 | let event = document.createEvent('HTMLEvents'); 605 | event.initEvent('${eventName}', true, true); 606 | event.params = Array.from(arguments); 607 | event.resolve = resolve; 608 | document.dispatchEvent(event); 609 | }); 610 | } 611 | `); 612 | } 613 | 614 | let globalEval = function(code){ 615 | return new Promise(resolve => { 616 | insertFunction('laji_passObject', 'obj', o => { 617 | resolve(o); 618 | }); 619 | insertScript(` 620 | (() => { 621 | try{ 622 | laji_passObject(eval("${code}")); 623 | } 624 | catch(e){ 625 | console.log(e); 626 | laji_passObject(null); 627 | } 628 | finally{ 629 | window.laji_passObject = undefined; 630 | } 631 | })() 632 | `); 633 | }); 634 | } 635 | 636 | insertFunction('laji_baiduFanyiTranslateAsync', 'text, from, to', async(content, from, to) => await baiduFanyi.translate(content, from, to)); 637 | insertFunction('laji_baiduFanyiDetectLangAsync', 'text', async(content) => await baiduFanyi.getLang(content)); 638 | insertFunction('laji_cxhrAsync', 'url, method, dataString', cxhrAsync) 639 | insertFunction('laji_GenerateAndTranslate', '', () => ui.elem.generateButton.click()); 640 | insertFunction('laji_OpenDeepl', '', () => ui.elem.deeplButton.click()); 641 | 642 | 643 | //load wordlist 644 | console.log('get wordlist'); 645 | //wordsEnglish = await getWordList('https://github.com/first20hours/google-10000-english/raw/master/google-10000-english-no-swears.txt'); 646 | wordsChinese = await getWordList('https://gist.github.com/c4d0/47b712b20ac1f85724048d500909d1cc/raw/904236c3c1fecf348b9757b7d705ac9ba40bf655/chinese_10000words'); 647 | 648 | //badduFanyi 649 | console.log('get fanyi token'); 650 | await baiduFanyi.initialize(); 651 | setInterval(() => baiduFanyi.initialize(), 600 * 1000);//10分钟重新获取token 652 | 653 | 654 | //setup ui 655 | let smallWindow = document.createElement('div'); 656 | smallWindow.id = 'laji_root'; 657 | smallWindow.style['position'] = 'fixed'; 658 | smallWindow.style['left'] = '0'; 659 | smallWindow.style['top'] = '0'; 660 | //smallWindow.style['width'] = '200px'; 661 | //smallWindow.style['height'] = '100px'; 662 | smallWindow.style['background-color'] = '#fff'; 663 | smallWindow.style['border-width'] = '2px'; 664 | smallWindow.style['border-style'] = 'solid'; 665 | smallWindow.style['border-color'] = '#888'; 666 | smallWindow.style['border-radius'] = '5px'; 667 | smallWindow.style['padding'] = '4px'; 668 | smallWindow.style['z-index'] = '100000'; 669 | smallWindow.style['display'] = 'none'; 670 | smallWindow.style['user-select'] = 'none'; 671 | ui.initialize(smallWindow, uiConfig); 672 | ui.loadInput(); 673 | document.body.appendChild(smallWindow); 674 | console.log(ui); 675 | 676 | 677 | 678 | //drag window 679 | let startX = 0, startY = 0; 680 | let currentX = 0, currentY = 0; 681 | let isMouseDown = false; 682 | smallWindow.addEventListener('mousedown', e =>{ 683 | if (e.target.tagName == "TEXTAREA" || e.target.tagName == "BUTTON" || e.target.tagName == "INPUT") return; 684 | startX = e.pageX; 685 | startY = e.pageY; 686 | isMouseDown = true; 687 | }); 688 | document.addEventListener('mousemove', e =>{ 689 | if (!isMouseDown) return; 690 | currentX += e.pageX - startX; 691 | currentY += e.pageY - startY; 692 | startX = e.pageX; 693 | startY = e.pageY; 694 | smallWindow.style['left'] = currentX + 'px'; 695 | smallWindow.style['top'] = currentY + 'px'; 696 | 697 | }); 698 | document.addEventListener('mouseup', e =>{ 699 | isMouseDown = false; 700 | }); 701 | 702 | //hotkey 703 | document.addEventListener('keydown', e =>{ 704 | if (e.key == 'R'){ 705 | smallWindow.style['display'] = smallWindow.style['display'] == 'none' ? '' : 'none'; 706 | } 707 | }); 708 | 709 | smallWindow.style['display'] = ''; 710 | 711 | 712 | dulunche = await globalEval('window.dulunche'); 713 | if (dulunche != null){ 714 | dulunche.eventBus.on('dlc.run', ()=>{ 715 | dlcIsRunning = true; 716 | if (ui.elem.autoDLC.checked && ui.elem.dynamicReload.checked) { 717 | sendToDlc(ui.elem.resultText.value); 718 | } 719 | }); 720 | dulunche.eventBus.on('dlc.stop', ()=>{ 721 | dlcIsRunning = false; 722 | }); 723 | } 724 | 725 | // insertFunction('laji_passDlcObject', 'dlc', d => { 726 | // console.log('randomsentencegenerator: dulunche detected'); 727 | // dulunche = d; 728 | // dulunche.eventBus.on('dlc.run', ()=>{ 729 | // dlcIsRunning = true; 730 | // if (ui.elem.autoDLC.checked && ui.elem.dynamicReload.checked) { 731 | // sendToDlc(ui.elem.resultText.value); 732 | // } 733 | // }); 734 | // dulunche.eventBus.on('dlc.stop', ()=>{ 735 | // dlcIsRunning = false; 736 | // }); 737 | // }); 738 | // insertScript(` 739 | // if (window.dulunche != null){ 740 | // laji_passDlcObject(window.dulunche); 741 | // window.laji_passDlcObject = undefined; 742 | // } 743 | // `); 744 | 745 | })(); 746 | -------------------------------------------------------------------------------- /randomsentencegenerator.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RandomSentenceGenerator 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.7.1 5 | // @description generates random sentence, helps you come up with good ideas. 6 | // @author sqrl 7 | // @license MIT 8 | // @match *://www.youtube.com/* 9 | // @grant GM_xmlhttpRequest 10 | // @grant GM_setValue 11 | // @grant GM_getValue 12 | // ==/UserScript== 13 | 14 | 15 | //要求独轮车版本 >= 2.20 16 | 17 | (async function() { 18 | 19 | if (window.top !== window.self) throw new Error('非顶层框架'); 20 | 21 | let isBusy = false; 22 | let wordsChinese = []; 23 | let wordsTone = ['!', '?']; 24 | let wordsLogic = ['虽然', '但是', '因为', '所以', '如果']; 25 | let dlcIsRunning = false; 26 | let dulunche = null; 27 | let translators = {}; //字典,key为标识符,value为translator对象 28 | 29 | let ui = { 30 | saveInput : function (){ 31 | for (let i = 0; i < this.config.length; i++){ 32 | let cfg = this.config[i]; 33 | if (cfg.name != null && cfg.tag == 'input'){ 34 | switch (cfg.properties.type){ 35 | case 'checkbox': 36 | GM_setValue(cfg.storage, this.elem[cfg.name].checked); 37 | break; 38 | default: 39 | GM_setValue(cfg.storage, this.elem[cfg.name].value); 40 | break; 41 | } 42 | } 43 | } 44 | }, 45 | loadInput : function (){ 46 | for (let i = 0; i < this.config.length; i++){ 47 | let cfg = this.config[i]; 48 | if (cfg.name != null && cfg.tag == 'input'){ 49 | let loaded = null; 50 | switch (cfg.properties.type){ 51 | case 'checkbox': 52 | loaded = GM_getValue(cfg.storage); 53 | this.elem[cfg.name].checked = loaded == null ? cfg.def : loaded; 54 | break; 55 | default: 56 | loaded = GM_getValue(cfg.storage); 57 | this.elem[cfg.name].value = loaded == null ? cfg.def : loaded; 58 | break; 59 | } 60 | this.elem[cfg.name].dispatchEvent(new InputEvent('change')); 61 | } 62 | } 63 | }, 64 | initialize : function(root, config){ 65 | this.config = config; 66 | for (let i = 0; i < config.length; i++){ 67 | let cfg = config[i]; 68 | let ele = document.createElement(cfg.tag); 69 | if (cfg.name != null) this.elem[cfg.name] = ele; 70 | if (cfg.properties != null){ 71 | for (let k in cfg.properties){ 72 | switch(k){ 73 | case 'style': 74 | for (let styleKey in cfg.properties.style){ 75 | ele.style[styleKey] = cfg.properties.style[styleKey]; 76 | } 77 | break; 78 | default: 79 | ele[k] = cfg.properties[k]; 80 | break; 81 | } 82 | } 83 | } 84 | root.appendChild(ele); 85 | } 86 | }, 87 | elem : { } 88 | }; 89 | let uiConfig = [ 90 | { 91 | tag : 'span', 92 | properties : { 93 | innerHTML : '垃圾话生成器 0.7.1(alt+shift+R隐藏/显示界面)' 94 | } 95 | }, 96 | { tag : 'br' }, 97 | { 98 | tag : 'span', 99 | properties : { 100 | innerHTML : '鼠标悬停可以查看输入提示 ' 101 | } 102 | }, 103 | { 104 | tag : 'a', 105 | properties : { 106 | href : 'https://github.com/c4d0/Dulunche_RandomSentenceGenerator', 107 | target : '_blank', 108 | innerHTML : '打开github' 109 | } 110 | }, 111 | { tag : 'br' }, 112 | { 113 | tag : 'span', 114 | properties : { 115 | innerHTML : '主题:' 116 | } 117 | }, 118 | { 119 | tag : 'input', 120 | name : 'insertWordBox', 121 | storage : 'insertWordBox', 122 | def : '垃圾 coco', 123 | properties : { 124 | type : 'text', 125 | id : 'laji_insertWordBox', 126 | title : '会随机插入到生成的文本中。多个词用空格隔开' 127 | } 128 | }, 129 | { tag : 'br' }, 130 | { 131 | tag : 'span', 132 | properties : { 133 | innerHTML : '翻译顺序:' 134 | } 135 | }, 136 | { 137 | tag : 'input', 138 | name : 'translationOrderBox', 139 | storage : 'translationOrderBox', 140 | def : 'zh jp zh jp en', 141 | properties : { 142 | type : 'text', 143 | id : 'laji_translationOrderBox', 144 | title : '百度翻译的语言代码。例如:zh=简中 jp=日语 de=德语 ru=俄语 fra=法语 kor=韩语。\n空格隔开,生成时会从原文开始,按照这个顺序依次翻译得出结果' 145 | } 146 | }, 147 | { tag : 'br' }, 148 | { 149 | tag : 'span', 150 | properties : { 151 | innerHTML : '敏感词:' 152 | } 153 | }, 154 | { 155 | tag : 'input', 156 | name : 'banWordBox', 157 | storage : 'banWordBox', 158 | def : 'bot report taiwan pizza', 159 | properties : { 160 | type : 'text', 161 | id : 'laji_banWordBox', 162 | title : '翻译完成后会从文本里删去这些词,避免触发敏感词封禁。正则表达式,忽略大小写' 163 | } 164 | }, 165 | { tag : 'br' }, 166 | { 167 | tag : 'span', 168 | properties : { 169 | innerHTML : '一次生成条数:' 170 | } 171 | }, 172 | { 173 | tag : 'input', 174 | name : 'lineNumBox', 175 | storage : 'lineNumBox', 176 | def : '20', 177 | properties : { 178 | type : 'text', 179 | id : 'laji_lineNumBox', 180 | style : { 181 | 'width' : '50px' 182 | } 183 | } 184 | }, 185 | { tag : 'br' }, 186 | { 187 | tag : 'span', 188 | properties : { 189 | innerHTML : '每条中文词数:' 190 | } 191 | }, 192 | { 193 | tag : 'input', 194 | name : 'wordNumBox', 195 | storage : 'wordNumBox', 196 | def : '10', 197 | properties : { 198 | type : 'text', 199 | id : 'laji_wordNumBox', 200 | style : { 201 | 'width' : '50px' 202 | } 203 | } 204 | }, 205 | { tag : 'br' }, 206 | { 207 | tag : 'span', 208 | properties : { 209 | innerHTML : '语气增强', 210 | title : '随机插入问号和感叹号' 211 | } 212 | }, 213 | { 214 | tag : 'input', 215 | name : 'enhanceTone', 216 | storage : 'enhanceTone', 217 | def : false, 218 | properties : { 219 | type : 'checkbox', 220 | id : 'laji_enhanceTone', 221 | title : '随机插入问号和感叹号' 222 | } 223 | }, 224 | { 225 | tag : 'span', 226 | properties : { 227 | innerHTML : '  ' 228 | } 229 | }, 230 | { 231 | tag : 'span', 232 | properties : { 233 | innerHTML : '逻辑增强', 234 | title : '随机插入逻辑连接词' 235 | } 236 | }, 237 | { 238 | tag : 'input', 239 | name : 'enhanceLogic', 240 | storage : 'enhanceLogic', 241 | def : false, 242 | properties : { 243 | type : 'checkbox', 244 | id : 'laji_enhanceLogic', 245 | title : '随机插入逻辑连接词' 246 | } 247 | }, 248 | { 249 | tag : 'span', 250 | properties : { 251 | innerHTML : '  ' 252 | } 253 | }, 254 | { 255 | tag : 'span', 256 | properties : { 257 | innerHTML : '强制小写', 258 | title : '强制转换成小写字母' 259 | } 260 | }, 261 | { 262 | tag : 'input', 263 | name : 'forceLower', 264 | storage : 'forceLower', 265 | def : false, 266 | properties : { 267 | type : 'checkbox', 268 | id : 'laji_forceLower', 269 | title : '强制转换成小写字母' 270 | } 271 | }, 272 | { tag : 'br' }, 273 | { 274 | tag : 'span', 275 | properties : { 276 | innerHTML : '自动装填', 277 | title : '生成后自动填入独轮车\n【如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中】' 278 | } 279 | }, 280 | { 281 | tag : 'input', 282 | name : 'autoDLC', 283 | storage : 'autoDLC', 284 | def : false, 285 | properties : { 286 | type : 'checkbox', 287 | id : 'laji_autoDLC', 288 | title : '生成后自动填入独轮车\n【如果你没有独轮车或着想用其他工具,则可以把此选项关掉,手动复制生成的文本到你的工具中】', 289 | onchange : function (e){ 290 | ui.elem.dynamicReload.disabled = !ui.elem.autoDLC.checked; 291 | } 292 | } 293 | }, 294 | { 295 | tag : 'span', 296 | properties : { 297 | innerHTML : '  ' 298 | } 299 | }, 300 | { 301 | tag : 'span', 302 | properties : { 303 | innerHTML : '动态装填', 304 | title : '【适合长时间全自动挂机,如果用手动穿甲的话则没必要开】\n开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药' 305 | } 306 | }, 307 | { 308 | tag : 'input', 309 | name : 'dynamicReload', 310 | storage : 'dynamicReload', 311 | def : false, 312 | properties : { 313 | type : 'checkbox', 314 | id : 'laji_dynamicReload', 315 | title : '【适合长时间全自动挂机,如果用手动穿甲的话则没必要开】\n开启此选项后会强制覆盖dulunche的danmakuGener,在弹药消耗到一半时自动生成新的弹药' 316 | } 317 | }, 318 | { tag : 'br' }, 319 | { 320 | tag : 'button', 321 | name : 'generateButton', 322 | properties : { 323 | innerHTML : '开始生成', 324 | id : 'laji_generateButton', 325 | title : '生成随机中文+多次翻译', 326 | onclick : async e=>{ 327 | if (isBusy) return; 328 | isBusy = true; 329 | ui.saveInput(); 330 | let original = ui.elem.generateButton.innerHTML; 331 | ui.elem.generateButton.innerHTML = '...'; 332 | let numLines = Number(ui.elem.lineNumBox.value); 333 | let numWords = Number(ui.elem.wordNumBox.value); 334 | if (isNaN(numLines)) numLines = 20; 335 | if (isNaN(numWords)) numLines = 10; 336 | await asyncGenerate(numLines, numWords); 337 | await asyncTranslate(); 338 | //fill DLC 339 | if (ui.elem.autoDLC.checked) { 340 | sendToDlc(ui.elem.resultText.value); 341 | } 342 | ui.elem.generateButton.innerHTML = original; 343 | isBusy = false; 344 | } 345 | } 346 | }, 347 | { 348 | tag : 'button', 349 | name : 'deeplButton', 350 | properties : { 351 | innerHTML : '用deepl打开', 352 | id : 'laji_deeplButton', 353 | title : '在新窗口中用deepl打开当前文本框的内容', 354 | onclick : async e=>{ 355 | openDeepl(ui.elem.resultText.value); 356 | } 357 | } 358 | }, 359 | { tag : 'br' }, 360 | { 361 | tag : 'textarea', 362 | name : 'resultText', 363 | properties : { 364 | id : 'laji_resultText', 365 | cols : 40, 366 | rows : 8, 367 | style : { 368 | 'min-width' : '180px', 369 | 'min-height' : '50px' 370 | } 371 | } 372 | } 373 | ]; 374 | 375 | function cxhrAsync(url, method, dataStr){ 376 | return new Promise(resolve => { 377 | GM_xmlhttpRequest({ 378 | method: method, 379 | url: url, 380 | data: dataStr, 381 | headers: { 382 | "Content-Type": "application/x-www-form-urlencoded" 383 | }, 384 | onload: function(res){ 385 | if(res.status === 200){ 386 | //console.log(res.responseText); 387 | resolve(res.responseText); 388 | }else{ 389 | console.log('error'); 390 | console.log(res); 391 | resolve(null); 392 | } 393 | }, 394 | onerror : function(err){ 395 | console.log('error'); 396 | console.log(err); 397 | resolve(null); 398 | } 399 | }); 400 | }); 401 | } 402 | 403 | //翻译器:百度翻译 404 | //必要的异步函数:initialize()和translate(content, from, to) 405 | //每当有东西需要翻译时就依次调用initialize和translate 406 | //为了统一格式,from和to就用百度翻译的语言代号,如果实现别的api可能需要做一个转换 407 | //可以照此实现别的翻译api 408 | let tokenReg = new RegExp("token:\\s'(\\S{32})'"); 409 | let gtkReg = new RegExp("window.gtk\\s=\\s'(\\d{6}.\\d{9})';"); 410 | let baiduFanyi = { 411 | initialized : false, 412 | currentToken : null, 413 | currentGtk : null, 414 | initialize : async function(){ //异步,当需要此翻译的时候被调用 415 | if (this.initialized) return;//只初始化一次 416 | console.log('initializing baiduFanyi'); 417 | await this.fetchToken(); 418 | setInterval(() => this.fetchToken(), 600 * 1000);//10分钟重新获取token 419 | this.initialized = true; 420 | }, 421 | fetchToken : async function(){ 422 | let page = await cxhrAsync('https://fanyi.baidu.com/', 'get', ''); 423 | this.currentToken = tokenReg.exec(page)[1]; 424 | this.currentGtk = gtkReg.exec(page)[1]; 425 | }, 426 | getSign : function(content){ 427 | function a(r, o) { 428 | for (var t = 0; t < o.length - 2; t += 3) { 429 | var a = o.charAt(t + 2); 430 | a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a), 431 | a = "+" === o.charAt(t + 1) ? r >>> a: r << a, 432 | r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a 433 | } 434 | return r 435 | } 436 | var C = null; 437 | var token = function(r, _gtk) { 438 | var o = r.length; 439 | o > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(o / 2) - 5, 10) + r.substring(r.length, r.length - 10)); 440 | var t; 441 | t = void 0, 442 | t = null !== C ? C: (C = _gtk || "") || ""; 443 | for (var e = t.split("."), h = Number(e[0]) || 0, i = Number(e[1]) || 0, d = [], f = 0, g = 0; g < r.length; g++) { 444 | var m = r.charCodeAt(g); 445 | 128 > m ? d[f++] = m: (2048 > m ? d[f++] = m >> 6 | 192 : (55296 === (64512 & m) && g + 1 < r.length && 56320 === (64512 & r.charCodeAt(g + 1)) ? (m = 65536 + ((1023 & m) << 10) + (1023 & r.charCodeAt(++g)), d[f++] = m >> 18 | 240, d[f++] = m >> 12 & 63 | 128) : d[f++] = m >> 12 | 224, d[f++] = m >> 6 & 63 | 128), d[f++] = 63 & m | 128) 446 | } 447 | for (var S = h, 448 | u = "+-a^+6", 449 | l = "+-3^+b+-f", 450 | s = 0; s < d.length; s++) S += d[s], 451 | S = a(S, u); 452 | 453 | return S = a(S, l), 454 | S ^= i, 455 | 0 > S && (S = (2147483647 & S) + 2147483648), 456 | S %= 1e6, 457 | S.toString() + "." + (S ^ h) 458 | } 459 | return token(content, this.currentGtk); 460 | }, 461 | translate : async function (content, from, to){ 462 | let sign = this.getSign(content); 463 | let textres = await cxhrAsync(`https://fanyi.baidu.com/v2transapi?from=${from}&to=${to}`, 464 | 'post', `from=${from}&to=${to}&query=${encodeURIComponent(content)}&transtype=realtime&simple_means_flag=3&sign=${sign}&token=${this.currentToken}&domain=common`); 465 | if (textres == null) return null; 466 | let obj = eval(`(${textres})`); 467 | //console.log(obj); 468 | let resstr = ''; 469 | obj.trans_result.data.forEach(line => resstr += line.dst + '\n'); 470 | return resstr; 471 | }, 472 | getLang : async function (content){ 473 | let textres = await cxhrAsync('https://fanyi.baidu.com/langdetect', 'post', 'query=' + encodeURIComponent(content)); 474 | let obj = eval(`(${textres})`); 475 | return obj.lan; 476 | }, 477 | } 478 | 479 | //生成随机中文 480 | let asyncGenerate = async (numLines, numWords) => {//其实没有async... 481 | let insertWords = ui.elem.insertWordBox.value.split(' '); 482 | ui.elem.resultText.value = ''; 483 | for (let i = 0; i < numLines; i++){ 484 | let trashArr = randomFromWordList(wordsChinese, numWords); 485 | let j, insertPosition; 486 | for (j = 0; j < insertWords.length; j++){ 487 | if (Math.random() > 1 - 0.02**(1.0 / insertWords.length)) continue; 488 | insertPosition = randomInt(0, trashArr.length + 1); 489 | trashArr.splice(insertPosition, 0, insertWords[j]); 490 | } 491 | if (ui.elem.enhanceTone.checked){ 492 | let toneArr = randomFromWordList(wordsTone, randomInt(1, 3)); 493 | for (j = 0; j < toneArr.length; j++){ 494 | insertPosition = [Math.floor(trashArr.length / 2), Math.floor(trashArr.length * 2 / 3), trashArr.length][randomInt(0, 3)]; 495 | trashArr.splice(insertPosition, 0, toneArr[j]); 496 | } 497 | } 498 | if (ui.elem.enhanceLogic.checked){ 499 | let logicArr = randomFromWordList(wordsLogic, randomInt(1, 3)); 500 | for (j = 0; j < logicArr.length; j++){ 501 | insertPosition = randomInt(0, trashArr.length / 2); 502 | trashArr.splice(insertPosition, 0, logicArr[j]); 503 | } 504 | } 505 | trashArr.forEach(trash => ui.elem.resultText.value += trash); 506 | ui.elem.resultText.value += '\n'; 507 | } 508 | //console.log(ui.elem.resultText.value); 509 | } 510 | 511 | //翻译 512 | let asyncTranslate = async () => { 513 | let translations = ui.elem.translationOrderBox.value.split(' '); 514 | while (translations.length > 0) { 515 | let thisLang = await baiduFanyi.getLang(ui.elem.resultText.value); 516 | let nextLang = translations.shift(); 517 | if (thisLang == nextLang) continue; 518 | //console.log(`translating: ${thisLang} to ${nextLang}`); 519 | let translated = await baiduFanyi.translate(ui.elem.resultText.value, thisLang, nextLang); 520 | if (translated == null){ 521 | console.log(`error translating: ${thisLang} to ${nextLang}`); 522 | break; 523 | } 524 | //console.log(translated); 525 | ui.elem.resultText.value = translated; 526 | } 527 | let banWords = ui.elem.banWordBox.value.split(' '); 528 | for (let i = 0; i < banWords.length; i++){ 529 | //去除不允许的词 暂且这么处理 530 | ui.elem.resultText.value = ui.elem.resultText.value.replaceAll(new RegExp(banWords[i], 'gi'), ''); 531 | } 532 | if (ui.elem.forceLower.checked){ 533 | ui.elem.resultText.value = ui.elem.resultText.value.toLowerCase(); 534 | } 535 | 536 | } 537 | 538 | 539 | //jump to deepl 540 | function openDeepl(content){ 541 | window.open('https://www.deepl.com/en/translator#zh/en/' + encodeURIComponent(content)); 542 | } 543 | 544 | function sendToDlc(text){ 545 | if (dulunche != null){ 546 | try{ 547 | dulunche.config.text = text; 548 | }catch(e){ 549 | console.log(e); 550 | } 551 | if (dlcIsRunning && ui.elem.dynamicReload.checked){ 552 | //动态装填,覆盖独轮车的danmakuGener 553 | console.log('randomsentencegenerator: overriding danmakuGener'); 554 | let splitText = text.split('\n'); 555 | let splitFiltered = []; 556 | let currentIndex = 0; 557 | let sentCount = 0; 558 | splitText.forEach(i => { 559 | if (i.length > 0){ 560 | splitFiltered.push(i); 561 | } 562 | }); 563 | //覆盖danmakuGener 564 | dulunche.refs.danmakuGener = (function*(){ 565 | while(true){ 566 | if (splitFiltered.length == 0) { 567 | ui.elem.generateButton.click(); 568 | yield ''; 569 | } 570 | else{ 571 | if (dulunche.config.randomDanmaku){ 572 | sentCount++; 573 | yield splitFiltered[randomInt(0, splitFiltered.length)]; 574 | } 575 | else{ 576 | currentIndex++; 577 | sentCount++; 578 | if (currentIndex >= splitFiltered.length) currentIndex = 0; 579 | yield splitFiltered[currentIndex]; 580 | } 581 | if (sentCount > splitFiltered.length / 2 && sentCount > 1){ 582 | ui.elem.generateButton.click(); 583 | } 584 | } 585 | } 586 | })(); 587 | } 588 | } 589 | } 590 | 591 | //下载词库 592 | async function getWordList(url){ 593 | let raw = await cxhrAsync(url, 'get', ''); 594 | return raw.split('\n'); 595 | } 596 | 597 | function randomInt(from, to){ 598 | return Math.floor(Math.random() * (to - from) + from); 599 | } 600 | 601 | function randomFromWordList(wordList, numWords){ 602 | let res = []; 603 | for (let i = 0; i < numWords; i++){ 604 | res.push(wordList[Math.floor(Math.random()**2 * wordList.length)]); 605 | } 606 | return res; 607 | } 608 | 609 | //注入代码 610 | let insertScript = function(script){ 611 | //console.log(script); 612 | let scriptElem = document.createElement('script'); 613 | scriptElem.innerHTML = script; 614 | document.body.appendChild(scriptElem); 615 | } 616 | 617 | //注入函数 618 | let insertFunction = function(globalName, params, func){ 619 | let eventName = globalName + '_userevent' + randomInt(10000000, 99999999); 620 | document.addEventListener(eventName, async e => { 621 | //console.log(e); 622 | let promise = func.apply(window, e.params); 623 | e.resolve(await promise); 624 | }); 625 | insertScript(` 626 | window.${globalName} = function(${params}){ 627 | return new Promise(resolve =>{ 628 | let event = document.createEvent('HTMLEvents'); 629 | event.initEvent('${eventName}', true, true); 630 | event.params = Array.from(arguments); 631 | event.resolve = resolve; 632 | document.dispatchEvent(event); 633 | }); 634 | } 635 | `); 636 | } 637 | 638 | //异步,从外面取值 639 | let globalEval = function(code){ 640 | return new Promise(resolve => { 641 | insertFunction('laji_passObject', 'obj', o => { 642 | resolve(o); 643 | }); 644 | insertScript(` 645 | (() => { 646 | try{ 647 | laji_passObject(eval("${code}")); 648 | } 649 | catch(e){ 650 | console.log(e); 651 | laji_passObject(null); 652 | } 653 | finally{ 654 | window.laji_passObject = undefined; 655 | } 656 | })() 657 | `); 658 | }); 659 | } 660 | 661 | insertFunction('laji_baiduFanyiTranslateAsync', 'text, from, to', async(content, from, to) => await baiduFanyi.translate(content, from, to)); 662 | insertFunction('laji_baiduFanyiDetectLangAsync', 'text', async(content) => await baiduFanyi.getLang(content)); 663 | insertFunction('laji_cxhrAsync', 'url, method, dataString', cxhrAsync) 664 | insertFunction('laji_GenerateAndTranslate', '', () => ui.elem.generateButton.click()); 665 | insertFunction('laji_OpenDeepl', '', () => ui.elem.deeplButton.click()); 666 | 667 | 668 | //load wordlist 669 | console.log('get wordlist'); 670 | //wordsEnglish = await getWordList('https://github.com/first20hours/google-10000-english/raw/master/google-10000-english-no-swears.txt'); 671 | wordsChinese = await getWordList('https://gist.github.com/c4d0/47b712b20ac1f85724048d500909d1cc/raw/904236c3c1fecf348b9757b7d705ac9ba40bf655/chinese_10000words'); 672 | 673 | 674 | baiduFanyi.initialize(); 675 | 676 | 677 | //setup ui 678 | let smallWindow = document.createElement('div'); 679 | smallWindow.id = 'laji_root'; 680 | smallWindow.style['position'] = 'fixed'; 681 | smallWindow.style['left'] = '0'; 682 | smallWindow.style['top'] = '0'; 683 | //smallWindow.style['width'] = '200px'; 684 | //smallWindow.style['height'] = '100px'; 685 | smallWindow.style['background-color'] = '#fff'; 686 | smallWindow.style['border-width'] = '2px'; 687 | smallWindow.style['border-style'] = 'solid'; 688 | smallWindow.style['border-color'] = '#888'; 689 | smallWindow.style['border-radius'] = '5px'; 690 | smallWindow.style['padding'] = '4px'; 691 | smallWindow.style['z-index'] = '100000'; 692 | smallWindow.style['display'] = 'none'; 693 | smallWindow.style['user-select'] = 'none'; 694 | ui.initialize(smallWindow, uiConfig); 695 | ui.loadInput(); 696 | document.body.appendChild(smallWindow); 697 | console.log(ui); 698 | 699 | 700 | 701 | //drag window 702 | let startX = 0, startY = 0; 703 | let currentX = 0, currentY = 0; 704 | let isMouseDown = false; 705 | smallWindow.addEventListener('mousedown', e =>{ 706 | if (e.target.tagName == "TEXTAREA" || e.target.tagName == "BUTTON" || e.target.tagName == "INPUT") return; 707 | startX = e.pageX; 708 | startY = e.pageY; 709 | isMouseDown = true; 710 | }); 711 | document.addEventListener('mousemove', e =>{ 712 | if (!isMouseDown) return; 713 | currentX += e.pageX - startX; 714 | currentY += e.pageY - startY; 715 | startX = e.pageX; 716 | startY = e.pageY; 717 | smallWindow.style['left'] = currentX + 'px'; 718 | smallWindow.style['top'] = currentY + 'px'; 719 | 720 | }); 721 | document.addEventListener('mouseup', e =>{ 722 | isMouseDown = false; 723 | }); 724 | 725 | //hotkey 726 | document.addEventListener('keydown', e =>{ 727 | if (e.keyCode == 82 && e.altKey && e.shiftKey){ 728 | smallWindow.style['display'] = smallWindow.style['display'] == 'none' ? '' : 'none'; 729 | } 730 | }); 731 | 732 | smallWindow.style['display'] = ''; 733 | 734 | //获取独轮车接口 735 | dulunche = await globalEval('window.dulunche'); 736 | if (dulunche != null){ 737 | dulunche.eventBus.on('dlc.run', ()=>{ 738 | dlcIsRunning = true; 739 | if (ui.elem.autoDLC.checked && ui.elem.dynamicReload.checked) { 740 | sendToDlc(ui.elem.resultText.value); 741 | } 742 | }); 743 | dulunche.eventBus.on('dlc.stop', ()=>{ 744 | dlcIsRunning = false; 745 | }); 746 | } 747 | else{ 748 | console.log('randomsentencegenerator: 未找到独轮车'); 749 | } 750 | 751 | 752 | })(); 753 | --------------------------------------------------------------------------------