Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Transform URL with regexp

If the site displays a thumbnail image, you can transform the URL to its full size URL with this feature, by defining multiple replace rules in the code box. For example:

```
```cfg
# baidu
imgsa\.baidu\.com/.+/(\w+\.\w+)$
imgsrc.baidu.com/forum/pic/item/$1
Expand All @@ -109,6 +109,14 @@ pbs\.twimg\.com/media/(.+\.\w+)$
pbs.twimg.com/media/$1:orig
```

You can also use it to exclude images from being picked, by setting the replacement to a single hyphen (`-`):

```cfg
# exclude images from example.com
example\.com/.*
-
```

* Each replace rule includes:
- A line of regex.
- A line of replacement.
Expand Down
3 changes: 2 additions & 1 deletion src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -635,8 +635,9 @@ async function singleDownload({url, env, tabId, frameId, referrer, alt}) {
url,
base: data && data.filename,
alt,
ext: data && data.ext
ext: data?.ext ? `.${data.ext}` : undefined
});
expandEnv(env);
const filePattern = pref.get("filePatternStandaloneEnabled") && env.pageContentType.startsWith("image/") ?
pref.get("filePatternStandalone") : pref.get("filePattern");
const filename = compileStringTemplate(filePattern)(env);
Expand Down
4 changes: 3 additions & 1 deletion src/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ function viewSourceElement(pickaId) {
}

function downloadImage({url, referrerPolicy = getDefaultReferrerPolicy(), alt}) {
url = transformURL(url);
browser.runtime.sendMessage({
method: "singleDownload",
env: window.top === window ? getEnv() : null,
Expand All @@ -83,6 +82,9 @@ function getImages() {
const images = new Map;
for (const {src, referrerPolicy, alt, pickaId} of getAllImages()) {
const url = transformURL(src)
if (!url) {
continue;
}
const image = {
url,
referrer: getReferrer(location.href, url, referrerPolicy || getDefaultReferrerPolicy()),
Expand Down
28 changes: 23 additions & 5 deletions src/lib/dragndrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import browser from "webextension-polyfill";
import * as imageUtil from "./image-util.js";
import {IS_CHROME} from "./env.js";
import {pref} from "./pref.js";
import {transformURL} from "./url-map.js";

export default function init({downloadImage}) {
const EVENT_OPTIONS = {passive: true};
Expand Down Expand Up @@ -100,12 +101,13 @@ export default function init({downloadImage}) {
if (!imageUtil.isImage(e.target) || !testEvent(e, context)) {
return;
}
const imageSrc = imageUtil.getSrcFromElement(e.target).next().value;
if (!imageSrc) {
let url = imageUtil.getSrcFromElement(e.target).next().value;
url = transformURL(url);
if (!url) {
return;
}
downloadImage({
url: imageSrc,
url,
referrerPolicy: e.target.referrerPolicy || undefined,
alt: e.target.alt
});
Expand Down Expand Up @@ -142,6 +144,11 @@ export default function init({downloadImage}) {
img = [...img.querySelectorAll("img")].find(i => i.offsetParent);
}
if (!img || !imageUtil.isImage(img)) return;
let url = imageUtil.getSrcFromElement(img).next().value;
url = transformURL(url);
if (!url) {
return;
}

const events = [
["dragover", dragOver, pref.get("dragndropHard")],
Expand All @@ -167,7 +174,7 @@ export default function init({downloadImage}) {
return;
}
downloadImage({
url: imageUtil.getSrcFromElement(img).next().value,
url,
referrerPolicy: img.referrerPolicy || undefined,
alt: img.alt
});
Expand All @@ -189,6 +196,7 @@ export default function init({downloadImage}) {
closeTimer,
decideHideTimer;
let buttonAni;
let imageUrl;

const state = createSwitch(
() => pref.get("downloadButton") && !IS_BLACKLISTED && !button && pref.get("enabled"),
Expand Down Expand Up @@ -225,13 +233,19 @@ export default function init({downloadImage}) {
// not an image
return;
}
let url = imageUtil.getSrcFromElement(el).next().value;
url = transformURL(url);
if (!url) {
return;
}
if (timer == null) {
// start countdown
timer = setTimeout(() => {
timer = null;
showDownloadButton();
}, pref.get("downloadButtonDelay"));
image = el;
imageUrl = url;
return;
}
}
Expand All @@ -249,13 +263,17 @@ export default function init({downloadImage}) {
function decideHideButton(e) {
var el = e.type == "mouseover" ? e.target : e.relatedTarget,
_isImage = el && isImage(el);
let url = _isImage ? transformURL(imageUtil.getSrcFromElement(el).next().value) : null;
_isImage = _isImage && url;
if (_isImage || el && el.closest(".image-picka-download-button")) {
if (closeTimer != null) {
clearTimeout(closeTimer);
closeTimer = null;
}
if (_isImage && el != image) {
// moved to another image
image = el;
imageUrl = url;
updateButtonPosition();
}
return;
Expand Down Expand Up @@ -306,7 +324,7 @@ export default function init({downloadImage}) {
button.onclick = () => {
buttonAni = fadeOut(button);
downloadImage({
url: imageUtil.getSrcFromElement(image).next().value,
url: imageUrl,
referrerPolicy: image.referrerPolicy || undefined,
alt: image.alt
});
Expand Down
9 changes: 9 additions & 0 deletions src/lib/url-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ function createTransform(search, repl) {
return fn(...match);
};
}
if (repl === "-") {
const re = new RegExp(search, "i");
return url => {
if (re.test(url)) {
return "";
}
return url;
};
}
const re = new RegExp(search, "ig");
return url => url.replace(re, repl);
}
Expand Down
2 changes: 1 addition & 1 deletion src/picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ function updateFilenamePreviewFactory(tabs) {
url: image.url,
base: image.data && image.data.filename,
alt: image.alt,
ext: image.data && image.data.ext
ext: image.data?.ext ? `.${image.data.ext}` : null
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with the rest of the codebase and with background.js line 638, consider using undefined instead of null as the fallback value when ext is not available. This maintains consistency with how other optional properties (like base and alt) are handled.

Suggested change
ext: image.data?.ext ? `.${image.data.ext}` : null
ext: image.data?.ext ? `.${image.data.ext}` : undefined

Copilot uses AI. Check for mistakes.
});
expandEnv(env);
const filename = compileStringTemplate(pattern)(env);
Expand Down