Skip to content

Instantly share code, notes, and snippets.

@ernstki
Last active July 25, 2023 23:47
Show Gist options
  • Save ernstki/31447ba40685f21b24bda34e16875712 to your computer and use it in GitHub Desktop.
Save ernstki/31447ba40685f21b24bda34e16875712 to your computer and use it in GitHub Desktop.
Copy URLs of full-resolution images from Meetup event photos page
// ==UserScript==
// @name Copy Meetup full-res URLs
// @namespace https://gist.github.com/ernstki
// @version 1.0
// @description Copy URLs of full-resolution images from Meetup event photos page to the clipboard
// @author Kevin Ernst
// @match https://www.meetup.com/*
// @icon https://icons.duckduckgo.com/ip2/meetup.com.ico
// @grant GM_setClipboard
// ==/UserScript==
function onAppearElement(sel, cb) {
// author: https://github.com/joeytwiddle
// source: https://github.com/Tampermonkey/tampermonkey/issues/1279#issuecomment-875386821
'use strict';
const ATTEMPTS = 43;
let att = 0;
let tryIt = function() {
let e = document.querySelector(sel);
if (e) {
console.info(`Element '${sel}' appeared; running callback.`);
cb(e);
} else {
att++;
if (att >= ATTEMPTS) {
console.warn(`Giving up after ${ATTEMPTS} attempts; couldn't find '${sel}'`);
} else {
setTimeout(tryIt, 250 * Math.pow(1.1, att));
}
}
};
tryIt();
}
function addFullResUrlButton() {
'use strict';
var a = document.querySelector('#add-to-album');
var b = a.cloneNode(true);
b.id = "copy-full-res-urls";
b.removeChild(b.getElementsByTagName('div')[0]); // remove SVG icon
b.removeAttribute('data-event-label');
b.removeAttribute('data-event-category');
b.addEventListener('click', copyUrls);
var span = b.getElementsByTagName('span')[0];
span.textContent = "Copy full-res URLs";
a.parentNode.appendChild(b);
// force width so that changing the text later doesn't resize the button
console.info(`New button's span.clientWidth (after .appendChild) = ${span.clientWidth}`);
span.style.minWidth = `${span.clientWidth}px`;
}
function copyUrls(urls) {
'use strict';
var meetupPhotos = Array.from(document.querySelectorAll('img.rounded-lg'));
var meetupHighResUrls = meetupPhotos.filter(x => x.src.match(/\.webp/))
.map(x => x.src.replace(/(.*)\/\w+_(\d+).webp.*/, "$1/highres_$2.jpeg"));
console.info(meetupHighResUrls);
GM_setClipboard(JSON.stringify(meetupHighResUrls));
var b = document.querySelector('#copy-full-res-urls');
var span = b.getElementsByTagName('span')[0];
span.textContent = 'Copied!'
setTimeout(() => {span.textContent = 'Copy full-res URLs'}, 1500);
}
onAppearElement('#add-to-album', addFullResUrlButton);
@ernstki
Copy link
Author

ernstki commented Jul 25, 2023

Notes

A key point from the GreaseSpot wiki:

Gist is GitHub's "paste" service, where any set of simple files can be pasted into a web form and saved. Gist files may be named. If they are given the .user.js suffix, then the raw link for the gist will serve perfectly as an install. HTTPS is available and used by default. (emphasis mine)

In order to actually do something with the JSON array copied to the clipboard, you could try something like this:

# check to make sure you got all photos
pbpaste | jq -r .[] | wc -l  

# be nice
pbpaste | jq -r .[] | parallel -j4 --delay 2s wget -nv

Caveats

Meetup event photo pages lazy-load now. The userscript doesn't attempt to load all the images for you—although maybe with some manipulation of .scrollTo or .scrollTop, that might be possible.

That means that, for now, you, the human, need to scroll down until all images are loaded, then click the "Copy full-res URLs" button.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment