feat: migrate to plasmo

This commit is contained in:
DIYgod
2023-12-08 04:20:34 +00:00
parent 4e406d4378
commit d60aad7d12
58 changed files with 4574 additions and 24312 deletions
-5
View File
@@ -1,5 +0,0 @@
.github/
.vscode/
dist
release
*.config.js
-64
View File
@@ -1,64 +0,0 @@
{
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
],
"plugins": [
"prettier"
],
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"env": {
"node": true,
"es6": true
},
"rules": {
"no-console": 0,
"block-scoped-var": 1,
"curly": 1,
"eqeqeq": 1,
"no-global-assign": 1,
"no-implicit-globals": 1,
"no-labels": 1,
"no-multi-str": 1,
"comma-spacing": 1,
"comma-style": 1,
"func-call-spacing": 1,
"keyword-spacing": 1,
"linebreak-style": 1,
"lines-around-comment": 1,
"no-multiple-empty-lines": 1,
"space-infix-ops": 1,
"arrow-spacing": 1,
"no-var": 1,
"prefer-const": 1,
"no-unsafe-negation": 1,
"array-callback-return": 1,
"dot-notation": 1,
"no-eval": 0,
"no-extend-native": 1,
"no-extra-label": 1,
"semi": 1,
"space-before-blocks": 1,
"space-in-parens": 1,
"space-unary-ops": 1,
"spaced-comment": 1,
"arrow-body-style": 1,
"arrow-parens": 1,
"no-restricted-imports": 1,
"no-duplicate-imports": 1,
"no-useless-computed-key": 1,
"no-useless-rename": 1,
"rest-spread-spacing": 1,
"no-trailing-spaces": 1,
"no-control-regex": 0,
"prettier/prettier": 0,
"no-await-in-loop": 1,
"require-atomic-updates": 0,
"no-prototype-builtins": 0,
"no-undef": 0,
"vue/no-use-v-if-with-v-for": "off",
}
}
-40
View File
@@ -1,40 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
time: "21:00"
open-pull-requests-limit: 10
reviewers:
- DIYgod
labels:
- dependencies
ignore:
- dependency-name: webpack
versions:
- 5.26.2
- 5.27.2
- 5.28.0
- 5.28.0
- 5.30.0
- 5.31.0
- 5.31.2
- 5.35.0
- 5.35.1
- dependency-name: webpack-cli
versions:
- 4.4.0
- 4.5.0
- 4.5.0
- 4.5.0
- 4.6.0
- 4.6.0
- 4.6.0
- 4.6.0
- dependency-name: copy-webpack-plugin
versions:
- 8.1.0
- dependency-name: postcss-loader
versions:
- 5.1.0
-43
View File
@@ -1,43 +0,0 @@
name: release
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
name: Build assets
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm i
- name: Build file
run: pnpm run release
- name: Upload file
uses: xresloader/upload-to-github-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
file: "release/radar.zip"
tags: true
draft: false
+34
View File
@@ -0,0 +1,34 @@
name: "Submit to Web Store"
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache pnpm modules
uses: actions/cache@v3
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
- uses: pnpm/action-setup@v2.2.4
with:
version: latest
run_install: true
- name: Use Node.js 16.x
uses: actions/setup-node@v3.4.1
with:
node-version: 16.x
cache: "pnpm"
- name: Build the extension
run: pnpm build
- name: Package the extension into a zip artifact
run: pnpm package
- name: Browser Platform Publish
uses: PlasmoHQ/bpp@v3
with:
keys: ${{ secrets.SUBMIT_KEYS }}
artifact: build/chrome-mv3-prod.zip
+39 -4
View File
@@ -1,4 +1,39 @@
node_modules
dist
release
yarn-error.log
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
#cache
.turbo
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*
out/
build/
dist/
# plasmo - https://www.plasmo.com
.plasmo
# bpp - http://bpp.browser.market/
keys.json
# typescript
.tsbuildinfo
-8
View File
@@ -1,8 +0,0 @@
package.json
package-lock.json
.github/
.vscode/
dist
release
*.config.js
src/js/common/radar-rules.js
-7
View File
@@ -1,7 +0,0 @@
{
"printWidth": 233,
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "es5",
"arrowParens": "always"
}
+26
View File
@@ -0,0 +1,26 @@
/**
* @type {import('prettier').Options}
*/
export default {
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: false,
singleQuote: false,
trailingComma: "none",
bracketSpacing: true,
bracketSameLine: true,
plugins: ["@ianvs/prettier-plugin-sort-imports"],
importOrder: [
"<BUILTIN_MODULES>", // Node.js built-in modules
"<THIRD_PARTY_MODULES>", // Imports not matched by other special words or groups.
"", // Empty line
"^@plasmo/(.*)$",
"",
"^@plasmohq/(.*)$",
"",
"^~(.*)$",
"",
"^[./]"
]
}
+33
View File
@@ -0,0 +1,33 @@
This is a [Plasmo extension](https://docs.plasmo.com/) project bootstrapped with [`plasmo init`](https://www.npmjs.com/package/plasmo).
## Getting Started
First, run the development server:
```bash
pnpm dev
# or
npm run dev
```
Open your browser and load the appropriate development build. For example, if you are developing for the chrome browser, using manifest v3, use: `build/chrome-mv3-dev`.
You can start editing the popup by modifying `popup.tsx`. It should auto-update as you make changes. To add an options page, simply add a `options.tsx` file to the root of the project, with a react component default exported. Likewise to add a content page, add a `content.ts` file to the root of the project, importing some module and do some logic, then reload the extension on your browser.
For further guidance, [visit our Documentation](https://docs.plasmo.com/)
## Making production build
Run the following:
```bash
pnpm build
# or
npm run build
```
This should create a production bundle for your extension, ready to be zipped and published to the stores.
## Submit to the webstores
The easiest way to deploy your Plasmo extension is to use the built-in [bpp](https://bpp.browser.market) GitHub action. Prior to using this action however, make sure to build your extension and upload the first version to the store to establish the basic credentials. Then, simply follow [this setup instruction](https://docs.plasmo.com/framework/workflows/submit) and you should be on your way for automated submission!

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+31 -76
View File
@@ -1,83 +1,38 @@
{
"name": "rsshub-radar",
"version": "0.0.1",
"description": "Browser extension to detect available RSS and RSSHub for current page",
"displayName": "RSSHub Radar",
"version": "2.0.0",
"description": "Browser extension that simplifies finding and subscribing RSS and RSSHub",
"author": "DIYgod <i@diygod.me>",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack -w --mode=production --progress",
"build": "webpack --mode=production --progress",
"release": "npm run build && mkdir release && zip -r release/radar.zip dist",
"format": "eslint \"**/*.js\" --fix && prettier \"**/*.{js,scss,less}\" --write",
"format:staged": "eslint \"**/*.js\" --fix && pretty-quick --staged --verbose --pattern \"**/*.{js,scss,less}\"",
"format:check": "eslint \"**/*.js\" && prettier-check \"**/*.{js,scss,less}\""
},
"repository": {
"type": "git",
"url": "git+https://github.com/DIYgod/RSSHub-Radar.git"
},
"keywords": [
"rsshub",
"rss"
],
"gitHooks": {
"pre-commit": "npm run format:staged"
},
"author": "DIYgod",
"license": "MIT",
"bugs": {
"url": "https://github.com/DIYgod/RSSHub-Radar/issues"
},
"homepage": "https://github.com/DIYgod/RSSHub-Radar#readme",
"devDependencies": {
"@babel/core": "7.23.3",
"@babel/preset-env": "7.23.3",
"autoprefixer": "10.4.16",
"babel-loader": "9.1.3",
"babel-plugin-component": "1.1.1",
"copy-webpack-plugin": "11.0.0",
"css-loader": "6.8.1",
"cssnano": "5.1.14",
"eslint": "8.54.0",
"eslint-config-prettier": "9.0.0",
"eslint-loader": "4.0.2",
"eslint-plugin-prettier": "5.0.1",
"file-loader": "6.2.0",
"less": "4.2.0",
"less-loader": "11.1.3",
"mini-css-extract-plugin": "2.7.6",
"postcss-loader": "7.3.3",
"prettier": "2.8.3",
"prettier-check": "2.0.0",
"pretty-quick": "3.1.3",
"sass": "^1.69.5",
"sass-loader": "13.3.2",
"svg-inline-loader": "0.8.2",
"template-string-optimize-loader": "3.0.0",
"url-loader": "4.1.1",
"vue-loader": "15.10.1",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "2.7.15",
"webpack": "5.89.0",
"webpack-cli": "5.1.4",
"yorkie": "2.0.0"
"dev": "plasmo dev",
"build": "plasmo build",
"package": "plasmo package"
},
"dependencies": {
"buffer": "^6.0.3",
"clipboard": "2.0.11",
"element-ui": "2.15.14",
"https-browserify": "^1.0.0",
"i18n-js": "^4.3.2",
"lodash": "^4.17.21",
"md5.js": "^1.3.5",
"process": "^0.11.10",
"psl": "1.9.0",
"route-recognizer": "0.3.4",
"rss-parser": "3.13.0",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"timers-browserify": "^2.0.12",
"url": "^0.11.3",
"vue": "2",
"vue-router": "3.6.5"
"@plasmohq/messaging": "^0.6.1",
"plasmo": "0.84.0",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "4.1.1",
"@types/chrome": "0.0.251",
"@types/node": "20.9.0",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32",
"prettier": "3.0.3",
"tailwindcss": "^3.3.6",
"typescript": "5.2.2"
},
"manifest": {
"host_permissions": [
"https://*/*"
],
"permissions": [
"tabs"
]
}
}
+4280 -4322
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
/**
* @type {import('postcss').ProcessOptions}
*/
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}
-5
View File
@@ -1,5 +0,0 @@
{
"extends": [
"config:base"
]
}
-10
View File
@@ -1,10 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<title>RSSHub Radar Background</title>
</head>
<body>
<iframe id="sandbox" src="sandbox.html"></iframe>
<script src="background.js"></script>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

-41
View File
@@ -1,41 +0,0 @@
{
"manifest_version": 2,
"applications": {
"gecko": {
"id": "i@diygod.me"
}
},
"name": "RSSHub Radar",
"description": "RSSHub Radar is a spin-off of RSSHub that helps you quickly discover and subscribe to RSS and RSSHub for your current site.",
"version": "1.10.3",
"homepage_url": "https://docs.rsshub.app",
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
"browser_action": {
"default_icon": "rsshub.png",
"default_popup": "popup.html"
},
"content_scripts": [{
"matches": ["https://*/*", "http://*/*"],
"js": ["content.js"]
}],
"background" : {
"page": "background.html",
"persistent": true
},
"options_page": "options.html",
"sandbox": {
"pages": ["sandbox.html"]
},
"permissions": [
"tabs",
"storage",
"notifications",
"alarms",
"idle"
]
}
-12
View File
@@ -1,12 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<title data-i18n>RSSHub Radar Options</title>
<link rel="stylesheet" href="./options.css">
</head>
<body>
<iframe id="sandbox" style="display: none;" src="sandbox.html"></iframe>
<div id="app"></div>
<script src="./options.js"></script>
</body>
</html>
-30
View File
@@ -1,30 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<title>RSSHub Radar</title>
<link rel="stylesheet" href="./popup.css">
</head>
<body>
<div class="icons">
<a class="icons-item icons-about" href="/options.html#/about"></a>
<a class="icons-item icons-setting" href="/options.html#/setting"></a>
</div>
<div class="no-rss">
<h2>( ´・・)ノ(._.`) <span data-i18n>rss not found</span></h2>
<p data-i18n>join rsshub</p>
</div>
<div class="page-rss">
<h2 data-i18n>current page rss</h2>
<ul></ul>
</div>
<div class="page-rsshub">
<h2 data-i18n>current page RSSHub</h2>
<ul></ul>
</div>
<div class="website-rsshub">
<h2 data-i18n>current site RSSHub</h2>
<ul></ul>
</div>
<script src="./popup.js"></script>
</body>
</html>
-9
View File
@@ -1,9 +0,0 @@
<html>
<head>
<meta charset="UTF-8">
<title>RSSHub Radar Sandbox</title>
</head>
<body>
<script src="sandbox.js"></script>
</body>
</html>
+2
View File
@@ -0,0 +1,2 @@
export {}
console.log("HELLO WORLD FROM BGSCRIPTS")
+11
View File
@@ -0,0 +1,11 @@
import type { PlasmoCSConfig } from "plasmo"
export const config: PlasmoCSConfig = {
matches: ["https://www.plasmo.com/*"]
}
window.addEventListener("load", () => {
console.log("content script loaded")
document.body.style.background = "pink"
})
-5
View File
@@ -1,5 +0,0 @@
$--color-primary: #f5712c;
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import '~element-ui/packages/theme-chalk/src/index';
-262
View File
@@ -1,262 +0,0 @@
body {
min-width: 350px;
margin: 0;
padding: 20px 20px 5px;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
&.something {
.no-rss {
display: none;
}
.icons {
right: 25px;
}
}
}
.icons {
position: absolute;
right: 16px;
top: 21px;
.icons-item {
width: 18px;
display: inline-block;
fill: #666;
transition: 0.3s;
margin-left: 5px;
&:hover {
fill: #000;
}
}
}
.page-rss,
.page-rsshub,
.website-rsshub {
display: none;
margin-bottom: 20px;
h2 {
font-size: 16px;
margin: 0 0 15px;
}
ul,
li {
padding: 0;
list-style-type: none;
}
ul {
margin: 0 5px;
}
}
.no-rss {
margin-bottom: 20px;
h2 {
font-size: 16px;
margin: 0 0 15px;
}
p {
margin: 0;
font-size: 14px;
line-height: 20px;
}
a {
color: #ff8549;
text-decoration: none;
}
}
.rss-item {
display: flex;
height: 30px;
margin-bottom: 15px;
.rss-image {
width: 30px;
height: 30px;
margin-right: 10px;
}
.rss-info {
width: 200px;
cursor: pointer;
display: flex;
text-decoration: none;
color: #000;
line-height: 1;
flex-direction: column;
justify-content: space-between;
.rss-title {
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rss-url {
font-size: 12px;
color: #aaa;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
}
.rss-action {
white-space: nowrap;
padding: 0 10px;
font-size: 13px;
color: #f5712c;
background: #fff;
border: 1px solid #f5712c;
line-height: 30px;
text-align: center;
transition: 0.3s;
border-radius: 4px;
cursor: pointer;
box-sizing: border-box;
text-decoration: none;
margin-left: 10px;
min-width: 61px;
&:hover {
color: #fff;
background: #f5712c;
}
&.rss-copy {
width: 61px;
}
&.rss-submitto-ttrss {
color: #f28f34;
border: 1px solid #f28f34;
&:hover {
color: #fff;
background: #f28f34;
}
}
&.rss-submitto-checkchan {
color: #f28f34;
border: 1px solid #f28f34;
&:hover {
color: #fff;
background: #f28f34;
}
}
&.rss-submitto-miniflux {
color: #33995b;
border: 1px solid #33995b;
&:hover {
color: #fff;
background: #33995b;
}
}
&.rss-submitto-freshrss {
color: #0062bd;
border: 1px solid #0062db;
&:hover {
color: #fff;
background: #0062db;
}
}
&.rss-submitto-nextcloudnews {
color: #0082c9;
border: 1px solid #0082c9;
&:hover {
color: #fff;
background: #0082c9;
}
}
&.rss-submitto-feedly {
color: #2bb24c;
border: 1px solid #2bb24c;
&:hover {
color: #fff;
background: #2bb24c;
}
}
&.rss-submitto-inoreader {
color: #0099eb;
border: 1px solid #0099eb;
&:hover {
color: #fff;
background: #0099eb;
}
}
&.rss-submitto-feedbin {
color: #0867e2;
border: 1px solid #0867e2;
&:hover {
color: #fff;
background: #0867e2;
}
}
&.rss-submitto-theoldreader {
color: #ff2300;
border: 1px solid #ff2300;
&:hover {
color: #fff;
background: #ff2300;
}
}
&.rss-submitto-feedspub {
color: #61af4b;
border: 1px solid #61af4b;
&:hover {
color: #fff;
background: #61af4b;
}
}
&.rss-submitto-bazqux {
color: #00af00;
border: 1px solid #00af00;
&:hover {
color: #fff;
background: #00af00;
}
}
}
}
.website-rsshub {
.rss-info {
flex: 1;
margin-right: 10px;
}
.rss-action {
margin-left: auto;
}
}
-69
View File
@@ -1,69 +0,0 @@
import { handleRSS, removeRSS, addPageRSS, getAllRSS } from './utils';
import { getConfig, saveConfig } from '../common/config';
chrome.tabs.onActivated.addListener((tab) => {
chrome.tabs.sendMessage(
tab.tabId,
{
text: 'getPageRSS',
},
(feeds) => {
handleRSS(feeds, tab.tabId, true);
}
);
});
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.url && tab.active) {
chrome.tabs.sendMessage(
tab.id,
{
text: 'getPageRSS',
},
(feeds) => {
handleRSS(feeds, tab.id);
}
);
}
});
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (sender.tab && sender.tab.active) {
if (msg.text === 'setPageRSS') {
handleRSS(msg.feeds, sender.tab.id);
} else if (msg.text === 'addPageRSS') {
addPageRSS(msg.feed, sender.tab.id);
}
}
if (msg.text === 'getAllRSS') {
sendResponse(getAllRSS(msg.tabId));
}
});
chrome.tabs.onRemoved.addListener((tabId) => {
removeRSS(tabId);
});
getConfig((config) => {
if (!config.version) {
config.version = VERSION;
saveConfig(config);
} else if (config.version !== VERSION) {
chrome.notifications.create('RSSHubRadarUpdate', {
type: 'basic',
iconUrl: './rsshub.png',
title: '🎉 RSSHub Radar 更新',
message: `v${VERSION},点击查看更新日志`,
});
chrome.notifications.onClicked.addListener((id) => {
if (id === 'RSSHubRadarUpdate') {
chrome.tabs.create({
url: 'https://github.com/DIYgod/RSSHub-Radar/releases',
});
chrome.notifications.clear('RSSHubRadarUpdate');
}
});
config.version = VERSION;
saveConfig(config);
}
});
-171
View File
@@ -1,171 +0,0 @@
import { getRules, getRulesDate, refreshRules } from '../common/rules';
import { commandSandbox } from '../common/utils';
import { getConfig } from '../common/config';
let config;
let rules = {};
import RSSParser from 'rss-parser';
const rssParser = new RSSParser();
window.pageRSS = {};
window.pageRSSHub = {};
window.websiteRSSHub = {};
function schedule(time = +new Date() + config.refreshTimeout * 1000) {
chrome.alarms.create('refreshRules', {
when: time,
periodInMinutes: config.refreshTimeout / 60,
});
}
function initSchedule() {
getRulesDate((lastDate) => {
if (!lastDate || +new Date() - lastDate > config.refreshTimeout * 1000) {
refreshRules();
schedule();
} else {
schedule(lastDate + config.refreshTimeout * 1000);
}
});
}
chrome.storage.onChanged.addListener((result) => {
if (result.config) {
config = result.config.newValue;
}
if (result.rules) {
getRules((rul) => {
rules = rul;
});
}
});
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'refreshRules') {
refreshRules();
}
});
if ('idle' in chrome) {
chrome.idle.onStateChanged.addListener((newState) => {
if (newState === 'active') {
initSchedule();
}
});
}
getConfig((conf) => {
config = conf;
getRules((rul) => {
rules = rul;
initSchedule();
});
});
chrome.browserAction.setBadgeBackgroundColor({
color: '#F62800',
});
chrome.browserAction.setBadgeTextColor &&
chrome.browserAction.setBadgeTextColor({
color: '#fff',
});
function setBadge(tabId) {
chrome.browserAction.setBadgeText({
text: config.notice.badge ? (window.pageRSS[tabId].length + (window.pageRSSHub[tabId] ? window.pageRSSHub[tabId].length : 0) || (window.websiteRSSHub[tabId] && window.websiteRSSHub[tabId].length ? ' ' : '')) + '' : '',
tabId,
});
}
function getPageRSSHub(url, tabId, done) {
chrome.tabs.sendMessage(
tabId,
{
text: 'getHTML',
},
(html) => {
commandSandbox(
'getPageRSSHub',
{
url,
html,
rules,
},
done
);
}
);
}
function getWebsiteRSSHub(url, done) {
commandSandbox(
'getWebsiteRSSHub',
{
url,
rules,
},
done
);
}
export function handleRSS(feeds, tabId, useCache) {
if (useCache && window.pageRSS[tabId]) {
setBadge(tabId);
} else {
chrome.tabs.get(tabId, (tab) => {
feeds &&
feeds.forEach((feed) => {
feed.image = tab.favIconUrl || feed.image;
});
window.pageRSS[tabId] = (feeds && feeds.filter((feed) => !feed.uncertain)) || [];
getWebsiteRSSHub(tab.url, (feeds) => {
window.websiteRSSHub[tabId] = feeds || [];
setBadge(tabId);
});
getPageRSSHub(tab.url, tabId, (feeds) => {
window.pageRSSHub[tabId] = feeds || [];
setBadge(tabId);
});
});
feeds &&
feeds
.filter((feed) => feed.uncertain)
.forEach((feed) => {
rssParser.parseURL(feed.url, (err, result) => {
if (!err) {
feed.title = result.title;
window.pageRSS[tabId].push(feed);
setBadge(tabId);
}
});
});
}
}
export function removeRSS(tabId) {
delete window.pageRSS[tabId];
delete window.websiteRSSHub[tabId];
delete window.pageRSSHub[tabId];
}
export function addPageRSS(feed, tabId) {
if (feed) {
chrome.tabs.get(tabId, (tab) => {
feed.image = tab.favIconUrl || feed.image;
window.pageRSS[tabId].push(feed);
setBadge(tabId);
});
}
}
export function getAllRSS(tabId) {
return {
pageRSS: window.pageRSS[tabId] || {},
websiteRSSHub: window.websiteRSSHub[tabId] || {},
pageRSSHub: window.pageRSSHub[tabId] || {},
};
}
-79
View File
@@ -1,79 +0,0 @@
export const defaultConfig = {
rsshubDomain: 'https://rsshub.app',
rsshubAccessControl: {
enabled: false,
accessKey: '',
useCode: false,
},
notice: {
badge: true,
},
submitto: {
ttrss: false,
ttrssDomain: '',
checkchan: false,
checkchanBase: '',
miniflux: false,
minifluxDomain: '',
freshrss: false,
freshrssDomain: '',
nextcloudnews: false,
nextcloudnewsDomain: '',
feedly: true,
inoreader: false,
inoreaderDomain: 'https://www.inoreader.com',
feedbin: false,
feedbinDomain: 'https://feedbin.com',
theoldreader: false,
feedspub: false,
bazqux: false,
local: false,
},
refreshTimeout: 5 * 60 * 60,
// typical UA:
// Firefox: Mozilla/5.0 (X11; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0
// Chromium/Chrome: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
// Some Chromium: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/80.0.3987.87 Chrome/80.0.3987.87 Safari/537.36
// Safari: Mozilla/5.0 (Macintosh; Intel Mac OS X 12_3_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Safari/605.1.15
// Edge: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/99.0.1150.36
enableFullRemoteRules: !(navigator.userAgent.match(/firefox/i) || (navigator.userAgent.match(/safari/i) && !navigator.userAgent.match(/chrome/i))),
};
export function getConfig(success) {
if (chrome.storage) {
chrome.storage.sync.get('config', (result) => {
const config = Object.assign({}, defaultConfig, result.config);
if (!config.submitto.feedbinDomain) {
config.submitto.feedbinDomain = defaultConfig.submitto.feedbinDomain;
}
if (!config.submitto.inoreaderDomain) {
config.submitto.inoreaderDomain = defaultConfig.submitto.inoreaderDomain;
}
success(config);
});
} else {
success && success(defaultConfig);
}
}
export function saveConfig(config, success) {
if (!config.rsshubDomain) {
config.rsshubDomain = defaultConfig.rsshubDomain;
}
config.rsshubDomain = config.rsshubDomain.replace(/\/$/, '');
if (config.rsshubDomain === defaultConfig.rsshubDomain) {
config.rsshubAccessControl.enabled = defaultConfig.rsshubAccessControl.enabled;
}
if (chrome.storage) {
chrome.storage.sync.set(
{
config,
},
() => {
success && success();
}
);
}
}
-18
View File
@@ -1,18 +0,0 @@
import { I18n } from 'i18n-js';
import en from '../../translations/en.json';
import es from '../../translations/es.json';
import eu from '../../translations/eu.json';
import pt from '../../translations/pt.json';
import zh from '../../translations/zh.json';
const i18n = new I18n({
en,
es,
eu,
pt,
zh,
});
i18n.enableFallback = true;
i18n.defaultLocale = 'en';
i18n.locale = navigator.language;
export default i18n;
File diff suppressed because it is too large Load Diff
-51
View File
@@ -1,51 +0,0 @@
import { defaultConfig } from './config';
export function refreshRules(success) {
const done = (response) => {
response.text().then((text) => {
chrome.storage.local.set({
rules: text,
rulesDate: +new Date(),
});
success && success();
});
};
fetch(`https://rsshub.js.org/build/radar-rules.${defaultConfig.enableFullRemoteRules ? 'js' : 'json'}`)
.then((response) => {
done(response);
})
.catch(() => {
fetch(`https://cdn.jsdelivr.net/gh/DIYgod/RSSHub@gh-pages/build/radar-rules.${defaultConfig.enableFullRemoteRules ? 'js' : 'json'}`).then((response) => {
done(response);
});
});
}
export function getRules(success) {
chrome.storage.local.get('rules', (result) => {
if (result && result.rules) {
success(result.rules);
} else {
refreshRules(() => {
getRules(success);
});
}
});
}
export function getRulesDate(success) {
chrome.storage.local.get('rulesDate', (result) => {
if (result && result.rulesDate) {
success(result.rulesDate);
} else {
success(null);
}
});
}
export function updateRules(text, success) {
chrome.storage.local.set({
rules: text,
});
success && success();
}
-46
View File
@@ -1,46 +0,0 @@
export function secondToTime(second) {
const hour = Math.floor(second / 3600);
const min = Math.floor((second - hour * 3600) / 60);
return `${hour ? hour + 'h ' : ''}${min}min `;
}
export function secondToHoursMinutes(second) {
const hours = Math.floor(second / 3600);
const minutes = Math.floor((second - hours * 3600) / 60);
return { hours, minutes };
}
const iframe = document.querySelector('#sandbox');
const returnResults = [];
window.addEventListener('message', (event) => {
returnResults.forEach((returnResult) => {
returnResult(event);
});
});
export function commandSandbox(command, data, callback) {
if (data.rules && typeof data.rules === 'object') {
try {
callback(iframe.contentWindow[command](data));
return;
} catch (e) {
// nothing
}
}
iframe.contentWindow.postMessage(
{
command: command,
data: data,
},
'*'
);
const myReturn = (event) => {
if (event.data.origin.command === command && (!data.url || event.data.origin.data.url === data.url)) {
returnResults.splice(returnResults.indexOf(myReturn), 1);
if (event.data && event.data.result) {
callback(event.data.result);
}
}
};
returnResults.push(myReturn);
}
-14
View File
@@ -1,14 +0,0 @@
import { getPageRSS } from './utils';
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.text === 'getPageRSS') {
sendResponse(getPageRSS());
} else if (msg.text === 'getHTML') {
sendResponse(document.documentElement.innerHTML);
}
});
chrome.runtime.sendMessage(null, {
text: 'setPageRSS',
feeds: getPageRSS(),
});
-120
View File
@@ -1,120 +0,0 @@
import RSSParser from 'rss-parser';
const rssParser = new RSSParser();
let pageRSS = null;
const defaultTitle =
document.querySelector('title') &&
document.querySelector('title').innerHTML &&
document
.querySelector('title')
.innerHTML.replace(/<!\[CDATA\[(.*)]]>/, (match, p1) => p1)
.trim();
const image = (document.querySelector('link[rel~="icon"]') && handleUrl(document.querySelector('link[rel~="icon"]').getAttribute('href'))) || document.location.origin + '/favicon.ico';
function handleUrl(url) {
return new URL(url, document.location.href).toString();
}
export function getPageRSS() {
if (!pageRSS) {
pageRSS = [];
const unique = {
data: {},
save: function (url) {
this.data[url.replace(/^(https?:)?\/\//, '')] = 1;
},
check: function (url) {
return this.data[url.replace(/^(https?:)?\/\//, '')];
},
};
// links
const types = [
'application/rss+xml',
'application/atom+xml',
'application/rdf+xml',
'application/rss',
'application/atom',
'application/rdf',
'text/rss+xml',
'text/atom+xml',
'text/rdf+xml',
'text/rss',
'text/atom',
'text/rdf',
'application/feed+json',
];
const links = document.querySelectorAll('link[type]');
for (let i = 0; i < links.length; i++) {
if (links[i].hasAttribute('type') && types.indexOf(links[i].getAttribute('type')) !== -1) {
const feed_url = links[i].getAttribute('href');
if (feed_url) {
const feed = {
url: handleUrl(feed_url),
title: links[i].getAttribute('title') || defaultTitle,
image,
};
if (!unique.check(feed.url)) {
pageRSS.push(feed);
unique.save(feed.url);
}
}
}
}
// a
const aEles = document.querySelectorAll('a');
const check = /([^a-zA-Z]|^)rss([^a-zA-Z]|$)/i;
for (let i = 0; i < aEles.length; i++) {
if (aEles[i].hasAttribute('href')) {
const href = aEles[i].getAttribute('href');
if (
href.match(/\/(feed|rss|atom)(\.(xml|rss|atom))?\/?$/) ||
(aEles[i].hasAttribute('title') && aEles[i].getAttribute('title').match(check)) ||
(aEles[i].hasAttribute('class') && aEles[i].getAttribute('class').match(check)) ||
(aEles[i].innerText && aEles[i].innerText.match(check))
) {
const feed = {
url: handleUrl(href),
title: aEles[i].innerText || aEles[i].getAttribute('title') || defaultTitle,
image,
uncertain: 1,
};
if (!unique.check(feed.url)) {
pageRSS.push(feed);
unique.save(feed.url);
}
}
}
}
// whole page
if (!unique.check(document.location.href)) {
let html;
if (document.body && document.body.childNodes && document.body.childNodes.length === 1 && document.body.childNodes[0].tagName && document.body.childNodes[0].tagName.toLowerCase()) {
html = document.body.childNodes[0].innerText;
} else if (document.querySelector('#webkit-xml-viewer-source-xml')) {
html = document.querySelector('#webkit-xml-viewer-source-xml').innerHTML;
}
if (html) {
rssParser.parseString(html, (err, result) => {
if (!err) {
chrome.runtime.sendMessage(null, {
text: 'addPageRSS',
feed: {
url: document.location.href,
title: result.title,
image,
},
});
}
});
}
}
unique.save(document.location.href);
}
return pageRSS;
}
-121
View File
@@ -1,121 +0,0 @@
<template>
<div id="app">
<el-container class="container">
<el-aside width="200px">
<el-menu
class="menu"
:default-active="this.$route.path"
@select="handleSelect">
<el-header
class="header"
height="80px">RSSHub Radar</el-header>
<el-menu-item index="/setting">
<i class="el-icon-setting"></i>
<span slot="title">{{ $i18n.t('settings') }}</span>
</el-menu-item>
<el-menu-item index="/list">
<i class="el-icon-magic-stick"></i>
<span slot="title">{{ $i18n.t('list of rules') }}</span>
</el-menu-item>
<el-menu-item index="/about">
<i class="el-icon-coordinate"></i>
<span slot="title">{{ $i18n.t('about') }}</span>
</el-menu-item>
<el-footer class="footer">{{ $i18n.t('version')}} v{{ version }}<br>Made with <i style="color:#d43f57"></i> by <a target="_blank" href="https://diygod.me">DIYgod</a></el-footer>
</el-menu>
</el-aside>
<el-container class="sub-container">
<!-- <el-main><router-view></router-view></el-main> -->
<router-view></router-view>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
name: 'app',
data: () => ({
version: VERSION,
}),
methods: {
handleSelect(key, keyPath) {
this.$router.push(key);
},
}
}
</script>
<style lang="less">
@color-primary: #f5712c;
body {
margin: 0;
height: 100%;
}
#app {
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
height: 100%;
}
.container {
height: 100%;
}
.sub-container {
overflow: scroll;
}
.menu {
height: 100%;
.el-menu-item {
&:focus {
background-color: transparent;
}
&:hover {
background-color: #fef1ea;
}
}
}
.header {
color: @color-primary;
line-height: 80px;
font-size: 21px;
font-weight: bold;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
line-height: 60px;
text-align: center;
font-size: 14px;
color: #999;
line-height: 25px;
a {
color: @color-primary;
text-decoration: none;
}
}
.el-menu-item {
i,
span {
transition: color .3s;
}
&.is-active {
color: #303133;
i,
span {
color: #f5712c;
}
}
}
</style>
-52
View File
@@ -1,52 +0,0 @@
import '../../css/options.scss';
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import Setting from './views/Setting.vue';
import List from './views/List.vue';
import About from './views/About.vue';
import i18n from '../common/i18n';
import { Container, Menu, MenuItem, Aside, Header, Main, Footer, Input, Checkbox, Message, Loading, Collapse, CollapseItem, Button, Progress, Tooltip } from 'element-ui';
// import translations from "../../translations/translations.json";
// const i18n = new I18n(translations);
// i18n.enableFallback = true;
// i18n.defaultLocale = "zh";
// i18n.locale = navigator.language;
Vue.use(VueRouter);
Vue.use(Container);
Vue.use(Menu);
Vue.use(MenuItem);
Vue.use(Aside);
Vue.use(Header);
Vue.use(Main);
Vue.use(Footer);
Vue.use(Input);
Vue.use(Checkbox);
Vue.use(Loading.directive);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Button);
Vue.use(Progress);
Vue.use(Tooltip);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$message = Message;
Vue.prototype.$i18n = i18n;
Vue.config.productionTip = false;
const routes = [
{ path: '/', redirect: '/setting' },
{ path: '/setting', component: Setting },
{ path: '/list', component: List },
{ path: '/about', component: About },
];
const router = new VueRouter({
routes,
});
new Vue({
render: (h) => h(App),
router,
}).$mount('#app');
-62
View File
@@ -1,62 +0,0 @@
<template>
<div class="about">
<el-main>
<div class="title">{{$i18n.t('about')}}</div>
<div class="content">
<div class="tip">
<p v-html="$i18n.t('rsshub radar info')"></p>
<p><i class="el-icon-trophy"></i> <span v-html="$i18n.t('sponsored development')"></span></p>
<p>&nbsp;</p>
<p>{{$i18n.t('update log')}}: <a target="_blank" href="https://github.com/DIYgod/RSSHub-Radar/releases">https://github.com/DIYgod/RSSHub-Radar/releases</a></p>
<p>{{$i18n.t('question feedback')}}: <a target="_blank" href="https://github.com/DIYgod/RSSHub-radar/issues">https://github.com/DIYgod/RSSHub-radar/issues</a></p>
<p>GitHub: <a target="_blank" href="https://github.com/DIYgod/RSSHub-Radar">https://github.com/DIYgod/RSSHub-Radar</a></p>
<p v-html="$i18n.t('rsshub documentation')"></p>
<p>&nbsp;</p>
<p><b>{{$i18n.t('everything is possible with rss')}}</b></p>
<p><b>Made with <i style="color:#d43f57"></i> by <a target="_blank" href="https://diygod.me">DIYgod</a></b></p>
</div>
</div>
</el-main>
</div>
</template>
<script>
export default {
name: 'About',
data: () => ({
}),
}
</script>
<style lang="less" scoped>
a {
text-decoration: none;
color: #f5712c;
}
.about {
width: 100%;
max-width: 800px;
margin: 0 auto;
padding: 40px 10px;
}
.title {
font-size: 25px;
font-weight: bold;
border-bottom: 1px solid #e6e6e6;
padding-bottom: 10px;
color: #f5712c;
}
.tip {
font-size: 14px;
margin: 20px 0;
color: #555;
}
.content {
margin-top: 20px;
color: #222;
}
</style>
-140
View File
@@ -1,140 +0,0 @@
<template>
<div class="list">
<el-main>
<div class="title">{{ $i18n.t('rules') }}</div>
<div class="tip">
<p v-html="$i18n.t('for more rules join us')"></p>
<p>{{ $i18n.t('updated time ago', {hours: hours, minutes: minutes})}}</p>
</div>
<div class="content" v-loading="loading">
<el-collapse accordion>
<el-collapse-item v-for="(rule, domain) in rules" :key="domain" :title="rule._name + ' - ' + domain">
<div v-for="(subrule, subdomain) in rule" v-if="subdomain[0] !== '_'" :key="subdomain">
<p v-for="subsubrule in subrule" :key="subsubrule.title">
<a target="_blank" :href="subsubrule.docs">{{ subsubrule.title }}</a>
</p>
</div>
</el-collapse-item>
</el-collapse>
<div class="debug">
<div class="tip" v-if="defaultConfig.enableFullRemoteRules">
<p>This area is used for debugging rules in development</p>
<p>Edited content may be overwritten by automatically updated rules at any time, please ensure that there is a local backup</p>
<p>Use Settings - Update Now to immediately restore remote rules</p>
</div>
<div class="tip" v-if="!defaultConfig.enableFullRemoteRules">
<p>This area is used for debugging rules in development</p>
<p>Remote updates and debug function is not available due to browser limitations</p>
</div>
<el-input
type="textarea"
:rows="100"
v-model="rulesText"
@change="updateRules"
:disabled="!defaultConfig.enableFullRemoteRules"
>
</el-input>
</div>
</div>
</el-main>
</div>
</template>
<script>
import { getRules, getRulesDate, updateRules } from '../../common/rules';
import { secondToHoursMinutes, commandSandbox } from '../../common/utils';
import { defaultConfig } from '../../common/config';
export default {
name: 'List',
data: () => ({
loading: true,
rules: {},
hours: '',
minutes: '',
rulesText: '',
defaultConfig,
}),
created() {
getRulesDate((date) => {
let second = (+new Date - +date) / 1000;
const {hours, minutes} = secondToHoursMinutes(second)
this.hours = hours;
this.minutes = minutes;
this.refreshTime();
});
getRules((rules) => {
if (typeof rules === 'string') {
this.rulesText = rules;
commandSandbox('getList', {
rules,
}, (rules) => {
this.rules = rules;
this.loading = false;
});
} else {
this.rulesText = JSON.stringify(rules, null, 4);
this.rules = rules;
this.loading = false;
}
});
},
methods: {
refreshTime() {
getRulesDate((date) => {
const {hours, minutes} = secondToHoursMinutes((+new Date - +date) / 1000)
this.hours = hours;
this.minutes = minutes;
setTimeout(() => {
this.refreshTime();
}, 1000);
});
},
updateRules() {
updateRules(this.rulesText, () => {
this.$message({
message: this.$i18n.t('successfully saved'),
type: 'success'
});
});
},
}
}
</script>
<style lang="less" scoped>
a {
text-decoration: none;
color: #f5712c;
}
.list {
width: 100%;
max-width: 800px;
margin: 0 auto;
padding: 40px 10px;
}
.title {
font-size: 25px;
font-weight: bold;
border-bottom: 1px solid #e6e6e6;
padding-bottom: 10px;
color: #f5712c;
}
.tip {
font-size: 14px;
margin: 20px 0;
color: #555;
}
.content {
margin-top: 20px;
color: #222;
}
.debug {
margin: 200px 0;
}
</style>
-235
View File
@@ -1,235 +0,0 @@
<template>
<div class="setting">
<div class="title">{{ $i18n.t('settings') }}</div>
<div class="content" v-loading="loading">
<div v-if="!loading">
<div class="subtitle">{{ $i18n.t('general') }}</div>
<div class="setting-item">
<div class="setting-name">{{ $i18n.t('custom rsshub domain') }}</div>
<div class="setting-input">
<el-input @change="saveConfig" v-model="config.rsshubDomain" :placeholder="$i18n.t('enter rsshub domain')"></el-input>
</div>
<template v-if="config.rsshubDomain !== defaultConfig.rsshubDomain">
<div class="setting-name">{{ $i18n.t('access key') }}<a target="_blank" href="https://docs.rsshub.app/install/#fang-wen-kong-zhi-pei-zhi"><el-tooltip class="item" effect="dark" :content="$i18n.t('configuration required if access keys enabled')" placement="top"><i class="el-icon-info"></i></el-tooltip></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.rsshubAccessControl.enabled">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.rsshubAccessControl.enabled" v-model="config.rsshubAccessControl.accessKey" :placeholder="$i18n.t('required access key')"></el-input>
<el-checkbox @change="saveConfig" style="margin-left: 20px;" v-if="config.rsshubAccessControl.enabled" v-model="config.rsshubAccessControl.useCode">{{ $i18n.t('generate access code') }}</el-checkbox>
</div>
</template>
<div class="setting-name" v-if="isChrome">{{ $i18n.t('hot key') }}</div>
<div class="setting-input" v-if="isChrome">
<el-button size="medium" @click="toHotkey">{{ $i18n.t('click to set') }}</el-button>
</div>
</div>
<div class="subtitle">{{ $i18n.t('rules update') }}</div>
<div class="setting-item">
<div class="setting-name">{{ $i18n.t('i will update automatically and you can') }}</div>
<div class="setting-input">
<el-button style="" size="medium" @click="refreshRu" :disabled="refreshDisabled">{{ refreshDisabled ? $i18n.t('updating') : $i18n.t('update now') }}</el-button><el-progress :text-inside="true" :stroke-width="20" :percentage="percentage"></el-progress><span class="time">{{ time }} {{ $i18n.t('before update') }}, {{ leftTime }} {{ $i18n.t('after automatic update') }}</span>
</div>
<div class="setting-name" v-if="!defaultConfig.enableFullRemoteRules">{{ $i18n.t('full remote updates are disabled due to browser limitations') }}</div>
</div>
<div class="subtitle">{{ $i18n.t('one-click subscription') }}</div>
<div class="setting-item">
<div class="setting-name">Check酱<a target="_blank" href="https://ckc.ftqq.com"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.checkchan">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.checkchan" v-model="config.submitto.checkchanBase" :placeholder="$i18n.t('required extension base URI', {service: 'CheckChan'})"></el-input>
</div>
<div class="setting-name">Tiny Tiny RSS <a target="_blank" href="https://ttrss.henry.wang/zh/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.ttrss">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.ttrss" v-model="config.submitto.ttrssDomain" :placeholder="$i18n.t('required address', {service: 'Tiny Tiny RSS'})"></el-input>
</div>
<div class="setting-name">Miniflux <a target="_blank" href="https://miniflux.app"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.miniflux">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.miniflux" v-model="config.submitto.minifluxDomain" :placeholder="$i18n.t('required address', {service: 'Miniflux'})"></el-input>
</div>
<div class="setting-name">FreshRSS <a target="_blank" href="https://freshrss.org"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.freshrss">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.freshrss" v-model="config.submitto.freshrssDomain" :placeholder="$i18n.t('required address', {service: 'FreshRSS'})"></el-input>
</div>
<div class="setting-name">Nextcloud News <a target="_blank" href="https://apps.nextcloud.com/apps/news"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.nextcloudnews">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.nextcloudnews" v-model="config.submitto.nextcloudnewsDomain" :placeholder="$i18n.t('required address', {service: 'Nextcloud'})"></el-input>
</div>
<div class="setting-name">Feedly <a target="_blank" href="https://feedly.com/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.feedly">{{ $i18n.t('enable') }}</el-checkbox>
</div>
<div class="setting-name">Inoreader <a target="_blank" href="https://www.inoreader.com/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.inoreader">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.inoreader" v-model="config.submitto.inoreaderDomain" :placeholder="$i18n.t('required address', {service: 'Inoreader'})"></el-input>
</div>
<div class="setting-name">Feedbin <a target="_blank" href="https://feedbin.com/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.feedbin">{{ $i18n.t('enable') }}</el-checkbox>
<el-input @change="saveConfig" style="margin-left: 20px;" v-if="config.submitto.feedbin" v-model="config.submitto.feedbinDomain" :placeholder="$i18n.t('required address', {service: 'Feedbin'})"></el-input>
</div>
<div class="setting-name">The Old Reader <a target="_blank" href="https://theoldreader.com/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.theoldreader">{{ $i18n.t('enable') }}</el-checkbox>
</div>
<div class="setting-name">Feeds.Pub <a target="_blank" href="https://feeds.pub/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.feedspub">{{ $i18n.t('enable') }}</el-checkbox>
</div>
<div class="setting-name">BazQux Reader <a target="_blank" href="https://bazqux.com/"><i class="el-icon-info"></i></a></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.bazqux">{{ $i18n.t('enable') }}</el-checkbox>
</div>
<div class="setting-name">{{ $i18n.t('local reader') }} <el-tooltip class="item" effect="dark" :content="$i18n.t('requires reader support')" placement="top"><i class="el-icon-info"></i></el-tooltip></div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.submitto.local">{{ $i18n.t('enable') }}</el-checkbox>
</div>
</div>
<div class="subtitle">{{ $i18n.t('notifications and reminders') }}</div>
<div class="setting-item">
<div class="setting-name">{{ $i18n.t('show corner badge') }}</div>
<div class="setting-input">
<el-checkbox @change="saveConfig" v-model="config.notice.badge">{{ $i18n.t('enable') }}</el-checkbox>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { getRulesDate, refreshRules } from '../../common/rules';
import { defaultConfig, getConfig, saveConfig } from '../../common/config';
import { secondToTime } from '../../common/utils';
export default {
name: 'Setting',
data: () => ({
loading: true,
defaultConfig,
config: defaultConfig,
time: '',
leftTime: '',
second: 0,
refreshDisabled: false,
isChrome: navigator.userAgent.indexOf('Chrome') !== -1,
}),
computed: {
percentage: function () {
return (this.second / this.config.refreshTimeout * 100).toFixed(2);
},
},
created() {
getConfig((config) => {
this.config = config;
this.loading = false;
this.refreshTime();
});
},
methods: {
saveConfig() {
saveConfig(this.config, () => {
this.$message({
message: this.$i18n.t('successfully saved'),
type: 'success'
});
});
},
toHotkey() {
chrome.tabs.create({
url: 'chrome://extensions/shortcuts'
});
},
refreshRu() {
this.refreshDisabled = true;
refreshRules(() => {
this.second = 0;
this.time = secondToTime(this.second);
this.leftTime = secondToTime(this.config.refreshTimeout - this.second);
this.refreshDisabled = false;
});
},
refreshTime() {
getRulesDate((date) => {
this.second = (+new Date - +date) / 1000;
this.time = secondToTime(this.second);
this.leftTime = secondToTime(this.config.refreshTimeout - this.second);
setTimeout(() => {
this.refreshTime();
}, 1000);
});
}
}
}
</script>
<style lang="less" scoped>
.setting {
width: 100%;
max-width: 800px;
margin: 0 auto;
padding: 40px 10px;
}
.title {
font-size: 25px;
font-weight: bold;
border-bottom: 1px solid #e6e6e6;
padding-bottom: 10px;
color: #f5712c;
}
.content {
margin-top: 20px;
margin-bottom: 30px;
color: #222;
}
.subtitle {
font-size: 20px;
font-weight: bold;
margin: 30px 0 15px;
}
.setting-name {
font-size: 15px;
margin: 15px 0 5px;
}
.setting-input {
height: 40px;
display: flex;
align-items: center;
}
.el-button:focus {
color: #606266;
background: #fff;
border: 1px solid #dcdfe6;
}
.el-button:hover {
color: #f5712c;
border-color: #fcd4c0;
background-color: #fef1ea;
}
.el-icon-info {
color: #777;
margin-left: 2px;
}
.el-progress {
width: 170px;
margin: 0 20px;
}
.time {
color: #606266;
font-size: 14px;
}
</style>
-145
View File
@@ -1,145 +0,0 @@
import '../../css/popup.less';
import ClipboardJS from 'clipboard';
import { getConfig } from '../common/config';
import i18n from '../common/i18n';
import settingIcon from '../../svg/setting.svg';
import aboutIcon from '../../svg/about.svg';
import MD5 from 'md5.js';
let config;
let favicon;
let title;
function generateList(type, list) {
let result = '';
if (list && list.length) {
list.forEach((item) => {
const replaced_url = item.url.replace('{rsshubDomain}', config.rsshubDomain);
const url = encodeURI(
type !== 'page-rsshub' || !config.rsshubAccessControl.enabled
? replaced_url
: config.rsshubAccessControl.useCode
? `${replaced_url}?code=${new MD5().update(item.path + config.rsshubAccessControl.accessKey).digest('hex')}`
: `${replaced_url}?key=${config.rsshubAccessControl.accessKey}`
);
result += `
<li class="rss-item">
<img class="rss-image" src="${item.image || './rsshub.png'}">
<a href="${url}" class="rss-info">
<div class="rss-title">${item.title}</div>
<div class="rss-url">${url.replace('https://', '').replace('http://', '')}</div>
</a>
${
item.isDocs
? `<a href="${url}" class="rss-action">${i18n.t('documentation')}</a>`
: `<div class="rss-action rss-copy" data-clipboard-text="${url}">${i18n.t('copy')}</div>
${
config.submitto.checkchan && config.submitto.checkchanBase
? `<a href="${config.submitto.checkchanBase.replace(/\/$/, '')}/index.html#/check/add?title=${encodeURI(title)}&url=${encodeURI(url)}&type=rss&icon=${encodeURI(
favicon
)}" class="rss-action rss-submitto-checkchan">${i18n.t('subscribe to')} CheckChan</a>`
: ''
}
${
config.submitto.ttrss && config.submitto.ttrssDomain
? `<a href="${config.submitto.ttrssDomain.replace(/\/$/, '')}/public.php?op=bookmarklets--subscribe&feed_url=${encodeURI(url)}" class="rss-action rss-submitto-ttrss">${i18n.t('subscribe to')} TTRSS</a>`
: ''
}
${
config.submitto.miniflux && config.submitto.minifluxDomain
? `<a href="${config.submitto.minifluxDomain.replace(/\/$/, '')}/bookmarklet?uri=${encodeURI(url)}" class="rss-action rss-submitto-miniflux">${i18n.t('subscribe to')} Miniflux</a>`
: ''
}
${
config.submitto.freshrss && config.submitto.freshrssDomain
? `<a href="${config.submitto.freshrssDomain.replace(/\/$/, '')}/i/?c=feed&a=add&url_rss=${encodeURI(url)}" class="rss-action rss-submitto-freshrss">${i18n.t('subscribe to')} FreshRSS</a>`
: ''
}
${
config.submitto.nextcloudnews && config.submitto.nextcloudnewsDomain
? `<a href="${config.submitto.nextcloudnewsDomain.replace(/\/$/, '')}/?subscribe_to=${encodeURI(url)}" class="rss-action rss-submitto-nextcloudnews">${i18n.t('subscribe to')} Nextcloud News</a>`
: ''
}
${config.submitto.feedly ? `<a href="https://feedly.com/i/subscription/feed/${encodeURI(url)}" class="rss-action rss-submitto-feedly">${i18n.t('subscribe to')} Feedly</a>` : ''}
${
config.submitto.inoreader && config.submitto.inoreaderDomain
? `<a href="${config.submitto.inoreaderDomain.replace(/\/$/, '')}/?add_feed=${encodeURI(url)}" class="rss-action rss-submitto-inoreader">${i18n.t('subscribe to')} Inoreader</a>`
: ''
}
${
config.submitto.feedbin && config.submitto.feedbinDomain
? `<a href="${config.submitto.feedbinDomain.replace(/\/$/, '')}/?subscribe=${encodeURI(url)}" class="rss-action rss-submitto-feedbin">${i18n.t('subscribe to')} Feedbin</a>`
: ''
}
${config.submitto.theoldreader ? `<a href="https://theoldreader.com/feeds/subscribe?url=${encodeURI(url)}" class="rss-action rss-submitto-theoldreader">${i18n.t('subscribe to')} The Old Reader</a>` : ''}
${config.submitto.feedspub ? `<a href="https://feeds.pub/feed/${encodeURIComponent(url)}" class="rss-action rss-submitto-feedspub">${i18n.t('subscribe to')} Feeds.Pub</a>` : ''}
${config.submitto.bazqux ? `<a href="https://bazqux.com/add?url=${encodeURIComponent(url)}" class="rss-action rss-submitto-bazqux">${i18n.t('subscribe to')} BazQux Reader</a>` : ''}
${config.submitto.local ? `<a href="feed://${url}" class="rss-action rss-submitto-local">${i18n.t('subscribe to local reader')}</a>` : ''}`
}
</li>
`;
});
document.querySelector(`.${type} ul`).innerHTML = result;
document.querySelector(`.${type}`).style.display = 'block';
document.body.classList.add('something');
}
}
document.querySelector('.icons-setting').innerHTML = settingIcon;
document.querySelector('.icons-about').innerHTML = aboutIcon;
const translatableNodes = document.querySelectorAll('[data-i18n]');
[...translatableNodes].forEach((element) => {
element.innerHTML = i18n.t(element.innerHTML);
});
chrome.tabs.query(
{
active: true,
currentWindow: true,
},
(tabs) => {
const tabId = tabs[0].id;
title = tabs[0].title || '';
favicon = tabs[0].favIconUrl || '/favicon.ico';
getConfig((conf) => {
config = conf;
chrome.runtime.sendMessage(
null,
{
text: 'getAllRSS',
tabId: tabId,
},
(feeds) => {
generateList('page-rss', feeds.pageRSS);
generateList('page-rsshub', feeds.pageRSSHub);
generateList('website-rsshub', feeds.websiteRSSHub);
const clipboard = new ClipboardJS('.rss-copy');
clipboard.on('success', function (e) {
e.trigger.innerHTML = i18n.t('copied');
setTimeout(() => {
e.trigger.innerHTML = i18n.t('copy');
}, 1000);
});
document.querySelectorAll('.rss-image').forEach((ele) => {
ele.addEventListener('error', function () {
this.setAttribute('src', './rsshub.png');
});
});
document.querySelectorAll('a').forEach((ele) => {
ele.addEventListener('click', (e) => {
e.preventDefault();
chrome.tabs.create({
url: ele.getAttribute('href'),
});
window.close();
});
});
}
);
});
}
);
-38
View File
@@ -1,38 +0,0 @@
import { getPageRSSHub, getWebsiteRSSHub, getList } from './utils';
window.getPageRSSHub = getPageRSSHub;
window.getWebsiteRSSHub = getWebsiteRSSHub;
window.getList = getList;
window.addEventListener('message', function (event) {
const command = event.data.command;
switch (command) {
case 'getPageRSSHub':
event.source.postMessage(
{
origin: event.data,
result: getPageRSSHub(event.data.data),
},
event.origin
);
break;
case 'getWebsiteRSSHub':
event.source.postMessage(
{
origin: event.data,
result: getWebsiteRSSHub(event.data.data),
},
event.origin
);
break;
case 'getList':
event.source.postMessage(
{
origin: event.data,
result: getList(event.data.data),
},
event.origin
);
break;
}
});
-244
View File
@@ -1,244 +0,0 @@
import psl from 'psl';
import RouteRecognizer from 'route-recognizer';
import _ from 'lodash';
import { defaultRules } from '../common/radar-rules';
import { defaultConfig } from '../common/config';
function ruleHandler(rule, params, url, html, success, fail) {
const run = () => {
let resultWithParams;
if (typeof rule.target === 'function') {
const parser = new DOMParser();
const document = parser.parseFromString(html, 'text/html');
try {
resultWithParams = rule.target(params, url, document);
} catch (error) {
console.warn(error);
resultWithParams = '';
}
} else if (typeof rule.target === 'string') {
resultWithParams = rule.target;
}
if (resultWithParams) {
// if no :param in resultWithParams, requiredParams will be null
// in that case, just skip the following steps and return resultWithParams
const requiredParams = resultWithParams.match(/\/:\w+\??(?=\/|$)/g)?.map((param) => ({
name: param.slice(2).replace(/\?$/, ''),
optional: param.endsWith('?'),
}));
if (!requiredParams) {
return resultWithParams;
}
for (const param of requiredParams) {
if (params[param.name]) {
// successfully matched
const regex = new RegExp(`/:${param.name}\\??(?=/|$)`);
resultWithParams = resultWithParams.replace(regex, `/${params[param.name]}`);
} else if (param.optional) {
// missing optional parameter, drop all following parameters, otherwise the route will be invalid
const regex = new RegExp(`/:${param.name}\\?(/.*)?$`);
resultWithParams = resultWithParams.replace(regex, '');
break;
} else {
// missing necessary parameter, fail
resultWithParams = '';
break;
}
}
// bypassing double-check since `:` maybe a part of parameter value
// if (resultWithParams && resultWithParams.includes(':')) {
// // double-check
// resultWithParams = '';
// }
}
return resultWithParams;
};
const resultWithParams = run();
if (resultWithParams && (!rule.verification || rule.verification(params))) {
success(resultWithParams);
} else {
fail();
}
}
function formatBlank(str1, str2) {
if (str1 && str2) {
return str1 + (str1[str1.length - 1].match(/[a-zA-Z0-9]/) || str2[0].match(/[a-zA-Z0-9]/) ? ' ' : '') + str2;
} else {
return (str1 || '') + (str2 || '');
}
}
function parseRules(rules) {
let incomeRules = rules;
if (typeof rules === 'string') {
if (defaultConfig.enableFullRemoteRules) {
incomeRules = window['lave'.split('').reverse().join('')](rules);
} else {
incomeRules = JSON.parse(rules);
}
}
return _.mergeWith(defaultRules, incomeRules, (objValue, srcValue) => {
if (_.isFunction(srcValue)) {
return srcValue;
} else if (_.isFunction(objValue)) {
return objValue;
}
});
}
export function getPageRSSHub(data) {
const { url, html } = data;
const rules = parseRules(data.rules);
let parsedDomain;
try {
parsedDomain = psl.parse(new URL(url).hostname);
} catch (error) {
return [];
}
if (parsedDomain && parsedDomain.domain) {
const subdomain = parsedDomain.subdomain;
const domain = parsedDomain.domain;
if (rules[domain]) {
let rule = rules[domain][subdomain || '.'];
if (!rule) {
if (subdomain === 'www') {
rule = rules[domain]['.'];
} else if (!subdomain) {
rule = rules[domain].www;
}
}
if (rule) {
const recognized = [];
rule.forEach((ru, index) => {
const oriSources = Object.prototype.toString.call(ru.source) === '[object Array]' ? ru.source : typeof ru.source === 'string' ? [ru.source] : [];
let sources = [];
// route-recognizer do not support optional segments or partial matching
// thus, we need to manually handle it
// allowing partial matching is necessary, since many rule authors did not mark optional segments
oriSources.forEach((source) => {
// trimming `?` is necessary, since route-recognizer considers it as a part of segment
source = source.replace(/(\/:\w+)\?(?=\/|$)/g, '$1');
sources.push(source);
let tailMatch;
do {
tailMatch = source.match(/\/:\w+$/);
if (tailMatch) {
const tail = tailMatch[0];
source = source.slice(0, source.length - tail.length);
sources.push(source);
}
} while (tailMatch);
});
// deduplicate (some rule authors may already have done similar job)
sources = sources.filter((item, index) => sources.indexOf(item) === index);
// match!
sources.forEach((source) => {
const router = new RouteRecognizer();
router.add([
{
path: source,
handler: index,
},
]);
const result = router.recognize(new URL(url).pathname.replace(/\/$/, ''));
if (result && result[0]) {
recognized.push(result[0]);
}
});
});
const result = [];
Promise.all(
recognized.map(
(recog) =>
new Promise((resolve) => {
ruleHandler(
rule[recog.handler],
recog.params,
url,
html,
(parsed) => {
if (parsed) {
result.push({
title: formatBlank(rules[domain]._name ? '当前' : '', rule[recog.handler].title),
url: '{rsshubDomain}' + parsed,
path: parsed,
});
} else {
result.push({
title: formatBlank(rules[domain]._name ? '当前' : '', rule[recog.handler].title),
url: rule[recog.handler].docs,
isDocs: true,
});
}
resolve();
},
() => {
resolve();
}
);
})
)
);
return result;
} else {
return [];
}
} else {
return [];
}
} else {
return [];
}
}
export function getWebsiteRSSHub(data) {
const { url } = data;
const rules = parseRules(data.rules);
let parsedDomain;
try {
parsedDomain = psl.parse(new URL(url).hostname);
} catch (error) {
return [];
}
if (parsedDomain && parsedDomain.domain) {
const domain = parsedDomain.domain;
if (rules[domain]) {
const domainRules = [];
for (const subdomainRules in rules[domain]) {
if (subdomainRules[0] !== '_') {
domainRules.push(...rules[domain][subdomainRules]);
}
}
return domainRules.map((rule) => ({
title: formatBlank(rules[domain]._name, rule.title),
url: rule.docs,
isDocs: true,
}));
} else {
return [];
}
} else {
return [];
}
}
export function getList(data) {
const rules = parseRules(data.rules);
for (const rule in rules) {
for (const subrule in rules[rule]) {
if (subrule[0] !== '_') {
rules[rule][subrule].forEach((item) => {
delete item.source;
delete item.target;
delete item.script;
delete item.verification;
delete item.test;
});
}
}
}
return rules;
}
+25
View File
@@ -0,0 +1,25 @@
import { useState } from "react"
import "./style.css"
function IndexNewtab() {
const [data, setData] = useState("")
return (
<div
className="new-tab"
style={{
padding: 16,
display: "flex",
flexDirection: "column"
}}>
<h1>
Welcome to your <a href="https://www.plasmo.com">Plasmo</a> Extension!
</h1>
<input onChange={(e) => setData(e.target.value)} value={data} />
<footer>Crafted by @PlamoHQ</footer>
</div>
)
}
export default IndexNewtab
+22
View File
@@ -0,0 +1,22 @@
import { useState } from "react"
function IndexOptions() {
const [data, setData] = useState("")
return (
<div
style={{
display: "flex",
flexDirection: "column",
padding: 16
}}>
<h1>
Welcome to your <a href="https://www.plasmo.com">Plasmo</a> Extension!
</h1>
<input onChange={(e) => setData(e.target.value)} value={data} />
<footer>Crafted by @PlamoHQ</footer>{" "}
</div>
)
}
export default IndexOptions
+33
View File
@@ -0,0 +1,33 @@
import { useState } from "react"
import "./style.css"
function IndexPopup() {
const [data, setData] = useState("")
return (
<div className="min-w-[350px]">
<div className="icons">
<a className="icons-item icons-about" href="/options.html#/about"></a>
<a className="icons-item icons-setting" href="/options.html#/setting"></a>
</div>
<div className="no-rss">
<h2>( ´)(._.`) <span data-i18n>rss not found</span></h2>
<p data-i18n>join rsshub</p>
</div>
<div className="page-rss">
<h2 data-i18n>current page rss</h2>
<ul></ul>
</div>
<div className="page-rsshub">
<h2 data-i18n>current page RSSHub</h2>
<ul></ul>
</div>
<div className="website-rsshub">
<h2 data-i18n>current site RSSHub</h2>
<ul></ul>
</div>
</div>
)
}
export default IndexPopup
+3
View File
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
-1
View File
@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1564303021552" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3669" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512.23 960.22c-247.43 0-448-200.57-448-448s200.58-448 448-448 448 200.58 448 448-200.57 448-448 448z m-56-503.83v279.67a56 56 0 1 0 112 0V456.39a56 56 0 1 0-112 0z m0-168.17a56 56 0 1 0 56-56 55.88 55.88 0 0 0-56 56z m0 0" fill="" p-id="3670"></path></svg>

Before

Width:  |  Height:  |  Size: 634 B

-1
View File
@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1564226990819" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1117" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M962.496 448.96c-3.584-19.84-22.656-39.808-42.304-44.288l-14.72-3.392c-34.624-10.432-65.536-33.536-84.992-67.328-19.648-33.984-24.128-72.576-15.616-107.968 0 0 0 0 0 0l4.288-13.824c5.952-19.264-1.792-45.76-17.216-58.816 0 0-13.824-11.712-52.992-34.304-39.168-22.592-56.128-28.736-56.128-28.736-19.008-6.848-45.76-0.32-59.52 14.464L612.928 115.84C586.56 140.672 551.104 155.904 512 155.904c-39.232 0-74.88-15.36-101.248-40.384L400.832 104.832C387.136 90.048 360.32 83.52 341.312 90.368c0 0-17.024 6.144-56.256 28.736C245.952 141.696 232.128 153.344 232.128 153.344 216.768 166.4 209.024 192.832 214.976 212.16l4.288 14.016c8.448 35.328 3.904 73.856-15.68 107.776C184 367.872 152.896 391.04 118.08 401.408L103.808 404.672c-19.648 4.48-38.72 24.448-42.304 44.288 0 0-3.2 17.792-3.2 63.04 0 45.248 3.2 62.976 3.2 62.976 3.584 19.84 22.656 39.808 42.304 44.288l13.952 3.2c0 0 0 0 0 0 34.944 10.304 66.112 33.536 85.824 67.584 19.648 33.984 24.128 72.576 15.616 107.968 0 0 0 0 0 0l-4.224 13.76c-5.952 19.264 1.792 45.76 17.216 58.816 0 0 13.824 11.712 52.992 34.304 39.168 22.592 56.128 28.736 56.128 28.736 19.008 6.848 45.76 0.32 59.52-14.464l9.792-10.56c26.432-25.024 62.08-40.448 101.376-40.448 39.296 0 75.008 15.424 101.44 40.512 0 0 0 0 0.064 0l9.728 10.496c13.76 14.784 40.512 21.312 59.52 14.464 0 0 17.024-6.144 56.256-28.736 39.168-22.592 52.928-34.304 52.928-34.304 15.424-13.056 23.168-39.488 17.216-58.816l-4.352-14.208c-8.32-35.264-3.84-73.664 15.744-107.52 19.648-34.048 50.88-57.216 85.824-67.584 0 0 0-0.064 0-0.064l13.952-3.2c19.648-4.48 38.72-24.448 42.304-44.288 0 0 3.2-17.792 3.2-63.04C965.696 466.752 962.496 448.96 962.496 448.96zM512 692.928c-99.904 0-180.928-81.024-180.928-180.928S412.096 331.136 512 331.136s180.928 81.024 180.928 180.928S611.904 692.928 512 692.928z" p-id="1118"></path></svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

-52
View File
@@ -1,52 +0,0 @@
{
"access key": "Access key",
"about": "About",
"click to set": "Click to set",
"configuration required if access keys enabled": "Configuration is only required if the instance has access keys enabled, keep it off if you don't know the situation",
"copied": "Copied",
"copy": "Copy",
"current page rss": "RSS on the current site",
"current page RSSHub": "RSSHub for the current page",
"custom rsshub domain": "Custom RSSHub domain name",
"current site RSSHub": "RSSHub for the current site",
"documentation": "Info",
"enable": "Enable",
"i will update automatically and you can": "I will update automatically, and you can",
"updating": "Updating",
"update now": "Update Now",
"before update": "before update",
"after automatic update": "after automatic update",
"full remote updates are disabled due to browser limitations": "Full remote updates are disabled due to browser limitations",
"enter rsshub domain": "Please enter your RSSHub domain name, leave it blank to use the official domain name",
"for more rules join us": "For more rules support, <a target=\"_blank\" href=\"https://docs.rsshub.app/en/joinus/quick-start.html\">join us</a>",
"general": "General",
"generate access code": "Generate access code",
"hot key": "Hot key",
"join rsshub": "Participate in the <a href=\"https://docs.rsshub.app/en/\"> to make everything RSS-able!",
"list of rules": "List of rules",
"local reader": "Local reader",
"one-click subscription": "One-click subscription",
"notifications and reminders": "Notifications and reminders",
"required access key": "Required, please enter the correct access key",
"required address": "Required. Please enter you %{service} address",
"required extension base URI": "Required. Please enter the %{service} extension URL after installation",
"requires reader support": "Requires reader support, such as Reeder, etc.",
"rss not found": "No RSS found",
"rsshub radar options": "RSSHub Radar Options",
"rules": "Rules",
"rules update": "Rules update",
"settings": "Settings",
"show corner badge": "Show corner badge",
"subscribe to": "Subscribe to",
"subscribe to local reader": "Subscribe to local reader",
"successfully saved": "Successfully saved",
"updated time ago": "%{hours}h %{minutes}m since last update",
"version": "Version",
"rsshub radar info": "RSSHub Radar is a spin-off of <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">RSSHub</a> that helps you quickly discover and subscribe to RSS and RSSHub for your current site, and the project is <a target=\"_blank\" href=\"https://github.com/DIYgod/RSSHub-Radar\">open source</a> under the MIT license and is completely free to use, but as the project grows in size, it also needs to be funded to sustain its maintenance and development",
"sponsored development": "Sponsored development of RSSHub Radar: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/support/\">https://docs.rsshub.app/en/support/</a>",
"update log": "Update log",
"question feedback": "Question Feedback",
"rsshub documentation": "RSSHub Documentation: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">https://docs.rsshub.app/en/</a>",
"everything is possible with rss": "Everything is possible with RSS"
}
-47
View File
@@ -1,47 +0,0 @@
{
"about": "Acerca de",
"access key": "Clave de acceso",
"click to set": "Hacer click para establecer",
"configuration required if access keys enabled": "La configuración solo es necesaria si las claves de acceso están habilitada. Mantenlo desactivado en caso de duda",
"copied": "Copiado",
"copy": "Copiar",
"current page rss": "RSS en esta página",
"current page RSSHub": "RSSHub para página actual",
"custom rsshub domain": "Dominio RSSHub personalizado",
"current site RSSHub": "RSSHub para website actual",
"documentation": "Info",
"enable": "Activar",
"full remote updates are disabled due to browser limitations": "Las actualizaciones remotas están desactivadas debido a las limitaciones del navegador",
"enter rsshub domain": "Introduce to dominio de RSSHub, deja el espacio en blanco para utilizar el dominio oficial",
"for more rules join us": "Para más reglas <a target=\"_blank\" href=\"https://docs.rsshub.app/en/joinus/quick-start.html\">únete</a>",
"general": "General",
"generate access code": "Generar código de acceso",
"hot key": "Hot key",
"join rsshub": "Únete a <a href=\"https://docs.rsshub.app/en/\">RSSHub</a> para hacer todo accesible mediante RSS!",
"list of rules": "Lista de reglas",
"local reader": "Lector local",
"notifications and reminders": "Notificaciones y avisos",
"one-click subscription": "Subscripción mediante un click",
"required access key": "Obligatorio, por favor introduct la clave de acceso correcta",
"required address": "Obligatorio. Por favor introduce tu dirección %{service}",
"required extension base URI": "Obligatorio. Ingrese la URL de la extensión %{service} después de la instalación",
"requires reader support": "Necesita tener un visor como Reeder o algo del estilo instalado ",
"rss not found": "No se han encontrado RSS's",
"rsshub radar options": "RSSHub Radar Configuración",
"rules": "Reglas",
"rules update": "Actualización de reglas",
"settings": "Opciones",
"show corner badge": "Mostrar insignia",
"subscribe to": "Subscribirse a",
"subscribe to local reader": "Subscribirse en lector local",
"successfully saved": "Guardado",
"updated time ago": "%{hours}h %{minutes}m desde la última actualización",
"version": "Versión",
"rsshub radar info": "RSSHub Radar es un proyecto derivado de <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">RSSHub</a> que permite subscribrirse rápidamente al RSS y/o RSSHub del website actual. Es un proyecto <a target=\"_blank\" href=\"https://github.com/DIYgod/RSSHub-Radar\">open source</a> bajo licencia MIT y su uso es completamete libre y gratuito, pero a medida que el proyecto crece también necesita ser patrocinado para mantener su soporte y desarrollo",
"sponsored development": "Soporta el desarrollo de RSSHub Radar: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/support/\">https://docs.rsshub.app/en/support/</a>",
"update log": "Registro de cambios",
"question feedback": "Feedback e incidencias",
"rsshub documentation": "Documentación de RSSHub: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">https://docs.rsshub.app/en/</a>",
"everything is possible with rss": "Todo es posible con RSS"
}
-47
View File
@@ -1,47 +0,0 @@
{
"about": "Honi buruz",
"access key": "Sarrera-gakoa",
"click to set": "Ezartzeko klik egin",
"configuration required if access keys enabled": "Konfigurazioa sarrera-gakoak gaituta daudenean da derrigorrezkoa, ez gaitu ez baduzu egoera ezagutzen",
"copied": "Kopiatuta",
"copy": "Kopiatu",
"current page rss": "Orrialde honetako RSSak",
"current page RSSHub": "Orrialde honetarako RSSHub-ak",
"custom rsshub domain": "RSSHub domeinu pertsonalizatua",
"current site RSSHub": "Gune honetarako RSSHub-ak",
"documentation": "Info",
"enable": "Gaitu",
"full remote updates are disabled due to browser limitations": "Urruneko eguneraketak desgaituta daude arakatzailearen mugak direla eta",
"enter rsshub domain": "Mesedez sartu zure RSSHub domeinua, domeinu ofiziala erabiltzeko utzi zuriz",
"for more rules join us": "Arau gehiago jasatzeko <a target=\"_blank\" href=\"https://docs.rsshub.app/en/joinus/quick-start.html\">batu zaitez</a>!",
"general": "Orokorra",
"generate access code": "Sarrera kodea sortu",
"hot key": "Hot key",
"join rsshub": "Gehitu zure burua <a href=\"https://docs.rsshub.app/en/\">RSSHub</a>-era dena RSS bitartez jaso ahal izateko!",
"list of rules": "Arau-zerrenda",
"local reader": "Bertako irakurgailua",
"one-click subscription": "Klik bakarreko harpidetza",
"notifications and reminders": "Jakinarazpenak",
"required access key": "Nahitaezkoa, mesedez sartu sarrera-gako zuzena",
"required address": "Nahitaezkoa. Mesedez sartu zure %{service} helbidea",
"required extension base URI": "Nahitaezkoa. Sartu %{service} luzapenaren URLa instalatu ondoren",
"requires reader support": "Reeder edo horrelakoren baten moduko irakurgailua behar du",
"rss not found": "Ez da RSSrik aurkitu",
"rsshub radar options": "RSSHub Radar Aukerak",
"rules": "Arauak",
"rules update": "Arauen eguneraketa",
"settings": "Aukerak",
"show corner badge": "Izkinako marka erakutsi",
"subscribe to": "Harpidetu: ",
"subscribe to local reader": "Harpidetu irakurgailu lokalean",
"successfully saved": "Gordeta",
"updated time ago": "%{hours}o %{minutes}m azken eguneraketatik",
"version": "Bertsioa",
"rsshub radar info": "RSSHub Radar momentuko webgunearen RSS eta RSSHub-era modu azkar eta erraz batean harpidetzera laguntzen duen <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">RSSHub</a>-en proiektu eratorria da. Guztiz erabilera librea du eta MIT lizentziapean dagoen <a target=\"_blank\" href=\"https://github.com/DIYgod/RSSHub-Radar\">kode irekiko</a> proiektua da, baina handitzen doan heinean bere mantentze eta garapenari eusteko finantzazio beharra dauka.",
"sponsored development": "RSSHub Radar laguntzeko: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/support/\">https://docs.rsshub.app/en/support/</a>",
"update log": "Eguneraketa-egunkaria",
"question feedback": "Galdera eta atazak",
"rsshub documentation": "RSSHub dokumentazioa: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">https://docs.rsshub.app/en/</a>",
"everything is possible with rss": "Dena da posible RSS-ekin"
}
-47
View File
@@ -1,47 +0,0 @@
{
"access key": "Chave de acesso",
"about": "Sobre",
"click to set": "Clique para definir",
"configuration required if access keys enabled": "Configuração só é requirida se a instância tiver chaves de acesso habilitadas, mantenha desligado se desconhecer a situação",
"copied": "Copiado",
"copy": "Copiar",
"current page rss": "RSS no site atual",
"current page RSSHub": "RSSHub para a página atual",
"custom rsshub domain": "Nome de domínio personalizado RSSHub",
"current site RSSHub": "RSSHub para o site atual",
"documentation": "Informação",
"enable": "Habilitar",
"full remote updates are disabled due to browser limitations": "As actualizações remotas são desactivadas devido a limitações do navegador",
"enter rsshub domain": "Por favor insira o seu nome de domínio RSSHub, deixe em branco para usar o nome de domínio oficial",
"for more rules join us": "Para suporte a mais regras, <a target=\"_blank\" href=\"https://docs.rsshub.app/en/joinus/quick-start.html\">junte-se a nós</a>",
"general": "Geral",
"generate access code": "Gerar código de acesso",
"hot key": "Tecla de atalho",
"join rsshub": "Participe no <a href=\"https://docs.rsshub.app/en/\"> para tornar tudo em RSS!",
"list of rules": "Lista de regras",
"local reader": "Leitor local",
"one-click subscription": "Sobrescrever com um-clique",
"notifications and reminders": "Notificações e lembretes",
"required access key": "Obrigatório, por favor insira a chave de acesso correta",
"required address": "Obrigatório. Por favor insira o seu endereço de %{service}",
"required extension base URI": "Obrigatório. Insira o URL da extensão %{service} após a instalação",
"requires reader support": "Requer suporte a leitor, tais como Reeder, etc.",
"rss not found": "Nenhuma RSS encontrada",
"rsshub radar options": "Opções RSSHub Radar",
"rules": "Regras",
"rules update": "Atualização das regras",
"settings": "Definições",
"show corner badge": "Mostrar canto do distintivo",
"subscribe to": "Subscrever para",
"subscribe to local reader": "Subscrever para leitor local",
"successfully saved": "Gurdaddo com sucesso",
"updated time ago": "%{hours}h %{minutes}m desde a última atualização",
"version": "Versão",
"rsshub radar info": "RSSHub Radar é um subproduto do <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">RSSHub</a> que o ajuda rapidamente a descobrir e subscrever RSS e RSSHub para o seu site atual, e o projeto é de <a target=\"_blank\" href=\"https://github.com/DIYgod/RSSHub-Radar\">código aberto</a> sob licença do MIT e é completamente gratuito para ser usado, mas á medida que o projeto cresce em tamanho, também precisa de ser financiado para sustentar a sua manutenção e desenvolvimento",
"sponsored development": "Desenvolvimento patrocinado do RSSHub Radar: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/support/\">https://docs.rsshub.app/en/support/</a>",
"update log": "Histórico de atualização",
"question feedback": "Questões e Feedback",
"rsshub documentation": "Documentação RSSHub: <a target=\"_blank\" href=\"https://docs.rsshub.app/en/\">https://docs.rsshub.app/en/</a>",
"everything is possible with rss": "Tudo é possível com RSS"
}
-52
View File
@@ -1,52 +0,0 @@
{
"about": "关于",
"access key": "访问密钥",
"click to set": "点此设置",
"configuration required if access keys enabled": "只有实例启用了访问密钥,才需要配置,如果你不清楚情况,请保持关闭",
"copied": "已复制",
"copy": "复制",
"current page rss": "当前页面上的 RSS",
"current page RSSHub": "适用于当前页面的 RSSHub",
"custom rsshub domain": "自定义 RSSHub 域名",
"current site RSSHub": "适用于当前网站的 RSSHub",
"documentation": "文档",
"enable": "开启",
"i will update automatically and you can": "我会自动更新,你也可以",
"updating": "更新中",
"update now": "立即更新",
"before update": "前更新",
"after automatic update": "后自动更新",
"full remote updates are disabled due to browser limitations": "由于浏览器限制,完整的远程更新被禁用",
"enter rsshub domain": "请输入你的 RSSHub 域名,留空使用官方域名",
"for more rules join us": "更多规则支持中,快来<a target=\"_blank\" href=\"https://docs.rsshub.app/joinus/quick-start.html\">参与我们</a>吧!",
"general": "常规",
"generate access code": "生成访问码",
"hot key": "快捷键",
"join rsshub": "参与到 <a href=\"https://docs.rsshub.app\">RSSHub</a> 让万物皆可 RSS 吧!",
"list of rules": "规则列表",
"local reader": "本地阅读器",
"notifications and reminders": "通知与提醒",
"one-click subscription": "一键订阅",
"required address": "必填,请输入你的 %{service} 地址",
"required extension base URI": "必填,请输入你安装完成后的%{service}插件地址",
"required access key": "必填,请输入正确的访问密钥",
"requires reader support": "需要阅读器支持,如 Reeder 等",
"rss not found": "当前页面没有检测到 RSS",
"rsshub radar options": "RSSHub Radar 选项",
"rules": "规则列表",
"rules update": "规则更新",
"settings": "设置",
"show corner badge": "角标提醒",
"subscribe to": "订阅到",
"subscribe to local reader": "订阅到本地阅读器",
"successfully saved": "保存成功",
"updated time ago": "%{hours}小时 %{minutes}分钟 前更新",
"version": "版本",
"rsshub radar info": "RSSHub Radar 是 <a target=\"_blank\" href=\"https://docs.rsshub.app\">RSSHub</a> 的衍生项目,她可以帮助你快速发现和订阅当前网站的 RSS 和 RSSHub,项目<a target=\"_blank\" href=\"https://github.com/DIYgod/RSSHub-Radar\">采用 MIT 许可开源</a>,使用完全免费,但是随着项目规模的增长,也需要有相应的资金支持才能持续项目的维护与开发",
"sponsored development": "赞助 RSSHub Radar 的开发: <a target=\"_blank\" href=\"https://docs.rsshub.app/support/\">https://docs.rsshub.app/support/</a>",
"update log": "更新日志",
"question feedback": "问题反馈",
"rsshub documentation": "RSSHub 文档: <a target=\"_blank\" href=\"https://docs.rsshub.app\">https://docs.rsshub.app</a>",
"everything is possible with rss": "万物皆可 RSS"
}
+7
View File
@@ -0,0 +1,7 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
mode: "jit",
darkMode: "class",
content: ["./**/*.tsx"],
plugins: []
}
+19
View File
@@ -0,0 +1,19 @@
{
"extends": "plasmo/templates/tsconfig.base",
"exclude": [
"node_modules"
],
"include": [
".plasmo/index.d.ts",
"./**/*.ts",
"./**/*.tsx"
],
"compilerOptions": {
"paths": {
"~*": [
"./src/*"
]
},
"baseUrl": "."
}
}
-210
View File
@@ -1,210 +0,0 @@
const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
mode: 'production',
devtool: false,
performance: {
maxEntrypointSize: 1000000,
},
entry: {
'popup': './src/js/popup/index.js',
'content': './src/js/content/index.js',
'background': './src/js/background/index.js',
'options': './src/js/options/index.js',
'sandbox': './src/js/sandbox/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
publicPath: '/',
},
resolve: {
modules: ['node_modules'],
extensions: ['.js', '.less'],
fallback: {
'stream': require.resolve('stream-browserify'),
'buffer': require.resolve('buffer/'),
'http': require.resolve('stream-http'),
"url": require.resolve("url/"),
"https": require.resolve("https-browserify"),
"timers": require.resolve("timers-browserify"),
"process": require.resolve("process/browser"),
}
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.js$/,
enforce: 'pre',
loader: 'eslint-loader',
include: path.resolve(__dirname, '../src/js'),
},
{
test: /\.js$/,
use: [
'template-string-optimize-loader',
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: ['@babel/preset-env'],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
],
],
}
}
]
},
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
},
}
},
],
},
{
test: /\.less$/,
use: [
'vue-style-loader',
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
},
}
},
'less-loader'
],
},
{
test: /\.scss$/,
use: [
'vue-style-loader',
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('autoprefixer'),
require('cssnano')({
preset: 'default',
}),
],
},
}
},
'sass-loader'
],
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(png|jpg)$/,
loader: 'url-loader',
options: {
'limit': 40000
}
},
{
test: /\.svg$/,
loader: 'svg-inline-loader'
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new CopyPlugin({
patterns: [
{
from: 'src/assets',
to: '',
},
],
}),
new VueLoaderPlugin(),
new webpack.DefinePlugin({
VERSION: JSON.stringify(require('./src/assets/manifest.json').version)
}),
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser',
}),
],
};