// ==UserScript==
// @name 增强版推特搜索助手-Twitter Search Assistant Enhanced
// @namespace example.twitter.enhanced
// @version 2.6
// @description 推特搜索助手
// @match https://twitter.com/*
// @match https://x.com/*
// @grant none
// @license MIT
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
// 定义搜索预设
const presets = {
"📷 图片": "filter:images -filter:retweets -filter:replies",
"🎬 视频": "filter:videos -filter:retweets -filter:replies",
"🔥 高热度": "min_faves:200 -filter:retweets",
"🈶 日语": "lang:ja -filter:retweets -filter:replies",
"🌎 英语": "lang:en -filter:retweets -filter:replies",
"💬 感想": "感想 OR 評価 lang:ja -filter:retweets -filter:replies",
"⏰ 近期": "since:2024-07-25 -filter:retweets",
"🎵 BGM讨论": "BGM OR 音乐 OR OST lang:ja -filter:retweets"
};
// 历史记录管理
const MAX_HISTORY = 20;
// 主面板HTML - 增加历史面板
const container = document.createElement('div');
container.id = 'tw-search-container';
container.innerHTML = `
`;
// 样式 - 修改间距、宽度和位置
const style = document.createElement('style');
style.textContent = `
#tw-search-container {
position: fixed;
top: 5px;
right: 190px; /* 搜索框整体偏移距离,数值越小越靠右 */
display: flex;
gap: 4px; /* 紧贴间距从8px减少到4px */
z-index: 10000;
align-items: stretch;
}
#tw-search-assistant, #tw-history-panel {
background: #ffffff;
border: 1px solid #e1e8ed;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
font-size: 13px;
color: #0f1419;
transition: all 0.3s ease;
opacity: 0;
transform: translateY(-10px);
box-sizing: border-box;
}
#tw-search-assistant {
flex: 0 0 280px; /* 固定主面板宽度 */
}
#tw-history-panel {
flex: 0 0 160px; /* 历史栏宽度从200px减少到160px */
}
#tw-search-assistant.show, #tw-history-panel.show {
opacity: 1;
transform: translateY(0);
}
#tw-search-assistant.hidden, #tw-history-panel.hidden {
opacity: 0 !important;
pointer-events: none !important;
z-index: -1 !important;
}
#tw-search-assistant:hover, #tw-history-panel:hover {
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
}
.panel-header, .history-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px 8px;
border-bottom: 1px solid #eff3f4;
font-weight: 600;
}
.history-header {
padding: 10px 12px 6px; /* 历史栏标题稍小一点 */
}
.toggle-mode, .clear-history {
background: none;
border: none;
cursor: pointer;
font-size: 14px;
padding: 2px 4px;
border-radius: 4px;
transition: background 0.2s;
}
.toggle-mode:hover, .clear-history:hover {
background: #f7f9fa;
}
.mode-indicator {
padding: 4px 16px;
font-size: 11px;
color: #536471;
background: #f7f9fa;
margin: 0 16px 8px;
border-radius: 6px;
text-align: center;
}
.mode-indicator.multi-mode {
background: #e8f5fe;
color: #1da1f2;
}
.keyword-container {
padding: 0 16px 12px;
}
#tw-keyword {
width: 100%;
padding: 8px 12px;
border: 1px solid #eff3f4;
border-radius: 8px;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
box-sizing: border-box;
}
#tw-keyword:focus {
border-color: #1da1f2;
box-shadow: 0 0 0 3px rgba(29, 161, 242, 0.1);
}
.preset-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px;
padding: 0 16px 12px;
}
.preset-btn {
padding: 8px 12px;
background: #f7f9fa;
border: 1px solid #eff3f4;
border-radius: 8px;
color: #0f1419;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 4px;
}
.preset-btn:hover {
background: #e8f5fe;
border-color: #cfe5f7;
}
.preset-btn.selected {
background: #e8f5fe;
color: #1da1f2;
border-color: #1da1f2;
}
.preset-btn.selected::after {
content: '✓';
margin-left: auto;
font-size: 11px;
font-weight: bold;
}
.history-list {
padding: 4px 8px; /* 历史栏内边距稍小 */
max-height: 400px;
overflow-y: auto;
}
.history-item {
padding: 6px 8px; /* 历史项内边距也相应缩小 */
border-radius: 6px;
cursor: pointer;
transition: background 0.2s;
font-size: 12px;
color: #0f1419;
margin-bottom: 2px; /* 历史项间距缩小 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.history-item:hover {
background: #f7f9fa;
}
.history-item:active {
background: #e1e8ed;
}
.empty-history {
padding: 16px 8px; /* 空状态提示也调整 */
text-align: center;
color: #536471;
font-size: 11px; /* 字体稍小一点 */
}
.action-buttons {
display: flex;
gap: 8px;
padding: 0 16px 16px;
}
.btn-clear, .btn-apply {
flex: 1;
padding: 8px;
border: none;
border-radius: 8px;
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
font-weight: 500;
}
.btn-clear {
background: #f7f9fa;
color: #536471;
border: 1px solid #eff3f4;
}
.btn-clear:hover {
background: #e1e8ed;
}
.btn-apply {
background: #1da1f2;
color: white;
}
.btn-apply:hover {
background: #1a91da;
}
.btn-apply.active {
background: #17bf63;
box-shadow: 0 2px 8px rgba(23, 191, 99, 0.3);
}
`;
document.head.appendChild(style);
document.body.appendChild(container);
// 状态管理
let isMultiSelectMode = false;
let selectedPresets = new Set();
// 历史记录功能
function getHistory() {
try {
const history = localStorage.getItem('tw-search-history');
return history ? JSON.parse(history) : [];
} catch (e) {
return [];
}
}
function saveHistory(keyword) {
if (!keyword || keyword.trim() === '') return;
keyword = keyword.trim();
let history = getHistory();
// 移除重复项
history = history.filter(item => item !== keyword);
// 添加到最前面
history.unshift(keyword);
// 限制数量
if (history.length > MAX_HISTORY) {
history = history.slice(0, MAX_HISTORY);
}
try {
localStorage.setItem('tw-search-history', JSON.stringify(history));
} catch (e) {
// 存储失败时的静默处理
}
renderHistory();
}
function clearAllHistory() {
try {
localStorage.removeItem('tw-search-history');
renderHistory();
} catch (e) {
// 清空失败时的静默处理
}
}
function renderHistory() {
const historyList = document.querySelector('.history-list');
const history = getHistory();
if (history.length === 0) {
historyList.innerHTML = '暂无搜索历史
';
return;
}
historyList.innerHTML = history.map(item =>
`${escapeHtml(item)}
`
).join('');
// 绑定点击事件
historyList.querySelectorAll('.history-item').forEach(item => {
item.addEventListener('click', () => {
const keyword = decodeURIComponent(item.getAttribute('data-keyword'));
document.getElementById('tw-keyword').value = keyword;
// 不触发搜索,只是填充
});
});
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 极速消失检测 - 监听特定元素出现
function initMediaDetection() {
const observer = new MutationObserver(() => {
const modal = document.querySelector('[aria-modal="true"]') ||
document.querySelector('[data-testid="swipe-to-dismiss-container"]') ||
document.querySelector('[data-testid="media-modal"]');
const assistant = document.getElementById('tw-search-assistant');
const history = document.getElementById('tw-history-panel');
if (modal) {
assistant.classList.add('hidden');
history.classList.add('hidden');
} else {
assistant.classList.remove('hidden');
history.classList.remove('hidden');
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['aria-modal', 'style']
});
}
// 简化:只提取关键词,不要任何过滤条件
function extractKeywordOnly(url) {
if (!url.includes('/search?q=')) return '';
try {
const match = url.match(/\/search\?q=([^&]+)/);
if (!match) return '';
const query = decodeURIComponent(match[1]);
const keyword = query.split(/\s+(?:filter:|lang:|min_faves:|since:|from:|to:|until:|OR|AND|NOT)/)[0].trim();
return keyword;
} catch (e) {
return '';
}
}
// 处理预设点击
function handlePresetClick(btn, filter) {
if (isMultiSelectMode) {
if (selectedPresets.has(filter)) {
selectedPresets.delete(filter);
btn.classList.remove('selected');
} else {
selectedPresets.add(filter);
btn.classList.add('selected');
}
updateApplyButton();
} else {
const keyword = document.getElementById('tw-keyword').value.trim() || extractKeywordOnly(window.location.href);
if (!keyword) {
alert('请输入关键词');
return;
}
saveHistory(keyword);
const searchUrl = `https://twitter.com/search?q=${encodeURIComponent(keyword + ' ' + filter)}&src=typed_query&f=top`;
window.location.href = searchUrl;
}
}
// 更新应用按钮
function updateApplyButton() {
const applyBtn = document.querySelector('.btn-apply');
if (isMultiSelectMode && selectedPresets.size > 0) {
applyBtn.classList.add('active');
applyBtn.textContent = `应用搜索(${selectedPresets.size})`;
} else if (isMultiSelectMode) {
applyBtn.classList.remove('active');
applyBtn.textContent = '应用搜索';
}
}
// 多选模式搜索 - 彻底清空旧条件
function applyMultiSelect() {
if (!isMultiSelectMode || selectedPresets.size === 0) {
alert('多选模式下请至少选择一个筛选条件');
return;
}
const keyword = document.getElementById('tw-keyword').value.trim() || extractKeywordOnly(window.location.href);
if (!keyword) {
alert('请输入关键词');
return;
}
saveHistory(keyword);
const selectedFilters = Array.from(selectedPresets).join(' ');
const finalQuery = keyword + ' ' + selectedFilters;
const searchUrl = `https://twitter.com/search?q=${encodeURIComponent(finalQuery.trim())}&src=typed_query&f=top`;
window.location.href = searchUrl;
}
// 清空选择
function clearSelection() {
selectedPresets.clear();
document.querySelectorAll('.preset-btn.selected').forEach(btn => {
btn.classList.remove('selected');
});
updateApplyButton();
}
// 切换模式
function toggleMode() {
isMultiSelectMode = !isMultiSelectMode;
const indicator = document.querySelector('.mode-indicator');
const applyBtn = document.querySelector('.btn-apply');
if (isMultiSelectMode) {
indicator.textContent = '多选模式';
indicator.classList.add('multi-mode');
applyBtn.style.display = 'block';
clearSelection();
} else {
indicator.textContent = '单选模式';
indicator.classList.remove('multi-mode');
applyBtn.style.display = 'none';
clearSelection();
}
}
// 自动填充关键词
function autoFillKeyword() {
const keyword = extractKeywordOnly(window.location.href);
if (keyword && !document.getElementById('tw-keyword').value) {
document.getElementById('tw-keyword').value = keyword;
}
}
// 初始化按钮
function initButtons() {
const grid = document.querySelector('.preset-grid');
Object.keys(presets).forEach(name => {
const btn = document.createElement('button');
btn.className = 'preset-btn';
btn.textContent = name;
btn.onclick = () => handlePresetClick(btn, presets[name]);
grid.appendChild(btn);
});
}
// 监听URL变化
observeUrlChanges();
function observeUrlChanges() {
let currentUrl = window.location.href;
setInterval(() => {
if (window.location.href !== currentUrl) {
currentUrl = window.location.href;
autoFillKeyword();
clearSelection();
}
}, 500);
}
// 绑定事件
document.querySelector('.toggle-mode').onclick = toggleMode;
document.querySelector('.btn-clear').onclick = clearSelection;
document.querySelector('.btn-apply').onclick = applyMultiSelect;
document.querySelector('.clear-history').onclick = clearAllHistory;
// 初始化
initButtons();
autoFillKeyword();
renderHistory();
initMediaDetection();
// 显示面板
setTimeout(() => {
document.getElementById('tw-search-assistant').classList.add('show');
document.getElementById('tw-history-panel').classList.add('show');
}, 100);
})();