RSS+ : 显示当前网站所有的 RSS

显示当前网站的所有 RSS(如果有的话)

  1. // ==UserScript==
  2. // @name RSS+ : Show Site All RSS
  3. // @name:zh RSS+ : 显示当前网站所有的 RSS
  4. // @name:zh-CN RSS+ : 显示当前网站所有的 RSS
  5. // @name:zh-TW RSS+ : 顯示當前網站所有的 RSS
  6. // @name:ja RSS+ : 現在のサイトのRSSを表示
  7. // @name:ko RSS+ : 현재 사이트의 RSS 표시
  8. // @name:pt-PT RSS+ : Mostrar todos os RSS do site
  9. // @name:pt-BR RSS+ : Mostrar todos os RSS do site
  10. // @name:fr RSS+ : Afficher tous les flux RSS du site
  11. // @description Show All RSS Of The Site (If Any)
  12. // @description:zh 显示当前网站的所有 RSS(如果有的话)
  13. // @description:zh-CN 显示当前网站的所有 RSS(如果有的话)
  14. // @description:zh-TW 顯示當前網站的所有 RSS(如果有的话)
  15. // @description:ja サイトのすべてのRSSを表示します (あれば)
  16. // @description:ko 웹 사이트의 모든 RSS 를 표시합니다 (있는 경우)
  17. // @description:pt-PT Mostra todos os feeds RSS do site (se houver)
  18. // @description:pt-BR Mostra todos os feeds RSS do site (se houver)
  19. // @description:fr Montre tous les flux RSS du site (s'il y en a)
  20. // @license GPL3.0
  21. // @version 1.1.4
  22.  
  23. // @icon data:image/png;base64,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
  24. // @author Wizos
  25. // @namespace https://blog.wizos.me
  26. // @supportURL wizos@qq.com
  27. // @match http://*/*
  28. // @match https://*/*
  29. // @require https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.4.4/qrcode.min.js
  30. // @resource RulerJs https://fastly.jsdelivr.net/gh/wizos/rssplus/Ruler.js
  31. // @grant GM_xmlhttpRequest
  32. // @grant GM_getResourceText
  33. // @grant GM_setClipboard
  34. // @grant GM_notification
  35. // @grant GM_addStyle
  36. // @grant GM_getValue
  37. // @grant GM_setValue
  38. // @grant GM_registerMenuCommand
  39. // @grant unsafeWindow
  40. // @connect rssplus.vercel.app
  41. // @connect rssplus.pages.dev
  42. // @connect rssfind.val.run
  43. // @connect rssplus.deno.dev
  44. // @connect rssplus.mdict.workers.dev
  45. // @noframes
  46. // @run-at document-idle
  47. // ==/UserScript==
  48.  
  49. // 2025.06.29_1.1.4 1.由于流量过大,增加 rssplus.pages.dev, rssfind.val.run, rssplus.deno.dev, rssplus.mdict.workers.dev 域名。2.修复无法使用自定义 RSSHub 域名。3.增加 Folo 订阅。
  50. // 2025.04.05_1.1.3 1.修复火狐136版本无法查看 RSS 问题。2. 支持 NewsBlur 和 The Old Reader。3. 全屏时隐藏图标。4. 保持订阅源 URL 大小写。
  51. // 2025.01.16_1.1.2 1.使用 TTP 给元素增加 innerHTML。2、增加识别 feed.json。
  52. // 2024.10.20_1.1.1 1.修复未开启远程规则的问题。2.增加更多的网站适配。
  53. // 2024.10.08_1.0.9 1.增加支持葡萄牙语和法语(感谢Filipe Mota (BlackSpirits)提供的翻译)。2.支持 RSSHub 访问密钥。3.重构代码。
  54. // 2022.10.18_1.0.8 1.修复 TinyTinyRSS 订阅地址错误问题。2.修复 Bug。
  55. // 2022.07.04_1.0.7 支持用Miniflux订阅(感谢Sevichecc提供的代码https://gist.github.com/Sevichecc/f5608c4ad52e71d98f6fcf74110369df)
  56. // 2022.07.04_1.0.6 修复火狐上因为GSAP库导致无法使用问题
  57. // 2022.05.20_1.0.5 1.解决 jsdelivr 在中国被墙的问题。2.修复bilibili video页面获取feed标题异常问题。
  58. // 2022.04.18_1.0.4 修复导致网页加载卡顿的问题。
  59. // 2022.04.05_1.0.2 1.受unsafe-eval影响,无法本地执行规则时使用远程规则,改用 rssplus.vercel.app 接口。2.调整 UI,每次获取到新 RSS 都同步到 UI 中。3.精简设置项。4.监听 URL 变化,同步获取新的 RSS。
  60. // 2022.04.02_1.0.0 1.将远程规则放到 GitHub。2.修复订阅 RSS 网址的转义问题。
  61. // 2021.12.17_0.9.2 1.支持设置 FreshRSS 一键订阅。2.支持设置带端口的网址。
  62. // 2021.02.24_0.9.1 1.支持开启/关闭二维码。
  63. // 2021.02.19_0.9.0 1.支持鼠标悬停在订阅链接上时展示其二维码,方便扫码订阅。
  64. // 2021.02.05_0.8.1 1.url参数用base64编码,防止服务端获取url参数时,漏掉query部分的数据。
  65. // 2021.02.03_0.8.0 1.支持小屏幕展示。2.支持设置 TinyTinyRSS 服务的域名。
  66. // 2021.01.05_0.7.3 1.改用 GM_xmlhttpRequest。2.改用 rssfinder.vercel.app 接口。
  67. // 2020.12.16_0.7.2 1.修复 bug。
  68. // 2020.12.06_0.7.1 1.调整搞定。2.优化代码。
  69. // 2020.11.16_0.7.0 1.支持设置 InoReader 服务的域名。2.在打印页面时隐藏。3.修复影响页面样式的问题。
  70. // 2020.09.11_0.6.4 1.支持 RSSHub 服务器为 IP 地址。2.被识别的 RSS 地址不再转换为小写(因为 news.google.com 的小写地址打不开)
  71. // 2020.04.28_0.6.3 修复改了脚本name导致无法更新的bug。
  72. // 2020.04.27_0.6.2 修复rsshub domain默认为undefined的bug。
  73. // 2020.04.26_0.6.1 支持设置 RSSHub 服务的域名。
  74. // 2020.03.01_0.6 1.可设置点击“订阅”时打开的rss服务商(feedly,inoreadly)。2.修复火狐浏览器下无法展示的问题。
  75. // 2019.09.29_0.5 增加hexo站点的rss嗅探规则。
  76. // 2019.04.26_0.4.2 1.修复默认圆圈状态下宽度太宽,导致遮挡下层页面事件触发的问题。2.将icon由字体改为svg形式,修复部分站点无法显示icon的问题。3.优化RSS没有title时的默认名称。
  77. // 2018.11.10_0.4.1 关闭发现RSS后的h5通知
  78. // 2018.10.29_0.4 1.在无法链接服务器时也能展示本地的RSS;2.针对开启 Content-Security-Policy 的网站直接展示本地的RSS;3.发现RSS后,进行h5通知
  79. // 2018.10.23_0.4 1.增加识别为 wordpress 站点时,尝试使用/feed后缀;2.增加多语言支持
  80. // 2018.10.16_0.3 1.改为iframe方式显示,兼容性更好;2.改为post方式传递页面地址;
  81. // 2018.10.14_0.2 第一版 RSS+ 成型;
  82. // 2018.09.16_0.1 在 RSS+Atom Feed Subscribe Button Generator 脚本基础上增加连接后端获取feed的方式;
  83.  
  84. (function() {
  85. 'use strict';
  86.  
  87. // 过滤掉明确不包含 RSS 源的URL
  88. if (location.href.match(/(api\.wizos\.me)|(feedly\.com\/i\/subscription)|(inoreader\.com\/feed\/http)/i)) {
  89. return;
  90. }
  91. // 修复火狐上不支持 trustedTypes 问题
  92. if (typeof window.trustedTypes === 'undefined') {
  93. window.trustedTypes = {
  94. createPolicy: function(name, rules) {
  95. return rules;
  96. }
  97. };
  98. }
  99.  
  100. // 国际化文本
  101. const i18n = {
  102. zh: {
  103. noTitle: "无标题",
  104. copied: "已复制",
  105. copy: "复制",
  106. copySucceeded: "复制成功",
  107. follow: "订阅",
  108. found: "发现 ",
  109. feed: "订阅源数量:",
  110. clickToView: "点击右下角的数字查看",
  111. useFeedly: "使用 Feedly 订阅",
  112. useInoreader: "使用 Inoreader 订阅",
  113. useTinytinyrss: "使用 Tiny Tiny RSS 订阅",
  114. useFreshrss: "使用 FreshRSS 订阅",
  115. useMiniflux: "使用 Miniflux 订阅",
  116. useFoloReader: "使用 Folo 订阅",
  117. useNewsBlur: "使用 NewsBlur 订阅",
  118. useTheOldReader: "使用 The Old Reader 订阅",
  119. settingRSShubDomain: "设置 RSSHub 的域名",
  120. settingRSShubAccessKey: "设置 RSSHub 的访问密钥",
  121. settingInoreaderDomain: "设置 Inoreader 的域名",
  122. settingTinytinyrssDomain: "设置 Tiny Tiny RSS 的域名",
  123. settingFreshrssDomain: "设置 FreshRSS 的域名",
  124. settingMinifluxDomain: "设置 Miniflux 的域名",
  125. domainIsWrong: "服务器地址格式有误,请检查",
  126. enableQRCode: "启用/禁用二维码",
  127. enabled: "已启用",
  128. disabled: "已禁用",
  129. close: "关闭"
  130. },
  131. zhtw: {
  132. noTitle: "無標題",
  133. copied: "已複製",
  134. copy: "複製",
  135. copySucceeded: "複製成功",
  136. follow: "訂閱",
  137. found: "發現 ",
  138. feed: "訂閱源數量:",
  139. clickToView: "點擊右下角的數字查看",
  140. useFeedly: "使用 Feedly 訂閱",
  141. useInoreader: "使用 Inoreader 訂閱",
  142. useTinytinyrss: "使用 Tiny Tiny RSS 訂閱",
  143. useFreshrss: "使用 FreshRSS 訂閱",
  144. useMiniflux: "使用 Miniflux 訂閱",
  145. useFoloReader: "使用 Folo 訂閱",
  146. useNewsBlur: "使用 NewsBlur 訂閱",
  147. useTheOldReader: "使用 The Old Reader 訂閱",
  148. settingRSShubDomain: "設定 RSSHub 的網域",
  149. settingRSShubAccessKey: "設定 RSSHub 的存取密鑰",
  150. settingInoreaderDomain: "設定 Inoreader 的網域",
  151. settingTinytinyrssDomain: "設定 Tiny Tiny RSS 的網域",
  152. settingFreshrssDomain: "設定 FreshRSS 的網域",
  153. settingMinifluxDomain: "設定 Miniflux 的網域",
  154. domainIsWrong: "伺服器位址格式有誤,請檢查",
  155. enableQRCode: "啟用/停用 QR 碼",
  156. enabled: "已啟用",
  157. disabled: "已停用",
  158. close: "關閉"
  159. },
  160. en: {
  161. noTitle: "Untitled",
  162. copied: "Copied",
  163. copy: "Copy",
  164. copySucceeded: "Copy succeeded",
  165. follow: "Subscribe",
  166. found: "Found ",
  167. feed: "Number of feeds: ",
  168. clickToView: "Click the number in the bottom right to view",
  169. useFeedly: "Use Feedly subscription",
  170. useInoreader: "Use Inoreader subscription",
  171. useTinytinyrss: "Use Tiny Tiny RSS subscription",
  172. useFreshrss: "Use FreshRSS subscription",
  173. useMiniflux: "Use Miniflux subscription",
  174. useFoloReader: "Use Folo subscription",
  175. useNewsBlur: "Use NewsBlur subscription",
  176. useTheOldReader: "Use The Old Reader subscription",
  177. settingRSShubDomain: "Set RSSHub domain",
  178. settingRSShubAccessKey: "Set RSSHub access key",
  179. settingInoreaderDomain: "Set Inoreader domain",
  180. settingTinytinyrssDomain: "Set Tiny Tiny RSS domain",
  181. settingFreshrssDomain: "Set FreshRSS domain",
  182. settingMinifluxDomain: "Set Miniflux domain",
  183. domainIsWrong: "Error in domain name format. Please check",
  184. enableQRCode: "Enable/disable QR code",
  185. enabled: "Enabled",
  186. disabled: "Disabled",
  187. close: "Close"
  188. },
  189. ja: {
  190. noTitle: "無題",
  191. copied: "コピーしました",
  192. copy: "コピー",
  193. copySucceeded: "コピーに成功しました",
  194. follow: "購読",
  195. found: "見つかりました ",
  196. feed: "フィード数:",
  197. clickToView: "右下の数字をクリックして表示",
  198. useFeedly: "Feedly で購読",
  199. useInoreader: "Inoreader で購読",
  200. useTinytinyrss: "Tiny Tiny RSS で購読",
  201. useFreshrss: "FreshRSS で購読",
  202. useMiniflux: "Miniflux で購読",
  203. useFoloReader: "Folo で購読",
  204. useNewsBlur: "NewsBlur で購読",
  205. useTheOldReader: "The Old Reader で購読",
  206. settingRSShubDomain: "RSSHub のドメインを設定",
  207. settingRSShubAccessKey: "RSSHub のアクセスキーを設定",
  208. settingInoreaderDomain: "Inoreader のドメインを設定",
  209. settingTinytinyrssDomain: "Tiny Tiny RSS のドメインを設定",
  210. settingFreshrssDomain: "FreshRSS のドメインを設定",
  211. settingMinifluxDomain: "Miniflux のドメインを設定",
  212. domainIsWrong: "サーバーアドレスの形式に問題があります。確認してください",
  213. enableQRCode: "QRコードの有効/無効を切り替え",
  214. enabled: "有効",
  215. disabled: "無効",
  216. close: "閉じる"
  217. },
  218. ko: {
  219. noTitle: "제목 없음",
  220. copied: "복사됨",
  221. copy: "복사",
  222. copySucceeded: "복사 성공",
  223. follow: "구독",
  224. found: "발견 ",
  225. feed: "피드 수: ",
  226. clickToView: "오른쪽 하단의 숫자를 클릭하여 보기",
  227. useFeedly: "Feedly로 구독",
  228. useInoreader: "Inoreader로 구독",
  229. useTinytinyrss: "Tiny Tiny RSS로 구독",
  230. useFreshrss: "FreshRSS로 구독",
  231. useMiniflux: "Miniflux로 구독",
  232. useFoloReader: "Folo로 구독",
  233. useNewsBlur: "NewsBlur로 구독",
  234. useTheOldReader: "The Old Reader로 구독",
  235. settingRSShubDomain: "RSSHub 도메인 설정",
  236. settingRSShubAccessKey: "RSSHub 액세스 키 설정",
  237. settingInoreaderDomain: "Inoreader 도메인 설정",
  238. settingTinytinyrssDomain: "Tiny Tiny RSS 도메인 설정",
  239. settingFreshrssDomain: "FreshRSS 도메인 설정",
  240. settingMinifluxDomain: "Miniflux 도메인 설정",
  241. domainIsWrong: "서버 주소 형식에 문제가 있습니다. 확인해 주세요",
  242. enableQRCode: "QR 코드 활성화/비활성화",
  243. enabled: "활성화됨",
  244. disabled: "비활성화됨",
  245. close: "닫기"
  246. },
  247. ptpt: {
  248. noTitle: "Sem título",
  249. copied: "Copiado",
  250. copy: "Copiar",
  251. copySucceeded: "Cópia bem-sucedida",
  252. follow: "Seguir",
  253. found: "Encontrado ",
  254. feed: "Número de feeds: ",
  255. clickToView: "Clique no número no canto inferior direito para visualizar",
  256. useFeedly: "Utilizar a subscrição do Feedly",
  257. useInoreader: "Utilizar a subscrição do InoReader",
  258. useTinytinyrss: "Utilizar a subscrição do TinyTinyRSS",
  259. useFreshrss: "Utilizar a subscrição do FreshRSS",
  260. useMiniflux: "Utilizar a subscrição do Miniflux",
  261. useFoloReader: "Utilizar a subscrição do Folo",
  262. useNewsBlur: "Utilizar a subscrição do NewsBlur",
  263. useTheOldReader: "Utilizar a subscrição do The Old Reader",
  264. settingRSShubDomain: "Definir o domínio do RSSHub",
  265. settingRSShubAccessKey: "Definir a chave de acesso do RSSHub",
  266. settingInoreaderDomain: "Definir o domínio do InoReader",
  267. settingTinytinyrssDomain: "Definir o domínio do TinyTinyRSS",
  268. settingFreshrssDomain: "Definir o domínio do FreshRSS",
  269. settingMinifluxDomain: "Definir o domínio do Miniflux",
  270. domainIsWrong: "Erro no formato do nome do domínio. Por favor, verifica-o",
  271. enableQRCode: "Ativar/desativar o código QR",
  272. enabled: "Ativado",
  273. disabled: "Desativado",
  274. close: "Fechar"
  275. },
  276. ptbr: {
  277. noTitle: "Sem título",
  278. copied: "Copiado",
  279. copy: "Copiar",
  280. copySucceeded: "Copiado com sucesso",
  281. follow: "Seguir",
  282. found: "Encontrado ",
  283. feed: "Número de feeds: ",
  284. clickToView: "Clique no número no canto inferior direito para visualizá-lo",
  285. useFeedly: "Usar assinatura do Feedly",
  286. useInoreader: "Usar assinatura do Inoreader",
  287. useTinytinyrss: "Usar assinatura do Tiny Tiny RSS",
  288. useFreshrss: "Usar assinatura do FreshRSS",
  289. useMiniflux: "Usar assinatura do Miniflux",
  290. useFoloReader: "Usar assinatura do Folo",
  291. useNewsBlur: "Usar assinatura do NewsBlur",
  292. useTheOldReader: "Usar assinatura do The Old Reader",
  293. settingRSShubDomain: "Configurar domínio do RSSHub",
  294. settingRSShubAccessKey: "Configurar chave de acesso do RSSHub",
  295. settingInoreaderDomain: "Configurar domínio do Inoreader",
  296. settingTinytinyrssDomain: "Configurar domínio do Tiny Tiny RSS",
  297. settingFreshrssDomain: "Configurar domínio do FreshRSS",
  298. settingMinifluxDomain: "Configurar domínio do Miniflux",
  299. domainIsWrong: "Erro no formato do nome de domínio. Por favor, verifique",
  300. enableQRCode: "Ativar/desativar código QR",
  301. enabled: "Ativado",
  302. disabled: "Desativado",
  303. close: "Fechar"
  304. },
  305. fr: {
  306. noTitle: "Sans titre",
  307. copied: "Copié",
  308. copy: "Copier",
  309. copySucceeded: "Copie réussie",
  310. follow: "S'abonner",
  311. found: "Trouvé ",
  312. feed: "Nombre de flux : ",
  313. clickToView: "Cliquer sur le numéro en bas à droite pour le visualiser",
  314. useFeedly: "Utiliser l'abonnement Feedly",
  315. useInoreader: "Utiliser l'abonnement Inoreader",
  316. useTinytinyrss: "Utiliser l'abonnement Tiny Tiny RSS",
  317. useFreshrss: "Utiliser l'abonnement FreshRSS",
  318. useMiniflux: "Utiliser l'abonnement Miniflux",
  319. useFoloReader: "Utiliser l'abonnement Folo",
  320. useNewsBlur: "Utiliser l'abonnement NewsBlur",
  321. useTheOldReader: "Utiliser l'abonnement The Old Reader",
  322. settingRSShubDomain: "Configuration du domaine RSSHub",
  323. settingRSShubAccessKey: "Configuration la clé d'accès de RSSHub",
  324. settingInoreaderDomain: "Configuration du domaine Inoreader",
  325. settingTinytinyrssDomain: "Configuration du domaine TinyTinyRSS",
  326. settingFreshrssDomain: "Configuration du domaine FreshRSS",
  327. settingMinifluxDomain: "Configuration du domaine Miniflux",
  328. domainIsWrong: "Erreur dans le format du nom de domaine. Veuillez vérifier",
  329. enableQRCode: "Activer/désactiver le code QR",
  330. enabled: "Activé",
  331. disabled: "Désactivé",
  332. close: "Fermer"
  333. }
  334. };
  335.  
  336. const ICON_CLOSE = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 256 256"><path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path></svg>'
  337. i18n.zhcn = i18n.zh;
  338. // 获取当前语言
  339. const lang = (navigator.language || 'en').replace('-', "").toLowerCase();
  340. const t = i18n[lang] || i18n.en;
  341.  
  342. const proxyList = [
  343. "https://rssplus.vercel.app/",
  344. "https://rssplus.pages.dev/",
  345. "https://rssfind.val.run/",
  346. "https://rssplus.deno.dev/",
  347. "https://rssplus.mdict.workers.dev/"
  348. ];
  349.  
  350. GM_registerMenuCommand(t.useFeedly, function() {
  351. GM_setValue("rss_service", "feedly");
  352. });
  353. GM_registerMenuCommand(t.useInoreader, function() {
  354. const input = window.prompt(t.settingInoreaderDomain, GM_getValue("inoreader_domain", "https://www.inoreader.com"));
  355. if (input !== null) {
  356. if (isValidUrl(input)) {
  357. GM_setValue("inoreader_domain", input);
  358. GM_setValue("rss_service", "inoreader");
  359. } else {
  360. alert(t.domainIsWrong);
  361. }
  362. }
  363. });
  364. GM_registerMenuCommand(t.useTinytinyrss, function() {
  365. const input = window.prompt(t.settingTinytinyrssDomain, GM_getValue("tinytinyrss_domain", "https://www.example.com"));
  366. if (input !== null) {
  367. if (isValidUrl(input)) {
  368. GM_setValue("tinytinyrss_domain", input);
  369. GM_setValue("rss_service", "tinytinyrss");
  370. } else {
  371. alert(t.domainIsWrong);
  372. }
  373. }
  374. });
  375. GM_registerMenuCommand(t.useFreshrss, function() {
  376. const input = window.prompt(t.settingFreshrssDomain, GM_getValue("freshrss_domain", "https://www.example.com"));
  377. if (input !== null) {
  378. if (isValidUrl(input)) {
  379. GM_setValue("freshrss_domain", input);
  380. GM_setValue("rss_service", "freshrss");
  381. } else {
  382. alert(t.domainIsWrong);
  383. }
  384. }
  385. });
  386. GM_registerMenuCommand(t.useMiniflux, function() {
  387. const input = window.prompt(t.settingMinifluxDomain, GM_getValue("miniflux_domain", "https://www.example.com"));
  388. if (input !== null) {
  389. if (isValidUrl(input)) {
  390. GM_setValue("miniflux_domain", input);
  391. GM_setValue("rss_service", "miniflux");
  392. } else {
  393. alert(t.domainIsWrong);
  394. }
  395. }
  396. });
  397. GM_registerMenuCommand(t.useFoloReader, function() {
  398. GM_setValue("rss_service", "folo");
  399. });
  400. GM_registerMenuCommand(t.useNewsBlur, function() {
  401. GM_setValue("rss_service", "newsblur");
  402. });
  403. GM_registerMenuCommand(t.useTheOldReader, function() {
  404. GM_setValue("rss_service", "theoldreader");
  405. });
  406. GM_registerMenuCommand(t.enableQRCode, function() {
  407. if (!GM_getValue("enable_qr_code", true)) {
  408. GM_setValue("enable_qr_code", true);
  409. GM_notification({
  410. text: t.enabled,
  411. title: t.enableQRCode,
  412. timeout: 2000
  413. });
  414. } else {
  415. GM_setValue("enable_qr_code", false);
  416. GM_notification({
  417. text: t.disabled,
  418. title: t.enableQRCode,
  419. timeout: 2000
  420. });
  421. }
  422. });
  423.  
  424. GM_registerMenuCommand(t.settingRSShubDomain, function() {
  425. const input = window.prompt(t.settingRSShubDomain, GM_getValue("rsshub_domain", "https://rsshub.app"));
  426. if (input !== null) {
  427. if (isValidUrl(input)) {
  428. GM_setValue("rsshub_domain", input);
  429. } else {
  430. alert(t.domainIsWrong);
  431. }
  432. }
  433. });
  434.  
  435. GM_registerMenuCommand(t.settingRSShubAccessKey, function() {
  436. const input = window.prompt(t.settingRSShubAccessKey, GM_getValue("rsshub_access_key"));
  437. if (input !== null) {
  438. GM_setValue("rsshub_access_key", input);
  439. }
  440. });
  441.  
  442. // 使用 forceInner 可能会报错 forceInner 被禁用
  443. // 使用 default ,这将禁用 TrustedHTML 分配(CSP)保护
  444. // window.trustedTypes.createPolicy('default', {createHTML: (string, sink) => string});
  445. // WORKAROUND: TypeError: Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment.
  446. const TTP = window.trustedTypes.createPolicy("forceInner", {
  447. createHTML: (x) => x
  448. });
  449.  
  450. // 主要功能类
  451. const feedsSet = new Set();
  452. const suffixes = [
  453. '/feed', '/rss', '/rss.xml', '/atom.xml', '/feed.xml', '/rss.json', '/atom.json', '/feed.json', //'/index.xml',
  454. '/?feed=rss', '/?feed=rss2', '/blog/feed', '/blog/rss', '/latest/rss',
  455. '/news/atom', '/feed/index.xml'
  456. ];
  457. let rpDiv;
  458. let rpStyle;
  459. let rpIframe;
  460. let rpDocument;
  461. let rpBadge;
  462. let rpDialog;
  463. let rpDialogTitle;
  464. let rpDialogFeeds;
  465.  
  466. // 检测Feed
  467. function findFeeds() {
  468. const rpDiv = document.getElementById('rss-plus');
  469. if(rpDiv){
  470. return;
  471. }
  472. findKnownFeeds();
  473. findUnknownFeeds();
  474. findCloudFeeds();
  475. }
  476.  
  477. // 检测已知的Feed
  478. // 获取在<head>的<link>元素中,已经声明为RSS的链接
  479. function findKnownFeeds() {
  480. const links = document.getElementsByTagName("link");
  481. for (const link of links) {
  482. const { href, type, title = document.title } = link;
  483. if (type && (type.match(/.+\/(rss|rdf|atom|feed\+json)/i) || type.match(/^text\/xml$/i))) {
  484. addFeed(title, href);
  485. }
  486. }
  487. }
  488.  
  489. // 寻找未明确标示的RSS源
  490. function findUnknownFeeds() {
  491. // links 属性返回一个文档中所有具有 href 属性值的 <area> 元素与 <a> 元素的集合
  492. const links = document.links || document.getElementsByTagName("a");
  493. for (const link of links) {
  494. const href = link.href;
  495. if (
  496. href.match(/^(https|http|ftp|feed).*([.\/]rss([.\/]xml|\.aspx|\.jsp|\/)?$|\/node\/feed$|\/feed(\.xml|\/$|$)|\/rss\/[a-z0-9]+$|[?&;](rss|xml)=|[?&;]feed=rss[0-9.]*$|[?&;]action=rss_rc$|feeds\.feedburner\.com\/[\w\W]+$)/i)
  497. || href.match(/^(https|http|ftp|feed).*\/atom(\.xml|\.aspx|\.jsp|\/)?$|[?&;]feed=atom[0-9.]*$/i)
  498. || href.match(/^(https|http|ftp|feed).*(\/feeds?\/[^.\/]*\.xml$|.*\/index\.xml$|feed\/msgs\.xml(\?num=\d+)?$)/i)
  499. || href.match(/^(https|http|ftp|feed).*\.rdf$/i)
  500. || href.match(/^(rss|feed):\/\//i)
  501. || href.match(/^(https|http):\/\/feed\./i)
  502. ) {
  503. addFeed(link.title || link.textContent || link.innerText || document.title, href);
  504. }
  505. }
  506.  
  507. checkFeedForPlatform("html > head > link", /(wp-content)/i); // WordPress
  508. checkFeedForPlatform("html > body footer a", /(bitcron\.com|typecho\.org|hexo\.io)/i); // Blog platforms
  509. }
  510.  
  511. function findCloudFeeds() {
  512. const url = optimizeLink(location.href);
  513. const res = document.documentElement.outerHTML;
  514. try {
  515. findCloudFeedsByEval(url, res);
  516. } catch (e) {
  517. console.error("无法通过 Eval 执行:", e);
  518. findCloudFeedsByAPI(url);
  519. }
  520. }
  521. function findCloudFeedsByEval(url, res) {
  522. return function(jsStr, url, res) {
  523. if (isEmpty(jsStr)) {
  524. throw new Error("未获取到可执行脚本");
  525. }
  526. const Ruler = Function(`"use strict";return (${jsStr})`)();
  527.  
  528. const list = Ruler.find(url, res);
  529. if (!list) {
  530. return;
  531. }
  532. list.forEach(element => {
  533. addFeed(element.title || document.title, element.link);
  534. });
  535. }.call(window, GM_getResourceText('RulerJs'), url, res);
  536. }
  537.  
  538. function findCloudFeedsByAPI(url) {
  539. console.log("请求远程:" + url);
  540. try {
  541. fetch(`${proxyList[Math.floor(Math.random() * proxyList.length)]}api/find?url=${encodeURIComponent(url)}`, {method: 'get', timeout: 5000}) // 设置超时
  542. .then(async response => {
  543. if (response.status === 200) {
  544. const obj = JSON.parse(await response.text());
  545. if (!obj) {
  546. return;
  547. }
  548. obj.forEach(element => {
  549. addFeed(element.title || document.title, element.link);
  550. });
  551. }
  552. })
  553. .catch(err => console.error('检测 feed 异常:', err))
  554. } catch (error) {
  555. console.error('检测 feed 异常:', error);
  556. }
  557. }
  558. function checkFeedForPlatform(selector, regex) {
  559. const links = document.querySelectorAll(selector);
  560. for (const link of links) {
  561. if (link.href.match(regex)) {
  562. checkFeed(`${document.location.protocol}//${document.domain}`);
  563. break; // 找到匹配项后立即退出
  564. }
  565. }
  566. }
  567. async function checkFeed(url) {
  568. try {
  569. const requests = suffixes.map(suffix =>
  570. fetch(url + suffix, {method: 'HEAD', timeout: 5000}) // 设置超时
  571. .then(response => {
  572. if (response.status === 200) {
  573. addFeed(document.title, url + suffix);
  574. }
  575. })
  576. .catch(err => console.error('检测 feed 异常:', err))
  577. );
  578. await Promise.all(requests); // 并行处理所有请求
  579. } catch (error) {
  580. console.error('检测 feed 异常:', error);
  581. }
  582. }
  583.  
  584. // 添加Feed
  585. function addFeed(title, url) {
  586. console.log("添加RSS:" + title + " => " + url);
  587. if (url.match(/(api\.wizos\.me)|(feedly\.com\/i\/subscription)|(inoreader\.com\/feed\/http)/i)) {
  588. return;
  589. }
  590.  
  591. if (feedsSet.size === 0){
  592. initUI();
  593. }
  594. let absoluteUrl = new URL(url, document.location.href).href;
  595. let lookupValue = absoluteUrl.toLowerCase();
  596.  
  597. if (!feedsSet.has(lookupValue)) {
  598. feedsSet.add(lookupValue);
  599. if(url.match(/^https*:\/\/rsshub.app/i)){
  600. const rsshubDomain = GM_getValue("rsshub_domain");
  601. if(rsshubDomain != null && rsshubDomain !== ""){
  602. absoluteUrl = absoluteUrl.replace(/^https*:\/\/rsshub.app/i, rsshubDomain);
  603. }
  604.  
  605. const rsshubAccessKey = GM_getValue("rsshub_access_key");
  606. if(rsshubAccessKey != null && rsshubAccessKey !== ""){
  607. const uri = new URL(absoluteUrl);
  608. uri.searchParams.set('key', rsshubAccessKey);
  609. absoluteUrl = uri.href;
  610. }
  611. }
  612.  
  613. updateBadge();
  614. updateDialog(title || t.noTitle, absoluteUrl);
  615. }
  616. }
  617.  
  618. function observeUrlChange() {
  619. const _historyWrap = function(type) {
  620. const orig = history[type];
  621. const e = new Event(type);
  622. return function() {
  623. const rv = orig.apply(this, arguments);
  624. e.arguments = arguments;
  625. window.dispatchEvent(e);
  626. return rv;
  627. };
  628. };
  629. history.pushState = _historyWrap('pushState');
  630. history.replaceState = _historyWrap('replaceState');
  631.  
  632. window.addEventListener('pushState', () => {
  633. window.dispatchEvent(new Event('locationchange'));
  634. });
  635. window.addEventListener('replaceState', () => {
  636. window.dispatchEvent(new Event('locationchange'));
  637. });
  638. window.addEventListener('popstate', () => {
  639. window.dispatchEvent(new Event('locationchange'));
  640. });
  641. window.addEventListener('hashchange', function() {
  642. window.dispatchEvent(new Event('locationchange'));
  643. }, false);
  644. window.addEventListener('locationchange', ()=> {
  645. reset();
  646. findFeeds();
  647. });
  648. }
  649.  
  650. // 初始化UI
  651. function initUI() {
  652. rpStyle = document.createElement('style');
  653. rpStyle.innerHTML = TTP.createHTML(
  654. `
  655. @media print {
  656. #rss-plus {
  657. display: none;
  658. }
  659. }
  660.  
  661. #rss-plus {
  662. position: fixed;
  663. bottom: 60px;
  664. right: 5px;
  665. z-index: 9999;
  666. }
  667.  
  668. #rss-plus > iframe {
  669. display: block !important;
  670. max-width: 100% !important;
  671. border: 0px !important;
  672. }
  673. `
  674. );
  675. document.head.appendChild(rpStyle);
  676.  
  677. rpDiv = document.createElement('div');
  678. rpDiv.id = 'rss-plus';
  679. document.body.appendChild(rpDiv);
  680.  
  681. rpIframe = document.createElement("iframe");
  682. rpIframe.id = "rss-plus-iframe";
  683. rpIframe.allowTransparency = "true";
  684. if (navigator.userAgent.indexOf("Firefox") !== -1) {
  685. rpIframe.src = "javascript:";
  686. }
  687. rpDiv.appendChild(rpIframe);
  688. rpDocument = rpIframe.contentDocument || rpIframe.contentWindow.document;// || rssPlusEnvironment.window.document;
  689.  
  690. const rpBoxStyle = rpDocument.createElement("style");
  691.  
  692. rpBoxStyle.textContent = TTP.createHTML(`
  693. .hover-reveal {
  694. position: fixed;
  695. width: 80px;
  696. height: 80px;
  697. top: 0;
  698. left: 0;
  699. pointer-events: none;
  700. opacity: 0
  701. }
  702.  
  703. .hover-reveal__inner,.hover-reveal__img {
  704. width: 100%;
  705. height: 100%;
  706. position: relative
  707. }
  708.  
  709. .hover-reveal__deco {
  710. width: 100%;
  711. height: 100%;
  712. position: absolute;
  713. top: 0;
  714. left: 0;
  715. background-color: #181314
  716. }
  717.  
  718. .hover-reveal__img {
  719. background-size: cover;
  720. background-position: 50% 50%
  721. }
  722.  
  723. body {
  724. margin: 0px;
  725. }
  726.  
  727. #rp-box, #rp-badge, #rp-dialog {
  728. width: 100%;
  729. position: fixed;
  730. z-index: 99999;
  731. bottom: 0px;
  732. right: 0px;
  733. }
  734.  
  735. #rp-badge {
  736. background: #4b5979;
  737. color: white;
  738. border-radius: 50%;
  739. width: 28px;
  740. height: 28px;
  741. text-align: center;
  742. line-height: 30px;
  743. cursor: pointer;
  744. float: right;
  745. min-width: 20px;
  746. border: 1px solid #fff;
  747. white-space: nowrap;
  748. }
  749.  
  750. #rp-badge:hover {
  751. border-color: #e9eaec;
  752. }
  753.  
  754. #rp-dialog {
  755. display: none;
  756. height: 100%;
  757. }
  758.  
  759. #rp-dialog-container {
  760. height: 100%;
  761. display: flex;
  762. flex-direction: column;
  763. font-size: 14px;
  764. background: white;
  765. border-radius: 5px;
  766. border: 2px dashed rgb(209, 217, 224);
  767. }
  768.  
  769. #rp-dialog-title {
  770. display: flex;
  771. justify-content: space-between;
  772. align-items: center;
  773. gap: 10px;
  774. border-radius: 5px 5px 0 0;
  775. padding: 5px 10px 5px 10px;
  776. background-color: #f8f8f9;
  777. }
  778.  
  779. #rp-dialog-feeds-container {
  780. display: flex;
  781. flex-direction: column;
  782. align-items: stretch;
  783. gap: 5px;
  784. padding: 0px;
  785. overflow-y: auto;
  786. }
  787.  
  788. #rp-dialog-feeds {
  789. list-style-type: none;
  790. padding: 0px 10px 5px 10px;
  791. margin: 0;
  792. }
  793.  
  794. .rss-title {
  795. font-weight: bold;
  796. margin: 5px 0 5px 0;
  797. }
  798.  
  799. .rss-link {
  800. color: #666;
  801. font-size: 0.9em;
  802. word-break: break-all;
  803. margin: 5 0 5 0;
  804. display: block;
  805. white-space: nowrap;
  806. overflow: hidden;
  807. text-overflow: ellipsis;
  808. max-width: 70vw;
  809. }
  810.  
  811. .rss-actions {
  812. display: flex;
  813. justify-content: space-between;
  814. }
  815.  
  816. .rss-btn {
  817. background: #4b5979;
  818. color: white;
  819. border: none;
  820. padding: 3px 8px;
  821. margin-right: 5px;
  822. cursor: pointer;
  823. border-radius: 3px;
  824. }
  825.  
  826. .rp-dialog-count {
  827. font-weight: bold;
  828. color: #ed3f14;
  829. }
  830.  
  831. .rp-badge-count {
  832. position: relative;
  833. display: inline-block;
  834. width: 26px;
  835. height: 26px;
  836. color: #fff;
  837. text-align: center;
  838. font-size: 12px;
  839. line-height: 26px;
  840. }
  841.  
  842. .rp-badge-count a,.rp-badge-count a:hover {
  843. color: #fff
  844. }
  845.  
  846. .rp-btn {
  847. cursor: pointer;
  848. display: inline-block;
  849. border: 1px solid transparent;
  850. -ms-touch-action: manipulation;
  851. touch-action: manipulation;
  852. font-weight: 400;
  853. }
  854.  
  855. .rp-btn>.rp-icon {
  856. line-height: 1
  857. }
  858.  
  859. .rp-btn:hover {
  860. color: #6d7380;
  861. background-color: #f9f9f9;
  862. border-color: #e4e5e7
  863. }
  864.  
  865. .rp-btn>.rp-icon+span,.rp-btn>span+.rp-icon {
  866. margin-left: 4px
  867. }
  868.  
  869. .rp-btn-primary {
  870. color: #fff;
  871. background-color: #2d8cf0;
  872. border-color: #2d8cf0;
  873. }
  874.  
  875. .rp-btn-primary:hover {
  876. color: #fff;
  877. background-color: #57a3f3;
  878. border-color: #57a3f3
  879. }
  880.  
  881. .rp-btn-small {
  882. padding: 2px 7px;
  883. font-size: 12px;
  884. border-radius: 3px;
  885. margin: 5px;
  886. color: #495060;
  887. background-color: #f7f7f7;
  888. }
  889.  
  890. .rss-item {
  891. display: flex;
  892. justify-content: space-between;
  893. align-items: center;
  894. padding: 5px 0;
  895. }
  896. `);
  897. rpDocument.head.appendChild(rpBoxStyle);
  898.  
  899. const rpBadgeDiv = rpDocument.createElement("div");
  900. rpBadgeDiv.id = "rp-badge";
  901. // 方法 1
  902. //const span = rpDocument.createElement("span");
  903. //span.classList.add("rp-badge-count", "rp-count");
  904. //rpBadgeDiv.appendChild(span);
  905. // 方法 2
  906. rpBadgeDiv.innerHTML = TTP.createHTML(`<span class="rp-badge-count rp-count"></span>`);
  907. rpDocument.body.appendChild(rpBadgeDiv);
  908.  
  909. rpDialog = rpDocument.createElement("div");
  910. rpDialog.id = "rp-dialog";
  911. rpDialog.innerHTML = TTP.createHTML( `
  912. <div id="rp-dialog-container">
  913. <div id="rp-dialog-title">
  914. <div>${t.feed}<span class="rp-dialog-count rp-count"></span></div>
  915. <button type="button" id="rp-close-btn" class="rp-btn rp-btn-small" title="${t.close}"><span>${ICON_CLOSE}</span></button>
  916. </div>
  917. <div id="rp-dialog-feeds-container">
  918. <ul id="rp-dialog-feeds"></ul>
  919. </div>
  920. </div>
  921. `);
  922. rpDocument.body.appendChild(rpDialog);
  923.  
  924. rpBadge = rpDocument.getElementById("rp-badge");
  925. rpDialog = rpDocument.getElementById("rp-dialog");
  926. rpDialogTitle = rpDocument.getElementById("rp-dialog-title");
  927. rpDialogFeeds = rpDocument.getElementById("rp-dialog-feeds");
  928.  
  929. rpIframe.style.width = rpBadge.getBoundingClientRect().width + "px";
  930. rpIframe.style.height = rpBadge.getBoundingClientRect().height + "px";
  931.  
  932. addEventHandler(rpDocument.getElementById("rp-close-btn"), "click", function () {
  933. rpDialog.style.display = "none";
  934. rpBadge.style.display = "block";
  935. rpIframe.style.width = rpBadge.getBoundingClientRect().width + "px";
  936. rpIframe.style.height = rpBadge.getBoundingClientRect().height + "px";
  937. });
  938.  
  939. rpDocument.getElementById("rp-badge").addEventListener("click", () => {
  940. if (feedsSet.size === 0) {
  941. return
  942. }
  943. rpDialog.style.display = "block";
  944. rpBadge.style.display = "none";
  945.  
  946. resizeIframe();
  947. });
  948.  
  949. window.addEventListener('resize', resizeIframe);
  950. window.addEventListener('load', resizeIframe);
  951. }
  952.  
  953. function resizeIframe() {
  954. if (rpDialog.style.display === "block"){
  955. if (window.innerWidth < 400){
  956. rpIframe.style.width = `${window.innerWidth}px`;
  957. } else {
  958. rpIframe.style.width = "400px";
  959. }
  960. const dialogHeight = rpDialogFeeds.getBoundingClientRect().height + rpDialogTitle.getBoundingClientRect().height;
  961. const availableHeight = rpIframe.getBoundingClientRect().bottom;
  962. if (dialogHeight < availableHeight) {
  963. rpIframe.style.height = `${dialogHeight}px`;
  964. } else {
  965. rpIframe.style.height = `${availableHeight}px`;
  966. }
  967. }
  968. }
  969.  
  970. // 更新徽章
  971. function updateBadge() {
  972. Array.from(rpDocument.getElementsByClassName("rp-count")).forEach(el => {el.textContent = feedsSet.size});
  973. }
  974.  
  975. // 更新对话框内容
  976. function updateDialog(title, url) {
  977. const li = rpDocument.createElement('li');
  978. li.className = 'rss-item';
  979. li.innerHTML = TTP.createHTML(`
  980. <div class="rss-info">
  981. <h5 class="rss-title">${title}</h5>
  982. <a class="rss-link" href="${url}" target="_blank">${url}</a>
  983. </div>
  984. <div class="rss-actions">
  985. <button class="rss-btn rss-copy rp-btn-primary">${t.copy}</button>
  986. <button class="rss-btn rss-follow rp-btn-primary">${t.follow}</button>
  987. </div>
  988. `);
  989. li.querySelector('.rss-copy').addEventListener('click', () => copyToClipboard(url));
  990. li.querySelector('.rss-follow').addEventListener('click', () => followFeed(url));
  991. rpDialogFeeds.appendChild(li);
  992. new HoverImgQR(li.querySelector('.rss-link'));
  993. }
  994.  
  995. // 复制到剪贴板
  996. function copyToClipboard(url) {
  997. GM_setClipboard(url);
  998. GM_notification({
  999. text: t.copied,
  1000. title: t.copySucceeded,
  1001. timeout: 2000
  1002. });
  1003. }
  1004.  
  1005. // 关注Feed
  1006. function followFeed(url) {
  1007. // 这里可以根据用户设置的RSS阅读器来打开相应的订阅链接
  1008. const rssService = GM_getValue("rss_service", "feedly");
  1009. if (rssService === "feedly") {
  1010. window.open(`https://feedly.com/i/subscription/feed/${encodeURIComponent(url)}`, '_blank');
  1011. } else if (rssService === "inoreader") {
  1012. window.open(GM_getValue("inoreader_domain", "https://www.inoreader.com") + `/?add_feed=${encodeURIComponent(url)}`, "_blank");
  1013. } else if (rssService === "tinytinyrss") {
  1014. window.open(GM_getValue("tinytinyrss_domain") + `/public.php?op=bookmarklets--subscribe&feed_url=${url}`, "_blank");
  1015. } else if (rssService === "freshrss") {
  1016. window.open(GM_getValue("freshrss_domain") + `/i/?c=feed&a=add&url_rss=${encodeURIComponent(url)}`, "_blank");
  1017. } else if (rssService === "miniflux") {
  1018. window.open(GM_getValue("miniflux_domain") + `/bookmarklet?uri=${encodeURIComponent(url)}`, "_blank");
  1019. } else if (rssService === "folo") {
  1020. window.open(`follow://add?url=${encodeURIComponent(url)}`, "_blank");
  1021. } else if (rssService === "newsblur") {
  1022. window.open(`http://www.newsblur.com/?url=${encodeURIComponent(url)}`, "_blank");
  1023. } else if (rssService === "theoldreader") {
  1024. window.open(`https://theoldreader.com/feeds/subscribe?url=${encodeURIComponent(url)}`, "_blank");
  1025. }
  1026. }
  1027.  
  1028. function reset() {
  1029. if (rpDiv){
  1030. rpDiv.remove();
  1031. }
  1032. if (rpStyle){
  1033. rpStyle.remove();
  1034. }
  1035. feedsSet.clear();
  1036. }
  1037.  
  1038.  
  1039. function addEventHandler(target, eventName, eventHandler, scope) {
  1040. let f = scope ? function() {
  1041. eventHandler.apply(scope, arguments);
  1042. } : eventHandler;
  1043. if (target.addEventListener) {
  1044. target.addEventListener(eventName, f, true);
  1045. } else if (target.attachEvent) {
  1046. target.attachEvent("on" + eventName, f);
  1047. }
  1048. return f;
  1049. }
  1050.  
  1051. function optimizeLink(link) {
  1052. if (link.match(/douban\.com\/people/i)) {
  1053. const src = document.querySelector("#profile > div > div.bd > div.basic-info > div.uhead-wrap > img.userface").src;
  1054. const m = src.match(/ul(\d+)-/i);
  1055. link = "https://www.douban.com/people/" + m[1];
  1056. }
  1057. return link;
  1058. }
  1059. function isEmpty(str) {
  1060. return str.trim().length === 0;
  1061. }
  1062. function isValidUrl(url) {
  1063. return url && (url.match(/^https*:\/\/.*?\.\w+(:\d+)?(\/|$)/i) || url.match(/^https*:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)*(:\d+)?(\/|$)/i));
  1064. }
  1065. function fetch(url, options = {}) {
  1066. return new Promise((resolve, reject) => {
  1067. GM_xmlhttpRequest({
  1068. url: url,
  1069. method: options.method || 'GET',
  1070. headers: options.headers,
  1071. data: options.body,
  1072. responseType: options.responseType || 'json',
  1073. onload: function(response) {
  1074. resolve({
  1075. ok: response.status >= 200 && response.status < 300,
  1076. status: response.status,
  1077. statusText: response.statusText,
  1078. json: () => {
  1079. if (options.responseType === 'json') {
  1080. return Promise.resolve(response.response); // 直接返回解析后的 JSON
  1081. } else {
  1082. try {
  1083. return Promise.resolve(JSON.parse(response.responseText)); // 手动解析 JSON
  1084. } catch (e) {
  1085. return Promise.reject(new Error('Failed to parse JSON'));
  1086. }
  1087. }
  1088. },
  1089. text: () => Promise.resolve(response.responseText),
  1090. blob: () => Promise.resolve(new Blob([response.response])),
  1091. headers: response.responseHeaders,
  1092. });
  1093. },
  1094. onerror: function(error) {
  1095. reject(error);
  1096. },
  1097. ontimeout: function() {
  1098. reject(new Error('Request timed out'));
  1099. },
  1100. timeout: options.timeout || 0,
  1101. });
  1102. });
  1103. }
  1104.  
  1105. class HoverImgQR {
  1106. constructor(el) {
  1107. this.DOM = {el: el};
  1108. this.DOM.reveal = document.createElement('div');
  1109. this.DOM.reveal.className = 'hover-reveal';
  1110.  
  1111. try {
  1112. const qr = qrcode(0, 'L');
  1113. qr.addData(this.DOM.el.href);
  1114. qr.make();
  1115. const url = qr.createDataURL();
  1116.  
  1117. const thisDOM = this.DOM;
  1118. thisDOM.reveal.innerHTML = TTP.createHTML(`<div class="hover-reveal__inner"><div class="hover-reveal__img" style="background-image:url(${url})"></div></div>`);
  1119. thisDOM.revealInner = thisDOM.reveal.querySelector('.hover-reveal__inner');
  1120. thisDOM.revealInner.style.overflow = 'hidden';
  1121. thisDOM.revealImg = thisDOM.revealInner.querySelector('.hover-reveal__img');
  1122. thisDOM.el.appendChild(thisDOM.reveal);
  1123.  
  1124. this.initEvents();
  1125. } catch (e) {
  1126. console.error("报错:", e);
  1127. }
  1128. }
  1129. getMousePos (e) {
  1130. let posX = 0;
  1131. let posY = 0;
  1132. if (!e) e = window.event;
  1133. if (e.pageX || e.pageY) {
  1134. posX = e.pageX;
  1135. posY = e.pageY;
  1136. } else if (e.clientX || e.clientY) {
  1137. posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
  1138. posY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
  1139. }
  1140. return {
  1141. x: posX,
  1142. y: posY
  1143. }
  1144. }
  1145. initEvents() {
  1146. this.positionElement = (ev) => {
  1147. const mousePos = this.getMousePos(ev);
  1148. const docScrolls = {
  1149. left: rpDocument.body.scrollLeft + rpDocument.documentElement.scrollLeft,
  1150. top: rpDocument.body.scrollTop + rpDocument.documentElement.scrollTop
  1151. };
  1152. this.DOM.reveal.style.top = `${mousePos.y-70-docScrolls.top}px`;
  1153. this.DOM.reveal.style.left = `${mousePos.x+10-docScrolls.left}px`;
  1154. };
  1155. this.mouseenterFn = (ev) => {
  1156. if (!GM_getValue("enable_qr_code", true)) return;
  1157. this.positionElement(ev);
  1158. this.DOM.revealInner.style.overflow = 'visible';
  1159. this.DOM.reveal.style.opacity = '1';
  1160. };
  1161. this.mousemoveFn = ev => requestAnimationFrame(() => {
  1162. if (!GM_getValue("enable_qr_code", true)) return;
  1163. this.positionElement(ev);
  1164. });
  1165. this.mouseleaveFn = () => {
  1166. if (!GM_getValue("enable_qr_code", true)) return;
  1167. this.DOM.revealInner.style.overflow = 'hidden';
  1168. this.DOM.reveal.style.opacity = '0';
  1169. };
  1170. this.DOM.el.addEventListener('mouseenter', this.mouseenterFn);
  1171. this.DOM.el.addEventListener('mousemove', this.mousemoveFn);
  1172. this.DOM.el.addEventListener('mouseleave', this.mouseleaveFn);
  1173. }
  1174. }
  1175.  
  1176. // 监听全屏变化
  1177. document.addEventListener('fullscreenchange', handleFullscreenChange);
  1178. document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
  1179. document.addEventListener('mozfullscreenchange', handleFullscreenChange);
  1180. function handleFullscreenChange() {
  1181. const isFullscreen = document.fullscreenElement ||
  1182. document.webkitFullscreenElement ||
  1183. document.mozFullScreenElement;
  1184. rpDiv.style.display = isFullscreen ? 'none' : 'block';
  1185. }
  1186.  
  1187.  
  1188. // 检查环境
  1189. if (window.top !== window.self || !window.location.protocol.startsWith('http')) {
  1190. return;
  1191. }
  1192. // 当页面加载完成后初始化
  1193. observeUrlChange();
  1194. findFeeds();
  1195. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址