base on this edge & chrome extension code ,manifest.json "{
  "manifest_version": 3,
  "name": "Auto Close and Auto Pause Media",
  "version": "4.3",
  "description": "Stops Autoplay, Closes Tabs After Media Ends, One-Click Stop All Media, Plays One Media at a Time",
  "permissions": [
    "tabs",
    "scripting",
    "webNavigation"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "content_scripts": [
    {
      "matches": [
        "<all_urls>"
      ],
      "js": ["content.js"],
      "run_at": "document_idle",
      "all_frames": true
    }
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_icon": {
      "16": "icon.png",
      "48": "icon.png",
      "128": "icon.png"
    },
    "default_title": "Auto Close and Auto Pause Media"
  },
  "icons": {
    "16": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  }
}" , background.js "let currentlyPlayingTabId = null;
const closeTimers = {};
const closeDuration = 10000; // 10 seconds
const videoTabs = new Set();

// Listener for the extension icon click to pause all media
chrome.action.onClicked.addListener(() => {
  videoTabs.forEach((tabId) => {
    chrome.tabs.sendMessage(tabId, { action: 'pauseAllMedia' });
  });
});

// Updates the red progress bar and closes the tab when complete
const updateRedBarProgress = (tabId) => {
  const timerData = closeTimers[tabId];
  if (!timerData) return;

  const { closeStartTime } = timerData;
  const elapsedTime = Date.now() - closeStartTime;
  const progress = Math.min((elapsedTime / closeDuration) * 100, 100);

  chrome.tabs.sendMessage(tabId, { action: 'updateRedBarProgress', progress: progress });

  if (progress < 100) {
    timerData.closeTimerId = setTimeout(() => updateRedBarProgress(tabId), 100); // Update every 100ms
  } else {
    clearTimeout(timerData.closeTimerId);
    chrome.tabs.remove(tabId, () => {
      if (chrome.runtime.lastError) {
        console.error(`Error closing tab: ${chrome.runtime.lastError.message}`);
      }
    });
    delete closeTimers[tabId];
    videoTabs.delete(tabId);
  }
};

// Message handler from content scripts
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  const tabId = sender.tab.id;
  switch (request.action) {
    case 'mediaStartedPlaying':
      videoTabs.add(tabId);

      if (currentlyPlayingTabId && currentlyPlayingTabId !== tabId) {
        chrome.tabs.sendMessage(currentlyPlayingTabId, { action: 'pauseAllMedia' });
      }
      currentlyPlayingTabId = tabId;
      break;
    case 'mediaStoppedPlaying':
      videoTabs.delete(tabId);
      if (tabId === currentlyPlayingTabId) {
        currentlyPlayingTabId = null;
      }
      break;
    case 'startCloseTimer':
      if (closeTimers[tabId]) {
        clearTimeout(closeTimers[tabId].closeTimerId);
      }
      closeTimers[tabId] = {
        closeStartTime: Date.now(),
        closeTimerId: null,
      };
      updateRedBarProgress(tabId);
      break;
    case 'cancelCloseTimer':
      if (closeTimers[tabId]) {
        clearTimeout(closeTimers[tabId].closeTimerId);
        delete closeTimers[tabId];
      }
      break;
  }
  sendResponse({ status: 'Message received' });
  return true;
});

// Listen for webNavigation events to inject content script into dynamically added iframes
chrome.webNavigation.onCompleted.addListener(async (details) => {
  if (details.frameId !== 0) {
    // It's an iframe
    try {
      await chrome.scripting.executeScript({
        target: { tabId: details.tabId, frameIds: [details.frameId] },
        files: ['content.js'],
      });
    } catch (e) {
      // Ignore injection failures for cross-origin iframes
    }
  }
}, {
  url: [{ schemes: ['http', 'https'] }]
});" , content.js "let currentlyPlaying = null;
let lastUserInteractionTime = 0;
let mediaElements = new WeakSet();
let lastTitle = document.title;
const mediaEventHandlers = new WeakMap();

/**
 * Clears the red progress bar and cancels the close timer.
 */
const clearRedBarAndTimer = () => {
  const redBar = document.getElementById('extension-red-bar');
  if (redBar) {
    redBar.remove();
  }
  if (chrome.runtime && chrome.runtime.sendMessage) {
    chrome.runtime.sendMessage({ action: 'cancelCloseTimer' });
  }
};

/**
 * Shows the red progress bar at the top of the page.
 */
const showRedBar = () => {
  clearRedBarAndTimer();
  const redBar = document.createElement('div');
  redBar.id = 'extension-red-bar';
  redBar.style.cssText = `
    position: fixed;
    top: 0;
    left: 0;
    width: 0%;
    height: 5px;
    background: red;
    z-index: 9999;
    transition: width 0.1s linear;
  `;
  document.body.appendChild(redBar);

  if (chrome.runtime && chrome.runtime.sendMessage) {
    chrome.runtime.sendMessage({ action: 'startCloseTimer' });
  }
};

/**
 * Updates the width of the red progress bar based on the provided progress percentage.
 * @param {number} progress - The progress percentage (0 to 100).
 */
const updateRedBarProgress = (progress) => {
  const redBar = document.getElementById('extension-red-bar');
  if (redBar) {
    redBar.style.width = `${progress}%`;
  }
};

/**
 * Pauses all media elements that are tracked by the extension.
 */
const pauseAllMedia = () => {
  document.querySelectorAll('video, audio').forEach((media) => {
    if (mediaElements.has(media)) {
      media.pause();
    }
  });
  currentlyPlaying = null;
  clearRedBarAndTimer();
  if (chrome.runtime && chrome.runtime.sendMessage) {
    chrome.runtime.sendMessage({ action: 'mediaStoppedPlaying' });
  }
};

/**
 * Handles the end of media playback by showing the red progress bar.
 */
const handleMediaEnd = () => {
  showRedBar();
};

/**
 * Checks if a media element is significant based on its size relative to the viewport.
 * @param {HTMLMediaElement} media - The media element to evaluate.
 * @returns {boolean} - True if the media is significant; otherwise, false.
 */
const isSignificantMedia = (media) => {
  if (media instanceof HTMLAudioElement) {
    // Treat audio elements as significant
    return true;
  }
  const rect = media.getBoundingClientRect();
  const area = rect.width * rect.height;
  const viewportArea = window.innerWidth * window.innerHeight;
  const areaRatio = area / viewportArea;
  return areaRatio > 0.1; // Adjust threshold as needed
};

/**
 * Handles the play event of a media element.
 * @param {HTMLMediaElement} media - The media element that started playing.
 */
const handleMediaPlay = (media) => {
  clearRedBarAndTimer();
  const currentTime = Date.now();
  const timeSinceLastInteraction = currentTime - lastUserInteractionTime;

  if (timeSinceLastInteraction > 2000) {
    setTimeout(() => {
      if (!media.paused) {
        media.pause();
      }
    }, 100);
  } else {
    if (isSignificantMedia(media)) {
      pauseOtherMedia(media);
      if (chrome.runtime && chrome.runtime.sendMessage) {
        chrome.runtime.sendMessage({ action: 'mediaStartedPlaying' });
      }
    }
  }
};

/**
 * Pauses all other media except the newly started one.
 * @param {HTMLMediaElement} newMedia - The media element that should keep playing.
 */
const pauseOtherMedia = (newMedia) => {
  document.querySelectorAll('video, audio').forEach((media) => {
    if (media !== newMedia && mediaElements.has(media)) {
      media.pause();
    }
  });
  currentlyPlaying = newMedia;
};

/**
 * Initializes control over a media element.
 * @param {HTMLMediaElement} media - The media element to control.
 */
const initMediaControl = (media) => {
  if (mediaElements.has(media)) return;

  mediaElements.add(media);
  media.pause(); // Only auto-pause media on initial load

  const onEnded = handleMediaEnd;
  const onPlay = () => handleMediaPlay(media);

  media.addEventListener('ended', onEnded);
  media.addEventListener('play', onPlay);

  mediaEventHandlers.set(media, { onEnded, onPlay });

  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      if (
        mutation.type === 'childList' &&
        Array.from(mutation.removedNodes).includes(media)
      ) {
        cleanupMediaElement(media);
        observer.disconnect();
      }
    });
  });
  if (media.parentNode) {
    observer.observe(media.parentNode, { childList: true });
  }
};

/**
 * Cleans up event listeners and references for a media element that's been removed.
 * @param {HTMLMediaElement} media - The media element to clean up.
 */
const cleanupMediaElement = (media) => {
  const handlers = mediaEventHandlers.get(media);
  if (handlers) {
    media.removeEventListener('ended', handlers.onEnded);
    media.removeEventListener('play', handlers.onPlay);
    mediaEventHandlers.delete(media);
  }
  mediaElements.delete(media);
  if (currentlyPlaying === media) {
    currentlyPlaying = null;
  }
};

/**
 * Observes the given document for added or removed media elements.
 * @param {Node} root - The root node to observe (document or shadow root).
 */
const observeMediaElementsInDocument = (root) => {
  const observer = new MutationObserver((mutations) => {
    for (let mutation of mutations) {
      if (mutation.type === 'childList') {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeName === 'VIDEO' || node.nodeName === 'AUDIO') {
            initMediaControl(node);
          } else if (node.nodeType === Node.ELEMENT_NODE) {
            // Check for media in shadow DOM
            if (node.shadowRoot) {
              observeMediaElementsInDocument(node.shadowRoot);
              node.shadowRoot.querySelectorAll('video, audio').forEach(initMediaControl);
            }
            node.querySelectorAll('video, audio').forEach(initMediaControl);
          }
        });
        mutation.removedNodes.forEach((node) => {
          if (node.nodeName === 'VIDEO' || node.nodeName === 'AUDIO') {
            cleanupMediaElement(node);
          } else if (node.nodeType === Node.ELEMENT_NODE) {
            node.querySelectorAll('video, audio').forEach(cleanupMediaElement);
          }
        });
      }
    }
  });

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

/**
 * Tracks user interactions to prevent the extension from pausing user-initiated media playbacks.
 */
const initUserInteractionTracking = () => {
  const userInteractionHandler = () => {
    lastUserInteractionTime = Date.now();
    clearRedBarAndTimer();
  };

  ['mousedown', 'keydown', 'touchstart', 'click'].forEach((eventType) => {
    document.addEventListener(
      eventType,
      userInteractionHandler,
      {
        capture: true,
        passive: true,
      }
    );
  });
};

/**
 * Handles changes to the document's title to reset the extension's state on page navigation.
 */
const handleTitleChange = () => {
  if (document.title !== lastTitle) {
    lastTitle = document.title;
    clearRedBarAndTimer();
    pauseAllMedia();
  }
};

/**
 * Observes changes to the document's title element.
 */
const observeTitleChanges = () => {
  const titleObserver = new MutationObserver(handleTitleChange);
  const titleElement = document.querySelector('title');
  if (titleElement) {
    titleObserver.observe(titleElement, {
      subtree: true,
      characterData: true,
      childList: true,
    });
  }
};

/**
 * Initializes the extension by setting up observers and event listeners.
 */
const initExtension = () => {
  // Initialize media in the main document
  document.querySelectorAll('video, audio').forEach(initMediaControl);

  // Observe the main document for media elements
  observeMediaElementsInDocument(document);

  // Track user interactions
  initUserInteractionTracking();

  // Observe title changes to handle navigation
  observeTitleChanges();

  if (chrome.runtime && chrome.runtime.onMessage) {
    chrome.runtime.onMessage.addListener(
      (request, sender, sendResponse) => {
        if (request.action === 'pauseAllMedia') {
          pauseAllMedia();
        } else if (request.action === 'updateRedBarProgress') {
          updateRedBarProgress(request.progress);
        }
        sendResponse({ status: 'Message received' });
        return true;
      }
    );
  }
};

/**
 * Starts the extension once the document is ready.
 */
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initExtension);
} else {
  initExtension();
}" ,fix error Uncaught SyntaxError: Identifier 'currentlyPlaying' has already been declared



Context

https://shopee.co.th/search?keyword=rtx%204080

Stack Trace

content.js:1 (anonymous function) (let currentlyPlaying = null;
) ,and when playing youtube video and then switch to youtube short (it play for first time then pause) this cause other video to pause (due to allow one active playing function) it should not case this problem ,make sure other function still work fine.