HTML5 এ একটি ব্রাউজার ট্যাব স্ক্রিনশেয়ার করছেন?

গত কয়েক বছরে, আমি কয়েকটি ভিন্ন কোম্পানিকে শুধুমাত্র ব্রাউজার প্রযুক্তি ব্যবহার করে স্ক্রিন শেয়ারিং-এর মতো কার্যকারিতা অর্জন করতে সাহায্য করেছি। আমার অভিজ্ঞতা থেকে, শুধুমাত্র ওয়েব প্ল্যাটফর্ম প্রযুক্তিতে (যেমন কোন প্লাগইন নেই) VNC বাস্তবায়ন করা একটি কঠিন সমস্যা। বিবেচনা করার জন্য অনেক কিছু আছে এবং অনেক চ্যালেঞ্জ অতিক্রম করতে হবে। মাউস পয়েন্টার পজিশন রিলে করা, কীস্ট্রোক ফরোয়ার্ড করা এবং 60fps-এ সম্পূর্ণ 24-বিট কালার রিপেইন্ট করা হল কয়েকটি সমস্যা।

ট্যাবের বিষয়বস্তু ক্যাপচার করা হচ্ছে

আমরা যদি প্রথাগত স্ক্রিন শেয়ারিং এর জটিলতাগুলিকে সরিয়ে একটি ব্রাউজার ট্যাবের বিষয়বস্তু ভাগ করে নেওয়ার উপর ফোকাস করি, তাহলে সমস্যাটি অনেকটাই সরল হয়ে যায় ক) দৃশ্যমান ট্যাবটিকে তার বর্তমান অবস্থায় ক্যাপচার করা এবং খ.) তারের জুড়ে সেই "ফ্রেম" পাঠানো। মূলত, আমাদের DOM-এর স্ন্যাপশট করার একটি উপায় প্রয়োজন এবং এটি ভাগ করে নেওয়ার জন্য।

ভাগ করা অংশ সহজ. ওয়েবসকেটগুলি বিভিন্ন ফর্ম্যাটে (স্ট্রিং, JSON, বাইনারি) ডেটা পাঠাতে খুব সক্ষম। স্ন্যাপশট অংশ একটি অনেক কঠিন সমস্যা. html2canvas- এর মতো প্রজেক্টগুলি জাভাস্ক্রিপ্টে ব্রাউজারের রেন্ডারিং ইঞ্জিনকে পুনরায় প্রয়োগ করে HTML স্ক্রিনক্যাপচারিংকে মোকাবেলা করেছে! আরেকটি উদাহরণ হল Google Feedback , যদিও এটি ওপেন সোর্স নয়। এই ধরণের প্রকল্পগুলি খুব দুর্দান্ত, তবে সেগুলিও ভয়ঙ্করভাবে ধীর। আপনি 1fps থ্রুপুট পাওয়ার জন্য ভাগ্যবান হবেন, যা লোভনীয় 60fps থেকে অনেক কম।

এই নিবন্ধটি একটি ট্যাব "স্ক্রিনশেয়ার করার" জন্য আমার কয়েকটি প্রিয় প্রমাণ-অব-ধারণা সমাধান নিয়ে আলোচনা করে।

পদ্ধতি 1: মিউটেশন পর্যবেক্ষক + ওয়েবসকেট

ট্যাব মিরর করার জন্য একটি পদ্ধতি এই বছরের শুরুতে + রাফায়েল ওয়েইনস্টেইন দ্বারা প্রদর্শিত হয়েছিল। তার কৌশল মিউটেশন পর্যবেক্ষক এবং একটি ওয়েবসকেট ব্যবহার করে।

মূলত, উপস্থাপক যে ট্যাবটি ভাগ করছেন সেটি পৃষ্ঠার পরিবর্তনের জন্য ঘড়ি এবং একটি ওয়েবসকেট ব্যবহার করে দর্শকের কাছে পার্থক্য পাঠায়। ব্যবহারকারী যখন পৃষ্ঠার সাথে স্ক্রল করে বা ইন্টারঅ্যাক্ট করে, পর্যবেক্ষকরা এই পরিবর্তনগুলি তুলে নেয় এবং রাফায়েলের মিউটেশন সারাংশ লাইব্রেরি ব্যবহার করে দর্শকদের কাছে রিপোর্ট করে। এটি জিনিসগুলিকে কার্যকর রাখে। পুরো পৃষ্ঠাটি প্রতিটি ফ্রেমের জন্য পাঠানো হয় না।

রাফায়েল যেমন ভিডিওতে উল্লেখ করেছেন, এটি নিছক ধারণার প্রমাণ। তবুও, আমি মনে করি এটি একটি নতুন প্ল্যাটফর্ম বৈশিষ্ট্য যেমন মিউটেশন পর্যবেক্ষকদের ওয়েবসকেটের মতো পুরানোটির সাথে একত্রিত করার একটি ঝরঝরে উপায়।

পদ্ধতি 2: একটি HTML ডকুমেন্ট + বাইনারি ওয়েবসকেট থেকে ব্লব

এই পরবর্তী পদ্ধতিটি এমন একটি যা সম্প্রতি আমার উপর উঠে এসেছে। এটি মিউটেশন পর্যবেক্ষক পদ্ধতির অনুরূপ, কিন্তু সারাংশের পার্থক্য পাঠানোর পরিবর্তে, এটি সমগ্র HTMLDocument একটি ব্লব ক্লোন তৈরি করে এবং এটি একটি বাইনারি ওয়েবসকেট জুড়ে পাঠায়। এখানে সেটআপ দ্বারা সেটআপ আছে:

  1. নিখুঁত হতে পৃষ্ঠায় সমস্ত URL পুনরায় লিখুন। এটি স্ট্যাটিক ইমেজ এবং CSS সম্পদগুলিকে ভাঙা লিঙ্কগুলি ধারণ করতে বাধা দেয়।
  2. পৃষ্ঠার নথি উপাদান ক্লোন করুন: document.documentElement.cloneNode(true);
  3. ক্লোনটিকে শুধুমাত্র পঠনযোগ্য, অ-নির্বাচনযোগ্য করুন এবং CSS pointer-events: 'none';user-select:'none';overflow:hidden;
  4. পৃষ্ঠার বর্তমান স্ক্রোল অবস্থানটি ক্যাপচার করুন এবং তাদের ডুপ্লিকেটের data-* বৈশিষ্ট্য হিসাবে যুক্ত করুন।
  5. ডুপ্লিকেটের .outerHTML থেকে একটি new Blob() তৈরি করুন।

কোডটি এরকম কিছু দেখায় (আমি সম্পূর্ণ উত্স থেকে সরলীকরণ করেছি):

function screenshotPage() {
    // 1. Rewrite current doc's imgs, css, and script URLs to be absolute before
    // we duplicate. This ensures no broken links when viewing the duplicate.
    urlsToAbsolute(document.images);
    urlsToAbsolute(document.querySelectorAll("link[rel='stylesheet']"));
    urlsToAbsolute(document.scripts);

    // 2. Duplicate entire document tree.
    var screenshot = document.documentElement.cloneNode(true);

    // 3. Screenshot should be readyonly, no scrolling, and no selections.
    screenshot.style.pointerEvents = 'none';
    screenshot.style.overflow = 'hidden';
    screenshot.style.userSelect = 'none'; // Note: need vendor prefixes

    // 4. … read on …

    // 5. Create a new .html file from the cloned content.
    var blob = new Blob([screenshot.outerHTML], {type: 'text/html'});

    // Open a popup to new file by creating a blob URL.
    window.open(window.URL.createObjectURL(blob));
}

urlsToAbsolute() আপেক্ষিক/স্কিমহীন ইউআরএলগুলিকে পরমগুলির সাথে পুনরায় লেখার জন্য সহজ রেজেক্স রয়েছে। এটি প্রয়োজনীয় তাই ছবি, সিএসএস, ফন্ট এবং স্ক্রিপ্টগুলি যখন একটি ব্লব ইউআরএলের প্রেক্ষাপটে (যেমন একটি ভিন্ন উত্স থেকে) দেখা হয় তখন ভেঙে না যায়৷

আমি তৈরি একটি শেষ খামচি ছিল স্ক্রোল সমর্থন যোগ করা. উপস্থাপক যখন পৃষ্ঠাটি স্ক্রোল করেন, তখন দর্শকের অনুসরণ করা উচিত। এটি করার জন্য, আমি বর্তমান scrollX এবং scrollY পজিশনগুলিকে ডুপ্লিকেট HTMLDocumentdata-* বৈশিষ্ট্য হিসাবে লুকিয়ে রাখি। চূড়ান্ত ব্লব তৈরি হওয়ার আগে, কিছুটা JS ইনজেকশন দেওয়া হয় যা পৃষ্ঠা লোডে আগুন দেয়:

// 4. Preserve current x,y scroll position of this page. See addOnPageLoad().
screenshot.dataset.scrollX = window.scrollX;
screenshot.dataset.scrollY = window.scrollY;

// 4.5. When screenshot loads (e.g. in blob URL), scroll it to the same location
// of this page. Do this by appending a window.onDOMContentLoaded listener
// which pulls out the screenshot (dupe's) saved scrollX/Y state on the DOM.
var script = document.createElement('script');
script.textContent = '(' + addOnPageLoad_.toString() + ')();'; // self calling.
screenshot.querySelector('body').appendChild(script);

// NOTE: Not to be invoked directly. When the screenshot loads, scroll it
// to the same x,y location of original page.
function addOnPageLoad() {
    window.addEventListener('DOMContentLoaded', function(e) {
    var scrollX = document.documentElement.dataset.scrollX || 0;
    var scrollY = document.documentElement.dataset.scrollY || 0;
    window.scrollTo(scrollX, scrollY);
    });

স্ক্রলিং জাল করা ছাপ দেয় যে আমরা আসল পৃষ্ঠার একটি অংশের স্ক্রিনশট করেছি, যখন বাস্তবে, আমরা সম্পূর্ণ জিনিসটি নকল করেছি এবং কেবল এটিকে পুনঃস্থাপন করেছি। #চতুর

ডেমো

কিন্তু ট্যাব ভাগ করার জন্য, আমাদের ক্রমাগত ট্যাবটি ক্যাপচার করতে হবে এবং দর্শকদের কাছে পাঠাতে হবে। এর জন্য আমি একটি ছোট নোড ওয়েবসকেট সার্ভার, অ্যাপ এবং বুকমার্কলেট লিখেছি যা প্রবাহ প্রদর্শন করে। আপনি যদি কোডটিতে আগ্রহী না হন তবে এখানে কাজ করা জিনিসগুলির একটি ছোট ভিডিও রয়েছে:

ভবিষ্যতের উন্নতি

একটি অপ্টিমাইজেশন প্রতিটি ফ্রেমে সমগ্র নথির নকল করা নয়। এটি অপব্যয় এবং এমন কিছু যা মিউটেশন অবজারভারের উদাহরণটি ভাল করে। আরেকটি উন্নতি হল urlsToAbsolute() এ আপেক্ষিক CSS ব্যাকগ্রাউন্ড ইমেজ পরিচালনা করা। এটি এমন কিছু যা বর্তমান স্ক্রিপ্ট বিবেচনা করে না।

পদ্ধতি 3: ক্রোম এক্সটেনশন API + বাইনারি ওয়েবসকেট

Google I/O 2012- এ, আমি একটি ব্রাউজার ট্যাবের বিষয়বস্তু স্ক্রিন শেয়ার করার জন্য আরেকটি পদ্ধতি প্রদর্শন করেছি। যাইহোক, এই এক একটি প্রতারক. এটির জন্য একটি Chrome এক্সটেনশন API প্রয়োজন: বিশুদ্ধ HTML5 জাদু নয়।

এটির উত্সটিও গিথুবে রয়েছে, তবে সারাংশটি হল:

  1. একটি .png dataURL হিসাবে বর্তমান ট্যাবটি ক্যাপচার করুন৷ ক্রোম এক্সটেনশনে সেই chrome.tabs.captureVisibleTab() এর জন্য একটি API রয়েছে।
  2. ডাটা ইউআরএলকে একটি Blob রূপান্তর করুন। convertDataURIToBlob() সহায়ক দেখুন।
  3. socket.responseType='blob' সেট করে বাইনারি ওয়েবসকেট ব্যবহার করে প্রতিটি ব্লব (ফ্রেম) দর্শকের কাছে পাঠান।

উদাহরণ

বর্তমান ট্যাবটিকে পিএনজি হিসাবে স্ক্রিনশট করার কোড এবং একটি ওয়েবসকেটের মাধ্যমে ফ্রেমটি পাঠানোর জন্য এখানে কোড রয়েছে:

var IMG_MIMETYPE = 'images/jpeg'; // Update to image/webp when crbug.com/112957 is fixed.
var IMG_QUALITY = 80; // [0-100]
var SEND_INTERVAL = 250; // ms

var ws = new WebSocket('ws://…', 'dumby-protocol');
ws.binaryType = 'blob';

function captureAndSendTab() {
    var opts = {format: IMG_MIMETYPE, quality: IMG_QUALITY};
    chrome.tabs.captureVisibleTab(null, opts, function(dataUrl) {
    // captureVisibleTab returns a dataURL. Decode it -> convert to blob -> send.
    ws.send(convertDataURIToBlob(dataUrl, IMG_MIMETYPE));
    });
}

var intervalId = setInterval(function() {
    if (ws.bufferedAmount == 0) {
    captureAndSendTab();
    }
}, SEND_INTERVAL);

ভবিষ্যতের উন্নতি

এর জন্য ফ্রেমরেট আশ্চর্যজনকভাবে ভাল, তবে এটি আরও ভাল হতে পারে। একটি উন্নতি হবে ডেটা ইউআরএলকে একটি ব্লবে রূপান্তর করার ওভারহেড অপসারণ করা। দুর্ভাগ্যবশত, chrome.tabs.captureVisibleTab() আমাদের শুধুমাত্র একটি dataURL দেয়। যদি এটি একটি ব্লব বা টাইপ করা অ্যারে ফেরত দেয়, আমরা নিজেরাই ব্লব-এ রূপান্তর না করে সরাসরি ওয়েবসকেটের মাধ্যমে পাঠাতে পারি। এটা ঘটতে crbug.com/32498 তারকা দয়া করে!

পদ্ধতি 4: WebRTC - প্রকৃত ভবিষ্যত

শেষ কিন্তু অন্তত না!

ব্রাউজারে স্ক্রিন শেয়ারিং এর ভবিষ্যত WebRTC দ্বারা উপলব্ধি করা হবে। আগস্ট 14, 2012-এ, দলটি ট্যাব বিষয়বস্তু ভাগ করার জন্য একটি WebRTC ট্যাব সামগ্রী ক্যাপচার API প্রস্তাব করেছে:

এই লোকটি প্রস্তুত না হওয়া পর্যন্ত আমাদের 1-3 পদ্ধতি বাকি আছে।

উপসংহার

তাই আজকের ওয়েব প্রযুক্তিতে ব্রাউজার ট্যাব শেয়ারিং সম্ভব!

কিন্তু... সেই বিবৃতিটি লবণের দানা দিয়ে নেওয়া উচিত। ঝরঝরে থাকাকালীন, এই নিবন্ধের কৌশলগুলি এক বা অন্য উপায়ে একটি দুর্দান্ত শেয়ারিং ইউএক্সের অভাব রয়েছে। WebRTC ট্যাব বিষয়বস্তু ক্যাপচার প্রচেষ্টার সাথে এটি সবই পরিবর্তিত হবে, কিন্তু এটি একটি বাস্তবতা না হওয়া পর্যন্ত, আমাদের কাছে ব্রাউজার প্লাগইন বা সীমিত সমাধান রয়েছে যা এখানে কভার করা হয়েছে।

আরো কৌশল আছে? একটি মন্তব্য পোস্ট করুন!