Gelbooru Preview and Download

Quick preview images and download in simple click

2020-11-14 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

  1. // ==UserScript==
  2. // @name Gelbooru Preview and Download
  3. // @namespace https://sleazyfork.org/
  4. // @version 2.0.0
  5. // @description Quick preview images and download in simple click
  6. // @author Ubhelbr
  7. // @match https://gelbooru.com/index.php?page=post&s=list*
  8. // @grant GM_download
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // ==/UserScript==
  12.  
  13. function fetchPage(link) {
  14. return new Promise((resolve, reject) => {
  15. if (dataStore[link.id]) {
  16. resolve(dataStore[link.id])
  17. return
  18. }
  19. fetch(link)
  20. .then(function(response) {
  21. return response.text()
  22. })
  23. .then(function(html) {
  24. let parser = new DOMParser()
  25. , doc = parser.parseFromString(html, "text/html")
  26. , images = getImage(doc)
  27. dataStore[link.id] = {
  28. name: getTags(doc),
  29. image: images.full,
  30. sample: images.sample
  31. }
  32. resolve(dataStore[link.id])
  33. })
  34. .catch(function(err) {
  35. reject(err)
  36. console.log('Failed to fetch page: ', err)
  37. })
  38. })
  39. }
  40.  
  41. var dataStore = {}
  42.  
  43. function getTags(doc, options = {
  44. categories: ['character', 'artist', 'tag:reverse'],
  45. limit: 20
  46. }) {
  47. let tagDiv = doc.querySelector('#tag-list div')
  48. , list = {}, currentCategory
  49. ;[].find.call(tagDiv.children, el => {
  50. if (el.tagName == 'DIV') {
  51. currentCategory = el.innerText.toLowerCase()
  52. list[currentCategory] = []
  53. }
  54. else if (el.tagName == 'H3') {
  55. return 1
  56. }
  57. else if (el.tagName == 'LI'){
  58. list[currentCategory].push({
  59. tag: el.querySelector('a[href^="index.php?page=post"]').innerText.replace(/ /g, '_'),
  60. count: + el.querySelector('span').innerText
  61. })
  62. }
  63. return 0
  64. })
  65. let allTags = []
  66. options.categories.forEach(category => {
  67. let s = category.split(':')
  68. , cat = list[s[0]]
  69. if (!cat) return;
  70. if (s[1] == 'reverse') {
  71. cat.sort((a,b) => a.count - b.count)
  72. }
  73. cat.map(i => i.tag).forEach(tag => {
  74. if (!tag.match(/["#%&\*:<>\?\/\\{\|}]/) && tag.length)
  75. allTags.push(tag)
  76. })
  77. })
  78. return allTags.slice(0, options.limit).join('-')
  79. }
  80.  
  81. function getImage(doc) {
  82. let s = doc.querySelector('.contain-push > script').innerText
  83. , domain = s.match(/'domain':'(.+?)'/)[1]
  84. , dir = s.match(/'dir':'(.+?)'/)[1]
  85. , img = s.match(/'img':'(.+?)'/)[1]
  86. , base_dir = s.match(/'base_dir':'(.+?)'/)[1]
  87. , sample_dir = s.match(/'sample_dir':'(.+?)'/)[1]
  88. , sample_width = s.match(/'sample_width':'(.+?)'/)[1]
  89. let full = `${domain}${base_dir}/${dir}/${img}`
  90. return {
  91. full: full,
  92. sample: (sample_width > 0) ? `${domain}${sample_dir}/${dir}/sample_${img.match(/(.+)\.[^\.]+$/)[1]}.jpg` : full
  93. }
  94. }
  95.  
  96. function init() {
  97. let downloaded = GM_getValue('GBPAD-downloaded')
  98. downloaded = (typeof downloaded !== 'string') ? [] : downloaded.split(',')
  99. ;[].forEach.call(document.querySelectorAll('div.thumbnail-preview span'), link => {
  100. let markAsDownloaded = ~downloaded.indexOf(link.id)
  101. , a = link.querySelector('a')
  102. , thumb = a.querySelector('img')
  103. if (markAsDownloaded)
  104. thumb.style.boxShadow = "rgb(43, 175, 0) 0px 0px 0px 2px"
  105. a.onclick = ev => {
  106. ev.preventDefault()
  107. thumb.style.boxShadow = "rgb(32, 173, 255) 0px 0px 0px 2px"
  108. fetchPage(a).then(data => {
  109. GM_download({
  110. url: data.image,
  111. name: `${a.id.split('p')[1]} ${data.name}.${data.image.match(/(:?.+)\.(.+?)$/)[2]}`,
  112. onload: () => {
  113. thumb.style.boxShadow = "rgb(43, 175, 0) 0px 0px 0px 2px"
  114. }
  115. })
  116. if (!markAsDownloaded) {
  117. downloaded.push(link.id)
  118. GM_setValue('GBPAD-downloaded', downloaded.join(','))
  119. }
  120. })
  121. }
  122. thumb.addEventListener('mouseenter', () => {
  123. if (thumb.classList.contains('GBPAD-expanded') || thumb.classList.contains('webm')) return;
  124. setTimeout(() => {
  125. fetchPage(a).then(data => {
  126. thumb.style.width = `${thumb.width + 10}px`
  127. thumb.style.height = `${thumb.height + 10}px`
  128. thumb.src = data.sample
  129. thumb.classList.add('GBPAD-expanded')
  130. })
  131. }, 250)
  132. });
  133. })
  134.  
  135. injector.inject('GBPAD', `
  136. .thumbnail-preview img {
  137. transform: scale(1);
  138. transition: transform .2s, box-shadow .2s;
  139. }
  140. .thumbnail-preview img:hover {
  141. transform: scale(2);
  142. z-index: 1;
  143. position: relative;
  144. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  145. }
  146. `)
  147. }
  148.  
  149. // CSS injector
  150. var injector = {
  151. inject: function(alias, css) {
  152. var id = `injector:${alias}`
  153. var existing = document.getElementById(id)
  154. if(existing) {
  155. existing.innerHTML = css
  156. return
  157. }
  158. var head = document.head || document.getElementsByTagName('head')[0]
  159. , style = document.createElement('style');
  160. style.type = 'text/css'
  161. style.id = id
  162. if (style.styleSheet) {
  163. style.styleSheet.cssText = css
  164. } else {
  165. style.appendChild(document.createTextNode(css))
  166. }
  167. head.appendChild(style)
  168. },
  169. remove: function(alias) {
  170. var id = `injector:${alias}`
  171. var style = document.getElementById(id)
  172. if(style) {
  173. var head = document.head || document.getElementsByTagName('head')[0]
  174. if(head)
  175. head.removeChild(document.getElementById(id))
  176. }
  177. }
  178. }
  179.  
  180. init()