name

Imager

icon

photo_camera_back

instructions


If the image you pasted inside Amplenote is only a reference to the original location, the Imager plugin will appear in the note options. The plugin fetches attempts to fetch the image and upload it to the Amplenote servers instead.

This is particularly useful if you're pasting images from sources that have unreliable access, such as links that can expire.

Important note for the "Save all note images to Amplenote" Note Option
When using this option to replace all images in a note, the plugin has to rewrite the entire contents of the note, which might result in some inconsistencies or even data loss. Those cases should be rare and you can undo that at any time using the Note Version History. Should you find such a case, please send us an email about it and we will fix it as quickly as we can.


Change log:

August 16th, 2023:

Added note option that saves all images in a note found to be external


/***
* Source Code: undefined
* Author:
* Build: production
* Character Count: 4963 (0.0050 M)
* Target Folder: plugin
***/
(() => {
// plugin/plugin.js
var plugin = {
// List of CORS proxy services to try
corsProxies: [
"https://amplenote-plugins-cors-anywhere.onrender.com/",
"https://cors-anywhere.herokuapp.com/",
"https://api.allorigins.win/raw?url=",
"https://corsproxy.io/?"
],
imageOption: {
"Save image to Amplenote": {
run: async function(app, image) {
try {
let src = image.src, dataURL = await plugin.retry(() => plugin._dataURLFromImageURL(src)), sourceNoteHandle = await app.findNote({ uuid: app.context.noteUUID }), fileURL = await app.attachNoteMedia(sourceNoteHandle, dataURL);
await app.context.updateImage({ src: fileURL }), await app.alert("Success!");
} catch (err) {
await app.alert(err.message || err);
}
},
check: async function(app, image) {
return !image.src.startsWith("https://images.amplenote.com");
}
}
},
appOption: {
"Save all images in a tag to Amplenote": {
run: async function(app) {
let tag = await app.prompt(
"Choose the tag. Please note that this plugin is experimental and we don't recommend using it tag-wide without a backup.",
{ inputs: [{
type: "tags"
}] }
);
if (!tag) return;
let notes = await app.filterNotes({ tag });
for (let note of notes)
console.log("Processing note", note.name), await plugin.noteOption["Save all note images to Amplenote"].run(app, note.uuid);
}
}
},
noteOption: {
"Save all note images to Amplenote": {
check: async function(app, noteUUID) {
var _a;
let noteHandle = { uuid: noteUUID }, images = await app.getNoteImages(noteHandle);
return (_a = images == null ? void 0 : images.some((image) => !image.src.startsWith("images.amplenote.com"))) != null ? _a : !1;
},
run: async function(app, noteUUID) {
try {
let noteHandle = { uuid: noteUUID }, images = await app.getNoteImages(noteHandle);
for (let i = 0; i < images.length; i++) {
let image = images[i];
if (console.log(`Processing ${i + 1}/${images.length}: ${image.src}`), image.src.startsWith("images.amplenote.com")) {
console.log(`Skipping already hosted image ${i + 1}/${images.length}`);
continue;
}
let dataURL = await plugin.retry(() => plugin._dataURLFromImageURL(image.src));
if (!dataURL) {
console.warn(`Failed to download image ${i + 1}/${images.length}: ${image.src}`);
continue;
}
let fileURL = await app.attachNoteMedia(noteHandle, dataURL);
await app.updateNoteImage(noteHandle, image, { src: fileURL }), console.log(`Successfully processed ${i + 1}/${images.length}`);
}
} catch (err) {
await app.alert(err.message || err);
}
}
}
},
async _dataURLFromImageURL(src) {
try {
let response = await fetch(src);
if (response.ok) {
let blob = await response.blob();
return await plugin._blobToDataURL(blob);
}
} catch {
console.log("Direct fetch failed, trying proxies...");
}
for (let proxy of plugin.corsProxies)
try {
let proxyUrl = `${proxy}${encodeURIComponent(src)}`, response = await fetch(proxyUrl, {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
});
if (response.ok) {
let blob = await response.blob();
return await plugin._blobToDataURL(blob);
} else
console.log(`Proxy ${proxy} failed with status:`, response.status);
} catch (e) {
console.log(`Proxy ${proxy} failed with error:`, e.message);
continue;
}
return console.warn(`Failed to fetch image from all available sources: ${src}`), null;
},
async _blobToDataURL(blob) {
return await new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = (event) => resolve(event.target.result), reader.onerror = () => reject(new Error("Failed to read blob as data URL")), reader.readAsDataURL(blob);
});
},
async retry(fn, retries = 2, delayMs = 100) {
for (let i = 0; i < retries; i++)
try {
return await fn();
} catch (e) {
if (console.log(`Attempt ${i + 1} failed:`, e.message), i === retries - 1) throw e;
await plugin.delay(delayMs * (i + 1));
}
},
delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}, plugin_default = plugin;
return plugin;
})()
//# sourceMappingURL=plugin.js.map