mirror of
https://github.com/DIYgod/RSSHub-Radar.git
synced 2026-08-28 17:45:13 +08:00
feat: migrate extension from Plasmo to WXT (#1172)
* feat: migrate extension framework to wxt - Replace Plasmo entrypoints, messaging, and storage usage with WXT-compatible implementations - Update workflows, build scripts, and locale paths for WXT outputs - Switch store submission to wxt submit with optional dry-run input * fix(ci): fallback to vars for submit credentials - Resolve missing required config in submit workflow when values are stored in GitHub Variables instead of Secrets - Keep existing secrets first and add vars fallback for Chrome, Firefox, and Edge credentials
This commit is contained in:
@@ -6,8 +6,9 @@ on:
|
||||
- "*"
|
||||
|
||||
env:
|
||||
PLASMO_PUBLIC_UMAMI_ID: ${{ vars.PLASMO_PUBLIC_UMAMI_ID }}
|
||||
PLASMO_PUBLIC_UMAMI_URL: ${{ vars.PLASMO_PUBLIC_UMAMI_URL }}
|
||||
WXT_UMAMI_ID: ${{ vars.WXT_UMAMI_ID || vars.PLASMO_PUBLIC_UMAMI_ID }}
|
||||
WXT_UMAMI_URL: ${{ vars.WXT_UMAMI_URL || vars.PLASMO_PUBLIC_UMAMI_URL }}
|
||||
WXT_UMAMI_SAMPLE_RATE: ${{ vars.WXT_UMAMI_SAMPLE_RATE || vars.PLASMO_PUBLIC_UMAMI_SAMPLE_RATE }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -32,9 +33,9 @@ jobs:
|
||||
node-version: 22.x
|
||||
cache: "pnpm"
|
||||
- name: Package the extension for Chrome
|
||||
run: pnpm build --zip
|
||||
run: pnpm zip
|
||||
- name: Package the extension for Firefox
|
||||
run: pnpm build:firefox --zip
|
||||
run: pnpm zip:firefox
|
||||
- name: Package the extension for Safari
|
||||
run: pnpm build:safari:zip
|
||||
- name: Upload file
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
name: "Submit to Web Store"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: "Run submission in dry-run mode"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
PLASMO_PUBLIC_UMAMI_ID: ${{ vars.PLASMO_PUBLIC_UMAMI_ID }}
|
||||
PLASMO_PUBLIC_UMAMI_URL: ${{ vars.PLASMO_PUBLIC_UMAMI_URL }}
|
||||
WXT_UMAMI_ID: ${{ vars.WXT_UMAMI_ID || vars.PLASMO_PUBLIC_UMAMI_ID }}
|
||||
WXT_UMAMI_URL: ${{ vars.WXT_UMAMI_URL || vars.PLASMO_PUBLIC_UMAMI_URL }}
|
||||
WXT_UMAMI_SAMPLE_RATE: ${{ vars.WXT_UMAMI_SAMPLE_RATE || vars.PLASMO_PUBLIC_UMAMI_SAMPLE_RATE }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -28,14 +35,30 @@ jobs:
|
||||
node-version: 22.x
|
||||
cache: "pnpm"
|
||||
- name: Package the extension for Chrome
|
||||
run: pnpm build --zip
|
||||
run: pnpm zip
|
||||
- name: Package the extension for Firefox
|
||||
run: pnpm build:firefox --zip
|
||||
- name: Browser Platform Publish
|
||||
uses: PlasmoHQ/bpp@v3
|
||||
with:
|
||||
keys: ${{ secrets.SUBMIT_KEYS }}
|
||||
chrome-file: build/chrome-mv3-prod.zip
|
||||
edge-file: build/chrome-mv3-prod.zip
|
||||
firefox-file: build/firefox-mv3-prod.zip
|
||||
notes: "RSSHub Radar is an open source project, you can find the source code at https://github.com/DIYgod/RSSHub-Radar"
|
||||
run: pnpm zip:firefox
|
||||
- name: Submit to web stores
|
||||
env:
|
||||
CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID || vars.CHROME_EXTENSION_ID }}
|
||||
CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID || vars.CHROME_CLIENT_ID }}
|
||||
CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET || vars.CHROME_CLIENT_SECRET }}
|
||||
CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN || vars.CHROME_REFRESH_TOKEN }}
|
||||
FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID || vars.FIREFOX_EXTENSION_ID }}
|
||||
FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER || vars.FIREFOX_JWT_ISSUER }}
|
||||
FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET || vars.FIREFOX_JWT_SECRET }}
|
||||
EDGE_PRODUCT_ID: ${{ secrets.EDGE_PRODUCT_ID || vars.EDGE_PRODUCT_ID }}
|
||||
EDGE_CLIENT_ID: ${{ secrets.EDGE_CLIENT_ID || vars.EDGE_CLIENT_ID }}
|
||||
EDGE_API_KEY: ${{ secrets.EDGE_API_KEY || vars.EDGE_API_KEY }}
|
||||
run: |
|
||||
DRY_RUN_FLAG=""
|
||||
if [ "${{ inputs.dry_run }}" = "true" ]; then
|
||||
DRY_RUN_FLAG="--dry-run"
|
||||
fi
|
||||
|
||||
pnpm wxt submit \
|
||||
--chrome-zip .output/*-chrome.zip \
|
||||
--firefox-zip .output/*-firefox.zip \
|
||||
--firefox-sources-zip .output/*-sources.zip \
|
||||
--edge-zip .output/*-chrome.zip \
|
||||
${DRY_RUN_FLAG}
|
||||
|
||||
@@ -4,8 +4,9 @@ on:
|
||||
push:
|
||||
|
||||
env:
|
||||
PLASMO_PUBLIC_UMAMI_ID: ${{ vars.PLASMO_PUBLIC_UMAMI_ID }}
|
||||
PLASMO_PUBLIC_UMAMI_URL: ${{ vars.PLASMO_PUBLIC_UMAMI_URL }}
|
||||
WXT_UMAMI_ID: ${{ vars.WXT_UMAMI_ID || vars.PLASMO_PUBLIC_UMAMI_ID }}
|
||||
WXT_UMAMI_URL: ${{ vars.WXT_UMAMI_URL || vars.PLASMO_PUBLIC_UMAMI_URL }}
|
||||
WXT_UMAMI_SAMPLE_RATE: ${{ vars.WXT_UMAMI_SAMPLE_RATE || vars.PLASMO_PUBLIC_UMAMI_SAMPLE_RATE }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -30,9 +31,9 @@ jobs:
|
||||
node-version: 22.x
|
||||
cache: "pnpm"
|
||||
- name: Package the extension for Chrome
|
||||
run: pnpm build --zip
|
||||
run: pnpm zip
|
||||
- name: Package the extension for Firefox
|
||||
run: pnpm build:firefox --zip
|
||||
run: pnpm zip:firefox
|
||||
- name: Package the extension for Safari
|
||||
run: pnpm build:safari:zip
|
||||
- name: Archive production artifacts
|
||||
|
||||
@@ -15,8 +15,6 @@ export default {
|
||||
"<BUILTIN_MODULES>", // Node.js built-in modules
|
||||
"<THIRD_PARTY_MODULES>", // Imports not matched by other special words or groups.
|
||||
"", // Empty line
|
||||
"^@plasmo/(.*)$",
|
||||
"",
|
||||
"^@plasmohq/(.*)$",
|
||||
"",
|
||||
"^~(.*)$",
|
||||
|
||||
@@ -67,7 +67,7 @@ Open the upper right corner `Developer mode`
|
||||
|
||||
Click `Load unpacked extension` in the upper left corner
|
||||
|
||||
Select the unzipped `dist` directory
|
||||
Select the unzipped extension directory containing `manifest.json`
|
||||
|
||||
**Firefox install extension:**
|
||||
|
||||
@@ -75,13 +75,13 @@ Open `about:debugging`
|
||||
|
||||
Click `Load Temporary Extension` in the upper right corner
|
||||
|
||||
Select the `manifest.json` file in the unzipped `dist` directory
|
||||
Select the `manifest.json` file in the unzipped extension directory
|
||||
|
||||
## Join us
|
||||
|
||||
### Start the Development Server
|
||||
|
||||
Also refer to: https://docs.plasmo.com/framework/workflows/dev
|
||||
Also refer to: https://wxt.dev/guide/installation
|
||||
|
||||
```
|
||||
pnpm i
|
||||
@@ -95,7 +95,7 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Get the `build/chrome-mv3-dev` directory, the installation method refers to [manual installation](#manual installation)
|
||||
Get the `.output/chrome-mv3` directory, the installation method refers to [manual installation](#manual installation)
|
||||
|
||||
### Submit New RSSHub Radar Rules
|
||||
|
||||
|
||||
+18
-31
@@ -6,21 +6,22 @@
|
||||
"author": "DIYgod",
|
||||
"packageManager": "pnpm@9.12.3",
|
||||
"scripts": {
|
||||
"dev": "plasmo dev --no-cs-reload",
|
||||
"build": "plasmo build",
|
||||
"dev:firefox": "plasmo dev --target=firefox-mv3 --no-cs-reload",
|
||||
"build:firefox": "plasmo build --target=firefox-mv3",
|
||||
"build:safari": "plasmo build --target=safari-mv3",
|
||||
"safari-convert": "xcrun safari-web-extension-converter build/safari-mv3-prod --project-location build --bundle-identifier app.rsshub.RSSHub-Radar --force",
|
||||
"dev": "wxt",
|
||||
"build": "wxt build",
|
||||
"dev:firefox": "wxt -b firefox --mv3",
|
||||
"build:firefox": "wxt build -b firefox --mv3",
|
||||
"build:safari": "wxt build -b safari --mv3",
|
||||
"zip": "wxt zip && mkdir -p build && cp .output/rsshub-radar-*-chrome.zip build/chrome-mv3-prod.zip",
|
||||
"zip:firefox": "wxt zip -b firefox --mv3 && mkdir -p build && cp .output/rsshub-radar-*-firefox.zip build/firefox-mv3-prod.zip",
|
||||
"safari-convert": "xcrun safari-web-extension-converter .output/safari-mv3 --project-location build --bundle-identifier app.rsshub.RSSHub-Radar --force",
|
||||
"safari-zip": "zip -r build/safari-mv3-prod.zip \"build/RSSHub Radar\"",
|
||||
"build:safari:zip": "npm run build:safari && npm run safari-convert && npm run safari-zip",
|
||||
"package": "plasmo package",
|
||||
"prepare": "husky install"
|
||||
"build:safari:zip": "pnpm build:safari && pnpm safari-convert && pnpm safari-zip",
|
||||
"package": "pnpm zip && pnpm zip:firefox",
|
||||
"prepare": "husky install",
|
||||
"postinstall": "wxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/mingcute": "^1.2.3",
|
||||
"@plasmohq/messaging": "^0.6.2",
|
||||
"@plasmohq/storage": "^1.13.0",
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
"@radix-ui/react-dialog": "1.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
@@ -34,7 +35,6 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.475.0",
|
||||
"md5.js": "^1.3.5",
|
||||
"plasmo": "0.89.4",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-hot-toast": "^2.5.1",
|
||||
@@ -54,6 +54,7 @@
|
||||
"@types/node": "22.13.1",
|
||||
"@types/react": "18.3.11",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@wxt-dev/module-react": "^1.1.5",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"husky": "9.1.7",
|
||||
"lint-staged": "15.4.3",
|
||||
@@ -62,29 +63,15 @@
|
||||
"prettier-package-json": "2.8.0",
|
||||
"shadcn-ui": "^0.9.4",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"typescript": "5.7.3"
|
||||
"typescript": "5.7.3",
|
||||
"wxt": "^0.20.14"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": "prettier --write --ignore-unknown"
|
||||
},
|
||||
"manifest": {
|
||||
"default_locale": "en",
|
||||
"host_permissions": [
|
||||
"https://*/*"
|
||||
],
|
||||
"permissions": [
|
||||
"tabs",
|
||||
"offscreen",
|
||||
"storage",
|
||||
"alarms"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"notifications"
|
||||
],
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "i@diygod.me"
|
||||
}
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"publish-browser-extension": "3.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2274
-4101
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -1,3 +1,9 @@
|
||||
import contentReady from "./messages/contentReady"
|
||||
import popupReady from "./messages/popupReady"
|
||||
import refreshRules from "./messages/refreshRules"
|
||||
import requestDisplayedRules from "./messages/requestDisplayedRules"
|
||||
import responseDisplayedRules from "./messages/responseDisplayedRules"
|
||||
import responseRSS from "./messages/responseRSS"
|
||||
import { deleteCachedRSS, getRSS } from "./rss"
|
||||
import { initSchedule } from "./rules"
|
||||
import { initUpdateNotifications } from "./update-notifications"
|
||||
@@ -29,5 +35,37 @@ chrome.tabs.onRemoved.addListener((tabId) => {
|
||||
deleteCachedRSS(tabId)
|
||||
})
|
||||
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
const run = async () => {
|
||||
switch (msg?.name) {
|
||||
case "contentReady":
|
||||
return contentReady(msg, sender)
|
||||
case "popupReady":
|
||||
return popupReady(msg, sender)
|
||||
case "refreshRules":
|
||||
return refreshRules(msg, sender)
|
||||
case "requestDisplayedRules":
|
||||
return requestDisplayedRules(msg, sender)
|
||||
case "responseDisplayedRules":
|
||||
return responseDisplayedRules(msg, sender)
|
||||
case "responseRSS":
|
||||
return responseRSS(msg, sender)
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
||||
.then((res) => {
|
||||
sendResponse(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
sendResponse(undefined)
|
||||
})
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
initSchedule()
|
||||
initUpdateNotifications()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
import { getRSS } from "~/background/rss"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = (req, res) => {
|
||||
getRSS(req.sender.tab.id, req.sender.tab.url)
|
||||
res.send("")
|
||||
const handler = (_message: unknown, sender: chrome.runtime.MessageSender) => {
|
||||
if (sender.tab?.id && sender.tab?.url) {
|
||||
getRSS(sender.tab.id, sender.tab.url)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
import { getCachedRSS } from "~/background/rss"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = (req, res) => {
|
||||
chrome.tabs.query(
|
||||
{
|
||||
active: true,
|
||||
lastFocusedWindow: true,
|
||||
},
|
||||
([tab]) => {
|
||||
res.send(getCachedRSS(tab.id))
|
||||
},
|
||||
)
|
||||
return true
|
||||
const handler = (
|
||||
_message?: unknown,
|
||||
_sender?: chrome.runtime.MessageSender,
|
||||
) => {
|
||||
return new Promise((resolve) => {
|
||||
chrome.tabs.query(
|
||||
{
|
||||
active: true,
|
||||
lastFocusedWindow: true,
|
||||
},
|
||||
([tab]) => {
|
||||
resolve(getCachedRSS(tab.id))
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
import { refreshRules } from "~/background/rules"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = (req, res) => {
|
||||
refreshRules().then(() => {
|
||||
res.send(true)
|
||||
})
|
||||
const handler = async (
|
||||
_message?: unknown,
|
||||
_sender?: chrome.runtime.MessageSender,
|
||||
) => {
|
||||
await refreshRules()
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
import { getDisplayedRules } from "~/background/rules"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = (req, res) => {
|
||||
getDisplayedRules().then((rules) => {
|
||||
res.send(rules)
|
||||
})
|
||||
return true
|
||||
}
|
||||
const handler = async (
|
||||
_message?: unknown,
|
||||
_sender?: chrome.runtime.MessageSender,
|
||||
) => getDisplayedRules()
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
import { setDisplayedRules } from "~/background/rules"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = (req, res) => {
|
||||
setDisplayedRules(req.body.displayedRules)
|
||||
res.send("")
|
||||
const handler = (
|
||||
message: { body?: { displayedRules?: any } },
|
||||
_sender?: chrome.runtime.MessageSender,
|
||||
) => {
|
||||
setDisplayedRules(message?.body?.displayedRules)
|
||||
return ""
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
import { setRSS } from "~/background/rss"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
|
||||
setRSS(req.body.tabId || req.sender.tab.id, req.body.rss)
|
||||
res.send("")
|
||||
const handler = async (
|
||||
message: { body?: { tabId?: number; rss?: any } },
|
||||
sender?: chrome.runtime.MessageSender,
|
||||
) => {
|
||||
const tabId = message?.body?.tabId ?? sender?.tab?.id
|
||||
if (tabId) {
|
||||
setRSS(tabId, message?.body?.rss)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
+16
-21
@@ -1,19 +1,14 @@
|
||||
import AsyncLock from "async-lock"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
|
||||
import { sendToContentScript } from "~/lib/messaging"
|
||||
import { setupOffscreenDocument } from "~/lib/offscreen"
|
||||
import report from "~/lib/report"
|
||||
import { getLocalStorage } from "~/lib/storage"
|
||||
import type { RSSData } from "~/lib/types"
|
||||
import { getRSSHub as sandboxGetRSSHub } from "~/sandboxes"
|
||||
import { getRSSHub as sandboxGetRSSHub } from "~/tabs/sandboxes"
|
||||
|
||||
import { setBadge } from "./badge"
|
||||
|
||||
const storage = new Storage({
|
||||
area: "local",
|
||||
})
|
||||
|
||||
const savedRSS: {
|
||||
[tabId: number]: {
|
||||
pageRSSHub: RSSData[]
|
||||
@@ -44,8 +39,8 @@ export const getRSS = async (tabId, url) => {
|
||||
tabId,
|
||||
})
|
||||
|
||||
if (chrome.offscreen && chrome.runtime.getContexts) {
|
||||
await setupOffscreenDocument("tabs/offscreen.html")
|
||||
if (chrome.offscreen && (chrome.runtime as any).getContexts) {
|
||||
await setupOffscreenDocument("offscreen.html")
|
||||
chrome.runtime.sendMessage({
|
||||
target: "offscreen",
|
||||
data: {
|
||||
@@ -54,7 +49,7 @@ export const getRSS = async (tabId, url) => {
|
||||
tabId,
|
||||
html,
|
||||
url,
|
||||
rules: await storage.get("rules"),
|
||||
rules: await getLocalStorage("rules"),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -62,7 +57,7 @@ export const getRSS = async (tabId, url) => {
|
||||
const rsshub = sandboxGetRSSHub({
|
||||
html,
|
||||
url,
|
||||
rules: await storage.get("rules"),
|
||||
rules: await getLocalStorage("rules"),
|
||||
})
|
||||
setRSS(tabId, rsshub)
|
||||
}
|
||||
@@ -84,12 +79,14 @@ export const getCachedRSS = (tabId) => {
|
||||
|
||||
export const setRSS = async (
|
||||
tabId,
|
||||
data: {
|
||||
pageRSS: RSSData[]
|
||||
} | {
|
||||
pageRSSHub: RSSData[]
|
||||
websiteRSSHub: RSSData[]
|
||||
},
|
||||
data:
|
||||
| {
|
||||
pageRSS: RSSData[]
|
||||
}
|
||||
| {
|
||||
pageRSSHub: RSSData[]
|
||||
websiteRSSHub: RSSData[]
|
||||
},
|
||||
) => {
|
||||
if (!data) {
|
||||
return
|
||||
@@ -111,9 +108,7 @@ export const setRSS = async (
|
||||
let text = ""
|
||||
if (savedRSS[tabId].pageRSS.length || savedRSS[tabId].pageRSSHub.length) {
|
||||
text =
|
||||
savedRSS[tabId].pageRSS.length +
|
||||
savedRSS[tabId].pageRSSHub.length +
|
||||
""
|
||||
savedRSS[tabId].pageRSS.length + savedRSS[tabId].pageRSSHub.length + ""
|
||||
} else if (savedRSS[tabId].websiteRSSHub.length) {
|
||||
text = " "
|
||||
}
|
||||
|
||||
+8
-13
@@ -1,19 +1,14 @@
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
|
||||
import { getConfig } from "~/lib/config"
|
||||
import { setupOffscreenDocument } from "~/lib/offscreen"
|
||||
import { getRemoteRules } from "~/lib/rules"
|
||||
import { getDisplayedRules as sandboxGetDisplayedRules } from "~/sandboxes"
|
||||
|
||||
const storage = new Storage({
|
||||
area: "local",
|
||||
})
|
||||
import { getLocalStorage, setLocalStorage } from "~/lib/storage"
|
||||
import { getDisplayedRules as sandboxGetDisplayedRules } from "~/tabs/sandboxes"
|
||||
|
||||
export const refreshRules = async () => {
|
||||
const rules = await getRemoteRules()
|
||||
await storage.set("rules", rules)
|
||||
if (chrome.offscreen && chrome.runtime.getContexts) {
|
||||
await setupOffscreenDocument("tabs/offscreen.html")
|
||||
await setLocalStorage("rules", rules)
|
||||
if (chrome.offscreen && (chrome.runtime as any).getContexts) {
|
||||
await setupOffscreenDocument("offscreen.html")
|
||||
chrome.runtime.sendMessage({
|
||||
target: "offscreen",
|
||||
data: {
|
||||
@@ -30,10 +25,10 @@ export const refreshRules = async () => {
|
||||
return rules
|
||||
}
|
||||
|
||||
export const getDisplayedRules = () => storage.get("displayedRules")
|
||||
export const getDisplayedRules = () => getLocalStorage("displayedRules")
|
||||
|
||||
export const setDisplayedRules = (displayedRules) =>
|
||||
storage.set("displayedRules", displayedRules)
|
||||
setLocalStorage("displayedRules", displayedRules)
|
||||
|
||||
chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
if (alarm.name === "refreshRulesAlarm") {
|
||||
@@ -43,7 +38,7 @@ chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
|
||||
export async function initSchedule() {
|
||||
const config = await getConfig()
|
||||
const rules = await storage.get("rules")
|
||||
const rules = await getLocalStorage("rules")
|
||||
if (!rules) {
|
||||
setTimeout(() => {
|
||||
refreshRules()
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import RSSHubIcon from "data-base64:~/assets/icon.png"
|
||||
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
import RSSHubIcon from "~/assets/icon.png"
|
||||
import { getLocalStorage, setLocalStorage } from "~/lib/storage"
|
||||
|
||||
import info from "../../package.json"
|
||||
|
||||
const storage = new Storage({
|
||||
area: "local",
|
||||
})
|
||||
|
||||
export const initUpdateNotifications = async () => {
|
||||
const version = await storage.get("version")
|
||||
const version = await getLocalStorage("version")
|
||||
if (version === info.version) return
|
||||
|
||||
chrome.notifications?.create("RSSHubRadarUpdate", {
|
||||
@@ -28,5 +23,5 @@ export const initUpdateNotifications = async () => {
|
||||
chrome.notifications?.clear("RSSHubRadarUpdate")
|
||||
}
|
||||
})
|
||||
await storage.set("version", info.version)
|
||||
await setLocalStorage("version", info.version)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
|
||||
import { sendToBackground } from "~/lib/messaging"
|
||||
import { getPageRSS } from "~/lib/rss"
|
||||
|
||||
sendToBackground({
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export default defineBackground(() => {
|
||||
import("~/background/index")
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
export default defineContentScript({
|
||||
matches: ["<all_urls>"],
|
||||
main() {
|
||||
import("~/contents/index")
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>RSSHub Radar</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import ReactDOM from "react-dom/client"
|
||||
|
||||
import OffscreenPage from "~/tabs/offscreen"
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(<OffscreenPage />)
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>RSSHub Radar</title>
|
||||
<meta name="manifest.open_in_tab" content="true" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import ReactDOM from "react-dom/client"
|
||||
|
||||
import Options from "~/options/index"
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(<Options />)
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>RSSHub Radar</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import ReactDOM from "react-dom/client"
|
||||
|
||||
import IndexPopup from "~/popup/index"
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(<IndexPopup />)
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>RSSHub Radar</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import ReactDOM from "react-dom/client"
|
||||
|
||||
import PreviewPage from "~/tabs/preview"
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(<PreviewPage />)
|
||||
@@ -0,0 +1,11 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>RSSHub Radar</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="./main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
import "~/tabs/sandboxes"
|
||||
+4
-6
@@ -1,9 +1,7 @@
|
||||
import _ from "lodash"
|
||||
import toast from "react-hot-toast"
|
||||
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
|
||||
const storage = new Storage()
|
||||
import { getLocalStorage, setLocalStorage } from "~/lib/storage"
|
||||
|
||||
export const defaultConfig = {
|
||||
rsshubDomain: "https://rsshub.app",
|
||||
@@ -45,7 +43,7 @@ export const defaultConfig = {
|
||||
export async function getConfig() {
|
||||
let storagedConfig = {}
|
||||
try {
|
||||
storagedConfig = await storage.get("config")
|
||||
storagedConfig = await getLocalStorage("config")
|
||||
} catch (error) {}
|
||||
return _.merge({}, defaultConfig, storagedConfig) as typeof defaultConfig
|
||||
}
|
||||
@@ -54,10 +52,10 @@ let toastId: string | undefined
|
||||
export async function setConfig(config: Partial<typeof defaultConfig>) {
|
||||
let storagedConfig = {}
|
||||
try {
|
||||
storagedConfig = await storage.get("config")
|
||||
storagedConfig = await getLocalStorage("config")
|
||||
} catch (error) {}
|
||||
config = _.merge({}, storagedConfig, config)
|
||||
await storage.set("config", config)
|
||||
await setLocalStorage("config", config)
|
||||
toastId = toast.success("Saved", {
|
||||
id: toastId,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
export type ExtensionMessage = {
|
||||
name: string
|
||||
body?: any
|
||||
}
|
||||
|
||||
export function sendToBackground<T = any>(message: ExtensionMessage) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
chrome.runtime.sendMessage(message, (response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message))
|
||||
return
|
||||
}
|
||||
resolve(response as T)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function sendToContentScript<T = any>({
|
||||
name,
|
||||
tabId,
|
||||
body,
|
||||
}: {
|
||||
name: string
|
||||
tabId: number
|
||||
body?: any
|
||||
}) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
chrome.tabs.sendMessage(tabId, { name, body }, (response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message))
|
||||
return
|
||||
}
|
||||
resolve(response as T)
|
||||
})
|
||||
})
|
||||
}
|
||||
+10
-9
@@ -1,14 +1,15 @@
|
||||
// https://developer.chrome.com/docs/extensions/reference/api/offscreen
|
||||
let creating
|
||||
async function setupOffscreenDocument(path) {
|
||||
const offscreenUrl = chrome.runtime.getURL(path)
|
||||
// @ts-ignore
|
||||
const existingContexts = await chrome.runtime.getContexts({
|
||||
contextTypes: ["OFFSCREEN_DOCUMENT"],
|
||||
documentUrls: [offscreenUrl],
|
||||
})
|
||||
|
||||
if (existingContexts.length > 0) {
|
||||
async function setupOffscreenDocument(path: string) {
|
||||
const offscreenUrl = chrome.runtime.getURL(path)
|
||||
|
||||
const existingContexts = (await (chrome.runtime as any).getContexts({
|
||||
contextTypes: ["OFFSCREEN_DOCUMENT"] as any,
|
||||
documentUrls: [offscreenUrl],
|
||||
})) as chrome.runtime.ExtensionContext[] | undefined
|
||||
|
||||
if (existingContexts?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,7 +17,7 @@ async function setupOffscreenDocument(path) {
|
||||
await creating
|
||||
} else {
|
||||
creating = chrome.offscreen.createDocument({
|
||||
url: chrome.runtime.getURL("tabs/offscreen.html"),
|
||||
url: offscreenUrl,
|
||||
reasons: [chrome.offscreen.Reason.IFRAME_SCRIPTING],
|
||||
justification: "Get RSS in the sandbox for enhanced security.",
|
||||
})
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import FollowLogo from "data-base64:~/assets/follow.svg"
|
||||
import InoreaderLogo from "data-base64:~/assets/inoreader.svg"
|
||||
import MinifluxLogo from "data-base64:~/assets/miniflux.ico"
|
||||
import FreshRSSLogo from "data-base64:~/assets/freshrss.svg"
|
||||
import TinyTinyRSSLogo from "data-base64:~/assets/ttrss.png"
|
||||
import FeedlyLogo from "data-base64:~/assets/feedly.png"
|
||||
import NewsBlurLogo from "data-base64:~/assets/newsblur.png"
|
||||
import FeedlyLogo from "~/assets/feedly.png"
|
||||
import FollowLogo from "~/assets/follow.svg"
|
||||
import FreshRSSLogo from "~/assets/freshrss.svg"
|
||||
import InoreaderLogo from "~/assets/inoreader.svg"
|
||||
import MinifluxLogo from "~/assets/miniflux.ico"
|
||||
import NewsBlurLogo from "~/assets/newsblur.png"
|
||||
import TinyTinyRSSLogo from "~/assets/ttrss.png"
|
||||
|
||||
export const logoMap = new Map<string, string>([
|
||||
["follow", FollowLogo],
|
||||
|
||||
+10
-9
@@ -1,6 +1,6 @@
|
||||
function isSampled(rate) {
|
||||
const randomNumber = Math.floor(Math.random() * 100);
|
||||
return randomNumber < rate * 100;
|
||||
const randomNumber = Math.floor(Math.random() * 100)
|
||||
return randomNumber < rate * 100
|
||||
}
|
||||
|
||||
function report({
|
||||
@@ -10,11 +10,12 @@ function report({
|
||||
url?: string
|
||||
name?: string
|
||||
}) {
|
||||
if (
|
||||
process.env.PLASMO_PUBLIC_UMAMI_ID &&
|
||||
process.env.PLASMO_PUBLIC_UMAMI_URL &&
|
||||
(name || isSampled(parseFloat(process.env.PLASMO_PUBLIC_UMAMI_SAMPLE_RATE) || 0.01))
|
||||
) {
|
||||
const umamiId = import.meta.env.WXT_UMAMI_ID
|
||||
const umamiUrl = import.meta.env.WXT_UMAMI_URL
|
||||
const sampleRate =
|
||||
parseFloat(import.meta.env.WXT_UMAMI_SAMPLE_RATE || "") || 0.01
|
||||
|
||||
if (umamiId && umamiUrl && (name || isSampled(sampleRate))) {
|
||||
let hostname = ""
|
||||
try {
|
||||
hostname = new URL(url).hostname
|
||||
@@ -26,13 +27,13 @@ function report({
|
||||
language: chrome?.i18n?.getUILanguage(),
|
||||
referrer: hostname,
|
||||
url: hostname,
|
||||
website: process.env.PLASMO_PUBLIC_UMAMI_ID,
|
||||
website: umamiId,
|
||||
name: name,
|
||||
},
|
||||
type: "event",
|
||||
}
|
||||
|
||||
fetch(`${process.env.PLASMO_PUBLIC_UMAMI_URL}/api/send`, {
|
||||
fetch(`${umamiUrl}/api/send`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
export function getLocalStorage<T = any>(key: string) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
chrome.storage.local.get(key, (result) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message))
|
||||
return
|
||||
}
|
||||
|
||||
resolve(result[key] as T)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function setLocalStorage<T = any>(key: string, value: T) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
chrome.storage.local.set(
|
||||
{
|
||||
[key]: value,
|
||||
},
|
||||
() => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message))
|
||||
return
|
||||
}
|
||||
|
||||
resolve()
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import RSSHubIcon from "data-base64:~/assets/icon.png"
|
||||
import { Link, useLocation } from "react-router"
|
||||
import { useMediaQuery } from "usehooks-ts"
|
||||
|
||||
import RSSHubIcon from "~/assets/icon.png"
|
||||
import { AppearanceSwitch } from "~/lib/components/AppearanceSwitch"
|
||||
import {
|
||||
Sheet,
|
||||
@@ -13,11 +13,7 @@ import { cn } from "~/lib/utils"
|
||||
|
||||
import info from "../../package.json"
|
||||
|
||||
function SiderbarContent({
|
||||
withClose,
|
||||
}: {
|
||||
withClose?: boolean
|
||||
}) {
|
||||
function SiderbarContent({ withClose }: { withClose?: boolean }) {
|
||||
const location = useLocation()
|
||||
const links = [
|
||||
{
|
||||
|
||||
@@ -3,33 +3,67 @@ import { Loader2 } from "lucide-react"
|
||||
import { useEffect, useState } from "react"
|
||||
import toast from "react-hot-toast"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import { Button } from "~/lib/components/Button"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "~/lib/components/Card"
|
||||
import { Input } from "~/lib/components/Input"
|
||||
import { Label } from "~/lib/components/Label"
|
||||
import { Switch } from "~/lib/components/Switch"
|
||||
import { defaultConfig, setConfig } from "~/lib/config"
|
||||
import { defaultConfig, getConfig, setConfig } from "~/lib/config"
|
||||
import { sendToBackground } from "~/lib/messaging"
|
||||
import { quickSubscriptions } from "~/lib/quick-subscriptions"
|
||||
import { logoMap } from "~/lib/quick-subscriptions-logos"
|
||||
import report from "~/lib/report"
|
||||
import { getRulesCount, parseRules } from "~/lib/rules"
|
||||
import type { Rules as IRules } from "~/lib/types"
|
||||
import { getRadarRulesUrl } from "~/lib/utils"
|
||||
import { logoMap } from "~/lib/quick-subscriptions-logos"
|
||||
|
||||
function General() {
|
||||
let [config] = useStorage("config")
|
||||
config = _.merge({}, defaultConfig, config)
|
||||
const [config, setConfigState] = useState(defaultConfig)
|
||||
|
||||
const updateConfig = (partialConfig: Partial<typeof defaultConfig>) => {
|
||||
setConfigState(
|
||||
(currentConfig) =>
|
||||
_.merge({}, currentConfig, partialConfig) as typeof defaultConfig,
|
||||
)
|
||||
void setConfig(partialConfig)
|
||||
}
|
||||
|
||||
const [rules, setRules] = useState<IRules>({})
|
||||
useEffect(() => {
|
||||
getConfig().then(setConfigState)
|
||||
|
||||
sendToBackground({
|
||||
name: "requestDisplayedRules",
|
||||
}).then((res) => setRules(parseRules(res, true)))
|
||||
|
||||
const onStorageChange = (
|
||||
changes: {
|
||||
[key: string]: chrome.storage.StorageChange
|
||||
},
|
||||
areaName: string,
|
||||
) => {
|
||||
if (areaName !== "local" || !changes.config) {
|
||||
return
|
||||
}
|
||||
|
||||
setConfigState(
|
||||
_.merge(
|
||||
{},
|
||||
defaultConfig,
|
||||
changes.config.newValue,
|
||||
) as typeof defaultConfig,
|
||||
)
|
||||
}
|
||||
|
||||
chrome.storage.onChanged.addListener(onStorageChange)
|
||||
|
||||
report({
|
||||
name: "options-general",
|
||||
})
|
||||
|
||||
return () => {
|
||||
chrome.storage.onChanged.removeListener(onStorageChange)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const [count, setCount] = useState(0)
|
||||
@@ -102,7 +136,7 @@ function General() {
|
||||
id="notificationsAndReminders"
|
||||
checked={config.notice.badge}
|
||||
onCheckedChange={(value) =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
notice: {
|
||||
badge: value,
|
||||
},
|
||||
@@ -140,7 +174,7 @@ function General() {
|
||||
id="customRSSHubDomain"
|
||||
value={config.rsshubDomain}
|
||||
onChange={(e) =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
rsshubDomain: e.target.value,
|
||||
})
|
||||
}
|
||||
@@ -162,11 +196,11 @@ function General() {
|
||||
id="accessKey"
|
||||
value={config.rsshubAccessControl.accessKey}
|
||||
onChange={(e) =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
rsshubAccessControl: {
|
||||
accessKey: e.target.value,
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
}
|
||||
placeholder={chrome.i18n.getMessage(
|
||||
"configurationRequiredIfAccessKeysEnabled",
|
||||
@@ -180,13 +214,15 @@ function General() {
|
||||
<input
|
||||
type="radio"
|
||||
id="accessKeyTypeCode"
|
||||
checked={config.rsshubAccessControl.accessKeyType === "code"}
|
||||
checked={
|
||||
config.rsshubAccessControl.accessKeyType === "code"
|
||||
}
|
||||
onChange={() =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
rsshubAccessControl: {
|
||||
accessKeyType: "code",
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
}
|
||||
/>
|
||||
<label htmlFor="accessKeyTypeCode">code={"{md5}"}</label>
|
||||
@@ -195,16 +231,20 @@ function General() {
|
||||
<input
|
||||
type="radio"
|
||||
id="accessKeyTypeKey"
|
||||
checked={config.rsshubAccessControl.accessKeyType === "key"}
|
||||
checked={
|
||||
config.rsshubAccessControl.accessKeyType === "key"
|
||||
}
|
||||
onChange={() =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
rsshubAccessControl: {
|
||||
accessKeyType: "key",
|
||||
},
|
||||
})
|
||||
} as any)
|
||||
}
|
||||
/>
|
||||
<label htmlFor="accessKeyTypeKey">key={"{accessKey}"}</label>
|
||||
<label htmlFor="accessKeyTypeKey">
|
||||
key={"{accessKey}"}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -264,14 +304,17 @@ function General() {
|
||||
id={quickSubscription.key}
|
||||
checked={config.submitto[quickSubscription.key]}
|
||||
onCheckedChange={(value) =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
submitto: {
|
||||
[quickSubscription.key]: value,
|
||||
},
|
||||
} as any)
|
||||
}
|
||||
/>
|
||||
<Label className="w-28 flex gap-2 items-center" htmlFor={quickSubscription.key}>
|
||||
<Label
|
||||
className="w-28 flex gap-2 items-center"
|
||||
htmlFor={quickSubscription.key}
|
||||
>
|
||||
{logoMap.get(quickSubscription.key) && (
|
||||
<img
|
||||
src={logoMap.get(quickSubscription.key)}
|
||||
@@ -293,7 +336,7 @@ function General() {
|
||||
config.submitto[quickSubscription.subscribeDomainKey]
|
||||
}
|
||||
onChange={(e) =>
|
||||
setConfig({
|
||||
updateConfig({
|
||||
submitto: {
|
||||
[quickSubscription.subscribeDomainKey]:
|
||||
e.target.value,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import _ from "lodash"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "~/lib/components/Pagination"
|
||||
import { sendToBackground } from "~/lib/messaging"
|
||||
import report from "~/lib/report"
|
||||
import { getRulesCount, parseRules } from "~/lib/rules"
|
||||
import type { Rules as IRules } from "~/lib/types"
|
||||
|
||||
+29
-15
@@ -1,14 +1,14 @@
|
||||
import RSSHubIcon from "data-base64:~/assets/icon.png"
|
||||
import MD5 from "md5.js"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useCopyToClipboard } from "usehooks-ts"
|
||||
|
||||
import RSSHubIcon from "~/assets/icon.png"
|
||||
import { Button } from "~/lib/components/Button"
|
||||
import { defaultConfig, getConfig } from "~/lib/config"
|
||||
import { quickSubscriptions } from "~/lib/quick-subscriptions"
|
||||
import { logoMap } from "~/lib/quick-subscriptions-logos"
|
||||
import report from "~/lib/report"
|
||||
import type { RSSData } from "~/lib/types"
|
||||
import { logoMap } from "~/lib/quick-subscriptions-logos"
|
||||
|
||||
function RSSItem({
|
||||
item,
|
||||
@@ -33,19 +33,20 @@ function RSSItem({
|
||||
}
|
||||
}, [copied])
|
||||
|
||||
let url = item.url.replace(
|
||||
"{rsshubDomain}",
|
||||
config.rsshubDomain.replace(/\/$/, ""),
|
||||
).replace(/\/$/, "")
|
||||
let url = item.url
|
||||
.replace("{rsshubDomain}", config.rsshubDomain.replace(/\/$/, ""))
|
||||
.replace(/\/$/, "")
|
||||
|
||||
if (type === "currentPageRSSHub" && config.rsshubAccessControl.accessKey) {
|
||||
const urlObj = new URL(url)
|
||||
|
||||
if (config.rsshubAccessControl.accessKeyType === "key") {
|
||||
urlObj.searchParams.append('key', config.rsshubAccessControl.accessKey)
|
||||
urlObj.searchParams.append("key", config.rsshubAccessControl.accessKey)
|
||||
} else {
|
||||
const md5 = new MD5().update(urlObj.pathname + config.rsshubAccessControl.accessKey).digest("hex")
|
||||
urlObj.searchParams.append('code', md5)
|
||||
const md5 = new MD5()
|
||||
.update(urlObj.pathname + config.rsshubAccessControl.accessKey)
|
||||
.digest("hex")
|
||||
urlObj.searchParams.append("code", md5)
|
||||
}
|
||||
|
||||
url = urlObj.toString()
|
||||
@@ -112,10 +113,15 @@ function RSSItem({
|
||||
image: item.image,
|
||||
})}`}
|
||||
>
|
||||
{logoMap.get(quickSubscription.key) ?
|
||||
<img className="w-5 h-5 rounded" src={logoMap.get(quickSubscription.key)} /> : (chrome.i18n.getMessage(quickSubscription.name) ||
|
||||
quickSubscription.name)
|
||||
}
|
||||
{logoMap.get(quickSubscription.key) ? (
|
||||
<img
|
||||
className="w-5 h-5 rounded"
|
||||
src={logoMap.get(quickSubscription.key)}
|
||||
/>
|
||||
) : (
|
||||
chrome.i18n.getMessage(quickSubscription.name) ||
|
||||
quickSubscription.name
|
||||
)}
|
||||
</a>
|
||||
</Button>
|
||||
)
|
||||
@@ -149,7 +155,11 @@ function RSSItem({
|
||||
})
|
||||
}}
|
||||
>
|
||||
<i className={copied ? "i-mingcute-check-line" : "i-mingcute-copy-2-line"}></i>
|
||||
<i
|
||||
className={
|
||||
copied ? "i-mingcute-check-line" : "i-mingcute-copy-2-line"
|
||||
}
|
||||
></i>
|
||||
</Button>
|
||||
)}
|
||||
{!item.isDocs && !hidePreview && (
|
||||
@@ -158,7 +168,11 @@ function RSSItem({
|
||||
size="sm"
|
||||
className="text-primary hover:text-primary text-lg"
|
||||
>
|
||||
<a target="_blank" href={`/tabs/preview.html?url=${encodedUrl}`} className="flex center">
|
||||
<a
|
||||
target="_blank"
|
||||
href={`/preview.html?url=${encodedUrl}`}
|
||||
className="flex center"
|
||||
>
|
||||
<i className="i-mingcute-eye-line"></i>
|
||||
</a>
|
||||
</Button>
|
||||
|
||||
+1
-2
@@ -2,9 +2,8 @@ import "~/lib/style.css"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
|
||||
import { useDark } from "~/lib/hooks/use-dark"
|
||||
import { sendToBackground } from "~/lib/messaging"
|
||||
import report from "~/lib/report"
|
||||
|
||||
import RSSList from "./RSSList"
|
||||
|
||||
+35
-14
@@ -1,24 +1,45 @@
|
||||
import { useRef } from "react"
|
||||
import { useEffect, useRef } from "react"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
import { sendToBackground } from "~/lib/messaging"
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data?.name.startsWith("response")) {
|
||||
chrome.runtime.sendMessage(event.data)
|
||||
sendToBackground(event.data)
|
||||
}
|
||||
})
|
||||
type OffscreenMessage = {
|
||||
name: string
|
||||
body?: unknown
|
||||
}
|
||||
|
||||
function OffscreenPage() {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null)
|
||||
|
||||
chrome.runtime.onMessage.addListener((msg) => {
|
||||
iframeRef.current?.contentWindow?.postMessage(msg.data, "*")
|
||||
})
|
||||
useEffect(() => {
|
||||
const onWindowMessage = (
|
||||
event: MessageEvent<Partial<OffscreenMessage>>,
|
||||
) => {
|
||||
if (
|
||||
typeof event.data?.name === "string" &&
|
||||
event.data.name.startsWith("response")
|
||||
) {
|
||||
chrome.runtime.sendMessage(event.data)
|
||||
sendToBackground({
|
||||
name: event.data.name,
|
||||
body: event.data.body,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<iframe id="sandbox" src="/sandboxes/index.html" ref={iframeRef}></iframe>
|
||||
)
|
||||
const onRuntimeMessage = (msg: { data?: unknown }) => {
|
||||
iframeRef.current?.contentWindow?.postMessage(msg.data, "*")
|
||||
}
|
||||
|
||||
window.addEventListener("message", onWindowMessage)
|
||||
chrome.runtime.onMessage.addListener(onRuntimeMessage)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", onWindowMessage)
|
||||
chrome.runtime.onMessage.removeListener(onRuntimeMessage)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <iframe id="sandbox" src="/sandbox.html" ref={iframeRef}></iframe>
|
||||
}
|
||||
|
||||
export default OffscreenPage
|
||||
|
||||
@@ -3,9 +3,9 @@ import Parser from "rss-parser"
|
||||
|
||||
import "~/lib/style.css"
|
||||
|
||||
import RSSHubIcon from "data-base64:~/assets/icon.png"
|
||||
import xss from "xss"
|
||||
|
||||
import RSSHubIcon from "~/assets/icon.png"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "~/sandboxes"
|
||||
+1
-1
@@ -14,7 +14,7 @@ quickSubscriptions.forEach((subscription) => {
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["class"],
|
||||
content: ["./**/*.tsx"],
|
||||
content: ["./src/**/*.{ts,tsx,html}"],
|
||||
safelist,
|
||||
theme: {
|
||||
container: {
|
||||
|
||||
+6
-7
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"extends": "plasmo/templates/tsconfig.base",
|
||||
"exclude": ["node_modules"],
|
||||
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx"],
|
||||
"extends": "./.wxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"~/*": ["./src/*"],
|
||||
},
|
||||
"baseUrl": ".",
|
||||
"allowImportingTsExtensions": true,
|
||||
"jsx": "react-jsx",
|
||||
"strict": false,
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { defineConfig } from "wxt"
|
||||
|
||||
const iconMap = {
|
||||
16: "/icon.png",
|
||||
32: "/icon.png",
|
||||
48: "/icon.png",
|
||||
64: "/icon.png",
|
||||
128: "/icon.png",
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
srcDir: "src",
|
||||
modules: ["@wxt-dev/module-react"],
|
||||
manifest: ({ browser }) => ({
|
||||
name: "RSSHub Radar",
|
||||
description: "__MSG_extensionDescription__",
|
||||
default_locale: "en",
|
||||
permissions: ["tabs", "offscreen", "storage", "alarms"],
|
||||
host_permissions: ["https://*/*"],
|
||||
optional_permissions: ["notifications"],
|
||||
icons: iconMap,
|
||||
action: {
|
||||
default_icon: iconMap,
|
||||
},
|
||||
browser_specific_settings:
|
||||
browser === "firefox"
|
||||
? {
|
||||
gecko: {
|
||||
id: "i@diygod.me",
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
}),
|
||||
})
|
||||
Reference in New Issue
Block a user