ViewOnYP

Links various membership platforms to Kemono and Coomer.

Mint 2022.01.06.. Lásd a legutóbbi verzió

  1. // @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT
  2. /* eslint-env browser, greasemonkey */
  3.  
  4. // ==UserScript==
  5. // @name ViewOnYP
  6. // @name:de ViewOnYP
  7. // @name:en ViewOnYP
  8. // @namespace https://github.com/TheLastZombie/
  9. // @version 2.8.1
  10. // @description Links various membership platforms to Kemono and Coomer.
  11. // @description:de Vernetzt verschiedene Mitgliedschaftsplattformen mit Kemono und Coomer.
  12. // @description:en Links various membership platforms to Kemono and Coomer.
  13. // @homepageURL https://github.com/TheLastZombie/userscripts#viewonyp-
  14. // @supportURL https://github.com/TheLastZombie/userscripts/issues/new?labels=ViewOnYP
  15. // @contributionURL https://ko-fi.com/rcrsch
  16. // @author TheLastZombie
  17. // @match *://www.dlsite.com/*/circle/profile/=/maker_id/*
  18. // @match *://*.fanbox.cc/
  19. // @match *://www.fanbox.cc/@*
  20. // @match *://fantia.jp/fanclubs/*
  21. // @match *://gumroad.com/*
  22. // @match *://onlyfans.com/*
  23. // @match *://www.patreon.com/*
  24. // @match *://www.subscribestar.com/*
  25. // @match *://subscribestar.adult/*
  26. // @connect coomer.party
  27. // @connect kemono.party
  28. // @connect api.fanbox.cc
  29. // @grant GM.deleteValue
  30. // @grant GM_deleteValue
  31. // @grant GM.getValue
  32. // @grant GM_getValue
  33. // @grant GM.registerMenuCommand
  34. // @grant GM_registerMenuCommand
  35. // @grant GM.setValue
  36. // @grant GM_setValue
  37. // @grant GM.xmlHttpRequest
  38. // @grant GM_xmlhttpRequest
  39. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
  40. // @icon https://raw.githubusercontent.com/TheLastZombie/userscripts/master/icons/ViewOnYP.ico
  41. // @copyright 2020-2022, TheLastZombie (https://github.com/TheLastZombie/)
  42. // @license MIT; https://github.com/TheLastZombie/userscripts/blob/master/LICENSE
  43. // ==/UserScript==
  44.  
  45. // ==OpenUserJS==
  46. // @author TheLastZombie
  47. // ==/OpenUserJS==
  48.  
  49. (async function () {
  50. if (!await GM.getValue('cache2')) await GM.setValue('cache2', {})
  51. const cache = await GM.getValue('cache2')
  52.  
  53. if (await GM.getValue('cache')) {
  54. cache.Kemono = await GM.getValue('cache')
  55. await GM.deleteValue('cache')
  56. }
  57.  
  58. const sites = [
  59. {
  60. name: 'Coomer',
  61. check: 'https://coomer.party/api/creators',
  62. cache: (response, x) => {
  63. JSON.parse(response.responseText).forEach(y => {
  64. if (!cache[x.name]) cache[x.name] = {}
  65. if (!cache[x.name][y.service]) cache[x.name][y.service] = []
  66. cache[x.name][y.service].push(y.id)
  67. })
  68. return cache
  69. },
  70. get: (response, host, user) => {
  71. return Boolean(JSON.parse(response.responseText).filter(x => x.service === host).filter(x => x.id === user).length)
  72. },
  73. profile: 'https://coomer.party/$HOST/user/$USER'
  74. },
  75. {
  76. name: 'Kemono',
  77. check: 'https://kemono.party/api/creators',
  78. cache: (response, x) => {
  79. JSON.parse(response.responseText).forEach(y => {
  80. if (!cache[x.name]) cache[x.name] = {}
  81. if (!cache[x.name][y.service]) cache[x.name][y.service] = []
  82. cache[x.name][y.service].push(y.id)
  83. })
  84. return cache
  85. },
  86. get: (response, host, user) => {
  87. return Boolean(JSON.parse(response.responseText).filter(x => x.service === host).filter(x => x.id === user).length)
  88. },
  89. profile: 'https://kemono.party/$HOST/user/$USER'
  90. }
  91. ]
  92.  
  93. GM.registerMenuCommand('Populate cache', () => {
  94. sites.forEach(x => {
  95. GM.xmlHttpRequest({
  96. url: x.check,
  97. method: 'GET',
  98. onload: async response => {
  99. const cache = x.cache(response, x)
  100. await GM.setValue('cache2', cache)
  101. alert('Populated cache for ' + x.name + '.')
  102. }
  103. })
  104. })
  105. })
  106.  
  107. GM.registerMenuCommand('Clear cache', () => {
  108. GM.deleteValue('cache2')
  109. .then(alert('Cache cleared successfully.'))
  110. })
  111.  
  112. document.getElementsByTagName('head')[0].insertAdjacentHTML('beforeend', `
  113. <style>
  114. #voyp {
  115. background: white;
  116. position: fixed;
  117. top: calc(100vh - 25px);
  118. left: 50%;
  119. transform: translateX(-50%);
  120. border-radius: 5px 5px 0 0;
  121. padding: 25px;
  122. box-shadow: 0 1px 2px 0 rgba(60,64,67,0.302), 0 1px 3px 1px rgba(60,64,67,0.149);
  123. text-align: center;
  124. z-index: 9999;
  125. }
  126. #voyp:hover {
  127. top: initial;
  128. bottom: 0;
  129. }
  130. #voyp div {
  131. font-size: small;
  132. text-transform: uppercase;
  133. margin-bottom: 12.5px;
  134. opacity: 0.5;
  135. text-align: center;
  136. }
  137. </style>
  138. `)
  139.  
  140. const host = window.location.hostname.split('.').slice(-2, -1)[0]
  141. if (!host) return
  142.  
  143. const p = new Promise((resolve, reject) => {
  144. switch (host) {
  145. case 'dlsite':
  146. resolve(document.location.pathname.split('/')[6].slice(0, -5))
  147. break
  148. case 'fanbox': {
  149. let creatorId = window.location.hostname.split('.').slice(-3, -2)[0]
  150. if (creatorId === 'www') creatorId = window.location.pathname.split('/')[1].slice(1)
  151.  
  152. GM.xmlHttpRequest({
  153. url: 'https://api.fanbox.cc/creator.get?creatorId=' + creatorId,
  154. headers: { Origin: 'https://fanbox.cc' },
  155. onload: response => resolve(JSON.parse(response.responseText).body.user.userId)
  156. })
  157. break
  158. }
  159. case 'fantia':
  160. resolve(document.location.pathname.split('/')[2])
  161. break
  162. case 'gumroad':
  163. resolve(document.querySelector('.creator-profile-wrapper').getAttribute('data-username'))
  164. break
  165. case 'patreon':
  166. resolve(document.head.innerHTML.match(/https:\/\/www\.patreon\.com\/api\/user\/\d+/)[0].slice(33))
  167. break
  168. case 'onlyfans':
  169. case 'subscribestar':
  170. resolve(document.location.pathname.split('/')[1])
  171. break
  172. }
  173. })
  174.  
  175. p.then(user => {
  176. sites.forEach(x => {
  177. if (cache[x.name] && cache[x.name][host] && cache[x.name][host].includes(user)) return show(x, host, user)
  178. GM.xmlHttpRequest({
  179. url: x.check,
  180. method: 'GET',
  181. onload: response => {
  182. if (x.get(response, host, user)) show(x, host, user)
  183. }
  184. })
  185. })
  186. })
  187.  
  188. function show (site, host, user) {
  189. if (!document.getElementById('voyp')) document.getElementsByTagName('body')[0].insertAdjacentHTML('beforeend', '<div id="voyp"><div>ViewOnYP</div></div>')
  190.  
  191. const name = site.name
  192. const url = site.profile.replace('$HOST', host).replace('$USER', user)
  193.  
  194. document.getElementById('voyp').insertAdjacentHTML('beforeend', name + ': <a href="' + url + '">' + url + '</a><br>')
  195.  
  196. if (!cache[site.name]) cache[site.name] = {}
  197. if (!cache[site.name][host]) cache[site.name][host] = []
  198. if (!cache[site.name][host].includes(user)) cache[site.name][host].push(user)
  199. GM.setValue('cache2', cache)
  200. }
  201. })()
  202.  
  203. // @license-end