T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/soundstudiopro.com/public_html/js/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/public_html/js/track_monitor.js
// Track Status Monitor - Automatic Polling System
// This script automatically checks for track status updates every 30 seconds

class TrackMonitor {
    constructor() {
        this.monitorKey = 'soundstudiopro_monitor_2025';
        this.pollingInterval = 60000; // 60 seconds (reduced from 30)
        this.isPolling = false;
        this.pollingTimer = null;
        this.lastCheck = null;
        this.onStatusUpdate = null; // Callback function
        this.notifiedTrackIds = new Set(); // Track IDs that have already been notified
        this.currentUserId = null; // Will be set from session or page data
        this.storageKey = 'trackMonitor_notifiedIds'; // localStorage key
        
        // Load persisted notified track IDs from localStorage
        this.loadNotifiedTrackIds();
    }
    
    // Load notified track IDs from localStorage
    loadNotifiedTrackIds() {
        try {
            const stored = localStorage.getItem(this.storageKey);
            if (stored) {
                const ids = JSON.parse(stored);
                this.notifiedTrackIds = new Set(ids);
                console.log(`đŸŽĩ Loaded ${this.notifiedTrackIds.size} previously notified track IDs from storage`);
            }
        } catch (e) {
            console.warn('đŸŽĩ Could not load notified track IDs from storage:', e);
            this.notifiedTrackIds = new Set();
        }
    }
    
    // Save notified track IDs to localStorage
    saveNotifiedTrackIds() {
        try {
            const ids = Array.from(this.notifiedTrackIds);
            localStorage.setItem(this.storageKey, JSON.stringify(ids));
        } catch (e) {
            console.warn('đŸŽĩ Could not save notified track IDs to storage:', e);
        }
    }
    
    // Clean up notified track IDs for tracks that are no longer in the monitor response
    // This is called after processing results to remove IDs for tracks that were deleted
    cleanupNotifiedTrackIds(data) {
        if (this.notifiedTrackIds.size === 0) return;
        
        try {
            // Get all track IDs from current response (all statuses)
            const currentTrackIds = new Set();
            if (data.fixed_tracks) {
                data.fixed_tracks.forEach(track => currentTrackIds.add(String(track.track_id)));
            }
            if (data.failed_tracks) {
                data.failed_tracks.forEach(track => currentTrackIds.add(String(track.track_id)));
            }
            if (data.still_processing) {
                data.still_processing.forEach(track => currentTrackIds.add(String(track.track_id)));
            }
            
            // Remove notified IDs for tracks that aren't in the current response
            // (they were likely deleted)
            const toRemove = [];
            this.notifiedTrackIds.forEach(id => {
                const trackId = id.replace(/^(failed_|fixed_)/, '');
                // Only remove if track is not in current response AND it's been more than 5 minutes
                // (to avoid removing IDs for tracks that are just temporarily not showing)
                if (!currentTrackIds.has(trackId)) {
                    toRemove.push(id);
                }
            });
            
            // Only remove a few at a time to be safe (tracks might be temporarily not in response)
            const removed = toRemove.slice(0, 10); // Remove max 10 at a time
            removed.forEach(id => this.notifiedTrackIds.delete(id));
            
            if (removed.length > 0) {
                console.log(`đŸŽĩ Cleaned up ${removed.length} notified track IDs for tracks no longer in monitor`);
                this.saveNotifiedTrackIds();
            }
        } catch (e) {
            console.warn('đŸŽĩ Could not cleanup notified track IDs:', e);
        }
    }

    // Start automatic polling
    start() {
        if (this.isPolling) {
            console.log('đŸŽĩ Track monitor already running');
            return;
        }

        console.log('đŸŽĩ Starting track status monitor...');
        this.isPolling = true;
        this.poll();
    }

    // Stop automatic polling
    stop() {
        if (this.pollingTimer) {
            clearTimeout(this.pollingTimer);
            this.pollingTimer = null;
        }
        this.isPolling = false;
        console.log('đŸŽĩ Track monitor stopped');
    }

    // Perform a single check
    async poll() {
        if (!this.isPolling) return;

        try {
            console.log('đŸŽĩ Checking for track status updates...');
            
            const response = await fetch(`/api/monitor.php?key=${this.monitorKey}`, {
                credentials: 'same-origin' // Include cookies/session
            });
            const data = await response.json();

            if (data.error) {
                console.error('đŸŽĩ Monitor error:', data.error);
                return;
            }

            this.lastCheck = new Date();
            
            // Process results
            this.processResults(data);

            // Schedule next poll
            this.pollingTimer = setTimeout(() => this.poll(), this.pollingInterval);

        } catch (error) {
            console.error('đŸŽĩ Monitor polling error:', error);
            // Retry in 60 seconds on error
            this.pollingTimer = setTimeout(() => this.poll(), 60000);
        }
    }

    // Process monitor results
    processResults(data) {
        const { fixed_tracks, failed_tracks, still_processing } = data;

        // Get current user ID from page if available
        if (!this.currentUserId) {
            const userIdElement = document.querySelector('[data-user-id]');
            if (userIdElement) {
                this.currentUserId = parseInt(userIdElement.getAttribute('data-user-id'));
            }
        }

        // Filter tracks to only show notifications for current user's tracks
        const userFixedTracks = fixed_tracks.filter(track => {
            // If user_id is provided, filter by it; otherwise show all (for backward compatibility)
            return !this.currentUserId || !track.user_id || track.user_id === this.currentUserId;
        });

        const userFailedTracks = failed_tracks.filter(track => {
            // If user_id is provided, filter by it; otherwise show all (for backward compatibility)
            return !this.currentUserId || !track.user_id || track.user_id === this.currentUserId;
        });

        // Filter out tracks that have already been notified
        const newFixedTracks = userFixedTracks.filter(track => {
            const key = `fixed_${track.track_id}`;
            if (this.notifiedTrackIds.has(key)) {
                return false; // Already notified
            }
            this.notifiedTrackIds.add(key);
            this.saveNotifiedTrackIds(); // Persist to localStorage
            return true;
        });

        const newFailedTracks = userFailedTracks.filter(track => {
            const key = `failed_${track.track_id}`;
            if (this.notifiedTrackIds.has(key)) {
                return false; // Already notified
            }
            this.notifiedTrackIds.add(key);
            this.saveNotifiedTrackIds(); // Persist to localStorage
            return true;
        });

        // Show notifications for new fixed tracks
        if (newFixedTracks.length > 0) {
            console.log(`đŸŽĩ ${newFixedTracks.length} track(s) completed!`);
            this.showNotification(`${newFixedTracks.length} track(s) are ready to play!`, 'success');
            
            // Trigger page refresh if we're on a relevant page
            if (this.shouldRefreshPage()) {
                setTimeout(() => {
                    window.location.reload();
                }, 2000);
            }
        }

        // Show notifications for new failed tracks
        if (newFailedTracks.length > 0) {
            console.log(`đŸŽĩ ${newFailedTracks.length} track(s) failed`);
            this.showNotification(`${newFailedTracks.length} track(s) failed to process`, 'error');
        }

        // Call callback if provided
        if (this.onStatusUpdate && typeof this.onStatusUpdate === 'function') {
            this.onStatusUpdate(data);
        }

        // Update UI if we're on a page with tracks
        this.updateTrackStatusUI(data);
        
        // Cleanup notified track IDs for deleted tracks (after a delay to avoid race conditions)
        setTimeout(() => {
            this.cleanupNotifiedTrackIds(data);
        }, 10000); // Wait 10 seconds after processing
    }

    // Show notification to user
    showNotification(message, type = 'info') {
        // Create notification element
        const notification = document.createElement('div');
        notification.className = `track-notification track-notification-${type}`;
        notification.innerHTML = `
            <div class="notification-content">
                <span class="notification-icon">${type === 'success' ? '✅' : type === 'error' ? '❌' : 'â„šī¸'}</span>
                <span class="notification-message">${message}</span>
                <button class="notification-close" onclick="this.parentElement.parentElement.remove()">×</button>
            </div>
        `;

        // Add styles
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: ${type === 'success' ? '#48bb78' : type === 'error' ? '#f56565' : '#4299e1'};
            color: white;
            padding: 15px 20px;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            z-index: 10000;
            max-width: 400px;
            animation: slideIn 0.3s ease-out;
        `;

        // Add to page
        document.body.appendChild(notification);

        // Auto-remove after 5 seconds
        setTimeout(() => {
            if (notification.parentElement) {
                notification.remove();
            }
        }, 5000);
    }

    // Check if we should refresh the current page
    shouldRefreshPage() {
        const currentPage = window.location.pathname;
        const relevantPages = ['/library_new.php', '/feed.php', '/dashboard.php', '/'];
        return relevantPages.some(page => currentPage.includes(page));
    }

    // Update track status in UI
    updateTrackStatusUI(data) {
        const { fixed_tracks, failed_tracks } = data;
        
        // Update processing tracks display
        const processingElements = document.querySelectorAll('.track-status-processing');
        processingElements.forEach(element => {
            const trackId = element.getAttribute('data-track-id');
            
            // Check if this track was fixed
            const fixedTrack = fixed_tracks.find(track => track.track_id == trackId);
            if (fixedTrack) {
                element.innerHTML = '<span class="status-complete">✅ Complete</span>';
                element.className = 'track-status-complete';
                
                // Update play button if it exists
                const playButton = element.closest('.track-card').querySelector('.play-button');
                if (playButton) {
                    playButton.disabled = false;
                    playButton.innerHTML = '<i class="fas fa-play"></i> Play';
                }
            }
            
            // Check if this track failed
            const failedTrack = failed_tracks.find(track => track.track_id == trackId);
            if (failedTrack) {
                element.innerHTML = '<span class="status-failed">❌ Failed</span>';
                element.className = 'track-status-failed';
            }
        });
    }

    // Manual check (can be called from UI)
    async manualCheck() {
        console.log('đŸŽĩ Manual track status check...');
        await this.poll();
    }

    // Set callback for status updates
    setStatusUpdateCallback(callback) {
        this.onStatusUpdate = callback;
    }
}

// Global instance
window.trackMonitor = new TrackMonitor();

// Auto-start on pages that show tracks
document.addEventListener('DOMContentLoaded', function() {
    const currentPage = window.location.pathname;
    const trackPages = ['/library_new.php', '/feed.php', '/dashboard.php', '/', '/library.php'];
    
    if (trackPages.some(page => currentPage.includes(page))) {
        console.log('đŸŽĩ Auto-starting track monitor on track page');
        window.trackMonitor.start();
    }
});

// Add CSS for notifications
const style = document.createElement('style');
style.textContent = `
    @keyframes slideIn {
        from { transform: translateX(100%); opacity: 0; }
        to { transform: translateX(0); opacity: 1; }
    }
    
    .track-notification .notification-content {
        display: flex;
        align-items: center;
        gap: 10px;
    }
    
    .track-notification .notification-close {
        background: none;
        border: none;
        color: white;
        font-size: 18px;
        cursor: pointer;
        margin-left: auto;
    }
    
    .track-status-processing {
        color: #ed8936;
        font-weight: 600;
    }
    
    .track-status-complete {
        color: #48bb78;
        font-weight: 600;
    }
    
    .track-status-failed {
        color: #f56565;
        font-weight: 600;
    }
`;
document.head.appendChild(style); 

CasperSecurity Mini