Extensão para Google Chrome (Manifest V3) que envia o vídeo principal da aba ativa para o modo Picture-in-Picture nativo do navegador. Três formas de ativar:
Alt+Shift+F por padrão — fica todo do lado esquerdo do teclado, dá pra usar com uma mão só; configurável em chrome://extensions/shortcuts)Se já houver um vídeo em PiP, qualquer um desses gestos fecha a janela.
chrome://extensions no Chrome.VideoToPopUp).Dois arquivos, cada um com uma única responsabilidade:
content.js — content script declarado no manifest, roda automaticamente em toda página carregada (e em todo <iframe>). É a única fonte de verdade: escolhe o vídeo, desenha/posiciona o botão e controla o toggle de PiP. Expõe uma única função, window.__soltaDoVideoToggle, dentro do mundo isolado da extensão (invisível ao JavaScript da própria página).background.js — service worker. Não contém nenhuma lógica de seleção de vídeo; só escuta o clique no ícone e o atalho de teclado e injeta, via chrome.scripting.executeScript, uma função de uma linha que chama window.__soltaDoVideoToggle().Essa separação elimina a duplicação da lógica de escolha de vídeo entre os dois arquivos. executeScript (em vez de chrome.tabs.sendMessage) é obrigatório aqui: só assim o Chrome propaga o gesto do usuário (clique no ícone/atalho) para dentro da página, permitindo que requestPictureInPicture() funcione — uma mensagem comum não carrega essa permissão e a chamada seria rejeitada pelo navegador.
content.js não fica rodando requestAnimationFrame para sempre em toda página — a maioria das páginas não tem vídeo. Ele checa uma vez no carregamento e, se não encontrar nada, fica em espera observando mudanças no DOM (MutationObserver); o loop de posicionamento do botão só começa quando um vídeo utilizável aparece, e para sozinho se o vídeo some.
Entre os elementos <video> da página, ignora qualquer um com readyState < 1, largura ou altura zero, ou totalmente fora da área visível da tela. Entre os candidatos restantes, prioriza o vídeo que estiver tocando; em caso de empate, escolhe o de maior área visível na viewport. Como o content script roda em todos os frames (all_frames: true), vídeos dentro de <iframe> — inclusive de outra origem — também são detectados normalmente.
activeTab e scripting (exigidas pelo chrome.scripting.executeScript usado no clique/atalho), mais content_scripts com matches: ["<all_urls>"], necessário para o botão aparecer automaticamente em qualquer site. Não há tabs, storage, webRequest, host_permissions adicionais, externally_connectable nem onMessageExternal.fetch, XMLHttpRequest, WebSocket, CDN, analytics ou telemetria em todo o código.<video> para controlar PiP e cria um único botão de overlay via document.createElement/createElementNS — nunca innerHTML, outerHTML, insertAdjacentHTML ou document.write. Nenhum conteúdo, URL ou título da página é lido, armazenado ou transmitido.chrome://, edge://, about:, chrome-extension://, view-source: ou na Chrome Web Store — o próprio Chrome nunca injeta content_scripts declarativos nem permite executeScript nessas páginas, independentemente do padrão de matches, então não há lista manual para manter.func, mundo ISOLATED: background.js chama chrome.scripting.executeScript com func (nunca code/strings), sem world: "MAIN". A função injetada só lê window.__soltaDoVideoToggle, que o content.js define no mesmo mundo isolado da extensão — nunca fica visível para o JavaScript da própria página.chrome.storage ou de variáveis globais mutáveis além do necessário para rastrear o vídeo atual e a posição do botão em memória, perdidos ao recarregar a página.