{"id":18674564,"url":"https://github.com/lightapis/gloria-x","last_synced_at":"2025-06-20T21:37:01.929Z","repository":{"id":104067424,"uuid":"325475509","full_name":"LightAPIs/Gloria-X","owner":"LightAPIs","description":"提供定时执行 javascript 脚本任务的功能，以实现检测网页变化或进行论坛签到等自动化工作，并完成通知聚合。 Provides the function of performing the JavaScript script task to implement automated work such as detection web page changes or forum check-in, and complete the notification aggregation.","archived":false,"fork":false,"pushed_at":"2023-11-22T14:11:20.000Z","size":1964,"stargazers_count":18,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-19T10:22:32.842Z","etag":null,"topics":["chrome-extension","edge-addon","mozilla-addons"],"latest_commit_sha":null,"homepage":"","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LightAPIs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-12-30T06:39:40.000Z","updated_at":"2025-03-31T06:45:02.000Z","dependencies_parsed_at":"2023-11-22T13:46:25.579Z","dependency_job_id":"1b5d6155-1da1-43ef-b610-2d64d0189cef","html_url":"https://github.com/LightAPIs/Gloria-X","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/LightAPIs/Gloria-X","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAPIs%2FGloria-X","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAPIs%2FGloria-X/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAPIs%2FGloria-X/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAPIs%2FGloria-X/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LightAPIs","download_url":"https://codeload.github.com/LightAPIs/Gloria-X/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LightAPIs%2FGloria-X/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261021111,"owners_count":23098279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chrome-extension","edge-addon","mozilla-addons"],"created_at":"2024-11-07T09:19:24.134Z","updated_at":"2025-06-20T21:36:56.909Z","avatar_url":"https://github.com/LightAPIs.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\r\n  \u003cimg src=\"https://gcore.jsdelivr.net/gh/LightAPIs/PicGoImg@master/img/20210414171507.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n\u003ch1 align=\"center\"\u003eGloria-X\u003c/h1\u003e\r\n\r\n\u003cp align=\"center\"\u003e\r\n  \u003ca href=\"https://github.com/LightAPIs/Gloria-X/releases/latest\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/github/v/release/LightAPIs/Gloria-X.svg?color=orange\" alt=\"Release\" /\u003e\r\n  \u003c/a\u003e\r\n  \u003ca href=\"https://chrome.google.com/webstore/detail/npdafhgodaenfglcfkkbnmdbfkgfadbh\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/chrome-web-store/v/npdafhgodaenfglcfkkbnmdbfkgfadbh?maxAge=86400\" alt=\"Chrome Web Store\" /\u003e\r\n  \u003c/a\u003e\r\n  \u003ca href=\"https://microsoftedge.microsoft.com/addons/detail/ijhoikcicadeigejkkknglnhbcfkfkkc\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/badge/-edge_addons-blue.svg\" /\u003e\r\n  \u003c/a\u003e\r\n  \u003ca href=\"https://github.com/LightAPIs/Gloria-X/releases/latest\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/badge/-mozilla_addons-orange.svg\" alt=\"Mozilla Addons\" /\u003e\r\n  \u003c/a\u003e\r\n  \u003ca href=\"./LICENSE\"\u003e\r\n    \u003cimg src=\"https://img.shields.io/github/license/LightAPIs/Gloria-X.svg\" alt=\"MIT License\" /\u003e\r\n  \u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n- [English](/README_EN.md)\r\n- 中文版\r\n\r\n\u003e 可编程网站通知聚合器\r\n\u003e\r\n\u003e **原项目：**[BlackGlory](https://github.com/BlackGlory)/[Gloria](https://github.com/BlackGlory/Gloria) [![MIT License](https://img.shields.io/github/license/BlackGlory/Gloria.svg)](https://raw.githubusercontent.com/BlackGlory/Gloria/master/LICENSE)\r\n\r\n通过定时执行自定义的 JavaScript 代码任务，实现网页监视或者论坛签到等自动化工作，并弹出通知提醒。\r\n\r\n_本项目是由我个人采用 TypeScript 进行编写和维护的 Gloria 衍生版本，用于修改及扩充 Gloria 中的部分功能，并添加我个人所需要的一些特性，所以 Gloria-X 可以理解为是一个以 Gloria 为核心，并提供功能增强的版本。_\r\n\r\n## 目录\r\n\r\n\u003cdetails\u003e\r\n\u003csummary\u003e目录\u003c/summary\u003e\r\n\r\n- [安装方法](#安装方法)\r\n  - [Chrome](#chrome)\r\n  - [Edge](#edge)\r\n  - [Firefox](#firefox)\r\n- [使用方法](#使用方法)\r\n  - [Gloria Notification 对象结构](#gloria-notification-对象结构)\r\n    - [对象属性介绍](#对象属性介绍)\r\n  - [commit 函数](#commit-函数)\r\n    - [任务分类](#任务分类)\r\n      - [观察任务](#观察任务)\r\n      - [常规任务](#常规任务)\r\n    - [两种任务的区别](#两种任务的区别)\r\n    - [注意事项](#注意事项)\r\n  - [访问 URL](#访问-url)\r\n    - [访问 URL 示例](#访问-url-示例)\r\n  - [异步载入外部脚本](#异步载入外部脚本)\r\n- [额外功能](#额外功能)\r\n  - [选取网页元素进行监视](#选取网页元素进行监视)\r\n- [高级选项](#高级选项)\r\n  - [调试任务代码](#调试任务代码)\r\n  - [观察内部状态](#观察内部状态)\r\n  - [自定义请求头信息](#自定义请求头信息)\r\n  - [通知 Reducer](#通知-reducer)\r\n    - [Reducer 介绍](#reducer-介绍)\r\n    - [工作方式](#工作方式)\r\n    - [作用](#作用)\r\n    - [具体用法](#具体用法)\r\n    - [示例](#示例)\r\n      - [过滤通知](#过滤通知)\r\n      - [修改通知](#修改通知)\r\n      - [发送给 Pushbullet](#发送给-pushbullet)\r\n    - [测试 Rudecer](#测试-rudecer)\r\n- [其他事项](#其他事项)\r\n  - [准时模式](#准时模式)\r\n  - [其他特性](#其他特性)\r\n- [相关文档](#相关文档)\r\n- [Firefox 版本的限制](#firefox-版本的限制)\r\n- [开发编译](#开发编译)\r\n  - [环境需求](#环境需求)\r\n  - [初始化指令](#初始化指令)\r\n  - [构建指令](#构建指令)\r\n  - [相关目录及文件](#相关目录及文件)\r\n- [相关项目](#相关项目)\r\n- [许可证](#许可证)\r\n\r\n\u003c/details\u003e\r\n\r\n## 安装方法\r\n\r\n### Chrome\r\n\r\n1. 前往 [Chrome 网上应用店](https://chrome.google.com/webstore/detail/npdafhgodaenfglcfkkbnmdbfkgfadbh) 进行下载安装。\r\n2. 启动浏览器在地址栏内输入 `chrome://extensions/` 进入扩展程序管理页面，点击网页右上角的开关以开启\"开发者模式\"：\r\n\r\n- a. 前往 [Releases](https://github.com/LightAPIs/Gloria-X/releases/latest) 下载扩展程序 `crx` 文件，拖动至扩展程序管理页面进行安装。\r\n- b. 前往 [Releases](https://github.com/LightAPIs/Gloria-X/releases/latest) 下载扩展程序压缩包 `zip` 文件并进行解压，然后点击\"加载已解压的扩展程序\"按钮，选择加载先前解压文件的根目录即可完成扩展程序的安装。\r\n\r\n### Edge\r\n\r\n- 前往 [Microsoft Edge Addons](https://microsoftedge.microsoft.com/addons/detail/gloriax/ijhoikcicadeigejkkknglnhbcfkfkkc) 进行下载安装。\r\n\r\n### Firefox\r\n\r\n- 前往 [Releases](https://github.com/LightAPIs/Gloria-X/releases/latest) 下载附加组件 `xpi` 文件进行安装 _(由于声明了 `unsafe-eval` 权限，所以无法上架至 Mozilla Add-ons，仅可自行托管。)_\r\n\r\n## 使用方法\r\n\r\n由于是承袭自 Gloria，所以 Gloria-X 基本上实现了 Gloria 上所有的功能，使用方法和任务开发与其相同。正常情况下，为 Gloria 所编写的任务代码是同样可以在 Gloria-X 上工作的，反之亦可行。以下是一些简要的使用方法介绍：\r\n\r\nJavaScript 同样是 Gloria-X 任务代码唯一支持的编程语言。任务创建通知的编写方法与 Gloria 相同，只需要将一个 `Gloria Notification` 对象或一个由该对象所组成的数组传递给特定的回调函数 `commit`。Gloria-X 会在内部处理 `commit` 函数的参数，并根据该参数决定推送通知的内容。\r\n\r\n比如，下面这段简单的任务代码就是真实可运行的，它会在每次设定的时间间隔到达后执行并弹出一个关于时间戳的通知消息：\r\n\r\n```javascript\r\ncommit({\r\n  message: Date.now().toString(),\r\n});\r\n```\r\n\r\n_当然这段任务代码本身是没有实际意义的，只是一个简单的使用示例。_\r\n\r\n### Gloria Notification 对象结构\r\n\r\n通知消息的显示内容取决于所传递的 `Gloria Notification` 对象属性值，所以首先你需要了解该对象的结构。\r\n\r\n`Gloria Notification` 对象结构如下：\r\n\r\n```javascript\r\n{\r\n  title: String,    // 默认为 \"\"，推送通知的标题\r\n  message: String,  // 默认为 \"\"，推送通知的内容\r\n  iconUrl: String,  // 默认为 undefined，推送通知的图标\r\n  imageUrl: String, // 默认为 undefined，在推送通知上额外显示的图片 (Firefox 通知忽略该属性)\r\n  url: String,      // 默认为 undefined，点击推送通知时打开的网址\r\n  id: String,       // 默认为 undefined，用于额外判定通知是否相同。如非特定需求，一般不需要手动指定\r\n}\r\n```\r\n\r\n_为了安全性和避免可能发生某些未知的错误，扩展程序在内部处理时会忽略掉 `Gloria Notification` 对象上的其他属性。_\r\n\r\n#### 对象属性介绍\r\n\r\n\u003e 提示：设定上所有的对象属性类型均为**可选的** `String` 字符串。在编写任务代码时不要直接传递其他可能可以隐式转换为 `String` 的类型 (如：`Number`，`Boolean` 等)，如果这样做，扩展程序会认为传递的属性类型出错，所以请务必自行手动将值转换为 `String` 类型。\r\n\r\n- `title`\r\n  - 类型: `String`\r\n  - 默认值: `\"\"`\r\n  - 含义: 推送通知的标题。\r\n  - 该属性值会用于与 STAGES 缓存中的旧通知进行判定。\r\n  - 如：在一个[观察任务](#观察任务)中，如果新对象中的 `title` 值与 STAGES 缓存里旧对象中的 `title` 值不相同时，则该新对象就会被判定为是一则新通知并需要进行推送。\r\n- `message`\r\n  - 类型: `String`\r\n  - 默认值: `\"\"`\r\n  - 含义: 推送通知的主体内容或描述。\r\n  - 该属性值会用于与 STAGES 缓存中的旧通知进行判定。\r\n  - 小提示：如果不是用于测试之类的用途，建议不要直接在 `title` 或 `message` 属性中包含与通知内容本身无关的第三方可变量 (比如在标题上附加了一个时间戳 `Date.now().toString()`)。因为这可能会导致每一次任务执行完毕后所得到的对象都不同，从而会被判定成新通知而进行推送。如果出于某种需求需要将两个 `title` 和 `message` 属性值相同的对象当作两个不同的通知处理，可以为对象指定两个不相同的 `id` 属性值 (在 Gloria 中同样可以采用这种方式)，这样这两个对象在扩展程序内部就会被视作两个不相同的对象了。\r\n- `iconUrl`\r\n  - 类型: `String`\r\n  - 默认值: `undefined`\r\n  - 含义: 推送通知显示的图标信息。\r\n  - 这是 Chrome 创建通知消息时必须提供的参数，所以若在对象中不指定 `iconUrl` 属性时，扩展程序会先查找 `url` 网站的网站图标 (_如果指定了 `url` 并在设置中启用自动检测网站图标功能_)，其次会提供一个默认图标值 `\"icons/app/icon-128.png\"` (即 Gloria-X 的图标)。\r\n- `imageUrl`\r\n  - 类型: `String`\r\n  - 默认值: `undefined`\r\n  - 含义: 推送通知上额外显示的一张图片。若指定 `imageUrl` 属性，通知会变为一个带图片的通知。\r\n  - **Firefox 通知会忽略该属性，即在通知中不会显示额外的图片，但是会在通知记录中显示。**\r\n- `url`\r\n  - 类型: `String`\r\n  - 默认值: `undefined`\r\n  - 含义: 点击推送通知时打开的网站。\r\n- `id`\r\n  - 类型: `String`\r\n  - 默认值: `undefined`\r\n  - 含义: 对象的标识符，可以用于额外判定通知是否相同。\r\n  - 该属性值会用于与 STAGES 缓存中的旧通知进行判定。\r\n\r\n### commit 函数\r\n\r\n`commit` 函数是由 Gloria-X 提供给任务代码的一个特殊函数。通过在任务代码中将需要观测的数据结果，即 `Gloria Notification` 对象或由该对象所组成的数组，以参数的形式传递给 `commit`，便完成了任务代码的编写。\r\n\r\n而根据传递给 `commit` 参数的区别，任务分为\"**观察任务**\"和\"**常规任务**\"。\r\n\r\n#### 任务分类\r\n\r\n##### 观察任务\r\n\r\n当传递一个单一的 `Gloria Notification` 对象给 `commit` 函数时，该任务会被识别为\"观察任务\"，会将每次得到的 `Gloria Notification` 对象与上一次所记录的 `Gloria Notification` 对象进行对比，不相同时则会推送新通知。\r\n\r\n_注意：若在观察任务中返回 `null` 或 `undefined`，则此次执行结果会被直接忽略，不会被缓存和用于比较。_\r\n\r\n##### 常规任务\r\n\r\n当传递一个由 `Gloria Notification` 对象所组成的数组给 `commit` 函数时，该任务会被识别为\"常规任务\"，每次所收集到的内容都会被缓存于内部的 `Stages` 组件中，这样只有新对象时才会推送相应的通知。当然，每一个\"常规任务\"的 `Stages` 组件缓存数量是存在上限值的，但理论上你不会需要去关心其大小，只需要保证每个\"常规任务\"不会一次传入数量过多的 `Gloria Notification` 对象即可。\r\n\r\n#### 两种任务的区别\r\n\r\n观察任务会响应每次结果的变化，依据的是上一次是执行结果；而常规任务只会响应新出现的结果，不会处理过往出现过的重复执行结果。\r\n\r\n以下通过两份可以实际运行的任务代码来具体解释一下两种任务的区别。\r\n\r\n假设存在下面两个任务，一个为观察任务，另一个为常规任务。\r\n\r\n```javascript\r\n//* 观察任务，传入的是单个对象\r\n(async () =\u003e {\r\n  const { lodash: _ } = await importScripts('gloria-utils');\r\n  return {\r\n    title: _.random(1).toString(),\r\n  };\r\n})().then(commit);\r\n```\r\n\r\n```javascript\r\n//* 常规任务，传入的是一个数组\r\n(async () =\u003e {\r\n  const { lodash: _ } = await importScripts('gloria-utils');\r\n  return [\r\n    {\r\n      title: _.random(1).toString(),\r\n    },\r\n  ];\r\n})().then(commit);\r\n```\r\n\r\n_当然这两个任务并没有任何实际意义，仅供用来测试参考两种任务间的区别。_\r\n\r\n我们使用了 `lodash` 库中的 `random` 方法进行测试。先不要管 `importScripts ('gloria-utils')` 是什么东西，后面的内容中会提到，我们现在只需要关注两个任务传递给 `commit` 函数的结果。在两个任务中对象的 `title` 属性都采用 `_.random(1).toString()` 赋值，这个方法的结果值只有两种可能性，`\"0\"` 或者 `\"1\"` 。\r\n\r\n当实际运行这两个任务时你就会发现：\r\n\r\n观察任务在每一次任务执行时都会有可能推送新的通知，只要这一次的对象的 `title` 值与上一次对象的 `title` 值不相同即可。\r\n\r\n而常规任务的行为则完全不相同，当执行次数足够多时，你会发现常规任务至多也只会推送一次新的通知。\r\n\r\n这是因为在任务创建时，任务会首先执行一次，并将第一次执行的结果缓存进 STAGES 组件中。当后续执行中出现一个不相同的结果时，则会推送新的通知，并将新的结果缓存进 STAGES 组件中。值得注意的是，常规任务不同于观察任务，它并不会被移除旧的结果，而是与新结果一同缓存在 STAGES 组件当中。又因为这个示例任务的特殊性，即只存在两种可能性结果，所以此时无论后续执行会得出什么结果，它都会与 STAGES 组件中缓存的两个结果之一相同，那也就不可能再出现推送新通知的情况出现了。\r\n\r\n以上就是两种任务间区别的示例，具体行为可以通过选项页面中内部状态观察面板观测。\r\n\r\n#### 注意事项\r\n\r\n在一个任务代码中，`commit` 函数是**必需的**。即应该在任何代码的结束位置上将一个 `Gloria Notification` 对象、`Gloria Notification` 数组、`null` 或 `undefined` 提供给 `commit` 函数。\r\n\r\n例如，在以下示例任务代码中：\r\n\r\n```javascript\r\n(async () =\u003e {\r\n  const { lodash: _ } = await importScripts('gloria-utils');\r\n  const result = _.random(1);\r\n  if (result) {\r\n    commit({\r\n      title: result.toString(),\r\n    });\r\n  }\r\n})();\r\n```\r\n\r\n当上述代码中 `result` 为 `0` 时，由于没有提供值给 `commit` 函数，任务将需要等到超时(`60s`)出错才结束执行。所以上述任务代码应规范为：\r\n\r\n```javascript\r\n(async () =\u003e {\r\n  const { lodash: _ } = await importScripts('gloria-utils');\r\n  const result = _.random(1);\r\n  if (result) {\r\n    commit({\r\n      title: result.toString(),\r\n    });\r\n  } else {\r\n    commit(null);\r\n  }\r\n})();\r\n```\r\n\r\n### 访问 URL\r\n\r\n在了解了如何在任务代码中创建通知后，接下来需要的就是访问 url 了。\r\n\r\n在任务代码中访问 url 有两种方法：\r\n\r\n1. 通过 `fetch` 函数\r\n\r\n你可以在 [Fetch API](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API) 里查看 `fetch` 的使用方法。需要注意的是在 Gloria-X 环境下的 `fetch` 在创建请求时会自动附加目标 url 的 Cookie，以便可以利用到在目标网站上的登录状态。当然这样推送的通知显示内容里也许会包含你的私人信息，具体显示内容取决于 `Gloria Notification` 对象是如何编写的。\r\n\r\n2. 通过 `XMLHttpRequest(XHR)` 对象\r\n\r\n你可以在 [XMLHttpRequest](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest) 里查看 `XHR` 的使用方法。与 `fetch` 不同的时，Gloria-X 环境下的 `XHR` 不会自动附加目标 url 的 Cookie，也就无法获取到目标网站上的登录状态了。\r\n\r\n若你打算使用 `XHR`，你可能需要在任务代码中使用一个相类似的 `Promise` 封装方法：\r\n\r\n```javascript\r\n// Encapsulation method\r\nfunction ajax(url, method = 'GET', headers = []) {\r\n  return new Promise((resolve, reject) =\u003e {\r\n    const xhr = new XMLHttpRequest();\r\n    xhr.open(method, url);\r\n    headers.forEach(head =\u003e {\r\n      xhr.setRequestHeader(head.name, head.value);\r\n    });\r\n    xhr.responseType = 'json';\r\n    xhr.onload = res =\u003e {\r\n      resolve(res.target.response);\r\n    };\r\n    xhr.onerror = res =\u003e {\r\n      reject(res.target.response);\r\n    };\r\n    xhr.send();\r\n  });\r\n}\r\n\r\n// Use ajax\r\najax('...').then( ... ).catch( ... )\r\n```\r\n\r\n#### 访问 URL 示例\r\n\r\n比如创建一个检测本项目的最新版本的简单观察任务：\r\n\r\n```javascript\r\nfetch('https://api.github.com/repos/LightAPIs/Gloria-X/releases/latest')\r\n  .then(res =\u003e res.json())\r\n  .then(json =\u003e {\r\n    const message = json.tag_name;\r\n    const url = json.html_url;\r\n    commit({\r\n      title: 'Gloria-X',\r\n      message,\r\n      url,\r\n    });\r\n  });\r\n```\r\n\r\n我还在 Gloria 的[任务代码分享网站](https://gloria.pub/)里找了一个可实际运行的任务。\r\n\r\n[方块游戏 新闻资讯](https://gloria.pub/task/5f4e832dab474400108be608)：\r\n\r\n```javascript\r\nfetch('https://infodev.cubejoy.com/Store/GetNews?area=2\u0026pageindex=1\u0026pagesize=15')\r\n  .then(res =\u003e res.text())\r\n  .then(res =\u003e JSON.parse(res.substring(1, res.length - 1)))\r\n  .then(json =\u003e {\r\n    let notifications = json.result.list.map(feed =\u003e {\r\n      return {\r\n        message: feed.Title,\r\n        url: 'https://news.cubejoy.com/html/en/news/newsdetail/detail' + feed.Id + '.html',\r\n        iconUrl: feed.ImgUrlM,\r\n      };\r\n    });\r\n    commit(notifications);\r\n  });\r\n```\r\n\r\n如果你了解 `fetch` 或 `XHR` 的话，通过这些任务应该也就能明白具体如何在任务代码中访问 URL 了。\r\n\r\n### 异步载入外部脚本\r\n\r\n虽然已经可以在任务代码中访问 URL，但是并不是所有网站都存在类似上面示例中的返回 JSON 格式数据的 API 接口。这时候就需要直接访问 URL 并读取 HTML 内容，再通过 `cheerio` 等模块处理 HTML。\r\n\r\n在 Gloria-X 环境下可以像 Web Worker 通过 `importScripts` 方法载入外部脚本。\r\n\r\n需要注意的一点，不同于 Web Worker 运行环境，Gloria-X 的环境下会制造一个虚拟的 `window` 对象，用于让一些外部脚本能正常工作，并且 `importScripts` 方法被改造成了异步方法，仅支持单个参数。你可以像下面这样调用它:\r\n\r\n```javascript\r\nimportScripts('script.js')\r\n  .then(script =\u003e {\r\n    ...\r\n  })\r\n```\r\n\r\n当调用这个异步的 `importScripts` 方法载入外部脚本时会返回一个 `Promise` 对象。`Promise.then` 的回调函数所接收到的第一个参数就是载入的外部脚本的返回值。\r\n\r\nGloria-X 和 Gloria 同样内置了一些常用的模块，并可以通过 `importScripts('gloria-utils')` 加载这些模块，所能使用的模块如下表所示：\r\n\r\n|                                               集成模块                                               |  版本   |\r\n| :--------------------------------------------------------------------------------------------------: | :-----: |\r\n|               export `cheerio` from '[cheerio](https://github.com/cheeriojs/cheerio)'                | 0.22.0  |\r\n|                          export `co` from '[co](https://github.com/tj/co)'                           |  4.6.0  |\r\n|                  export `cookie` from '[cookie](https://github.com/jshttp/cookie)'                   |  0.3.1  |\r\n|         export `immutable` from '[immutable](https://github.com/immutable-js/immutable-js)'          |  3.8.1  |\r\n|                  export `is` from '[is_js](https://github.com/arasatasaygin/is.js)'                  |  0.9.0  |\r\n|                  export `lodash` from '[lodash](https://github.com/lodash/lodash)'                   | 4.16.4  |\r\n|                  export `moment` from '[moment](https://github.com/moment/moment)'                   | 2.18.1  |\r\n|                        export `qs` from '[qs](https://github.com/ljharb/qs)'                         |  6.3.0  |\r\n|                    export `ramda` from '[ramda](https://github.com/ramda/ramda)'                     | 0.24.1  |\r\n|                 export `rx` from '[rx](https://github.com/Reactive-Extensions/RxJS)'                 |  4.1.0  |\r\n|     export `sanitizeHtml` from '[sanitize-html](https://github.com/apostrophecms/sanitize-html)'     | 1.13.0  |\r\n|              export `SystemJS` from '[systemjs](https://github.com/systemjs/systemjs)'               | 0.20.14 |\r\n| export `underscoreString` from '[underscore.string](https://github.com/esamattis/underscore.string)' |  3.3.4  |\r\n|          export `validator` from '[validator](https://github.com/validatorjs/validator.js)'          |  7.1.0  |\r\n|          export `xml2js` from '[xml2js](https://github.com/Leonidas-from-XIV/node-xml2js)'           | 0.4.17  |\r\n|               export `XRegExp` from '[xregexp](https://github.com/slevithan/xregexp)'                |  3.2.0  |\r\n\r\n例如，你可以使用 `cheerio` 来解析一个页面：\r\n\r\n```javascript\r\n(async () =\u003e {\r\n  const { cheerio } = await importScripts('gloria-utils');\r\n  const html = await fetch('https://github.com/LightAPIs/Gloria-X/releases').then(res =\u003e res.text());\r\n  const $ = cheerio.load(html);\r\n  return $('.release-main-section.commit')\r\n    .map((_i, ele) =\u003e {\r\n      const link = $(ele).find('.release-header .f1 a');\r\n      const title = link.text().trim();\r\n      const url = 'https://github.com/' + link.attr('href');\r\n      return {\r\n        title,\r\n        url,\r\n      };\r\n    })\r\n    .get();\r\n})().then(commit);\r\n```\r\n\r\n## 额外功能\r\n\r\n### 选取网页元素进行监视\r\n\r\n\u003e _v1.2.0 +_\r\n\r\n可以在网页的右键菜单或者扩展程序图标的右键菜单里找到该功能。\r\n\r\n触发该功能后，会进入选取网页元素模式，可以通过鼠标左键单击点选网页内元素，按住 Ctrl 键的同时可以进行多选。完成元素选取之后，再点击\"生成任务代码\"按钮即可生成相应的任务代码。接下来需要测试一遍生成的任务代码，只有测试任务代码执行成功才能进行下一步并创建任务。\r\n\r\n需要注意的是，这个功能本质只是一个[观察任务](#观察任务)的快捷生成器。从原理上来说它是无法生成[常规任务](#常规任务)的，并且也不一定能监视所有类型的网页，比如基于 Ajax 技术动态加载的网页等。\r\n\r\n## 高级选项\r\n\r\n### 调试任务代码\r\n\r\n可以在扩展程序选项页面的\"任务调试\"分页中找到调试任务的面板。\r\n\r\n在代码输入框中输入需要调试的任务代码后，点击页面上方的\"测试\"按钮，即可查看测试输出结果 (当然，异步执行的任务代码可能需要等上一会儿)，并且所得到的测试结果既不会经过内部的 STAGES 组件 (一个用于缓存通知的组件)，也不会经过 Reducer 函数 (见后面介绍)，而是直接生成相应的通知。\r\n\r\n若任务代码中存在语法等错误，也会显示在面板中 (_注：仅支持捕获同步执行代码的错误，采用异步执行的代码的错误或者是在代码中使用 `console` 语句的输出需要打开扩展程序的背景页\u003c\"background.html\"\u003e进行查看_)。\r\n\r\n### 观察内部状态\r\n\r\n可以在扩展程序选项页面的\"内部状态\"分页中找到观察内部状态的面板。\r\n\r\n在这里，你可以观察到\"通知记录\"、\"Gloria-X 任务\" 和 \"STAGES\" 组件在内部储存的实时状态。\r\n\r\n同时在页面底部还提供了一些清理功能的按钮。\r\n\r\n### 自定义请求头信息\r\n\r\n\u003e _v2.6.0+_\r\n\r\n可以在扩展程序选项页面的\"请求头信息\"分页中找到自定义请求头信息的面板。\r\n\r\n在这里，你可以手动为一些被[禁止修改的消息首部](https://developer.mozilla.org/zh-CN/docs/Glossary/Forbidden_header_name)提供值。\r\n\r\n_注：此处的设定会覆盖扩展程序内部自动附加的一些同名值，如 `Cookie` 等。_\r\n\r\n### 通知 Reducer\r\n\r\n可以在扩展程序选项页面的\"通知 Reducer\"分页中找到 Reducer 设置面板。\r\n\r\n**在介绍和使用 Reducer 函数之前，希望你能清楚该函数本身是一把\"双刃剑\"，在带来便利的同时有可能会因为使用不当而造成一些不必要的麻烦。**\r\n\r\n#### Reducer 介绍\r\n\r\n如果你需要对任务执行后所得到的新通知在被正式推送之前进行一些二次操作的话，那么你就需要使用到 Reducer 函数。Reducer 函数是 Gloria-X 提供的一个特殊函数 (当然，你同样可以在 Gloria 里找到它)。与之前任务代码中的 `commit` 函数不同，它不会出现在任务代码当中，而是单独地在选项页面里进行设置。如果你提供了 Reducer 函数，那么所有的任务都会使用同一个 Reducer 函数。\r\n\r\n#### 工作方式\r\n\r\nReducer 是一个同步执行的函数，当一个任务执行完成后若存在需要进行推送的新 `Gloria Notification` 对象时，该对象会作为参数被传递进 Reducer 函数中执行一次操作。\r\n\r\n注意：在 Reducer 函数执行之前，通知的对比和缓存都已经完成，Reducer 函数的操作只会影响到后面通知的显示和记录中的内容。\r\n\r\n它的执行时机大概是像下面这样的：\r\n\r\n```mermaid\r\nflowchart LR\r\n  subgraph Execute\r\n    id1([Task]) --\u003e id2[commit]\r\n  end\r\n  id2 --\u003e id3\r\n  subgraph Compare and Cache\r\n    id3[\"Gloria Notification(s)\"] --\u003e id4[STAGES]\r\n  end\r\n  id4 --\u003e id5{reducer exists?}\r\n  id5 -- No ----\u003e id7[/Popup Notifications/]\r\n  id5 -- Yes --\u003e id6[Reducer] --\u003e id7\r\n```\r\n\r\n#### 作用\r\n\r\n在 Reducer 函数中，你可以完成修改、过滤以及通过 HTTP 请求发送给第三方服务(比如：[Pushbullet](https://www.pushbullet.com/)、[Pushover](https://pushover.net/)、[Server 酱](https://sct.ftqq.com/)等)将通知同步至其他设备当中的操作。\r\n\r\n#### 具体用法\r\n\r\nReducer 接收一个 `Gloria Notification` 对象作为参数，并可选的返回一个新的 `Gloria Notification` 对象，该返回值将被用于弹出新通知。若函数没有提供返回值或者返回的是一个 `null` 时，则被视为被抛弃，不会弹出新通知，更不会在通知记录中看到它。\r\n\r\n#### 示例\r\n\r\n##### 过滤通知\r\n\r\n过滤掉 `message` 中包含 \"sad\" 字符串的通知：\r\n\r\n```javascript\r\nfunction reducer(notification) {\r\n  if (notification.message.includes('sad')) {\r\n    return null;\r\n  }\r\n  return notification;\r\n}\r\n```\r\n\r\n\u003e _注：由于 Reducer 函数工作于将通知消息缓存进 STAGES 组件的操作之后，所以即使通知被丢弃，STAGES 组件中仍然会保存关于该通知消息的缓存，但是不会出现在通知记录当中。_\r\n\u003e\r\n\u003e _（当然，你其实并不需要十分关心这些内容，因为它不会影响到任务代码的编写，我之所以要告诉你这些，只是希望你能更清楚 Reducer 函数是在何时工作的，产生了什么影响，多了解一些没什么坏处。）_\r\n\u003e\r\n\u003e _即假设当你通过 Reducer 丢弃一则通知消息，然后删除了 Reducer 函数，那么理论上在下一次任务执行后，这一则通知也不会被当作新消息弹出，因为它之前已经被缓存进 STAGES 组件中了。_\r\n\r\n##### 修改通知\r\n\r\n将 `message` 中的 \"sad\" 修改为 \"happy\"：\r\n\r\n```javascript\r\nfunction reducer(notification) {\r\n  notification.message = notification.message.replace('sad', 'happy');\r\n  return notification;\r\n}\r\n```\r\n\r\n\u003e _注：由于 Reducer 函数工作于将通知消息缓存进 STAGES 组件的操作之后，所以 STAGES 组件中仍然保存的是关于修改之前的通知消息的缓存，但是通知记录中会显示修改之后的通知内容。_\r\n\u003e\r\n\u003e _即假设当你通过 Reducer 修改了一则通知消息，然后删除了 Reducer 函数，那么理论上在下一次任务执行后，这一则通知也不会被当作新消息弹出，因为它其实和 STAGES 组件中缓存的消息相同。_\r\n\r\n小提示：通常来说在 Reducer 函数中去修改 `notification.id` 属性是没有意义的，因为这个属性值并不会真实地反馈到通知消息当中去，它仅仅是用于在 STAGES 组件中进行判定(见：[对象属性介绍](#对象属性介绍))。\r\n\r\n当然，也许你会通过在观察内部状态面板中发现每一条通知记录都拥用一个独立了 `id` 属性，但其实它与你在 `Gloria Notification` 对象中填写的 `id` 属性没有任何的关联。通知记录当中通知的 ID 值和任务的 ID 值作用是相同的，都是由扩展程序内部自动随机生成并且是唯一的。\r\n\r\n##### 发送给 Pushbullet\r\n\r\n你可以通过 Pushbullet 将通知消息同步到其它设备上。更多关于 Pushbullet 的使用方法，请参考[官方文档](https://docs.pushbullet.com/)。\r\n\r\n```javascript\r\nfunction reducer(notification) {\r\n  const { title, message, url } = notification;\r\n  const data = {\r\n    type: 'note',\r\n    title,\r\n    body: message,\r\n    device_iden: '...', //? 可选，设备标识，具体见 Pushbullet 文档\r\n  };\r\n  url \u0026\u0026\r\n    Object.assign(data, {\r\n      type: 'link',\r\n      url,\r\n    });\r\n  fetch('https://api.pushbullet.com/v2/pushes', {\r\n    method: 'POST',\r\n    headers: new Headers({\r\n      'Access-Token': 'o.xxx', //! 你的访问令牌\r\n      'Content-Type': 'application/json',\r\n    }),\r\n    body: JSON.stringify(data),\r\n  });\r\n  return notification;\r\n}\r\n```\r\n\r\n你还可以在这里([Reducer 函数 (Pushover 版)](https://gloria.pub/task/60157ce3ab474400108be625))找到使用 Pushover 的版本，更多其他工具的使用接口请参考其文档。\r\n\r\n#### 测试 Rudecer\r\n\r\n在 Reducer 设置面板中你还可以对所编写的 Reducer 函数进行一些简单的测试。\r\n\r\n你可以在测试对象输入框中填入一个由 `Gloria Notification` 对象或其所组成的数组序列化后的 **JSON 字符串**，其实也就是直接模拟出一个任务执行后得出的结果，然后再点击测试按钮后就可以查看 Reducer 函数的返回值及弹出的通知效果了。\r\n\r\n至于 Reducer 函数的代码错误或者是在 Reducer 函数中使用 `console` 语句的输出需要打开扩展程序的背景页\u003c\"background.html\"\u003e进行查看。\r\n\r\n最后再叮嘱一句，一定要小心使用 Reducer 函数。\r\n\r\n## 其他事项\r\n\r\n### 准时模式\r\n\r\n任务中有一个可选的 `准时模式` 选项，即任务严格按照给定时间间隔执行检查 (_不影响任务代码本身，任务依旧兼容 Gloria_)。在任务已启用的前提下，\r\n\r\n- 采用默认模式(Gloria 的设定)的任务在启动浏览器时总是会自动执行一次，再以此刻活动时间为基准设定计时器；\r\n\r\n- 采用准时模式的任务在启动浏览器时会先判定该任务距上一次的执行时间是否超过所设定的执行间隔，若还在间隔时间内，则不会立即执行检查，而是依照预定的时间到达时才会执行检查。\r\n\r\n### 其他特性\r\n\r\n- 允许隐式推送通知 (记录通知但不会有消息提示)\r\n- 支持稍后查阅通知的功能\r\n- 允许筛选任务和通知记录\r\n- 允许自定义通知是否发出提示音\r\n- 可以在 Popup 页面中通过鼠标右键菜单操作任务和通知记录\r\n\r\n## 相关文档\r\n\r\n**更多相关的具体详情可以参考：**\r\n\r\n1. Gloria 中文指南：https://docs.gloria.pub/\r\n2. 任务代码分享网站：https://gloria.pub/\r\n\r\n## Firefox 版本的限制\r\n\r\n由于所提供的 API 支持程度不相同，在 Firefox 上的版本存在一些功能限制。\r\n\r\n以下是 Firefox 版本相对 Chrome 版本所\u003cu\u003e不支持\u003c/u\u003e的功能：\r\n\r\n- 弹出的通知需要手动关闭的可选选项\r\n- 在弹出的通知中显示图片\r\n- 在弹出的通知中提供操作按钮\r\n\r\n以下是 Firefox 版本相对 Chrome 版本一些处理逻辑上的区别：\r\n\r\n- 如果启用了\"在扩展程序图标上显示未读通知数量标记\"功能，当点击通知的关闭按钮时，并不会使数量标记值减少。(若通知关联着网址，点击通知打开网址时才会标记值减少。)\r\n\r\n## 开发编译\r\n\r\n### 环境需求\r\n\r\n- 安装 [Node.js](https://nodejs.org/) 16(_已集成 `npm`，若您的网络环境不佳，推荐安装使用 [`cnpm`](https://github.com/cnpm/cnpm)_)\r\n\r\n### 安装依赖\r\n\r\n```bash\r\nnpm install\r\n```\r\n\r\n### 构建指令\r\n\r\n- 构建 Chrome 版本: `npm run build-chrome`\r\n- 构建 Edge 版本: `npm run build-edge`\r\n- 构建 Firefox 版本: `npm run build-firefox`\r\n\r\n### 相关目录及文件\r\n\r\n- 与打包相关的配置位于 `vue.config.js` 文件中\r\n- 扩展程序源代码位于 `src` 目录中\r\n- 未改动配置的情况下，`src/assets` 目录下所有文件及文件夹在打包时会自动复制到项目根目录\r\n\r\n## 相关项目\r\n\r\n在此，向 Gloria 作者 [BlackGlory](https://github.com/BlackGlory) 以及所有相关项目人员表示由衷的感谢。:heart:\r\n\r\n- [BlackGlory/Gloria](https://github.com/BlackGlory/Gloria)\r\n- [akanshgulati/scrap-favicon](https://github.com/akanshgulati/scrap-favicon)\r\n- [CarterLi/vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)\r\n- [element-plus/element-plus](https://github.com/element-plus/element-plus)\r\n- [GitHub-Laziji/menujs](https://github.com/GitHub-Laziji/menujs)\r\n- [ReactiveX/rxjs](https://github.com/ReactiveX/RxJS)\r\n- [Simonwep/selection](https://github.com/Simonwep/selection)\r\n- [vuejs/vue-next](https://github.com/vuejs/vue-next)\r\n- [yyf1994gggg/vuex-chrome](https://github.com/yyf1994gggg/vuex-chrome)\r\n\r\n## 许可证\r\n\r\n[MIT](/LICENSE) License\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightapis%2Fgloria-x","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flightapis%2Fgloria-x","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightapis%2Fgloria-x/lists"}