
Muitas vezes, o vĂdeo em cinemas online tem uma proporção de aspecto diferente da do monitor. Portanto, Ă s vezes há um desejo de tornar a escala geral um pouco maior cortando ligeiramente nas bordas. Ou ainda - ajuste a imagem ao tamanho da tela no lado menor da imagem. Isso Ă© especialmente verdadeiro para telas pequenas, bem como para monitores 4: 3 mais antigos. Já estou calado sobre o fato de que o vĂdeo original pode ser geralmente esticado para um lado e isso deve ser corrigido de alguma forma.
Para resolver este problema, decidi escrever uma extensĂŁo de navegador para Chrome e Firefox. A ideia Ă© esta: ao reproduzir qualquer vĂdeo do navegador, um menu na tela Ă© chamado, o que permite alterar arbitrariamente a escala e a proporção da imagem.
iframe
O primeiro problema que encontrei Ă© que os vĂdeos em sites nĂŁo estĂŁo necessariamente localizados na página principal, mas podem estar ocultos em iframes aninhados. Decidi verificar todos os iframes e encontrar todos os elementos de vĂdeo em cada um. A propĂłsito, isso tambĂ©m resolve outro problema - vocĂŞ nunca sabe onde está o vĂdeo publicitário e onde está o prĂłprio filme. Vamos encontrá-los todos primeiro.
A função getVideos chama a si mesma recursivamente atĂ© que todos os elementos de vĂdeo sejam encontrados no Ăşltimo iframe. Todos os vĂdeos sĂŁo adicionados ao array ap_ext_space.videos. A função getVideos usa o documento da página atual como um parâmetro de entrada. No primeiro lançamento, o documento principal Ă© obtido. Ao longo do caminho, manipuladores sĂŁo adicionados a cada vĂdeo, mas mais sobre isso a seguir.
getVideos: function (srcDoc) {
if (!srcDoc) {
srcDoc = document;
window.onkeydown = function (event) {
var e = event || window.event;
ap_ext_space.keyDn(e);
};
};
var els = srcDoc.getElementsByTagName('video');
for (var i = 0; i < els.length; i++) {
els[i].addEventListener("seeked", function () {ap_ext_space.zoomw(); console.log('seeked'); }, true);
els[i].addEventListener("abort", function () {ap_ext_space.zoomw(); console.log('abort'); }, true);
els[i].addEventListener("pause", function () {ap_ext_space.zoomw(); console.log('pause'); }, true);
els[i].addEventListener("play", function () {ap_ext_space.zoomw(); console.log('play'); }, true);
els[i].addEventListener("playing", function () {ap_ext_space.zoomw(); console.log('playing'); }, true);
els[i].addEventListener("seeked", function () {ap_ext_space.zoomw(); console.log('seeked'); }, true);
ap_ext_space.videos.push(els[i]);
ap_ext_space.menu(els[i], srcDoc);
};
console.log('all videos:', ap_ext_space.videos);
var ifrs = srcDoc.getElementsByTagName("iframe");
console.log('iframes:', ifrs);
var ifr;
for (var i = 0; i < ifrs.length; i++) {
ifr = ifrs[i];
try {
var innerDoc = (ifr.contentDocument || ifr.contentWindow.document);
var innerWindow = (ifr.contentWindow || ifr);
innerWindow.onkeydown = function (event) {
var e = event || window.event;
ap_ext_space.keyDn(e);
};
ap_ext_space.getVideos(innerDoc);
} catch (err) {
console.log('err', err);
};
};
},
Menu OSD

Ok, temos uma lista de todos os elementos de vĂdeo. Agora, como exibir o menu OSD? Vamos apenas adicionar seu elemento de bloco a cada vĂdeo. Sim, teremos muitos menus na tela, mas em um determinado momento apenas um vĂdeo Ă© exibido: um dos comerciais ou o prĂłprio filme. E apenas um menu será mostrado com eles.
O vĂdeo geralmente está localizado no div pai. Vamos adicionar nosso elemento div de menu a ele como o Ăşltimo filho. Assim, o OSD sempre será exibido sobre o vĂdeo.
Vamos codificar a imagem OSD em base64 no formato png com um canal alfa transparente e colocá-la em ap_ext_space.imgUR, pois o navegador nĂŁo nos permitirá carregar a imagem de outro domĂnio. Crie um menu para cada vĂdeo:
menu: function(videoEl, doc) {
// div video
// , ( menuInside)
var els = videoEl.parentNode.getElementsByTagName('div');
var menuInside = false;
for (var j = 0; j < els.length; j++) {
if (els[j].id == 'ap_ext_space_container') {
menuInside = true;
ap_ext_space.menus.push(els[j]);
};
};
if (menuInside == false) {
//
var div = doc.createElement('div');
div.innerHTML = ap_ext_space.html();
videoEl.parentNode.appendChild(div);
div.style.width = '520px';
div.style.height = '410px';
div.style.display = 'block';
div.style.position = 'absolute';
div.id = 'ap_ext_space_container';
var url = "url('" + ap_ext_space.imgURL + "')";
div.style.backgroundImage = url;
div.style.opacity = 0.95;
ap_ext_space.menus.push(div);
//
div.addEventListener("dblclick", function(e) {
e.preventDefault();
e.stopPropagation();
}, true);
div.addEventListener("mouseover", function(e) {
e.preventDefault();
e.stopPropagation();
var elem, evt = e ? e : event;
if (evt.srcElement) {
elem = evt.srcElement;
} else if (evt.target) {
elem = evt.target;
};
//
var pos = {
ap_ext_space_num7: [520 + 134, 82],
ap_ext_space_num8: [520 + 134 + 90, 82],
ap_ext_space_num9: [520 + 134 + 90 + 90, 82],
ap_ext_space_num4: [520 + 134, 82 + 90],
ap_ext_space_num5: [520 + 134 + 90, 82 + 90],
ap_ext_space_num6: [520 + 134 + 90 + 90, 82 + 90],
ap_ext_space_num1: [520 + 134, 82 + 90 + 90],
ap_ext_space_num2: [520 + 134 + 90, 82 + 90 + 90],
ap_ext_space_num3: [520 + 134 + 90 + 90, 82 + 90 + 90]
};
var key, el;
for (var j = 1; j < 10; j++) {
key = 'ap_ext_space_num' + j;
if (elem.id == key) {
elem.style.backgroundImage = "url('" + ap_ext_space.imgURL + "')";
elem.style.backgroundPosition = -pos[key][0] + 'px ' + -pos[key][1] + 'px';
};
};
}, true);
div.addEventListener("mouseout", function(e) {
e.preventDefault();
e.stopPropagation();
var elem, evt = e ? e : event;
if (evt.srcElement) {
elem = evt.srcElement;
} else if (evt.target) {
elem = evt.target;
};
var key, el;
for (var j = 1; j < 10; j++) {
key = 'ap_ext_space_num' + j;
if (elem.id == key) {
elem.style.backgroundImage = "none";
};
};
}, true);
div.addEventListener("click", function(e) {
e.preventDefault();
e.stopPropagation();
var elem, evt = e ? e : event;
if (evt.srcElement) {
elem = evt.srcElement;
} else if (evt.target) {
elem = evt.target;
};
ap_ext_space.clickHandler(elem);
}, true);
div.addEventListener("touchstart", function(e) {
e.preventDefault();
e.stopPropagation();
var elem, evt = e ? e : event;
if (evt.srcElement) {
elem = evt.srcElement;
} else if (evt.target) {
elem = evt.target;
};
ap_ext_space.clickHandler(elem);
}, true);
div.addEventListener("touchend", function(e) {
e.preventDefault();
}, true);
div.addEventListener("touchmove", function(e) {
e.preventDefault();
}, true);
// ( )
ap_ext_space.menuPos();
};
console.log('all menus:', ap_ext_space.menus);
},
Se vocĂŞ adicionar um OSD div a um vĂdeo como este: videoEl.parentNode.appendChild (div), ele aparecerá na parte superior do vĂdeo, mesmo no modo de tela inteira. Resta apenas centralizá-lo, ou melhor, fazĂŞ-lo com todos os itens do menu do bloco anexados aos elementos de vĂdeo (eles tĂŞm um tamanho de 520x410):
menuPos: function() {
if (ap_ext_space.isFullScreen()) {
var sc = ap_ext_space.scale;
var iw = window.innerWidth,
ih = window.innerHeight;
var w = iw * sc;
var h = w / 16 * 9;
for (var i = 0; i < ap_ext_space.menus.length; i++) {
ap_ext_space.menus[i].style.marginLeft = (iw - 520) / 2 + 'px';
ap_ext_space.menus[i].style.marginTop = (-h - 410) / 2 + 'px';
};
} else {
ap_ext_space.scale = 1;
for (var i = 0; i < ap_ext_space.menus.length; i++) {
ap_ext_space.menus[i].style.marginLeft = '0px';
ap_ext_space.menus[i].style.marginTop = '0px';
};
};
},
isFullScreen: function() {
return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
},
A propĂłsito, no final, decidi ocultar completamente o menu no modo de janela e permitir o controle do tamanho do vĂdeo apenas no modo de tela inteira. Na janela, nĂŁo faz sentido.
Handlers
Aqui, eu acho, tudo está claro. Em cada botĂŁo do menu na tela, manipuladores de clique, um carrinho de mĂŁo e tambĂ©m pressionando a combinação de teclas correspondente sĂŁo pendurados para controlar o vĂdeo, mesmo com o menu oculto. Os botões controlam os valores de escala: ap_ext_space.scale, ap_ext_space.scalew e ap_ext_space.scaleh, aumentando ou diminuindo esses valores e, em seguida, redimensionando cada elemento de vĂdeo encontrado acima da seguinte maneira:
var sc = ap_ext_space.scale;
var iw = window.innerWidth,
ih = window.innerHeight;
var w = iw * sc;
var h = w / 16 * 9;
for (var i = 0; i < ap_ext_space.videos.length; i++) {
el = ap_ext_space.videos[i];
el.style.position = 'initial';
el.style.width = (w) + 'px';
el.style.height = (h) + 'px';
el.style.marginLeft = -(w - iw) / 2 + 'px';
el.style.marginTop = -(h - ih) / 2 + 'px';
el.style.transform = 'scaleX(' + ap_ext_space.scalew + ') scaleY(' + ap_ext_space.scaleh + ')';
};
AlĂ©m disso, tambĂ©m desliguei os manipuladores de eventos de vĂdeo seeked, abort, pause, play, playing, seeked para cada elemento de vĂdeo (na função getVideos () acima) uma chamada para a Ăşnica função que redesenha o menu na tela com recalculando suas coordenadas, porque Ă s vezes ele "sai" com alguma ação do usuário. Fiz o mesmo para o evento de redimensionamento da janela do navegador.
Namespace
Em geral, que tipo de ap_ext_space Ă© esse? O fato Ă© que todas as funções que servem para redimensionar o vĂdeo devem estar embutidas na página correspondente (seja na página principal ou no iframe). EntĂŁo, eu apenas combinei essas funções, e com elas o fundo OSD de base64, em um Ăşnico namespace. Tudo isso Ă© injetado no cĂłdigo da guia do navegador atual a partir do script de plano de fundo da seguinte maneira:
var codeString = ap_ext_space_f.toString() + '; ap_ext_space_f(); ap_ext_space.init()';
chrome.tabs.executeScript({
code: codeString
});
function ap_ext_space_f() {
ap_ext_space = {
init: function() {
//...
},
//...
};
};
Bem, dentro de ap_ext_space, uma busca por todos os iframes Ă© acionada, entĂŁo todos os vĂdeos dentro de cada um deles, um menu na tela com manipuladores Ă© construĂdo, e assim por diante.
Como usar
Reproduza o vĂdeo. Clique no Ăcone da extensĂŁo. Expanda o vĂdeo para tela inteira. Ajuste a escala e a proporção da imagem. O menu pode ser oculto com o atalho de teclado ctrl + 0.
Resultado
A extensĂŁo Ă© chamada de Browser Video Tuner, Ă© gratuita e está atualmente disponĂvel nas lojas de extensões do Chrome e do Firefox. AlĂ©m disso, Ă© claro, ele pode ser instalado em todos os navegadores compatĂveis com o Chrome, como Opera, Yandex Browser e assim por diante. Deve-se notar que a extensĂŁo nĂŁo funciona em todos os sites de vĂdeo. Onde o acesso externo aos elementos iframe for protegido pela polĂtica de segurança, nenhum vĂdeo será simplesmente encontrado. E um aviso correspondente sobre isso aparecerá no console. Nesse caso, o menu simplesmente nĂŁo será exibido. Mas no Youtube e em muitos cinemas online tudo funciona.
Pequenos problemas foram observados em alguns navegadores. Por exemplo, no Yandex Browser, a imagem exibida de alguma forma se deteriora e se assemelha a um JPEG fortemente compactado. Mas isso nĂŁo afeta a funcionalidade de forma alguma.

Eu estava procurando uma maneira de exibir o menu na tela em modo de tela inteira simplesmente sobre todo o documento sem incorporá-lo em iframes, para nĂŁo depender da polĂtica de segurança do navegador e tentar controlar o tamanho de todo o documento como um todo, mas atĂ© agora nĂŁo consegui. Acho que no futuro a expansĂŁo será complementada com novas funções.