From eecf8b57a5a63b7de8fbbf6b049039e919f15ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B5=A9=E8=BF=9C?= Date: Thu, 18 Jun 2020 13:42:14 +0800 Subject: [PATCH] use fetch api instead of node http --- dist/styles.css | 1 + package.json | 13 +++--- src/components/settings/app.tsx | 3 ++ src/electron.ts | 3 ++ src/scripts/i18n/en-US.json | 3 +- src/scripts/i18n/zh-CN.json | 3 +- src/scripts/models/item.ts | 2 +- src/scripts/models/source.ts | 16 +++----- src/scripts/settings.ts | 11 +++--- src/scripts/utils.ts | 70 +++++++++++++++++++++------------ 10 files changed, 74 insertions(+), 51 deletions(-) diff --git a/dist/styles.css b/dist/styles.css index 960c9eb..529e226 100644 --- a/dist/styles.css +++ b/dist/styles.css @@ -560,6 +560,7 @@ img.favicon { align-items: center; color: var(--neutralSecondary); font-size: 14px; + user-select: none; } .info { diff --git a/package.json b/package.json index 97f7c0a..c9001a4 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,10 @@ "output": "./bin/${platform}/${arch}/" }, "win": { - "target": [ "nsis", "appx" ] + "target": [ + "nsis", + "appx" + ] }, "appx": { "applicationId": "FluentReader", @@ -43,7 +46,9 @@ "deleteAppDataOnUninstall": true }, "mac": { - "target": [ "dmg" ] + "target": [ + "dmg" + ] } }, "devDependencies": { @@ -55,17 +60,14 @@ "@types/redux": "^3.6.0", "@types/redux-thunk": "^2.1.0", "@types/reselect": "^2.2.0", - "@yang991178/electron-proxy-agent": "^1.2.1", "@yang991178/rss-parser": "^3.8.1", "electron": "^9.0.4", "electron-builder": "^22.7.0", "electron-react-devtools": "^0.5.3", "electron-store": "^5.2.0", "electron-window-state": "^5.0.3", - "favicon": "0.0.2", "html-webpack-plugin": "^4.3.0", "nedb": "^1.8.0", - "pac-proxy-agent": "^4.1.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-intl-universal": "^2.2.5", @@ -74,7 +76,6 @@ "redux-devtools": "^3.5.0", "redux-thunk": "^2.3.0", "reselect": "^4.0.0", - "simplebar-react": "^2.2.0", "ts-loader": "^7.0.4", "typescript": "^3.9.2", "webpack": "^4.43.0", diff --git a/src/components/settings/app.tsx b/src/components/settings/app.tsx index 9f08d22..1c020a2 100644 --- a/src/components/settings/app.tsx +++ b/src/components/settings/app.tsx @@ -164,6 +164,9 @@ class AppTab extends React.Component { text={intl.get("app.setPac")} /> + + {intl.get("app.pacHint")} + } diff --git a/src/electron.ts b/src/electron.ts index fd4768a..f578e43 100644 --- a/src/electron.ts +++ b/src/electron.ts @@ -66,6 +66,9 @@ app.on("second-instance", () => { }) app.on("window-all-closed", function () { + if (mainWindow) { + mainWindow.webContents.session.clearStorageData({ storages: ["cookies"] }) + } mainWindow = null if (restarting) { init() diff --git a/src/scripts/i18n/en-US.json b/src/scripts/i18n/en-US.json index 4b46fc1..290c536 100644 --- a/src/scripts/i18n/en-US.json +++ b/src/scripts/i18n/en-US.json @@ -141,6 +141,7 @@ "enableProxy": "Enable Proxy", "badUrl": "Invalid URL", "pac": "PAC Address", - "setPac": "Set PAC" + "setPac": "Set PAC", + "pacHint": "For Socks proxies, it is recommended for PAC to return \"SOCKS5\" for proxy-side DNS. Turning off proxy requires restart." } } \ No newline at end of file diff --git a/src/scripts/i18n/zh-CN.json b/src/scripts/i18n/zh-CN.json index e01b052..953834e 100644 --- a/src/scripts/i18n/zh-CN.json +++ b/src/scripts/i18n/zh-CN.json @@ -141,6 +141,7 @@ "enableProxy": "启用代理", "badUrl": "请正确输入URL", "pac": "PAC地址", - "setPac": "设置PAC" + "setPac": "设置PAC", + "pacHint": "对于Socks代理建议PAC返回“SOCKS5”以启用代理端解析。关闭代理需重启应用后生效。" } } \ No newline at end of file diff --git a/src/scripts/models/item.ts b/src/scripts/models/item.ts index 2bafd2c..7ee4c20 100644 --- a/src/scripts/models/item.ts +++ b/src/scripts/models/item.ts @@ -163,7 +163,7 @@ export function fetchItems(): AppThunk> { if (r.status === "fulfilled") items.push(...r.value) else { console.log(r.reason) - dispatch(fetchItemsFailure(getState().sources[i], r.reason)) + dispatch(fetchItemsFailure(sources[i], r.reason)) } }) insertItems(items) diff --git a/src/scripts/models/source.ts b/src/scripts/models/source.ts index af4e489..3a3aed6 100644 --- a/src/scripts/models/source.ts +++ b/src/scripts/models/source.ts @@ -1,7 +1,7 @@ import Parser = require("@yang991178/rss-parser") import intl = require("react-intl-universal") import * as db from "../db" -import { rssParser, faviconPromise, ActionStatus, AppThunk } from "../utils" +import { rssParser, fetchFavicon, ActionStatus, AppThunk, parseRSS } from "../utils" import { RSSItem, insertItems, ItemActionTypes, FETCH_ITEMS, MARK_READ, MARK_UNREAD, MARK_ALL_READ } from "./item" import { SourceGroup } from "./group" import { saveSettings } from "./app" @@ -29,21 +29,15 @@ export class RSSSource { } async fetchMetaData(parser: Parser) { - let feed = await parser.parseURL(this.url) + let feed = await parseRSS(this.url) if (!this.name) { if (feed.title) this.name = feed.title.trim() this.name = this.name || intl.get("sources.untitled") } let domain = this.url.split("/").slice(0, 3).join("/") - let f: string = null try { - f = await faviconPromise(domain) - if (f === null) f = domain + "/favicon.ico" - let result = await fetch(f) - if (result.status == 200 && result.headers.has("Content-Type") - && result.headers.get("Content-Type").startsWith("image")) { - this.iconurl = f - } + let f = await fetchFavicon(domain) + if (f !== null) this.iconurl = f } finally { return feed } @@ -82,7 +76,7 @@ export class RSSSource { } static async fetchItems(source: RSSSource, parser: Parser) { - let feed = await parser.parseURL(source.url) + let feed = await parseRSS(source.url) db.sdb.update({ sid: source.sid }, { $set: { lastFetched: new Date() } }) return await this.checkItems(source, feed.items) } diff --git a/src/scripts/settings.ts b/src/scripts/settings.ts index 830d800..e18b513 100644 --- a/src/scripts/settings.ts +++ b/src/scripts/settings.ts @@ -35,12 +35,11 @@ export function setProxy(address = null) { } else { store.set(PAC_STORE_KEY, address) } - remote.getCurrentWebContents().session.setProxy({ - pacScript: getProxyStatus() ? address : "" - }) - remote.session.fromPartition("sandbox").setProxy({ - pacScript: getProxyStatus() ? address : "" - }) + if (getProxyStatus()) { + let rules = { pacScript: address } + remote.getCurrentWebContents().session.setProxy(rules) + remote.session.fromPartition("sandbox").setProxy(rules) + } } const VIEW_STORE_KEY = "view" diff --git a/src/scripts/utils.ts b/src/scripts/utils.ts index e0db184..210ba64 100644 --- a/src/scripts/utils.ts +++ b/src/scripts/utils.ts @@ -17,41 +17,61 @@ export type AppThunk = ThunkAction< export type AppDispatch = ThunkDispatch import Parser = require("@yang991178/rss-parser") -const customFields = { - item: ["thumb", "image", ["content:encoded", "fullContent"]] as Parser.CustomFieldItem[] -} - -import ElectronProxyAgent = require("@yang991178/electron-proxy-agent") -import { ViewType } from "./models/page" -import { IPartialTheme } from "@fluentui/react" -import { SourceGroup } from "./models/group" -let agent = new ElectronProxyAgent(remote.getCurrentWebContents().session) export const rssParser = new Parser({ - customFields: customFields, - requestOptions: { - agent: agent + customFields: { + item: ["thumb", "image", ["content:encoded", "fullContent"]] as Parser.CustomFieldItem[] } }) +export async function parseRSS(url: string) { + try { + let result = await fetch(url, { credentials: "omit" }) + if (result.ok) { + return await rssParser.parseString(await result.text()) + } else { + throw new Error(result.statusText) + } + } catch { + throw new Error("A network error has occured.") + } +} + export const domParser = new DOMParser() -const favicon = require("favicon") -export function faviconPromise(url: string): Promise { - return new Promise((resolve, reject) => { - favicon(url, (err, icon: string) => { - if (err) reject(err) - else if (!icon) resolve(icon) - else { - let parts = icon.split("//") - resolve(parts[0] + "//" + parts[parts.length - 1]) +import Url = require("url") +export async function fetchFavicon(url: string) { + try { + let result = await fetch(url, { credentials: "omit" }) + if (result.ok) { + let html = await result.text() + let dom = domParser.parseFromString(html, "text/html") + let links = dom.getElementsByTagName("link") + for (let link of links) { + let rel = link.getAttribute("rel") + if ((rel === "icon" || rel === "shortcut icon") && link.hasAttribute("href")) { + let href = link.getAttribute("href") + let parsedUrl = Url.parse(url) + if (href.startsWith("//")) return parsedUrl.protocol + href + else if (href.startsWith("/")) return url + href + else return href + } } - }) - }) + } + url = url + "/favicon.ico" + result = await fetch(url, { credentials: "omit" }) + if (result.status == 200 && result.headers.has("Content-Type") + && result.headers.get("Content-Type").startsWith("image")) { + return url + } + return null + } catch { + return null + } } export function htmlDecode(input: string) { - var doc = domParser.parseFromString(input, "text/html"); - return doc.documentElement.textContent; + var doc = domParser.parseFromString(input, "text/html") + return doc.documentElement.textContent } export function openExternal(url: string) {