Pinterest Slideshow

Start a slideshow on any Pinterest page where there's pins. Clean and minimalist design. 5s interval between slides. Press ctrl+spacebar to start, left/right keys to navigate.

  1. // ==UserScript==
  2. // @name Pinterest Slideshow
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.5.1
  5. // @description Start a slideshow on any Pinterest page where there's pins. Clean and minimalist design. 5s interval between slides. Press ctrl+spacebar to start, left/right keys to navigate.
  6. // @author French Bond
  7. // @include https://*.pinterest.*/*
  8. // @grant none
  9. // @require http://code.jquery.com/jquery-latest.js
  10. // ==/UserScript==
  11.  
  12. /* globals jQuery, $ */
  13.  
  14. $(function () {
  15. 'use strict';
  16.  
  17. const slideInterval = 5000;
  18. let pins = [];
  19. let c = 0; // Current slide number
  20. let interval;
  21. let running = 0;
  22.  
  23. function init() {
  24. addSlideShowButton();
  25. addSlideShowImageAndControls();
  26. }
  27.  
  28. function addSlideShowButton() {
  29. $('body').append(
  30. '<div style="position: fixed; bottom: 20px; left: 10px;">' +
  31. '<div>' +
  32. '<span class="slideshow-button" style="cursor:pointer; background-color: #C92228; color: #fff; padding: 8px; font-weight: bold; font-size: 14px; border-radius: 4px;">Slideshow</span>' +
  33. '</div>' +
  34. '</div>'
  35. );
  36.  
  37. $('.slideshow-button').click(startSlideshow);
  38. }
  39.  
  40. function addSlideShowImageAndControls() {
  41. // Add slideshow div
  42. $('html').append(
  43. '<div class="slideshow" style="display:none; position: fixed; width: 100%; height: 100%; background-color: #333; z-index: 10000000; left: 0; top: 0;">' +
  44. '<img style="object-fit: contain; width: 100%; height: 100%;">' +
  45. '</div>'
  46. );
  47.  
  48. // Add the slideshow menu
  49. $('.slideshow').append(
  50. '<div class="menu-slideshow" style="position: absolute; left:3px; top:3px; font-size:14px;"></div>'
  51. );
  52.  
  53. $('.menu-slideshow')
  54. .append(
  55. '<div class="stop-slideshow" style="cursor:pointer; background-color: #C92228; color: #fff; padding: 7px; float:left; font-weight: bold; border-radius: 4px;">Stop</div>'
  56. )
  57. //.append('<div class="options-slideshow" style="cursor:pointer; background-color: #666; color: #fff; padding: 7px; float:left; border-radius: 4px; margin-left:3px;">Options</div>')
  58. .append('<div class="info-slideshow" style="color: #ccc; padding: 7px; float:left;">/</div>');
  59.  
  60. // Handle Stop Button
  61. $('.stop-slideshow').click(function () {
  62. clearInterval(interval);
  63. running = 0;
  64. $('.slideshow').hide();
  65. console.log('Slideshow stopped');
  66. });
  67. }
  68.  
  69. function getPinsInfo() {
  70. return $('[role="listitem"]')
  71. .map(function () {
  72. const a = $(this).find('a[aria-label*="pin"]').first();
  73. return {
  74. href: a.attr('href'),
  75. // Not always available
  76. src: a
  77. .find('img[srcset]')
  78. ?.attr('srcset')
  79. ?.match(/([^ ]*) 4x$/)[1],
  80. };
  81. })
  82. .get();
  83. }
  84.  
  85. function startSlideshow() {
  86. $('.slideshow').show();
  87.  
  88. pins = getPinsInfo();
  89. console.log(pins);
  90.  
  91. console.log('Starting slideshow');
  92. console.log('Number of slides: ' + pins.length);
  93. console.log('Slide interval: ' + slideInterval / 1000 + 's');
  94.  
  95. // Start from first slide
  96. c = 0;
  97. running = 1;
  98.  
  99. // Reset interval
  100. clearInterval(interval);
  101. interval = setInterval(nextSlide, slideInterval);
  102.  
  103. showSlide();
  104. }
  105.  
  106. async function showSlide() {
  107. console.log('Current slide: ' + (c + 1));
  108.  
  109. // Show slide
  110. const pin = pins[c];
  111. const imgSrc = pin.src || (await getImgSrc(pin));
  112. $('.slideshow img').attr('src', imgSrc);
  113. $('.info-slideshow').html(c + 1 + '/' + pins.length);
  114.  
  115. preloadNextSlide();
  116. }
  117.  
  118. async function preloadNextSlide() {
  119. const nextSlide = c + 1;
  120. if (nextSlide > pins.length - 1) return;
  121. const pin = pins[nextSlide];
  122. const imgSrc = pin.src || (await getImgSrc(pin));
  123. console.log('Preloading next slide: ' + imgSrc);
  124. preloadPictures([imgSrc]);
  125. }
  126.  
  127. function preloadPictures(pictureUrls, callback) {
  128. var i,
  129. j,
  130. loaded = 0;
  131.  
  132. for (i = 0, j = pictureUrls.length; i < j; i++) {
  133. (function (img, src) {
  134. img.onload = function () {
  135. if (++loaded == pictureUrls.length && callback) {
  136. callback();
  137. }
  138. };
  139. img.onerror = function () {};
  140. img.onabort = function () {};
  141. img.src = src;
  142. })(new Image(), pictureUrls[i]);
  143. }
  144. }
  145.  
  146. async function getImgSrc(pin) {
  147. const url = pin.href;
  148. try {
  149. // Fetch the HTML content from the URL
  150. const response = await fetch(url);
  151. const html = await response.text();
  152.  
  153. // Parse the HTML content
  154. const parser = new DOMParser();
  155. const doc = parser.parseFromString(html, 'text/html');
  156.  
  157. // Find the image with the specified alt text and return its src
  158. const img = doc.querySelector('img[alt="Story pin image"]');
  159.  
  160. // Cache the src on the pin object
  161. pin.src = img ? img.src : null;
  162.  
  163. return pin.src;
  164. } catch (error) {
  165. console.error('Error fetching or parsing:', error);
  166. return null;
  167. }
  168. }
  169.  
  170. function nextSlide() {
  171. c++;
  172. if (c > pins.length - 1) c = 0;
  173. showSlide();
  174. }
  175.  
  176. function previousSlide() {
  177. c--;
  178. if (c < 0) c = pins.length - 1;
  179. showSlide();
  180. }
  181.  
  182. $('body').keydown(function (e) {
  183. if (running) {
  184. if (e.keyCode == 37) {
  185. // left
  186. clearInterval(interval);
  187. previousSlide();
  188. interval = setInterval(nextSlide, slideInterval);
  189. }
  190. if (e.keyCode == 39) {
  191. // right
  192. clearInterval(interval);
  193. nextSlide();
  194. interval = setInterval(nextSlide, slideInterval);
  195. }
  196. } else {
  197. if (e.ctrlKey && e.keyCode == 32) startSlideshow();
  198. }
  199. });
  200.  
  201. init();
  202. });