一开始用Gemini的时候发现回车键只能发送,让我习惯了ctrl+回车发送的微信打工人深恶痛绝。
遂用Gemini写了一个油猴的脚本用来更好的使用Gemini(师夷长技以制夷)。 
搞了20个版本的迭代和修复,现在比较稳定,分享给各位大佬,也请多提出宝贵意见可以增加功能。

【核心功能】
1. 📜 智能滚动系统
- 自动滚动 (Auto-Scroll):检测到 AI 正在生成内容时,屏幕瞬间锁定底部,解放双手,不用再疯狂滑滚轮了。
- 回到最下:一键直达对话底部(采用全覆盖算法,兼容所有 Gemini 页面结构)。
2. ⌨️ 输入体验增强
- 回车 (Enter):强制换行(拒绝误触发送)。
- Ctrl + Enter:发送消息。
- Tab 重命名:标签页标题自动变更为当前对话主题,多开不迷路。
3. 🎨 颜值与交互
- 多主题切换:下拉选择 ⬜极简、🤖赛博朋克、🧸糖果卡通、🖌️水墨中国 四大主题。
- 水滴悬浮球:面板最小化后变成一颗炫酷的“水滴球”,支持全屏拖动,位置自动记忆。
- 磨砂玻璃:UI 采用高级毛玻璃特效,视觉舒适。
4. 🚀 效率工具
- 纯净复制:一键提取 AI 回复,自动去除
**、##等 Markdown 符号,文案直接用。 - 宽屏模式:一键隐藏侧边栏,将对话区拉伸至 90%,看代码极爽。
- 智能大纲:自动提取长回复的标题(H1-H3),生成可折叠的目录导航。
- 护眼模式:内置豆沙绿、护眼黄、夜间灰三种滤镜。
【安装方式】
- 安装 Tampermonkey 插件。
- 新建脚本,粘贴代码保存即可。
// ==UserScript==
// @name Gemni GG-BOOM V.20.0 (滚动终极版)
// @namespace http://tampermonkey.net/
// @version 20.0
// @description V20里程碑:全覆盖滚动算法,确保自动滚动生效。含多主题、下拉切换、大纲、纯净复制。
// @author cshaizhihao
// @match https://gemini.google.com/*
// @grant GM_addStyle
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
console.log("🌊 GG-BOOM V20.0: 滚动引擎已升级");
// --- 1. CSS 样式 (保持 V19 美学) ---
const css = `
:root { --gg-bg:#111; --gg-border:#333; --gg-text:#eee; --gg-accent:#fff; --gg-btn-bg:#222; --gg-btn-hover:#333; --gg-radius:4px; --gg-shadow:0 0 0 1px #333; --gg-font:sans-serif; --gg-title-grad:#fff; --gg-blur:0px; --gg-pattern:none; --gg-glow:none; }
[data-gg-theme="minimal"] { --gg-bg:#1a1a1a; --gg-border:#333; --gg-text:#ccc; --gg-accent:#fff; --gg-btn-bg:#262626; --gg-btn-hover:#333; --gg-radius:6px; --gg-shadow:0 10px 30px rgba(0,0,0,0.5); --gg-font:-apple-system,system-ui,sans-serif; --gg-title-grad:#eee; --gg-blur:0px; }
[data-gg-theme="cyber"] { --gg-bg:rgba(5,10,20,0.92); --gg-border:#0ff; --gg-text:#0ff; --gg-accent:#f0f; --gg-btn-bg:rgba(0,255,255,0.05); --gg-btn-hover:rgba(0,255,255,0.2); --gg-radius:2px; --gg-shadow:0 0 15px rgba(0,255,255,0.3),inset 0 0 20px rgba(0,0,0,0.8); --gg-font:"Courier New",monospace; --gg-title-grad:linear-gradient(90deg,#f0f,#0ff); --gg-blur:4px; --gg-glow:0 0 5px #0ff; --gg-pattern:linear-gradient(0deg,transparent 24%,rgba(0,255,255,0.05) 25%,rgba(0,255,255,0.05) 26%,transparent 27%,transparent 74%,rgba(0,255,255,0.05) 75%,rgba(0,255,255,0.05) 76%,transparent 77%,transparent); background-size:50px 50px; }
[data-gg-theme="cartoon"] { --gg-bg:rgba(255,245,248,0.95); --gg-border:#FFB7B2; --gg-text:#666; --gg-accent:#FF9A9E; --gg-btn-bg:#fff; --gg-btn-hover:#FFF0F5; --gg-radius:20px; --gg-shadow:5px 5px 0px rgba(255,183,178,0.6); --gg-font:"Varela Round","幼圆",sans-serif; --gg-title-grad:linear-gradient(45deg,#FF9A9E,#FECFEF); --gg-blur:0px; --gg-pattern:radial-gradient(#FFB7B2 20%,transparent 20%) 0 0,radial-gradient(#FFB7B2 20%,transparent 20%) 8px 8px; background-size:16px 16px; }
[data-gg-theme="ink"] { --gg-bg:rgba(250,249,246,0.95); --gg-border:#666; --gg-text:#2c2c2c; --gg-accent:#B22222; --gg-btn-bg:rgba(0,0,0,0.03); --gg-btn-hover:rgba(0,0,0,0.08); --gg-radius:4px; --gg-shadow:0 10px 40px rgba(0,0,0,0.2); --gg-font:"Kaiti","STKaiti","楷体",serif; --gg-title-grad:#000; --gg-blur:8px; --gg-pattern:url('data:image/svg+xml;utf8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><g fill="%23000" fill-opacity="0.03"><circle cx="50" cy="50" r="40"/><circle cx="20" cy="20" r="10"/></g></svg>'); }
#gg-panel-v20 { position:fixed; width:300px; background-color:var(--gg-bg); background-image:var(--gg-pattern); backdrop-filter:blur(var(--gg-blur)); -webkit-backdrop-filter:blur(var(--gg-blur)); border:1px solid var(--gg-border); border-radius:var(--gg-radius); padding:15px; z-index:2147483647; box-shadow:var(--gg-shadow); font-family:var(--gg-font); color:var(--gg-text); display:flex; flex-direction:column; gap:10px; transition:all 0.3s ease; user-select:none; }
.gg-header { display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--gg-border); padding-bottom:10px; cursor:move; }
.gg-title { font-size:15px; font-weight:900; background:var(--gg-title-grad); -webkit-background-clip:text; -webkit-text-fill-color:transparent; text-shadow:var(--gg-glow); pointer-events:none; }
.gg-min-btn { cursor:pointer; padding:2px 8px; font-size:16px; color:var(--gg-text); opacity:0.6; } .gg-min-btn:hover { opacity:1; transform:scale(1.1); }
.gg-select { width:100%; padding:6px; border-radius:var(--gg-radius); background:var(--gg-btn-bg); border:1px solid var(--gg-border); color:var(--gg-text); font-family:var(--gg-font); font-size:12px; cursor:pointer; outline:none; margin-top:5px; } .gg-select option { background:#222; color:#fff; } [data-gg-theme="cartoon"] .gg-select option, [data-gg-theme="ink"] .gg-select option { background:#fff; color:#333; }
.gg-label { font-size:11px; color:var(--gg-text); opacity:0.7; font-weight:bold; pointer-events:none; margin-top:8px; }
.gg-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-top:5px; }
.gg-btn { background:var(--gg-btn-bg); border:1px solid var(--gg-border); color:var(--gg-text); padding:8px; border-radius:var(--gg-radius); cursor:pointer; font-size:12px; text-align:center; display:flex; align-items:center; justify-content:center; transition:0.2s; } .gg-btn:hover { background:var(--gg-btn-hover); transform:translateY(-1px); border-color:var(--gg-accent); } .gg-btn.active { border-color:var(--gg-accent); color:var(--gg-accent); font-weight:bold; box-shadow:inset 0 0 5px var(--gg-accent); }
#gg-outline-box { background:rgba(0,0,0,0.03); border:1px solid var(--gg-border); border-radius:var(--gg-radius); padding:5px; max-height:120px; overflow-y:auto; list-style:none; margin-top:5px; font-size:12px; color:var(--gg-text); display:block; }
.gg-outline-item { padding:4px; border-radius:4px; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; opacity:0.8; } .gg-outline-item:hover { background:var(--gg-btn-hover); opacity:1; color:var(--gg-accent); }
.gg-chip-area { display:flex; flex-wrap:wrap; gap:5px; margin-top:5px; }
.gg-chip { background:var(--gg-btn-bg); border:1px solid var(--gg-border); padding:4px 10px; border-radius:20px; font-size:13px; cursor:pointer; color:var(--gg-text); opacity:0.9; } .gg-chip:hover { border-color:var(--gg-accent); color:var(--gg-accent); transform:scale(1.05); }
#gg-float-ball { position:fixed; width:50px; height:50px; border-radius:50%; z-index:2147483647; cursor:pointer; display:none; align-items:center; justify-content:center; font-weight:900; font-size:12px; color:#fff; background:var(--gg-accent); box-shadow:0 4px 15px var(--gg-accent); border:2px solid rgba(255,255,255,0.3); opacity:0.8; transition:opacity 0.3s, transform 0.2s; } #gg-float-ball:hover { opacity:1; transform:scale(1.1); } #gg-float-ball.dragging { opacity:1; cursor:move; }
.gg-footer { font-size:10px; color:var(--gg-text); opacity:0.5; text-align:center; margin-top:10px; border-top:1px solid var(--gg-border); padding-top:8px; }
body.gg-wide-mode sidenav { display:none !important; } body.gg-wide-mode .input-area-container, body.gg-wide-mode .conversation-container, body.gg-wide-mode .bottom-container { max-width:90% !important; margin:0 auto !important; }
#gg-eye-overlay { position:fixed; top:0; left:0; width:100vw; height:100vh; pointer-events:none; z-index:2147483646; display:none; transition:background 0.3s; }
`;
const style = document.createElement('style'); style.innerText = css; document.head.appendChild(style);
// --- 状态 ---
let isHidden = false;
let eyeMode = 0;
let autoScroll = false;
let outlineCollapsed = false;
let currentTheme = localStorage.getItem('gg_theme_v20') || 'minimal';
const themes = { 'minimal': '⬜ 极简主义 (Minimal)', 'cyber': '🤖 赛博朋克 (Cyberpunk)', 'cartoon': '🧸 糖果卡通 (Cartoon)', 'ink': '🖌️ 水墨中国 (Ink)' };
// --- 滚动核心 (全覆盖算法) ---
function forceScrollBottom(smooth) {
// 1. 寻找所有可能的滚动容器
const candidates = [
document.querySelector('infinite-scroller'),
document.querySelector('main'),
document.querySelector('.conversation-container')?.parentElement,
document.documentElement,
document.body
];
// 过滤出真正能滚动的元素
const scrollers = candidates.filter(el => el && el.scrollHeight > el.clientHeight);
if (scrollers.length > 0) {
scrollers.forEach(el => {
// 如果是平滑滚动(手动点击),用 smooth
// 如果是自动跟手(Auto),用 instant (防止抖动)
el.scrollTo({ top: el.scrollHeight, behavior: smooth ? 'smooth' : 'instant' });
});
}
}
// --- 拖动 ---
function makeDraggable(el, handle = el) {
let isDragging=false, startX, startY, initLeft, initTop, hasMoved=false;
const saved = JSON.parse(localStorage.getItem('gg_pos_'+el.id));
if(saved) { el.style.left=saved.left; el.style.top=saved.top; el.style.bottom='auto'; el.style.right='auto'; }
else { el.style.bottom='30px'; el.style.right='30px'; }
handle.addEventListener('mousedown', e=>{
if(e.button!==0)return; isDragging=true; hasMoved=false;
if(el.id==='gg-float-ball')el.classList.add('dragging');
startX=e.clientX; startY=e.clientY;
initLeft=el.getBoundingClientRect().left; initTop=el.getBoundingClientRect().top;
el.style.transition='none';
});
window.addEventListener('mousemove', e=>{
if(!isDragging)return; e.preventDefault();
const dx=e.clientX-startX; const dy=e.clientY-startY;
if(Math.abs(dx)>3||Math.abs(dy)>3)hasMoved=true;
el.style.left=(initLeft+dx)+'px'; el.style.top=(initTop+dy)+'px';
el.style.bottom='auto'; el.style.right='auto';
});
window.addEventListener('mouseup', ()=>{
if(!isDragging)return; isDragging=false;
if(el.id==='gg-float-ball')el.classList.remove('dragging');
el.style.transition='';
localStorage.setItem('gg_pos_'+el.id, JSON.stringify({left:el.style.left, top:el.style.top}));
if(el.id==='gg-float-ball' && !hasMoved) togglePanel();
});
}
// --- 交互 ---
function togglePanel() {
const p = document.getElementById('gg-panel-v20');
const b = document.getElementById('gg-float-ball');
isHidden = !isHidden;
if(isHidden) {
p.style.opacity='0'; p.style.transform='scale(0.9)'; setTimeout(()=>p.style.display='none',200);
b.style.display='flex'; setTimeout(()=>b.style.transform='scale(1)',10);
} else {
b.style.transform='scale(0)'; setTimeout(()=>b.style.display='none',200);
p.style.display='flex'; setTimeout(()=>{p.style.opacity='1'; p.style.transform='scale(1)';},10);
}
}
// --- 功能 ---
function switchTheme(k) {
currentTheme = k; localStorage.setItem('gg_theme_v20', k);
const p = document.getElementById('gg-panel-v20');
if(p) {
p.setAttribute('data-gg-theme', k);
const b = document.getElementById('gg-float-ball');
if(k==='minimal'||k==='ink') b.style.background='#333';
else if(k==='cyber') b.style.background='#f0f';
else if(k==='cartoon') b.style.background='#FF9A9E';
}
}
function toggleWide(btn) {
document.body.classList.toggle('gg-wide-mode');
const v = document.body.classList.contains('gg-wide-mode');
btn.innerText = v ? '🖥️ 宽屏: 开' : '🖥️ 宽屏: 关';
if(v) btn.classList.add('active'); else btn.classList.remove('active');
}
function toggleEye(btn) {
eyeMode=(eyeMode+1)%4;
let ov=document.getElementById('gg-eye-overlay');
if(!ov){ov=document.createElement('div');ov.id='gg-eye-overlay';document.body.appendChild(ov);}
const m = [{t:'👁️ 护眼: 关',d:'none',c:''},{t:'👁️ 豆沙绿',d:'block',c:'#e8f5e9',x:'multiply'},{t:'👁️ 护眼黄',d:'block',c:'#fff3e0',x:'multiply'},{t:'👁️ 夜间灰',d:'block',c:'rgba(0,0,0,0.7)',x:'normal'}];
const c=m[eyeMode]; btn.innerText=c.t; ov.style.display=c.d; ov.style.backgroundColor=c.c; ov.style.mixBlendMode=c.x||'normal';
}
function cleanCopy(btn) {
const msgs = document.querySelectorAll('.model-response-text');
if(msgs.length===0) return;
let t = msgs[msgs.length-1].innerText;
t = t.replace(/\*\*(.*?)\*\*/g,'$1').replace(/##\s?/g,'').replace(/`{3,}/g,'').replace(/\[\d+\]/g,'');
navigator.clipboard.writeText(t).then(()=>{
const old=btn.innerText; btn.innerText='✅'; setTimeout(()=>btn.innerText=old,1000);
});
}
function toggleOutline(btn) {
outlineCollapsed=!outlineCollapsed;
const b=document.getElementById('gg-outline-box');
if(b) b.style.display=outlineCollapsed?'none':'block';
btn.innerText=outlineCollapsed?'▶':'▼';
}
function refreshOutline() {
const box=document.getElementById('gg-outline-box'); if(!box)return;
while(box.firstChild) box.removeChild(box.firstChild);
const hs=document.querySelectorAll('.model-response-text h1, .model-response-text h2, .model-response-text h3');
if(hs.length===0) { const d=document.createElement('div');d.innerText='暂无目录';d.style.textAlign='center';d.style.padding='5px';box.appendChild(d);return; }
hs.forEach(h=>{
if(h.innerText.length>50||h.innerText.length<2)return;
const li=document.createElement('li'); li.className='gg-outline-item'; li.innerText=h.innerText;
if(h.tagName==='H2')li.style.paddingLeft='10px'; if(h.tagName==='H3')li.style.paddingLeft='20px';
li.onclick=()=>h.scrollIntoView({behavior:"smooth",block:"center"});
box.appendChild(li);
});
}
function mkBtn(t,fn) { const b=document.createElement('div');b.className='gg-btn';b.innerText=t;b.onclick=fn;return b; }
// --- UI 构建 ---
function buildUI() {
if(document.getElementById('gg-panel-v20')) return;
const ball=document.createElement('div'); ball.id='gg-float-ball'; ball.innerText='GG爆'; document.body.appendChild(ball); makeDraggable(ball);
const p=document.createElement('div'); p.id='gg-panel-v20'; p.setAttribute('data-gg-theme', currentTheme);
// Header
const h=document.createElement('div'); h.className='gg-header';
const t=document.createElement('span'); t.className='gg-title'; t.innerText='GG-BOOM V20.0';
const m=document.createElement('span'); m.className='gg-min-btn'; m.innerText='—'; m.title='最小化';
m.onclick=(e)=>{e.stopPropagation();togglePanel();};
h.appendChild(t); h.appendChild(m); p.appendChild(h);
// Theme
const lT=document.createElement('div'); lT.className='gg-label'; lT.innerText='主题风格'; p.appendChild(lT);
const sel=document.createElement('select'); sel.className='gg-select';
Object.keys(themes).forEach(k=>{const opt=document.createElement('option');opt.value=k;opt.innerText=themes[k];if(k===currentTheme)opt.selected=true;sel.appendChild(opt);});
sel.onchange=(e)=>switchTheme(e.target.value); p.appendChild(sel);
// Tools
const l1=document.createElement('div'); l1.className='gg-label'; l1.innerText='小工具'; p.appendChild(l1);
const g=document.createElement('div'); g.className='gg-grid';
const bCopy=mkBtn('📄 纯净复制',()=>cleanCopy(bCopy));
const bWide=mkBtn('🖥️ 宽屏: 关',()=>toggleWide(bWide));
const bEye=mkBtn('👁️ 护眼: 关',()=>toggleEye(bEye));
const bScr=mkBtn('📜 自动滚动',function(){autoScroll=!autoScroll; this.classList.toggle('active'); if(autoScroll)forceScrollBottom(true);});
const bBot=mkBtn('⬇️ 回到最下',()=>forceScrollBottom(true));
const bExp=mkBtn('💾 导出MD',()=>{const b=new Blob([document.body.innerText],{type:'text/markdown'});const a=document.createElement('a');a.href=URL.createObjectURL(b);a.download='Gemini.md';a.click();});
g.appendChild(bCopy); g.appendChild(bWide); g.appendChild(bEye); g.appendChild(bScr); g.appendChild(bBot); g.appendChild(bExp); p.appendChild(g);
// Outline
const l2=document.createElement('div'); l2.className='gg-section-header'; l2.style.marginTop='8px';
const lb2=document.createElement('span'); lb2.className='gg-label'; lb2.innerText='大纲';
const ctrls=document.createElement('div');
const cCol=document.createElement('span'); cCol.className='gg-icon-btn'; cCol.innerText='▼'; cCol.onclick=()=>toggleOutline(cCol);
const cRef=document.createElement('span'); cRef.className='gg-icon-btn'; cRef.innerText='🔄'; cRef.onclick=refreshOutline;
ctrls.appendChild(cCol); ctrls.appendChild(cRef); l2.appendChild(lb2); l2.appendChild(ctrls); p.appendChild(l2);
const ol=document.createElement('ul'); ol.id='gg-outline-box'; p.appendChild(ol);
// Prompts
const l3=document.createElement('div'); l3.className='gg-label'; l3.style.marginTop='8px'; l3.innerText='快捷提示字'; p.appendChild(l3);
const chips=document.createElement('div'); chips.className='gg-chip-area';
let pm=JSON.parse(localStorage.getItem('gg_v20_pm'))||['继续','详细解释','翻译','润色','总结'];
const renderPm=()=>{
while(chips.firstChild)chips.removeChild(chips.firstChild);
pm.forEach((txt,i)=>{
const c=document.createElement('span'); c.className='gg-chip'; c.innerText=txt;
c.onclick=()=>{const e=document.querySelector('div[contenteditable="true"]');if(e){e.focus();document.execCommand('insertText',false,txt);}};
c.oncontextmenu=(e)=>{e.preventDefault();if(confirm('Del?')){pm.splice(i,1);localStorage.setItem('gg_v20_pm',JSON.stringify(pm));renderPm();}};
chips.appendChild(c);
});
const add=document.createElement('span'); add.className='gg-chip'; add.innerText='+'; add.style.color='var(--gg-accent)';
add.onclick=()=>{const n=prompt('New:');if(n){pm.push(n);localStorage.setItem('gg_v20_pm',JSON.stringify(pm));renderPm();}};
chips.appendChild(add);
};
renderPm(); p.appendChild(chips);
// Footer
const f=document.createElement('div'); f.className='gg-footer'; f.innerText='Enter 换行 | Ctrl+Enter 发送'; p.appendChild(f);
document.body.appendChild(p); makeDraggable(p,h); switchTheme(currentTheme); setTimeout(refreshOutline,1000);
}
// --- Loop ---
setInterval(()=>{
buildUI();
// 自动滚动核心逻辑
if(autoScroll) {
const stop = document.querySelector('button[aria-label*="Stop"]') || document.querySelector('button[aria-label*="停止"]');
if(stop) forceScrollBottom(false); // 瞬时滚动
}
const q=document.querySelector('.user-query-text'); if(q&&!document.title.startsWith('🤖'))document.title='🤖 '+q.innerText.slice(0,10);
}, 100);
// --- Keys ---
window.addEventListener('keydown',e=>{
if(e.altKey&&(e.key==='g'||e.key==='G')){const p=document.getElementById('gg-panel-v20');p.style.left='50%';p.style.top='50%';p.style.transform='translate(-50%,-50%)';p.style.display='flex';p.style.opacity='1';document.getElementById('gg-float-ball').style.display='none';isHidden=false;}
if(!e.target.isContentEditable)return;
if(e.key==='Enter'&&e.ctrlKey){
e.preventDefault();e.stopPropagation();
const btn=document.querySelector('button[aria-label*="Send"]')||document.querySelector('button[aria-label*="发送"]');
if(btn)btn.click();else{const icon=document.querySelector('mat-icon[data-mat-icon-name="send"]');if(icon)icon.closest('button').click();}
}else if(e.key==='Enter'&&!e.shiftKey){
e.preventDefault();e.stopPropagation(); document.execCommand('insertText',false,'\n');
}
},true);
})();
觉得好用求个鸡腿!🍗 感谢!
**
@91 #1 嘿嘿,不知道应该咋说。。。
哥们,让Gemini更好用,不叫“制夷”
待会试试,给鸡腿
如果有好用的功能,各位可以随时评论回复。我有空看到我就加进去
比较喜欢这个去除**##的功能
@a5293604 #5 我主要是用AI来写公众号啥的。 这样我拿着直接偷很舒服
真不错😦
大佬nb
历史对话分组功能感觉挺有用的,不知道能否实现。
感谢分享