এই ডকটির লক্ষ্য হল আপনাকে Sencha Ext JS ফ্রেমওয়ার্কের সাথে Chrome Apps তৈরি করা শুরু করা। এই লক্ষ্য অর্জনের জন্য, আমরা সেঞ্চা দ্বারা নির্মিত একটি মিডিয়া প্লেয়ার অ্যাপে ডুব দেব। সোর্স কোড এবং API ডকুমেন্টেশন GitHub এ উপলব্ধ।
এই অ্যাপটি একটি ব্যবহারকারীর উপলব্ধ মিডিয়া সার্ভারগুলি আবিষ্কার করে, যার মধ্যে পিসির সাথে সংযুক্ত মিডিয়া ডিভাইস এবং নেটওয়ার্কের মাধ্যমে মিডিয়া পরিচালনা করে এমন সফ্টওয়্যার রয়েছে৷ ব্যবহারকারীরা মিডিয়া ব্রাউজ করতে, নেটওয়ার্কে খেলতে বা অফলাইনে সংরক্ষণ করতে পারে।
Sencha Ext JS ব্যবহার করে একটি মিডিয়া প্লেয়ার অ্যাপ তৈরি করতে আপনাকে যা করতে হবে তা এখানে রয়েছে:
- ম্যানিফেস্ট,
manifest.json
তৈরি করুন। - ইভেন্ট পৃষ্ঠা ,
background.js
তৈরি করুন। - স্যান্ডবক্স অ্যাপের যুক্তি।
- Chrome অ্যাপ এবং স্যান্ডবক্স করা ফাইলগুলির মধ্যে যোগাযোগ করুন৷
- মিডিয়া সার্ভার আবিষ্কার করুন।
- মিডিয়া অন্বেষণ এবং খেলা.
- মিডিয়া অফলাইনে সংরক্ষণ করুন।
ম্যানিফেস্ট তৈরি করুন
সমস্ত Chrome অ্যাপ্লিকেশানগুলির জন্য একটি ম্যানিফেস্ট ফাইল প্রয়োজন যাতে Chrome অ্যাপগুলি লঞ্চ করার জন্য প্রয়োজনীয় তথ্য ধারণ করে৷ ম্যানিফেস্টে নির্দেশিত হিসাবে, মিডিয়া প্লেয়ার অ্যাপটি "অফলাইন_সক্ষম"; মিডিয়া সম্পদ স্থানীয়ভাবে সংরক্ষিত, অ্যাক্সেস করা এবং সংযোগ নির্বিশেষে চালানো যাবে.
"স্যান্ডবক্স" ক্ষেত্রটি একটি অনন্য মূলে অ্যাপের মূল যুক্তিকে স্যান্ডবক্স করতে ব্যবহৃত হয়। সমস্ত স্যান্ডবক্সযুক্ত সামগ্রী Chrome অ্যাপ সামগ্রী নিরাপত্তা নীতি থেকে মুক্ত, কিন্তু সরাসরি Chrome অ্যাপ APIগুলি অ্যাক্সেস করতে পারে না৷ ম্যানিফেস্টে "সকেট" অনুমতিও অন্তর্ভুক্ত রয়েছে; মিডিয়া প্লেয়ার অ্যাপ্লিকেশন নেটওয়ার্কের মাধ্যমে একটি মিডিয়া সার্ভারের সাথে সংযোগ করতে সকেট API ব্যবহার করে।
{
"name": "Video Player",
"description": "Features network media discovery and playlist management",
"version": "1.0.0",
"manifest_version": 2,
"offline_enabled": true,
"app": {
"background": {
"scripts": [
"background.js"
]
}
},
...
"sandbox": {
"pages": ["sandbox.html"]
},
"permissions": [
"experimental",
"http://*/*",
"unlimitedStorage",
{
"socket": [
"tcp-connect",
"udp-send-to",
"udp-bind"
]
}
]
}
ইভেন্ট পৃষ্ঠা তৈরি করুন
সমস্ত ক্রোম অ্যাপ্লিকেশানের অ্যাপ্লিকেশান চালু করতে background.js
প্রয়োজন৷ মিডিয়া প্লেয়ারের প্রধান পৃষ্ঠা, index.html
, নির্দিষ্ট মাত্রা সহ একটি উইন্ডোতে খোলে:
chrome.app.runtime.onLaunched.addListener(function(launchData) {
var opt = {
width: 1000,
height: 700
};
chrome.app.window.create('index.html', opt, function (win) {
win.launchData = launchData;
});
});
স্যান্ডবক্স অ্যাপের যুক্তি
Chrome অ্যাপ্লিকেশানগুলি একটি নিয়ন্ত্রিত পরিবেশে চলে যা একটি কঠোর সামগ্রী নিরাপত্তা নীতি (CSP) প্রয়োগ করে৷ Ext JS উপাদান রেন্ডার করার জন্য মিডিয়া প্লেয়ার অ্যাপটির কিছু উচ্চতর সুবিধার প্রয়োজন। CSP মেনে চলতে এবং অ্যাপ লজিক কার্যকর করতে, অ্যাপের প্রধান পৃষ্ঠা, index.html
, একটি আইফ্রেম তৈরি করে যা একটি স্যান্ডবক্স পরিবেশ হিসেবে কাজ করে:
<iframe id="sandbox-frame" sandbox="allow-scripts" src="sandbox.html"></iframe>
iframe নির্দেশ করে sandbox.html যা Ext JS অ্যাপ্লিকেশনের জন্য প্রয়োজনীয় ফাইলগুলিকে অন্তর্ভুক্ত করে:
<html>
<head>
<link rel="stylesheet" type="text/css" href="resources/css/app.css" />'
<script src="sdk/ext-all-dev.js"></script>'
<script src="lib/ext/data/PostMessage.js"></script>'
<script src="lib/ChromeProxy.js"></script>'
<script src="app.js"></script>
</head>
<body></body>
</html>
app.js স্ক্রিপ্ট সমস্ত Ext JS কোড নির্বাহ করে এবং মিডিয়া প্লেয়ারের ভিউ রেন্ডার করে। যেহেতু এই স্ক্রিপ্টটি স্যান্ডবক্স করা হয়েছে, তাই এটি সরাসরি Chrome অ্যাপ এপিআই অ্যাক্সেস করতে পারে না। app.js
এবং নন-স্যান্ডবক্সড ফাইলের মধ্যে যোগাযোগ HTML5 পোস্ট মেসেজ API ব্যবহার করে করা হয়।
ফাইলগুলির মধ্যে যোগাযোগ করুন
মিডিয়া প্লেয়ার অ্যাপ যাতে ক্রোম অ্যাপ এপিআই অ্যাক্সেস করতে পারে, যেমন মিডিয়া সার্ভারের জন্য নেটওয়ার্ক অনুসন্ধান করা, app.js
index.js- এ বার্তা পোস্ট করে। স্যান্ডবক্সড app.js
এর বিপরীতে, index.js
সরাসরি Chrome অ্যাপ API-এ অ্যাক্সেস করতে পারে।
index.js
আইফ্রেম তৈরি করে:
var iframe = document.getElementById('sandbox-frame');
iframeWindow = iframe.contentWindow;
এবং স্যান্ডবক্স করা ফাইল থেকে বার্তা শোনে:
window.addEventListener('message', function(e) {
var data= e.data,
key = data.key;
console.log('[index.js] Post Message received with key ' + key);
switch (key) {
case 'extension-baseurl':
extensionBaseUrl(data);
break;
case 'upnp-discover':
upnpDiscover(data);
break;
case 'upnp-browse':
upnpBrowse(data);
break;
case 'play-media':
playMedia(data);
break;
case 'download-media':
downloadMedia(data);
break;
case 'cancel-download':
cancelDownload(data);
break;
default:
console.log('[index.js] unidentified key for Post Message: "' + key + '"');
}
}, false);
নিম্নলিখিত উদাহরণে, app.js
index.js
এ একটি বার্তা পাঠায় যা 'এক্সটেনশন-বেসউর্ল' কী অনুরোধ করে:
Ext.data.PostMessage.request({
key: 'extension-baseurl',
success: function(data) {
//...
}
});
index.js
অনুরোধটি গ্রহণ করে, ফলাফল নির্ধারণ করে এবং বেস ইউআরএলটি ফেরত পাঠিয়ে উত্তর দেয়:
function extensionBaseUrl(data) {
data.result = chrome.extension.getURL('/');
iframeWindow.postMessage(data, '*');
}
মিডিয়া সার্ভার আবিষ্কার করুন
মিডিয়া সার্ভার আবিষ্কার করার জন্য অনেক কিছু আছে। একটি উচ্চ স্তরে, উপলব্ধ মিডিয়া সার্ভারগুলি অনুসন্ধান করার জন্য একটি ব্যবহারকারীর ক্রিয়া দ্বারা আবিষ্কার কর্মপ্রবাহ শুরু হয়। MediaServer কন্ট্রোলার index.js
এ একটি বার্তা পোস্ট করে; index.js
এই বার্তাটি শোনে এবং প্রাপ্ত হলে Upnp.js কে কল করে।
Upnp library
মিডিয়া প্লেয়ার অ্যাপটিকে যেকোনো আবিষ্কৃত মিডিয়া সার্ভারের সাথে সংযোগ করতে এবং মিডিয়া সার্ভার থেকে মিডিয়া ডেটা গ্রহণ করতে Chrome অ্যাপ সকেট API ব্যবহার করে। Upnp.js
মিডিয়া সার্ভার ডেটা পার্স করতে soapclient.js ব্যবহার করে। এই বিভাগের বাকি অংশ এই কর্মপ্রবাহকে আরো বিস্তারিতভাবে বর্ণনা করে।
বার্তা পোস্ট করুন
যখন একজন ব্যবহারকারী মিডিয়া প্লেয়ার অ্যাপের কেন্দ্রে মিডিয়া সার্ভার বোতামে ক্লিক করেন, তখন MediaServers.js
discoverServers()
কল করে। এই ফাংশনটি প্রথমে কোনও অসামান্য আবিষ্কারের অনুরোধের জন্য পরীক্ষা করে এবং সত্য হলে, সেগুলি বাতিল করে যাতে নতুন অনুরোধ শুরু করা যায়। এরপরে, নিয়ামক একটি কী upnp-আবিষ্কার এবং দুটি কলব্যাক শ্রোতাদের সাথে index.js
এ একটি বার্তা পোস্ট করে:
me.activeDiscoverRequest = Ext.data.PostMessage.request({
key: 'upnp-discover',
success: function(data) {
var items = [];
delete me.activeDiscoverRequest;
if (serversGraph.isDestroyed) {
return;
}
mainBtn.isLoading = false;
mainBtn.removeCls('pop-in');
mainBtn.setIconCls('ico-server');
mainBtn.setText('Media Servers');
//add servers
Ext.each(data, function(server) {
var icon,
urlBase = server.urlBase;
if (urlBase) {
if (urlBase.substr(urlBase.length-1, 1) === '/'){
urlBase = urlBase.substr(0, urlBase.length-1);
}
}
if (server.icons && server.icons.length) {
if (server.icons[1]) {
icon = server.icons[1].url;
}
else {
icon = server.icons[0].url;
}
icon = urlBase + icon;
}
items.push({
itemId: server.id,
text: server.friendlyName,
icon: icon,
data: server
});
});
...
},
failure: function() {
delete me.activeDiscoverRequest;
if (serversGraph.isDestroyed) {
return;
}
mainBtn.isLoading = false;
mainBtn.removeCls('pop-in');
mainBtn.setIconCls('ico-error');
mainBtn.setText('Error...click to retry');
}
});
কল upnpDiscover()
index.js
app.js
থেকে 'upnp-discover' বার্তা শোনে এবং upnpDiscover()
কল করে প্রতিক্রিয়া জানায়। যখন একটি মিডিয়া সার্ভার আবিষ্কৃত হয়, তখন index.js
পরামিতিগুলি থেকে মিডিয়া সার্ভার ডোমেন বের করে, সার্ভারটিকে স্থানীয়ভাবে সংরক্ষণ করে, মিডিয়া সার্ভারের ডেটা ফর্ম্যাট করে এবং ডেটা MediaServer
কন্ট্রোলারে পুশ করে।
মিডিয়া সার্ভার ডেটা পার্স করুন
যখন Upnp.js
একটি নতুন মিডিয়া সার্ভার আবিষ্কার করে, তখন এটি ডিভাইসের একটি বিবরণ পুনরুদ্ধার করে এবং মিডিয়া সার্ভারের ডেটা ব্রাউজ ও পার্স করার জন্য একটি Soaprequest পাঠায়; soapclient.js
একটি নথিতে ট্যাগ নামের মাধ্যমে মিডিয়া উপাদানগুলিকে পার্স করে।
মিডিয়া সার্ভারের সাথে সংযোগ করুন
Upnp.js
আবিষ্কৃত মিডিয়া সার্ভারের সাথে সংযোগ করে এবং Chrome অ্যাপ সকেট API ব্যবহার করে মিডিয়া ডেটা গ্রহণ করে:
socket.create("udp", {}, function(info) {
var socketId = info.socketId;
//bind locally
socket.bind(socketId, "0.0.0.0", 0, function(info) {
//pack upnp message
var message = String.toBuffer(UPNP_MESSAGE);
//broadcast to upnp
socket.sendTo(socketId, message, UPNP_ADDRESS, UPNP_PORT, function(info) {
// Wait 1 second
setTimeout(function() {
//receive
socket.recvFrom(socketId, function(info) {
//unpack message
var data = String.fromBuffer(info.data),
servers = [],
locationReg = /^location:/i;
//extract location info
if (data) {
data = data.split("\r\n");
data.forEach(function(value) {
if (locationReg.test(value)){
servers.push(value.replace(locationReg, "").trim());
}
});
}
//success
callback(servers);
});
}, 1000);
});
});
});
মিডিয়া অন্বেষণ এবং খেলা
MediaExplorer কন্ট্রোলার একটি মিডিয়া সার্ভার ফোল্ডারের ভিতরে সমস্ত মিডিয়া ফাইল তালিকাভুক্ত করে এবং মিডিয়া প্লেয়ার অ্যাপ উইন্ডোতে ব্রেডক্রাম্ব নেভিগেশন আপডেট করার জন্য দায়ী। যখন একজন ব্যবহারকারী একটি মিডিয়া ফাইল নির্বাচন করেন, তখন কন্ট্রোলার 'প্লে-মিডিয়া' কী সহ index.js
এ একটি বার্তা পোস্ট করে:
onFileDblClick: function(explorer, record) {
var serverPanel, node,
type = record.get('type'),
url = record.get('url'),
name = record.get('name'),
serverId= record.get('serverId');
if (type === 'audio' || type === 'video') {
Ext.data.PostMessage.request({
key : 'play-media',
params : {
url: url,
name: name,
type: type
}
});
}
},
index.js
এই পোস্ট বার্তা শোনে এবং playMedia()
কল করে প্রতিক্রিয়া জানায় :
function playMedia(data) {
var type = data.params.type,
url = data.params.url,
playerCt = document.getElementById('player-ct'),
audioBody = document.getElementById('audio-body'),
videoBody = document.getElementById('video-body'),
mediaEl = playerCt.getElementsByTagName(type)[0],
mediaBody = type === 'video' ? videoBody : audioBody,
isLocal = false;
//save data
filePlaying = {
url : url,
type: type,
name: data.params.name
};
//hide body els
audioBody.style.display = 'none';
videoBody.style.display = 'none';
var animEnd = function(e) {
//show body el
mediaBody.style.display = '';
//play media
mediaEl.play();
//clear listeners
playerCt.removeEventListener( 'transitionend', animEnd, false );
animEnd = null;
};
//load media
mediaEl.src = url;
mediaEl.load();
//animate in player
playerCt.addEventListener( 'transitionend', animEnd, false );
playerCt.style.transform = "translateY(0)";
//reply postmessage
data.result = true;
sendMessage(data);
}
মিডিয়া অফলাইনে সংরক্ষণ করুন
মিডিয়া অফলাইনে সংরক্ষণ করার জন্য সবচেয়ে বেশি পরিশ্রম করা হয় filer.js লাইব্রেরি দ্বারা। Introducing filer.js- এ আপনি এই লাইব্রেরিটি আরও পড়তে পারেন।
প্রক্রিয়াটি শুরু হয় যখন একজন ব্যবহারকারী এক বা একাধিক ফাইল নির্বাচন করে এবং 'অফলাইন নিন' অ্যাকশন শুরু করে। MediaExplorer কন্ট্রোলার একটি কী 'ডাউনলোড-মিডিয়া' সহ index.js
এ একটি বার্তা পোস্ট করে; index.js
এই বার্তাটি শোনে এবং ডাউনলোড প্রক্রিয়া শুরু করতে downloadMedia()
ফাংশনকে কল করে:
function downloadMedia(data) {
DownloadProcess.run(data.params.files, function() {
data.result = true;
sendMessage(data);
});
}
DownloadProcess
ইউটিলিটি পদ্ধতি মিডিয়া সার্ভার থেকে ডেটা পাওয়ার জন্য একটি xhr অনুরোধ তৈরি করে এবং সমাপ্তির স্থিতির জন্য অপেক্ষা করে। এটি অনলোড কলব্যাক শুরু করে যা প্রাপ্ত সামগ্রী পরীক্ষা করে এবং filer.js
ফাংশন ব্যবহার করে স্থানীয়ভাবে ডেটা সংরক্ষণ করে:
filer.write(
saveUrl,
{
data: Util.arrayBufferToBlob(fileArrayBuf),
type: contentType
},
function(fileEntry, fileWriter) {
console.log('file saved!');
//increment downloaded
me.completedFiles++;
//if reached the end, finalize the process
if (me.completedFiles === me.totalFiles) {
sendMessage({
key : 'download-progresss',
totalFiles : me.totalFiles,
completedFiles : me.completedFiles
});
me.completedFiles = me.totalFiles = me.percentage = me.downloadedFiles = 0;
delete me.percentages;
//reload local
loadLocalFiles(callback);
}
},
function(e) {
console.log(e);
}
);
ডাউনলোড প্রক্রিয়া শেষ হলে, MediaExplorer
মিডিয়া ফাইল তালিকা এবং মিডিয়া প্লেয়ার ট্রি প্যানেল আপডেট করে।