booru图站汉化插件

汉化danbooru/yande/gelbooru/chan.sankakucomplex 四个图站中的标签 (konachan尚未完成)

  1. // ==UserScript==
  2. // @name booru图站汉化插件
  3. // @version 0.9.3
  4. // @description 汉化danbooru/yande/gelbooru/chan.sankakucomplex 四个图站中的标签 (konachan尚未完成)
  5. // @author Yellow Rush
  6. // @match https://danbooru.donmai.us/*
  7. // @match https://yande.re/*
  8. // @match https://gelbooru.com/*
  9. // @match https://chan.sankakucomplex.com/*
  10. // @icon https://www.google.com/s2/favicons?sz=64&domain=donmai.us
  11. // @grant GM_xmlhttpRequest
  12. // @namespace https://greasyfork.org/users/1081192
  13. // ==/UserScript==
  14.  
  15. (async function () {
  16. 'use strict';
  17.  
  18. console.log("脚本开始执行");
  19.  
  20. // dannboru所需代码
  21. if (window.location.hostname === 'danbooru.donmai.us') {
  22. console.log("运行dannboru所需代码");
  23.  
  24. var translationMap = {
  25. "Login": "登录",
  26. "Posts": "投稿",
  27. "Comments": "评论",
  28. "Notes": "附注",
  29. "Artists": "艺术家",
  30. "Tags": "标签",
  31. "Pools": "图集",
  32. "Wiki": "百科",
  33. "Forum": "论坛",
  34. "More": "更多",
  35. "Gallery": "画廊",
  36. "Listing": "列出",
  37. "Changes": "投稿改动",
  38. "Help": "帮助",
  39. "Hot": "热门",
  40. "Upload": "上传投稿",
  41. "Favorites": "收藏",
  42. "Fav groups": "收藏夹",
  43. "Recommended": "推荐",
  44. "Saved searches": "已保存的搜索",
  45. "My Account": "我的账户"
  46.  
  47. };
  48.  
  49. var contentElement = document.getElementById("nav");
  50.  
  51. if (contentElement) {
  52. console.log("找到导航栏父元素");
  53.  
  54. var elementsToTranslate = contentElement.querySelectorAll("a");
  55.  
  56. elementsToTranslate.forEach(function (element) {
  57. var originalText = element.textContent;
  58.  
  59. for (var key in translationMap) {
  60. if (originalText.includes(key)) {
  61. var translatedText = originalText.replace(key, translationMap[key]);
  62. element.textContent = translatedText;
  63. console.log(`翻译完成: ${originalText} -> ${translatedText}`);
  64. }
  65. }
  66. });
  67.  
  68. console.log("替换完成");
  69. } else {
  70. console.log("未找到导航栏父元素");
  71. }
  72.  
  73.  
  74.  
  75.  
  76. // 标签汉化过程
  77. // 获取对照表
  78. async function loadTranslationData() {
  79. return new Promise((resolve, reject) => {
  80. GM_xmlhttpRequest({
  81. method: "GET",
  82. url: "https://raw.githubusercontent.com/Yellow-Rush/zh_CN-Tags/main/danbooru.csv",
  83. onload: function (response) {
  84. const csvData = response.responseText;
  85. const translationMap = {};
  86. const lines = csvData.split('\n');
  87. for (const line of lines) {
  88. const [englishTag, chineseTranslation] = line.split(',');
  89. translationMap[englishTag] = chineseTranslation;
  90. }
  91. resolve(translationMap);
  92. },
  93. onerror: function (error) {
  94. reject(error);
  95. }
  96. });
  97. });
  98. }
  99.  
  100. // 获取标签的英文名称,将空格转换为下划线
  101. function getSanitizedEnglishTagName(tagElement) {
  102. const englishTag = tagElement.getAttribute('data-tag-name');
  103. return englishTag.replace(/ /g, '_');
  104. }
  105.  
  106. // 替换属性值为中文翻译
  107. async function replaceAttributeValuesWithTranslations() {
  108. console.log("标签汉化过程开始");
  109. const translationMap = await loadTranslationData();
  110. const tagElements = document.querySelectorAll('li[data-tag-name]');
  111. const untranslatedTags = [];
  112.  
  113. tagElements.forEach(tagElement => {
  114. const sanitizedEnglishTag = getSanitizedEnglishTagName(tagElement);
  115. if (translationMap[sanitizedEnglishTag]) {
  116. const chineseTranslation = translationMap[sanitizedEnglishTag];
  117.  
  118. const translationElement = document.createElement('a');
  119. translationElement.className = 'tag-CN';
  120. translationElement.href = tagElement.querySelector('.search-tag').getAttribute('href');
  121. translationElement.textContent = chineseTranslation;
  122.  
  123. tagElement.insertBefore(translationElement, tagElement.querySelector('.wiki-link'));
  124. // console.log(`标签翻译完成: ${sanitizedEnglishTag} -> ${chineseTranslation}`);
  125. } else {
  126. untranslatedTags.push(sanitizedEnglishTag);
  127. }
  128. });
  129.  
  130. console.log("标签汉化过程结束");
  131.  
  132. // 输出找不到中文翻译的英文标签列表
  133. console.log("找不到中文翻译的英文标签列表:");
  134. const csvContent = untranslatedTags.map(tag => `${tag}`).join(',\n');
  135. console.log(csvContent);
  136. }
  137.  
  138. // 在页面加载完毕后执行替换操作
  139. await replaceAttributeValuesWithTranslations();
  140.  
  141.  
  142. // 插入自定义的 CSS 样式
  143. var customStylesForDanbooru = document.createElement("style");
  144. customStylesForDanbooru.textContent = `
  145. :root{
  146. --body-background-color: #f1f1f1;
  147. }
  148. li[data-tag-name] {
  149. display: flex;
  150. flex-wrap: wrap;
  151. flex-direction: row;
  152. padding: 0.2rem 0.5rem 0.2rem 0.5rem;
  153. background-color: #ffffff;
  154. box-shadow: 0 0 0 0.07rem grey;
  155. font-size: 0.5rem;
  156. min-height: 2.5em;
  157. align-content: center;
  158. align-items: center;
  159. }
  160. .tag-CN{
  161. display: block;
  162. padding: 0;
  163. margin-right: 0.2rem;
  164. font-size: 0.98rem;
  165. filter: contrast(1.5) brightness(0.5);
  166. }
  167. .sidebar-container #sidebar {
  168. min-width: 350px;
  169. }
  170. .post-count {
  171. margin-left: auto;
  172. }
  173. .tag-list a.wiki-link {
  174. position: absolute;
  175. left: 2.1em;
  176. }
  177. .fit-width {
  178. max-height: 124vh;
  179. width: auto;
  180. }
  181. `;
  182. document.head.appendChild(customStylesForDanbooru);
  183. }
  184.  
  185. // 给另外的网站用的
  186. if (window.location.hostname === 'yande.re') {
  187. console.log("运行yande.re所需代码");
  188.  
  189. //获取对照表
  190. async function loadTranslationData() {
  191. return new Promise((resolve, reject) => {
  192. GM_xmlhttpRequest({
  193. method: "GET",
  194. url: "https://raw.githubusercontent.com/Yellow-Rush/zh_CN-Tags/main/yande.csv",
  195. onload: function (response) {
  196. const csvData = response.responseText;
  197. const translationMap = {};
  198. const lines = csvData.split('\n');
  199. for (const line of lines) {
  200. const [englishTag, chineseTranslation] = line.split(',');
  201. translationMap[englishTag] = chineseTranslation;
  202. }
  203. resolve(translationMap);
  204. },
  205. onerror: function (error) {
  206. reject(error);
  207. }
  208. });
  209. });
  210. }
  211.  
  212. // 替换属性值为中文翻译
  213. async function replaceAttributeValuesWithTranslations() {
  214. console.log("标签汉化过程开始");
  215. const translationMap = await loadTranslationData();
  216. const tagElements = document.querySelectorAll('a[onmouseover*="Post.highlight_posts_with_tag"], li.tag-type-general > a[href^="/post?tags="]');
  217.  
  218. tagElements.forEach(tagElement => {
  219. let englishTag;
  220.  
  221. if (tagElement.hasAttribute('onmouseover')) {
  222. const onmouseoverAttributeValue = tagElement.getAttribute('onmouseover');
  223. const startIndex = onmouseoverAttributeValue.indexOf("'");
  224. const endIndex = onmouseoverAttributeValue.lastIndexOf("'");
  225. englishTag = onmouseoverAttributeValue.substring(startIndex + 1, endIndex);
  226. } else {
  227. const href = tagElement.getAttribute('href');
  228. const startIndex = href.indexOf('=') + 1;
  229. englishTag = href.substring(startIndex);
  230. }
  231.  
  232. if (translationMap[englishTag]) {
  233. const chineseTranslation = translationMap[englishTag];
  234.  
  235. const translationElement = document.createElement('a');
  236. translationElement.className = 'tag-CN';
  237. translationElement.href = tagElement.getAttribute('href');
  238. translationElement.textContent = chineseTranslation;
  239.  
  240. if (tagElement.parentNode.classList.contains('tag-type')) {
  241. const thirdChild = tagElement.parentNode.children[2];
  242. tagElement.parentNode.insertBefore(translationElement, thirdChild.nextSibling);
  243. } else {
  244. tagElement.parentNode.insertBefore(translationElement, tagElement);
  245. }
  246.  
  247. console.log(`标签翻译完成: ${englishTag} -> ${chineseTranslation}`);
  248. }
  249. });
  250. console.log("标签汉化过程结束");
  251. }
  252.  
  253.  
  254. //汉化标签大列表以检查哪些热门标签没翻译
  255. async function replaceTagsInTdElements() {
  256. console.log("在td元素中替换标签开始");
  257.  
  258. const translationMap = await loadTranslationData();
  259. const tdElements = document.querySelectorAll('[class^="tag-type-"]');
  260.  
  261. tdElements.forEach(tdElement => {
  262. const tagLink = tdElement.querySelector('a[href^="/post?tags="]');
  263. if (tagLink) {
  264. const href = tagLink.getAttribute('href');
  265. const startIndex = href.indexOf('=') + 1;
  266. const englishTag = href.substring(startIndex);
  267.  
  268. if (translationMap[englishTag]) {
  269. const chineseTranslation = translationMap[englishTag];
  270.  
  271. const translationElement = document.createElement('a');
  272. translationElement.className = 'tag-CN';
  273. translationElement.href = href;
  274. translationElement.textContent = chineseTranslation;
  275.  
  276. tdElement.insertBefore(translationElement, tagLink);
  277. console.log(`标签翻译完成: ${englishTag} -> ${chineseTranslation}`);
  278. }
  279. }
  280. });
  281.  
  282. console.log("在td元素中替换标签结束");
  283. }
  284.  
  285. // 使用 DOMContentLoaded 事件来确保页面已加载完成
  286. document.addEventListener('DOMContentLoaded', async () => {
  287. await replaceAttributeValuesWithTranslations();
  288. await replaceTagsInTdElements(); // 调用新添加的函数
  289. });
  290.  
  291.  
  292.  
  293. // 在页面加载完毕后执行替换操作
  294. await replaceAttributeValuesWithTranslations();
  295. await replaceTagsInTdElements(); // 调用新添加的函数
  296.  
  297. // 插入自定义的 CSS 样式
  298. var customStyles = document.createElement("style");
  299. customStyles.textContent = `
  300. #tag-sidebar>li {
  301. background-color: #181818;
  302. box-shadow: 0 0 0 1px #474747;
  303. padding: 0.4em 0 0.4em 0.4em;
  304. }
  305.  
  306. div.sidebar{
  307. width: 20%;
  308. max-width: 15vw;
  309. }
  310.  
  311. div.content {
  312. width: 67%;
  313. }
  314.  
  315. #tag-sidebar>li>a:nth-child(1){
  316. position:absolute;
  317. left: 0.1em;
  318. opacity: 0.7;
  319. }
  320. #tag-sidebar>li>a:nth-child(2){
  321. position:absolute;
  322. left: 0.9em;
  323. opacity: 0.7;
  324. }
  325.  
  326. #tag-sidebar>li>a:nth-child(3){
  327. position:absolute;
  328. left: 2em;
  329. opacity: 0.7;
  330. }
  331.  
  332. a.tag-CN {
  333. font-size: 1.2em !important;
  334. margin: 0.3em;
  335. filter: contrast(1.1);
  336. font-weight: bold;
  337. }
  338.  
  339. #tag-sidebar>li>*:not(.tag-CN){
  340. opacity:0.8
  341. }
  342.  
  343. .tag-type-copyright > a, #history .tag-type-copyright, .color-tag-types .tag-type-copyright {
  344. color: #ff669d;
  345. }
  346.  
  347. .action-post-show > body {
  348. background: #2d2d2d;
  349. }
  350.  
  351. .image.js-notes-manager--toggle.js-notes-manager--image {
  352. max-width: 75vw;
  353. height: auto;
  354. }
  355.  
  356.  
  357. `;
  358. document.head.appendChild(customStyles);
  359.  
  360. }
  361.  
  362.  
  363. if (window.location.hostname === 'chan.sankakucomplex.com') {
  364. console.log("Running code for chan.sankakucomplex.com");
  365.  
  366. // 获取对照表
  367. async function loadTranslationData() {
  368. return new Promise((resolve, reject) => {
  369. GM_xmlhttpRequest({
  370. method: "GET",
  371. url: "https://raw.githubusercontent.com/Yellow-Rush/zh_CN-Tags/main/sankakucomplex_chan.csv",
  372. onload: function (response) {
  373. const csvData = response.responseText;
  374. const translationMap = {};
  375. const lines = csvData.split('\n');
  376. for (const line of lines) {
  377. const [englishTag, chineseTranslation] = line.split(',');
  378. translationMap[englishTag] = chineseTranslation;
  379. }
  380. resolve(translationMap);
  381. },
  382. onerror: function (error) {
  383. reject(error);
  384. }
  385. });
  386. });
  387. }
  388.  
  389. // 查找id为tag-sidebar的元素
  390. var tagSidebar = document.getElementById("tag-sidebar");
  391.  
  392. if (tagSidebar) {
  393. // 加载对照表
  394. loadTranslationData().then((translationMap) => {
  395. // 查找所有li元素
  396. var tagListItems = tagSidebar.querySelectorAll("li");
  397.  
  398. // 用于存储找不到中文标签的英文标签的数组
  399. var untranslatedTags = [];
  400.  
  401. tagListItems.forEach(function (listItem) {
  402. // 查找li元素下的a元素
  403. var tagLink = listItem.querySelector("a");
  404.  
  405. if (tagLink) {
  406. // 获取标签的英文名称
  407. var englishTagName = tagLink.textContent.trim();
  408.  
  409. // 根据映射表进行翻译
  410. var translatedTag = translationMap[englishTagName];
  411.  
  412. if (translatedTag) {
  413. // 创建一个新的a元素包含中文翻译,并设置相同的链接
  414. var translationElement = document.createElement('a');
  415. translationElement.className = 'tag-CN';
  416. translationElement.href = tagLink.href;
  417. translationElement.textContent = translatedTag;
  418.  
  419. // 添加role="tooltip"属性
  420. translationElement.setAttribute('role', 'tooltip');
  421.  
  422. // 将新元素插入到a元素之前
  423. tagLink.parentNode.insertBefore(translationElement, tagLink);
  424. } else {
  425. // 将找不到中文标签的英文标签添加到数组
  426. untranslatedTags.push(englishTagName);
  427. }
  428. }
  429. });
  430.  
  431. // 输出找不到中文标签的英文标签列表
  432. console.log("找不到中文翻译的英文标签列表:");
  433. const csvContent = untranslatedTags.map(tag => `${tag}`).join(',\n');
  434. console.log(csvContent);
  435. });
  436.  
  437.  
  438. }
  439.  
  440. // 插入自定义的 CSS 样式
  441. var customStyles = document.createElement("style");
  442. customStyles.textContent = `
  443. li[class*="tag-type"]{
  444. background:#f7f7f7;
  445. border:1px solid #656565;
  446. padding: 4px;
  447. }
  448.  
  449. .tag-CN{
  450. margin-right: 0.5em;
  451. }
  452.  
  453. [href*="/?tags="]:not(.tag-CN){
  454. color:#916849 ;
  455. font-weight:400;
  456. font-size:0.7rem !important;
  457. }
  458. [href*="/?tags="]:not(.tag-CN):hover{
  459. color:#ff0000;
  460. }
  461.  
  462. #has-mail-notice{
  463. display:none;
  464. }
  465. #headerlogo{
  466. display:none;
  467. }
  468.  
  469. #tag-sidebar{
  470. overflow: visible;
  471. }
  472. .tooltip {
  473. z-index: 10 !important;
  474. position: relative;
  475. }
  476. div.sidebar {
  477. overflow-y: visible;
  478. }
  479. .tooltip[data-show]{
  480. line-height: 1.5em;
  481. border-radius:0.2em;
  482. border:1px black solid;
  483. background:white
  484. }
  485. `;
  486. document.head.appendChild(customStyles);
  487. }
  488.  
  489.  
  490. // 给另外的网站用的
  491. if (window.location.hostname === 'gelbooru.com') {
  492. console.log("Running code for gelbooru.com");
  493.  
  494. // 获取对照表
  495. async function loadTranslationData() {
  496. return new Promise((resolve, reject) => {
  497. GM_xmlhttpRequest({
  498. method: "GET",
  499. url: "https://raw.githubusercontent.com/Yellow-Rush/zh_CN-Tags/main/gelbooru.csv",
  500. onload: function (response) {
  501. const csvData = response.responseText;
  502. const translationMap = {};
  503. const lines = csvData.split('\n');
  504. for (const line of lines) {
  505. const [englishTag, chineseTranslation] = line.split(',');
  506. translationMap[englishTag] = chineseTranslation;
  507. }
  508. resolve(translationMap);
  509. },
  510. onerror: function (error) {
  511. reject(error);
  512. }
  513. });
  514. });
  515. }
  516.  
  517. // 查找class为tag-list的元素
  518. var tagList = document.querySelector(".tag-list");
  519.  
  520. if (tagList) {
  521. // 加载对照表
  522. loadTranslationData().then((translationMap) => {
  523. // 查找所有包含标签的a元素
  524. var tagLinks = tagList.querySelectorAll("a[href*='tags=']");
  525.  
  526. // 用于存储找不到中文标签的英文标签的数组
  527. var untranslatedTags = [];
  528.  
  529. tagLinks.forEach(function (tagLink) {
  530. // 获取标签的英文名称
  531. var englishTagName = tagLink.textContent.trim();
  532. var sanitizedEnglishTagName = englishTagName.replace(/ /g, '_'); // 将空格替换为下划线
  533.  
  534. // 根据映射表进行翻译
  535. var translatedTag = translationMap[sanitizedEnglishTagName];
  536.  
  537. if (translatedTag) {
  538. // 创建一个新的a元素包含中文翻译,并设置相同的链接
  539. var translationElement = document.createElement('a');
  540. translationElement.className = 'tag-CN';
  541. translationElement.href = tagLink.href;
  542. translationElement.textContent = translatedTag;
  543.  
  544. // 将新元素插入到a元素之前
  545. tagLink.parentNode.insertBefore(translationElement, tagLink);
  546. } else {
  547. // 将找不到中文标签的英文标签添加到数组
  548. untranslatedTags.push(sanitizedEnglishTagName);
  549. }
  550. });
  551.  
  552. // 输出找不到中文翻译的英文标签列表
  553. console.log("找不到中文翻译的英文标签列表:");
  554. const csvContent = untranslatedTags.map(tag => `${tag}`).join(',\n');
  555. console.log(csvContent);
  556. });
  557. }
  558.  
  559.  
  560. // 插入自定义的 CSS 样式
  561. var customStyles = document.createElement("style");
  562. customStyles.textContent = `
  563. .tag-CN {
  564. margin-right: 0.5em;
  565. }
  566. a.tag-CN {
  567. font-size: 1.3em;
  568. }
  569. a.mobile-spacing {}
  570. li>a[title="Wiki"] {
  571. position: absolute;
  572. left: -2em;
  573. opacity: 50%;
  574. }
  575. li>a[title="Wiki"]:hover {
  576. opacity: 100%;
  577. }
  578. li[class*="tag-type"]>.sm-hidden {
  579. position: relative;
  580. }
  581. li[class*="tag-type"]>.sm-hidden>a[href*="wiki"]{
  582. position: absolute;
  583. left: -1.5em;
  584. opacity: 50%;
  585. z-index: 2;
  586. }
  587. [title="Remove from search"] {
  588. display: none;
  589. }
  590. [title="Add to search"] {
  591. left: -1.1em;
  592. position: absolute;
  593. opacity: 50%;
  594. }
  595. [title="Add to search"]:hover {
  596. opacity: 100%;
  597. }
  598. #tag-list>li[class*="tag-type"] {
  599. position: relative;
  600. }
  601. li[class*="tag-type"]>span {
  602. right: 0.2em;
  603. top: 30%;
  604. position: absolute;
  605. color: #cacaca !important;
  606. }
  607. .aside {
  608. margin-left: 1.6em;
  609. }
  610. #container {
  611. grid-template-columns: 285px auto;
  612. }
  613. ul.tag-list li[class*="tag-type"] {
  614. background: #ffffff;
  615. display: inline-block;
  616. width: 230px;
  617. margin: 0px 4px 0px 15px;
  618. border: none;
  619. box-shadow: 0 0 0 0.07rem grey;
  620. padding: 0.2em 0.5em 0.3em 0.5em;
  621. }
  622. ul.tag-list a[href*="tags"]:not(a.tag-CN) {
  623. opacity: 60% !important;
  624. filter: hue-rotate(-15deg) saturate(0.5);
  625. }
  626. a.tag-CN {
  627. filter: saturate(1.3) brightness(0.8)
  628. }
  629.  
  630. body{
  631. background:#f7f7f7;
  632.  
  633. }
  634. `;
  635. document.head.appendChild(customStyles);
  636. }
  637.  
  638. // 给另外的网站用的
  639. if (window.location.hostname === 'another-example.com') {
  640. console.log("Running code for another-example.com");
  641.  
  642.  
  643. }
  644.  
  645. // 全部网站所通用规则
  646. console.log("Common code for all matched websites");
  647.  
  648.  
  649. console.log("脚本执行结束");
  650.  
  651. })();