في كثير من الأحيان ، يكون للفيديو في دور السينما عبر الإنترنت نسبة عرض إلى ارتفاع تختلف عن تلك الخاصة بالشاشة. لذلك ، في بعض الأحيان تكون هناك رغبة في جعل المقياس العام أكبر قليلاً عن طريق الاقتصاص قليلاً عند الحواف. أو حتى - احتواء الصورة في حجم الشاشة على الجانب الأصغر من الصورة. هذا ينطبق بشكل خاص على الشاشات الصغيرة ، وكذلك للشاشات القديمة 4: 3. أنا صامت بالفعل بشأن حقيقة أن الفيديو الأصلي يمكن تمديده بشكل عام من جانب واحد وهذا يحتاج إلى تصحيح بطريقة ما.
لحل هذه المشكلة ، قررت كتابة امتداد متصفح لمتصفحي Chrome و Firefox. الفكرة هي: عند تشغيل أي مقطع فيديو في المتصفح ، يتم استدعاء قائمة على الشاشة ، والتي تسمح لك بتغيير مقياس الصورة ونسبة العرض إلى الارتفاع بشكل تعسفي.
iframe
المشكلة الأولى التي واجهتها هي أن مقاطع الفيديو على مواقع الويب ليست بالضرورة موجودة على الصفحة الرئيسية ، ولكن يمكن إخفاؤها بعمق في إطارات iframe المتداخلة. قررت فحص جميع إطارات iframe والعثور على جميع عناصر الفيديو في كل منها. بالمناسبة ، هذا أيضًا يحل مشكلة أخرى - فأنت لا تعرف أبدًا مكان وجود الفيديو الإعلاني ومكان الفيلم نفسه. دعونا نعثر عليهم جميعًا أولاً.
تستدعي وظيفة getVideos نفسها بشكل متكرر حتى يتم العثور على جميع عناصر الفيديو في إطار iframe الأخير. تتم إضافة جميع مقاطع الفيديو إلى مجموعة ap_ext_space.videos. تأخذ وظيفة getVideos مستند الصفحة الحالية كمعامل إدخال. عند الإطلاق الأول ، يتم أخذ المستند الرئيسي. على طول الطريق ، يتم تعليق المعالجات على كل مقطع فيديو ، ولكن المزيد حول ذلك أدناه.
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

حسنًا ، لدينا قائمة بجميع عناصر الفيديو. الآن كيف يتم عرض قائمة OSD؟ دعنا فقط نضيف عنصر الكتلة الخاص به إلى كل فيديو. نعم ، عندها سيكون لدينا الكثير من القوائم المعروضة على الشاشة ، ولكن في وقت واحد يتم عرض فيديو واحد فقط: أحد الإعلانات التجارية أو الفيلم نفسه. وسيتم عرض قائمة واحدة فقط معهم.
يوجد الفيديو عادة في div. دعونا نضيف عنصر div في القائمة لدينا باعتباره الطفل الأخير. وبالتالي ، سيتم دائمًا عرض OSD فوق الفيديو.
يتم ترميز صورة OSD في base64 بتنسيق png بقناة ألفا شفافة ويتم وضعها في ap_ext_space.imgUR ، نظرًا لأن المتصفح لن يسمح لنا بتحميل الصورة من مجال آخر. أنشئ قائمة لكل فيديو:
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);
},
إذا أضفت عنصر OSD div إلى مقطع فيديو مثل هذا: videoEl.parentNode.appendChild (div) ، فسيظهر أعلى الفيديو حتى في وضع ملء الشاشة. يبقى فقط لتوسيطه ، أو بالأحرى ، القيام بذلك مع جميع عناصر قائمة الحظر المرفقة بعناصر الفيديو (حجمها 520 × 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);
},
بالمناسبة ، قررت في النهاية إخفاء القائمة تمامًا في وضع الإطارات والسماح بالتحكم في حجم الفيديو فقط في وضع ملء الشاشة. في النافذة ، لا معنى له.
معالجات
هنا ، على ما أعتقد ، كل شيء واضح. في كل زر في القائمة التي تظهر على الشاشة ، يتم تعليق معالجات النقر ، وعربة اليد ، وكذلك الضغط على مجموعة المفاتيح المقابلة للتحكم في الفيديو حتى مع إخفاء القائمة. تتحكم الأزرار في قيم التكبير / التصغير ap_ext_space.scale و ap_ext_space.scalew و ap_ext_space.scaleh ، وزيادة أو تقليل هذه القيم ، ثم تغيير حجم كل عنصر فيديو موجود أعلاه على النحو التالي:
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 + ')';
};
بالإضافة إلى ذلك ، لقد علقت أيضًا على معالجات أحداث الفيديو التي طلبت ، وإحباط ، وإيقاف مؤقت ، وتشغيل ، وتشغيل ، والبحث عن كل عنصر فيديو (في وظيفة getVideos () أعلاه) استدعاء الوظيفة الوحيدة التي تعيد رسم القائمة التي تظهر على الشاشة مع إعادة حساب إحداثياتها ، لأنه في بعض الأحيان "يترك" مع بعض إجراءات المستخدم. فعلت الشيء نفسه لحدث تغيير حجم نافذة المتصفح.
مساحة الاسم
بشكل عام ، ما هو نوع ap_ext_space هذا؟ الحقيقة هي أنه يجب تضمين جميع الوظائف المستخدمة لتغيير حجم الفيديو في الصفحة المقابلة (إما في الصفحة الرئيسية أو في إطار iframe). لذلك قمت للتو بدمج هذه الوظائف ومعها خلفية base64 OSD في مساحة اسم واحدة. يتم إدخال كل هذا في كود علامة تبويب المتصفح الحالية من البرنامج النصي للخلفية على النحو التالي:
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() {
//...
},
//...
};
};
حسنًا ، داخل ap_ext_space ، تم بالفعل تشغيل البحث عن جميع إطارات iframes ، ثم - لجميع مقاطع الفيديو داخل كل منها ، تم إنشاء قائمة على الشاشة مع معالجات ، وما إلى ذلك.
كيف تستعمل
شغل الفيديو. انقر فوق أيقونة الامتداد. قم بتوسيع الفيديو إلى وضع ملء الشاشة. ضبط المقياس ونسبة العرض إلى الارتفاع. يمكن إخفاء القائمة باستخدام اختصار لوحة المفاتيح ctrl + 0.
النتيجة
يسمى الامتداد Browser Video Tuner ، وهو مجاني ومتوفر حاليًا في متاجر ملحقات Chrome و Firefox. أيضًا ، بالطبع ، يمكن تثبيته في جميع المتصفحات المتوافقة مع Chrome مثل Opera و Yandex Browser وما إلى ذلك. وتجدر الإشارة إلى أن الامتداد لا يعمل على جميع مواقع الفيديو. عندما يكون الوصول إلى عناصر iframe من الخارج محميًا بواسطة سياسة الأمان ، فلن يتم العثور على أي مقطع فيديو. وسيظهر تحذير مماثل حول هذا في وحدة التحكم. في هذه الحالة ، لن يتم عرض القائمة ببساطة. ولكن على Youtube والعديد من دور السينما عبر الإنترنت ، كل شيء يعمل.
تم ملاحظة مشاكل بسيطة في بعض المتصفحات. على سبيل المثال ، في متصفح Yandex ، تتدهور الصورة المعروضة بطريقة ما وتشبه JPEG المضغوط بشدة. لكن هذا لا يؤثر على الوظائف بأي شكل من الأشكال.

كنت أبحث عن طريقة لعرض القائمة التي تظهر على الشاشة في وضع ملء الشاشة ببساطة أعلى المستند بأكمله دون تضمينه داخل إطارات iframe ، حتى لا أعتمد على سياسة أمان المتصفح ، ومحاولة التحكم في حجم المستند بأكمله ككل ، لكنني لم أنجح حتى الآن. أعتقد أنه في المستقبل سيتم استكمال التوسيع بوظائف جديدة.