├── 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 | 
44 |
45 | 放一张增强全开的生成结果图
46 |
47 | 
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 |
--------------------------------------------------------------------------------