轻小说机翻机器人

https://n.novelia.cc

holzora (7778)1天前

by·holzora
详细说明请见:https://n.novelia.cc/forum/66a8e77866bff10c16e51d6a
二维码导入
{
    "bookSourceComment": "by·holzora\n详细说明请见:https:\/\/n.novelia.cc\/forum\/66a8e77866bff10c16e51d6a",
    "bookSourceGroup": "轻小说",
    "bookSourceName": "轻小说机翻机器人",
    "bookSourceType": 0,
    "bookSourceUrl": "https:\/\/n.novelia.cc",
    "bookUrlPattern": "(?:https?:\/\/)?(?:books\\d?.fishhawk.top|n.novelia.cc)\/(?:api\/)?novel\/\\w+\/[\\w-]+",
    "customOrder": 0,
    "enabled": true,
    "enabledCookieJar": false,
    "enabledExplore": true,
    "exploreUrl": "<js>\nvar discover = [];\nvar showR18 = false;\nvar push = (title, url, style) => {\n    discover.push({\n        title: title,\n        url: url,\n        style: {\n            layout_flexGrow: 1,\n            layout_flexBasisPercent: style\n        }\n    });\n};\nvar addSlots = (count, style) => {\n    var remainder = count % 3;\n    var slotsAdd = remainder === 0 ? 0 : 3 - remainder;\n    for (var i = 0; i < slotsAdd; i++) {\n        push(\"\", null, style);\n    }\n};\npush(\"书架\", null, 1);\ntry {\n    var favored = java.ajax(`${baseUrl}\/api\/user\/favored`);\n    if (favored.includes(\"Token不合法或者过期\")) {\n    \t   showR18 = false;\n        push(\"账号未登录\", null, 0.25);\n        addSlots(1, 0.25);\n    } else {\n    \t   showR18 = true;\n    \t   push(\"阅读历史\", \"\/api\/user\/read-history?page={{(page-1)}}&pageSize=30\", 0.25);\n        var favoredData = JSON.parse(favored).favoredWeb;\n        favoredData.forEach(item => {\n            push(item.title, `\/api\/user\/favored-web\/${item.id}?page={{(page-1)}}&pageSize=30&query=&provider=kakuyomu%2Csyosetu%2Cnovelup%2Chameln%2Cpixiv%2Calphapolis&type=0&level=0&translate=0&sort=update`, 0.25);\n        });\n        addSlots(1 + favoredData.length, 0.25);\n    }\n} catch (e) {\n\t   showR18 = false;\n    push(\"未知错误\", null, 0.25);\n    addSlots(1, 0.25);\n}\npush(\"来源\", null, 1);\nvar providers = [\"全部\", \"kakuyomu\", \"syosetu\", \"novelup\", \"hameln\", \"pixiv\", \"alphapolis\"];\nproviders.forEach(provider => {\n    var url = provider === \"全部\" ? \n        `\/api\/novel?page={{(page-1)}}&pageSize=20&query=&provider=${providers.slice(1).join('%2C')}&type=0&level=0&translate=0&sort=0` : \n        `\/api\/novel?page={{(page-1)}}&pageSize=20&query=&provider=${provider}&type=0&level=0&translate=0&sort=0`;\n    push(provider, url, 0.25);\n});\naddSlots(providers.length, 0.25);\npush(\"类型\", null, 1);\nvar types = [\"全部\", \"连载中\", \"已完结\", \"短篇\"];\ntypes.forEach((type, index) => {\n    var url = `\/api\/novel?page={{(page-1)}}&pageSize=20&query=&provider=kakuyomu%2Csyosetu%2Cnovelup%2Chameln%2Cpixiv%2Calphapolis&type=${index}&level=0&translate=0&sort=0`;\n    push(type, url, 0.25);\n});\naddSlots(types.length, 0.25);\npush(\"分级\", null, 1);\nvar levels = showR18 ? [\"全部\", \"一般向\", \"R18\"] : [\"全部\", \"一般向\"];\nlevels.forEach((level, index) => {\n    var url = `\/api\/novel?page={{(page-1)}}&pageSize=20&query=&provider=kakuyomu%2Csyosetu%2Cnovelup%2Chameln%2Cpixiv%2Calphapolis&type=0&level=${index}&translate=0&sort=0`;\n    push(level, url, 0.25);\n});\naddSlots(levels.length, 0.25);\npush(\"排序\", null, 1);\nvar sorts = [\"更新\", \"点击\"];\nsorts.forEach((sort, index) => {\n    var url = `\/api\/novel?page={{(page-1)}}&pageSize=20&query=&provider=kakuyomu%2Csyosetu%2Cnovelup%2Chameln%2Cpixiv%2Calphapolis&type=0&level=0&translate=0&sort=${index}`;\n    push(sort, url, 0.25);\n});\naddSlots(sorts.length, 0.25);\nJSON.stringify(discover);\n<\/js>",
    "header": "<js>\nvar header = {\n    \"Referer\": baseUrl\n};\nJSON.stringify(header);\n<\/js>",
    "jsLib": "var update = (initUrl, initToken) => {\n    try {\n        var [novelUrl, chapterId] = initUrl.split('\/chapter\/');\n        var url = novelUrl.replace('\/novel\/', '\/user\/read-history\/');\n        var {Authorization: token} = JSON.parse(initToken);\n        return Packages.org.jsoup.Jsoup.connect(url).method(Packages.org.jsoup.Connection.Method.PUT).header(\"Authorization\", token).requestBody(chapterId).execute().body();\n    } catch (e) {\n        return \"\";\n    }\n};\nvar annotate = (text, dict) => {\n    var keys = Object.keys(dict).sort((a, b) => b.length - a.length);\n    var pat = new RegExp(keys.join('|'), 'g');\n    return text.replace(pat, word => {\n        var read = dict[word];\n        if (\/[ぁ-んァ-ン]\/.test(word) && \/[一-龯々]\/.test(word)) {\n            var pre = (word.match(\/^([ぁ-んァ-ン]+)\/) || [''])[0];\n            var suf = (word.match(\/([ぁ-んァ-ン]+)$\/) || [''])[0];\n            var kanji = word.substring(pre.length, word.length - suf.length);\n            return (!pre || read.startsWith(pre)) && (!suf || read.endsWith(suf)) ? `${pre}${kanji}(${read.substring(pre.length, read.length - suf.length)})${suf}` : `${word}(${read})`;\n        }\n        return `${word}(${read})`;\n    });\n};\nvar regex = content => {\n    var displayedImages = new Set();\n    return JSON.stringify(content).replace(\/<图片>(https?:\\\/\\\/[^\"\\s]+)\/g, (match, url) => {\n        if (displayedImages.has(url)) return '';\n        displayedImages.add(url);\n        var referer = url.match(\/https?:\\\/\\\/[^\\\/]+\/)[0].replace(\/i\\.pximg\\.net\/, 'www.pixiv.net');\n        var headers = JSON.stringify({headers: {Referer: referer}});\n        return `<img src=\"${url},${headers}\">`;\n    });\n};\nvar format = content => content.replace(\/^\\[|\\]$\/g, '').split(',').map(item => item.trim().replace(\/^\"|\"$\/g, '')).filter(Boolean).map((item, i) => item.startsWith('{\"headers\"') && i > 0 ? ',' + item : '    ' + item).join(\"\\n\");",
    "lastUpdateTime": "1756741400517",
    "loginUi": "[\n    {\n        \"name\": \"账号\",\n        \"type\": \"text\"\n    },\n    {\n        \"name\": \"密码\",\n        \"type\": \"password\"\n    }\n]",
    "loginUrl": "<js>\nvar login = () => {\n    var username = source.getLoginInfoMap().get(\"账号\");\n    var password = source.getLoginInfoMap().get(\"密码\");\n    var res = java.post(\n        `${baseUrl.replace('n', 'auth')}\/api\/v1\/auth\/login`,\n        JSON.stringify({\n            username: username,\n            password: password,\n            app: \"legado\"\n        }),\n        {\"Content-Type\": \"application\/json\"}\n    );\n    source.putLoginHeader(JSON.stringify({\n        Authorization: `Bearer ${res.body()}`\n    }));\n}\nlogin();\n<\/js>",
    "respondTime": 180000,
    "ruleBookInfo": {
        "author": "authors..name",
        "coverUrl": "{{'https:\/\/static.kksk.io\/image\/convert\/885e391180d8d1f37ad157338daa61dd.webp'}}",
        "init": "<js>\nvar initUrl = book.bookUrl;\nvar url = initUrl.includes('api\/novel') ? initUrl : initUrl.replace('\/novel\/', '\/api\/novel\/');\nvar body = initUrl.includes('api\/novel') ? result : java.ajax(url);\nif (body.includes('ID不合适,应当使用')) {\n    var match = body.match(\/\\\/\\w+\\\/[\\w-]+\/);\n    url = `${book.origin}\/api\/novel${match}`;\n    body = java.ajax(url);\n}\nif (body.includes(\"Token不合法或者过期\")) {\n    java.toast(\"当前会话已失效,请重新登录\");\n}\njava.put('url', url);\nbody;\n<\/js>",
        "intro": "<js>\nvar value = String(book.getVariable(\"custom\")) || String(source.getVariable());\nvar data = JSON.parse(result);\nvar cnIntro = data.introductionZh;\nvar jpIntro = data.introductionJp;\nvar intro = cnIntro ? (value === '5' ? jpIntro : ['6', '8'].includes(value) ? cnIntro + \"\\n&lrm;\\n\" + jpIntro : ['7', '9'].includes(value) ? jpIntro + \"\\n&lrm;\\n\" + cnIntro : cnIntro) : jpIntro;\nvar timeStamp = '{{$.toc[-1].createAt}}' || '{{$.syncAt}}';\nintro = '&nbsp;&nbsp;📬最近' + ('{{$.toc[-1].createAt}}' ? '更新' : '同步') + ':' + java.timeFormat(timeStamp * 1000) + '\\n&lrm;\\n' + intro;\nintro;\n<\/js>",
        "kind": "{{$.type##中|已}},{{$.attentions}},{{$.keywords}}",
        "name": "<js>\nvar value = String(book.getVariable(\"custom\")) || String(source.getVariable());\nvar data = JSON.parse(result);\nvar name = value === '5' ? data.titleJp : data.titleZh || data.titleJp;\nname;\n<\/js>",
        "tocUrl": "{{java.get('url')}}",
        "wordCount": "totalCharacters"
    },
    "ruleContent": {
        "content": "<js>\nvar token = source.getLoginHeader();\nupdate(baseUrl, token);\nvar value = String(book.getVariable(\"custom\")) || String(source.getVariable());\nvar get = \/^[1-9]$\/.test(value) ? value : '1';\nvar config = {\n    1: 'sakuraParagraphs',\n    2: 'gptParagraphs',\n    3: 'youdaoParagraphs',\n    4: 'baiduParagraphs',\n    5: 'paragraphs'\n};\nvar data = JSON.parse(result);\nvar content = data[config[get]] || data[config[1]] || data[config[2]] || data[config[3]] || data[config[4]] || data[config[5]];\nif (['6', '7', '8', '9'].includes(get)) {\n    var cnContent = data[config[1]] || data[config[2]] || data[config[3]] || data[config[4]];\n    var jpContent = data[config[5]];\n    if (cnContent) {\n        if (['8', '9'].includes(get)) {\n            var res = java.post(\n                'https:\/\/static.kksk.io\/api\/kanji',\n                JSON.stringify({\"content\": format(regex(jpContent))}),\n                {\"Content-Type\": \"application\/json\"}\n            );\n            var kanji = JSON.parse(res.body());\n            jpContent = jpContent.map(text => annotate(text, kanji));\n        }\n        var type = ['6', '8'].includes(get);\n        content = jpContent.flatMap((jp, i) => {\n            if (!((jp || '').trim() && (cnContent[i] || '').trim())) return [];\n            var pair = type ? [cnContent[i], jp] : [jp, cnContent[i]];\n            return pair.filter(Boolean).concat(i === jpContent.length - 1 ? [] : '\\u200B');\n        }).filter(Boolean);\n    } else {\n        content = jpContent;\n    }\n}\nformat(regex(content));\n<\/js>"
    },
    "ruleExplore": {},
    "ruleSearch": {
        "bookList": "<js>\nif (result.includes(\"Token不合法或者过期\")) {\n    java.toast(\"当前会话已失效,请重新登录\");\n}\nresult;\n<\/js>\nitems",
        "bookUrl": "\/api\/novel\/{{$.providerId}}\/{{$..novelId}}",
        "coverUrl": "{{'https:\/\/static.kksk.io\/image\/convert\/885e391180d8d1f37ad157338daa61dd.webp'}}",
        "intro": "&nbsp;&nbsp;源站:{{$.providerId}}{{'\\n'}}📬最近同步:{{java.timeFormat(java.getString('$.updateAt')*1000)}}{{'\\n'}}总计{{$.total}}|百度{{$.baidu}}|有道{{$.youdao}}|gpt{{$.gpt}}|sakura{{$.sakura}}",
        "kind": "{{$.type##中|已}},{{$.attentions}},{{$.keywords}}",
        "name": "<js>\nvar value = String(book.getVariable(\"custom\")) || String(source.getVariable());\nvar name = value === '5' ? result.titleJp : result.titleZh || result.titleJp;\nname;\n<\/js>"
    },
    "ruleToc": {
        "chapterList": "<js>\nif (result.includes(\"Token不合法或者过期\")) {\n    java.toast(\"当前会话已失效,请重新登录\");\n}\nresult;\n<\/js>\ntoc\n<js>\nresult.forEach(item => {\n    if ('chapterId' in item) {\n        item.url = `${baseUrl}\/chapter\/${item.chapterId}`;\n        var timeStamp = item.createAt ? item.createAt * 1000 : null;\n        if (timeStamp) {\n            item.time = java.timeFormat(timeStamp);\n        }\n    } else {\n        item.isVolume = true;\n    }\n});\nresult;\n<\/js>",
        "chapterName": "<js>\nvar value = String(book.getVariable(\"custom\")) || String(source.getVariable());\nvar name = result.titleZh ? (value === '5' ? result.titleJp : ['6', '8'].includes(value) ? result.titleZh + ' ↔ ' + result.titleJp : ['7', '9'].includes(value) ? result.titleJp + ' ↔ ' + result.titleZh : result.titleZh) : result.titleJp;\nname;\n<\/js>",
        "chapterUrl": "url",
        "isVolume": "isVolume",
        "updateTime": "<js>\nvar value = String(book.getVariable(\"custom\")) || String(source.getVariable());\nvar info = result.isVolume ? null : (result.time ? (result.titleZh ? (['6', '8'].includes(value) ? result.titleJp + ' · ' + result.time : ['7', '9'].includes(value) ? result.titleZh + ' · ' + result.time : result.time) : result.time) : (['7', '9'].includes(value) ? result.titleZh : ['6', '8'].includes(value) ? result.titleJp : null));\ninfo;\n<\/js>"
    },
    "searchUrl": "<js>\nvar providers = {\n    kakuyomu: \/(?:https?:\\\/\\\/)?kakuyomu\\.jp\\\/works\\\/(\\d+)\/,\n    syosetu: \/(?:https?:\\\/\\\/)?(ncode|novel18)\\.syosetu\\.com\\\/(\\w+)\/,\n    novelup: \/(?:https?:\\\/\\\/)?novelup\\.plus\\\/story\\\/(\\d+)\/,\n    hameln: \/(?:https?:\\\/\\\/)?syosetu\\.org\\\/novel\\\/(\\d+)\/,\n    pixiv: \/(?:https?:\\\/\\\/)?(www\\.pixiv\\.net\\\/novel\\\/series\\\/(\\d+)|www\\.pixiv\\.net\\\/novel\\\/show\\.php\\?id=(\\d+))\/,\n    alphapolis: \/(?:https?:\\\/\\\/)?www\\.alphapolis\\.co\\.jp\\\/novel\\\/(\\d+)\\\/(\\d+)\/,\n    sakura: \/(?:https?:\\\/\\\/)?(?:books\\d?\\.fishhawk\\.top|n\\.novelia\\.cc)\\\/(?:api\\\/)?novel\\\/(\\w+)\\\/([\\w-]+)\/\n};\nvar url;\nfor (var provider in providers) {\n    var match = key.match(providers[provider]);\n    if (match) {\n        var providerId = provider === 'sakura' ? match[1] : provider;\n        var novelId = provider === 'alphapolis' ? `${match[1]}-${match[2]}` : provider === 'pixiv' ? (match[3] ? `s${match[3]}` : match[2]) : (match[2] || match[1]);\n        url = `${baseUrl}\/api\/novel\/${providerId}\/${novelId}`;\n        break;\n    }\n}\nif (!url) {\n    url = `${baseUrl}\/api\/novel?page=${page-1}&pageSize=20&query=${key}&provider=kakuyomu,syosetu,novelup,hameln,pixiv,alphapolis&type=0&level=0&translate=0&sort=1`;\n}\nurl;\n<\/js>",
    "variableComment": "输入对应数字刷新即可获取对应文本,{1: \"sakura译文\", 2: \"gpt译文\", 3: \"有道译文\", 4: \"百度译文\", 5: \"原文\", 6: \"中日对照\", 7: \"日中对照\", 8: \"6+平假注音\", 9: \"7+平假注音\"},默认sakura译文。书籍变量作用于一本书,源变量作用于整个书源,书籍变量优先级高于源变量。",
    "weight": 0
}
广告