mirror of
https://github.com/yang991178/fluent-reader.git
synced 2025-02-14 10:40:44 +01:00
db performance and schema changes
This commit is contained in:
parent
06757d0fcd
commit
110be62694
@ -106,8 +106,8 @@ const settingsBridge = {
|
|||||||
getNeDBStatus: (): boolean => {
|
getNeDBStatus: (): boolean => {
|
||||||
return ipcRenderer.sendSync("get-nedb-status")
|
return ipcRenderer.sendSync("get-nedb-status")
|
||||||
},
|
},
|
||||||
setNeDBStatus: () => {
|
setNeDBStatus: (flag: boolean) => {
|
||||||
ipcRenderer.invoke("set-nedb-status")
|
ipcRenderer.invoke("set-nedb-status", flag)
|
||||||
},
|
},
|
||||||
|
|
||||||
getAll: () => {
|
getAll: () => {
|
||||||
|
@ -11,7 +11,7 @@ export type FeedProps = FeedReduxProps & {
|
|||||||
viewType: ViewType
|
viewType: ViewType
|
||||||
viewConfigs?: ViewConfigs
|
viewConfigs?: ViewConfigs
|
||||||
items: RSSItem[]
|
items: RSSItem[]
|
||||||
currentItem: string
|
currentItem: number
|
||||||
sourceMap: Object
|
sourceMap: Object
|
||||||
filter: FeedFilter
|
filter: FeedFilter
|
||||||
shortcuts: (item: RSSItem, e: KeyboardEvent) => void
|
shortcuts: (item: RSSItem, e: KeyboardEvent) => void
|
||||||
|
@ -8,7 +8,7 @@ type LogMenuProps = {
|
|||||||
display: boolean
|
display: boolean
|
||||||
logs: AppLog[]
|
logs: AppLog[]
|
||||||
close: () => void
|
close: () => void
|
||||||
showItem: (iid: string) => void
|
showItem: (iid: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLogIcon(log: AppLog) {
|
function getLogIcon(log: AppLog) {
|
||||||
|
@ -10,7 +10,7 @@ type PageProps = {
|
|||||||
contextOn: boolean
|
contextOn: boolean
|
||||||
settingsOn: boolean
|
settingsOn: boolean
|
||||||
feeds: string[]
|
feeds: string[]
|
||||||
itemId: string
|
itemId: number
|
||||||
itemFromFeed: boolean
|
itemFromFeed: boolean
|
||||||
viewType: ViewType
|
viewType: ViewType
|
||||||
dismissItem: () => void
|
dismissItem: () => void
|
||||||
|
@ -8,7 +8,7 @@ import Article from "../components/article"
|
|||||||
import { openTextMenu, closeContextMenu, openImageMenu } from "../scripts/models/app"
|
import { openTextMenu, closeContextMenu, openImageMenu } from "../scripts/models/app"
|
||||||
|
|
||||||
type ArticleContainerProps = {
|
type ArticleContainerProps = {
|
||||||
itemId: string
|
itemId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItem = (state: RootState, props: ArticleContainerProps) => state.items[props.itemId]
|
const getItem = (state: RootState, props: ArticleContainerProps) => state.items[props.itemId]
|
||||||
|
@ -12,7 +12,7 @@ const mapStateToProps = createSelector(getLogs, logs => logs)
|
|||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
close: () => dispatch(toggleLogMenu()),
|
close: () => dispatch(toggleLogMenu()),
|
||||||
showItem: (iid: string) => dispatch(showItemFromId(iid))
|
showItem: (iid: number) => dispatch(showItemFromId(iid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +177,6 @@ const NEDB_STATUS_STORE_KEY = "useNeDB"
|
|||||||
ipcMain.on("get-nedb-status", (event) => {
|
ipcMain.on("get-nedb-status", (event) => {
|
||||||
event.returnValue = store.get(NEDB_STATUS_STORE_KEY, true)
|
event.returnValue = store.get(NEDB_STATUS_STORE_KEY, true)
|
||||||
})
|
})
|
||||||
ipcMain.handle("set-nedb-status", () => {
|
ipcMain.handle("set-nedb-status", (_, flag: boolean) => {
|
||||||
store.set(NEDB_STATUS_STORE_KEY, false)
|
store.set(NEDB_STATUS_STORE_KEY, flag)
|
||||||
})
|
})
|
||||||
|
@ -7,7 +7,7 @@ export default function performUpdate(store: Store<SchemaTypes>) {
|
|||||||
let useNeDB = store.get("useNeDB", undefined)
|
let useNeDB = store.get("useNeDB", undefined)
|
||||||
let currentVersion = app.getVersion()
|
let currentVersion = app.getVersion()
|
||||||
|
|
||||||
if (useNeDB === undefined) {
|
if (useNeDB === undefined && version !== null) {
|
||||||
const revs = version.split(".").map(s => parseInt(s))
|
const revs = version.split(".").map(s => parseInt(s))
|
||||||
if ((revs[0] === 0 && revs[1] < 8) || !app.isPackaged) {
|
if ((revs[0] === 0 && revs[1] < 8) || !app.isPackaged) {
|
||||||
store.set("useNeDB", true)
|
store.set("useNeDB", true)
|
||||||
|
@ -11,7 +11,7 @@ sdbSchema.createTable("sources").
|
|||||||
addColumn("name", lf.Type.STRING).
|
addColumn("name", lf.Type.STRING).
|
||||||
addColumn("openTarget", lf.Type.NUMBER).
|
addColumn("openTarget", lf.Type.NUMBER).
|
||||||
addColumn("lastFetched", lf.Type.DATE_TIME).
|
addColumn("lastFetched", lf.Type.DATE_TIME).
|
||||||
addColumn("serviceRef", lf.Type.NUMBER).
|
addColumn("serviceRef", lf.Type.STRING).
|
||||||
addColumn("fetchFrequency", lf.Type.NUMBER).
|
addColumn("fetchFrequency", lf.Type.NUMBER).
|
||||||
addColumn("rules", lf.Type.OBJECT).
|
addColumn("rules", lf.Type.OBJECT).
|
||||||
addNullable(["iconurl", "serviceRef", "rules"]).
|
addNullable(["iconurl", "serviceRef", "rules"]).
|
||||||
@ -33,9 +33,10 @@ idbSchema.createTable("items").
|
|||||||
addColumn("starred", lf.Type.BOOLEAN).
|
addColumn("starred", lf.Type.BOOLEAN).
|
||||||
addColumn("hidden", lf.Type.BOOLEAN).
|
addColumn("hidden", lf.Type.BOOLEAN).
|
||||||
addColumn("notify", lf.Type.BOOLEAN).
|
addColumn("notify", lf.Type.BOOLEAN).
|
||||||
addColumn("serviceRef", lf.Type.NUMBER).
|
addColumn("serviceRef", lf.Type.STRING).
|
||||||
addNullable(["thumb", "creator", "serviceRef"]).
|
addNullable(["thumb", "creator", "serviceRef"]).
|
||||||
addIndex("idxDate", ["date"], false, lf.Order.DESC)
|
addIndex("idxDate", ["date"], false, lf.Order.DESC).
|
||||||
|
addIndex("idxService", ["serviceRef"], false)
|
||||||
|
|
||||||
export let sourcesDB: lf.Database
|
export let sourcesDB: lf.Database
|
||||||
export let sources: lf.schema.Table
|
export let sources: lf.schema.Table
|
||||||
@ -73,14 +74,14 @@ export async function init() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
const sRows = sourceDocs.map(doc => {
|
const sRows = sourceDocs.map(doc => {
|
||||||
//doc.serviceRef = String(doc.serviceRef)
|
if (doc.serviceRef !== undefined) doc.serviceRef = String(doc.serviceRef)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
delete doc._id
|
delete doc._id
|
||||||
if (!doc.fetchFrequency) doc.fetchFrequency = 0
|
if (!doc.fetchFrequency) doc.fetchFrequency = 0
|
||||||
return sources.createRow(doc)
|
return sources.createRow(doc)
|
||||||
})
|
})
|
||||||
const iRows = itemDocs.map(doc => {
|
const iRows = itemDocs.map(doc => {
|
||||||
//doc.serviceRef = String(doc.serviceRef)
|
if (doc.serviceRef !== undefined) doc.serviceRef = String(doc.serviceRef)
|
||||||
delete doc._id
|
delete doc._id
|
||||||
doc.starred = Boolean(doc.starred)
|
doc.starred = Boolean(doc.starred)
|
||||||
doc.hidden = Boolean(doc.hidden)
|
doc.hidden = Boolean(doc.hidden)
|
||||||
@ -91,6 +92,8 @@ export async function init() {
|
|||||||
sourcesDB.insert().into(sources).values(sRows).exec(),
|
sourcesDB.insert().into(sources).values(sRows).exec(),
|
||||||
itemsDB.insert().into(items).values(iRows).exec()
|
itemsDB.insert().into(items).values(iRows).exec()
|
||||||
])
|
])
|
||||||
window.settings.setNeDBStatus()
|
window.settings.setNeDBStatus(false)
|
||||||
|
sdb.remove({}, { multi: true }, () => { sdb.persistence.compactDatafile() })
|
||||||
|
idb.remove({}, { multi: true }, () => { idb.persistence.compactDatafile() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,10 @@ export class AppLog {
|
|||||||
type: AppLogType
|
type: AppLogType
|
||||||
title: string
|
title: string
|
||||||
details?: string
|
details?: string
|
||||||
iid?: string
|
iid?: number
|
||||||
time: Date
|
time: Date
|
||||||
|
|
||||||
constructor(type: AppLogType, title: string, details: string=null, iid: string = null) {
|
constructor(type: AppLogType, title: string, details: string=null, iid: number = null) {
|
||||||
this.type = type
|
this.type = type
|
||||||
this.title = title
|
this.title = title
|
||||||
this.details = details
|
this.details = details
|
||||||
@ -121,7 +121,7 @@ interface ToggleLogMenuAction { type: typeof TOGGLE_LOGS }
|
|||||||
|
|
||||||
interface PushNotificationAction {
|
interface PushNotificationAction {
|
||||||
type: typeof PUSH_NOTIFICATION
|
type: typeof PUSH_NOTIFICATION
|
||||||
iid: string
|
iid: number
|
||||||
title: string
|
title: string
|
||||||
source: string
|
source: string
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export class RSSFeed {
|
|||||||
loading: boolean
|
loading: boolean
|
||||||
allLoaded: boolean
|
allLoaded: boolean
|
||||||
sids: number[]
|
sids: number[]
|
||||||
iids: string[]
|
iids: number[]
|
||||||
filter: FeedFilter
|
filter: FeedFilter
|
||||||
|
|
||||||
constructor (id: string = null, sids=[], filter=null) {
|
constructor (id: string = null, sids=[], filter=null) {
|
||||||
@ -240,7 +240,7 @@ export function feedReducer(
|
|||||||
switch (action.status) {
|
switch (action.status) {
|
||||||
case ActionStatus.Success: return {
|
case ActionStatus.Success: return {
|
||||||
...state,
|
...state,
|
||||||
[ALL]: new RSSFeed(ALL, action.sources.map(s => s.sid))
|
[ALL]: new RSSFeed(ALL, Object.values(action.sources).map(s => s.sid))
|
||||||
}
|
}
|
||||||
default: return state
|
default: return state
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { pushNotification, setupAutoFetch } from "./app"
|
|||||||
import { getServiceHooks, syncWithService, ServiceActionTypes, SYNC_LOCAL_ITEMS } from "./service"
|
import { getServiceHooks, syncWithService, ServiceActionTypes, SYNC_LOCAL_ITEMS } from "./service"
|
||||||
|
|
||||||
export class RSSItem {
|
export class RSSItem {
|
||||||
_id: string
|
_id: number
|
||||||
source: number
|
source: number
|
||||||
title: string
|
title: string
|
||||||
link: string
|
link: string
|
||||||
@ -23,7 +23,7 @@ export class RSSItem {
|
|||||||
starred: boolean
|
starred: boolean
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
notify: boolean
|
notify: boolean
|
||||||
serviceRef?: string | number
|
serviceRef?: string
|
||||||
|
|
||||||
constructor (item: Parser.Item, source: RSSSource) {
|
constructor (item: Parser.Item, source: RSSSource) {
|
||||||
for (let field of ["title", "link", "creator"]) {
|
for (let field of ["title", "link", "creator"]) {
|
||||||
@ -79,7 +79,7 @@ export class RSSItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ItemState = {
|
export type ItemState = {
|
||||||
[_id: string]: RSSItem
|
[_id: number]: RSSItem
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FETCH_ITEMS = "FETCH_ITEMS"
|
export const FETCH_ITEMS = "FETCH_ITEMS"
|
||||||
@ -306,7 +306,7 @@ const toggleStarredDone = (item: RSSItem): ItemActionTypes => ({
|
|||||||
|
|
||||||
export function toggleStarred(item: RSSItem): AppThunk {
|
export function toggleStarred(item: RSSItem): AppThunk {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
if (item.starred === true) {
|
if (item.starred) {
|
||||||
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.starred, false).exec()
|
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.starred, false).exec()
|
||||||
} else {
|
} else {
|
||||||
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.starred, true).exec()
|
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.starred, true).exec()
|
||||||
@ -327,10 +327,10 @@ const toggleHiddenDone = (item: RSSItem): ItemActionTypes => ({
|
|||||||
|
|
||||||
export function toggleHidden(item: RSSItem): AppThunk {
|
export function toggleHidden(item: RSSItem): AppThunk {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
if (item.hidden === true) {
|
if (item.hidden) {
|
||||||
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.hidden, true).exec()
|
|
||||||
} else {
|
|
||||||
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.hidden, false).exec()
|
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.hidden, false).exec()
|
||||||
|
} else {
|
||||||
|
db.itemsDB.update(db.items).where(db.items._id.eq(item._id)).set(db.items.hidden, true).exec()
|
||||||
}
|
}
|
||||||
dispatch(toggleHiddenDone(item))
|
dispatch(toggleHiddenDone(item))
|
||||||
}
|
}
|
||||||
@ -371,7 +371,7 @@ export function applyItemReduction(item: RSSItem, type: string) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case TOGGLE_HIDDEN: {
|
case TOGGLE_HIDDEN: {
|
||||||
item.hidden = !item.hidden
|
nextItem.hidden = !item.hidden
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,13 +406,13 @@ export function itemReducer(
|
|||||||
case MARK_ALL_READ: {
|
case MARK_ALL_READ: {
|
||||||
let nextState = { ...state }
|
let nextState = { ...state }
|
||||||
let sids = new Set(action.sids)
|
let sids = new Set(action.sids)
|
||||||
for (let [id, item] of Object.entries(state)) {
|
for (let item of Object.values(state)) {
|
||||||
if (sids.has(item.source) && !item.hasRead) {
|
if (sids.has(item.source) && !item.hasRead) {
|
||||||
if (!action.time || (action.before
|
if (!action.time || (action.before
|
||||||
? item.date.getTime() <= action.time
|
? item.date.getTime() <= action.time
|
||||||
: item.date.getTime() >= action.time)
|
: item.date.getTime() >= action.time)
|
||||||
) {
|
) {
|
||||||
nextState[id] = {
|
nextState[item._id] = {
|
||||||
...item,
|
...item,
|
||||||
hasRead: true
|
hasRead: true
|
||||||
}
|
}
|
||||||
@ -435,15 +435,13 @@ export function itemReducer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SYNC_LOCAL_ITEMS: {
|
case SYNC_LOCAL_ITEMS: {
|
||||||
const unreadSet = new Set(action.unreadIds)
|
|
||||||
const starredSet = new Set(action.starredIds)
|
|
||||||
let nextState = { ...state }
|
let nextState = { ...state }
|
||||||
for (let [id, item] of Object.entries(state)) {
|
for (let item of Object.values(state)) {
|
||||||
if (item.hasOwnProperty("serviceRef")) {
|
if (item.hasOwnProperty("serviceRef")) {
|
||||||
const nextItem = { ...item }
|
const nextItem = { ...item }
|
||||||
nextItem.hasRead = !unreadSet.has(nextItem.serviceRef as number)
|
nextItem.hasRead = !action.unreadIds.has(item.serviceRef)
|
||||||
nextItem.starred = starredSet.has(item.serviceRef as number)
|
nextItem.starred = action.starredIds.has(item.serviceRef)
|
||||||
nextState[id] = nextItem
|
nextState[item._id] = nextItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nextState
|
return nextState
|
||||||
|
@ -114,7 +114,7 @@ export function showItem(feedId: string, item: RSSItem): AppThunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function showItemFromId(iid: string): AppThunk {
|
export function showItemFromId(iid: number): AppThunk {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState()
|
const state = getState()
|
||||||
const item = state.items[iid]
|
const item = state.items[iid]
|
||||||
@ -237,7 +237,7 @@ export class PageState {
|
|||||||
viewConfigs = window.settings.getViewConfigs(window.settings.getDefaultView())
|
viewConfigs = window.settings.getViewConfigs(window.settings.getDefaultView())
|
||||||
filter = new FeedFilter()
|
filter = new FeedFilter()
|
||||||
feedId = ALL
|
feedId = ALL
|
||||||
itemId = null as string
|
itemId = null as number
|
||||||
itemFromFeed = true
|
itemFromFeed = true
|
||||||
searchOn = false
|
searchOn = false
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ import { feedbinServiceHooks } from "./services/feedbin"
|
|||||||
|
|
||||||
export interface ServiceHooks {
|
export interface ServiceHooks {
|
||||||
authenticate?: (configs: ServiceConfigs) => Promise<boolean>
|
authenticate?: (configs: ServiceConfigs) => Promise<boolean>
|
||||||
updateSources?: () => AppThunk<Promise<[RSSSource[], Map<number | string, string>]>>
|
updateSources?: () => AppThunk<Promise<[RSSSource[], Map<string, string>]>>
|
||||||
fetchItems?: () => AppThunk<Promise<[RSSItem[], ServiceConfigs]>>
|
fetchItems?: () => AppThunk<Promise<[RSSItem[], ServiceConfigs]>>
|
||||||
syncItems?: () => AppThunk<Promise<[(number | string)[], (number | string)[]]>>
|
syncItems?: () => AppThunk<Promise<[Set<string>, Set<string>]>>
|
||||||
markRead?: (item: RSSItem) => AppThunk
|
markRead?: (item: RSSItem) => AppThunk
|
||||||
markUnread?: (item: RSSItem) => AppThunk
|
markUnread?: (item: RSSItem) => AppThunk
|
||||||
markAllRead?: (sids?: number[], date?: Date, before?: boolean) => AppThunk<Promise<void>>
|
markAllRead?: (sids?: number[], date?: Date, before?: boolean) => AppThunk<Promise<void>>
|
||||||
@ -71,7 +71,7 @@ export function syncWithService(background = false): AppThunk<Promise<void>> {
|
|||||||
function updateSources(hook: ServiceHooks["updateSources"]): AppThunk<Promise<void>> {
|
function updateSources(hook: ServiceHooks["updateSources"]): AppThunk<Promise<void>> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const [sources, groupsMap] = await dispatch(hook())
|
const [sources, groupsMap] = await dispatch(hook())
|
||||||
const existing = new Map<number | string, RSSSource>()
|
const existing = new Map<string, RSSSource>()
|
||||||
for (let source of Object.values(getState().sources)) {
|
for (let source of Object.values(getState().sources)) {
|
||||||
if (source.serviceRef) {
|
if (source.serviceRef) {
|
||||||
existing.set(source.serviceRef, source)
|
existing.set(source.serviceRef, source)
|
||||||
@ -138,29 +138,37 @@ function syncItems(hook: ServiceHooks["syncItems"]): AppThunk<Promise<void>> {
|
|||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
const state = getState()
|
const state = getState()
|
||||||
const [unreadRefs, starredRefs] = await dispatch(hook())
|
const [unreadRefs, starredRefs] = await dispatch(hook())
|
||||||
const promises = [
|
const unreadCopy = new Set(unreadRefs)
|
||||||
db.itemsDB.update(db.items).set(db.items.hasRead, false).where(lf.op.and(
|
const starredCopy = new Set(starredRefs)
|
||||||
db.items.serviceRef.in(unreadRefs),
|
const rows = await db.itemsDB.select(
|
||||||
db.items.hasRead.eq(true)
|
db.items.serviceRef, db.items.hasRead, db.items.starred
|
||||||
)).exec(),
|
).from(db.items).where(lf.op.and(
|
||||||
db.itemsDB.update(db.items).set(db.items.hasRead, true).where(lf.op.and(
|
db.items.serviceRef.isNotNull(),
|
||||||
lf.op.not(db.items.serviceRef.in(unreadRefs)),
|
lf.op.or(db.items.hasRead.eq(false), db.items.starred.eq(true))
|
||||||
db.items.hasRead.eq(false)
|
)).exec()
|
||||||
)).exec(),
|
const updates = new Array<lf.query.Update>()
|
||||||
db.itemsDB.update(db.items).set(db.items.starred, true).where(lf.op.and(
|
for (let row of rows) {
|
||||||
db.items.serviceRef.in(starredRefs),
|
const serviceRef = row["serviceRef"]
|
||||||
db.items.starred.eq(false)
|
if (row["hasRead"] === false && !unreadRefs.delete(serviceRef)) {
|
||||||
)).exec(),
|
updates.push(db.itemsDB.update(db.items).set(db.items.hasRead, true).where(db.items.serviceRef.eq(serviceRef)))
|
||||||
db.itemsDB.update(db.items).set(db.items.starred, false).where(lf.op.and(
|
}
|
||||||
lf.op.not(db.items.serviceRef.in(starredRefs)),
|
if (row["starred"] === true && !starredRefs.delete(serviceRef)) {
|
||||||
db.items.hasRead.eq(true)
|
updates.push(db.itemsDB.update(db.items).set(db.items.starred, false).where(db.items.serviceRef.eq(serviceRef)))
|
||||||
)).exec(),
|
}
|
||||||
]
|
}
|
||||||
await Promise.all(promises)
|
for (let unread of unreadRefs) {
|
||||||
await dispatch(updateUnreadCounts())
|
updates.push(db.itemsDB.update(db.items).set(db.items.hasRead, false).where(db.items.serviceRef.eq(unread)))
|
||||||
dispatch(syncLocalItems(unreadRefs, starredRefs))
|
}
|
||||||
if (!(state.page.filter.type & FilterType.ShowRead) || !(state.page.filter.type & FilterType.ShowNotStarred)) {
|
for (let starred of starredRefs) {
|
||||||
dispatch(initFeeds(true))
|
updates.push(db.itemsDB.update(db.items).set(db.items.starred, true).where(db.items.serviceRef.eq(starred)))
|
||||||
|
}
|
||||||
|
if (updates.length > 0) {
|
||||||
|
await db.itemsDB.createTransaction().exec(updates)
|
||||||
|
await dispatch(updateUnreadCounts())
|
||||||
|
dispatch(syncLocalItems(unreadCopy, starredCopy))
|
||||||
|
if (!(state.page.filter.type & FilterType.ShowRead) || !(state.page.filter.type & FilterType.ShowNotStarred)) {
|
||||||
|
dispatch(initFeeds(true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,8 +232,8 @@ interface SyncWithServiceAction {
|
|||||||
|
|
||||||
interface SyncLocalItemsAction {
|
interface SyncLocalItemsAction {
|
||||||
type: typeof SYNC_LOCAL_ITEMS
|
type: typeof SYNC_LOCAL_ITEMS
|
||||||
unreadIds: (string | number)[]
|
unreadIds: Set<string>
|
||||||
starredIds: (string | number)[]
|
starredIds: Set<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ServiceActionTypes = SaveServiceConfigsAction | SyncWithServiceAction | SyncLocalItemsAction
|
export type ServiceActionTypes = SaveServiceConfigsAction | SyncWithServiceAction | SyncLocalItemsAction
|
||||||
@ -240,7 +248,7 @@ export function saveServiceConfigs(configs: ServiceConfigs): AppThunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncLocalItems(unread: (string | number)[], starred: (string | number)[]): ServiceActionTypes {
|
function syncLocalItems(unread: Set<string>, starred: Set<string>): ServiceActionTypes {
|
||||||
return {
|
return {
|
||||||
type: SYNC_LOCAL_ITEMS,
|
type: SYNC_LOCAL_ITEMS,
|
||||||
unreadIds: unread,
|
unreadIds: unread,
|
||||||
|
@ -62,7 +62,7 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
const response = await fetchAPI(configs, "subscriptions.json")
|
const response = await fetchAPI(configs, "subscriptions.json")
|
||||||
if (response.status !== 200) throw APIError()
|
if (response.status !== 200) throw APIError()
|
||||||
const subscriptions: any[] = await response.json()
|
const subscriptions: any[] = await response.json()
|
||||||
let groupsMap: Map<number, string>
|
let groupsMap: Map<string, string>
|
||||||
if (configs.importGroups) {
|
if (configs.importGroups) {
|
||||||
const tagsResponse = await fetchAPI(configs, "taggings.json")
|
const tagsResponse = await fetchAPI(configs, "taggings.json")
|
||||||
if (tagsResponse.status !== 200) throw APIError()
|
if (tagsResponse.status !== 200) throw APIError()
|
||||||
@ -75,12 +75,12 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
tagsSet.add(title)
|
tagsSet.add(title)
|
||||||
dispatch(createSourceGroup(title))
|
dispatch(createSourceGroup(title))
|
||||||
}
|
}
|
||||||
groupsMap.set(tag.feed_id, title)
|
groupsMap.set(String(tag.feed_id), title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sources = subscriptions.map(s => {
|
const sources = subscriptions.map(s => {
|
||||||
const source = new RSSSource(s.feed_url, s.title)
|
const source = new RSSSource(s.feed_url, s.title)
|
||||||
source.serviceRef = s.feed_id
|
source.serviceRef = String(s.feed_id)
|
||||||
return source
|
return source
|
||||||
})
|
})
|
||||||
return [sources, groupsMap]
|
return [sources, groupsMap]
|
||||||
@ -95,7 +95,7 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
if (unreadResponse.status !== 200 || starredResponse.status !== 200) throw APIError()
|
if (unreadResponse.status !== 200 || starredResponse.status !== 200) throw APIError()
|
||||||
const unread = await unreadResponse.json()
|
const unread = await unreadResponse.json()
|
||||||
const starred = await starredResponse.json()
|
const starred = await starredResponse.json()
|
||||||
return [unread, starred]
|
return [new Set(unread.map(i => String(i))), new Set(starred.map(i => String(i)))]
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchItems: () => async (_, getState) => {
|
fetchItems: () => async (_, getState) => {
|
||||||
@ -120,10 +120,10 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
)
|
)
|
||||||
configs.lastId = items.reduce((m, n) => Math.max(m, n.id), configs.lastId)
|
configs.lastId = items.reduce((m, n) => Math.max(m, n.id), configs.lastId)
|
||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
const fidMap = new Map<number, RSSSource>()
|
const fidMap = new Map<string, RSSSource>()
|
||||||
for (let source of Object.values(state.sources)) {
|
for (let source of Object.values(state.sources)) {
|
||||||
if (source.serviceRef) {
|
if (source.serviceRef) {
|
||||||
fidMap.set(source.serviceRef as number, source)
|
fidMap.set(source.serviceRef, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const [unreadResponse, starredResponse] = await Promise.all([
|
const [unreadResponse, starredResponse] = await Promise.all([
|
||||||
@ -134,7 +134,7 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
const unread: Set<number> = new Set(await unreadResponse.json())
|
const unread: Set<number> = new Set(await unreadResponse.json())
|
||||||
const starred: Set<number> = new Set(await starredResponse.json())
|
const starred: Set<number> = new Set(await starredResponse.json())
|
||||||
const parsedItems = items.map(i => {
|
const parsedItems = items.map(i => {
|
||||||
const source = fidMap.get(i.feed_id)
|
const source = fidMap.get(String(i.feed_id))
|
||||||
const dom = domParser.parseFromString(i.content, "text/html")
|
const dom = domParser.parseFromString(i.content, "text/html")
|
||||||
const item = {
|
const item = {
|
||||||
source: source.sid,
|
source: source.sid,
|
||||||
@ -149,7 +149,7 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
starred: starred.has(i.id),
|
starred: starred.has(i.id),
|
||||||
hidden: false,
|
hidden: false,
|
||||||
notify: false,
|
notify: false,
|
||||||
serviceRef: i.id,
|
serviceRef: String(i.id),
|
||||||
} as RSSItem
|
} as RSSItem
|
||||||
if (i.images && i.images.original_url) {
|
if (i.images && i.images.original_url) {
|
||||||
item.thumb = i.images.original_url
|
item.thumb = i.images.original_url
|
||||||
@ -186,23 +186,23 @@ export const feedbinServiceHooks: ServiceHooks = {
|
|||||||
predicates.push(before ? db.items.date.lte(date) : db.items.date.gte(date))
|
predicates.push(before ? db.items.date.lte(date) : db.items.date.gte(date))
|
||||||
}
|
}
|
||||||
const rows = await db.itemsDB.select(db.items.serviceRef).where(lf.op.and.apply(null, predicates)).exec()
|
const rows = await db.itemsDB.select(db.items.serviceRef).where(lf.op.and.apply(null, predicates)).exec()
|
||||||
const refs = rows.map(row => row["serviceRef"]) as number[]
|
const refs = rows.map(row => parseInt(row["serviceRef"]))
|
||||||
markItems(configs, "unread", "DELETE", refs)
|
markItems(configs, "unread", "DELETE", refs)
|
||||||
},
|
},
|
||||||
|
|
||||||
markRead: (item: RSSItem) => async (_, getState) => {
|
markRead: (item: RSSItem) => async (_, getState) => {
|
||||||
await markItems(getState().service as FeedbinConfigs, "unread", "DELETE", [item.serviceRef as number])
|
await markItems(getState().service as FeedbinConfigs, "unread", "DELETE", [parseInt(item.serviceRef)])
|
||||||
},
|
},
|
||||||
|
|
||||||
markUnread: (item: RSSItem) => async (_, getState) => {
|
markUnread: (item: RSSItem) => async (_, getState) => {
|
||||||
await markItems(getState().service as FeedbinConfigs, "unread", "POST", [item.serviceRef as number])
|
await markItems(getState().service as FeedbinConfigs, "unread", "POST", [parseInt(item.serviceRef)])
|
||||||
},
|
},
|
||||||
|
|
||||||
star: (item: RSSItem) => async (_, getState) => {
|
star: (item: RSSItem) => async (_, getState) => {
|
||||||
await markItems(getState().service as FeedbinConfigs, "starred", "POST", [item.serviceRef as number])
|
await markItems(getState().service as FeedbinConfigs, "starred", "POST", [parseInt(item.serviceRef)])
|
||||||
},
|
},
|
||||||
|
|
||||||
unstar: (item: RSSItem) => async (_, getState) => {
|
unstar: (item: RSSItem) => async (_, getState) => {
|
||||||
await markItems(getState().service as FeedbinConfigs, "starred", "DELETE", [item.serviceRef as number])
|
await markItems(getState().service as FeedbinConfigs, "starred", "DELETE", [parseInt(item.serviceRef)])
|
||||||
},
|
},
|
||||||
}
|
}
|
@ -53,7 +53,7 @@ export const feverServiceHooks: ServiceHooks = {
|
|||||||
const feeds: any[] = response.feeds
|
const feeds: any[] = response.feeds
|
||||||
const feedGroups: any[] = response.feeds_groups
|
const feedGroups: any[] = response.feeds_groups
|
||||||
if (feeds === undefined) throw APIError()
|
if (feeds === undefined) throw APIError()
|
||||||
let groupsMap: Map<number, string>
|
let groupsMap: Map<string, string>
|
||||||
if (configs.importGroups) {
|
if (configs.importGroups) {
|
||||||
// Import groups on the first sync
|
// Import groups on the first sync
|
||||||
const groups: any[] = (await fetchAPI(configs, "&groups")).groups
|
const groups: any[] = (await fetchAPI(configs, "&groups")).groups
|
||||||
@ -66,14 +66,14 @@ export const feverServiceHooks: ServiceHooks = {
|
|||||||
}
|
}
|
||||||
groupsMap = new Map()
|
groupsMap = new Map()
|
||||||
for (let group of feedGroups) {
|
for (let group of feedGroups) {
|
||||||
for (let fid of group.feed_ids.split(",").map(s => parseInt(s))) {
|
for (let fid of group.feed_ids.split(",")) {
|
||||||
groupsMap.set(fid, groupsIdMap.get(group.group_id))
|
groupsMap.set(fid, groupsIdMap.get(group.group_id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sources = feeds.map(f => {
|
const sources = feeds.map(f => {
|
||||||
const source = new RSSSource(f.url, f.title)
|
const source = new RSSSource(f.url, f.title)
|
||||||
source.serviceRef = f.id
|
source.serviceRef = String(f.id)
|
||||||
return source
|
return source
|
||||||
})
|
})
|
||||||
return [sources, groupsMap]
|
return [sources, groupsMap]
|
||||||
@ -104,14 +104,14 @@ export const feverServiceHooks: ServiceHooks = {
|
|||||||
)
|
)
|
||||||
configs.lastId = items.reduce((m, n) => Math.max(m, n.id), configs.lastId)
|
configs.lastId = items.reduce((m, n) => Math.max(m, n.id), configs.lastId)
|
||||||
if (items.length > 0) {
|
if (items.length > 0) {
|
||||||
const fidMap = new Map<number, RSSSource>()
|
const fidMap = new Map<string, RSSSource>()
|
||||||
for (let source of Object.values(state.sources)) {
|
for (let source of Object.values(state.sources)) {
|
||||||
if (source.serviceRef) {
|
if (source.serviceRef) {
|
||||||
fidMap.set(source.serviceRef as number, source)
|
fidMap.set(source.serviceRef, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const parsedItems = items.map(i => {
|
const parsedItems = items.map(i => {
|
||||||
const source = fidMap.get(i.feed_id)
|
const source = fidMap.get(String(i.feed_id))
|
||||||
const item = {
|
const item = {
|
||||||
source: source.sid,
|
source: source.sid,
|
||||||
title: i.title,
|
title: i.title,
|
||||||
@ -125,7 +125,7 @@ export const feverServiceHooks: ServiceHooks = {
|
|||||||
starred: Boolean(i.is_saved),
|
starred: Boolean(i.is_saved),
|
||||||
hidden: false,
|
hidden: false,
|
||||||
notify: false,
|
notify: false,
|
||||||
serviceRef: typeof i.id === "string" ? parseInt(i.id) : i.id,
|
serviceRef: String(i.id),
|
||||||
} as RSSItem
|
} as RSSItem
|
||||||
// Try to get the thumbnail of the item
|
// Try to get the thumbnail of the item
|
||||||
let dom = domParser.parseFromString(item.content, "text/html")
|
let dom = domParser.parseFromString(item.content, "text/html")
|
||||||
@ -163,9 +163,9 @@ export const feverServiceHooks: ServiceHooks = {
|
|||||||
if (typeof unreadResponse.unread_item_ids !== "string" || typeof starredResponse.saved_item_ids !== "string") {
|
if (typeof unreadResponse.unread_item_ids !== "string" || typeof starredResponse.saved_item_ids !== "string") {
|
||||||
throw APIError()
|
throw APIError()
|
||||||
}
|
}
|
||||||
const unreadFids: number[] = unreadResponse.unread_item_ids.split(",").map(s => parseInt(s))
|
const unreadFids: string[] = unreadResponse.unread_item_ids.split(",")
|
||||||
const starredFids: number[] = starredResponse.saved_item_ids.split(",").map(s => parseInt(s))
|
const starredFids: string[] = starredResponse.saved_item_ids.split(",")
|
||||||
return [unreadFids, starredFids]
|
return [new Set(unreadFids), new Set(starredFids)]
|
||||||
},
|
},
|
||||||
|
|
||||||
markAllRead: (sids, date, before) => async (_, getState) => {
|
markAllRead: (sids, date, before) => async (_, getState) => {
|
||||||
|
@ -19,7 +19,7 @@ export class RSSSource {
|
|||||||
openTarget: SourceOpenTarget
|
openTarget: SourceOpenTarget
|
||||||
unreadCount: number
|
unreadCount: number
|
||||||
lastFetched: Date
|
lastFetched: Date
|
||||||
serviceRef?: string | number
|
serviceRef?: string
|
||||||
fetchFrequency: number // in minutes
|
fetchFrequency: number // in minutes
|
||||||
rules?: SourceRule[]
|
rules?: SourceRule[]
|
||||||
|
|
||||||
@ -81,12 +81,13 @@ export type SourceState = {
|
|||||||
export const INIT_SOURCES = "INIT_SOURCES"
|
export const INIT_SOURCES = "INIT_SOURCES"
|
||||||
export const ADD_SOURCE = "ADD_SOURCE"
|
export const ADD_SOURCE = "ADD_SOURCE"
|
||||||
export const UPDATE_SOURCE = "UPDATE_SOURCE"
|
export const UPDATE_SOURCE = "UPDATE_SOURCE"
|
||||||
|
export const UPDATE_UNREAD_COUNTS = "UPDATE_UNREAD_COUNTS"
|
||||||
export const DELETE_SOURCE = "DELETE_SOURCE"
|
export const DELETE_SOURCE = "DELETE_SOURCE"
|
||||||
|
|
||||||
interface InitSourcesAction {
|
interface InitSourcesAction {
|
||||||
type: typeof INIT_SOURCES
|
type: typeof INIT_SOURCES
|
||||||
status: ActionStatus
|
status: ActionStatus
|
||||||
sources?: RSSSource[]
|
sources?: SourceState
|
||||||
err?
|
err?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,12 +104,18 @@ interface UpdateSourceAction {
|
|||||||
source: RSSSource
|
source: RSSSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UpdateUnreadCountsAction {
|
||||||
|
type: typeof UPDATE_UNREAD_COUNTS
|
||||||
|
sources: SourceState
|
||||||
|
}
|
||||||
|
|
||||||
interface DeleteSourceAction {
|
interface DeleteSourceAction {
|
||||||
type: typeof DELETE_SOURCE,
|
type: typeof DELETE_SOURCE,
|
||||||
source: RSSSource
|
source: RSSSource
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SourceActionTypes = InitSourcesAction | AddSourceAction | UpdateSourceAction | DeleteSourceAction
|
export type SourceActionTypes = InitSourcesAction | AddSourceAction | UpdateSourceAction
|
||||||
|
| UpdateUnreadCountsAction | DeleteSourceAction
|
||||||
|
|
||||||
export function initSourcesRequest(): SourceActionTypes {
|
export function initSourcesRequest(): SourceActionTypes {
|
||||||
return {
|
return {
|
||||||
@ -117,7 +124,7 @@ export function initSourcesRequest(): SourceActionTypes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initSourcesSuccess(sources: RSSSource[]): SourceActionTypes {
|
export function initSourcesSuccess(sources: SourceState): SourceActionTypes {
|
||||||
return {
|
return {
|
||||||
type: INIT_SOURCES,
|
type: INIT_SOURCES,
|
||||||
status: ActionStatus.Success,
|
status: ActionStatus.Success,
|
||||||
@ -133,21 +140,34 @@ export function initSourcesFailure(err): SourceActionTypes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unreadCount(source: RSSSource): Promise<RSSSource> {
|
async function unreadCount(sources: SourceState): Promise<SourceState> {
|
||||||
source.unreadCount = (await db.itemsDB.select(
|
const rows = await db.itemsDB.select(
|
||||||
|
db.items.source,
|
||||||
lf.fn.count(db.items._id)
|
lf.fn.count(db.items._id)
|
||||||
).from(db.items).where(lf.op.and(
|
).from(db.items).where(
|
||||||
db.items.source.eq(source.sid),
|
|
||||||
db.items.hasRead.eq(false)
|
db.items.hasRead.eq(false)
|
||||||
)).exec())[0]["COUNT(_id)"]
|
).groupBy(
|
||||||
return source
|
db.items.source
|
||||||
|
).exec()
|
||||||
|
for (let row of rows) {
|
||||||
|
sources[row["source"]].unreadCount = row["COUNT(_id)"]
|
||||||
|
}
|
||||||
|
return sources
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateUnreadCounts(): AppThunk<Promise<void>> {
|
export function updateUnreadCounts(): AppThunk<Promise<void>> {
|
||||||
return async (dispatch, getState) => {
|
return async (dispatch, getState) => {
|
||||||
await Promise.all(Object.values(getState().sources).map(async s => {
|
const sources: SourceState = {}
|
||||||
dispatch(updateSourceDone(await unreadCount(s)))
|
for (let source of Object.values(getState().sources)) {
|
||||||
}))
|
sources[source.sid] = {
|
||||||
|
...source,
|
||||||
|
unreadCount: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch({
|
||||||
|
type: UPDATE_UNREAD_COUNTS,
|
||||||
|
sources: await unreadCount(sources),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,9 +176,13 @@ export function initSources(): AppThunk<Promise<void>> {
|
|||||||
dispatch(initSourcesRequest())
|
dispatch(initSourcesRequest())
|
||||||
await db.init()
|
await db.init()
|
||||||
const sources = (await db.sourcesDB.select().from(db.sources).exec()) as RSSSource[]
|
const sources = (await db.sourcesDB.select().from(db.sources).exec()) as RSSSource[]
|
||||||
const promises = sources.map(s => unreadCount(s))
|
const state: SourceState = {}
|
||||||
const counted = await Promise.all(promises)
|
for (let source of sources) {
|
||||||
dispatch(initSourcesSuccess(counted))
|
source.unreadCount = 0
|
||||||
|
state[source.sid] = source
|
||||||
|
}
|
||||||
|
await unreadCount(sources)
|
||||||
|
dispatch(initSourcesSuccess(sources))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,15 +337,10 @@ export function sourceReducer(
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case INIT_SOURCES:
|
case INIT_SOURCES:
|
||||||
switch (action.status) {
|
switch (action.status) {
|
||||||
case ActionStatus.Success: {
|
case ActionStatus.Success: return action.sources
|
||||||
let newState: SourceState = {}
|
|
||||||
for (let source of action.sources) {
|
|
||||||
newState[source.sid] = source
|
|
||||||
}
|
|
||||||
return newState
|
|
||||||
}
|
|
||||||
default: return state
|
default: return state
|
||||||
}
|
}
|
||||||
|
case UPDATE_UNREAD_COUNTS: return action.sources
|
||||||
case ADD_SOURCE:
|
case ADD_SOURCE:
|
||||||
switch (action.status) {
|
switch (action.status) {
|
||||||
case ActionStatus.Success: return {
|
case ActionStatus.Success: return {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import * as db from "./db"
|
||||||
import { IPartialTheme, loadTheme } from "@fluentui/react"
|
import { IPartialTheme, loadTheme } from "@fluentui/react"
|
||||||
import locales from "./i18n/_locales"
|
import locales from "./i18n/_locales"
|
||||||
import { ThemeSettings } from "../schema-types"
|
import { ThemeSettings } from "../schema-types"
|
||||||
@ -57,29 +58,17 @@ export function getCurrentLocale() {
|
|||||||
return (locale in locales) ? locale : "en-US"
|
return (locale in locales) ? locale : "en-US"
|
||||||
}
|
}
|
||||||
|
|
||||||
export function exportAll() {
|
export async function exportAll() {
|
||||||
const filters = [{ name: intl.get("app.frData"), extensions: ["frdata"] }]
|
const filters = [{ name: intl.get("app.frData"), extensions: ["frdata"] }]
|
||||||
window.utils.showSaveDialog(filters, "*/Fluent_Reader_Backup.frdata").then(write => {
|
const write = await window.utils.showSaveDialog(filters, "*/Fluent_Reader_Backup.frdata")
|
||||||
if (write) {
|
if (write) {
|
||||||
let output = window.settings.getAll()
|
let output = window.settings.getAll()
|
||||||
output["nedb"] = {}
|
output["lovefield"] = {
|
||||||
let openRequest = window.indexedDB.open("NeDB")
|
sources: await db.sourcesDB.select().from(db.sources).exec(),
|
||||||
openRequest.onsuccess = () => {
|
items: await db.itemsDB.select().from(db.items).exec(),
|
||||||
let db = openRequest.result
|
|
||||||
let objectStore = db.transaction("nedbdata").objectStore("nedbdata")
|
|
||||||
let cursorRequest = objectStore.openCursor()
|
|
||||||
cursorRequest.onsuccess = () => {
|
|
||||||
let cursor = cursorRequest.result
|
|
||||||
if (cursor) {
|
|
||||||
output["nedb"][cursor.key] = cursor.value
|
|
||||||
cursor.continue()
|
|
||||||
} else {
|
|
||||||
write(JSON.stringify(output), intl.get("settings.writeError"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
write(JSON.stringify(output), intl.get("settings.writeError"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importAll() {
|
export async function importAll() {
|
||||||
@ -94,21 +83,40 @@ export async function importAll() {
|
|||||||
)
|
)
|
||||||
if (!confirmed) return true
|
if (!confirmed) return true
|
||||||
let configs = JSON.parse(data)
|
let configs = JSON.parse(data)
|
||||||
let openRequest = window.indexedDB.open("NeDB")
|
await db.sourcesDB.delete().from(db.sources).exec()
|
||||||
openRequest.onsuccess = () => {
|
await db.itemsDB.delete().from(db.items).exec()
|
||||||
let db = openRequest.result
|
if (configs.nedb) {
|
||||||
let objectStore = db.transaction("nedbdata", "readwrite").objectStore("nedbdata")
|
let openRequest = window.indexedDB.open("NeDB")
|
||||||
let requests = Object.entries(configs.nedb).map(([key, value]) => {
|
configs.useNeDB = true
|
||||||
return objectStore.put(value, key)
|
openRequest.onsuccess = () => {
|
||||||
|
let db = openRequest.result
|
||||||
|
let objectStore = db.transaction("nedbdata", "readwrite").objectStore("nedbdata")
|
||||||
|
let requests = Object.entries(configs.nedb).map(([key, value]) => {
|
||||||
|
return objectStore.put(value, key)
|
||||||
|
})
|
||||||
|
let promises = requests.map(req => new Promise((resolve, reject) => {
|
||||||
|
req.onsuccess = () => resolve()
|
||||||
|
req.onerror = () => reject()
|
||||||
|
}))
|
||||||
|
Promise.all(promises).then(() => {
|
||||||
|
delete configs.nedb
|
||||||
|
window.settings.setAll(configs)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const sRows = configs.lovefield.sources.map(s => {
|
||||||
|
s.lastFetched = new Date(s.lastFetched)
|
||||||
|
return db.sources.createRow(s)
|
||||||
})
|
})
|
||||||
let promises = requests.map(req => new Promise((resolve, reject) => {
|
const iRows = configs.lovefield.items.map(i => {
|
||||||
req.onsuccess = () => resolve()
|
i.date = new Date(i.date)
|
||||||
req.onerror = () => reject()
|
i.fetchedDate = new Date(i.fetchedDate)
|
||||||
}))
|
return db.items.createRow(i)
|
||||||
Promise.all(promises).then(() => {
|
|
||||||
delete configs.nedb
|
|
||||||
window.settings.setAll(configs)
|
|
||||||
})
|
})
|
||||||
}
|
await db.sourcesDB.insert().into(db.sources).values(sRows).exec()
|
||||||
|
await db.itemsDB.insert().into(db.items).values(iRows).exec()
|
||||||
|
delete configs.lovefield
|
||||||
|
window.settings.setAll(configs)
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -189,15 +189,22 @@ function byteLength(str: string) {
|
|||||||
|
|
||||||
export function calculateItemSize(): Promise<number> {
|
export function calculateItemSize(): Promise<number> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let openRequest = window.indexedDB.open("NeDB")
|
let result = 0
|
||||||
|
let openRequest = window.indexedDB.open("itemsDB")
|
||||||
openRequest.onsuccess = () => {
|
openRequest.onsuccess = () => {
|
||||||
let db = openRequest.result
|
let db = openRequest.result
|
||||||
let objectStore = db.transaction("nedbdata").objectStore("nedbdata")
|
let objectStore = db.transaction("items").objectStore("items")
|
||||||
let getRequest = objectStore.get("items")
|
let cursorRequest = objectStore.openCursor()
|
||||||
getRequest.onsuccess = () => {
|
cursorRequest.onsuccess = () => {
|
||||||
resolve(byteLength(getRequest.result))
|
let cursor = cursorRequest.result
|
||||||
|
if (cursor) {
|
||||||
|
result += byteLength(JSON.stringify(cursor.value))
|
||||||
|
cursor.continue()
|
||||||
|
} else {
|
||||||
|
resolve(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
getRequest.onerror = () => reject()
|
cursorRequest.onerror = () => reject()
|
||||||
}
|
}
|
||||||
openRequest.onerror = () => reject()
|
openRequest.onerror = () => reject()
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user