// ==UserScript==
// @name Pinterest Slideshow
// @namespace http://tampermonkey.net/
// @version 1.5.1
// @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.
// @author French Bond
// @include https://*.pinterest.*/*
// @grant none
// @require http://code.jquery.com/jquery-latest.js
// @downloadURL https://update.greasyfork.icu/scripts/24116/Pinterest%20Slideshow.user.js
// @updateURL https://update.greasyfork.icu/scripts/24116/Pinterest%20Slideshow.meta.js
// ==/UserScript==
/* globals jQuery, $ */
$(function () {
'use strict';
const slideInterval = 5000;
let pins = [];
let c = 0; // Current slide number
let interval;
let running = 0;
function init() {
addSlideShowButton();
addSlideShowImageAndControls();
}
function addSlideShowButton() {
$('body').append(
'
' +
'
' +
'Slideshow' +
'
' +
'
'
);
$('.slideshow-button').click(startSlideshow);
}
function addSlideShowImageAndControls() {
// Add slideshow div
$('html').append(
'' +
'
![]()
' +
'
'
);
// Add the slideshow menu
$('.slideshow').append(
''
);
$('.menu-slideshow')
.append(
'Stop
'
)
//.append('Options
')
.append('/
');
// Handle Stop Button
$('.stop-slideshow').click(function () {
clearInterval(interval);
running = 0;
$('.slideshow').hide();
console.log('Slideshow stopped');
});
}
function getPinsInfo() {
return $('[role="listitem"]')
.map(function () {
const a = $(this).find('a[aria-label*="pin"]').first();
return {
href: a.attr('href'),
// Not always available
src: a
.find('img[srcset]')
?.attr('srcset')
?.match(/([^ ]*) 4x$/)[1],
};
})
.get();
}
function startSlideshow() {
$('.slideshow').show();
pins = getPinsInfo();
console.log(pins);
console.log('Starting slideshow');
console.log('Number of slides: ' + pins.length);
console.log('Slide interval: ' + slideInterval / 1000 + 's');
// Start from first slide
c = 0;
running = 1;
// Reset interval
clearInterval(interval);
interval = setInterval(nextSlide, slideInterval);
showSlide();
}
async function showSlide() {
console.log('Current slide: ' + (c + 1));
// Show slide
const pin = pins[c];
const imgSrc = pin.src || (await getImgSrc(pin));
$('.slideshow img').attr('src', imgSrc);
$('.info-slideshow').html(c + 1 + '/' + pins.length);
preloadNextSlide();
}
async function preloadNextSlide() {
const nextSlide = c + 1;
if (nextSlide > pins.length - 1) return;
const pin = pins[nextSlide];
const imgSrc = pin.src || (await getImgSrc(pin));
console.log('Preloading next slide: ' + imgSrc);
preloadPictures([imgSrc]);
}
function preloadPictures(pictureUrls, callback) {
var i,
j,
loaded = 0;
for (i = 0, j = pictureUrls.length; i < j; i++) {
(function (img, src) {
img.onload = function () {
if (++loaded == pictureUrls.length && callback) {
callback();
}
};
img.onerror = function () {};
img.onabort = function () {};
img.src = src;
})(new Image(), pictureUrls[i]);
}
}
async function getImgSrc(pin) {
const url = pin.href;
try {
// Fetch the HTML content from the URL
const response = await fetch(url);
const html = await response.text();
// Parse the HTML content
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
// Find the image with the specified alt text and return its src
const img = doc.querySelector('img[alt="Story pin image"]');
// Cache the src on the pin object
pin.src = img ? img.src : null;
return pin.src;
} catch (error) {
console.error('Error fetching or parsing:', error);
return null;
}
}
function nextSlide() {
c++;
if (c > pins.length - 1) c = 0;
showSlide();
}
function previousSlide() {
c--;
if (c < 0) c = pins.length - 1;
showSlide();
}
$('body').keydown(function (e) {
if (running) {
if (e.keyCode == 37) {
// left
clearInterval(interval);
previousSlide();
interval = setInterval(nextSlide, slideInterval);
}
if (e.keyCode == 39) {
// right
clearInterval(interval);
nextSlide();
interval = setInterval(nextSlide, slideInterval);
}
} else {
if (e.ctrlKey && e.keyCode == 32) startSlideshow();
}
});
init();
});