Force all iOS web videos to play inline using playsinline attribute.
// ==UserScript==
// @name iOS Video Force Inline Playback
// @name:zh-CN iOS 网页视频强制内嵌播放
// @namespace https://greasyfork.org/users/1603433
// @version 1.4
// @description Force all iOS web videos to play inline using playsinline attribute.
// @description:zh-CN 强制所有 iOS 网页视频使用 playsinline 内嵌播放
// @author Dason
// @license MIT
// @match *://*/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 核心处理函数:强注内嵌属性
function forceInline(video) {
if (!video || video.dataset.inlineForced) return;
video.playsInline = true;
video.webkitPlaysInline = true;
video.setAttribute('playsinline', 'true');
video.setAttribute('webkit-playsinline', 'true');
video.setAttribute('x5-playsinline', 'true');
video.dataset.inlineForced = 'true';
}
// ================= 原型链劫持 =================
try {
// 劫持 play 方法:确保那些通过 JS 动态创建、还没放入 DOM 树就直接播放的视频被注入 playsinline
const originalPlay = HTMLVideoElement.prototype.play;
HTMLVideoElement.prototype.play = function() {
forceInline(this);
return originalPlay.apply(this, arguments);
};
} catch (e) {
console.error("[InlineVideo] Prototype hijack failed: ", e);
}
// ================= DOM 监听 =================
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
mutation.addedNodes.forEach((node) => {
if (node.tagName === 'VIDEO') {
forceInline(node);
} else if (node.querySelectorAll) {
const videos = node.querySelectorAll('video');
if (videos.length > 0) videos.forEach(forceInline);
}
});
}
});
if (document.documentElement) {
observer.observe(document.documentElement, { childList: true, subtree: true });
} else {
document.addEventListener('DOMContentLoaded', () => {
observer.observe(document.body, { childList: true, subtree: true });
});
}
// ================= 定时器兜底 =================
setInterval(() => {
document.querySelectorAll('video').forEach(forceInline);
}, 2000);
})();