Skip to content

Instantly share code, notes, and snippets.

@dks50217
Last active July 11, 2025 07:22
Show Gist options
  • Save dks50217/5abfcf89497a3ef479f603a40e5325d4 to your computer and use it in GitHub Desktop.
Save dks50217/5abfcf89497a3ef479f603a40e5325d4 to your computer and use it in GitHub Desktop.
Google Chat Image Batch Downloader
// ==UserScript==
// @name Google Chat Image Downloader (Selected Only)
// @namespace https://chat.google.com/
// @version 1.7
// @description 下載 Google Chat 內有反白選取的圖片,附進度與轉圈動畫按鈕 UI!
// @author Michael Chang
// @match https://chat.google.com/*
// @grant GM_download
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
/* 只有「single_full_screen」這個 iframe 需要跑,其他全部 return */
if (window.name !== 'single_full_screen') return;
function downloadImage(url, index) {
let baseUrl = url.split("&sz=")[0];
if (!baseUrl.includes("&sz=")) {
baseUrl += "&sz=w1920-h919";
}
GM_download({
url: baseUrl,
name: `GoogleChat_image_${index + 1}.jpg`,
saveAs: false
});
}
function isElementInSelection(el) {
const selection = window.getSelection();
if (!selection || selection.rangeCount === 0) return false;
for (let i = 0; i < selection.rangeCount; i++) {
if (selection.getRangeAt(i).intersectsNode(el)) {
return true;
}
}
return false;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function findAndDownloadImages(button) {
button.disabled = true;
const originalText = button.textContent;
button.textContent = "";
const spinner = document.createElement("span");
spinner.className = "gchat-spinner";
spinner.style.display = "inline-block";
spinner.style.width = "16px";
spinner.style.height = "16px";
spinner.style.border = "2px solid #fff";
spinner.style.borderTop = "2px solid transparent";
spinner.style.borderRadius = "50%";
spinner.style.animation = "spin 1s linear infinite";
spinner.style.marginRight = "6px";
const text = document.createElement("span");
text.textContent = "下載中...";
button.appendChild(spinner);
button.appendChild(text);
let images = document.querySelectorAll("img[src^='https://chat.google.com/u/0/api/get_attachment_url?']");
let imageUrls = [];
images.forEach(img => {
if (isElementInSelection(img)) {
imageUrls.push(img.src);
}
});
if (imageUrls.length === 0) {
alert("沒有選取任何圖片!");
resetButton(button, originalText);
return;
}
const total = imageUrls.length;
for (let i = 0; i < total; i++) {
text.textContent = `下載中...(${i + 1} / ${total})`;
downloadImage(imageUrls[i], i);
await sleep(2000);
}
alert(`已下載 ${total} 張圖片!`);
resetButton(button, originalText);
}
function resetButton(button, text) {
button.disabled = false;
button.textContent = text;
}
function addDownloadButton() {
const button = document.createElement("button");
button.textContent = "下載選取圖片";
button.style.position = "fixed";
button.style.top = "20px";
button.style.right = "20px";
button.style.zIndex = "1000";
button.style.padding = "10px 16px";
button.style.backgroundColor = "#1a73e8";
button.style.color = "#fff";
button.style.border = "none";
button.style.borderRadius = "8px";
button.style.cursor = "move";
button.style.boxShadow = "0 2px 6px rgba(0,0,0,0.3)";
button.style.fontSize = "14px";
button.style.display = "flex";
button.style.alignItems = "center";
let isDragging = false;
let dragStartX = 0;
let dragStartY = 0;
let moved = false;
button.addEventListener("mousedown", (e) => {
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
moved = false;
offsetX = e.clientX - button.getBoundingClientRect().left;
offsetY = e.clientY - button.getBoundingClientRect().top;
document.body.style.userSelect = "none";
});
let offsetX = 0, offsetY = 0;
document.addEventListener("mousemove", (e) => {
if (isDragging) {
const dx = e.clientX - dragStartX;
const dy = e.clientY - dragStartY;
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) {
moved = true;
button.style.top = `${e.clientY - offsetY}px`;
button.style.left = `${e.clientX - offsetX}px`;
button.style.right = "auto";
}
}
});
document.addEventListener("mouseup", (e) => {
if (isDragging && !moved) {
findAndDownloadImages(button); // 只有沒拖動才觸發點擊事件
}
isDragging = false;
document.body.style.userSelect = "";
});
document.body.appendChild(button);
const style = document.createElement("style");
style.textContent = `
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
`;
document.head.appendChild(style);
}
// 快捷鍵 Ctrl + Shift + Z
document.addEventListener("keydown", function (event) {
if (event.ctrlKey && event.shiftKey && event.key === "Z") {
const button = document.querySelector("button:contains('下載選取圖片')");
if (button) findAndDownloadImages(button);
}
});
window.addEventListener("load", () => {
addDownloadButton();
console.log("💾 Google Chat Image Downloader 已啟動!");
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment