Video im Browser dehnen





Sehr oft hat Video in Online-Kinos ein anderes Seitenverhältnis als das des Monitors. Daher besteht manchmal der Wunsch, die Gesamtskala ein wenig zu vergrößern, indem sie an den Rändern etwas beschnitten wird. Oder passen Sie das Bild in die Bildschirmgröße auf der kleineren Seite des Bildes an. Dies gilt insbesondere für kleine Bildschirme sowie für ältere 4: 3-Monitore. Ich schweige über die Tatsache, dass das Originalvideo im Allgemeinen auf einer Seite gedehnt werden kann und dies irgendwie korrigiert werden muss.



Um dieses Problem zu lösen, habe ich beschlossen, eine Browser-Erweiterung für Chrome und Firefox zu schreiben. Die Idee ist folgende: Wenn Sie ein Browser-Video abspielen, wird ein Bildschirmmenü aufgerufen, mit dem Sie den Maßstab und das Seitenverhältnis des Bildes beliebig ändern können.



iframe



Das erste Problem, auf das ich gestoßen bin, ist, dass sich Videos auf Websites nicht unbedingt auf der Hauptseite befinden, sondern tief in verschachtelten Iframes versteckt sein können. Ich beschloss, alle Iframes zu scannen und alle Videoelemente in jedem zu finden. Dies löst übrigens auch ein anderes Problem - Sie wissen nie, wo sich das Werbevideo befindet und wo sich der Film selbst befindet. Lassen Sie uns sie alle zuerst finden.



Die Funktion getVideos ruft sich rekursiv auf, bis alle Videoelemente im letzten Iframe gefunden wurden. Alle Videos werden dem Array ap_ext_space.videos hinzugefügt. Die Funktion getVideos verwendet das Dokument der aktuellen Seite als Eingabeparameter. Beim ersten Start wird das Hauptdokument erstellt. Auf dem Weg werden Handler an jedes Video gehängt, aber mehr dazu weiter unten.



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);
		};
	};
},


OSD-Menü





Okay, wir haben eine Liste aller Videoelemente. Wie wird nun das OSD-Menü angezeigt? Fügen wir einfach jedem Video sein Blockelement hinzu. Ja, dann werden wir viele Bildschirmmenüs haben, aber gleichzeitig wird nur ein Video angezeigt: eine der Werbespots oder der Film selbst. Und nur ein Menü wird mit ihnen angezeigt.



Das Video befindet sich normalerweise im übergeordneten Div. Fügen wir unser Menü div-Element als letztes untergeordnetes Element hinzu. Somit wird das OSD immer über dem Video angezeigt.



Wir werden das OSD-Bild in base64 im PNG-Format mit einem transparenten Alphakanal codieren und in ap_ext_space.imgUR platzieren, da der Browser es uns nicht erlaubt, das Bild von einer anderen Domäne zu laden. Erstellen Sie für jedes Video ein Menü:



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);
},


Wenn Sie einem Video wie dem folgenden ein OSD-Div hinzufügen: videoEl.parentNode.appendChild (div), wird es auch im Vollbildmodus über dem Video angezeigt. Es bleibt nur zu zentrieren, oder besser gesagt, mit allen Blockmenüelementen zu tun, die an die Videoelemente angehängt sind (sie haben eine Größe von 520 x 410):



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);
},


Am Ende habe ich mich übrigens entschieden, das Menü im Fenstermodus vollständig auszublenden und die Steuerung der Videogröße nur im Vollbildmodus zuzulassen. Im Fenster macht es keinen Sinn.



Handler



Hier ist meiner Meinung nach alles klar. Auf jeder Schaltfläche des Bildschirmmenüs werden Klick-Handler, eine Schubkarre und das Drücken der entsprechenden Tastenkombination aufgehängt, um das Video auch bei ausgeblendetem Menü zu steuern. Die Schaltflächen steuern die Skalierungswerte: ap_ext_space.scale, ap_ext_space.scalew und ap_ext_space.scaleh, erhöhen oder verringern diese Werte und ändern dann die Größe jedes oben gefundenen Videoelements wie folgt:



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 + ')';
};


Außerdem habe ich mich an die Video-Event-Handler gehalten, die für jedes Videoelement (in der obigen Funktion getVideos ()) gesucht, abgebrochen, angehalten, abgespielt, abgespielt und gesucht wurden, um die einzige Funktion aufzurufen, die das Bildschirmmenü neu zeichnet und seine Koordinaten neu berechnet, weil manchmal es "verlässt" mit einer Benutzeraktion. Ich habe das gleiche für das Ereignis zur Größenänderung des Browserfensters getan.



Namespace



Was für ein ap_ext_space ist das im Allgemeinen? Tatsache ist, dass alle Funktionen, mit denen die Größe des Videos geändert wird, in die entsprechende Seite eingebettet sein müssen (entweder auf der Hauptseite oder im Iframe). Also habe ich diese Funktionen und zusammen mit ihnen den OSD-Hintergrund von base64 in einem einzigen Namespace zusammengefasst. All dies wird wie folgt aus dem Hintergrundskript in den Code der aktuellen Browser-Registerkarte eingefügt:



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() {
			//...
		},

		//...
	};

};


Nun, in ap_ext_space wird eine Suche nach allen Iframes ausgelöst, dann werden alle Videos in jedem von ihnen erstellt, ein Bildschirmmenü mit Handlern erstellt und so weiter.



Wie benutzt man



Video abspielen. Klicken Sie auf das Erweiterungssymbol. Erweitern Sie das Video auf Vollbild. Passen Sie Skalierung und Seitenverhältnis an. Das Menü kann mit der Tastenkombination Strg + 0 ausgeblendet werden.



Ergebnis



Die Erweiterung heißt Browser Video Tuner, ist kostenlos und derzeit in den Chrome- und Firefox-Erweiterungsgeschäften erhältlich. Natürlich kann es auch in allen Chrome-kompatiblen Browsern wie Opera, Yandex Browser usw. installiert werden. Es ist zu beachten, dass die Erweiterung nicht auf allen Video-Sites funktioniert. Wenn der Zugriff auf Iframe-Elemente von außen durch Sicherheitsrichtlinien geschützt ist, wird einfach kein Video gefunden. Eine entsprechende Warnung dazu wird in der Konsole angezeigt. In diesem Fall wird das Menü einfach nicht angezeigt. Aber auf Youtube und vielen Online-Kinos funktioniert alles.



Bei einigen Browsern wurden kleinere Probleme festgestellt. In Yandex Browser beispielsweise verschlechtert sich das angezeigte Bild irgendwie und ähnelt stark komprimiertem JPEG. Dies hat jedoch keinerlei Auswirkungen auf die Funktionalität.





Ich suchte nach einer Möglichkeit, das Bildschirmmenü im Vollbildmodus einfach über dem gesamten Dokument anzuzeigen, ohne es in iframes einzubetten, um nicht von der Sicherheitsrichtlinie des Browsers abhängig zu sein, und zu versuchen, die Größe des gesamten Dokuments als Ganzes zu steuern. Bisher ist mir dies jedoch nicht gelungen. Ich denke, dass die Erweiterung in Zukunft durch neue Funktionen ergänzt wird.



All Articles