This commit is contained in:
Vilyaem 2025-04-26 02:37:06 -04:00
commit 97e82ae1de
5 changed files with 155 additions and 0 deletions

19
README.md Normal file
View file

@ -0,0 +1,19 @@
# NotSmug
NotSmug is a Chromium-compatible browser extension that allows you to download
or view paywalled images from the SmugMug platform en masse. I made this so I
could access church photos.
## How to use/install
1. Clone/download this repository
2. Go to chrome://extensions
3. Load unpacked (you might need to enable some developer mode)
4. Select the folder containing NotSmug
5. Go to a SmugMug gallery that is paywalled
6. Click on the extension, you can choose to open all images in a new tab
or download all images.
## LICENSE
Public Domain CC0, as all things should be.

48
content.js Normal file
View file

@ -0,0 +1,48 @@
console.log("NotSmug loaded...");
/*********************************************
* Description - Get highest quality version of an image
* Author - Vilyaem
* *******************************************/
function Upgrade(url) {
return url.replace(/(-[A-Z]\d+)?\.jpg/, '-X5.jpg');
}
/*********************************************
* Description - Get all image URLs possible
* Author - Vilyaem
* *******************************************/
function ExtractImages() {
const allUrls = new Set();
/*extract image urls everywhere, they start with photos.smugmug.com*/
document.querySelectorAll('*').forEach(el => {
/*attributes*/
['src', 'href', 'data-src'].forEach(attr => {
const val = el.getAttribute?.(attr);
if (val && val.includes('photos.smugmug.com') && val.endsWith('.jpg')) {
allUrls.add(Upgrade(val));
}
});
const style = el.getAttribute?.('style') || '';
const matches = [...style.matchAll(/url\(["']?(https:\/\/photos\.smugmug\.com\/.*?\.jpg)["']?\)/g)];
matches.forEach(match => allUrls.add(Upgrade(match[1])));
});
/*scripts and styles*/
document.querySelectorAll('script, style').forEach(node => {
const text = node.textContent;
const matches = [...text.matchAll(/https:\/\/photos\.smugmug\.com\/.*?\.jpg/g)];
matches.forEach(match => allUrls.add(Upgrade(match[0])));
});
return Array.from(allUrls);
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "GetImageURLs") {
sendResponse({ urls: ExtractImages() });
}
});

18
manifest.json Normal file
View file

@ -0,0 +1,18 @@
{
"manifest_version": 3,
"name": "NotSmug",
"author": "Vilyaem",
"version": "1.0",
"description": "Allows you to download download-restricted SmugMug images.",
"permissions": ["scripting", "tabs", "downloads"],
"action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["*://*.smugmug.com/*"],
"js": ["content.js"],
"run_at": "document_idle"
}
]
}

26
popup.html Normal file
View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: sans-serif;
min-width: 220px;
padding: 10px;
}
button {
width: 100%;
margin-top: 5px;
padding: 10px;
font-size: 15px;
cursor: pointer;
background-color: cornflower;
color: black;
}
</style>
</head>
<body>
<button id="open">Open SmugMug Images in individual tabs</button>
<button id="download">Download all SmugMug images</button>
<script src="popup.js"></script>
</body>
</html>

44
popup.js Normal file
View file

@ -0,0 +1,44 @@
/*********************************************
* Description - Get all images in the current tab
* Author - Vilyaem
* *******************************************/
async function GetImagesFromTab() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab || !tab.id || !tab.url.startsWith("http")) {
alert("Not a valid tab.");
return [];
}
return new Promise(resolve => {
chrome.tabs.sendMessage(tab.id, { action: "GetImageURLs" }, (response) => {
if (chrome.runtime.lastError || !response) {
alert("Content script not available. Try refreshing the page.");
return resolve([]);
}
resolve(response.urls || []);
});
});
}
/*********************************************
* Description - Open all images in a new tab
* Author - Vilyaem
* *******************************************/
document.getElementById("open").addEventListener("click", async () => {
const urls = await GetImagesFromTab();
if (urls.length === 0) return alert("No image URLs found.");
urls.forEach(url => chrome.tabs.create({ url }));
});
/*********************************************
* Description - Download all images
* Author - Vilyaem
* *******************************************/
document.getElementById("download").addEventListener("click", async () => {
const urls = await GetImagesFromTab();
if (urls.length === 0) return alert("No image URLs found.");
urls.forEach(url => {
chrome.downloads.download({ url });
});
});