Amazon Delivery Status Monitor

Monitor delivery status changes on Amazon tracking pages and send notifications

ของเมื่อวันที่ 31-10-2025 ดู เวอร์ชันล่าสุด

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey, Greasemonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Amazon Delivery Status Monitor
// @version      1.9
// @description  Monitor delivery status changes on Amazon tracking pages and send notifications
// @author       incognico
// @namespace    https://greasyfork.org/users/931787
// @license      MIT
// @match        https://www.amazon.*/gp/your-account/ship-track*
// @match        https://amazon.*/gp/your-account/ship-track*
// @match        https://www.amazon.*/progress-tracker/*
// @match        https://amazon.*/progress-tracker/*
// @icon         https://i.imgur.com/LGHKHEs.png
// @grant        GM_notification
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    console.log('Amazon Delivery Status Monitor loaded');

    const STORAGE_KEY_PREFIX = 'amazon_delivery_status_monitor_';
    let observer = null;
    let refreshTimer = null;
    let isInitialized = false;

    function getItemId() {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get('itemId');
    }

    function getStorageKey() {
        const itemId = getItemId();
        if (!itemId) {
            console.warn('No itemId found in URL');
            return null;
        }
        return STORAGE_KEY_PREFIX + itemId;
    }

    function getStoredStatus() {
        try {
            const storageKey = getStorageKey();
            if (!storageKey) return {};

            const stored = localStorage.getItem(storageKey);
            return stored ? JSON.parse(stored) : {};
        } catch (e) {
            console.warn('Failed to read from localStorage:', e);
            return {};
        }
    }

    function setStoredStatus(statusObj) {
        try {
            const storageKey = getStorageKey();
            if (!storageKey) {
                console.warn('Cannot store status: no itemId found');
                return;
            }

            localStorage.setItem(storageKey, JSON.stringify(statusObj));
        } catch (e) {
            console.warn('Failed to write to localStorage:', e);
        }
    }

    function checkDeliveryStatus() {
        const itemId = getItemId();
        if (!itemId) {
            console.log('No itemId in URL, skipping status check');
            return;
        }

        const elements = {
            outForDelivery: document.querySelector('.H_ib_content'),
            promiseDate: document.querySelector('.pt-promise-main-slot'),
            promiseDetails: document.querySelector('.pt-promise-details-slot'),
            primaryStatus: document.querySelector('#primaryStatus'),
            exceptionMessage: document.querySelector('#lexicalExceptionMessage-container h3') || document.querySelector('.lexicalExceptionMessage-container h3'),
            mainStatus: document.querySelector('.pt-status-main-status'),
            secondaryStatus: document.querySelector('.pt-status-secondary-status')
        };

        const currentStatus = {};
        let hasAnyContent = false;

        // Collect current status from all elements
        Object.keys(elements).forEach(key => {
            const element = elements[key];
            if (element) {
                const content = element.textContent.trim();
                if (content) {
                    currentStatus[key] = content;
                    hasAnyContent = true;
                }
            }
        });

        if (!hasAnyContent) {
            console.log(`No delivery status elements found for item ${itemId}`);
            return;
        }

        const lastStatus = getStoredStatus();
        console.log(`Current delivery status for item ${itemId}:`, currentStatus);

        // Initialize on first run
        if (Object.keys(lastStatus).length === 0) {
            setStoredStatus(currentStatus);
            console.log(`Initial delivery status stored for item ${itemId}:`, currentStatus);
            isInitialized = true;
            setupAutoRefresh(currentStatus);
            return;
        }

        // On page reload, wait a bit before comparing to avoid false "none" notifications
        if (!isInitialized) {
            setStoredStatus(currentStatus);
            console.log(`Status reloaded for item ${itemId}:`, currentStatus);
            isInitialized = true;
            setupAutoRefresh(currentStatus);
            return;
        }

        // Check for changes in any status element
        const changes = [];
        Object.keys(currentStatus).forEach(key => {
            if (currentStatus[key] !== lastStatus[key]) {
                changes.push({
                    field: key,
                    from: lastStatus[key] || 'none',
                    to: currentStatus[key]
                });
            }
        });

        // Check for removed status elements
        Object.keys(lastStatus).forEach(key => {
            if (!currentStatus[key] && lastStatus[key]) {
                changes.push({
                    field: key,
                    from: lastStatus[key],
                    to: 'none'
                });
            }
        });

        if (changes.length > 0) {
            console.log(`Delivery status changes detected for item ${itemId}:`, changes);

            // Check for delivery completion (next stop -> none)
            const deliveryCompletionChange = changes.find(change =>
                change.field === 'outForDelivery' &&
                change.from &&
                change.from.toLowerCase().includes('next stop') &&
                change.to === 'none'
            );

            // Send notification for each change
            changes.forEach(change => {
                const fieldNames = {
                    outForDelivery: 'Out for Delivery',
                    promiseDate: 'Promise Date',
                    promiseDetails: 'Promise Details',
                    primaryStatus: 'Primary Status',
                    exceptionMessage: 'Exception Message',
                    mainStatus: 'Main Status',
                    secondaryStatus: 'Secondary Status'
                };

                const shortItemId = itemId.substring(0, 8) + '...';
                GM_notification({
                    title: `Amazon ${fieldNames[change.field]} Update`,
                    text: `[${shortItemId}] ${fieldNames[change.field]}: ${change.to}`,
                    image: 'https://www.amazon.de/favicon.ico',
                    timeout: 5000,
                    onclick: function() {
                        window.focus();
                    }
                });
            });

            // Store the new status
            setStoredStatus(currentStatus);

            // If delivery was completed (next stop -> none), refresh page after a short delay
            if (deliveryCompletionChange) {
                console.log(`Delivery completed for item ${itemId}, refreshing page in 5 seconds to update tracking info...`);
                setTimeout(() => {
                    window.location.reload();
                }, 5000);
            } else {
                // Update auto-refresh based on new status (only if not doing delivery completion refresh)
                setupAutoRefresh(currentStatus);
            }
        }
    }

    function setupAutoRefresh(currentStatus) {
        // Clear existing timer
        if (refreshTimer) {
            clearInterval(refreshTimer);
            refreshTimer = null;
        }

        // Check if currently out for delivery
        const isOutForDelivery = currentStatus.outForDelivery &&
                                currentStatus.outForDelivery.toLowerCase().includes('stop');

        if (!isOutForDelivery) {
            console.log(`Setting up auto-refresh every 10 minutes for item ${getItemId()}`);
            refreshTimer = setInterval(() => {
                console.log(`Auto-refreshing page for item ${getItemId()}`);
                window.location.reload();
            }, 10 * 60 * 1000); // 10 minutes
        } else {
            console.log(`Package is out for delivery, no auto-refresh needed for item ${getItemId()}`);
        }
    }

    function startMonitoring() {
        // Wait a bit for the page to fully load before initial check
        setTimeout(() => {
            checkDeliveryStatus();
        }, 2000);

        // Set up MutationObserver to watch for changes
        observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                // Check if the delivery status element was affected
                if (mutation.type === 'childList' || mutation.type === 'characterData') {
                    // Only check after initialization to avoid false notifications
                    if (isInitialized) {
                        checkDeliveryStatus();
                    }
                }
            });
        });

        // Start observing the document for changes
        observer.observe(document.body, {
            childList: true,
            subtree: true,
            characterData: true
        });

        console.log('Started monitoring delivery status changes');
    }

    function stopMonitoring() {
        if (observer) {
            observer.disconnect();
            observer = null;
            console.log('Stopped monitoring delivery status changes');
        }

        if (refreshTimer) {
            clearInterval(refreshTimer);
            refreshTimer = null;
            console.log('Stopped auto-refresh timer');
        }
    }

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

    // Clean up when leaving the page
    window.addEventListener('beforeunload', stopMonitoring);

    // Also check periodically in case MutationObserver misses something
    setInterval(checkDeliveryStatus, 10000); // Check every 10 seconds

})();