Sukebei Row Filter Enhanced

Filter out rows without background color on Sukebei and rows containing [FHDC], except in search results. Auto-navigate when all rows are filtered. Enhanced layout with shorter dates and optimized column widths.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Sukebei Row Filter Enhanced
// @namespace    http://tampermonkey.net/
// @version      0.7
// @description  Filter out rows without background color on Sukebei and rows containing [FHDC], except in search results. Auto-navigate when all rows are filtered. Enhanced layout with shorter dates and optimized column widths.
// @match        https://sukebei.nyaa.si/*
// @grant        none
// @license      MIT
// ==/UserScript==
(function() {
    'use strict';

    function shouldApplyFilter() {
        const url = window.location.href;
        // Apply filter on main page and category views
        return url === 'https://sukebei.nyaa.si/' || url.includes('/?c=');
    }

    function clickNextPage() {
        const nextButton = document.querySelector('ul.pagination li:last-child a');
        if (nextButton && !nextButton.parentElement.classList.contains('disabled')) {
            nextButton.click();
        }
    }

    function formatDate(dateString) {
        // Convert "2025-09-20 21:34" to "09/20/25"
        if (!dateString) return dateString;

        const match = dateString.match(/(\d{4})-(\d{2})-(\d{2})\s+\d{2}:\d{2}/);
        if (match) {
            const [, year, month, day] = match;
            return `${month}/${day}/${year.slice(-2)}`;
        }
        return dateString;
    }

    function optimizeLayout() {
        // Add custom CSS for layout optimization
        if (!document.getElementById('sukebei-layout-styles')) {
            const style = document.createElement('style');
            style.id = 'sukebei-layout-styles';
            style.textContent = `
                /* Hide the downloads/check column */
                .hdr-downloads,
                table.torrent-list tbody tr td:last-child {
                    display: none !important;
                }

                /* Adjust column widths */
                .hdr-name {
                    width: auto !important;
                    min-width: 300px !important;
                }

                .hdr-date {
                    width: 80px !important;
                }

                .hdr-seeders,
                .hdr-leechers {
                    width: 40px !important;
                }

                .hdr-size {
                    width: 60px !important;
                }

                /* Make the table more compact */
                table.torrent-list {
                    table-layout: fixed;
                    width: 100%;
                }

                /* Better text wrapping for name column */
                table.torrent-list tbody tr td:nth-child(2) {
                    word-wrap: break-word;
                    word-break: break-word;
                    white-space: normal;
                    line-height: 1.3;
                }

                /* Center align numeric columns */
                table.torrent-list tbody tr td:nth-child(7),
                table.torrent-list tbody tr td:nth-child(8) {
                    text-align: center;
                }
            `;
            document.head.appendChild(style);
        }
    }

    function formatSizes() {
        if (shouldApplyFilter()) {
            // Remove units from size column, keeping only numbers
            const sizeColumns = document.querySelectorAll('table.torrent-list tbody tr .text-center');
            sizeColumns.forEach(cell => {
                const originalText = cell.textContent.trim();
                // Check if this looks like a size (contains GiB, MiB, etc.)
                if (originalText.match(/\d+\.?\d*\s*(GiB|MiB|KiB|TiB|GB|MB|KB|TB)/i)) {
                    const match = originalText.match(/^([\d.,]+)/);
                    if (match) {
                        cell.textContent = match[1];
                    }
                }
            });
        }
    }

    function formatDatesInTable() {
        if (shouldApplyFilter()) {
            // Format dates in all visible rows - targeting the date column more specifically
            const dateColumns = document.querySelectorAll('table.torrent-list tbody tr td[data-timestamp]');
            dateColumns.forEach(cell => {
                const originalText = cell.textContent.trim();
                const formattedDate = formatDate(originalText);
                if (formattedDate !== originalText) {
                    cell.textContent = formattedDate;
                }
            });
        }
    }

    function filterRows() {
        if (shouldApplyFilter()) {
            const rows = document.querySelectorAll('table.torrent-list tbody tr');
            let visibleRows = 0;

            rows.forEach(row => {
                // Get the title text from the row
                const titleElement = row.querySelector('td:nth-child(2) a:not(.comments)');
                const titleText = titleElement ? titleElement.textContent : '';

                // Check if row should be hidden based on multiple conditions
                const shouldHide = (
                    // Original conditions: hide if no background color
                    (!row.classList.contains('success') && !row.classList.contains('danger')) ||
                    // New condition: hide if contains [FHDC]
                    titleText.includes('FHDC')
                );

                row.style.display = shouldHide ? 'none' : '';
                if (!shouldHide) {
                    visibleRows++;
                }
            });

            // If no visible rows remain, click the next page button
            if (visibleRows === 0) {
                clickNextPage();
            }
        }
    }

    function applyFiltering() {
        // Short delay to ensure the DOM is fully updated
        setTimeout(() => {
            optimizeLayout();
            filterRows();
            formatDatesInTable();
            formatSizes();
        }, 100);
    }

    // Initial application
    applyFiltering();

    // Handle pagination and dynamic content loading
    const observer = new MutationObserver((mutations) => {
        for (let mutation of mutations) {
            if (mutation.type === 'childList' &&
                (mutation.target.classList.contains('torrent-list') ||
                 mutation.target.querySelector('.torrent-list'))) {
                applyFiltering();
                break;
            }
        }
    });

    const config = { childList: true, subtree: true };
    observer.observe(document.body, config);

    // Handle page navigation for single-page application behavior
    window.addEventListener('popstate', applyFiltering);
})();