Add workaround for GM sandbox and refactor userscript a bit
This commit is contained in:
parent
8d3b2e59df
commit
578d3fbb23
|
@ -7,16 +7,20 @@
|
|||
// @grant GM_xmlhttpRequest
|
||||
// @connect docs.google.com
|
||||
// @run-at document-end
|
||||
// @version 1.0.0
|
||||
// @version 1.1.0
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
try {
|
||||
function debug(message) {
|
||||
if (!unsafeWindow.enableCyTubeGoogleDriveUserscriptDebug) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafeWindow.console.log.apply(unsafeWindow.console, arguments);
|
||||
try {
|
||||
unsafeWindow.console.log(message);
|
||||
} catch (error) {
|
||||
unsafeWindow.console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
var ITAG_QMAP = {
|
||||
|
@ -53,6 +57,8 @@
|
|||
method: 'GET',
|
||||
url: url,
|
||||
onload: function (res) {
|
||||
try {
|
||||
debug('Got response ' + res.responseText);
|
||||
var data = {};
|
||||
var error;
|
||||
res.responseText.split('&').forEach(function (kv) {
|
||||
|
@ -81,8 +87,12 @@
|
|||
var pair = item.split('|');
|
||||
data.links[pair[0]] = pair[1];
|
||||
});
|
||||
data.videoMap = mapLinks(data.links);
|
||||
|
||||
cb(null, data);
|
||||
} catch (error) {
|
||||
unsafeWindow.console.error(error);
|
||||
}
|
||||
},
|
||||
|
||||
onerror: function () {
|
||||
|
@ -118,36 +128,83 @@
|
|||
return videos;
|
||||
}
|
||||
|
||||
function GoogleDrivePlayer(data) {
|
||||
if (!(this instanceof GoogleDrivePlayer)) {
|
||||
return new GoogleDrivePlayer(data);
|
||||
/*
|
||||
* Greasemonkey 2.0 has this wonderful sandbox that attempts
|
||||
* to prevent script developers from shooting themselves in
|
||||
* the foot by removing the trigger from the gun, i.e. it's
|
||||
* impossible to cross the boundary between the browser JS VM
|
||||
* and the privileged sandbox that can run GM_xmlhttpRequest().
|
||||
*
|
||||
* So in this case, we have to resort to polling a special
|
||||
* variable to see if getGoogleDriveMetadata needs to be called
|
||||
* and deliver the result into another special variable that is
|
||||
* being polled on the browser side.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Browser side function -- sets gdUserscript.pollID to the
|
||||
* ID of the Drive video to be queried and polls
|
||||
* gdUserscript.pollResult for the result.
|
||||
*/
|
||||
function getGoogleDriveMetadata_GM(id, callback) {
|
||||
debug('Setting GD poll ID to ' + id);
|
||||
unsafeWindow.gdUserscript.pollID = id;
|
||||
var tries = 0;
|
||||
var i = setInterval(function () {
|
||||
if (unsafeWindow.gdUserscript.pollResult) {
|
||||
debug('Got result');
|
||||
clearInterval(i);
|
||||
var result = unsafeWindow.gdUserscript.pollResult;
|
||||
unsafeWindow.gdUserscript.pollResult = null;
|
||||
callback(result.error, result.result);
|
||||
} else if (++tries > 100) {
|
||||
// Took longer than 10 seconds, give up
|
||||
clearInterval(i);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
this.setMediaProperties(data);
|
||||
this.load(data);
|
||||
}
|
||||
|
||||
GoogleDrivePlayer.prototype = Object.create(unsafeWindow.VideoJSPlayer.prototype);
|
||||
|
||||
GoogleDrivePlayer.prototype.load = function (data) {
|
||||
var self = this;
|
||||
getVideoInfo(data.id, function (err, videoData) {
|
||||
if (err) {
|
||||
debug(err);
|
||||
var alertBox = unsafeWindow.document.createElement('div');
|
||||
alertBox.className = 'alert alert-danger';
|
||||
alertBox.textContent = err.message;
|
||||
document.getElementById('ytapiplayer').appendChild(alertBox);
|
||||
return;
|
||||
}
|
||||
|
||||
debug('Retrieved links: ' + JSON.stringify(videoData.links));
|
||||
data.meta.direct = mapLinks(videoData.links);
|
||||
unsafeWindow.VideoJSPlayer.prototype.loadPlayer.call(self, data);
|
||||
/*
|
||||
* Sandbox side function -- polls gdUserscript.pollID for
|
||||
* the ID of a Drive video to be queried, looks up the
|
||||
* metadata, and stores it in gdUserscript.pollResult
|
||||
*/
|
||||
function setupGDPoll() {
|
||||
unsafeWindow.gdUserscript = cloneInto({}, unsafeWindow);
|
||||
var pollInterval = setInterval(function () {
|
||||
if (unsafeWindow.gdUserscript.pollID) {
|
||||
var id = unsafeWindow.gdUserscript.pollID;
|
||||
unsafeWindow.gdUserscript.pollID = null;
|
||||
debug('Polled and got ' + id);
|
||||
getVideoInfo(id, function (error, data) {
|
||||
unsafeWindow.gdUserscript.pollResult = cloneInto({
|
||||
error: error,
|
||||
result: data
|
||||
}, unsafeWindow);
|
||||
});
|
||||
};
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function isRunningTampermonkey() {
|
||||
try {
|
||||
return GM_info.scriptHandler === 'Tampermonkey';
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRunningTampermonkey()) {
|
||||
unsafeWindow.getGoogleDriveMetadata = getVideoInfo;
|
||||
} else {
|
||||
debug('Using non-TM polling workaround');
|
||||
unsafeWindow.getGoogleDriveMetadata = exportFunction(
|
||||
getGoogleDriveMetadata_GM, unsafeWindow);
|
||||
setupGDPoll();
|
||||
}
|
||||
|
||||
unsafeWindow.GoogleDrivePlayer = GoogleDrivePlayer;
|
||||
unsafeWindow.console.log('Initialized userscript Google Drive player');
|
||||
unsafeWindow.hasDriveUserscript = true;
|
||||
})();
|
||||
} catch (error) {
|
||||
unsafeWindow.console.error(error);
|
||||
}
|
||||
|
|
|
@ -4,3 +4,19 @@ window.GoogleDrivePlayer = class GoogleDrivePlayer extends VideoJSPlayer
|
|||
return new GoogleDrivePlayer(data)
|
||||
|
||||
super(data)
|
||||
|
||||
load: (data) ->
|
||||
if typeof window.getGoogleDriveMetadata is 'function'
|
||||
window.getGoogleDriveMetadata(data.id, (error, metadata) =>
|
||||
if error
|
||||
console.error(error)
|
||||
alertBox = window.document.createElement('div')
|
||||
alertBox.className = 'alert alert-danger'
|
||||
alertBox.textContent = error.message
|
||||
document.getElementById('ytapiplayer').appendChild(alertBox)
|
||||
else
|
||||
data.meta.direct = metadata.videoMap
|
||||
super(data)
|
||||
)
|
||||
else
|
||||
super(data)
|
||||
|
|
|
@ -33,7 +33,7 @@ window.loadMediaPlayer = (data) ->
|
|||
else if data.type is 'gd'
|
||||
try
|
||||
if data.meta.html5hack or window.hasDriveUserscript
|
||||
window.PLAYER = new window.GoogleDrivePlayer(data)
|
||||
window.PLAYER = new GoogleDrivePlayer(data)
|
||||
else
|
||||
window.PLAYER = new GoogleDriveYouTubePlayer(data)
|
||||
catch e
|
||||
|
|
|
@ -43,8 +43,7 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
if not (this instanceof VideoJSPlayer)
|
||||
return new VideoJSPlayer(data)
|
||||
|
||||
@setMediaProperties(data)
|
||||
@loadPlayer(data)
|
||||
@load(data)
|
||||
|
||||
loadPlayer: (data) ->
|
||||
waitUntilDefined(window, 'videojs', =>
|
||||
|
|
|
@ -503,8 +503,7 @@
|
|||
if (!(this instanceof VideoJSPlayer)) {
|
||||
return new VideoJSPlayer(data);
|
||||
}
|
||||
this.setMediaProperties(data);
|
||||
this.loadPlayer(data);
|
||||
this.load(data);
|
||||
}
|
||||
|
||||
VideoJSPlayer.prototype.loadPlayer = function(data) {
|
||||
|
@ -676,6 +675,28 @@
|
|||
GoogleDrivePlayer.__super__.constructor.call(this, data);
|
||||
}
|
||||
|
||||
GoogleDrivePlayer.prototype.load = function(data) {
|
||||
if (typeof window.getGoogleDriveMetadata === 'function') {
|
||||
return window.getGoogleDriveMetadata(data.id, (function(_this) {
|
||||
return function(error, metadata) {
|
||||
var alertBox;
|
||||
if (error) {
|
||||
console.error(error);
|
||||
alertBox = window.document.createElement('div');
|
||||
alertBox.className = 'alert alert-danger';
|
||||
alertBox.textContent = error.message;
|
||||
return document.getElementById('ytapiplayer').appendChild(alertBox);
|
||||
} else {
|
||||
data.meta.direct = metadata.videoMap;
|
||||
return GoogleDrivePlayer.__super__.load.call(_this, data);
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
} else {
|
||||
return GoogleDrivePlayer.__super__.load.call(this, data);
|
||||
}
|
||||
};
|
||||
|
||||
return GoogleDrivePlayer;
|
||||
|
||||
})(VideoJSPlayer);
|
||||
|
@ -1359,7 +1380,7 @@
|
|||
} else if (data.type === 'gd') {
|
||||
try {
|
||||
if (data.meta.html5hack || window.hasDriveUserscript) {
|
||||
return window.PLAYER = new window.GoogleDrivePlayer(data);
|
||||
return window.PLAYER = new GoogleDrivePlayer(data);
|
||||
} else {
|
||||
return window.PLAYER = new GoogleDriveYouTubePlayer(data);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue