您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
X (Twitter) のタイムラインタブをフリックで移動。「フォロー中」タブをスキップします。
// ==UserScript== // @name X/Twitter タブフリック移動 (フォロー中スキップ) // @name:ja X/Twitter タブフリック移動 (フォロー中スキップ) // @namespace http://tampermonkey.net/ // @version 1.2 // @description X (Twitter) のタイムラインタブをフリックで移動。「フォロー中」タブをスキップします。 // @description:ja X (Twitter) のタイムラインタブをフリックで移動。「フォロー中」タブをスキップします。 // @description:en Allows you to switch between X (Twitter) timeline tabs by flicking, skipping the "Following" tab. // @author K-shir0 // @match https://x.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // スキップしたいタブのテキスト const TAB_TO_SKIP = 'フォロー中'; // スワイプ操作を検知する領域のセレクタ const TAB_LIST_SELECTOR = '[role="tablist"]'; // スワイプを検知する最小距離 (ピクセル) const MIN_SWIPE_DISTANCE = 30; let startX = 0; let startY = 0; let isSwiping = false; function findTabs() { const tabList = document.querySelector(TAB_LIST_SELECTOR); if (!tabList) return { tabs: [], activeIndex: -1 }; const tabs = Array.from(tabList.querySelectorAll('[role="tab"]')); const activeIndex = tabs.findIndex(tab => tab.getAttribute('aria-selected') === 'true'); return { tabs, activeIndex }; } function switchTab(direction) { const { tabs, activeIndex } = findTabs(); if (activeIndex === -1 || tabs.length === 0) return; let nextIndex = activeIndex; if (direction === 'right') { // 右フリック(左へ移動) nextIndex++; // 次のタブが「フォロー中」なら、さらに次のタブへ if (tabs[nextIndex] && tabs[nextIndex].textContent === TAB_TO_SKIP) { nextIndex++; } } else { // 左フリック(右へ移動) nextIndex--; // 前のタブが「フォロー中」なら、さらに前のタブへ if (tabs[nextIndex] && tabs[nextIndex].textContent === TAB_TO_SKIP) { nextIndex--; } } if (nextIndex >= 0 && nextIndex < tabs.length) { tabs[nextIndex].click(); } } function handleSwipeStart(e) { const touch = e.type === 'touchstart' ? e.touches[0] : e; startX = touch.clientX; startY = touch.clientY; isSwiping = true; } function handleSwipeEnd(e) { if (!isSwiping) return; isSwiping = false; const touch = e.type === 'touchend' ? e.changedTouches[0] : e; const diffX = touch.clientX - startX; const diffY = touch.clientY - startY; // 左右のスワイプを優先するため、垂直方向の移動が大きい場合は無視 if (Math.abs(diffX) < Math.abs(diffY)) { return; } if (Math.abs(diffX) > MIN_SWIPE_DISTANCE) { if (diffX > 0) { // 右へのスワイプ -> 左のタブへ switchTab('left'); } else { // 左へのスワイプ -> 右のタブへ switchTab('right'); } } } // イベントリスナーをセットアップする関数 function setupSwipeListeners() { if (window.flickTabListenerAdded) return; const mainContent = document.querySelector('main'); if (mainContent) { mainContent.addEventListener('touchstart', handleSwipeStart, { passive: true }); mainContent.addEventListener('touchend', handleSwipeEnd, { passive: true }); mainContent.addEventListener('mousedown', handleSwipeStart, { passive: true }); mainContent.addEventListener('mouseup', handleSwipeEnd, { passive: true }); window.flickTabListenerAdded = true; console.log('X/Twitter Tab Flipper (Skip Following) is active.'); } } // ページ遷移やコンテンツの動的読み込みに対応するため、MutationObserver を使用 const observer = new MutationObserver((mutations) => { if (document.querySelector(TAB_LIST_SELECTOR) && !window.flickTabListenerAdded) { setupSwipeListeners(); } }); observer.observe(document.body, { childList: true, subtree: true }); // 初期読み込み時にも実行 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', setupSwipeListeners); } else { setupSwipeListeners(); } })();