You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, defaultProvider = "yandex") {
// Create the main container for the tool
const container = document.createElement("div");
container.style.cssText = "max-width: 650px; margin: 0 auto; font-family: system-ui, -apple-system, sans-serif; background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 24px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); color: #111827; box-sizing: border-box;";
// Header section
const header = document.createElement("div");
header.style.textAlign = "center";
header.style.marginBottom = "24px";
header.innerHTML = `
<h2 style="margin: 0 0 8px 0; font-size: 24px; color: #1f2937;">Movie Name Finder</h2>
<p style="margin: 0; font-size: 14px; color: #6b7280;">Identify the movie by performing a smart visual search on your screenshot or poster. Some engines work better for specific movie genres!</p>
`;
container.appendChild(header);
// Image Preview section
const previewContainer = document.createElement("div");
previewContainer.style.cssText = "text-align: center; margin-bottom: 24px; background: #f3f4f6; border-radius: 8px; padding: 12px; display: flex; justify-content: center;";
const preview = document.createElement("img");
preview.src = originalImg.src;
preview.style.cssText = "max-width: 100%; max-height: 280px; border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); object-fit: contain;";
previewContainer.appendChild(preview);
container.appendChild(previewContainer);
// Dynamic Feedback Area
const feedbackArea = document.createElement("div");
feedbackArea.style.cssText = "margin-bottom: 20px; font-size: 14px; text-align: center; min-height: 20px; transition: all 0.3s;";
container.appendChild(feedbackArea);
// Loading indicator
const loadingText = document.createElement("p");
loadingText.innerText = "Analyzing image readiness...";
loadingText.style.textAlign = "center";
loadingText.style.color = "#6b7280";
container.appendChild(loadingText);
try {
// Convert the image securely into a processable Blob format
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d", { willReadFrequently: true });
canvas.width = originalImg.naturalWidth || originalImg.width || 300;
canvas.height = originalImg.naturalHeight || originalImg.height || 300;
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Security check for cross-origin taint
ctx.getImageData(0, 0, 1, 1);
canvas.toBlob((blob) => {
container.removeChild(loadingText); // Ready to show buttons
if (!blob) {
feedbackArea.innerHTML = "<span style='color: #ef4444;'>Error: Could not render image data.</span>";
return;
}
const buttonsContainer = document.createElement("div");
buttonsContainer.style.cssText = "display: flex; flex-wrap: wrap; gap: 12px; justify-content: center;";
// Standard Button Creation Utility
const createButton = (text, bgColor, textColor, onClick) => {
const btn = document.createElement("button");
btn.innerText = text;
btn.style.cssText = `flex: 1 1 45%; padding: 14px 16px; border: none; border-radius: 8px; background-color: ${bgColor}; color: ${textColor}; font-weight: 600; cursor: pointer; transition: all 0.2s ease-in-out; font-size: 14px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); display: flex; align-items: center; justify-content: center;`;
btn.onmouseover = () => {
btn.style.transform = "translateY(-2px)";
btn.style.boxShadow = "0 4px 8px rgba(0,0,0,0.15)";
};
btn.onmouseout = () => {
btn.style.transform = "translateY(0)";
btn.style.boxShadow = "0 2px 4px rgba(0,0,0,0.1)";
};
btn.onclick = onClick;
return btn;
};
// Form Submit Utility simulating a reverse image upload
const executeFormSearch = (action, fileParam, extraParams, engineName) => {
feedbackArea.innerHTML = "Preparing search request...";
feedbackArea.style.color = "#3b82f6";
try {
const form = document.createElement("form");
form.method = "POST";
form.action = action;
form.enctype = "multipart/form-data";
form.target = "_blank"; // Opens search successfully in a new tab
// Append hidden search parameters
for (const key in extraParams) {
const hiddenInput = document.createElement("input");
hiddenInput.type = "hidden";
hiddenInput.name = key;
hiddenInput.value = extraParams[key];
form.appendChild(hiddenInput);
}
// Attach image file securely without user manual intervention using DataTransfer API
const dt = new DataTransfer();
dt.items.add(new File([blob], "movie_screencap.jpg", { type: "image/jpeg" }));
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.name = fileParam;
fileInput.files = dt.files;
form.appendChild(fileInput);
document.body.appendChild(form); // Required for functionality internally in Firefox
form.submit();
document.body.removeChild(form);
feedbackArea.innerHTML = `Opened <strong>${engineName}</strong> in a new tab to find the movie!`;
feedbackArea.style.color = "#10b981";
} catch (e) {
// Fallback for browsers that block programmatic file list mapping or form action auto-submissions
const fallbackUrl = () => {
if(engineName.includes("Yandex")) return "https://yandex.com/images/";
if(engineName.includes("Google")) return "https://images.google.com/";
if(engineName.includes("Bing")) return "https://www.bing.com/visualsearch";
return action;
};
const objUrl = URL.createObjectURL(blob);
feedbackArea.innerHTML = `
<div style="color: #b45309; padding: 12px; background: #fef3c7; border-radius: 8px; border: 1px solid #fde68a; font-size: 13px;">
<strong>Your browser blocks automatic image uploads to outside sites.</strong><br>
1. <a href="${objUrl}" download="movie_screencap.jpg" style="color: #d97706; text-decoration: underline;">Click to download your image</a>.<br>
2. Manually upload it to <a href="${fallbackUrl()}" target="_blank" style="color: #d97706; text-decoration: underline;">${engineName}</a>.
</div>
`;
}
};
// 1. Yandex Button (Highly accurate for worldwide movie screenshots)
const btnYandex = createButton("Search Worldwide (Yandex)", "#fc3f1d", "#fff", () => {
executeFormSearch("https://yandex.com/images/search", "upfile", { rpt: "imageview" }, "Yandex Visual Search");
});
// 2. Google Lens Button (Excellent for posters, actor faces, and modern frames)
const btnGoogle = createButton("Search via Google Lens", "#4285F4", "#fff", () => {
executeFormSearch("https://lens.google.com/upload", "encoded_image", {}, "Google Lens");
});
// 3. Bing Button (Good visual feature fallback)
const btnBing = createButton("Search via Bing Visual", "#0078d4", "#fff", () => {
executeFormSearch("https://www.bing.com/images/search", "imageBin", { view: "detailv2", iss: "sbi" }, "Bing Visual Search");
});
// 4. Trace.Moe Anime API (Perfect matching for Japanese animations and anime movies)
const btnAnime = createButton("Find Anime Movie (Trace.moe)", "#FF6768", "#fff", async () => {
const originalText = btnAnime.innerText;
btnAnime.innerText = "Scanning Anime Database...";
btnAnime.disabled = true;
btnAnime.style.opacity = "0.7";
feedbackArea.innerHTML = "Querying extensive anime registry API...";
feedbackArea.style.color = "#f59e0b";
// Setup result presentation area unique to Trace.moe
let animeResultDiv = document.getElementById("movie-anime-result");
if(!animeResultDiv) {
animeResultDiv = document.createElement("div");
animeResultDiv.id = "movie-anime-result";
animeResultDiv.style.cssText = "margin-top: 20px; padding: 16px; background: #fdf2f8; border: 1px solid #fbcfe8; border-radius: 8px; text-align: left; display: none; width: 100%; box-sizing: border-box;";
container.appendChild(animeResultDiv);
}
try {
const fd = new FormData();
fd.append("image", blob, "screenshot.jpg");
const res = await fetch("https://api.trace.moe/search", { method: "POST", body: fd });
if(!res.ok) throw new Error("Anime API responded with " + res.status);
const data = await res.json();
// Function to convert seconds to MM:SS format safely
const formatTime = (seconds) => {
if (isNaN(seconds)) return "0:00";
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${m}:${s.toString().padStart(2, '0')}`;
};
if (data.result && data.result.length > 0) {
const bestMatch = data.result[0];
const similarity = (bestMatch.similarity * 100).toFixed(1);
animeResultDiv.style.display = "block";
if (similarity > 75) {
feedbackArea.innerHTML = "<span style='color: #10b981;'><strong>Success!</strong> Found a closely matching anime scene.</span>";
animeResultDiv.innerHTML = `
<div style="font-weight: 700; font-size: 16px; margin-bottom: 6px; color: #9d174d;">${bestMatch.filename}</div>
<div style="font-size: 14px; color: #831843; margin-bottom: 12px; display: grid; grid-template-columns: 1fr 1fr; gap: 8px;">
<span><strong>Episode:</strong> ${bestMatch.episode || 'Movie/N/A'}</span>
<span><strong>Confidence:</strong> ${similarity}%</span>
<span><strong>Timecode:</strong> ${formatTime(bestMatch.from)} - ${formatTime(bestMatch.to)}</span>
</div>
`;
// Include scene preview video if provided
if (bestMatch.video) {
const vid = document.createElement("video");
vid.src = bestMatch.video;
vid.controls = true;
vid.autoplay = true;
vid.muted = true;
vid.loop = true;
vid.style.cssText = "width: 100%; border-radius: 6px; box-shadow: 0 2px 6px rgba(0,0,0,0.15); background: #000;";
animeResultDiv.appendChild(vid);
}
} else {
feedbackArea.innerHTML = "<span style='color: #f59e0b;'>No highly confident anime match found. It may be live-action!</span>";
animeResultDiv.innerHTML = `<p style="margin:0; font-size: 14px; color: #9d174d;">The closest visual guess was <strong>${bestMatch.filename}</strong> (${similarity}% match).</p>`;
}
} else {
feedbackArea.innerHTML = "<span style='color: #ef4444;'>No anime matches found across the database.</span>";
animeResultDiv.style.display = "none";
}
} catch (err) {
feedbackArea.innerHTML = `<span style='color: #ef4444;'>Failed to reach anime database: ${err.message}. Try another search method above.</span>`;
} finally {
btnAnime.innerText = originalText;
btnAnime.disabled = false;
btnAnime.style.opacity = "1";
}
});
// Reorder options dynamically giving priority based on 'defaultProvider' string property
if (defaultProvider.toLowerCase() === "yandex") {
buttonsContainer.appendChild(btnYandex);
buttonsContainer.appendChild(btnGoogle);
} else {
buttonsContainer.appendChild(btnGoogle);
buttonsContainer.appendChild(btnYandex);
}
buttonsContainer.appendChild(btnAnime);
buttonsContainer.appendChild(btnBing);
container.appendChild(buttonsContainer);
}, "image/jpeg", 0.90);
} catch (error) {
if (error.name === "SecurityError" || error.message.includes("Tainted")) {
loadingText.style.display = "none";
feedbackArea.innerHTML = "<strong>CORS Security Restriction:</strong> The browser prevented processing this image. Try downloading the image and running the tool on the local file instead.";
feedbackArea.style.color = "#ef4444";
} else {
loadingText.style.display = "none";
feedbackArea.innerHTML = `<strong>Error processing image:</strong> ${error.message}`;
feedbackArea.style.color = "#ef4444";
}
}
return container;
}
Apply Changes