इस दस्तावेज़ का मकसद, Sencha Ext JS की मदद से Chrome ऐप्लिकेशन बनाना है फ़्रेमवर्क शामिल है. इस लक्ष्य को पाने के लिए, हम सेंचा के बनाए गए मीडिया प्लेयर ऐप्लिकेशन के बारे में बात करेंगे. सोर्स कोड और एपीआई से जुड़े दस्तावेज़, GitHub पर उपलब्ध हैं.
यह ऐप्लिकेशन, उपयोगकर्ता के उपलब्ध मीडिया सर्वर का पता लगाता है. इनमें, कंप्यूटर से कनेक्ट किए गए मीडिया डिवाइस और एक ऐसा सॉफ़्टवेयर है जो नेटवर्क पर मीडिया को मैनेज करता है. लोग मीडिया ब्राउज़ कर सकते हैं, नेटवर्क पर कॉन्टेंट चला सकते हैं या कॉन्टेंट सेव कर सकते हैं ऑफ़लाइन.
यहां कुछ मुख्य चीज़ों के बारे में बताया गया है, जो Sencha Ext JS का इस्तेमाल करके मीडिया प्लेयर ऐप्लिकेशन बनाने के लिए ज़रूरी हैं:
- मेनिफ़ेस्ट बनाएं,
manifest.json
. - इवेंट पेज बनाएं,
background.js
. - सैंडबॉक्स ऐप्लिकेशन का लॉजिक.
- Chrome ऐप्लिकेशन और सैंडबॉक्स की गई फ़ाइलों के बीच कम्यूनिकेट करें.
- मीडिया सर्वर खोजें.
- मीडिया एक्सप्लोर करें और चलाएं.
- मीडिया को ऑफ़लाइन सेव करें.
मेनिफ़ेस्ट बनाएं
सभी Chrome ऐप्स के लिए एक मेनिफ़ेस्ट फ़ाइल की ज़रूरत होती है, जिसमें वह जानकारी होती है जिसे Chrome को लॉन्च करने के लिए ज़रूरत होती है दिखाई देता है. जैसा कि मेनिफ़ेस्ट में बताया गया है, मीडिया प्लेयर ऐप्लिकेशन "ऑफ़लाइन_enabled" है; मीडिया ऐसेट इस सुविधा को स्थानीय तौर पर सेव किया जाता है, ऐक्सेस किया जा सकता है, और चलाया जाता है. इससे कोई फ़र्क़ नहीं पड़ता है कि आपने इसे कनेक्ट किया है या नहीं.
"सैंडबॉक्स" फ़ील्ड का इस्तेमाल ऐप्लिकेशन के मुख्य लॉजिक को यूनीक ऑरिजिन में सैंडबॉक्स करने के लिए किया जाता है. सभी सैंडबॉक्स किए गए कॉन्टेंट को Chrome ऐप्लिकेशन की कॉन्टेंट की सुरक्षा के बारे में नीति से छूट दी गई है. हालांकि, वह सीधे तौर पर Chrome ऐप्लिकेशन एपीआई. मेनिफ़ेस्ट में "सॉकेट" भी शामिल होता है अनुमति; मीडिया प्लेयर ऐप्लिकेशन socket 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"
]
}
]
}
इवेंट पेज बनाएं
सभी Chrome ऐप्स को ऐप्लिकेशन लॉन्च करने के लिए 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 ऐप्स एक ऐसे कंट्रोल किए गए एनवायरमेंट में चलते हैं जो सख्त कॉन्टेंट की सुरक्षा के बारे में नीति को लागू करता है
(सीएसपी). Ext JS कॉम्पोनेंट को रेंडर करने के लिए, मीडिया प्लेयर ऐप्लिकेशन को कुछ खास अधिकारों की ज़रूरत होती है. यहां की यात्रा पर हूं
CSP का पालन करते हैं और ऐप्लिकेशन के लॉजिक को एक्ज़ीक्यूट करते हैं, तो ऐप्लिकेशन का मुख्य पेज index.html
, एक iframe बनाता है जो
सैंडबॉक्स एनवायरमेंट की तरह काम करता है:
<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 Post Message API का इस्तेमाल करके किया जाता है.
फ़ाइलों के बीच बातचीत करें
मीडिया प्लेयर ऐप्लिकेशन को Chrome ऐप्लिकेशन एपीआई ऐक्सेस करने के लिए. जैसे, मीडिया के लिए नेटवर्क से क्वेरी करना
सर्वर, app.js
संदेशों को index.js पर पोस्ट करता है. सैंडबॉक्स किए गए app.js
के उलट, index.js
ये काम कर सकता है
Chrome ऐप्लिकेशन के एपीआई को सीधे ऐक्सेस करें.
index.js
iframe बनाता है:
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
को मैसेज भेजकर, पासकोड का अनुरोध किया है
'एक्सटेंशन-baseurl':
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
, मीडिया प्लेयर ऐप्लिकेशन को किसी भी
खोजे गए मीडिया सर्वर और मीडिया सर्वर से मीडिया डेटा पाएं. Upnp.js
इनका इस्तेमाल भी करता है
मीडिया सर्वर के डेटा को पार्स करने के लिए, soapclient.js का इस्तेमाल किया जा सकता है. इस सेक्शन के बाकी हिस्से में यह जानकारी दी गई है
देखें.
मैसेज पोस्ट करें
जब कोई उपयोगकर्ता मीडिया प्लेयर ऐप्लिकेशन के बीच में मीडिया सर्वर बटन पर क्लिक करता है, MediaServers.js
discoverServers()
को कॉल करता है. यह फ़ंक्शन सबसे पहले, खोज से जुड़े उन अनुरोधों की जांच करता है जिनके बाकी अनुरोध बाकी हैं. अगर
सही है, तो उन्हें निरस्त कर देता है, ताकि नया अनुरोध किया जा सके. इसके बाद, कंट्रोलर
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
ने 'upnp-discover' गाने को सुना app.js
से मैसेज आया है और कॉल करके जवाब दिया जा रहा है
upnpDiscover()
. मीडिया सर्वर का पता चलने पर index.js
, मीडिया सर्वर के डोमेन को एक्सट्रैक्ट करता है
पैरामीटर से पैरामीटर का इस्तेमाल करके, सर्वर को स्थानीय तौर पर सेव करता है, मीडिया सर्वर के डेटा को फ़ॉर्मैट करता है, और डेटा को
MediaServer
कंट्रोलर.
मीडिया सर्वर डेटा पार्स करें
जब Upnp.js
को किसी नए मीडिया सर्वर का पता चलता है, तो वह डिवाइस की जानकारी लेता है और
मीडिया सर्वर के डेटा को ब्राउज़ और पार्स करने के लिए कोई सोपअनुरोध; soapclient.js
, मीडिया एलिमेंट को पार्स करता है
टैग के नाम से व्यवस्थित करें.
मीडिया सर्वर से कनेक्ट करें
Upnp.js
खोजे गए मीडिया सर्वर से कनेक्ट करता है और Chrome ऐप्लिकेशन सॉकेट का इस्तेमाल करके मीडिया डेटा पाता है
एपीआई:
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);
});
});
});
मीडिया एक्सप्लोर करें और चलाएं
Media Explorer कंट्रोलर मीडिया सर्वर फ़ोल्डर में मौजूद सभी मीडिया फ़ाइलों की सूची बनाता है और
यह मीडिया प्लेयर ऐप्लिकेशन की विंडो में ब्रेडक्रंब नेविगेशन को अपडेट करता है. जब कोई उपयोगकर्ता
मीडिया फ़ाइल चुनता है, तो कंट्रोलर 'play-media' के साथ 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 Library से की जाती है. इस बारे में और पढ़ें filer.js पेश करते हैं.
यह प्रोसेस तब शुरू होती है, जब कोई उपयोगकर्ता एक या उससे ज़्यादा फ़ाइलें चुनता है और 'ऑफ़लाइन ले जाएं' को शुरू करता है कार्रवाई.
Media Explorer कंट्रोलर एक कुंजी 'download-media' के साथ, 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
मीडिया फ़ाइल की सूची और मीडिया को अपडेट करता है
प्लेयर ट्री पैनल.