commit
dfed4bf3e9
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fluent-reader",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fluent-reader",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"description": "Modern desktop RSS reader",
|
||||
"main": "./dist/electron.js",
|
||||
"scripts": {
|
||||
|
@ -68,6 +68,7 @@
|
|||
"category": "public.app-category.news",
|
||||
"electronLanguages": [
|
||||
"zh_CN",
|
||||
"zh_TW",
|
||||
"en",
|
||||
"fr",
|
||||
"es",
|
||||
|
|
|
@ -64,6 +64,7 @@ class GReaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReaderC
|
|||
endpoint: this.state.endpoint,
|
||||
fetchLimit: this.state.fetchLimit
|
||||
} as GReaderConfigs
|
||||
if (this.state.password) configs.password = this.state.password
|
||||
} else {
|
||||
configs = {
|
||||
type: SyncService.GReader,
|
||||
|
|
|
@ -4,7 +4,7 @@ import { ServiceConfigsTabProps } from "../service"
|
|||
import { GReaderConfigs } from "../../../scripts/models/services/greader"
|
||||
import { SyncService } from "../../../schema-types"
|
||||
import { Stack, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
|
||||
MessageBar, MessageBarType, Dropdown, IDropdownOption, MessageBarButton } from "@fluentui/react"
|
||||
MessageBar, MessageBarType, Dropdown, IDropdownOption, MessageBarButton, Link } from "@fluentui/react"
|
||||
import DangerButton from "../../utils/danger-button"
|
||||
|
||||
type GReaderConfigsTabState = {
|
||||
|
@ -12,8 +12,10 @@ type GReaderConfigsTabState = {
|
|||
endpoint: string
|
||||
username: string
|
||||
password: string
|
||||
apiId: string
|
||||
apiKey: string
|
||||
removeAd: boolean
|
||||
fetchLimit: number
|
||||
importGroups: boolean
|
||||
}
|
||||
|
||||
const endpointOptions: IDropdownOption[] = [
|
||||
|
@ -33,8 +35,10 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
endpoint: configs.endpoint || "https://www.inoreader.com",
|
||||
username: configs.username || "",
|
||||
password: "",
|
||||
apiId: configs.inoreaderId || "",
|
||||
apiKey: configs.inoreaderKey || "",
|
||||
removeAd: configs.removeInoreaderAd === undefined ? true : configs.removeInoreaderAd,
|
||||
fetchLimit: configs.fetchLimit || 250,
|
||||
importGroups: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +66,8 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
}
|
||||
|
||||
validateForm = () => {
|
||||
return this.state.existing || (this.state.username && this.state.password)
|
||||
return (this.state.existing || (this.state.username && this.state.password))
|
||||
&& this.state.apiId && this.state.apiKey
|
||||
}
|
||||
|
||||
save = async () => {
|
||||
|
@ -71,18 +76,25 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
configs = {
|
||||
...this.props.configs,
|
||||
endpoint: this.state.endpoint,
|
||||
fetchLimit: this.state.fetchLimit
|
||||
fetchLimit: this.state.fetchLimit,
|
||||
inoreaderId: this.state.apiId,
|
||||
inoreaderKey: this.state.apiKey,
|
||||
removeInoreaderAd: this.state.removeAd,
|
||||
} as GReaderConfigs
|
||||
if (this.state.password) configs.password = this.state.password
|
||||
} else {
|
||||
configs = {
|
||||
type: SyncService.Inoreader,
|
||||
endpoint: this.state.endpoint,
|
||||
username: this.state.username,
|
||||
password: this.state.password,
|
||||
inoreaderId: this.state.apiId,
|
||||
inoreaderKey: this.state.apiKey,
|
||||
removeInoreaderAd: this.state.removeAd,
|
||||
fetchLimit: this.state.fetchLimit,
|
||||
importGroups: true,
|
||||
useInt64: true
|
||||
}
|
||||
if (this.state.importGroups) configs.importGroups = true
|
||||
}
|
||||
this.props.blockActions()
|
||||
configs = await this.props.reauthenticate(configs) as GReaderConfigs
|
||||
|
@ -97,6 +109,8 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
}
|
||||
}
|
||||
|
||||
createKey = () => window.utils.openExternal(this.state.endpoint + "/all_articles#preferences-developer")
|
||||
|
||||
remove = async () => {
|
||||
this.props.exit()
|
||||
await this.props.remove()
|
||||
|
@ -106,8 +120,9 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
return <>
|
||||
<MessageBar messageBarType={MessageBarType.severeWarning}
|
||||
isMultiline={false}
|
||||
actions={<MessageBarButton text={intl.get("rules.help")} onClick={openSupport} />}>
|
||||
actions={<MessageBarButton text={intl.get("create")} onClick={this.createKey} />}>
|
||||
{intl.get("service.rateLimitWarning")}
|
||||
<Link onClick={openSupport} style={{marginLeft: 6}}>{intl.get("rules.help")}</Link>
|
||||
</MessageBar>
|
||||
{!this.state.existing && (
|
||||
<MessageBar messageBarType={MessageBarType.warning}>{intl.get("service.overwriteWarning")}</MessageBar>
|
||||
|
@ -155,6 +170,32 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
onChange={this.handleInputChange} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack className="login-form" horizontal>
|
||||
<Stack.Item>
|
||||
<Label>API ID</Label>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<TextField
|
||||
onGetErrorMessage={this.checkNotEmpty}
|
||||
validateOnLoad={false}
|
||||
name="apiId"
|
||||
value={this.state.apiId}
|
||||
onChange={this.handleInputChange} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack className="login-form" horizontal>
|
||||
<Stack.Item>
|
||||
<Label>API Key</Label>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<TextField
|
||||
onGetErrorMessage={this.checkNotEmpty}
|
||||
validateOnLoad={false}
|
||||
name="apiKey"
|
||||
value={this.state.apiKey}
|
||||
onChange={this.handleInputChange} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack className="login-form" horizontal>
|
||||
<Stack.Item>
|
||||
<Label>{intl.get("service.fetchLimit")}</Label>
|
||||
|
@ -166,10 +207,10 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
|||
onChange={this.onFetchLimitOptionChange} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
{!this.state.existing && <Checkbox
|
||||
label={intl.get("service.importGroups")}
|
||||
checked={this.state.importGroups}
|
||||
onChange={(_, c) => this.setState({importGroups: c})} />}
|
||||
<Checkbox
|
||||
label={intl.get("service.removeAd")}
|
||||
checked={this.state.removeAd}
|
||||
onChange={(_, c) => this.setState({removeAd: c})} />
|
||||
<Stack horizontal style={{marginTop: 32}}>
|
||||
<Stack.Item>
|
||||
<PrimaryButton
|
||||
|
|
|
@ -191,7 +191,8 @@
|
|||
"suggest": "Suggest a new service",
|
||||
"overwriteWarning": "Local sources will be deleted if they exist in the service.",
|
||||
"groupsWarning": "Groups aren't automatically synced with the service.",
|
||||
"rateLimitWarning": "If connection errors persist, the app may have been rate limited by the service.",
|
||||
"rateLimitWarning": "To avoid rate limiting, you need to create your own API Key.",
|
||||
"removeAd": "Remove Ad",
|
||||
"endpoint": "Endpoint",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
|
|
|
@ -189,7 +189,8 @@
|
|||
"suggest": "建议一项新服务",
|
||||
"overwriteWarning": "若本地与服务端存在URL相同的订阅源,则本地订阅源将被删除",
|
||||
"groupsWarning": "分组不会自动与服务端保持同步",
|
||||
"rateLimitWarning": "若反复出现错误,则原因可能是应用被服务限流",
|
||||
"rateLimitWarning": "为避免限流,您需要新建自己的 API Key",
|
||||
"removeAd": "移除广告",
|
||||
"endpoint": "端点",
|
||||
"username": "用户名",
|
||||
"password": "密码",
|
||||
|
|
|
@ -189,7 +189,8 @@
|
|||
"suggest": "建議一項新服務",
|
||||
"overwriteWarning": "若本地與服務端存在URL相同的訂閱源,則本地訂閱源將被刪除",
|
||||
"groupsWarning": "分組不會自動與服務端保持同步",
|
||||
"rateLimitWarning": "若反覆出現錯誤,則原因可能是應用被服務限流",
|
||||
"rateLimitWarning": "為避免限流,您需要新建自己的 API Key",
|
||||
"removeAd": "移除廣告",
|
||||
"endpoint": "端點",
|
||||
"username": "使用者名稱",
|
||||
"password": "密碼",
|
||||
|
|
|
@ -23,14 +23,22 @@ export interface GReaderConfigs extends ServiceConfigs {
|
|||
lastId?: string
|
||||
auth?: string
|
||||
useInt64: boolean // The Old Reader uses ids longer than 64 bits
|
||||
inoreaderId?: string
|
||||
inoreaderKey?: string
|
||||
removeInoreaderAd?: boolean
|
||||
}
|
||||
|
||||
async function fetchAPI(configs: GReaderConfigs, params: string, method="GET", body:BodyInit=null) {
|
||||
const headers = new Headers()
|
||||
if (configs.auth !== null) headers.set("Authorization", configs.auth)
|
||||
if (configs.type == SyncService.Inoreader) {
|
||||
headers.set("AppId", "999999298")
|
||||
headers.set("AppKey", "KPbKYXTfgrKbwmroOeYC7mcW21ZRwF5Y")
|
||||
if (configs.inoreaderId) {
|
||||
headers.set("AppId", configs.inoreaderId)
|
||||
headers.set("AppKey", configs.inoreaderKey)
|
||||
} else {
|
||||
headers.set("AppId", "999999298")
|
||||
headers.set("AppKey", "KPbKYXTfgrKbwmroOeYC7mcW21ZRwF5Y")
|
||||
}
|
||||
}
|
||||
return await fetch(configs.endpoint + params, {
|
||||
method: method,
|
||||
|
@ -189,13 +197,18 @@ export const gReaderServiceHooks: ServiceHooks = {
|
|||
const source = fidMap.get(i.origin.streamId)
|
||||
if (source === undefined) return
|
||||
const dom = domParser.parseFromString(i.summary.content, "text/html")
|
||||
if (configs.type == SyncService.Inoreader && configs.removeInoreaderAd !== false) {
|
||||
if (dom.documentElement.textContent.trim().startsWith("Ads from Inoreader")) {
|
||||
dom.body.firstChild.remove()
|
||||
}
|
||||
}
|
||||
const item = {
|
||||
source: source.sid,
|
||||
title: i.title,
|
||||
link: i.canonical[0].href,
|
||||
date: new Date(i.published * 1000),
|
||||
fetchedDate: new Date(parseInt(i.crawlTimeMsec)),
|
||||
content: i.summary.content,
|
||||
content: dom.body.innerHTML,
|
||||
snippet: dom.documentElement.textContent.trim(),
|
||||
creator: i.author,
|
||||
hasRead: false,
|
||||
|
|
Loading…
Reference in New Issue