Compare commits

..

3 Commits

Author SHA1 Message Date
5dc61fa742 Some Polish 2022-03-20 00:39:47 -04:00
71c2aff1cf Move manifest.json 2022-03-19 20:36:18 -04:00
8d89763857 Use document_start 2022-03-19 06:00:48 -04:00
3 changed files with 80 additions and 20 deletions

View File

@ -1,17 +1,19 @@
{ {
"description": "This browser extension forces DisneyNOW to use their higher-resolution video stream by imitating the Android app. (It also blocks DisneyNOW ads.)",
"manifest_version": 2, "manifest_version": 2,
"name": "Force High-Resolution DisneyNOW", "name": "Force High-Resolution DisneyNOW",
"version": "1.0", "author": "TheBrokenRail",
"version": "1.1",
"description": "This browser extension forces DisneyNOW to use their higher-resolution video stream by imitating the Android app. (It also blocks DisneyNOW ads.)",
"homepage_url": "https://gitea.thebrokenrail.com/TheBrokenRail/force-high-resolution-disneynow",
"content_scripts": [ "content_scripts": [
{ {
"matches": ["*://disneynow.com/*"], "matches": ["*://disneynow.com/*"],
"js": ["content.js"], "js": ["src/content.js"],
"run_at": "document_end" "run_at": "document_start"
} }
], ],
"web_accessible_resources": [ "web_accessible_resources": [
"page.js" "src/page.js"
], ],
"browser_specific_settings": { "browser_specific_settings": {
"gecko": { "gecko": {

View File

@ -1,5 +1,9 @@
'use strict';
// Load Extension
const script = document.createElement('SCRIPT'); const script = document.createElement('SCRIPT');
script.src = chrome.runtime.getURL('page.js'); script.src = chrome.runtime.getURL('src/page.js');
script.type = 'text/javascript';
script.onload = function() { script.onload = function() {
this.remove(); this.remove();
}; };

View File

@ -1,15 +1,22 @@
'use strict'; 'use strict';
// Constants // Constants
const DEVICE_ID = '031_04'; // Found in the APK as @string/device_id const DEVICE_ID = '031_04'; // Found in the APK as the resource @string/device_id. (Default: "001")
const BRAND_ID = '011'; // Selected from the function mapBrandCode(), which is found in embed.min.js (a script loaded by the website) const BRAND_ID = '011'; // Selected from the function mapBrandCode(), which is found in embed.min.js (a script loaded by the website). (Default: "004")
// Lock the reported app name and version to a known working value. (The reported app name and version can determine the video stream format.)
const APP_NAME = 'webplayer-dc';
const APP_VERSION = '1.2.7.49';
// Target File
const TARGET_FILE = 'playmanifest_secure.json';
// Patch XMLHttpRequest.open // Patch XMLHttpRequest.open
const oldOpen = XMLHttpRequest.prototype.open; const oldOpen = XMLHttpRequest.prototype.open;
Object.defineProperty(XMLHttpRequest.prototype, 'open', { Object.defineProperty(XMLHttpRequest.prototype, 'open', {
value: function (method, url, ...args) { value: function (method, url, ...args) {
// Flag // Flag
this._isTargetUrl = (new URL(url)).pathname.endsWith('/playmanifest_secure.json'); this._isTargetUrl = (new URL(url)).pathname.endsWith('/' + TARGET_FILE);
// Call Original Method // Call Original Method
oldOpen.call(this, method, url, ...args); oldOpen.call(this, method, url, ...args);
@ -19,34 +26,81 @@ Object.defineProperty(XMLHttpRequest.prototype, 'open', {
writable: false writable: false
}); });
// Patch XMLHttpRequest.setRequestHeader
const oldSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
Object.defineProperty(XMLHttpRequest.prototype, 'setRequestHeader', {
value: function (name, value) {
// Lock App Version
if (this._isTargetUrl && name.toLowerCase() === 'appversion') {
value = APP_VERSION;
}
// Call Original Method
oldSetRequestHeader.call(this, name, value);
},
enumerable: false,
configurable: false,
writable: false
});
// Add resolution info to video player.
function addResolutionInfo(player) {
// Create (or find existing) <p> element.
const id = '__disneynow_resolution_info__';
let p = document.getElementById(id);
if (!p) {
// Create
const p = document.createElement('P');
p.id = id;
// Add <p> element to DOM.
player.parentElement.insertBefore(p, player);
}
// Set initial resolution text.
function setResolutionText(resolution) {
p.innerText = `Video Quality: ${resolution}`;
}
setResolutionText('N/A');
// Hook into <video> element.
const video = player.getElementsByTagName('VIDEO')[0];
video.addEventListener("resize", e => setResolutionText(`${e.target.videoWidth}x${e.target.videoHeight}`), false);
}
// Patch XMLHttpRequest.send // Patch XMLHttpRequest.send
const oldSend = XMLHttpRequest.prototype.send; const oldSend = XMLHttpRequest.prototype.send;
Object.defineProperty(XMLHttpRequest.prototype, 'send', { Object.defineProperty(XMLHttpRequest.prototype, 'send', {
value: function (body, ...args) { value: function (body, ...args) {
// Check // Check
if (body && this._isTargetUrl) { if (this._isTargetUrl && body) {
// Parse Request Body // Parse Request Body
const params = new URLSearchParams(body); const params = new URLSearchParams(body);
// Pretend to be an Android device // Pretend to be an Android device.
if (params.has('device')) {
params.set('device', DEVICE_ID); params.set('device', DEVICE_ID);
} // Switch brand ID to one without ads.
// Switch brand to one without ads
if (params.has('brand')) {
params.set('brand', BRAND_ID); params.set('brand', BRAND_ID);
} // Set recommended video player size to current screen resolution.
params.set('vps', `${window.screen.width * window.devicePixelRatio}x${window.screen.height * window.devicePixelRatio}`);
// Ensure other miscellaneous parameters are correct.
params.set('hdcp_level', '2.3');
params.set('hlsver', '6');
params.set('app_name', APP_NAME);
// Apply Patch // Apply Patch
body = params.toString(); body = params.toString();
// Verify // Log Video Stream URL
this.addEventListener("load", function () { this.addEventListener("load", function () {
const obj = JSON.parse(this.responseText); const obj = JSON.parse(this.responseText);
const assetUrl = new URL(obj.video.assets.asset[0].value); const assetUrl = new URL(obj.video.assets.asset[0].value);
console.log('Video Stream URL: ' + assetUrl); console.log('Video Stream URL: ' + assetUrl);
}); });
// Find video player and add resolution info.
const player = document.getElementsByClassName('VideoPlayer')[0];
addResolutionInfo(player);
} }
// Call Original Method // Call Original Method