Padhaikarlothoda

Better PW Speed Controller

Jul 28th, 2025 (edited)
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 26.34 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name         PW Speed Controller - Fixed Menu & Sessions
  3. // @namespace    http://tampermonkey.net/
  4. // @version      4.6
  5. // @description  Fixed PW speed controller with session progress and working menu
  6. // @author       u/padhaikarlothoda
  7. // @match        *://www.pw.live/*
  8. // @match        *://*.pw.live/*
  9. // @grant        none
  10. // @run-at       document-end
  11. // ==/UserScript==
  12.  
  13. (function() {
  14.     'use strict';
  15.  
  16.     let currentSpeed = 2.5;
  17.     let isVisible = false;
  18.     let video = null;
  19.     let totalTimeSaved = 0;
  20.  
  21.     // Storage
  22.     function saveData() {
  23.         localStorage.setItem('pwSpeedController', JSON.stringify({
  24.             currentSpeed: currentSpeed,
  25.             totalTimeSaved: totalTimeSaved,
  26.             isVisible: isVisible
  27.         }));
  28.     }
  29.  
  30.     function loadData() {
  31.         const saved = localStorage.getItem('pwSpeedController');
  32.         if (saved) {
  33.             const data = JSON.parse(saved);
  34.             currentSpeed = data.currentSpeed || 2.5;
  35.             totalTimeSaved = data.totalTimeSaved || 0;
  36.             isVisible = data.isVisible || false;
  37.         }
  38.     }
  39.  
  40.     // Check if lecture is live
  41.     function isLiveLecture() {
  42.         const liveIndicators = [
  43.             '[class*="live" i]',
  44.             '[data-live="true"]',
  45.             'span:contains("LIVE")',
  46.             'div:contains("LIVE")',
  47.             '[class*="streaming" i]'
  48.         ];
  49.  
  50.         for (const selector of liveIndicators) {
  51.             try {
  52.                 if (document.querySelector(selector)) {
  53.                     return true;
  54.                 }
  55.             } catch (e) {
  56.                 // Skip invalid selectors
  57.             }
  58.         }
  59.  
  60.         return window.location.href.includes('live=true') ||
  61.                window.location.href.includes('type=live');
  62.     }
  63.  
  64.     // Calculate completion time
  65.     function calculateCompletionTime() {
  66.         if (isLiveLecture()) {
  67.             return "🔴 LIVE";
  68.         }
  69.  
  70.         if (!video || !video.duration || isNaN(video.duration)) {
  71.             return "Calculating...";
  72.         }
  73.  
  74.         const remainingTime = (video.duration - video.currentTime) / currentSpeed;
  75.         const completionTime = new Date(Date.now() + remainingTime * 1000);
  76.  
  77.         return completionTime.toLocaleTimeString('en-US', {
  78.             hour: 'numeric',
  79.             minute: '2-digit',
  80.             hour12: true
  81.         });
  82.     }
  83.  
  84.     // Calculate session progress
  85.     function getSessionProgress() {
  86.         if (isLiveLecture()) {
  87.             return { text: "🔴 LIVE", percentage: 0 };
  88.         }
  89.  
  90.         if (!video || !video.duration || isNaN(video.duration)) {
  91.             return { text: "0h 0m 0s (0%)", percentage: 0 };
  92.         }
  93.  
  94.         const currentTime = video.currentTime;
  95.         const duration = video.duration;
  96.         const percentage = Math.round((currentTime / duration) * 100);
  97.  
  98.         const hours = Math.floor(currentTime / 3600);
  99.         const minutes = Math.floor((currentTime % 3600) / 60);
  100.         const seconds = Math.floor(currentTime % 60);
  101.  
  102.         return {
  103.             text: `${hours}h ${minutes}m ${seconds}s (${percentage}%)`,
  104.             percentage: percentage
  105.         };
  106.     }
  107.  
  108.     // Find video
  109.     function findVideo() {
  110.         return document.querySelector('video');
  111.     }
  112.  
  113.     // Find video player container
  114.     function findVideoPlayerContainer() {
  115.         const video = findVideo();
  116.         if (!video) return null;
  117.  
  118.         const selectors = [
  119.             '.video-player',
  120.             '.plyr',
  121.             '.video-container',
  122.             '[class*="player"]',
  123.             '[class*="video"]'
  124.         ];
  125.  
  126.         for (const selector of selectors) {
  127.             const container = document.querySelector(selector);
  128.             if (container && container.contains(video)) {
  129.                 console.log('✅ Found video container:', selector);
  130.                 return container;
  131.             }
  132.         }
  133.  
  134.         return video.parentElement;
  135.     }
  136.  
  137.     // Find chat button
  138.     function findChatButton() {
  139.         const svgs = document.querySelectorAll('svg[width="40"][height="40"]');
  140.         for (const svg of svgs) {
  141.             const path = svg.querySelector('path[d*="M26.982 21.097"]');
  142.             if (path) {
  143.                 return svg.closest('button') || svg.closest('div[role="button"]') || svg.parentElement;
  144.             }
  145.         }
  146.  
  147.         const chatSvgs = document.querySelectorAll('svg path[d*="M34 10.376v14.979"]');
  148.         for (const path of chatSvgs) {
  149.             const svg = path.closest('svg');
  150.             if (svg) {
  151.                 return svg.closest('button') || svg.closest('div[role="button"]') || svg.parentElement;
  152.             }
  153.         }
  154.  
  155.         return null;
  156.     }
  157.  
  158.     // Create centered button
  159.     function createCenteredButton() {
  160.         const videoContainer = findVideoPlayerContainer();
  161.  
  162.         if (!videoContainer) {
  163.             console.log('Video container not found, creating floating button');
  164.             createFloatingButton();
  165.             return;
  166.         }
  167.  
  168.         const buttonContainer = document.createElement('div');
  169.         buttonContainer.id = 'pw-speed-btn-container';
  170.  
  171.         const speedBtn = document.createElement('button');
  172.         speedBtn.id = 'pw-speed-btn-centered';
  173.         speedBtn.innerHTML = `⚡ ${currentSpeed}x`;
  174.  
  175.         buttonContainer.appendChild(speedBtn);
  176.  
  177.         const style = document.createElement('style');
  178.         style.textContent = `
  179.             #pw-speed-btn-container {
  180.                 position: absolute !important;
  181.                 bottom: 10px !important;
  182.                 left: 50% !important;
  183.                 transform: translateX(-50%) !important;
  184.                 z-index: 999999 !important;
  185.                 pointer-events: none !important;
  186.             }
  187.  
  188.             #pw-speed-btn-centered {
  189.                 background: rgba(0, 0, 0, 0.8) !important;
  190.                 backdrop-filter: blur(10px) !important;
  191.                 border: 1px solid rgba(255, 255, 255, 0.3) !important;
  192.                 border-radius: 8px !important;
  193.                 color: #34c759 !important;
  194.                 padding: 6px 10px !important;
  195.                 font-size: 11px !important;
  196.                 font-weight: bold !important;
  197.                 cursor: pointer !important;
  198.                 transition: all 0.2s ease !important;
  199.                 min-width: 45px !important;
  200.                 pointer-events: auto !important;
  201.                 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif !important;
  202.             }
  203.  
  204.             #pw-speed-btn-centered:hover {
  205.                 background: rgba(0, 0, 0, 0.9) !important;
  206.                 transform: scale(1.05) !important;
  207.                 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4) !important;
  208.             }
  209.         `;
  210.  
  211.         document.head.appendChild(style);
  212.  
  213.         const containerStyle = window.getComputedStyle(videoContainer);
  214.         if (containerStyle.position === 'static') {
  215.             videoContainer.style.position = 'relative';
  216.         }
  217.  
  218.         videoContainer.appendChild(buttonContainer);
  219.         speedBtn.addEventListener('click', function() {
  220.             console.log('✅ Button clicked, toggling panel');
  221.             togglePanel();
  222.         });
  223.  
  224.         console.log('✅ Centered speed button created');
  225.     }
  226.  
  227.     // Fallback floating button
  228.     function createFloatingButton() {
  229.         const btn = document.createElement('div');
  230.         btn.id = 'pw-speed-floating';
  231.         btn.innerHTML = `<div class="pw-btn">⚡ ${currentSpeed}x</div>`;
  232.  
  233.         const style = document.createElement('style');
  234.         style.textContent = `
  235.             #pw-speed-floating {
  236.                 position: fixed !important;
  237.                 bottom: 60px !important;
  238.                 right: 20px !important;
  239.                 z-index: 999999 !important;
  240.                 font-family: Arial, sans-serif !important;
  241.             }
  242.  
  243.             .pw-btn {
  244.                 background: rgba(0, 0, 0, 0.8) !important;
  245.                 color: white !important;
  246.                 padding: 6px 10px !important;
  247.                 border-radius: 8px !important;
  248.                 cursor: pointer !important;
  249.                 font-size: 11px !important;
  250.                 font-weight: bold !important;
  251.                 border: 1px solid rgba(255, 255, 255, 0.3) !important;
  252.                 transition: all 0.2s !important;
  253.             }
  254.  
  255.             .pw-btn:hover {
  256.                 background: rgba(0, 0, 0, 0.9) !important;
  257.                 transform: scale(1.05) !important;
  258.             }
  259.         `;
  260.  
  261.         document.head.appendChild(style);
  262.         document.body.appendChild(btn);
  263.         btn.addEventListener('click', function() {
  264.             console.log('✅ Floating button clicked, toggling panel');
  265.             togglePanel();
  266.         });
  267.  
  268.         console.log('✅ Floating button created');
  269.     }
  270.  
  271.     // Get button position for panel placement
  272.     function getButtonPosition() {
  273.         const centeredBtn = document.getElementById('pw-speed-btn-centered');
  274.         const floatingBtn = document.getElementById('pw-speed-floating');
  275.  
  276.         const button = centeredBtn || floatingBtn;
  277.         if (!button) {
  278.             console.log('❌ No button found for positioning');
  279.             return { top: '50px', left: '50%' };
  280.         }
  281.  
  282.         const rect = button.getBoundingClientRect();
  283.         const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  284.  
  285.         const position = {
  286.             top: Math.max(10, rect.top + scrollTop - 240) + 'px', // 240px above button, min 10px from top
  287.             left: (rect.left + rect.width / 2) + 'px'
  288.         };
  289.  
  290.         console.log('✅ Button position calculated:', position);
  291.         return position;
  292.     }
  293.  
  294.     // Create panel with session progress
  295.     function createPanel() {
  296.         // Remove existing panel if any
  297.         const existingPanel = document.getElementById('pw-speed-panel');
  298.         if (existingPanel) {
  299.             existingPanel.remove();
  300.         }
  301.  
  302.         const panel = document.createElement('div');
  303.         panel.id = 'pw-speed-panel';
  304.         panel.style.display = 'none'; // Start hidden
  305.  
  306.         const completion = calculateCompletionTime();
  307.         const sessionProgress = getSessionProgress();
  308.  
  309.         panel.innerHTML = `
  310.             <div class="panel">
  311.                 <div class="panel-header">
  312.                     <div class="lecture-status">
  313.                         <span class="status-label">🎯 Done by:</span>
  314.                         <span class="completion-time" id="completion-time">${completion}</span>
  315.                     </div>
  316.                     <button class="close" id="close-panel">×</button>
  317.                 </div>
  318.  
  319.                 <div class="session-section">
  320.                     <div class="session-label">📊 Session Progress:</div>
  321.                     <div class="session-progress" id="session-progress">${sessionProgress.text}</div>
  322.                     <div class="progress-bar">
  323.                         <div class="progress-fill" id="progress-fill" style="width: ${sessionProgress.percentage}%"></div>
  324.                     </div>
  325.                 </div>
  326.  
  327.                 <div class="speeds-compact">
  328.                     <button class="speed-btn-small" data-speed="1">1x</button>
  329.                     <button class="speed-btn-small" data-speed="1.25">1.25x</button>
  330.                     <button class="speed-btn-small" data-speed="1.5">1.5x</button>
  331.                     <button class="speed-btn-small" data-speed="1.75">1.75x</button>
  332.                     <button class="speed-btn-small" data-speed="2">2x</button>
  333.                     <button class="speed-btn-small active" data-speed="2.5">2.5x</button>
  334.                     <button class="speed-btn-small" data-speed="3">3x</button>
  335.                 </div>
  336.  
  337.                 <div class="shortcuts-compact">
  338.                     <div class="shortcut-item">💬 <kbd>Alt + C</kbd></div>
  339.                     <div class="shortcut-item"><kbd>Shift + Z</kbd></div>
  340.                 </div>
  341.  
  342.                 <div class="stats-compact">
  343.                     <div>⏰ Saved: <span id="time-saved">0h 0m 0s</span></div>
  344.                 </div>
  345.             </div>
  346.         `;
  347.  
  348.         const panelStyle = document.createElement('style');
  349.         panelStyle.textContent = `
  350.             #pw-speed-panel {
  351.                 position: fixed !important;
  352.                 z-index: 999998 !important;
  353.                 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif !important;
  354.                 pointer-events: auto !important;
  355.             }
  356.  
  357.             .panel {
  358.                 background: rgba(28, 28, 30, 0.95) !important;
  359.                 backdrop-filter: blur(20px) !important;
  360.                 border-radius: 10px !important;
  361.                 padding: 12px !important;
  362.                 width: 240px !important;
  363.                 color: white !important;
  364.                 border: 1px solid rgba(255, 255, 255, 0.1) !important;
  365.                 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
  366.                 animation: slideInUp 0.3s ease-out !important;
  367.                 font-size: 11px !important;
  368.             }
  369.  
  370.             @keyframes slideInUp {
  371.                 from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  372.                 to { opacity: 1; transform: translateX(-50%) translateY(0); }
  373.             }
  374.  
  375.             .panel-header {
  376.                 display: flex !important;
  377.                 justify-content: space-between !important;
  378.                 align-items: center !important;
  379.                 margin-bottom: 10px !important;
  380.                 padding-bottom: 6px !important;
  381.                 border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
  382.             }
  383.  
  384.             .lecture-status {
  385.                 display: flex !important;
  386.                 flex-direction: column !important;
  387.                 gap: 2px !important;
  388.             }
  389.  
  390.             .status-label {
  391.                 font-size: 10px !important;
  392.                 color: rgba(255, 255, 255, 0.7) !important;
  393.             }
  394.  
  395.             .completion-time {
  396.                 font-size: 12px !important;
  397.                 font-weight: 600 !important;
  398.                 color: #34c759 !important;
  399.             }
  400.  
  401.             .close {
  402.                 background: none !important;
  403.                 border: none !important;
  404.                 color: rgba(255, 255, 255, 0.6) !important;
  405.                 font-size: 16px !important;
  406.                 cursor: pointer !important;
  407.                 padding: 0 !important;
  408.                 width: 16px !important;
  409.                 height: 16px !important;
  410.                 border-radius: 50% !important;
  411.                 transition: all 0.2s !important;
  412.             }
  413.  
  414.             .close:hover {
  415.                 background: rgba(255, 255, 255, 0.1) !important;
  416.                 color: white !important;
  417.             }
  418.  
  419.             .session-section {
  420.                 margin-bottom: 10px !important;
  421.                 padding-bottom: 8px !important;
  422.                 border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
  423.             }
  424.  
  425.             .session-label {
  426.                 font-size: 10px !important;
  427.                 color: rgba(255, 255, 255, 0.7) !important;
  428.                 margin-bottom: 4px !important;
  429.             }
  430.  
  431.             .session-progress {
  432.                 font-size: 11px !important;
  433.                 font-weight: 600 !important;
  434.                 color: #34c759 !important;
  435.                 margin-bottom: 6px !important;
  436.             }
  437.  
  438.             .progress-bar {
  439.                 width: 100% !important;
  440.                 height: 4px !important;
  441.                 background: rgba(255, 255, 255, 0.2) !important;
  442.                 border-radius: 2px !important;
  443.                 overflow: hidden !important;
  444.             }
  445.  
  446.             .progress-fill {
  447.                 height: 100% !important;
  448.                 background: linear-gradient(90deg, #34c759, #30d158) !important;
  449.                 border-radius: 2px !important;
  450.                 transition: width 0.3s ease !important;
  451.             }
  452.  
  453.             .speeds-compact {
  454.                 display: grid !important;
  455.                 grid-template-columns: repeat(4, 1fr) !important;
  456.                 gap: 4px !important;
  457.                 margin-bottom: 10px !important;
  458.             }
  459.  
  460.             .speed-btn-small {
  461.                 background: rgba(58, 58, 60, 0.8) !important;
  462.                 border: none !important;
  463.                 border-radius: 4px !important;
  464.                 color: white !important;
  465.                 padding: 4px !important;
  466.                 font-size: 9px !important;
  467.                 cursor: pointer !important;
  468.                 transition: all 0.2s !important;
  469.                 font-weight: 500 !important;
  470.                 min-height: 22px !important;
  471.             }
  472.  
  473.             .speed-btn-small:hover {
  474.                 background: rgba(78, 78, 80, 0.8) !important;
  475.                 transform: translateY(-1px) !important;
  476.             }
  477.  
  478.             .speed-btn-small.active {
  479.                 background: #007aff !important;
  480.                 box-shadow: 0 0 0 1px rgba(0, 122, 255, 0.3) !important;
  481.             }
  482.  
  483.             .shortcuts-compact {
  484.                 display: flex !important;
  485.                 justify-content: space-between !important;
  486.                 background: rgba(44, 44, 46, 0.6) !important;
  487.                 border-radius: 6px !important;
  488.                 padding: 6px !important;
  489.                 margin-bottom: 8px !important;
  490.             }
  491.  
  492.             .shortcut-item {
  493.                 font-size: 9px !important;
  494.                 display: flex !important;
  495.                 align-items: center !important;
  496.                 gap: 3px !important;
  497.             }
  498.  
  499.             kbd {
  500.                 background: rgba(58, 58, 60, 0.8) !important;
  501.                 border: 1px solid rgba(255, 255, 255, 0.2) !important;
  502.                 border-radius: 2px !important;
  503.                 padding: 1px 4px !important;
  504.                 font-size: 8px !important;
  505.                 color: #34c759 !important;
  506.                 font-family: monospace !important;
  507.             }
  508.  
  509.             .stats-compact {
  510.                 font-size: 10px !important;
  511.                 color: rgba(255, 255, 255, 0.8) !important;
  512.                 text-align: center !important;
  513.                 padding-top: 6px !important;
  514.                 border-top: 1px solid rgba(255, 255, 255, 0.1) !important;
  515.             }
  516.  
  517.             #time-saved {
  518.                 color: #34c759 !important;
  519.                 font-weight: 600 !important;
  520.             }
  521.         `;
  522.  
  523.         document.head.appendChild(panelStyle);
  524.         document.body.appendChild(panel);
  525.  
  526.         // Setup event listeners
  527.         setupPanelEventListeners();
  528.  
  529.         console.log('✅ Panel created with session progress');
  530.     }
  531.  
  532.     // Setup event listeners for panel
  533.     function setupPanelEventListeners() {
  534.         // Close button
  535.         const closeBtn = document.getElementById('close-panel');
  536.         if (closeBtn) {
  537.             closeBtn.addEventListener('click', function() {
  538.                 console.log('✅ Close button clicked');
  539.                 togglePanel();
  540.             });
  541.         }
  542.  
  543.         // Speed buttons
  544.         document.querySelectorAll('.speed-btn-small').forEach(btn => {
  545.             btn.addEventListener('click', function() {
  546.                 const speed = parseFloat(this.dataset.speed);
  547.                 console.log('✅ Speed button clicked:', speed);
  548.                 setSpeed(speed);
  549.             });
  550.         });
  551.     }
  552.  
  553.     // Toggle panel function
  554.     window.togglePanel = function() {
  555.         console.log('🔄 Toggle panel called, current visible state:', isVisible);
  556.  
  557.         isVisible = !isVisible;
  558.         const panel = document.getElementById('pw-speed-panel');
  559.  
  560.         if (panel) {
  561.             if (isVisible) {
  562.                 // Update position before showing
  563.                 const position = getButtonPosition();
  564.                 panel.style.top = position.top;
  565.                 panel.style.left = position.left;
  566.                 panel.style.transform = 'translateX(-50%)';
  567.                 panel.style.display = 'block';
  568.                 console.log('✅ Panel shown at position:', position);
  569.             } else {
  570.                 panel.style.display = 'none';
  571.                 console.log('✅ Panel hidden');
  572.             }
  573.             saveData();
  574.         } else {
  575.             console.log('❌ Panel not found');
  576.         }
  577.     };
  578.  
  579.     // Set speed function
  580.     window.setSpeed = function(speed) {
  581.         video = findVideo();
  582.         if (video) {
  583.             video.playbackRate = speed;
  584.             currentSpeed = speed;
  585.  
  586.             // Update buttons
  587.             document.querySelectorAll('.speed-btn-small').forEach(btn => {
  588.                 btn.classList.remove('active');
  589.                 if (parseFloat(btn.dataset.speed) === speed) {
  590.                     btn.classList.add('active');
  591.                 }
  592.             });
  593.  
  594.             // Update speed button text
  595.             const centeredBtn = document.getElementById('pw-speed-btn-centered');
  596.             const floatingBtn = document.querySelector('.pw-btn');
  597.  
  598.             if (centeredBtn) {
  599.                 centeredBtn.textContent = `⚡ ${speed}x`;
  600.             }
  601.             if (floatingBtn) {
  602.                 floatingBtn.textContent = `⚡ ${speed}x`;
  603.             }
  604.  
  605.             // Preserve pitch
  606.             video.preservesPitch = true;
  607.             video.mozPreservesPitch = true;
  608.             video.webkitPreservesPitch = true;
  609.  
  610.             saveData();
  611.             console.log('✅ Speed set to:', speed);
  612.         }
  613.     };
  614.  
  615.     // Setup shortcuts
  616.     function setupShortcuts() {
  617.         document.addEventListener('keydown', (e) => {
  618.             // Alt + C for chat
  619.             if (e.altKey && e.key.toLowerCase() === 'c') {
  620.                 e.preventDefault();
  621.                 e.stopPropagation();
  622.  
  623.                 const chatBtn = findChatButton();
  624.                 if (chatBtn) {
  625.                     const clickEvent = new MouseEvent('click', {
  626.                         view: window,
  627.                         bubbles: true,
  628.                         cancelable: true
  629.                     });
  630.  
  631.                     chatBtn.click();
  632.                     chatBtn.dispatchEvent(clickEvent);
  633.  
  634.                     const svg = chatBtn.querySelector('svg[width="40"][height="40"]');
  635.                     if (svg) {
  636.                         svg.click();
  637.                         svg.dispatchEvent(clickEvent);
  638.                     }
  639.  
  640.                     console.log('✅ Chat opened via Alt+C');
  641.                 }
  642.             }
  643.  
  644.             // Shift + Z for speed panel toggle
  645.             if (e.shiftKey && e.key.toLowerCase() === 'z') {
  646.                 e.preventDefault();
  647.                 e.stopPropagation();
  648.                 console.log('✅ Shift+Z pressed, toggling panel');
  649.                 togglePanel();
  650.             }
  651.         });
  652.  
  653.         console.log('✅ Shortcuts setup complete');
  654.     }
  655.  
  656.     // Time tracking with session progress updates
  657.     function startTracking() {
  658.         setInterval(() => {
  659.             video = findVideo();
  660.  
  661.             // Update time saved
  662.             if (video && currentSpeed > 1 && !video.paused) {
  663.                 const timeSavedPerSecond = (currentSpeed - 1) / currentSpeed;
  664.                 totalTimeSaved += timeSavedPerSecond;
  665.  
  666.                 const timeSavedEl = document.getElementById('time-saved');
  667.                 if (timeSavedEl) {
  668.                     const hours = Math.floor(totalTimeSaved / 3600);
  669.                     const minutes = Math.floor((totalTimeSaved % 3600) / 60);
  670.                     const seconds = Math.floor(totalTimeSaved % 60);
  671.                     timeSavedEl.textContent = `${hours}h ${minutes}m ${seconds}s`;
  672.                 }
  673.  
  674.                 saveData();
  675.             }
  676.  
  677.             // Update completion time
  678.             const completionEl = document.getElementById('completion-time');
  679.             if (completionEl) {
  680.                 const newTime = calculateCompletionTime();
  681.                 completionEl.textContent = newTime;
  682.  
  683.                 if (newTime.includes('LIVE')) {
  684.                     completionEl.style.color = '#ff3b30';
  685.                 } else {
  686.                     completionEl.style.color = '#34c759';
  687.                 }
  688.             }
  689.  
  690.             // Update session progress
  691.             const sessionProgressEl = document.getElementById('session-progress');
  692.             const progressFillEl = document.getElementById('progress-fill');
  693.  
  694.             if (sessionProgressEl && progressFillEl) {
  695.                 const sessionData = getSessionProgress();
  696.                 sessionProgressEl.textContent = sessionData.text;
  697.                 progressFillEl.style.width = sessionData.percentage + '%';
  698.  
  699.                 if (sessionData.text.includes('LIVE')) {
  700.                     sessionProgressEl.style.color = '#ff3b30';
  701.                 } else {
  702.                     sessionProgressEl.style.color = '#34c759';
  703.                 }
  704.             }
  705.  
  706.         }, 1000);
  707.  
  708.         console.log('✅ Tracking started');
  709.     }
  710.  
  711.     // Initialize
  712.     function init() {
  713.         console.log('🚀 Initializing PW Speed Controller...');
  714.  
  715.         loadData();
  716.         setupShortcuts();
  717.  
  718.         let attempts = 0;
  719.         const check = setInterval(() => {
  720.             attempts++;
  721.             video = findVideo();
  722.  
  723.             if (video) {
  724.                 clearInterval(check);
  725.                 console.log('✅ Video found, setting up controller');
  726.  
  727.                 // Create button with delay
  728.                 setTimeout(() => {
  729.                     createCenteredButton();
  730.                 }, 2000);
  731.  
  732.                 // Create panel with delay
  733.                 setTimeout(() => {
  734.                     createPanel();
  735.                     setSpeed(currentSpeed);
  736.                 }, 2500);
  737.  
  738.                 startTracking();
  739.  
  740.                 console.log('🎉 PW Speed Controller ready!');
  741.                 console.log('🔥 Shortcuts: Alt+C (Chat), Shift+Z (Speed Panel)');
  742.  
  743.             } else if (attempts >= 20) {
  744.                 clearInterval(check);
  745.                 console.log('❌ Video not found after 20 attempts');
  746.             } else {
  747.                 console.log(`🔍 Looking for video... attempt ${attempts}/20`);
  748.             }
  749.         }, 1000);
  750.     }
  751.  
  752.     // Start initialization
  753.     setTimeout(init, 2000);
  754.  
  755. })();
  756.  
Tags: Pw
Advertisement
Add Comment
Please, Sign In to add comment