commit
b6c805246a
File diff suppressed because it is too large
Load Diff
|
@ -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",
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
},
|
||||
"context": {
|
||||
"share": "Partager",
|
||||
"read": "Lu",
|
||||
"read": "Lire",
|
||||
"copyTitle": "Copier le titre",
|
||||
"copyURL": "Copier le lien",
|
||||
"copy": "Copier",
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue