summaryrefslogtreecommitdiff
path: root/opera
diff options
context:
space:
mode:
authorch1p <me@ch1p.com>2015-08-14 01:04:22 +0300
committerch1p <me@ch1p.com>2015-08-14 01:04:22 +0300
commit8c1a7423a0e526f2896d17be768abeccbeb77ad7 (patch)
tree67ad777e65ff6b0cca64a27ab5bb8455b575ffae /opera
initial
Diffstat (limited to 'opera')
-rw-r--r--opera/bg.js192
-rw-r--r--opera/common.js270
-rw-r--r--opera/icons/128.pngbin0 -> 7780 bytes
-rw-r--r--opera/icons/16.pngbin0 -> 592 bytes
-rw-r--r--opera/icons/32.pngbin0 -> 1806 bytes
-rw-r--r--opera/manifest.json30
-rw-r--r--opera/vkpc.js709
7 files changed, 1201 insertions, 0 deletions
diff --git a/opera/bg.js b/opera/bg.js
new file mode 100644
index 0000000..91fea9a
--- /dev/null
+++ b/opera/bg.js
@@ -0,0 +1,192 @@
+var wsc, injectInterval;
+
+function init() {
+ // receive messages from webpage
+ chrome.runtime.onMessageExternal.addListener(function(msg, sender, sendResponse) {
+ if (msg.cmd == "injection_result") {
+ var obj = Injections.get(msg.id);
+ if (obj) {
+ obj.addResponse(sender.tab.id, msg.data);
+ }
+ }
+ if (msg.cmd == "to_app") {
+ // log('to_app received', msg.data);
+ wsc.send(msg.data);
+ }
+ });
+
+ // connect to the app
+ wsc = new WSClient("wss://vkpc-local.ch1p.com:56130", "signaling-protocol", {
+ onopen: function() {
+ Controller.clear();
+ this.send({command: 'setBrowser'});
+ },
+ onmessage: function(cmd) {
+ var json = JSON.parse(cmd);
+ switch (json.command) {
+ case 'set_sid':
+ Controller.sid = json.data;
+ break;
+
+ case 'set_playlist_id':
+ Controller.playlistId = json.data;
+ break;
+
+ case 'vkpc':
+ inject(json.data);
+ break;
+ }
+
+ // executeCommand(msg);
+ },
+ onerror: function() {
+ this.reconnect();
+ },
+ onclose: function() {
+ this.reconnect();
+ }
+ });
+ wsc.connect();
+
+ injectInterval = setInterval(function() {
+ inject('afterInjection');
+ }, 2000);
+}
+
+function sendClear() {
+ wsc.send({command: 'clearPlaylist', data: null});
+}
+
+function inject(command, callback) {
+ var injId = Injections.getNextId();
+ var data = {
+ extid: getExtensionId(),
+ injid: injId,
+ sid: Controller.sid,
+ command: command
+ };
+ var code_inj = "var el = document.createElement('script');" +
+ "el.src = chrome.extension.getURL('vkpc.js');" +
+ "document.body.appendChild(el);" +
+ "var el1 = document.createElement('script');" +
+ "el1.textContent = 'window.__vkpc_data = "+JSON.stringify(data)+"';" +
+ "document.body.appendChild(el1)";
+
+ var okTab_nowPlaying, okTab_playlistFound, okTab_lsSource, okTab_recentlyPlayed, okTab_havePlaylist,
+ activeTab, lastTab, outdatedTabs = [], tabsWithPlayingMusic = []/*, tabPlaylistIds = {}*/;
+ var lsSourceId, appPlaylistFound = false;
+
+ var injResponses, injResults;
+
+ function getCode(code) {
+ return "var el = document.createElement('script');" +
+ "el.textContent = '"+code.replace(/'/g, "\\'")+"';" +
+ "document.body.appendChild(el)";
+ }
+ function onDone(step) {
+ var results = injResponses.results;
+ var execCommand = getCode("VKPC.executeCommand('"+command+"', "+Controller.playlistId+")");
+
+ if (command == 'afterInjection') {
+ //log('[afterInjection onDone] results.length='+results.length);
+
+ for (var i = 0; i < results.length; i++) {
+ var data = results[i].data, tab = results[i].tab;
+
+ // tabPlaylistIds[tab] = data.playlistId;
+ if (data.playlistId != 0 && data.playlistId == Controller.playlistId) {
+ appPlaylistFound = true;
+ }
+ if (data.havePlaylist && data.playlistId != 0 && data.playlistId != Controller.playlistId) {
+ outdatedTabs.push(tab);
+ }
+ if (data.havePlaylist) {
+ okTab_havePlaylist = tab;
+ }
+ if (data.isPlaying) {
+ okTab_nowPlaying = tab;
+ }
+ }
+
+ if (!appPlaylistFound) {
+ var okTab = okTab_nowPlaying || okTab_havePlaylist;
+ if (okTab !== undefined) {
+ chrome.tabs.executeScript(okTab, {code: execCommand});
+ } else if (!appPlaylistFound) {
+ sendClear();
+ }
+ }
+
+ for (var i = 0; i < outdatedTabs.length; i++) {
+ chrome.tabs.executeScript(outdatedTabs[i], {code: getCode('VKPC.clearPlaylist(true, "as")')});
+ }
+ } else {
+ for (var i = 0; i < results.length; i++) {
+ var data = results[i].data;
+ if (!lsSourceId && data.lsSourceId) {
+ lsSourceId = data.lsSourceId;
+ break;
+ }
+ }
+
+ for (var i = 0; i < results.length; i++) {
+ var data = results[i].data, tab = results[i].tab;
+
+ if (data.playlistId == Controller.playlistId) {
+ okTab_playlistFound = tab;
+ }
+ if (data.havePlayer && (data.isPlaying || typeof data.trackId == 'string')) {
+ okTab_recentlyPlayed = tab;
+ }
+ if (data.isPlaying) {
+ okTab_nowPlaying = tab;
+ }
+ if (lsSourceId == data.tabId) {
+ okTab_lsSource = tab;
+ }
+
+ lastTab = tab;
+ }
+
+ var check = [okTab_nowPlaying, okTab_lsSource, okTab_recentlyPlayed, okTab_recentlyPlayed, okTab_havePlaylist, activeTab, lastTab];
+ //log('check[] =', check);
+ for (var i = 0; i < check.length; i++) {
+ if (check[i] !== undefined) {
+ chrome.tabs.executeScript(check[i], {code: execCommand});
+ break;
+ }
+ }
+ }
+
+ injResponses.unregister();
+ callback && callback();
+ }
+
+ getVKTabs(function(tabs) {
+ if (!tabs.length) {
+ sendClear();
+ return;
+ }
+
+ injResponses = new InjectionResponses(injId, tabs.length, onDone);
+ for (var i = 0; i < tabs.length; i++) {
+ if (tabs[i].active) {
+ activeTab = tabs[i].id;
+ }
+ chrome.tabs.executeScript(tabs[i].id, {
+ code: code_inj
+ });
+ }
+ });
+};
+
+var Controller = {
+ sid: 0,
+ playlistId: 0,
+ clear: function() {
+ this.sid = 0;
+ this.playlistId = 0;
+ }
+};
+
+DOMContentLoaded(init);
diff --git a/opera/common.js b/opera/common.js
new file mode 100644
index 0000000..9acd7ec
--- /dev/null
+++ b/opera/common.js
@@ -0,0 +1,270 @@
+var browser = (function() {
+ var ua = navigator.userAgent.toLowerCase();
+ var browser = {
+ id: null,
+ chrome: false,
+ safari: false,
+ yandex: false,
+ firefox: false,
+ opera: false
+ };
+
+ if (/opr/i.test(ua) && /chrome/i.test(ua)) {
+ browser.opera = true;
+ browser.id = 3;
+ } else if (/yabrowser/i.test(ua) && /chrome/i.test(ua)) {
+ browser.yandex = true;
+ browser.id = 4;
+ } else if (/firefox|iceweasel/i.test(ua)) {
+ browser.firefox = true;
+ browser.id = 1;
+ } else if (!(/chrome/i.test(ua)) && /webkit|safari|khtml/i.test(ua)) {
+ browser.safari = true;
+ browser.id = 2;
+ } else if (/chrome/i.test(ua)) {
+ browser.chrome = true;
+ browser.id = 0;
+ }
+
+ return browser;
+})();
+
+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 extend(dest, source) {
+ for (var i in source) {
+ dest[i] = source[i];
+ }
+ return dest;
+}
+function log() {
+ 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 intval(value) {
+ if (value === true) return 1;
+ return parseInt(value) || 0;
+}
+function str(v) {
+ var str;
+ if (v && v.toString)
+ str = v.toString();
+ else
+ str = v + '';
+ if (str == '[object Object]') {
+ str = JSON.stringify(v);
+ }
+ return str;
+}
+
+var WSC_STATE_NONE = 'NONE',
+ WSC_STATE_OK = 'OK',
+ WSC_STATE_CLOSED = 'CLOSED',
+ WSC_STATE_ERR = 'ERR';
+function WSClient(address, protocol, opts) {
+ this.state = WSC_STATE_NONE;
+ this._ws = null;
+
+ this.address = address;
+ this.protocol = protocol;
+
+ this._onmessage = opts.onmessage;
+ this._onclose = opts.onclose;
+ this._onerror = opts.onerror;
+ this._onopen = opts.onopen;
+
+ this._pingTimer = null;
+ this._reconnectTimer = null;
+}
+extend(WSClient.prototype, {
+ connect: function() {
+ this.state = WSC_STATE_NONE;
+ var self = this;
+
+ var _websocket = window.WebSocket || window.MozWebSocket;
+ if (!_websocket) {
+ log('[WSClient connect] websockets are not supported');
+ return;
+ }
+
+ this._ws = new _websocket(this.address, this.protocol);
+ this._ws.onopen = function() {
+ self.state = WSC_STATE_OK;
+ self._setTimers();
+ self._onopen && self._onopen.apply(self);
+ };
+ this._ws.onerror = function() {
+ self._unsetTimers();
+ if (self.state != WSC_STATE_ERR) {
+ self.state = WSC_STATE_ERR;
+ }
+ self._onerror && self._onerror.apply(self);
+ };
+ this._ws.onclose = function() {
+ self._unsetTimers();
+ if (self.state != WSC_STATE_ERR) {
+ self.state = WSC_STATE_ERR;
+ }
+ self._onclose && self._onclose.apply(self);
+ };
+ this._ws.onmessage = function(e) {
+ self._onmessage && self._onmessage.apply(self, [e.data]);
+ };
+ },
+ close: function() {
+ this._unsetTimers();
+ this._ws.close();
+ },
+ reconnect: function() {
+ var self = this;
+ if (this.state == WSC_STATE_OK) {
+ log('[WSClient reconnect] state = '+this.state+', why reconnect?');
+ return;
+ }
+ clearTimeout(this._reconnectTimer);
+ this._reconnectTimer = setTimeout(function() {
+ self.connect();
+ }, 3000);
+ },
+ send: function(obj) {
+ obj._browser = browser.id;
+ var self = this;
+ this._waitForConnection(function() {
+ self._ws.send(JSON.stringify(obj));
+ }, 200);
+ },
+ _setTimers: function() {
+ var self = this;
+ this._pingTimer = setInterval(function() {
+ try {
+ self._ws.send("PING");
+ } catch (e) {
+ log('[WSClient _pingTimer]', e);
+ }
+ }, 30000);
+ },
+ _unsetTimers: function() {
+ clearInterval(this._pingTimer);
+ },
+ _waitForConnection: function(callback, interval) {
+ if (this._ws.readyState === 1) {
+ callback();
+ } else {
+ var self = this;
+ setTimeout(function() {
+ self._waitForConnection(callback, interval);
+ }, interval);
+ }
+ }
+});
+
+(function(window, document) {
+ var queue = [], done = false, _top = true, root = document.documentElement, eventsAdded = false;
+
+ function init(e) {
+ if (e.type == 'readystatechange' && document.readyState != 'complete') return;
+ (e.type == 'load' ? window : document).removeEventListener(e.type, init);
+ if (!done) {
+ done = true;
+ while (queue.length) {
+ queue.shift().call(window);
+ }
+ }
+ }
+ function poll() {
+ try {
+ root.doScroll('left');
+ } catch (e) {
+ setTimeout(poll, 50);
+ return;
+ }
+ init('poll');
+ }
+
+ window.DOMContentLoaded = function(fn) {
+ if (document.readyState == 'complete' || done) {
+ fn.call(window);
+ } else {
+ queue.push(fn);
+
+ if (!eventsAdded) {
+ if (document.createEventObject && root.doScroll) {
+ try {
+ _top = !window.frameElement;
+ } catch (e) {}
+ if (_top) poll();
+ }
+
+ document.addEventListener('DOMContentLoaded', init);
+ document.addEventListener('readystatechange', init);
+ window.addEventListener('load', init);
+ eventsAdded = true;
+ }
+ }
+ }
+})(window, document);
+
+var Injections = {
+ id: 0,
+ objs: {},
+ getNextId: function() {
+ if (this.id == Number.MAX_VALUE) {
+ this.id = -1;
+ }
+ 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];
+ }
+};
+
+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);
+ }
+});
diff --git a/opera/icons/128.png b/opera/icons/128.png
new file mode 100644
index 0000000..6667635
--- /dev/null
+++ b/opera/icons/128.png
Binary files differ
diff --git a/opera/icons/16.png b/opera/icons/16.png
new file mode 100644
index 0000000..18018ce
--- /dev/null
+++ b/opera/icons/16.png
Binary files differ
diff --git a/opera/icons/32.png b/opera/icons/32.png
new file mode 100644
index 0000000..80791ea
--- /dev/null
+++ b/opera/icons/32.png
Binary files differ
diff --git a/opera/manifest.json b/opera/manifest.json
new file mode 100644
index 0000000..3a82a55
--- /dev/null
+++ b/opera/manifest.json
@@ -0,0 +1,30 @@
+{
+ "manifest_version": 2,
+ "name": "VK Player Controller",
+ "description": "This is a part of VK Player Controller for OSX. For more information, please visit https://ch1p.com/vkpc/",
+ "version": "3.0",
+ "icons": {
+ "128": "icons/128.png",
+ "16": "icons/16.png",
+ "32": "icons/32.png"
+ },
+ "content_security_policy": "script-src 'self' 'unsafe-eval' https://vk.com; object-src 'self' 'unsafe-eval'",
+ "permissions": [
+ "tabs",
+ //"background",
+ "https://vk.com/*",
+ "http://vk.com/*",
+ "https://*.vk.com/*",
+ "http://*.vk.com/*"
+ ],
+ "background": {
+ "scripts": [
+ "common.js",
+ "bg.js"
+ ]
+ },
+ "externally_connectable": {
+ "matches": ["https://vk.com/*", "http://vk.com/*", "https://*.vk.com/*", "http://*.vk.com/*"]
+ },
+ "web_accessible_resources": ["inject_and_return.js", "inject_exec.js", "vkpc.js"]
+}
diff --git a/opera/vkpc.js b/opera/vkpc.js
new file mode 100644
index 0000000..b31d40a
--- /dev/null
+++ b/opera/vkpc.js
@@ -0,0 +1,709 @@
+// VKPC for Opera
+
+(function(vkpc_sid) {
+if (!window.VKPC) {
+
+if (!document.addEventListener) {
+ window.console && console.log("[VKPC] an outdated browser detected, very strange, plz update");
+ return;
+}
+
+// variables
+var _debug = window.__vkpc_debug || true;
+var _extid = window.__vkpc_data.extid;
+
+(function(window, document) {
+ var queue = [], done = false, _top = true, root = document.documentElement, eventsAdded = false;
+
+ function init(e) {
+ if (e.type == 'readystatechange' && document.readyState != 'complete') return;
+ (e.type == 'load' ? window : document).removeEventListener(e.type, init);
+ if (!done) {
+ done = true;
+ while (queue.length) {
+ queue.shift().call(window);
+ }
+ }
+ }
+ function poll() {
+ try {
+ root.doScroll('left');
+ } catch (e) {
+ setTimeout(poll, 50);
+ return;
+ }
+ init('poll');
+ }
+
+ window.DOMContentLoaded = function(fn) {
+ if (document.readyState == 'complete' || done) {
+ fn.call(window);
+ } else {
+ queue.push(fn);
+
+ if (!eventsAdded) {
+ if (document.createEventObject && root.doScroll) {
+ try {
+ _top = !window.frameElement;
+ } catch (e) {}
+ if (_top) poll();
+ }
+
+ document.addEventListener('DOMContentLoaded', init);
+ document.addEventListener('readystatechange', init);
+ window.addEventListener('load', init);
+ eventsAdded = true;
+ }
+ }
+ }
+})(window, document);
+
+function log() {
+ if (!_debug)
+ return;
+ var args = Array.prototype.slice.call(arguments);
+ args.unshift(window.VKPC ? '[VKPC '+window.VKPC.getSID()+']' : '[VKPC]');
+ try {
+ window.console && console.log.apply(console, args);
+ } catch (e) {}
+}
+function trim(string) {
+ return string.replace(/(^\s+)|(\s+$)/g, "");
+}
+function startsWith(str, needle) {
+ return str.indexOf(needle) == 0;
+}
+function endsWith(str, suffix) {
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+}
+function random(min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+function shuffle(o) {
+ for (var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
+ return o;
+}
+function getStackTrace(split) {
+ split = split === undefined ? true : split;
+ try {
+ o.lo.lo += 0;
+ } catch(e) {
+ if (e.stack) {
+ return split ? e.stack.split('\n') : e.stack;
+ }
+ }
+ return null;
+}
+function buildQueryString(obj) {
+ var list = [], i;
+ for (i in obj) {
+ list.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
+ }
+ return list.join('&');
+}
+function stripTags(html) {
+ var div = document.createElement("div");
+ div.innerHTML = html;
+ return div.textContent || div.innerText || "";
+}
+function decodeEntities(value) {
+ var textarea = document.createElement('textarea');
+ textarea.innerHTML = value;
+ return textarea.value;
+}
+
+function toApp(command, data) {
+ chrome.runtime.sendMessage(_extid, {
+ cmd: "to_app",
+ data: {
+ command: command,
+ data: data
+ }
+ });
+}
+
+window.VKPC = new function() {
+ var _sid = null;
+ var _currentTrackId = null;
+ var _lastPlaylistSummary = null;
+ var _lastPlaylistId = 0;
+ var _operateQueue = [];
+ var _setTrackIdTimeout = null;
+ var _watchGraphicsChange = false;
+ var _checkPlaylistTimer = null;
+
+ function wrapAudioMethods() {
+ // var self = this;
+ if (window.audioPlayer) {
+ if (!audioPlayer.__operate) {
+ audioPlayer.__operate = audioPlayer.operate;
+ audioPlayer.operate = function(id, nextPlaylist, opts) {
+ var currentId = audioPlayer.id, _status = id != currentId ? 'play' : null;
+ audioPlayer.__operate.apply(audioPlayer, arguments);
+ //self.firstOperateAfterPlaylistUpdating = false;
+ log('operate(), arguments:', arguments);
+
+ if (existsInCurrentPlaylist(id)) {
+ log('operate(), found in current pl, setTrackId() now');
+ setTrackId(id, _status);
+ } else {
+ log('operate(), not found, setToOperateQueue() now');
+ setToOperateQueue(id, _status);
+ }
+ };
+ }
+
+ // disable it
+ if (false && !audioPlayer.__setGraphics) {
+ audioPlayer.__setGraphics = audioPlayer.setGraphics;
+ audioPlayer.setGraphics = function(act) {
+ audioPlayer.__setGraphics.apply(audioPlayer, arguments);
+ return;
+ /*if (self.watchGraphicsChange) {
+ if (browser.safari) self.sendOperateTrack(audioPlayer.id, (act == 'play' || act == 'load') ? 'play' : 'pause');
+ self.watchGraphicsChange = false;
+ }*/
+ };
+ }
+ }
+
+ log('[wrapAudioMethods] wrapped DONE');
+ }
+
+ function clear() {
+ log('clear()');
+ _currentTrackId = null;
+ _lastPlaylistSummary = null;
+ _lastPlaylistId = null;
+ _sid = null;
+ _watchGraphicsChange = false;
+ }
+
+ function getBrowser() {
+ return browser.safari ? 'safari' : 'chrome';
+ }
+
+ function executeCommand(command, plid) {
+ if (command == 'afterInjection') {
+ log('executeCommand: afterInjection, plid='+plid);
+ var pl = padAudioPlaylist();
+ if (window.audioPlayer && pl) {
+ updatePlaylist(getPlaylist(pl));
+ } else {
+ clearPlaylist();
+ }
+ return;
+ }
+
+ log('executeCommand:', command, plid);
+ // var self = this;
+
+ if (!window.audioPlayer || !padAudioPlaylist()) {
+ log('[executeCommand] audioplayer or playlist not found');
+ stManager.add(['audioplayer.js'], function() {
+ executeAfterPadLoading(function() {
+ log('[executeCommand] after execafterpadloading, window.audioPlayer:', window.audioPlayer);
+ wrapAudioMethods();
+
+ var plist = padAudioPlaylist();
+ if (plist) {
+ log('[executeCommand] after exec...: send updatePlaylist() with plist');
+ updatePlaylist(getPlaylist(plist));
+ }
+
+ if (command == 'playpause' || command == 'next' || command == 'prev') {
+ log('[executeCommand] after exec...: simple command');
+ var id = getPlayFirstId();
+ if (id) {
+ log('[executeCommand] after exec...: found id='+id+', playAudioNew() now');
+ playAudioNew(id);
+ } else if (plist && plist.start) {
+ log('[executeCommand] after exec...: found plist.start, playAudioNew() now');
+ playAudioNew(plist.start);
+ }
+ } else if (startsWith(command, 'operateTrack:')) { // TODO this is new fix
+ var id = parseInt(command.replace('operateTrack:'));
+ log('[executeCommand] after exec...: got operateTrack, id='+id);
+ if (!plist[id]) {
+ log('[executeCommand] after exec...: after got operateTrack: plist[id] not found, send new pl to app');
+ //self.clearPlaylist();
+ updatePlaylist(getPlaylist(plist));
+ if (plist.start) {
+ log('[executeCommand] after exec...: got operateTrack, pl not found... ... play plist.start now');
+ playAudioNew(plist.start);
+ }
+ } else {
+ log('[executeCommand] after exec...: got operateTrack, it is found, playAudioNew() now');
+ playAudioNew(id);
+ }
+ }
+ });
+ });
+ return;
+ }
+
+ function evaluateCommand(command) {
+ switch (command) {
+ case 'next':
+ case 'prev':
+ case 'playpause':
+ if (audioPlayer.id) {
+ if (command == 'next') next();
+ else if (command == 'prev') prev();
+ else if (command == 'playpause') playPause();
+ } else {
+ var id = getPlayFirstId();
+ if (id) playId(id);
+ }
+ break;
+
+ default:
+ if (startsWith(command, 'operateTrack:')) {
+ log('[executeCommand] got operateTrack;');
+ var id = command.replace('operateTrack:', ''), pl = padAudioPlaylist();
+ if (pl[id] !== undefined) {
+ log('[executeCommand] got operateTrack; track is found, playAudioNew() now');
+ //playAudioNew(id);
+ //audioPlayer.operate(id);
+ playId(id);
+ } else {
+ log('[executeCommand] got operateTrack; track not found, updatePlaylist with pl:', pl);
+ updatePlaylist(getPlaylist(pl));
+ var id = getPlayFirstId();
+ if (id) {
+ log('[executeCommand] got operateTrack; play id from getPlayFirstId() now');
+ playId(id);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (plid != _lastPlaylistId) {
+ log('[executeCommand] plid does not match');
+ var pl = padAudioPlaylist();
+ if (pl) {
+ updatePlaylist(getPlaylist(pl), true);
+ log('[executeCommand] plid does not match, sent updatePlaylist() with pl:', pl);
+
+ if (plid == 0) {
+ evaluateCommand(command);
+ } else {
+ if (['next', 'prev', 'playpause'].indexOf(command) != -1) {
+ var id = audioPlayer.id || pl.start || getPlayFirstId();
+ if (id) {
+ playId(id);
+ }
+ }
+ }
+ }
+ } else {
+ evaluateCommand(command);
+ }
+ }
+
+ function setTrackId(id, _status) {
+ _status = _status || (audioPlayer.player.paused() ? 'pause' : 'play');
+ clearTimeout(_setTrackIdTimeout);
+
+ var check = function() {
+ if (audioPlayer.player) {
+ sendOperateTrack(id, _status);
+ } else {
+ _setTrackIdTimeout = setTimeout(check, 200);
+ }
+ };
+ check();
+ }
+
+ function sendOperateTrack(id, _status) {
+ log('[sendOperateTrack]', id, _status);
+ toApp('operateTrack', {
+ 'id': id,
+ 'status': _status,
+ 'playlistId': _lastPlaylistId
+ });
+ }
+
+ function setToOperateQueue(id, _status) {
+ var q = _operateQueue;
+ for (var i = 0; i < q.length; i++) {
+ var track = q[i];
+ if (track[0] == id) {
+ track[1] = _status;
+ return;
+ }
+ }
+ q.push([id, _status]);
+ }
+
+ function existsInCurrentPlaylist(id) {
+ return _lastPlaylistSummary && _lastPlaylistSummary.indexOf(id) != -1;
+ }
+
+ function processOperateQueue(pl) {
+ log('[processOperateQueue]');
+ var q = _operateQueue;
+ while (q.length) {
+ var track = q.shift();
+ log('[processOperateQueue] track:', track[0]);
+ if (pl[track[0]] !== undefined) {
+ log('[processOperateQueue] track', track[0], 'found, send it now');
+ sendOperateTrack(track[0], track[1]);
+ }
+ }
+ }
+
+ function clearOperateQueue() {
+ _operateQueue = [];
+ }
+
+ function printPlaylist() {
+ var pl = padAudioPlaylist();
+ if (pl) {
+ for (var k in pl) {
+ log(pl[k][5] + ' - ' + pl[k][6]);
+ }
+ }
+ }
+
+ function getPlaylist(_pl) {
+ _pl = _pl || padAudioPlaylist();
+ var pl = null;
+ if (_pl) {
+ var start = _pl.start, pl = [];
+ var nextId = start;
+ do {
+ if (_pl[nextId]) {
+ _pl[nextId]._vkpcId = nextId;
+ pl.push(_pl[nextId]);
+ nextId = _pl[nextId]._next;
+ }
+ } while (nextId != '' && nextId !== undefined && nextId != start);
+ }
+ return pl;
+ }
+
+ // force=true is used when plids not match
+ function updatePlaylist(pl, force) {
+ var tracks = [], summary = [], title;
+ if (pl) {
+ for (var k = 0; k < pl.length; k++) {
+ tracks.push({
+ id: pl[k]._vkpcId,
+ artist: decodeEntities(pl[k][5]),
+ title: decodeEntities(pl[k][6]),
+ duration: pl[k][4]
+ });
+ summary.push(pl[k]._vkpcId);
+ }
+
+ summary = summary.join(';');
+
+ log("updatePlaylist: _lastPlaylistSummary:", _lastPlaylistSummary, 'summary:', summary);
+ if (force || _lastPlaylistSummary === null || _lastPlaylistSummary !== summary) {
+ log('[updatePlaylist] last summary not matched;', _lastPlaylistSummary, summary);
+ var activeId = '', activeStatus = '';
+ var vkpl = padAudioPlaylist();
+ var plTitle = (window.audioPlaylist && window.audioPlaylist.htitle) || vkpl.htitle;
+ if (audioPlayer.id && vkpl[audioPlayer.id] !== undefined) {
+ activeId = audioPlayer.id;
+ _watchGraphicsChange = true;
+
+ activeStatus = getPlayerStatus(true) ? 'play' : 'pause';
+ _watchGraphicsChange = true;
+ }
+
+ _lastPlaylistSummary = summary;
+ _lastPlaylistId = random(100000, 1000000);
+
+ log("[updatePlaylist] send pl with id="+_lastPlaylistId+', activeId='+activeId+', activeStatus='+activeStatus+' to app');
+ try {
+ toApp('updatePlaylist', {
+ tracks: tracks,
+ title: parsePlaylistTitle(plTitle) || "",
+ id: _lastPlaylistId,
+ active: { 'id': activeId, 'status': activeStatus },
+ browser: getBrowser()
+ });
+ } catch(e) {
+ log('[updatePlaylist] exception:', e, e.stack);
+ }
+
+ processOperateQueue(pl);
+ }
+ }
+ }
+
+ function clearPlaylist(no_send, called_from) {
+ called_from = called_from || "";
+ log('[clearPlaylist] (called from: '+called_from+')');
+
+ _lastPlaylistSummary = null;
+ _lastPlaylistId = 0;
+ if (!no_send) {
+ toApp('clearPlaylist', {});
+ }
+ }
+
+ function checkPlaylist() {
+ var pl = padAudioPlaylist();
+ if (!pl) {
+ clearPlaylist(true, 'checkPlaylist');
+ }
+ }
+
+ function parsePlaylistTitle(str) {
+ str = str || "";
+ str = trim(str);
+ if (str == '') return str;
+
+ var starts = {
+ 0: 'Сейчас играет — ', // ru
+ 100: 'Нынче играетъ— ', // re
+ 3: 'Now playing — ', // en
+ 1: 'Зараз звучить — ', // ua
+ 777: 'Проигрывается пластинка «' // su
+ };
+ var ends = {
+ 0: ' \\| [0-9]+ аудиоза[^\\s]+$',
+ 3: ' \\| [0-9]+ audio [^\\s]+$',
+ 1: ' \\| [0-9]+ аудіоза[^\\s]+$',
+ 100: ' \\| [0-9]+ композ[^\\s]+$',
+ 777: ' \\| [0-9]+ грамза[^\\s]+»$'
+ };
+
+ if (window.vk && vk.lang !== undefined) {
+ if (starts[vk.lang] !== undefined && startsWith(str, starts[vk.lang])) {
+ str = str.substring(starts[vk.lang].length);
+ }
+
+ if (ends[vk.lang] !== undefined) {
+ var regex = new RegExp(ends[vk.lang], 'i');
+ if (str.match(regex)) str = str.replace(regex, '');
+ }
+ }
+
+ return stripTags(trim(str));
+ }
+
+ function afterInjection() {
+ log("after injection");
+ var pl = getPlaylist();
+ if (pl) updatePlaylist(pl);
+ }
+
+ function next() {
+ audioPlayer.nextTrack(true, !window.audioPlaylist)
+ /*if (audioPlayer.controls && audioPlayer.controls.pd && audioPlayer.controls.pd.next) {
+ audioPlayer.controls.pd.next.click();
+ } else {
+ audioPlayer.nextTrack(true, !window.audioPlaylist)
+ }*/
+ }
+
+ function prev() {
+ audioPlayer.prevTrack(true, !window.audioPlaylist);
+ /*if (audioPlayer.controls && audioPlayer.controls.pd && audioPlayer.controls.pd.prev) {
+ audioPlayer.controls.pd.prev.click();
+ } else {
+ audioPlayer.prevTrack(true, !window.audioPlaylist);
+ }*/
+ }
+
+ function getPlayFirstId() {
+ var id = currentAudioId() || ls.get('audio_id') || (window.audioPlaylist && audioPlaylist.start);
+ return id || null;
+ }
+
+ function playFirst() {
+ var id = getPlayFirstId();
+
+ if (id) playId(id);
+ else {
+ var plist = padAudioPlaylist();
+ if (plist && plist.start) {
+ playId(plist.start);
+ } else {
+ executeAfterPadLoading(function() {
+ var plist = padAudioPlaylist();
+ if (plist && plist.start) {
+ playId(plist.start);
+ }
+ });
+ }
+ }
+ }
+
+ function executeAfterPadLoading(f) {
+ Pads.show('mus');
+ window.onPlaylistLoaded = function() {
+ if (f) {
+ try {
+ f();
+ } catch(e) {}
+ }
+ setTimeout(function() {
+ Pads.show('mus');
+ }, 10);
+ }
+ }
+
+ function getPlayerStatus(justStarted) {
+ if (!audioPlayer.player) return false;
+ try {
+ var pl = audioPlayer.player;
+ if (pl && pl.music && pl.music.buffered && !pl.music.buffered.length && justStarted) return true;
+ } catch (e) {
+ return true;
+ }
+
+ return audioPlayer.player && !audioPlayer.player.paused();
+ }
+
+ function pauseForSafari() {
+ if (window.audioPlayer && audioPlayer.player) audioPlayer.pauseTrack();
+ }
+
+ function playPause() {
+ if (window.audioPlayer && audioPlayer.player) {
+ if (audioPlayer.player.paused()) {
+ audioPlayer.playTrack();
+ } else {
+ audioPlayer.pauseTrack();
+ }
+ }
+ }
+
+ function operateTrack(id) {
+ if (id == audioPlayer.id) {
+ playPause();
+ } else {
+ audioPlayer.operate(id);
+ }
+ }
+
+ function playId(id) {
+ if (window.audioPlayer) audioPlayer.operate(id);
+ else playAudioNew(id);
+ }
+
+ function getLastInstanceId() {
+ var id = null, pp = ls.get('pad_playlist');
+ if (pp && pp.source) id = pp.source;
+ return id;
+ }
+
+ this.executeCommand = executeCommand;
+
+ this.getParams = function() {
+ if (window.__vkpc_data && window.__vkpc_data.command != 'afterInjection') {
+ checkPlaylist();
+ }
+ var havePlayer = window.audioPlayer !== undefined;
+ var havePlaylist = havePlayer && (window.padAudioPlaylist && !!padAudioPlaylist());
+
+ return {
+ havePlayer: havePlayer,
+ havePlaylist: havePlaylist,
+ isPlaying: window.audioPlayer && window.audioPlayer.player && !window.audioPlayer.player.paused(),
+ tabId: window.curNotifier && curNotifier.instance_id,
+ trackId: window.audioPlayer && audioPlayer.id,
+ playlistId: havePlaylist ? _lastPlaylistId : 0,
+ lsSourceId: getLastInstanceId()
+ };
+ };
+
+ this.init = function(sid) {
+ if (_checkPlaylistTimer === null) {
+ _checkPlaylistTimer = setInterval(function() {
+ if ((_lastPlaylistId || _lastPlaylistSummary) && !padAudioPlaylist()) {
+ clearPlaylist(true, 'timer'); // TODO func
+ }
+ }, 1000);
+ }
+
+ if (!window.__wrappedByVKPC && window.audioPlayer && window.ls && window.stManager) {
+ if (!stManager.__done) {
+ stManager.__done = stManager.done;
+ stManager.done = function(fn) {
+ if (fn == 'audioplayer.js') {
+ wrapAudioMethods(); // TODO func
+ }
+ stManager.__done.apply(stManager, arguments);
+ };
+ }
+
+ wrapAudioMethods();
+
+ if (!ls.__set) {
+ ls.__set = ls.set;
+ ls.set = function(k, v) {
+ ls.__set.apply(ls, arguments);
+ if (k == 'pad_playlist') {
+ log('pad_playlist updated:', v);
+ updatePlaylist(getPlaylist(v)); // TODO func
+ }
+ };
+ }
+ if (!ls.__remove) {
+ ls.__remove = ls.remove;
+ ls.remove = function(k, v) {
+ ls.__remove.apply(ls, arguments);
+ if (k == 'pad_playlist') {
+ log('pad_playlist removed from ls');
+ //self.clearPlaylist(true, 'ls.remove');
+ // self.clearPlaylist();
+ }
+ };
+ }
+
+ window.__wrappedByVKPC = true;
+ }
+
+ if (sid === _sid) {
+ return;
+ }
+ if (_sid !== null) {
+ clear(); // TODO
+ }
+ _sid = sid;
+
+ log('(re)inited OK');
+ };
+
+ this.getSID = function() {
+ return _sid;
+ };
+
+ this.getLastPlaylistID = function() {
+ return _lastPlaylistId;
+ };
+
+ this.getLastInstanceId = getLastInstanceId;
+ this.clearPlaylist = clearPlaylist;
+}; // window.VKPC = ...
+
+} // if (!window.VKPC) ...
+
+if (!window.DOMContentLoaded) {
+ window.console && console.log && console.log("[VKPC] !window.DOMContentLoaded, exising");
+ return;
+}
+
+window.DOMContentLoaded(function() {
+ VKPC.init(vkpc_sid);
+});
+
+// afterInjection
+
+chrome.runtime.sendMessage(window.__vkpc_data.extid, {
+ cmd: "injection_result",
+ id: parseInt(window.__vkpc_data.injid, 10),
+ data: VKPC.getParams()
+});
+
+})(window.__vkpc_data.sid);
+
+delete window.__vkpc_data;