fix(gemini-ops): 修复下载完整尺寸图片时的交互和重命名问题
This commit is contained in:
@@ -711,8 +711,8 @@ export function createOps(page) {
|
|||||||
* @returns {Promise<{ok: boolean, filePath?: string, suggestedFilename?: string, src?: string, index?: number, total?: number, error?: string}>}
|
* @returns {Promise<{ok: boolean, filePath?: string, suggestedFilename?: string, src?: string, index?: number, total?: number, error?: string}>}
|
||||||
*/
|
*/
|
||||||
async downloadFullSizeImage({ index, timeout = 30_000 } = {}) {
|
async downloadFullSizeImage({ index, timeout = 30_000 } = {}) {
|
||||||
// 1. 定位目标图片,获取其坐标用于 hover
|
// 1a. 先将目标图片滚动到屏幕正中间,避免视口外的元素无法交互
|
||||||
const imgInfo = await op.query((targetIndex) => {
|
const scrollResult = await op.query((targetIndex) => {
|
||||||
const imgs = [...document.querySelectorAll('img.image.loaded')];
|
const imgs = [...document.querySelectorAll('img.image.loaded')];
|
||||||
if (!imgs.length) return { ok: false, error: 'no_loaded_images', total: 0 };
|
if (!imgs.length) return { ok: false, error: 'no_loaded_images', total: 0 };
|
||||||
|
|
||||||
@@ -721,6 +721,20 @@ export function createOps(page) {
|
|||||||
return { ok: false, error: 'index_out_of_range', total: imgs.length, requestedIndex: i };
|
return { ok: false, error: 'index_out_of_range', total: imgs.length, requestedIndex: i };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const img = imgs[i];
|
||||||
|
// 【关键修复】:强行把图片滚到屏幕正中间,避免视口外的元素无法交互
|
||||||
|
img.scrollIntoView({ behavior: 'instant', block: 'center' });
|
||||||
|
return { ok: true, index: i, total: imgs.length };
|
||||||
|
}, index);
|
||||||
|
|
||||||
|
if (!scrollResult.ok) return scrollResult;
|
||||||
|
|
||||||
|
// 1b. 等待滚动和重排完成后,再获取准确的坐标
|
||||||
|
await sleep(250);
|
||||||
|
|
||||||
|
const imgInfo = await op.query((targetIndex) => {
|
||||||
|
const imgs = [...document.querySelectorAll('img.image.loaded')];
|
||||||
|
const i = targetIndex == null ? imgs.length - 1 : targetIndex;
|
||||||
const img = imgs[i];
|
const img = imgs[i];
|
||||||
const rect = img.getBoundingClientRect();
|
const rect = img.getBoundingClientRect();
|
||||||
return {
|
return {
|
||||||
@@ -731,7 +745,9 @@ export function createOps(page) {
|
|||||||
index: i,
|
index: i,
|
||||||
total: imgs.length,
|
total: imgs.length,
|
||||||
};
|
};
|
||||||
}, index);
|
}, scrollResult.index);
|
||||||
|
|
||||||
|
console.log('[downloadFullSizeImage] imgInfo', imgInfo);
|
||||||
|
|
||||||
if (!imgInfo.ok) return imgInfo;
|
if (!imgInfo.ok) return imgInfo;
|
||||||
|
|
||||||
@@ -768,7 +784,7 @@ export function createOps(page) {
|
|||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
client.off('Browser.downloadWillBegin', onBegin);
|
client.off('Browser.downloadWillBegin', onBegin);
|
||||||
client.off('Browser.downloadProgress', onProgress);
|
client.off('Browser.downloadProgress', onProgress);
|
||||||
resolve({ suggestedFilename });
|
resolve({ suggestedFilename, guid });
|
||||||
} else if (evt.state === 'canceled') {
|
} else if (evt.state === 'canceled') {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
client.off('Browser.downloadWillBegin', onBegin);
|
client.off('Browser.downloadWillBegin', onBegin);
|
||||||
@@ -786,7 +802,7 @@ export function createOps(page) {
|
|||||||
await sleep(500);
|
await sleep(500);
|
||||||
|
|
||||||
// 5. 点击"下载完整尺寸"按钮(带重试:hover 可能需要更长时间触发工具栏)
|
// 5. 点击"下载完整尺寸"按钮(带重试:hover 可能需要更长时间触发工具栏)
|
||||||
const btnSelector = 'button[data-test-id="download-enhanced-image-button"]';
|
const btnSelector = 'button[data-test-id="download-generated-image-button"]';
|
||||||
const clickResult = await op.click(btnSelector);
|
const clickResult = await op.click(btnSelector);
|
||||||
|
|
||||||
if (!clickResult.ok) {
|
if (!clickResult.ok) {
|
||||||
@@ -794,15 +810,33 @@ export function createOps(page) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 6. 等待下载完成
|
// 6. 等待下载完成
|
||||||
|
// allowAndName 模式下,Chrome 会把文件以 GUID 命名保存到 downloadDir,
|
||||||
|
// 真正的文件名在 downloadWillBegin 事件的 suggestedFilename 里。
|
||||||
|
// 下载完成后需要把 GUID 文件重命名为目标文件名。
|
||||||
try {
|
try {
|
||||||
const { suggestedFilename } = await downloadPromise;
|
const { suggestedFilename, guid } = await downloadPromise;
|
||||||
const { join } = await import('node:path');
|
const { join } = await import('node:path');
|
||||||
const filePath = join(downloadDir, suggestedFilename || `gemini_fullsize_${Date.now()}.png`);
|
const { renameSync, existsSync } = await import('node:fs');
|
||||||
|
|
||||||
|
const targetName = suggestedFilename || `gemini_fullsize_${Date.now()}.png`;
|
||||||
|
const guidPath = join(downloadDir, guid);
|
||||||
|
const filePath = join(downloadDir, targetName);
|
||||||
|
|
||||||
|
// 将 GUID 文件重命名为正确的文件名
|
||||||
|
if (existsSync(guidPath)) {
|
||||||
|
renameSync(guidPath, filePath);
|
||||||
|
console.log(`[ops] 已重命名: ${guid} → ${targetName}`);
|
||||||
|
} else {
|
||||||
|
// 有些 Chrome 版本可能已经用 suggestedFilename 保存了,检查一下
|
||||||
|
if (!existsSync(filePath)) {
|
||||||
|
console.warn(`[ops] 下载文件未找到: 既不存在 ${guidPath} 也不存在 ${filePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
filePath,
|
filePath,
|
||||||
suggestedFilename,
|
suggestedFilename: targetName,
|
||||||
src: imgInfo.src,
|
src: imgInfo.src,
|
||||||
index: imgInfo.index,
|
index: imgInfo.index,
|
||||||
total: imgInfo.total,
|
total: imgInfo.total,
|
||||||
|
|||||||
Reference in New Issue
Block a user