Seiko Watch Info Enhancer for Reddit & Forums

Automatically detect Seiko watch models in Reddit posts and comments, and add helpful info cards with mod options, custom builds, and upgrade paths. Essential tool for r/SeikoMods community!

// ==UserScript==
// @name         Seiko Watch Info Enhancer for Reddit & Forums
// @version      1.2
// @description  Automatically detect Seiko watch models in Reddit posts and comments, and add helpful info cards with mod options, custom builds, and upgrade paths. Essential tool for r/SeikoMods community!
// @author       SkyrimWrist
// @match        *://*.reddit.com/*
// @match        *://watchuseek.com/*
// @match        *://skyrimwrist.com/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @license      MIT
// @namespace https://greasyfork.org/users/1236237
// ==/UserScript==

(function() {
    'use strict';

    // Seiko model database with mod potential
    const SEIKO_MODELS = {
        'SKX007': {
            name: 'Seiko SKX007',
            modPotential: 'Excellent',
            popularMods: ['NH35 movement upgrade', 'Sapphire crystal', 'Ceramic bezel insert', 'Custom dial & hands'],
            difficulty: 'Beginner-Friendly',
            description: 'The most popular Seiko mod platform with endless customization options.'
        },
        'SKX009': {
            name: 'Seiko SKX009',
            modPotential: 'Excellent',
            popularMods: ['Pepsi bezel', 'NH36 movement', 'Double-dome sapphire', 'Aftermarket hands'],
            difficulty: 'Beginner-Friendly',
            description: 'Iconic Pepsi diver with massive modding community support.'
        },
        'SKX013': {
            name: 'Seiko SKX013',
            modPotential: 'Very Good',
            popularMods: ['36mm case mods', 'NH35 upgrade', 'Sapphire crystal', 'Custom bezels'],
            difficulty: 'Intermediate',
            description: 'Compact 38mm version perfect for smaller wrists.'
        },
        'TURTLE': {
            name: 'Seiko Turtle (SRP/SRPE)',
            modPotential: 'Excellent',
            popularMods: ['Ceramic bezel', 'Sapphire crystal', 'OEM+ dial swaps', 'Uncle Seiko bracelet'],
            difficulty: 'Intermediate',
            description: 'Cushion case classic with great water resistance and mod options.'
        },
        'SAMURAI': {
            name: 'Seiko Samurai (SRPB/SRPE)',
            modPotential: 'Good',
            popularMods: ['Bezel inserts', 'Sapphire crystal', 'Aftermarket bracelets'],
            difficulty: 'Intermediate',
            description: 'Angular sports diver with unique aesthetics.'
        },
        'MONSTER': {
            name: 'Seiko Monster',
            modPotential: 'Very Good',
            popularMods: ['Bezel mods', 'Crystal upgrades', 'Hand swaps'],
            difficulty: 'Intermediate',
            description: 'Bold design with distinctive shark-tooth markers.'
        },
        'ALPINIST': {
            name: 'Seiko Alpinist',
            modPotential: 'Good',
            popularMods: ['Sapphire crystal', 'Strap swaps', 'Dial variants'],
            difficulty: 'Intermediate',
            description: 'Field watch icon with compass bezel and cathedral hands.'
        },
        '5KX': {
            name: 'Seiko 5 Sports (SRPD/K)',
            modPotential: 'Excellent',
            popularMods: ['Complete case swaps', 'NH36 parts', 'SKX-style conversion'],
            difficulty: 'Beginner-Friendly',
            description: 'Modern Seiko 5 with NH36 movement - great value mod base.'
        },
        'SNK': {
            name: 'Seiko SNK (SNK80x series)',
            modPotential: 'Good',
            popularMods: ['Dial swaps', 'Hand upgrades', 'Strap mods'],
            difficulty: 'Beginner',
            description: 'Affordable automatic perfect for learning to mod.'
        }
    };

    // Movement compatibility info
    const MOVEMENTS = {
        'NH35': 'Workhorse automatic movement, hacking & hand-winding, 41h power reserve',
        'NH36': 'NH35 with day-date complication, most versatile Seiko mod movement',
        '4R36': 'OEM version of NH36, excellent reliability',
        '7S26': 'Original SKX movement, non-hacking, 41h power reserve',
        '6R15': 'Higher-grade movement with 50h power reserve, used in Alpinist'
    };

    GM_addStyle(`
        .seiko-info-card {
            background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
            border-left: 4px solid #00d4ff;
            border-radius: 8px;
            padding: 12px 15px;
            margin: 10px 0;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
            box-shadow: 0 4px 12px rgba(0, 212, 255, 0.15);
            color: #ffffff;
        }

        .seiko-info-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 10px;
        }

        .seiko-model-name {
            font-size: 15px;
            font-weight: 700;
            color: #00d4ff;
            margin: 0;
        }

        .seiko-mod-badge {
            display: inline-block;
            padding: 3px 8px;
            background: rgba(0, 212, 255, 0.2);
            border-radius: 12px;
            font-size: 11px;
            color: #00d4ff;
            font-weight: 600;
        }

        .seiko-info-description {
            font-size: 13px;
            color: rgba(255, 255, 255, 0.85);
            margin: 8px 0;
            line-height: 1.5;
        }

        .seiko-mods-list {
            margin: 10px 0;
        }

        .seiko-mods-title {
            font-size: 12px;
            font-weight: 600;
            color: #ffd700;
            margin-bottom: 6px;
        }

        .seiko-mod-item {
            font-size: 12px;
            color: rgba(255, 255, 255, 0.8);
            padding: 4px 0;
            padding-left: 16px;
            position: relative;
        }

        .seiko-mod-item:before {
            content: "•";
            position: absolute;
            left: 4px;
            color: #00d4ff;
            font-weight: bold;
        }

        .seiko-info-links {
            display: flex;
            gap: 8px;
            margin-top: 12px;
            padding-top: 12px;
            border-top: 1px solid rgba(255, 255, 255, 0.1);
        }

        .seiko-info-link {
            flex: 1;
            padding: 8px 12px;
            background: rgba(0, 212, 255, 0.15);
            border: 1px solid rgba(0, 212, 255, 0.3);
            border-radius: 6px;
            text-align: center;
            text-decoration: none;
            color: #00d4ff;
            font-size: 12px;
            font-weight: 600;
            transition: all 0.2s;
            cursor: pointer;
        }

        .seiko-info-link:hover {
            background: rgba(0, 212, 255, 0.25);
            border-color: #00d4ff;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 212, 255, 0.2);
        }

        .seiko-difficulty {
            display: inline-block;
            padding: 2px 8px;
            background: rgba(255, 215, 0, 0.15);
            border-radius: 10px;
            font-size: 10px;
            color: #ffd700;
            margin-left: 8px;
        }

        .seiko-inline-link {
            color: #00d4ff;
            text-decoration: none;
            font-weight: 600;
            border-bottom: 1px dashed rgba(0, 212, 255, 0.4);
            transition: border-bottom 0.2s;
        }

        .seiko-inline-link:hover {
            border-bottom: 1px solid #00d4ff;
        }

        @keyframes fadeInUp {
            from {
                opacity: 0;
                transform: translateY(10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .seiko-info-card {
            animation: fadeInUp 0.3s ease-out;
        }
    `);

    // Detect Seiko model mentions in text
    function detectSeikoModels(text) {
        const upperText = text.toUpperCase();
        const foundModels = [];

        for (const [key, data] of Object.entries(SEIKO_MODELS)) {
            if (upperText.includes(key)) {
                foundModels.push({ key, ...data });
            }
        }

        return foundModels;
    }

    // Create info card for a Seiko model
    function createInfoCard(modelData) {
        const card = document.createElement('div');
        card.className = 'seiko-info-card';

        const modsHtml = modelData.popularMods
            .map(mod => `<div class="seiko-mod-item">${mod}</div>`)
            .join('');

        card.innerHTML = `
            <div class="seiko-info-header">
                <h4 class="seiko-model-name">⌚ ${modelData.name}</h4>
                <span class="seiko-mod-badge">Mod Potential: ${modelData.modPotential}</span>
            </div>
            <div class="seiko-info-description">
                ${modelData.description}
                <span class="seiko-difficulty">🔧 ${modelData.difficulty}</span>
            </div>
            <div class="seiko-mods-list">
                <div class="seiko-mods-title">Popular Modifications:</div>
                ${modsHtml}
            </div>
            <div class="seiko-info-links">
                <a href="https://skyrimwrist.com/collections/seiko-mod-watches?filter=${modelData.key.toLowerCase()}"
                   target="_blank"
                   class="seiko-info-link">
                    🔧 View Mod Parts
                </a>
                <a href="https://skyrimwrist.com/collections/custom-seiko-watches"
                   target="_blank"
                   class="seiko-info-link">
                    ✨ Custom Builds
                </a>
                <a href="https://skyrimwrist.com/pages/seiko-mod-guide"
                   target="_blank"
                   class="seiko-info-link">
                    📚 Mod Guide
                </a>
            </div>
        `;

        return card;
    }

    // Process Reddit posts and comments
    function processRedditContent() {
        // Reddit post titles
        const postTitles = document.querySelectorAll('[data-testid="post-container"] h3, .Post .title');

        postTitles.forEach(title => {
            if (title.hasAttribute('data-seiko-processed')) return;

            const models = detectSeikoModels(title.textContent);
            if (models.length > 0) {
                title.setAttribute('data-seiko-processed', 'true');

                // Add info card after the post
                const postContainer = title.closest('[data-testid="post-container"]') || title.closest('.Post');
                if (postContainer) {
                    const existingCard = postContainer.querySelector('.seiko-info-card');
                    if (!existingCard) {
                        models.forEach(model => {
                            const card = createInfoCard(model);
                            const contentArea = postContainer.querySelector('[data-click-id="text"]') ||
                                              postContainer.querySelector('.expando');
                            if (contentArea) {
                                contentArea.appendChild(card);
                            }
                        });
                    }
                }
            }
        });

        // Reddit comments
        const comments = document.querySelectorAll('[data-testid="comment"], .Comment .md');

        comments.forEach(comment => {
            if (comment.hasAttribute('data-seiko-processed')) return;

            const models = detectSeikoModels(comment.textContent);
            if (models.length > 0) {
                comment.setAttribute('data-seiko-processed', 'true');

                const existingCard = comment.querySelector('.seiko-info-card');
                if (!existingCard) {
                    models.slice(0, 1).forEach(model => { // Only show first match to avoid clutter
                        const card = createInfoCard(model);
                        comment.appendChild(card);
                    });
                }
            }
        });
    }

    // Process WatchUSeek forum posts
    function processForumContent() {
        const posts = document.querySelectorAll('.postcontent, .post-content, .messageText');

        posts.forEach(post => {
            if (post.hasAttribute('data-seiko-processed')) return;

            const models = detectSeikoModels(post.textContent);
            if (models.length > 0) {
                post.setAttribute('data-seiko-processed', 'true');

                const existingCard = post.querySelector('.seiko-info-card');
                if (!existingCard) {
                    models.slice(0, 1).forEach(model => {
                        const card = createInfoCard(model);
                        post.appendChild(card);
                    });
                }
            }
        });
    }

    // Initialize
    function init() {
        // Initial processing
        processRedditContent();
        processForumContent();

        // Watch for new content (infinite scroll, dynamic loading)
        const observer = new MutationObserver((mutations) => {
            processRedditContent();
            processForumContent();
        });

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

        // Also process on scroll (for lazy-loaded content)
        let scrollTimeout;
        window.addEventListener('scroll', () => {
            clearTimeout(scrollTimeout);
            scrollTimeout = setTimeout(() => {
                processRedditContent();
                processForumContent();
            }, 500);
        });
    }

    // Start when page is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();