Last active 1778119947

在办公室使用gpt会被同事追问:你怎么用上的?怎么翻墙的?能给我用用吗?而你又不想给这类 “等人喂饭” 的人群分享时,那么这个脚本就可以帮助到你了

change-gpt-logo.user.js Raw
1// ==UserScript==
2// @name ChatGPT Logo 换成 DeepSeek
3// @namespace https://gist.doracoin.cc/doracoin/39fd3ec77d3044fc95b408bdf6c0ac13
4// @version 2026.05.07
5// @license MIT
6// @description 替换 ChatGPT 左上角 sidebar-header 的 SVG logo 为 DeepSeek logo,并实现 #page-header 向上收缩(垂直折叠),支持 SPA 重绘、状态记忆,并增加可配置项与主题适配按钮。
7// @author Doracoin <[email protected]>
8// @homepageURL https://gist.doracoin.cc/doracoin/39fd3ec77d3044fc95b408bdf6c0ac13
9// @updateURL https://gist.doracoin.cc/doracoin/39fd3ec77d3044fc95b408bdf6c0ac13/raw/HEAD/change-gpt-logo.user.js
10// @downloadURL https://gist.doracoin.cc/doracoin/39fd3ec77d3044fc95b408bdf6c0ac13/download/HEAD/change-gpt-logo.user.js
11// @match https://chatgpt.com/*
12// @icon https://deepseek.com/favicon.ico
13// @run-at document-body
14// @grant GM_addStyle
15// ==/UserScript==
16
17(function () {
18 'use strict';
19
20 // ====== 配置区 ======
21 const CONFIG = {
22 deepseekLogoUrl: 'https://commons.wikimedia.org/wiki/Special:Redirect/file/DeepSeek_logo.svg',
23 deepseekSquareIconUrl: 'https://deepseek.com/favicon.ico',
24 storageKey: 'deepseek_header_collapsed_v2',
25 headerMaxHeight: 82,
26 buttonSize: 36,
27 buttonPosition: { top: 10, right: 12 },
28 enableLogs: false
29 };
30 // ====================
31
32 // 动态样式,支持深色/浅色主题自动适配
33 GM_addStyle(`
34 #page-header {
35 --ds-header-max-height: ${CONFIG.headerMaxHeight}px;
36 max-height: var(--ds-header-max-height);
37 overflow: hidden;
38 transition: max-height 260ms ease, padding 260ms ease;
39 }
40 #page-header.collapsed {
41 max-height: 0 !important;
42 padding-top: 0 !important;
43 padding-bottom: 0 !important;
44 }
45 #page-header.collapsed * {
46 visibility: hidden;
47 pointer-events: none;
48 }
49
50 #ds-page-header-toggle {
51 position: fixed;
52 top: ${CONFIG.buttonPosition.top}px;
53 right: ${CONFIG.buttonPosition.right}px;
54 z-index: 2147483647;
55 display: inline-flex;
56 align-items: center;
57 justify-content: center;
58 width: ${CONFIG.buttonSize}px;
59 height: ${CONFIG.buttonSize}px;
60 border-radius: 6px;
61 font-size: 16px;
62 line-height: 1;
63 background: var(--ds-btn-bg, rgba(0,0,0,0.6));
64 color: var(--ds-btn-fg, #fff);
65 cursor: pointer;
66 user-select: none;
67 transition: transform 140ms ease, opacity 140ms ease, background 200ms ease;
68 box-shadow: 0 6px 18px rgba(0,0,0,0.35);
69 margin-top: 38px;
70 }
71 #ds-page-header-toggle:hover {
72 transform: translateY(-2px);
73 }
74
75 @media (prefers-color-scheme: light) {
76 #ds-page-header-toggle {
77 --ds-btn-bg: rgba(255,255,255,0.85);
78 --ds-btn-fg: #000;
79 }
80 }
81 @media (prefers-color-scheme: dark) {
82 #ds-page-header-toggle {
83 --ds-btn-bg: rgba(0,0,0,0.6);
84 --ds-btn-fg: #fff;
85 }
86 }
87 `);
88
89 function log(...args) {
90 if (CONFIG.enableLogs) console.log('[DeepSeek]', ...args);
91 }
92
93 function replaceLogo() {
94 try {
95 const sidebarHeader = document.querySelector('#sidebar-header');
96 if (!sidebarHeader) return;
97
98 if (sidebarHeader.querySelector('img[data-deepseek-logo]')) return;
99
100 const logoLink = sidebarHeader.querySelector('a[aria-label="主页"]');
101 if (!logoLink) return;
102
103 const img = document.createElement('img');
104 img.setAttribute('src', CONFIG.deepseekLogoUrl);
105 img.setAttribute('alt', 'DeepSeek');
106 img.setAttribute('data-deepseek-logo', '1');
107 img.style.height = '28px';
108 img.style.width = 'auto';
109 img.style.objectFit = 'contain';
110 img.style.verticalAlign = 'middle';
111
112 logoLink.innerHTML = '';
113 logoLink.appendChild(img);
114
115 if (logoLink.classList.contains("w-9")) {
116 logoLink.classList.remove("w-9");
117 logoLink.classList.add("w-21");
118 }
119
120 log('logo replaced');
121 } catch (e) {
122 log('replaceLogo error', e);
123 }
124 }
125
126 function replaceCollapsedIcon() {
127 try {
128 const openBtn = document.querySelector('button[aria-label="打开边栏"]');
129 if (!openBtn) return;
130
131 const firstSvg = openBtn.querySelector('svg');
132 if (!firstSvg) return;
133
134 if (openBtn.querySelector('img[data-deepseek-collapsed]')) return;
135
136 const img = document.createElement('img');
137 img.setAttribute('src', CONFIG.deepseekSquareIconUrl);
138 img.setAttribute('alt', 'DeepSeek');
139 img.setAttribute('data-deepseek-collapsed', '1');
140 img.style.width = '20px';
141 img.style.height = '20px';
142 img.style.objectFit = 'contain';
143
144 firstSvg.replaceWith(img);
145
146 log('collapsed icon replaced');
147 } catch (e) {
148 log('replaceCollapsedIcon error', e);
149 }
150 }
151
152 function ensureToggle() {
153 let btn = document.getElementById('ds-page-header-toggle');
154 if (btn) return btn;
155
156 btn = document.createElement('div');
157 btn.id = 'ds-page-header-toggle';
158 btn.setAttribute('role', 'button');
159 btn.setAttribute('aria-pressed', 'false');
160 btn.setAttribute('title', '折叠/展开页眉 (DeepSeek)');
161 btn.innerText = '▲';
162 btn.addEventListener('click', () => toggleHeader());
163 document.body.appendChild(btn);
164 return btn;
165 }
166
167 function getHeader() {
168 return document.querySelector('#page-header') || document.querySelector('header') || document.querySelector('.page-header');
169 }
170
171 function toggleHeader(forceState) {
172 const header = getHeader();
173 if (!header) return;
174
175 const shouldCollapse = typeof forceState === 'boolean' ? forceState : !header.classList.contains('collapsed');
176 header.classList.toggle('collapsed', shouldCollapse);
177
178 try { localStorage.setItem(CONFIG.storageKey, shouldCollapse ? '1' : '0'); } catch (e) {}
179
180 const btn = ensureToggle();
181 btn.innerText = shouldCollapse ? '▼' : '▲';
182 btn.setAttribute('aria-pressed', shouldCollapse ? 'true' : 'false');
183 }
184
185 function restoreState() {
186 try {
187 const v = localStorage.getItem(CONFIG.storageKey);
188 if (v === '1') toggleHeader(true);
189 } catch (e) {}
190 }
191
192 let debounceTimer = null;
193 function onDomChanged() {
194 if (debounceTimer) clearTimeout(debounceTimer);
195 debounceTimer = setTimeout(() => {
196 replaceLogo();
197 replaceCollapsedIcon();
198 ensureToggle();
199 restoreState();
200 }, 250);
201 }
202
203 const observer = new MutationObserver(onDomChanged);
204 observer.observe(document.body, { childList: true, subtree: true });
205
206 replaceLogo();
207 replaceCollapsedIcon();
208 ensureToggle();
209 restoreState();
210 window.addEventListener('load', () => setTimeout(onDomChanged, 300));
211})();
212