Cơ chế hoạt động của Nvirya AdGuard
Để hiểu rõ những gì Nvirya AdGuard có thể và không thể làm, trước hết cần phân biệt vị trí của một userscript trong kiến trúc trình duyệt so với tiện ích mở rộng trình duyệt (browser extension) và bộ lọc VPN/DNS.
So sánh các công nghệ lọc nội dung#
Mỗi công cụ lọc nội dung hoạt động ở một tầng khác nhau trên thiết bị và trình duyệt của bạn:
| Công nghệ | Khả năng điển hình | Giới hạn quan trọng |
|---|---|---|
| Userscript (Nvirya AdGuard) | Chạy JavaScript trong trang (@run-at document-start), chèn CSS ẩn phần tử, quan sát và chỉnh sửa cây DOM, đồng thời bọc các API JavaScript (fetch, XMLHttpRequest, sendBeacon, window.open) nơi được hỗ trợ | Phụ thuộc vào thời điểm tiêm script, khả năng của trình quản lý userscript, API trình duyệt, Chính sách bảo mật nội dung (CSP) và cơ chế cô lập sandbox của WebKit; không thể chặn lưu lượng mạng cấp trình duyệt bên ngoài JavaScript |
| Tiện ích mở rộng trình duyệt (Browser extension) | Truy cập được các API đặc quyền của trình duyệt (như declarativeNetRequest hoặc webRequest) để hủy hoặc chuyển hướng yêu cầu mạng trước khi vào trang, kết hợp với content script và CSS | Phụ thuộc vào sự hỗ trợ của nhà sản xuất trình duyệt (bị hạn chế hoặc không có trên nhiều trình duyệt di động), chính sách kho tiện ích, giới hạn Manifest và quyền truy cập tên miền |
| Bộ lọc VPN hoặc DNS (Shadowrocket, Surge, Loon, AdGuard DNS) | Chặn hoặc chuyển hướng phân giải tên miền và gói tin mạng trên toàn hệ điều hành hoặc giao diện mạng trước khi kết nối tới trình duyệt | Không thể kiểm tra hay chỉnh sửa cây DOM của trang, không thể thu gọn khung quảng cáo trống, mở khóa cuộn trang, nhấn nút bỏ qua quảng cáo video, hoặc phân biệt quảng cáo dùng chung tên miền với nội dung chính |
Vì Nvirya AdGuard là một userscript, thế mạnh cốt lõi của nó là dọn dẹp DOM trực tiếp trong trang, ẩn phần tử tương tác theo yêu cầu và bảo vệ điều hướng JavaScript, trong khi phải tuân theo các rào cản tự nhiên của trình duyệt đối với lưu lượng mạng tầng thấp.
Kiến trúc khởi động 3 giai đoạn#
Để giảm thiểu độ trễ khi tải trang, Nvirya AdGuard v11.7.0 chia quá trình khởi tạo (init()) thành 3 giai đoạn tuần tự:
- Giai đoạn 1 — Lõi bảo vệ tức thì (
document-start):- Tiêm script bảo vệ ngữ cảnh chính (
injectMainWorldShield) khi trang web không nằm trong danh sách cho phép hoặc tạm dừng. - Cài đặt các lớp bọc API JavaScript cho
fetch,XMLHttpRequest,navigator.sendBeacon,window.open,document.write,HTMLScriptElement.prototype.srcvàHTMLImageElement.prototype.src. - Cài đặt bộ chặn sự kiện pha bắt giữ (capture-phase) đối với bẫy nhấp chuột vô hình, chuyển hướng liên kết ngoài, ghi bộ nhớ tạm (clipboard) trái phép và giả mạo trạng thái hiển thị tab.
- Loại bỏ các tham số truy vấn theo dõi đã biết (như
utm_*,fbclid,gclid,msclkid) khỏi thanh địa chỉ quahistory.replaceState(cleanTrackingQuery), ngoại trừ tên miền YouTube. - Chèn CSS ẩn quảng cáo (
installCosmeticCSS) và quy tắc tùy chỉnh của trang (installSiteRulesCSS) ngay khidocument.documentElementhoặcdocument.headxuất hiện.
- Tiêm script bảo vệ ngữ cảnh chính (
- Giai đoạn 2 — Xử lý DOM trì hoãn (
DOMContentLoadedhoặc khidocument.bodysẵn sàng):- Gắn Nút thao tác nhanh (FAB) vào bên trong một vùng chứa Shadow DOM mở ở khung chính (
window.self === window.top). Lưu ý rằng việc khởi tạo toàn bộ DOM của bảng điều khiển (ensureSheetBuilt) được trì hoãn tối đa 3 giây hoặc cho đến khi trình duyệt rảnh để giữ tốc độ hiển thị trang ban đầu mượt mà. - Khởi động MutationObserver theo lô (
startObserver) và chạyinitialScan()(hoặcinitYouTubeShield()trên các tên miền YouTube). - Theo dõi thay đổi lịch sử điều hướng SPA (
history.pushState,history.replaceStatevàpopstate).
- Gắn Nút thao tác nhanh (FAB) vào bên trong một vùng chứa Shadow DOM mở ở khung chính (
- Giai đoạn 3 — Tác vụ nền khi rảnh (
requestIdleCallbackhoặc sau 2.000 ms):- Tải số liệu thống kê tích lũy và lịch sử hoạt động 14 ngày từ bộ nhớ lưu trữ.
- Lên lịch quét dự phòng anti-adblock có giới hạn (
600 ms,1.800 msvà4.200 ms). - Đăng ký các lệnh menu cho trình quản lý userscript (
GM_registerMenuCommand). - Kiểm tra bản cập nhật script (mỗi 30 phút) và đồng bộ danh sách tên miền từ xa (mỗi 24 giờ, nếu đã cấu hình).
Lọc cấp độ DOM so với Lọc cấp độ mạng#
Lọc cấp độ DOM#
Lọc cấp độ DOM xử lý các phần tử HTML sau khi chúng được tạo hoặc chèn vào cây tài liệu:
- Chèn CSS ẩn phần tử (Cosmetic CSS): Thẻ
<style data-nvirya-cosmetic>ẩn các bộ chọn quảng cáo phổ biến ([id^="google_ads_"],ins.adsbygoogle,[id^="div-gpt-ad"],[data-ad-slot], các iframe quảng cáo đã biết và[data-nvirya-hidden]) cùng các quy tắc giới hạn theo tên miền cho YouTube, Google Search, Bing Search, Reddit, X/Twitter, Quora và Facebook di động. - Quan sát biến đổi DOM theo lô: Thay vì quét toàn bộ trang sau mỗi thay đổi,
startObserver()gom các nút mới thêm và thay đổi thuộc tính (src,href,style,class,id,data-src,data-srcset) vào hàng đợi giới hạn (MAX_QUEUE = 800) và xử lý theo từng lát thời gian (processInChunks, tối đa8 msmỗi khung hình) thông quarequestIdleCallbackhoặcrequestAnimationFrame. Trên Google Search và Bing Search, các đợt biến đổi được trì hoãn gom nhóm150 ms(RE_SEARCH_DEBOUNCE_HOST) để tránh giật cục khi gõ phím tìm kiếm. - Dọn lớp phủ, nền tối và khôi phục cuộn trang: Khi xóa một hộp thoại quảng cáo (
removeTrackedAdNode), script ghi nhận ngữ cảnh lớp phủ xung quanh (captureOverlayRemovalContext), xóa các lớp nền làm mờ toàn màn hình đi kèm (adjacentBackdropNodes), thu gọn các thanh quảng cáo bám dính trống ở cuối trang (cleanupBottomStickyAdWrappers) và khôi phụcoverflow: autocùngposition: statictrên<html>và<body>(unlockPageScroll) trừ khi trang đang mở một hộp thoại hợp lệ (hasVisibleLegitimateModal).
Bọc API mạng trong JavaScript (và giới hạn của chúng)#
Userscript không thể can thiệp vào tầng mạng nội bộ của trình duyệt. Thay vào đó, Nvirya AdGuard chặn yêu cầu ở tầng API JavaScript trong cả ngữ cảnh userscript (installNetworkGuard) và ngữ cảnh trang chính (mainWorldShield):
- Window.fetch (Fetch API): Khi trang gọi
fetch(url)tới một địa chỉ khớp vớiisAdUrl(u)(hoặcRE_TRACKERkhi bật Lọc kết nối sâu), Nvirya AdGuard không ném lỗi mạng dễ làm kích hoạt anti-adblock. Thay vào đó,createFakeFetchResponsetrả về một đối tượngResponse200 OKgiả lập phù hợp với kiểu dữ liệu mong đợi ({"status":"ok","success":true,"data":[]}cho JSON,/* Nvirya Stub OK */ window.canRunAds = true;cho JavaScript, hoặc chuỗi rỗng cho văn bản thuần). - XMLHttpRequest: Khi
xhr.open(method, url)nhắm tới URL quảng cáo hoặc trình theo dõi bị chặn, script chuyển hướng cuộc gọi nội bộ sang URIdata:text/plain,vô hại và ghi đèreadyState(4),status(200),statusText("OK"),responseTextcùngresponsekhi gọixhr.send(), đồng thời phát các sự kiệnreadystatechange,loadvàloadendgiả lập. - Navigator.sendBeacon: Các gói tin beacon bị chặn sẽ trả về
truengay lập tức mà không gửi dữ liệu qua mạng. - Thuộc tính động
<script>và<img>: Khi gán.srchoặcsetAttribute('src', ...)trênHTMLScriptElementtrỏ tới tên miền quảng cáo, script đổitype = "javascript/blocked"và phát sự kiệnloadgiả lập (triggerFakeScriptLoad). Khi gán.srctrênHTMLImageElementtrỏ tới URL quảng cáo, script giả lập một ảnh32×32đã tải xong (complete = true,naturalWidth = 32,naturalHeight = 32).
Những gì hook JavaScript không thể chặn:
- Tài nguyên con khai báo tĩnh trong HTML được trình duyệt tải trước khi hook của userscript kịp chạy (chẳng hạn thẻ
<img src="...">hoặc<iframe src="...">tĩnh được bộ quét tải trước của trình duyệt nạp sớm, dù bộ lọc DOM vẫn sẽ ẩn hoặc xóa phần tử đó sau khi tạo). - Yêu cầu mạng từ CSS (như
background-image: url(...)hoặc@font-face). - Chuyển hướng HTTP từ máy chủ (
301,302,307,308) hoặc lưu lượng bên trong các iframe khác nguồn (cross-origin) nơi trình quản lý userscript không tiêm script. - Script ngữ cảnh chính trên các trang có Chính sách bảo mật nội dung (CSP) nghiêm ngặt hoặc giới hạn sandbox của WebKit chặn chèn thẻ
<script>nội tuyến (injectMainWorldShield).
Vì sao quảng cáo trong luồng phát video khác với quảng cáo DOM thông thường#
Quảng cáo biểu ngữ hoặc cửa sổ bật lên truyền thống là một phần tử DOM tách biệt (<iframe>, <ins>, <div>, hoặc <script>) tải từ tên miền quảng cáo bên thứ ba. Việc xóa phần tử hoặc trả về phản hồi rỗng thường loại bỏ quảng cáo một cách gọn gàng.
Quảng cáo video trên các nền tảng như YouTube hoạt động khác hẳn:
- Hạ tầng truyền tải dùng chung: Các phân đoạn video và dữ liệu điều khiển trình phát thường được truyền qua cùng các điểm cuối API cốt lõi (
/youtubei/v1/player,/youtubei/v1/next) và máy chủ CDN (googlevideo.com,youtube.com/videoplayback) phục vụ chính video nội dung bạn đang xem. - Nguy cơ gây lỗi phát video: Nếu một script chặn mù quáng
googlevideo.comhoặc hủy phản hồi/youtubei/v1/player, trình phát video sẽ bị treo, hiện màn hình đen hoặc báo lỗi phát. - Xử lý phối hợp trạng thái trình phát: Vì Nvirya AdGuard phải cho phép các luồng media hợp lệ đi qua (
RE_YOUTUBE_CDN_WHITELIST), script xử lý quảng cáo video qua hai lớp phối hợp bên tronginitYouTubeShield():- Cắt tỉa JSON phản hồi (
installYouTubeJsonPruner): Can thiệp vàoytInitialPlayerResponse,Response.prototype.json(),Response.prototype.text()và phản hồiXMLHttpRequestcủa trình phát để làm rỗngadPlacements,playerAds,adSlots,adBreakHeartbeatParamsvàadBreakRenderertrước khi trình phát đọc dữ liệu. - Tăng tốc qua trạng thái trình phát (
scheduleVideoAdScan): Khi một quảng cáo vẫn lọt vào phần tử<video>HTML5 (phát hiện qua class.ad-showinghoặc.ad-interruptingtrên#movie_player), script sẽ tự động nhấn nút bỏ qua nếu có, tắt tiếng video, tăngplaybackRatelên16và tua tớiduration - 0.05giây ngay khi có dữ liệu thời lượng, sau đó khôi phục âm lượng và tốc độ phát ban đầu của bạn.
- Cắt tỉa JSON phản hồi (
Xem thêm chi tiết tại Giới hạn đã biết và Khắc phục sự cố.