Sleazy Fork is available in English.

eh详情页标签颜色

eh为详情页标签增加颜色

  1. // ==UserScript==
  2. // @name eh详情页标签颜色
  3. // @namespace com.xioxin.tag-color
  4. // @version 0.7
  5. // @description eh为详情页标签增加颜色
  6. // @author xioxin
  7. // @homepage https://github.com/EhTagTranslation/UserScripts
  8. // @supportURL https://github.com/EhTagTranslation/UserScripts/issues
  9. // @match *://exhentai.org/g/*
  10. // @match *://e-hentai.org/g/*
  11. // @match *://exhentai.org/mytags
  12. // @match *://e-hentai.org/mytags
  13. // @grant GM_addStyle
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // ==/UserScript==
  17.  
  18.  
  19. if(typeof GM_getValue == 'undefined') {
  20. function GM_getValue(key, val) {return JSON.parse(localStorage.getItem(key)||'null') || val }
  21. }
  22.  
  23. if(typeof GM_addStyle == 'undefined') {
  24. function GM_addStyle(script){
  25. var style = document.createElement("style");
  26. style.type = "text/css";
  27. style.innerHTML=script
  28. document.getElementsByTagName("HEAD").item(0).appendChild(style);
  29. }
  30. }
  31. if(typeof GM_setValue == 'undefined') {
  32. function GM_setValue(key, val) {localStorage.setItem(key, JSON.stringify(val))}
  33. }
  34.  
  35. async function saveMyTagData() {
  36. const msg = document.createElement('div');
  37. msg.style.clear = 'both';
  38. msg.style.textAlign = 'center';
  39. msg.style.width = '100%';
  40. document.querySelector('#tagset_outer').appendChild(msg);
  41. const setMsg = (text) => msg.innerText = text;
  42. try {
  43. const tags = [];
  44. for(let id of [...document.querySelectorAll("#tagset_outer select option")].map(v=> v.value)) {
  45. setMsg(`[详情页标签颜色]正在加载 ${id}`);
  46. tags.push(...await loadMyTagData(id));
  47. }
  48. // 从小到大排序,因为颜色渲染是css,靠后的权重更大.
  49. tags.sort((a,b) => a.weight - b.weight);
  50. GM_setValue("myTags", tags);
  51. setMsg(`[详情页标签颜色] 已更新 ${tags.length}个`);
  52. } catch (e) {
  53. setMsg(`[详情页标签颜色] 错误: ${e.message}`);
  54. }
  55. }
  56.  
  57.  
  58. async function loadMyTagData(tageset) {
  59. const html = await fetch(`${document.location.origin}/mytags?tagset=${tageset || 1}`, {credentials: "include"}).then(v => v.text());
  60. const safeHtml = html.replace(/^.*<body>(.*)<\/body>.*$/igms,"$1").replace(/<script.*?>(.*?)<\/script>/igms, '');
  61. const dom = document.createElement('div');
  62. dom.innerHTML = safeHtml;
  63. const tags = [...dom.querySelectorAll('#usertags_outer>div')].map(e => {
  64. if(e.querySelector('.gt') == null) return
  65. return {
  66. tag: e.querySelector('.gt').title,
  67. background: e.querySelector('.gt').style.background,
  68. color: e.querySelector('.gt').style.color,
  69. borderColor: e.querySelector('.gt').style.borderColor,
  70. weight: parseInt(e.querySelector('[id^=tagweight]').value, 10),
  71. }
  72. }).filter(v => v);
  73. return tags;
  74. }
  75.  
  76.  
  77. async function dyeing() {
  78. setTimeout(colorIcon, 0);
  79. const myTags = GM_getValue("myTags", []);
  80. let css = '';
  81. myTags.forEach(v => {
  82. const key = v.tag.replaceAll(' ', '_');
  83. css += `
  84. [id="td_${key}"]{
  85. border-color: ${v.borderColor} !important;
  86. background: ${v.background} !important;
  87. }
  88. [id="td_${key}"].gtw, [id="td_${key}"].gtl{
  89. outline: solid 1px ${v.borderColor};
  90. border-color: ${v.color} !important;
  91. }
  92. [id="td_${key}"] a {
  93. color: ${v.color};
  94. }
  95. .tup::after, .tdn::after {
  96. display: inline-block;
  97. color: #fff;
  98. border-radius: 4px;
  99. margin-left: 4px;
  100. margin-right: -2px;
  101. background-color: green;
  102. content: '';
  103. line-height: 14px;
  104. outline: solid 1px #fff;
  105. vertical-align: sub;
  106. width: 4px;
  107. height: 14px;
  108. }
  109. .tdn::after {
  110. background-color: red;
  111. }
  112. `
  113. });
  114. GM_addStyle(css);
  115. }
  116.  
  117. function colorIcon() {
  118. const myTags = GM_getValue("myTags", []);
  119. const tagIds = [...document.querySelectorAll("#taglist td>div")].map(v => v.id.replace('td_', '').replaceAll('_', ' '));
  120. const tags = tagIds.map(id => myTags.find(v => v.tag == id)).filter(v => v);
  121. tags.sort((a, b) => parseInt(a.weight) - parseInt(b.weight));
  122. const weight = tags.reduce((accumulator, tag) => accumulator + parseInt(tag.weight), 0);
  123. const colors = tags.map(tag => (/(rgb\(.*?\))/ig.exec(tag.borderColor)||[])[0]).filter(v => v);
  124. if(!colors.length) return;
  125. const canvas = document.createElement('canvas');
  126. canvas.width = canvas.height = 128;
  127. const edgeSize = 8;
  128. let ctx = canvas.getContext("2d");
  129. colors.forEach((c, i) => {
  130. ctx.fillStyle = ctx.strokeStyle = c;
  131. ctx.fillRect((canvas.width - edgeSize*2) / colors.length * i + edgeSize, 0, (canvas.width - edgeSize*2) / colors.length, canvas.height);
  132. });
  133. ctx.globalCompositeOperation="destination-in";
  134. ctx.fillStyle = "rgb(0,0,0)";
  135. ctx.roundRect(edgeSize/2,edgeSize/2,canvas.width - edgeSize,canvas.height - edgeSize, 20).fill();
  136. ctx.globalCompositeOperation="source-over";
  137. ctx.lineWidth = edgeSize;
  138. ctx.strokeStyle = "#5C0D11";
  139. ctx.stroke();
  140. ctx.font = '100px Consolas, Monaco, monospace';
  141. const tw = ctx.measureText("w").width;
  142. const fs = Math.min((( 100 / (tw * 3))) * canvas.width, canvas.width );
  143. ctx.font = `${fs.toFixed(2)}px Consolas, Monaco, monospace`;
  144. ctx.fillStyle = "#5C0D11";
  145. ctx.strokeStyle = "#FFF";
  146. const t = `${weight}`;
  147. const tl = t.length > 2 ? edgeSize : edgeSize * 2;
  148. ctx.strokeText(`${weight}`,tl, fs);
  149. ctx.fillText(`${weight}`, tl, fs);
  150. canvas.toBlob(function(blob) {
  151. const link = canvas.toDataURL('image/png');
  152. const favicon = document.createElement("link");
  153. favicon.rel = "icon";
  154. favicon.href = URL.createObjectURL(blob);
  155. document.head.appendChild(favicon);
  156. });
  157. }
  158.  
  159. CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {
  160. if (w < 2 * r) r = w / 2;
  161. if (h < 2 * r) r = h / 2;
  162. this.beginPath();
  163. this.moveTo(x+r, y);
  164. this.arcTo(x+w, y, x+w, y+h, r);
  165. this.arcTo(x+w, y+h, x, y+h, r);
  166. this.arcTo(x, y+h, x, y, r);
  167. this.arcTo(x, y, x+w, y, r);
  168. this.closePath();
  169. return this;
  170. }
  171.  
  172.  
  173. if(window.location.pathname == "/mytags")saveMyTagData();
  174. if(window.location.pathname.slice(0, 3) == '/g/')dyeing();