diff options
Diffstat (limited to 'extensions/chrome')
-rw-r--r-- | extensions/chrome/_locales/en/messages.json | 8 | ||||
-rw-r--r-- | extensions/chrome/common.js | 187 | ||||
-rw-r--r-- | extensions/chrome/inject_and_return.js | 28 | ||||
-rw-r--r-- | extensions/chrome/inject_exec.js | 74 | ||||
-rw-r--r-- | extensions/chrome/manifest.json | 23 |
5 files changed, 320 insertions, 0 deletions
diff --git a/extensions/chrome/_locales/en/messages.json b/extensions/chrome/_locales/en/messages.json new file mode 100644 index 0000000..eebbc14 --- /dev/null +++ b/extensions/chrome/_locales/en/messages.json @@ -0,0 +1,8 @@ +{ + "title": { + "message": "VK Player Controller Client" + }, + "description_short": { + "message": "Chrome client for VK Player Controller app." + } +} diff --git a/extensions/chrome/common.js b/extensions/chrome/common.js new file mode 100644 index 0000000..30dc55a --- /dev/null +++ b/extensions/chrome/common.js @@ -0,0 +1,187 @@ +function init() { + // receive messages from webpage + chrome.runtime.onMessageExternal.addListener(receiveMessage); +} +function receiveMessage(msg, sender, sendResponse) { + if (msg.cmd == "injection_result") { + var obj = Injections.get(msg.id); + if (obj) obj.addResponse(sender.tab.id, msg.data); + } +} +function extend(dest, source) { + for (var i in source) { + dest[i] = source[i]; + } +} +function getWebSocket() { + return window.WebSocket || window.MozWebSocket; +} +function print() { + var msgs = [], i, tmp; + for (i = 0; i < arguments.length; i++) { + if (arguments[i] instanceof Error) tmp = [arguments[i], arguments[i].stack]; + else tmp = arguments[i]; + msgs.push(tmp); + } + + try { + console.log.apply(console, msgs); + } catch(e) {} +} +function getExtensionId() { + return chrome.i18n.getMessage("@@extension_id"); +} +function getVKTabs(callback) { + var vkTabs = []; + chrome.tabs.query({}, function(tabs) { + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + if (tab.url.match(new RegExp('https?://vk.com/.*', 'gi'))) { + vkTabs.push(tab); + } + } + callback(vkTabs); + }); +} +function executeCommand(cmd) { + var injId = Injections.getNextId(); + var code_inj = "var el = document.createElement('script'); el.src = chrome.extension.getURL('inject_and_return.js'); document.body.appendChild(el); var el1 = document.createElement('script'); el1.textContent = 'window.__vkpc_extid=\""+getExtensionId()+"\"; window.__vkpc_injid="+injId+"'; document.body.appendChild(el1)"; + var code_exec = "var el = document.createElement('script'); el.src = chrome.extension.getURL('inject_exec.js'); document.body.appendChild(el); var el1 = document.createElement('script'); el1.textContent = 'window.__vkpc_cmd=\""+cmd+"\"'; document.body.appendChild(el1)"; + + getVKTabs(function(tabs) { + if (!tabs.length) return; + + var injResponses, activeTabId = null; + var onDone = function() { + var ok = {nowPlaying: null, lsSource: null, recentlyPlayed: null, active: activeTabId, last: null}; + var results = injResponses.results, lsSource = injResponses.lsSource; + + for (var i = 0; i < results.length; i++) { + var data = results[i].data, id = results[i].tab; + ok.last = id; + + if (data.havePlayer && (data.isPlaying || typeof data.trackId == 'string')) { + ok.recentlyPlayed = id; + } + if (data.isPlaying) { + ok.nowPlaying = id; + } + if (lsSource && lsSource == data.instanceId) { + ok.lsSource = id; + } + } + injResponses.unregister(); + + var rightId = ok.nowPlaying || ok.lsSource || ok.recentlyPlayed || ok.active || ok.last; + if (rightId) { + chrome.tabs.executeScript(rightId, {code: code_exec}); + } + }; + injResponses = new InjectionResponses(injId, tabs.length, onDone); + + for (var i = 0; i < tabs.length; i++) { + if (tabs[i].active) activeTabId = tabs[i].id; + chrome.tabs.executeScript(tabs[i].id, { + code: code_inj + }); + } + }); +} + +var Injections = { + id: 0, + objs: {}, + getNextId: function() { + return ++this.id; + }, + get: function(id) { + return this.objs[id] || false; + }, + register: function(id, obj) { + this.objs[id] = obj; + }, + unregister: function(id) { + if (this.objs[id] !== undefined) delete this.objs[id]; + } +}; + +var WSClient = new function() { + var STATUS_NONE = 0, STATUS_OK = 1, STATUS_ERR = 2; + var _ws = getWebSocket(), ws; + var _status = STATUS_NONE; + var ping_timer, reconnect_timer; + + if (!_ws) return; + + function setTimers() { + ping_timer = setInterval(function() { + if (ws) ws.send("PING"); + }, 30000); + } + function unsetTimers() { + clearInterval(ping_timer); + } + + function connect() { + _status = STATUS_NONE; + + print("[connect]"); + ws = new _ws("ws://localhost:52178", "signaling-protocol"); + ws.onopen = function() { + _status = STATUS_OK; + setTimers(); + }; + ws.onerror = function() { + unsetTimers(); + if (_status != STATUS_ERR) { + _status = STATUS_ERR; + tryToReconnect(); + } + } + ws.onclose = function() { + unsetTimers(); + if (_status != STATUS_ERR) { + _status = STATUS_ERR; + tryToReconnect(); + } + }; + ws.onmessage = function(e) { + onCommand(e.data); + }; + } + function tryToReconnect() { + print("[tryToReconnect]"); + + clearTimeout(reconnect_timer); + reconnect_timer = setTimeout(connect, 5000); + } + function onCommand(msg) { + executeCommand(msg); + } + + connect(); +}; + +function InjectionResponses(id, count, callback) { + this.id = id; + this.results = []; + this.lsSource = null; + this.maxCount = count; + this.callback = callback || function() {}; + + Injections.register(this.id, this); +} +extend(InjectionResponses.prototype, { + addResponse: function(id, response) { + this.results.push({tab: id, data: response}); + if (!this.lsSource && response && response.lastInstanceId) this.lsSource = response.lastInstanceId; + if (this.results.length == this.maxCount) { + this.callback(); + } + }, + unregister: function() { + Injections.unregister(this.id); + } +}); + +init(); diff --git a/extensions/chrome/inject_and_return.js b/extensions/chrome/inject_and_return.js new file mode 100644 index 0000000..ebb2827 --- /dev/null +++ b/extensions/chrome/inject_and_return.js @@ -0,0 +1,28 @@ +(function() { + function getLastInstanceId() { + var id = null, pp = ls.get('pad_playlist'); + if (pp && pp.source) id = pp.source; + return id; + } + + var data = {}; + try { + var havePlayer = window.audioPlayer !== undefined; + var havePlaylist = havePlayer && !!padAudioPlaylist(); + + data = { + havePlayer: havePlayer, + havePlaylist: havePlaylist, + isPlaying: havePlayer && window.audioPlayer.player && !window.audioPlayer.player.paused(), + instanceId: window.curNotifier && curNotifier.instance_id, + trackId: havePlayer && audioPlayer.id, + lastInstanceId: getLastInstanceId() + }; + } catch(e) {} + + chrome.runtime.sendMessage(window.__vkpc_extid, { + cmd: "injection_result", + id: parseInt(window.__vkpc_injid, 10), + data: data + }); +})(); diff --git a/extensions/chrome/inject_exec.js b/extensions/chrome/inject_exec.js new file mode 100644 index 0000000..c1df18f --- /dev/null +++ b/extensions/chrome/inject_exec.js @@ -0,0 +1,74 @@ +(function() { + function vkAudio__getPlayFirstId() { + var id = currentAudioId() || ls.get('audio_id') || (window.audioPlaylist && audioPlaylist.start); + return id || null; + } + function vkAudio__executeAfterPadLoading(f) { + Pads.show('mus'); + window.onPlaylistLoaded = function() { + if (f) { + try { + f(); + } catch(e) {} + } + setTimeout(function() { + Pads.show('mus'); + }, 10); + } + } + function vkAudio__next() { + console.log("Next"); + window.audioPlayer && audioPlayer.nextTrack(true, !window.audioPlaylist); + } + function vkAudio__prev() { + console.log("Prev"); + window.audioPlayer && audioPlayer.prevTrack(true, !window.audioPlaylist); + } + function vkAudio__playPause() { + console.log("PlayPause"); + if (!window.audioPlayer || !padAudioPlaylist()) { + stManager.add(['audioplayer.js'], function() { + vkAudio__executeAfterPadLoading(function() { + var plist = padAudioPlaylist(), id = vkAudio__getPlayFirstId(); + if (id) { + playAudioNew(id); + } else if (plist && plist.start) { + playAudioNew(plist.start); + } + }); + }); + } else { + if (window.audioPlayer && audioPlayer.player) { + if (audioPlayer.player.paused()) { + audioPlayer.playTrack(); + } else { + audioPlayer.pauseTrack(); + } + } + } + } + + try { + var data = window.__vkpc_cmd; + if (data) { + switch (data) { + case "next": + vkAudio__next(); + break; + + case "prev": + vkAudio__prev(); + break; + + case "play": + case "pause": + vkAudio__playPause(); + break; + } + + delete window.__vkpc_cmd; + } + } catch (e) { + console.log('[VKPC]', e, e.stack); + } +})(); diff --git a/extensions/chrome/manifest.json b/extensions/chrome/manifest.json new file mode 100644 index 0000000..f7b29d7 --- /dev/null +++ b/extensions/chrome/manifest.json @@ -0,0 +1,23 @@ +{ + "manifest_version": 2, + "name": "__MSG_title__", + "description": "__MSG_description_short__", + "version": "0.1", + "default_locale": "en", + "permissions": [ + "background", + "tabs", + "https://vk.com/*", + "http://vk.com/*", + "https://*.vk.com/*", + "http://*.vk.com/*" + ], + "background": { + "scripts": ["common.js"] + }, + "externally_connectable": { + "matches": ["https://vk.com/*", "http://vk.com/*", "https://*.vk.com/*", "http://*.vk.com/*"] + }, + "content_security_policy": "script-src 'self' 'unsafe-eval' https://vk.com; object-src 'self' 'unsafe-eval'", + "web_accessible_resources": ["inject_and_return.js", "inject_exec.js"] +} |