Merge pull request #602 from yang991178/1.1.4

Version 1.1.4
This commit is contained in:
Haoyuan Liu 2023-10-15 21:48:53 -07:00 committed by GitHub
commit b6c805246a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 523 additions and 650 deletions

1092
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "fluent-reader",
"version": "1.1.3",
"version": "1.1.4",
"description": "Modern desktop RSS reader",
"main": "./dist/electron.js",
"scripts": {
@ -25,8 +25,8 @@
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9",
"@yang991178/rss-parser": "^3.8.1",
"electron": "^21.0.1",
"rss-parser": "^3.13.0",
"electron": "^27.0.0",
"electron-builder": "^23.0.3",
"electron-react-devtools": "^0.5.3",
"electron-store": "^5.2.0",

View File

@ -17,8 +17,8 @@ const utilsBridge = {
ipcRenderer.invoke("open-external", url, background)
},
showErrorBox: (title: string, content: string) => {
ipcRenderer.invoke("show-error-box", title, content)
showErrorBox: (title: string, content: string, copy?: string) => {
ipcRenderer.invoke("show-error-box", title, content, copy)
},
showMessageBox: async (

View File

@ -24,9 +24,8 @@ import {
} from "@fluentui/react"
import { SourceRule, RuleActions } from "../../scripts/models/rule"
import { FilterType } from "../../scripts/models/feed"
import { validateRegex } from "../../scripts/utils"
import { MyParserItem, validateRegex } from "../../scripts/utils"
import { RSSItem } from "../../scripts/models/item"
import Parser from "@yang991178/rss-parser"
const actionKeyMap = {
"r-true": "article.markRead",
@ -337,7 +336,7 @@ class RulesTab extends React.Component<RulesTabProps, RulesTabState> {
testMockItem = () => {
let parsed = { title: this.state.mockTitle }
let source = this.props.sources[parseInt(this.state.sid)]
let item = new RSSItem(parsed as Parser.Item, source)
let item = new RSSItem(parsed as MyParserItem, source)
item.snippet = this.state.mockContent
item.creator = this.state.mockCreator
SourceRule.applyAll(this.getSourceRules(), item)

View File

@ -45,8 +45,23 @@ export function setUtilsListeners(manager: WindowManager) {
openExternal(url, background)
})
ipcMain.handle("show-error-box", (_, title, content) => {
dialog.showErrorBox(title, content)
ipcMain.handle("show-error-box", async (_, title, content, copy?: string) => {
if (manager.hasWindow() && copy != null) {
const response = await dialog.showMessageBox(manager.mainWindow, {
type: 'error',
title: title,
message: title,
detail: content,
buttons: ["OK", copy],
cancelId: 0,
defaultId: 0,
})
if (response.response === 1) {
clipboard.writeText(`${title}: ${content}`);
}
} else {
dialog.showErrorBox(title, content)
}
})
ipcMain.handle(
@ -56,7 +71,8 @@ export function setUtilsListeners(manager: WindowManager) {
let response = await dialog.showMessageBox(manager.mainWindow, {
type: type,
title: title,
message: message,
message: title,
detail: message,
buttons:
process.platform === "win32"
? ["Yes", "No"]

View File

@ -70,7 +70,7 @@
},
"context": {
"share": "Partager",
"read": "Lu",
"read": "Lire",
"copyTitle": "Copier le titre",
"copyURL": "Copier le lien",
"copy": "Copier",

View File

@ -300,7 +300,8 @@ export function importOPML(): AppThunk {
.map(e => {
return e[0] + "\n" + String(e[1])
})
.join("\n")
.join("\n"),
intl.get("context.copy")
)
}
})

View File

@ -1,6 +1,7 @@
import * as db from "../db"
import lf from "lovefield"
import intl from "react-intl-universal"
import type { MyParserItem } from "../utils"
import {
domParser,
htmlDecode,
@ -9,15 +10,7 @@ import {
platformCtrl,
} from "../utils"
import { RSSSource, updateSource, updateUnreadCounts } from "./source"
import {
FeedActionTypes,
INIT_FEED,
LOAD_MORE,
FilterType,
initFeeds,
dismissItems,
} from "./feed"
import Parser from "@yang991178/rss-parser"
import { FeedActionTypes, INIT_FEED, LOAD_MORE, dismissItems } from "./feed"
import {
pushNotification,
setupAutoFetch,
@ -48,7 +41,7 @@ export class RSSItem {
notify: boolean
serviceRef?: string
constructor(item: Parser.Item, source: RSSSource) {
constructor(item: MyParserItem, source: RSSSource) {
for (let field of ["title", "link", "creator"]) {
const content = item[field]
if (content && typeof content !== "string") delete item[field]
@ -65,7 +58,7 @@ export class RSSItem {
this.notify = false
}
static parseContent(item: RSSItem, parsed: Parser.Item) {
static parseContent(item: RSSItem, parsed: MyParserItem) {
for (let field of ["thumb", "content", "fullContent"]) {
const content = parsed[field]
if (content && typeof content !== "string") delete parsed[field]
@ -79,7 +72,7 @@ export class RSSItem {
}
if (parsed.thumb) {
item.thumb = parsed.thumb
} else if (parsed.image && parsed.image.$ && parsed.image.$.url) {
} else if (parsed.image?.$?.url) {
item.thumb = parsed.image.$.url
} else if (parsed.image && typeof parsed.image === "string") {
item.thumb = parsed.image

View File

@ -1,8 +1,13 @@
import Parser from "@yang991178/rss-parser"
import intl from "react-intl-universal"
import * as db from "../db"
import lf from "lovefield"
import { fetchFavicon, ActionStatus, AppThunk, parseRSS } from "../utils"
import {
fetchFavicon,
ActionStatus,
AppThunk,
parseRSS,
MyParserItem,
} from "../utils"
import {
RSSItem,
insertItems,
@ -64,7 +69,7 @@ export class RSSSource {
private static async checkItem(
source: RSSSource,
item: Parser.Item
item: MyParserItem
): Promise<RSSItem> {
let i = new RSSItem(item, source)
const items = (await db.itemsDB
@ -90,7 +95,7 @@ export class RSSSource {
static checkItems(
source: RSSSource,
items: Parser.Item[]
items: MyParserItem[]
): Promise<RSSItem[]> {
return new Promise<RSSItem[]>((resolve, reject) => {
let p = new Array<Promise<RSSItem>>()
@ -318,7 +323,8 @@ export function addSource(
if (!batch) {
window.utils.showErrorBox(
intl.get("sources.errorAdd"),
String(e)
String(e),
intl.get("context.copy")
)
}
throw e

View File

@ -2,7 +2,7 @@ import intl from "react-intl-universal"
import { ThunkAction, ThunkDispatch } from "redux-thunk"
import { AnyAction } from "redux"
import { RootState } from "./reducer"
import Parser from "@yang991178/rss-parser"
import Parser from "rss-parser"
import Url from "url"
import { SearchEngines } from "../schema-types"
@ -29,9 +29,11 @@ const rssParser = new Parser({
"image",
["content:encoded", "fullContent"],
["media:content", "mediaContent", { keepArray: true }],
] as Parser.CustomFieldItem[],
],
},
})
type extractGeneric<Type> = Type extends Parser<infer _, infer U> ? U : never
export type MyParserItem = extractGeneric<typeof rssParser> & Parser.Item
const CHARSET_RE = /charset=([^()<>@,;:\"/[\]?.=\s]*)/i
const XML_ENCODING_RE = /^<\?xml.+encoding="(.+?)".*?\?>/i