Go to kemono.su

Go to the corresponding kemono.su page from an artist's page. Supports Patreon, Pixiv, Fanbox and Fantia

  1. // ==UserScript==
  2. // @name Go to kemono.su
  3. // @name:ja kemono.suへ移動
  4. // @namespace https://greasyfork.org/ja/users/1126644-s-k-script
  5. // @version 0.2.2
  6. // @description Go to the corresponding kemono.su page from an artist's page. Supports Patreon, Pixiv, Fanbox and Fantia
  7. // @description:ja アーティストのページから対応するkemono.suのページへ移動します。Pixiv, Fanbox, Fantia, Patreonをサポートしています。
  8. // @author S.K.Script
  9. // @homepage https://gitler.moe/skscript/redirect2kemono
  10. // @license GPL-3.0-only
  11. // @match https://fantia.jp/*
  12. // @match https://*.fanbox.cc/*
  13. // @match https://www.pixiv.net/*
  14. // @match https://www.patreon.com/*
  15. // @match https://kemono.su/*
  16. // @match https://kemono.party/*
  17. // @icon https://www.google.com/s2/favicons?sz=64&domain=kemono.su
  18. // @grant none
  19. // @run-at context-menu
  20. // ==/UserScript==
  21.  
  22. (function() {
  23. 'use strict';
  24.  
  25. class FantiaUrl {
  26. static check(href) {
  27. return !!href.match(/^https:\/\/fantia.jp/i);
  28. }
  29.  
  30. constructor(href) {
  31. this.href = href;
  32. }
  33.  
  34. extract_metadata() {
  35. const re = /https:\/\/fantia.jp\/fanclubs\/(?<userid>\d+)/i;
  36. const match = this.href.match(re);
  37. if(match) {
  38. return {ok: match.groups.userid};
  39. }
  40. else {
  41. let result = undefined;
  42. document.querySelectorAll(".fanclub-name > a").forEach(element => {
  43. console.log(element, element.href);
  44. const match = element.href.match(re);
  45. if(match) {
  46. result = {ok: match.groups.userid};
  47. }
  48. });
  49. if (result) { return result };
  50. return {err: 'Try again in the top page of this fanclub.\nファンクラブのトップページに移動してからもう一度実行してください'};
  51. }
  52. }
  53.  
  54. generate_kemono_url(user_id) {
  55. return 'https://kemono.su/fantia/user/' + user_id;
  56. }
  57. }
  58.  
  59. class FanboxUrl {
  60. static check(href) {
  61. return !!href.match(/^https:\/\/\w+.fanbox.cc/i);
  62. }
  63.  
  64. constructor(href) {
  65. this.href = href;
  66. }
  67.  
  68. extract_metadata() {
  69. return {err: 'Try again in the Pixiv user page of this person. Note: Pixiv and Fanbox are run by the same company.\nこの人のPixiv(Fanboxではなく)のユーザーページへ移動してからもう一度実行してください'};
  70. }
  71.  
  72. generate_kemono_url(user_id) {
  73. return 'https://kemono.su/fanbox/user/' + user_id;
  74. }
  75. }
  76.  
  77. class PixivUrl {
  78. static check(href) {
  79. return !!href.match(/https:\/\/www.pixiv.net/i);
  80. }
  81.  
  82. constructor(href) {
  83. this.href = href;
  84. }
  85.  
  86. extract_metadata() {
  87. const re = /https:\/\/www.pixiv.net\/users\/(?<userid>\d+)/i;
  88. const match = href.match(re);
  89. if(match) {
  90. return {ok: match.groups.userid};
  91. }
  92. else {
  93. return {err: 'Try again in the Pixiv user page of this person.\nPixivのユーザーページに移動してからもう一度実行してください'};
  94. }
  95. }
  96.  
  97. generate_kemono_url(user_id) {
  98. return 'https://kemono.su/fanbox/user/' + user_id;
  99. }
  100. }
  101.  
  102. class PatreonUrl {
  103. static check(href) {
  104. return !!href.match(/https:\/\/www.patreon.com/i);
  105. }
  106.  
  107. constructor(href) {
  108. this.href = href;
  109. }
  110.  
  111. extract_metadata() {
  112. // https://www.patreon.com/user?u=35870453
  113. const re = /https:\/\/www.patreon.com\/user\?u=(?<userid>\d+)/i;
  114. const match = href.match(re);
  115. if(match) {
  116. return {ok: match.groups.userid};
  117. }
  118. else {
  119. return {err: 'Try again in the Patreon user page of this person.\nPatreonのユーザーページに移動してからもう一度実行してください'};
  120. }
  121. }
  122.  
  123. generate_kemono_url(user_id) {
  124. return 'https://kemono.su/patreon/user/' + user_id;
  125. }
  126. }
  127.  
  128. class KemonoUrl {
  129. static check(href) {
  130. return !!href.match(/https:\/\/kemono.(su|party)/i);
  131. }
  132.  
  133. constructor(href) {
  134. this.href = href;
  135. }
  136.  
  137. extract_metadata() {
  138. const re = /https:\/\/kemono.(su|party)\/(?<platform>\w+)\/user\/(?<userid>\d+)/i;
  139. const match = href.match(re);
  140. if(match) {
  141. return {ok: {userid: match.groups.userid, platform: match.groups.platform}};
  142. }
  143. else {
  144. return {err: '?'};
  145. }
  146. }
  147.  
  148. generate_kemono_url(metadata) {
  149. return 'https://kemono.su/' + metadata.platform + '/user/' + metadata.userid;
  150. }
  151. }
  152.  
  153. const href = location.href;
  154.  
  155. let url;
  156. if(FantiaUrl.check(href)) {
  157. url = new FantiaUrl(href);
  158. }
  159. else if(FanboxUrl.check(href)) {
  160. url = new FanboxUrl(href);
  161. }
  162. else if(PixivUrl.check(href)) {
  163. url = new PixivUrl(href);
  164. }
  165. else if(PatreonUrl.check(href)) {
  166. url = new PatreonUrl(href);
  167. }
  168. else if(KemonoUrl.check(href)) {
  169. url = new KemonoUrl(href);
  170. }
  171. else {
  172. url = undefined;
  173. }
  174.  
  175. if(!url) {
  176. window.alert('Not supported / 未対応/非対応です');
  177. return;
  178. }
  179.  
  180. const result = url.extract_metadata();
  181. if(result.ok) {
  182. const metadata = result.ok;
  183. const kemono_url = url.generate_kemono_url(metadata);
  184. window.open(kemono_url, '_blank');
  185. }
  186. else {
  187. const err_message = result.err ? result.err : 'Error / なんかエラーだって';
  188. window.alert(err_message);
  189. }
  190.  
  191. })();