您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
6/1/2020, 1:51:50 PM
// ==UserScript== // @name Reslator - LNMTL Plugin // @author Spawner // @version 1.2.7 // @namespace reader_translators // @match https://lnmtl.com/chapter/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @license MIT // @run-at document-start // @connect fanyi.sogou.com // @connect fanyi.baidu.com // @connect test.niutrans.vip // @connect translate.googleapis.com // @connect fanyi.yeekit.com // @require http://code.jquery.com/jquery-3.4.1.min.js // @description 6/1/2020, 1:51:50 PM // ==/UserScript== /* | Plugin : Reslator | Version : 1.2.7 | Author : Spawner | Description : Reader & Translator, which gives the user a better experience. CHANGELOG : 1.0 - Initial release 1.1 - Add Glossary support 1.2 - + Fixed : Word higlighter + Raw on click delay 1.2.1 - Fixed comments section 1.2.2 - + Improve performance + Fixing a small issue in the glossary 1.2.3 - + Performance improvement + Add secondary theme switcher + Save raw/original text state 1.2.4 - Improve baidu speed + Fix translation display 1.2.5 - Fix niutrans API 1.2.6 - Added a new provider 1.2.7 - + Navigation between chapters has become much smoother. + Changing the main font of the reader for a better a better one. + Adding a font size controller. + Fixed font delay problem. */ let iframeHandler; let uniqueWords = new Map(); let autoThemeState = GM_SuperValue.get( 'autoThemeState' , false ); let autoReaderState = GM_SuperValue.get( 'autoReaderState', false ); let autoRawState = GM_SuperValue.get( 'autoRawState' , false ); let providerOriginalState = GM_SuperValue.get( 'providerOriginalState', false ); let providerGoogleState = GM_SuperValue.get( 'providerGoogleState' , false ); let providerSogouState = GM_SuperValue.get( 'providerSogouState' , false ); let providerNiutransState = GM_SuperValue.get( 'providerNiutransState', false ); let providerBaiduState = GM_SuperValue.get( 'providerBaiduState' , false ); let providerYeekitState = GM_SuperValue.get( 'providerYeekitState' , false ); let secondaryTheme = GM_SuperValue.get( 'secondaryTheme' , "" ); let fontSizeValue = GM_SuperValue.get( 'fontSizeValue' , "" ); let fontSizeValueDefault = GM_SuperValue.get( 'fontSizeValueDefault' , "" ); const providers = [ "Google", "Sogou", "Niutrans", "Baidu", "Yeekit" ]; let isTranslated = { Google : [providerGoogleState , false], Niutrans : [providerNiutransState, false], Sogou : [providerSogouState , false], Baidu : [providerBaiduState , false], Yeekit : [providerYeekitState , false] }; const providerObject = { Google: { maxSize : 5000, timeout : 0, color : ['48, 175, 219', 0.04] }, Niutrans: { maxSize : 4000, timeout : 400, color : ['235, 77, 75', 0.06] }, Sogou: { maxSize : 4000, timeout : 1700, color : ['255, 164, 58', 0.06] }, Baidu: { maxSize : 2000, timeout : 30, color : ['140, 122, 230', 0.1] }, Yeekit: { maxSize : 4000, timeout : 500, color : ['120, 224, 143', 0.1] }, DeepL: { maxSize : 4000, timeout : 500, color : ['75, 75, 75', 0.1] }, } /** * Show text * * If no translation is enabled, show the original text * otherwise hide it. */ if( !providerGoogleState && !providerSogouState && !providerNiutransState && !providerBaiduState ) providerOriginalState = true; if( fontSizeValue === "" || fontSizeValueDefault === "" ) { fontSizeValue = "20"; fontSizeValueDefault = "19"; } /** * Apply the theme properly. * * The reason to set the display as 'none' and opacity as '0' * is to avoid the iframe onload screen flash, we also need to hide the scrollbar * since we will be using the iframe one. */ if ( autoReaderState ) { GM_addStyle( ` html { background-color : ${autoThemeState ? '#E9E9E9' : '#25282F'}; } #app { display : none; opacity : 0; overflow-y : hidden; } ` ); } /* * Initializing our CSS Styles * * The iframe ( #pageContainer ) needs to be created at document-start * to avoid any performance issues. */ GM_addStyle( ` #pageContainer, #pagePreload { font-family : Open sans; position : fixed; top : 0px; left : 0px; overflow-y : scroll; width : 100%; height : 100%; display : block; border-width : 0px; } `); /* * Global variables for theme & settings Colors * * Using the :root selector to easily * switch between colors. */ let CSSRoot = ` :root { --background-color : #E9E9E9; --close-btn-back-color : #fff; --close-btn-fore-color : #000; --title-color : #000; --chapter-color : #000; --raw-color : #424242; --settings-t-clicked-color : #E9E9E9; --settings-label-color : rgba(51, 47, 53, 0.4); --settings-check-back-color : linear-gradient(to right, #000000, #434343); --checked-background : #029992; --checked-background-rgb : 2, 153, 146; } [data-theme="dark"] { --background-color : #25282F; --close-btn-back-color : #000; --close-btn-fore-color : #fff; --title-color : #fff; --chapter-color : #E9E9E9; --raw-color : #424242; --settings-t-clicked-color : #25282F; --settings-label-color : #E9E9E9; --settings-check-back-color : #E9E9E847; --checked-background : #029992; --checked-background-rgb : 2, 153, 146; } [data-sec-theme="gold"] { --checked-background : #F39B3A; --checked-background-rgb : 243, 155, 58; } [data-sec-theme="moon"] { --checked-background : #9c88ff; --checked-background-rgb : 156, 136, 255; } [data-sec-theme="bomb"] { --checked-background : #eb4d4b; --checked-background-rgb : 235, 77, 75; } [data-sec-theme="default"] { --checked-background : #029992; --checked-background-rgb : 2, 153, 146; } `; /* * Our iframe body styles * * Note : To avoid the scroll flickering issue we will * be using will-change : transform as a temporary solution. */ let CSSContainer = ` html { background-color : var(--background-color); } @keyframes fadein { from { opacity : 0; } to { opacity : 1; } } .chapterBody { position : relative !important; font-family : "Source Sans Pro" !important; text-align : justify !important; animation : fadein 3s; will-change : transform; overflow : visible; color : var(--chapter-color); max-width : 72%; min-height : 100%; margin : 0 auto; padding-bottom : 80px; } .pageContainerBackground { animation : fadein 1s; min-height : 100%; } .pageContainerSettings { transition : all 0.35s ease-in-out; background-color : transparent !important; margin : auto; } .pageSplit { animation : fadein 3s; border-bottom : 1px solid rgba(var(--checked-background-rgb), 0.3) !important; /*margin : 0px 0px 10px;*/ } h1.header-title { color : var(--checked-background); animation : fadein 3s; font-family : Poppins; font-weight : 300; font-size : 2.25em; text-align : center; padding-bottom : .3em; line-height : 1.2; margin : 3em auto .2em; color : var(--title-color); text-shadow : 0 0 4px rgba(0, 0, 100,.5); } `; let CSSForm = ` .settingsForm { will-change : transform; position : relative; justify-content : center; margin-left : -16; margin-top : 20; flex-wrap : wrap; } form { font-size : 13px; letter-spacing : .2em; font-family : sans-serif; display : flex; margin-top : 0em; } label { user-select : none; color : var(--settings-label-color); text-transform : uppercase; font-family : sans-serif; display : flex; font-weight : bold; padding : 7px 16px; /* margin-right : -4px; */ } input[type=checkbox], input[type=radio] { color : #000; position : normal; visibility : hidden; display : none; } input[type=checkbox][value=o-translator-p]:checked+label { background : #fff; cursor : pointer; } input[type=checkbox][value=o-translator-p]:hover+label { color : #000; cursor : pointer; } input[type=checkbox][value=g-translator-p]:checked+label { color : #fff; background : var(--settings-check-back-color); cursor : pointer; } input[type=checkbox][value=s-translator-p]:checked+label { color : #fff; background : var(--settings-check-back-color); cursor : pointer; } input[type=checkbox][value=n-translator-p]:checked+label { color : #fff; background : var(--settings-check-back-color); cursor : pointer; } input[type=checkbox][value=b-translator-p]:checked+label { color : #fff; background : var(--settings-check-back-color); cursor : pointer; } input[type=checkbox][value=y-translator-p]:checked+label { color : #fff; background : var(--settings-check-back-color); cursor : pointer; } input[type=checkbox][name=g-translator-p]:checked+label, input[type=radio][name=g-translator-p]:checked+label { color : #fff; background : #000; cursor : pointer; } input[type=checkbox]+label:hover, input[type=radio]+label:hover { /* transition : all 0.25s ease-in-out; */ color : #fff; cursor : pointer; } input[type=checkbox]+label, input[type=radio]+label { transition : all 0.15s cubic-bezier(0.4, 0, 0.6, 1) 0s; background : var(--settings-t-clicked-color); color : #545454; } input[type=radio][value=raw]:checked+label { color : #fff; background : #7DD7FB; cursor : default; } input[type=radio][value=mode-enabled]:checked+label { transition : all 200ms ease; background : var(--checked-background); color : #fff; cursor : default; } input[type=radio][value=mode-disabled]:checked+label { background : #25282F; color : #fff; cursor : default; } input[type=radio][value=theme-enabled]:checked+label { background : #fff; color : #000; cursor : default; } input[type=radio][value=theme-disabled]:checked+label { background : #000; color : #fff; cursor : default; } .radio-group, .checkbox-group { font-size : 9px; letter-spacing : .2em; border : solid 0px rgb(125, 214, 255); display : flex; margin : 0px 0px 30px; border-radius : 20px; overflow : hidden; box-shadow : rgba(0, 0, 0, 0.3) 0px 8px 16px 0px; opacity : 0.7; } .radio-group:hover, .checkbox-group { opacity : 1; transition : 1.0s; } `; let CSSChapterBody = ` .sentence { animation : fadein 2s; } .sentence.or { margin-block-end: -0.5em !important; word-spacing : 1px; text-align : initial; font-weight : 300; line-height : 1.7; margin-top : 3.1em; font-size : 20px; } .sentence.google.default { padding : 0px; background : transparent; border-left-style : none; word-spacing : 1px; text-align : initial; font-weight : 300; line-height : 1.7; margin-top : 3.1em; font-size : 20px; } .sentence.sogou.default { padding : 0px; background : transparent; border-left-style : none; word-spacing : 1px; text-align : initial; font-weight : 300; line-height : 1.7; margin-top : 3.1em; font-size : 20px; } .sentence.niutrans.default { padding : 0px; background : transparent; border-left-style : none; word-spacing : 1px; text-align : initial; font-weight : 300; line-height : 1.7; margin-top : 3.1em; font-size : 20px; } .sentence.baidu.default { padding : 0px; background : transparent; border-left-style : none; word-spacing : 1px; text-align : initial; font-weight : 300; line-height : 1.7; margin-top : 3.1em; font-size : 20px; } .sentence.yeekit { margin-block-end: -0.5em !important; word-spacing : 1px; text-align : initial; animation : fadein 0.4s; line-height : 1.7; font-size : 17px; border-left-style : solid; border-color : transparent transparent transparent rgb(${providerObject["Yeekit"]["color"][0]}); padding : 10 10px; background : rgba(${providerObject["Yeekit"]["color"][0]}, ${providerObject["Yeekit"]["color"][1]}); margin : 25 0; } .sentence.yeekit.default { padding : 0px; background : transparent; border-left-style : none; word-spacing : 1px; text-align : initial; font-weight : 300; line-height : 1.7; margin-top : 3.1em; font-size : 20px; } .sentence.sogou { margin-block-end: -0.5em !important; word-spacing : 1px; text-align : initial; animation : fadein 1s; line-height : 1.7; font-size : 17px; border-left-style : solid; border-color : transparent transparent transparent rgb(${providerObject["Sogou"]["color"][0]}); padding : 10 10px; background : rgba(${providerObject["Sogou"]["color"][0]}, ${providerObject["Sogou"]["color"][1]}); margin : 25 0; } .sentence.google { margin-block-end: -0.5em !important; word-spacing : 1px; text-align : initial; animation : fadein 1s; line-height : 1.7; font-size : 18px; border-left-style : solid; border-color : transparent transparent transparent rgb(${providerObject["Google"]["color"][0]}); padding : 10 10px; background : rgba(${providerObject["Google"]["color"][0]}, ${providerObject["Google"]["color"][1]}); margin : 25 0; } .sentence.niutrans { margin-block-end: -0.5em !important; animation : fadein 1s; line-height : 1.7; font-size : 18px; border-left-style : solid; border-color : transparent transparent transparent rgb(${providerObject["Niutrans"]["color"][0]}); padding : 10 10px; background : rgba(${providerObject["Niutrans"]["color"][0]}, ${providerObject["Niutrans"]["color"][1]}); margin : 25 0; } .sentence.baidu { margin-block-end: -0.5em !important; word-spacing : 1px; text-align : initial; animation : fadein 1s; line-height : 1.7; font-size : 18px; border-left-style : solid; border-color : transparent transparent transparent rgb(${providerObject["Baidu"]["color"][0]}); padding : 10 10px; background : rgba(${providerObject["Baidu"]["color"][0]}, ${providerObject["Baidu"]["color"][1]}); margin : 25 0; } .sentence.deepl { margin-block-end: -0.5em !important; word-spacing : 1px; text-align : initial; animation : fadein 1s; line-height : 1.7; font-size : 18px; border-left-style : solid; border-color : transparent transparent transparent rgb(${providerObject["DeepL"]["color"][0]}); padding : 10 10px; background : rgba(${providerObject["DeepL"]["color"][0]}, ${providerObject["DeepL"]["color"][1]}); margin : 25 0; } .sentence.edit { overflow: hidden; background: none; outline: none; resize: none; margin-block-end: -0.5em !important; word-spacing: 1px; text-align: initial; animation: fadein 0.5s; line-height: 1.7; font-size: 18px; border-left-style: solid; padding: 10 20px; margin: 25 0; background-color: var(--background-color); box-shadow: 0 10px 10px 0 rgba(0, 0, 0, 0.1), 0 0 1px 0 rgba(0, 0, 0, 0.2); color: var(--title-color); border-radius: 13px; border-left-color: var(--checked-background); } .original { display : inline; word-spacing : 1px; text-align : initial; font-weight : 600; font-size : 19px; /*margin-bottom : 3.8em;*/ color : var(--checked-background); } .highlighter { font-weight : 500; /*animation : fadein 1s;*/ } `; let CSSTooltip = ` .tooltip { position : relative; display : inline; } .tooltip .tooltip-text { visibility : hidden; width : 120px; background-color : #555; color : #fff; text-align : center; /* border-radius : 6px; */ padding : 3px 0; position : absolute; z-index : 1; opacity : 0; transition : opacity 0.3s; } /* Tooltip top content */ .top .tooltip-text { bottom : 100%; left : 50%; margin-left : -60px; /* 120/2 = 60 */ } .tooltip .tooltip-text::after { content : ""; position : absolute; border-width : 5px; border-style : solid; } /* Tooltip top arrow */ .top .tooltip-text::after { margin-left : -5px; left : 50%; top : 100%; border-color : var(--checked-background) transparent transparent transparent; } .tooltip:hover .tooltip-text { visibility : visible; opacity : 1; } .highlighter-default { /* animation : fadein 1s; */ /* font-weight : 600; */ } `; let CSSNextPrevArrow = ` .arrow { position : fixed; top : 90%; width : 4vmin; height : 4vmin; background : transparent; border-top : 1vmin solid gray; border-right : 1vmin solid black; box-shadow : 0 0 0 black; transition : all 200ms ease; opacity : 0.4; } .arrow.left { cursor : pointer; /* left : 55px; */ right : 3%; top : 88%; transform : translate3d(0, -50%, 0) rotate(-135deg); } .arrow.right { cursor : pointer; right : 4%; top : 78%; transform : translate3d(0,-50%,0) rotate(45deg); } .arrow:hover { border-color : #2d3436; box-shadow : 0.5vmin -0.5vmin 0 white; opacity : 1; } .arrow: before { content : ''; position : absolute; top : 50%; left : 50%; transform : translate(-40%,-60%) rotate(45deg); width : 200%; height : 200%; } `; let CSSCloseBtn = ` .close-button { box-shadow : rgba(0, 0, 0, 0.4) 0px 8px 16px 0px; width : 5vmin; height : 5vmin; box-shadow : 0px 10 10px 10px rgba(0, 0, 0, 0.25); border-radius : 50%; background : var(--close-btn-back-color); position : fixed; right : 3.6%; top : 67%; display : block; z-index : 200; text-indent : -9999px; cursor : pointer; } .close-button:before, .close-button:after { content : ''; width : 55%; height : 2px; background : var(--close-btn-fore-color); position : absolute; top : 48%; left : 22%; -webkit-transform : rotate(-45deg); -moz-transform : rotate(-45deg); -ms-transform : rotate(-45deg); -o-transform : rotate(-45deg); transform : rotate(-45deg); -webkit-transition: all 0.3s ease-out; -moz-transition : all 0.3s ease-out; -ms-transition : all 0.3s ease-out; -o-transition : all 0.3s ease-out; transition : all 0.3s ease-out; } .close-button:after { -webkit-transform : rotate(45deg); -moz-transform : rotate(45deg); -ms-transform : rotate(45deg); -o-transform : rotate(45deg); transform : rotate(45deg); -webkit-transition: all 0.3s ease-out; -moz-transition : all 0.3s ease-out; -ms-transition : all 0.3s ease-out; -o-transition : all 0.3s ease-out; transition : all 0.3s ease-out; } .close-button:hover:before, .close-button:hover:after { -webkit-transform: rotate(180deg); -moz-transform : rotate(180deg); -ms-transform : rotate(180deg); -o-transform : rotate(180deg); transform : rotate(180deg); } `; let CSSBtnTheme = ` .fa, .fab, .fal, .far, .fas { line-height: 0; } ul { animation: fadein 2s; padding: 0; position: relative; margin: 0 0 100 0; transform: scale(0.65); justify-content: start; display: inline-block; flex-direction: row; flex-wrap: nowrap; /* justify-content: end; */ align-items: unsafe; /* align-content: end; */ margin: 0 -5vmin; /* margin: 0 500px; */ /* margin-bottom: 7.8em !important; */ padding-inline-start: 0px !important; display: inline-flex; flex-direction: row; flex-wrap: nowrap; justify-content: flex-start; align-items: baseline; align-content: stretch; } ul li { animation : fadein 1s; list-style : none; margin : 0 7px; display : block; } ul li:after, .rr-font--update.rr-inc:after { pointer-events: none; content: ""; position: absolute; top: -140px; bottom: -230px; right: 0; z-index: 10; /* padding-left: 320; */ border-right: 1.0px solid rgba(var(--checked-background-rgb), 0.3); transform: rotate(30deg); } ul li a { position : relative; display : list-item; width : 60px; height : 60px; text-align : center; line-height : 63px; background : var(--background-color); border-radius: 50%; font-size : 35px; color : darkgray; transition : .5s; } ul li a:hover { cursor : pointer; } ul li a::before { content : ''; position : absolute; top : 0; left : 0; width : 100%; height : 100%; border-radius: 50%; background : #009992; transition : .5s; transform : scale(.9); z-index : -1; } ul li a:hover { color : black; } ul li a:hover::before { transform : scale(1.1); background: #009992; } ul li:nth-child(1) a::before { background: #ffee10; } ul li:nth-child(1) a:hover::before { box-shadow: 0 0 10px #e67e22; } ul li:nth-child(1) a:hover { box-shadow : 0 0 5px #e67e22; text-shadow: 0 0 5px #e67e22; } ul li:nth-child(2) a::before { background: #95a5a6; } ul li:nth-child(2) a:hover::before { box-shadow: 0 0 10px #9b59b6; } ul li:nth-child(2) a:hover { box-shadow : 0 0 5px #9b59b6; text-shadow: 0 0 5px #9b59b6; } ul li:nth-child(3) a::before { background: #e74c3c; } ul li:nth-child(3) a:hover::before { box-shadow: 0 0 10px #e74c3c; } ul li:nth-child(3) a:hover { box-shadow : 0 0 5px #e74c3c; text-shadow: 0 0 5px #e74c3c; } ul li:nth-child(4) a:hover::before { box-shadow: 0 0 10px #029992; } ul li:nth-child(4) a:hover { box-shadow : 0 0 5px #029992; text-shadow: 0 0 5px #029992; } /*ul li a { color: transparent; }*/ `; let CSSTagBtn = ` .settings-container { animation: fadein 3s; overflow: hidden; border-bottom: 1px solid rgba(var(--checked-background-rgb), 0.3); margin-bottom: 150px; display: flex; flex-direction: row; flex-wrap: nowrap; justify-content: flex-start; align-items: center; align-content: stretch; } .raw-block { /* margin-bottom: 4.8em; */ margin: 16px 0; /* display: -webkit-box; */ align-items: center; margin-bottom: 4.5em; } .tag-num { user-select : none; font-size : 10px; line-height : 18px; position : relative; display : inline-flex; height : 18px; padding : 0 6px; letter-spacing: .25px; color : black; border-radius : 18px; background : #c0c2cc; margin : 0 7px; } .tag-num:hover { cursor : pointer; transition : all 400ms ease; background : black; color : white; } .rr-font--update.rr-dec { font-size: 15px; margin-left: 30px; } .rr-font--update.rr-inc { font-size: 22px; margin-right: 20px; position: relative; margin-left: 15px; } .rr-font--update.rr-inc:hover { /*transform: scale(1.3);*/ color: var(--checked-background); transition: all 0.3s ease-out; } .rr-font--update.rr-dec:hover { color: var(--checked-background); transition: all 0.3s ease-out; } .rr-font--update { user-select : none; color : darkgray; font-family : Open sans; width : 30px; font-weight : 700; font-size : 18px; cursor : pointer; } .btn-custom { font-family: "Source sans Pro"; outline: 0; border-radius: 16px; border: 1px solid var(--checked-background); background: transparent; color: var(--checked-background); width: 120px; height: 24px; cursor: pointer; text-transform: uppercase; margin-left: 30px; } .btn-custom:hover { transition: background 0.3s ease-in-out; background: white; } #font-indicator { color: var(--checked-background); font-family: Source sans pro; font-weight: 600; } .sentence.or,[class^="default"] { font-size: ${fontSizeValue}; } [class^="sentence"]:not(.or) { font-weight: 300; font-size: ${fontSizeValueDefault}; } `; /* | Plugin Mobile support. */ let CSSMediaQuery = ` @media only screen and (max-width: 600px) { label { display: inline-block; font-size: 95%; } .radio-group, .checkbox-group { display: grid; } .chapterBody { margin: 7%;max-width: 82%; } .sentence.or { font-size: 92%; text-align: initial; font-weight: 300; } .settingsForm { flex-wrap: wrap; display: contents; } .original { font-size: 87%; text-align: initial; font-weight: 500; } .sentence.google { font-size: 87%; text-align: initial; font-weight: 300; } .sentence.google.default { font-size: 92%; text-align: initial; font-weight: 300; } .sentence.niutrans { font-size: 87%; text-align: initial; font-weight: 300;} .sentence.niutrans.default { font-size: 92%; text-align: initial; font-weight: 300; } .sentence.baidu { font-size: 87%; text-align: initial; font-weight: 300; } .sentence.baidu.default { font-size: 92%; text-align: initial; font-weight: 300; } .sentence.sogou { font-size: 87%; text-align: initial; font-weight: 300; } .sentence.sogou.default { font-size: 92%; text-align: initial; font-weight: 300; } .sentence.yeekit { font-size: 87%; text-align: initial; font-weight: 300; } .sentence.yeekit.default { font-size: 92%; text-align: initial; font-weight: 300; } .close-button { max-width: 7vmin; max-height: 7vmin; min-width: 7vmin; min-height: 7vmin; right: 3%; top: 57%; background: #393A3D; border-radius: 50%; } .close-button:before, .close-button:after { background:white; } .arrow.left { top: 76%; } .arrow.right { top: 68%; right: 5%; } .tooltip { display: inline; } h1.header-title { font-size: 150% } .rr-font--update.rr-dec { font-size: 15px !important; margin-left: 35px !important; } .rr-font--update.rr-inc { margin-right: 15px !important; margin-left: 5px !important; } .btn-custom { height: 54px !important; text-align: center !important;} ul li { margin: 0 12px 4 !important; } ul li:after, .rr-font--update.rr-inc:after { border-right: 2px solid rgba(var(--checked-background-rgb), 1); } ul { animation:fadein 2s;padding:0!important;position:relative!important;margin:0 0 100!important;transform:scale(.65)!important;justify-content:center!important;display:flex!important;flex-direction:row!important;align-items:unsafe!important;margin:0 -10vm!important;margin:0 -10vmin!important;flex-wrap:wrap!important;justify-content:space-evenly!important;align-items:baseline!important;align-content:center!important} } ` ; window.onload = async function () { /* | Adding Glossary support */ await new Promise( resolve => setTimeout( resolve, 10 ) ); if ( $('style[type="text/css"]').text().includes( 'noWordWrapping' ) && !( window.sessionStorage.getItem("userjs_UGMTLComplete") && window.sessionStorage.getItem("userjs_UGMTLComplete") > window.performance.timing.fetchStart ) ) { await new Promise ( resolve => document.addEventListener( 'userjs_UGMTLComplete' , resolve ) ); } else { /* | Swaping Chinese/English words to have a better translation. */ mainBodyWordsReplacer( ); } /* | Inject the iframe to the DOM. */ $( '#app' ).get( 0 ).insertAdjacentHTML( 'afterEnd', `<iframe id="pageContainer" style="display:${autoReaderState ? 'block' : 'none'}">` ); /* | Get raw & original text from main page. */ const originalSentences = $( '.chapter-body' ).find( '.translated' ).text().replace( /(\xAD)/g, '' ).trim().split( '\n' ); const originalRaw = $( '.chapter-body' ).find( '.original' ).text().trim().split( '\n' ); const chapterTitle = $( '.chapter-title' )[ 0 ].textContent; /* | Add a button for the reader mode. */ $( '.js-toggle-original' ).after( '<button class="btn btn-enabled reader-mode">READER MODE</button>' ); $( '.btn.btn-enabled.reader-mode' ).css( 'boxShadow', 'rgb(236, 240, 241) 0px 0px 8px' ); $( '.btn.btn-enabled.reader-mode' ).css( 'color' , 'black' ); /* | Reader btn onClick event. */ $( '.reader-mode' ).click( function () { $( '#app' ).css( { 'display': 'none', 'opacity': '0' } ); $( '#pageContainer' ).show(); } ); /* | We will need this for the tooltip & highlighting words. | The values produces non-ut8 characters so we must remove them | so that there will be no problem replacing them using regex. */ $( '.translated t' ).each( function ( index ) { let chineseValue = $( this ).attr( 'data-title' ); let value = $( this ) .attr( 'data-title', $( this ).text() ) .text() .trimLeft() ; const replacedValue = value.replace( /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/(\xAD)]/g, '' ); if( replacedValue != "" || replacedValue.length != 0 ) uniqueWords.set( replacedValue , chineseValue ); } ); /* | This what will be using to control the iframe DOM */ iframeHandler = $( "#pageContainer" ).contents(); /* | Toggle theme state. */ autoThemeState ? iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-theme', 'light' ) : iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-theme', 'dark' ) ; /* | Append the needed styles for the iframe. */ addStyles( ); /* | Add iframe form. */ addForm( ); /* | Apply secondary theme. */ iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-sec-theme', secondaryTheme ); /* | Toggle secondary colors. */ iframeHandler.find( '.drag' ).click( function() { iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-sec-theme', 'gold' ); GM_SuperValue.set( 'secondaryTheme', "gold" ); }); iframeHandler.find( '.moon' ).click( function() { iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-sec-theme', 'moon' ); GM_SuperValue.set( 'secondaryTheme', "moon" ); }); iframeHandler.find( '.bomb' ).click( function() { iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-sec-theme', 'bomb' ); GM_SuperValue.set( 'secondaryTheme', "bomb" ); }); iframeHandler.find( '.norm' ).click( function() { iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-sec-theme', 'default' ); GM_SuperValue.set( 'secondaryTheme', "" ); }); /* | If one provider is running then removed color/border translation identifier. */ iframeHandler.find( "input[name='items[]']" ).change(function(e) { onlyOneRunning(); }); for( let index in providers ) { let provider = providers[ index ]; if( eval( 'provider' + provider + 'State' ) ) { providerSelector( originalRaw, provider.toLowerCase() , providerObject[ provider ][ "maxSize" ] ); } } iframeHandler.find( '.close-button' ).click( function () { $( '#app' ).css( { 'display': 'block', 'opacity': '1', 'overflow-y': 'scroll' } ); $( '#pageContainer' ).hide(); } ); /* | Hooking next/prev page on click | Replacing href results a bug, so I'll be using this approach. */ iframeHandler.find( '.arrow.right' ).click( function () { window.location.assign( $( this ).attr( 'value' ) ); } ); iframeHandler.find( '.arrow.left' ).click( function () { window.location.assign( $( this ).attr( 'value' ) ); } ); /* | Add original and raw text ( with display:none ) | Also there is a non-utf8 coming out of nowhere so we must clean that */ for ( let i in originalSentences ) { for ( const [key, value] of uniqueWords.entries() ) { originalSentences[i] = originalSentences[i].replace ( new RegExp( '(?<![<>])(' + key + ')(?![<>])' , 'g' ), `<span class="highlighter"><div class="tooltip top">$&<span class="tooltip-text">${value}</span></div></span>` ) ; } iframeHandler.find( '.chapterBody' ).append( `<div class="sentence or">${originalSentences[i]}</div>` ); iframeHandler.find( '.chapterBody' ).append( `<div class="raw-block"><p class="original">${originalRaw[i]}</p><a class="tag-num">${i}</a></div>` ); } if( !autoRawState ) iframeHandler.find( '.raw-block' ).hide(); if ( !providerOriginalState ) iframeHandler.find( '.sentence.or' ).hide(); // Should be optimized... iframeHandler.find( '.rr-dec' ).click( function() { let currentFontSize = parseInt( iframeHandler.find( '.sentence.or,[class^="default"]' ).css('font-size') ) - 1; let currentFontSizeDefault = parseInt( iframeHandler.find( '[class^="sentence"]:not(.or,.default)' ).css('font-size') ) - 1; if ( currentFontSize <= 17 ) return; iframeHandler.find( '[class^="sentence"]:not(.or)' ).css( 'font-size', currentFontSizeDefault ); iframeHandler.find( '.sentence.or,[class^="default"]' ).css( 'font-size', currentFontSize ); iframeHandler.find( '#font-indicator' ).text( currentFontSize ); GM_SuperValue.set( 'fontSizeValueDefault', currentFontSizeDefault ); GM_SuperValue.set( 'fontSizeValue', currentFontSize ); } ); iframeHandler.find( '.rr-inc' ).click( function() { let currentFontSize = parseInt( iframeHandler.find( '.sentence.or,[class^="default"]' ).css('font-size') ) + 1; let currentFontSizeDefault = parseInt( iframeHandler.find( '[class^="sentence"]:not(.or,.default)' ).css('font-size') ) + 1; if ( currentFontSize >= 30 ) return; iframeHandler.find( '[class^="sentence"]:not(.or)' ).css( 'font-size', currentFontSizeDefault ); iframeHandler.find( '.sentence.or' ).css( 'font-size', currentFontSize ); iframeHandler.find( '#font-indicator' ).text( currentFontSize ); GM_SuperValue.set( 'fontSizeValueDefault', currentFontSizeDefault ); GM_SuperValue.set( 'fontSizeValue', currentFontSize ); } ); providerChangedEvent( originalRaw ); settingsChangedEvent( ); iframeHandler.find( '.btn-custom' ).on( 'click', function() { let self = $( this ); let stringBuilder = `${chapterTitle}\n\n\n`; self.text( 'Copied ;-)' ); setTimeout( function ( ) { self.text( 'Copy Edited Text' ); }, 600 ); let rawEdits = iframeHandler.find( '.sentence.edit' ).toArray( ).map( ( p ) => p.textContent ); for ( let index in rawEdits ) { stringBuilder += `${rawEdits[ index ]}\n\n\n`; } window.navigator.clipboard.writeText( stringBuilder ); } ); iframeHandler.find( '.tag-num' ).on( 'click', function() { let index = parseInt( this.textContent ); if ( $( this ).attr( 'value' ) ) { iframeHandler.find( '.tag-num' ).eq( index ).next( ).filter( '.sentence.edit' ).fadeToggle( 200 ); return; } iframeHandler.find( '.raw-block' ).eq( index ).append( '<div class="sentence edit" contenteditable="plaintext-only" spellcheck="false"/>' ); $( this ).attr( 'value', 'clicked' ); } ); } function addStyles() { iframeHandler.find( 'head' ).append( $ ( ` <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="preload" onload="this.rel = 'stylesheet'" as="style" href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600|Poppins|Source+Sans+Pro:300,400,500,600'> <link rel="preload" onload="this.rel = 'stylesheet'" as="style" href='https://use.fontawesome.com/releases/v5.6.3/css/all.css'> ${$( '.next > a' ).attr( 'href' ) != undefined ? `<link rel="prefetch" href="${$( '.next > a' ).attr( 'href' )}">` : '' } <style type='text/css'> ${CSSRoot} ${CSSContainer} ${CSSCloseBtn} ${CSSForm} ${CSSChapterBody} ${CSSTooltip} ${CSSNextPrevArrow} ${CSSMediaQuery} ${CSSBtnTheme} ${CSSTagBtn} </style> ` ) ); } function addForm( ) { const chapterTitle = $( '.chapter-title' )[ 0 ].textContent.split( ':' ); const readerState = autoReaderState ? '' : 'checked'; const themeState = autoThemeState ? '' : 'checked'; const rawState = autoRawState ? '' : 'checked'; const pageNext = $( '.next > a' ).attr( 'href' ); const pagePrevious = $( '.previous > a' ).attr( 'href' ); const nextChapterButton = pageNext != null ? ( '<a value="' + pageNext + '" class="arrow right"></a>' ) : ''; const prevChapterButton = pagePrevious != null ? ( '<a value="' + pagePrevious + '" class="arrow left"></a>' ) : ''; const isOriginalEnabled = providerOriginalState ? 'checked' : ''; const isGoogleEnabled = providerGoogleState ? 'checked' : ''; const isSogouEnabled = providerSogouState ? 'checked' : ''; const isNiutransEnabled = providerNiutransState ? 'checked' : ''; const isBaiduEnabled = providerBaiduState ? 'checked' : ''; const isYeekitEnabled = providerYeekitState ? 'checked' : ''; iframeHandler.find( 'body' ).append ( ` <div id="clean-reader"> <div class="pageContainerBackground"> <a class="close-button">Close</a> ${prevChapterButton} ${nextChapterButton} <form class="settingsForm"> <label>Provider</label> <div class="radio-group"> <input type="checkbox" id="Original-translator" value="o-translator-p" name="items[]" ${isOriginalEnabled}> <label for="Original-translator">Original</label> <input type="checkbox" id="Google-translator" value="g-translator-p" name="items[]" ${isGoogleEnabled}> <label for="Google-translator"><span style="color:rgb(${providerObject["Google"]["color"][0]});text-shadow: 0 0 3px #30AFDB, 0 0 5px #30AFDB;padding-right: 6">◼ </span> Google</label> <input type="checkbox" id="Sogou-translator" value="s-translator-p" name="items[]" ${isSogouEnabled}> <label for="Sogou-translator"><span style="color:rgb(${providerObject["Sogou"]["color"][0]});text-shadow: 0 0 3px #e74c3c, 0 0 5px #e74c3c;padding-right: 6">◼ </span> Sogou</label> <input type="checkbox" id="Niutrans-translator" value="n-translator-p" name="items[]" ${isNiutransEnabled}> <label for="Niutrans-translator"><span style="color:rgb(${providerObject["Niutrans"]["color"][0]});text-shadow: 0 0 3px #e74c3c, 0 0 5px #e74c3c;padding-right: 6">◼ </span> Niutrans</label> <input type="checkbox" id="Baidu-translator" value="b-translator-p" name="items[]" ${isBaiduEnabled}> <label for="Baidu-translator"><span style="color:rgb(${providerObject["Baidu"]["color"][0]});text-shadow: 0 0 3px #6F68F2, 0 0 5px #6F68F2;padding-right: 6">◼ </span> Baidu</label> <input type="checkbox" id="Yeekit-translator" value="y-translator-p" name="items[]" ${isYeekitEnabled}> <label for="Yeekit-translator"><span style="color:rgb(${providerObject["Yeekit"]["color"][0]});text-shadow: 0 0 3px #6F68F2, 0 0 5px #78e08f;padding-right: 6">◼ </span> Yeekit</label> </div> <label>Raw</label> <div class="radio-group"> <input type="radio" id="option-one-a" name="raw" value="mode-enabled" checked> <label for="option-one-a">Enable</label> <input type="radio" id="option-two-2" name="raw" value="mode-disabled" ${rawState}> <label for="option-two-2">Disable</label> </div> <label>Reader</label> <div class="radio-group"> <input type="radio" id="option-1" name="mode" value="mode-enabled" data-theme="dark" checked> <label for="option-1">Always</label> <input type="radio" id="option-2" name="mode" value="mode-disabled" data-theme="light" ${readerState}> <label for="option-2">Never</label> </div> <label>Theme</label> <div class="radio-group theme"> <input type="radio" id="option-1-1" name="theme" value="theme-enabled" checked> <label for="option-1-1">Light</label> <input type="radio" id="option-2-2" name="theme" value="theme-disabled" ${themeState}> <label for="option-2-2">Dark</label> </div> </form> <h1 class="header-title">${chapterTitle[1]} - <span style="transition : all 200ms ease;color:var(--checked-background);font-weight:bold">${chapterTitle[0].replace( '#', '' )}</h1> <div class="pageSplit"></div> <div class="settings-container"> <ul> <li> <a class="drag"><i class="fab fa-d-and-d"></i></a> </li> <li> <a class="moon"><i class="fas fa-bowling-ball"></i></a> </li> <li> <a class="bomb"><i class="fas fa-bomb"></i></a> </li> <li> <a class="norm"><i class="fas fa-tint"></i> </a> </li> </ul><span class="rr-font--update rr-dec">A-</span><div id="font-indicator">${fontSizeValue}</div><span class="rr-font--update rr-inc">A+</span> <button class="btn-custom">Copy edited text</button></div> <div class="chapterBody"> </div> </div> </div> ` ) ; } function providerChangedEvent ( raws ) { const addEventHandler = ( iframe, provider ) => { const capitalizeProvider = provider.charAt( 0 ).toUpperCase( ) + provider.slice( 1 ); iframe.find( `#${capitalizeProvider}-translator` ).change( function ( ) { GM_SuperValue.set( `provider${capitalizeProvider}State`, this.checked ); this.checked && !isTranslated[ capitalizeProvider ][ 1 ] ? providerSelector( raws, provider, providerObject[ capitalizeProvider ][ 'maxSize' ] ) : iframe.find( `.sentence.${provider}` ).fadeToggle( 300 ) ; } ); }; addEventHandler( iframeHandler, 'google' ); addEventHandler( iframeHandler, 'sogou' ); addEventHandler( iframeHandler, 'niutrans' ); addEventHandler( iframeHandler, 'baidu' ); addEventHandler( iframeHandler, 'yeekit' ); iframeHandler.find( '#Original-translator' ).change( function ( ) { GM_SuperValue.set( 'providerOriginalState', this.checked ); iframeHandler.find( '.sentence.or' ).delay( 100 ).fadeToggle( 100 ); } ); } function settingsChangedEvent ( ) { /* READER CHANGING STATE */ iframeHandler.find( 'input[type=radio][name=mode]' ).change( function ( ) { autoReaderState = $( this ).val( ).includes( 'enabled' ); GM_SuperValue.set( 'autoReaderState', autoReaderState ); } ); /* RAW CHANGING STATE */ iframeHandler.find( 'input[type=radio][name=raw]' ).click( function ( ) { autoRawState = $( this ).val( ).includes( 'enabled' ); GM_SuperValue.set( 'autoRawState', autoRawState ); autoRawState ? iframeHandler.find( '.raw-block' ).delay( 100 ).fadeIn( 300 ) : iframeHandler.find( '.raw-block' ).fadeOut( 200 ); } ); /* THEME CHANGING STATE */ iframeHandler.find( 'input[type=radio][name=theme]' ).click( function ( ) { autoThemeState = $( this ).val( ).includes( 'enabled' ); GM_SuperValue.set( 'autoThemeState', autoThemeState ); autoThemeState ? iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-theme', 'light' ) : iframeHandler.find( ':root' ).eq( 0 ).attr( 'data-theme', 'dark' ); } ); } function onlyOneRunning () { let runningProviders = []; iframeHandler.find( "input[name='items[]']:checked" ).each( function () { runningProviders.push( $( this ).attr( 'id' ).replace( '-translator', '' ).toLowerCase() ); } ); if( runningProviders.length == 1 ) { iframeHandler.find( `.sentence.${ runningProviders[0] }` ).attr( 'class', `sentence ${ runningProviders[0] } default` ); iframeHandler.find( '.highlighter-default' ).css( 'font-weight', '500' ); } else { for( let id in runningProviders ) { iframeHandler.find( `.sentence.${ runningProviders[ id ] }.default` ).attr( 'class', `sentence ${ runningProviders[ id ] }` ); iframeHandler.find( '.highlighter-default' ).css( 'font-weight', '500' ); } } return runningProviders.length; } const disableCheckbox = ( elementId, status ) => iframeHandler.find( elementId ).prop( 'disabled', status ); async function providerSelector ( raw, name, chunksize ) { const taskDelay = ( m ) => new Promise( r => setTimeout( r, m ) ) let translatedChunks = []; let chunks = [] chunks = separateIntoChunks( raw, chunksize ); chunks[0] = chunks[0].trimLeft(); switch ( name ) { case "sogou": { disableCheckbox( '#Sogou-translator', true ); for ( let id in chunks ) { let value = await sogouSetCookies(); translatedChunks[id] = await sogouTranslator( chunks[id], value ); await taskDelay( providerObject["Sogou"]["timeout"] ); } // Translation is finished. isTranslated["Sogou"][1] = true; disableCheckbox( '#Sogou-translator', false ); } break; case "google": { disableCheckbox( '#Google-translator', true ); for ( let id in chunks ) { translatedChunks[id] = await googleTranslator( chunks[id] ); await taskDelay( providerObject["Google"]["timeout"] ); } // Translation is finished. isTranslated["Google"][1] = true; disableCheckbox( '#Google-translator', false ); } break; case "niutrans": { disableCheckbox( '#Niutrans-translator', true ); for ( let id in chunks ) { translatedChunks[id] = await niutransTranslator( chunks[id] ); await taskDelay( providerObject["Niutrans"]["timeout"] ); } // Translation is finished. isTranslated["Niutrans"][1] = true; disableCheckbox( '#Niutrans-translator', false ); } break; case "baidu": { disableCheckbox( '#Baidu-translator', true ); let timer = -performance.now(); const tokens = await baiduReceiveTokens(); for ( let id in chunks ) { translatedChunks[id] = await baiduTranslator( chunks[id], tokens ); await taskDelay( providerObject["Baidu"]["timeout"] ); } timer += performance.now(); console.log( "Time: " + ( timer / 1000 ).toFixed( 5 ) + " sec." ) // Translation is finished. isTranslated["Baidu"][1] = true; disableCheckbox( '#Baidu-translator', false ); } case "yeekit": { disableCheckbox( '#Yeekit-translator', true ); for ( let id in chunks ) { translatedChunks[id] = await yeekitTranslator( chunks[id] ); await taskDelay( providerObject["Yeekit"]["timeout"] ); } // Translation is finished. isTranslated["Yeekit"][1] = true; disableCheckbox( '#Yeekit-translator', false ); } break; } let finalResult = seperateChunksIntoPars( translatedChunks ); createSentence( finalResult, name, onlyOneRunning() ); } function mainBodyWordsReplacer () { $( '.original t' ).each ( function () { const textSpace = $( this ).get( 0 ).previousSibling.nodeName == 'T' ? ' ' : ''; const textValue = $( this ).text( ); $( this ).text( textSpace + $( this ).attr( 'data-title' ) ); $( this ).attr( 'data-title', textValue ); } ); } function createSentence ( paragraphs, provider, runningProviders ) { if( runningProviders == 1 ) { provider.concat( " default" ); } paragraphs.forEach( ( sentence, index ) => { for ( const [key, value] of uniqueWords.entries() ) sentence = sentence.replace( new RegExp( '(?<![<>])(' + key + ')(?![<>])' , 'g' ), `<span class="highlighter-default">$&</span>` ); iframeHandler.find( '.raw-block' ).eq( index ).before( `<p class="sentence ${provider}">` + sentence + '</p>' ); } ); onlyOneRunning( ); } function googleTranslator ( text ) { return new Promise( ( resolve ) => $.ajax( 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=zh-CN&tl=en&dt=t', { method: 'POST', data : { q: text }, dataType: "json" } ).done( ( t ) => { let paragraph = ""; for ( let i = 0; i < t[0].length; i++ ) { paragraph += t[0][i][0]; } resolve( paragraph ); } ) .fail( function( xhr, textStatus, errorThrown ) { GM_SuperValue.set( 'providerGoogleState', false ); disableCheckbox( '#Google-translator', false ); iframeHandler.find( '#Google-translator' ).prop( 'checked', false ); } ) ); } function sogouTranslator ( text, id ) { const userId = () => { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( /[xy]/g, function ( name ) { let M = 0 | 16 * Math.random(); var pid = "x" == name ? M : 8 | 3 & M; return pid.toString( 16 ); } ); }; return new Promise( ( resolve, reject ) => { var formData = { 'from' : 'zh-CHS', 'to' : 'en', 'text' : text, 'client' : 'pc', 'fr' : 'browser_pc', 'pid' : 'sogou-dict-vr', 'dict' : 'true', 'word_group' : 'true', 'second_query': 'true', 'uuid' : userId, 'needQc' : '1', 's' : md5( 'zh-CHS' + 'en' + text + '8511813095152' ) }; GM_xmlhttpRequest( { method : "POST", url : "https://fanyi.sogou.com/reventondc/translateV2", data : $.param( formData ), headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Accept" : "application/json", "Referer" : "https://fanyi.sogou.com/", "User-agent" : window.useragent, "Cookie" : "SNUID=" + id } , onload: function ( result ) { try { var jsonObj = JSON.parse( result.response ); resolve( jsonObj.data.translate.dit ); } catch ( error ) { GM_SuperValue.set( 'providerSogouState', false ); disableCheckbox( '#Sogou-translator', false ); iframeHandler.find( '#Sogou-translator' ).prop( 'checked', false ); } } } ); } ); } function sogouSetCookies () { let dateExpires = new Date; let match = ".sogou.com"; //let random = Math.floor( Math.random() * ( 9000000 - 1000 ) ) + 1000 let id = "1"; // Must be randomized in the next version return new Promise( ( resolve ) => { GM_xmlhttpRequest( { method : "GET", url : "https://fanyi.sogou.com/", headers: { "User-agent": window.useragent, "Cookie" : setCookie( "SNUID", id, dateExpires.toGMTString(), match, "/" ) } , onload: function ( result ) { resolve( id ) } } ); } ); } function niutransTranslator ( text ) { return new Promise( ( resolve ) => { GM_xmlhttpRequest( { method : "GET", url : "http://test.niutrans.vip/NiuTransServer/testtrans?&from=auto&to=en&src_text=" + encodeURIComponent( text ), headers: { "Accept-Encoding" : "gzip, deflate", "User-Agent": window.useragent } , onload: function ( result ) { try { var myResponse = JSON.parse( result.response ).tgt_text; resolve( [...myResponse.split( '\n \n' )].join( '\n\n' ) ); //console.log(result); } catch ( error ) { GM_SuperValue.set( 'providerNiutransState', false ); disableCheckbox( '#Niutrans-translator', false ); iframeHandler.find( '#Niutrans-translator' ).prop( 'checked', false ); } } } ); } ); } async function baiduTranslator ( text, _tokens ) { const formData = { 'from' : 'zh', 'to' : 'en', 'query' : text, 'transtype' : 'realtime', 'simple_means_flag': 3, 'sign' : sign( text, _tokens[0] ), 'token' : _tokens[1], 'domain' : 'common' }; return new Promise( ( resolve ) => { GM_xmlhttpRequest( { method : "POST", url : "https://fanyi.baidu.com/v2transapi", data : $.param( formData ), headers: { "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8", "Accept" : "application/json", "Referer" : "https://fanyi.baidu.com", "Accept-Encoding" : "gzip, deflate", "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" } , onload: function ( result ) { try { const jsonObj = JSON.parse( result.responseText ) resolve( jsonObj.trans_result.data.map( p => p.dst ).join( '\n\n' ) ); } catch ( error ) { GM_SuperValue.set( 'providerBaiduState', false ); disableCheckbox( '#Baidu-translator', false ); iframeHandler.find( '#Baidu-translator' ).prop( 'checked', false ); } } } ); } ); } function baiduReceiveTokens () { return new Promise( ( resolve ) => { GM_xmlhttpRequest( { method : "GET", url : "https://fanyi.baidu.com/", headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36" } , onload: function ( result ) { try { const windowToken = result.responseText.match( /window\.gtk = '(.*?)'/ )[1]; const commonToken = result.responseText.match( /token: '(.*?)',/ )[1]; resolve( [windowToken, commonToken] ); } catch ( error ) { disableCheckbox( '#Baidu-translator', false ); iframeHandler.find( '#Baidu-translator' ).prop( 'checked', false ); } } } ); } ); } function yeekitTranslator( text ) { return new Promise( ( resolve ) => { GM_xmlhttpRequest( { method: 'POST', url: 'http://fanyi.yeekit.com/zyyt/translate/translate', data: JSON.stringify( { "srcl" : "nzh", "tgtl" : "nen", "app_source": 9001, "text" : text, "domain" : "auto" }), headers: { "Content-Type": "application/json;charset=UTF-8", "Referer" : "http://fanyi.yeekit.com/", "Origin" :"http://fanyi.yeekit.com", "User-Agent" : window.useragent }, onload: function ( result ) { try { let jsonObj = JSON.parse( result.response ); resolve( jsonObj.data ) } catch (error) { GM_SuperValue.set( 'providerYeekitState', false ); disableCheckbox( '#Yeekit-translator', false ); iframeHandler.find( '#Yeekit-translator' ).prop( 'checked', false ); } } }); } ); } /* | Utilities */ function setCookie ( a, val, url, c, name ) { return a = [a, "=", val], url && a.push( ";expires=", url ), c && a.push( ";domain=", c ), name && a.push( ";path=", name ), document.cookie = a.join( "" ), a.join( "" ); } function separateIntoChunks ( paragraphs, size ) { let chunks = []; let currentchunk = ""; for ( let i = 0; i < paragraphs.length; i++ ) { if ( ( currentchunk + paragraphs[i] ).length >= size ) { chunks.push( currentchunk ); currentchunk = paragraphs[i]; } else { currentchunk = currentchunk + "\n\n" + paragraphs[i]; } } if ( paragraphs.length != 0 ) { chunks.push( currentchunk ); } return chunks; } function seperateChunksIntoPars ( chunks, splitby = "\n\n" ) { let pars = []; chunks.forEach( ( chunk ) => chunk.split( splitby ).forEach( ( par ) => pars.push( par ) ) ); return pars; } function a ( r ) { if ( Array.isArray( r ) ) { for ( var o = 0, t = Array( r.length ); o < r.length; o++ ) t[o] = r[o]; return t } return Array.from( r ) } function n ( a, o ) { var s = 0; for ( ; s < o.length - 2; s = s + 3 ) { var d = o.charAt( s + 2 ); d = d >= "a" ? d.charCodeAt( 0 ) - 87 : Number( d ); d = "+" === o.charAt( s + 1 ) ? a >>> d : a << d; a = "+" === o.charAt( s ) ? a + d & 4294967295 : a ^ d; } return a; } function sign ( r, gtk = 0 ) { var i = null; var o = r.match( /[\uD800-\uDBFF][\uDC00-\uDFFF]/g ); if ( null === o ) { var t = r.length; t > 30 && ( r = "" + r.substr( 0, 10 ) + r.substr( Math.floor( t / 2 ) - 5, 10 ) + r.substr( -10, 10 ) ) } else { for ( var e = r.split( /[\uD800-\uDBFF][\uDC00-\uDFFF]/ ), C = 0, h = e.length, f = []; h > C; C++ ) "" !== e[C] && f.push.apply( f, a( e[C].split( "" ) ) ), C !== h - 1 && f.push( o[C] ); var g = f.length; g > 30 && ( r = f.slice( 0, 10 ).join( "" ) + f.slice( Math.floor( g / 2 ) - 5, Math.floor( g / 2 ) + 5 ).join( "" ) + f.slice( -10 ).join( "" ) ) } var u = void 0 , l = "" + String.fromCharCode( 103 ) + String.fromCharCode( 116 ) + String.fromCharCode( 107 ); u = null !== i ? i : ( i = gtk || "" ) || ""; for ( var d = u.split( "." ), m = Number( d[0] ) || 0, s = Number( d[1] ) || 0, S = [], c = 0, v = 0; v < r.length; v++ ) { var A = r.charCodeAt( v ); 128 > A ? S[c++] = A : ( 2048 > A ? S[c++] = A >> 6 | 192 : ( 55296 === ( 64512 & A ) && v + 1 < r.length && 56320 === ( 64512 & r.charCodeAt( v + 1 ) ) ? ( A = 65536 + ( ( 1023 & A ) << 10 ) + ( 1023 & r.charCodeAt( ++v ) ), S[c++] = A >> 18 | 240, S[c++] = A >> 12 & 63 | 128 ) : S[c++] = A >> 12 | 224, S[c++] = A >> 6 & 63 | 128 ), S[c++] = 63 & A | 128 ) } for ( var p = m, F = "" + String.fromCharCode( 43 ) + String.fromCharCode( 45 ) + String.fromCharCode( 97 ) + ( "" + String.fromCharCode( 94 ) + String.fromCharCode( 43 ) + String.fromCharCode( 54 ) ), D = "" + String.fromCharCode( 43 ) + String.fromCharCode( 45 ) + String.fromCharCode( 51 ) + ( "" + String.fromCharCode( 94 ) + String.fromCharCode( 43 ) + String.fromCharCode( 98 ) ) + ( "" + String.fromCharCode( 43 ) + String.fromCharCode( 45 ) + String.fromCharCode( 102 ) ), b = 0; b < S.length; b++ ) p += S[b], p = n( p, F ); return p = n( p, D ), p ^= s, 0 > p && ( p = ( 2147483647 & p ) + 2147483648 ), p %= 1e6, p.toString() + "." + ( p ^ m ) } function md5 ( str ) { var k = [], i = 0; for ( i = 0; i < 64; ) k[i] = 0 | ( Math.abs( Math.sin( ++i ) ) * 4294967296 ); var b, c, d, j, x = [], str2 = unescape( encodeURI( str ) ), a = str2.length, h = [( b = 1732584193 ), ( c = -271733879 ), ~b, ~c]; for ( i = 0; i <= a; ) x[i >> 2] |= ( str2.charCodeAt( i ) || 128 ) << ( 8 * ( i++ % 4 ) ); x[( str = ( ( a + 8 ) >> 6 ) * 16 + 14 )] = a * 8; i = 0; for ( ; i < str; i += 16 ) { a = h; j = 0; for ( ; j < 64; ) { a = [ ( d = a[3] ), ( b = a[1] | 0 ) + ( ( ( d = a[0] + [ ( b & ( c = a[2] ) ) | ( ~b & d ), ( d & b ) | ( ~d & c ), b ^ c ^ d, c ^ ( b | ~d ) ][( a = j >> 4 )] + ( k[j] + ( x[( [j, 5 * j + 1, 3 * j + 5, 7 * j][a] % 16 ) + i] | 0 ) ) ) << ( a = [7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21][ 4 * a + ( j++ % 4 ) ] ) ) | ( d >>> ( 32 - a ) ) ), b, c ]; } for ( j = 4; j; ) { h[--j] = h[j] + a[j]; } } str = ""; for ( ; j < 32; ) { str += ( ( h[j >> 3] >> ( ( 1 ^ ( j++ & 7 ) ) * 4 ) ) & 15 ).toString( 16 ); } return str; }