// ==UserScript==
// @name NextGenMobileView
// @namespace http://tampermonkey.net/
// @version 3.0
// @description Intelligently forces mobile view with device profiles, adaptive redirection, and optimized performance
// @author Jonathan Laurendeau
// @match *://*/*
// @exclude *://*.m.*/*
// @exclude *://m.*/*
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @run-at document-start
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// Device profiles
const devices = {
iPhone14: {
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
platform: 'iPhone',
vendor: 'Apple Computer, Inc.',
width: 375,
height: 812,
touchPoints: 5
},
Pixel7: {
userAgent: 'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Mobile Safari/537.36',
platform: 'Linux armv8l',
vendor: 'Google Inc.',
width: 412,
height: 915,
touchPoints: 5
}
};
// Load user-selected device
const selectedDevice = GM_getValue('device', 'iPhone14');
// Spoof navigator and screen properties
function spoofDevice(device) {
Object.defineProperty(navigator, 'userAgent', {
value: devices[device].userAgent,
writable: false,
configurable: false
});
Object.defineProperty(navigator, 'platform', {
value: devices[device].platform,
writable: false,
configurable: false
});
Object.defineProperty(navigator, 'vendor', {
value: devices[device].vendor,
writable: false,
configurable: false
});
Object.defineProperty(navigator, 'maxTouchPoints', {
value: devices[device].touchPoints,
writable: false,
configurable: false
});
Object.defineProperty(window, 'screen', {
get: function() {
return {
width: devices[device].width,
height: devices[device].height,
availWidth: devices[device].width,
availHeight: devices[device].height,
colorDepth: 32,
pixelDepth: 32
};
},
configurable: false
});
Object.defineProperty(window, 'innerWidth', {
value: devices[device].width,
writable: false,
configurable: false
});
Object.defineProperty(window, 'innerHeight', {
value: devices[device].height,
writable: false,
configurable: false
});
window.dispatchEvent(new Event('resize'));
}
// Check for existing mobile viewport
function hasMobileViewport() {
const meta = document.querySelector('meta[name="viewport"]');
return meta && /width=device-width/.test(meta.content);
}
// Set adaptive viewport
function setAdaptiveViewport() {
if (!hasMobileViewport()) {
let meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no';
document.head.appendChild(meta);
}
}
// Debounce utility
function debounce(fn, delay) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
// Optimized MutationObserver
const debouncedUpdate = debounce(() => {
setAdaptiveViewport();
document.querySelectorAll('[style*="min-width"], [style*="max-width"]').forEach(el => {
el.style.minWidth = 'unset';
el.style.maxWidth = `${devices[selectedDevice].width}px`;
});
}, 100);
const observer = new MutationObserver(debouncedUpdate);
observer.observe(document.head, { childList: true });
observer.observe(document.body, { childList: true, subtree: true, attributes: true });
// Configurable CSS
GM_addStyle(`
@media screen and (min-width: 768px) {
html, body {
max-width: ${devices[selectedDevice].width}px !important;
margin: 0 auto !important;
overflow-x: hidden !important;
}
.desktop-only, [class*="desktop"] {
display: none !important;
}
.mobile-only, [class*="mobile"] {
display: block !important;
}
}
`);
// Detect mobile URL
async function detectMobileUrl(url) {
if (typeof url !== 'string' || url.includes('m.') || url.includes('/mobile/')) return url;
let mobileUrl = url.replace(/(https?:\/\/)([^\/]+)/, '$1m.$2');
try {
let response = await fetch(mobileUrl, { method: 'HEAD' });
if (response.ok) return mobileUrl;
mobileUrl = url + (url.includes('?') ? '&' : '?') + 'mobile=1';
response = await fetch(mobileUrl, { method: 'HEAD' });
if (response.ok) return mobileUrl;
} catch (e) {
console.log(`Mobile URL detection failed for ${mobileUrl}:`, e);
}
return url;
}
// Intercept fetch requests
let originalFetch = window.fetch;
window.fetch = async function(url, options = {}) {
if (GM_getValue('disableRedirection', false)) return originalFetch(url, options);
const mobileUrl = await detectMobileUrl(url);
return originalFetch(mobileUrl, options);
};
// Intercept XHR requests
let originalXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...args) {
this._url = url;
if (GM_getValue('disableRedirection', false)) {
return originalXHROpen.apply(this, [method, url, ...args]);
}
let mobileUrl = url;
if (typeof url === 'string' && !url.includes('m.') && !url.includes('/mobile/')) {
mobileUrl = url.replace(/(https?:\/\/)([^\/]+)/, '$1m.$2');
}
return originalXHROpen.apply(this, [method, mobileUrl, ...args]);
};
// Simulate touch support
function simulateTouchSupport() {
if (!('TouchEvent' in window)) {
window.TouchEvent = function() {};
Object.defineProperty(window, 'TouchEvent', {
value: function() {
return { touches: [{ clientX: 0, clientY: 0 }], targetTouches: [], changedTouches: [] };
},
writable: false,
configurable: false
});
}
window.ontouchstart = window.ontouchstart || function() {};
Object.defineProperty(window, 'ontouchstart', {
value: function() {},
writable: false,
configurable: false
});
}
// Menu commands
GM_registerMenuCommand('Select Device', () => {
const device = prompt('Enter device (iPhone14, Pixel7):', selectedDevice);
if (devices[device]) {
GM_setValue('device', device);
location.reload();
} else {
alert('Invalid device. Available: iPhone14, Pixel7');
}
});
GM_registerMenuCommand('Toggle URL Redirection', () => {
const current = GM_getValue('disableRedirection', false);
GM_setValue('disableRedirection', !current);
alert(`URL Redirection: ${!current ? 'Disabled' : 'Enabled'}`);
location.reload();
});
GM_registerMenuCommand('Create Custom Device', () => {
const profile = prompt('Enter JSON: { "name": "Custom", "userAgent": "...", "platform": "...", "vendor": "...", "width": 360, "height": 640, "touchPoints": 5 }');
try {
const parsed = JSON.parse(profile);
const profiles = GM_getValue('customProfiles', {});
profiles[parsed.name] = parsed;
GM_setValue('customProfiles', profiles);
GM_setValue('device', parsed.name);
location.reload();
} catch (e) {
alert('Invalid JSON');
}
});
// Initialize
if (document.contentType !== 'text/html') return;
spoofDevice(selectedDevice);
setAdaptiveViewport();
simulateTouchSupport();
})();