|
31 | 31 | // @name:da Pagetual |
32 | 32 | // @name:fr-CA Pagetual |
33 | 33 | // @namespace hoothin |
34 | | -// @version 1.9.37.124 |
| 34 | +// @version 1.9.37.125 |
35 | 35 | // @description Perpetual pages - powerful auto-pager script. Auto fetching next paginated web pages and inserting into current page for infinite scroll. Support thousands of web sites without any rule. |
36 | 36 | // @description:zh-CN 终极自动翻页 - 加载并拼接下一分页内容至当前页尾,智能适配任意网页 |
37 | 37 | // @description:zh-TW 終極自動翻頁 - 加載並拼接下一分頁內容至當前頁尾,智能適配任意網頁 |
|
4560 | 4560 | return segs.length ? '/' + segs.join('/') : null; |
4561 | 4561 | } |
4562 | 4562 |
|
4563 | | - const escapeHTMLPolicy = (_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.createPolicy) ? _unsafeWindow.trustedTypes.createPolicy('pagetual_default', { |
4564 | | - createHTML: (string, sink) => string |
4565 | | - }) : null; |
| 4563 | + function parseTrustedTypes(cspString) { |
| 4564 | + const policies = new Set(); |
| 4565 | + const ttRegex = /trusted-types\s+([^;]+)/gi; |
| 4566 | + let match; |
| 4567 | + while ((match = ttRegex.exec(cspString)) !== null) { |
| 4568 | + match[1].trim().split(/\s+/) |
| 4569 | + .forEach(name => { |
| 4570 | + if (name !== "'allow-duplicates'" && name !== "'none'") { |
| 4571 | + policies.add(name.replace(/'/g, '')); |
| 4572 | + } |
| 4573 | + }); |
| 4574 | + } |
| 4575 | + return Array.from(policies); |
| 4576 | + } |
| 4577 | + |
| 4578 | + async function getAvailablePolicyNamesOptimized() { |
| 4579 | + if (_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.getPolicyNames) { |
| 4580 | + const existingNames = _unsafeWindow.trustedTypes.getPolicyNames(); |
| 4581 | + if (existingNames.length > 0) { |
| 4582 | + return new Set(existingNames); |
| 4583 | + } |
| 4584 | + } |
| 4585 | + |
| 4586 | + const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]'); |
| 4587 | + if (meta) { |
| 4588 | + const metaNames = parseTrustedTypes(meta.content); |
| 4589 | + if (metaNames.length > 0) { |
| 4590 | + return new Set(metaNames); |
| 4591 | + } |
| 4592 | + } |
| 4593 | + |
| 4594 | + return new Promise((resolve) => { |
| 4595 | + GM_xmlhttpRequest({ |
| 4596 | + method: "HEAD", |
| 4597 | + url: window.location.href, |
| 4598 | + onload: function(response) { |
| 4599 | + const cspHeader = response.responseHeaders.split('\r\n') |
| 4600 | + .filter(h => h.toLowerCase().startsWith('content-security-policy:')) |
| 4601 | + .map(h => h.substring(26).trim()) |
| 4602 | + .join('; '); |
| 4603 | + |
| 4604 | + const headerNames = parseTrustedTypes(cspHeader); |
| 4605 | + if (headerNames.length > 0) { |
| 4606 | + resolve(new Set(headerNames)); |
| 4607 | + } else { |
| 4608 | + resolve(new Set()); |
| 4609 | + } |
| 4610 | + }, |
| 4611 | + onerror: function(error) { |
| 4612 | + resolve(new Set()); |
| 4613 | + } |
| 4614 | + }); |
| 4615 | + }); |
| 4616 | + } |
| 4617 | + |
| 4618 | + function isTrustedTypesEnforced() { |
| 4619 | + try { |
| 4620 | + document.createElement('div').innerHTML = ''; |
| 4621 | + return false; |
| 4622 | + } catch (e) { |
| 4623 | + return true; |
| 4624 | + } |
| 4625 | + } |
| 4626 | + |
| 4627 | + async function createPolicy() { |
| 4628 | + if (_unsafeWindow.trustedTypes && _unsafeWindow.trustedTypes.createPolicy && isTrustedTypesEnforced()) { |
| 4629 | + const allowedNames = await getAvailablePolicyNamesOptimized(); |
| 4630 | + |
| 4631 | + if (allowedNames.size === 0) { |
| 4632 | + escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy('pagetual_default', { |
| 4633 | + createHTML: (string, sink) => string |
| 4634 | + }); |
| 4635 | + return; |
| 4636 | + } |
| 4637 | + |
| 4638 | + for (const name of allowedNames) { |
| 4639 | + if (name === '*') continue; |
| 4640 | + try { |
| 4641 | + escapeHTMLPolicy = _unsafeWindow.trustedTypes.createPolicy(name, { |
| 4642 | + createHTML: (string, sink) => string |
| 4643 | + }); |
| 4644 | + break; |
| 4645 | + } catch (e) { |
| 4646 | + try { |
| 4647 | + escapeHTMLPolicy = _unsafeWindow.trustedTypes.policies.get(name); |
| 4648 | + if (escapeHTMLPolicy) { |
| 4649 | + break; |
| 4650 | + } |
| 4651 | + } catch (e2) { |
| 4652 | + console.warn(`create '${name}' failed`); |
| 4653 | + } |
| 4654 | + } |
| 4655 | + } |
| 4656 | + } |
| 4657 | + } |
| 4658 | + |
| 4659 | + let escapeHTMLPolicy = null; |
4566 | 4660 |
|
4567 | 4661 | function createHTML(html) { |
4568 | 4662 | return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html; |
|
10290 | 10384 | } |
10291 | 10385 |
|
10292 | 10386 | let pageReady = false; |
10293 | | - function initRules(callback) { |
| 10387 | + async function initRules(callback) { |
| 10388 | + await createPolicy(); |
10294 | 10389 | charset = (document.characterSet || document.charset || document.inputEncoding); |
10295 | 10390 | let equiv = document.querySelector('[http-equiv="Content-Type"]'); |
10296 | 10391 | if (equiv && equiv.content) { |
|
0 commit comments